timeout/untimeout ==> callout_*
[dragonfly.git] / sys / dev / serial / dgb / dgm.c
1 /*-
2  * $FreeBSD: src/sys/dev/dgb/dgm.c,v 1.31.2.3 2001/10/07 09:02:25 brian Exp $
3  * $DragonFly: src/sys/dev/serial/dgb/dgm.c,v 1.10 2004/09/18 19:54:26 dillon Exp $
4  *
5  *  This driver and the associated header files support the ISA PC/Xem
6  *  Digiboards.  Its evolutionary roots are described below.
7  *  Jack O'Neill <jack@diamond.xtalwind.net>
8  *
9  *  Digiboard driver.
10  *
11  *  Stage 1. "Better than nothing".
12  *  Stage 2. "Gee, it works!".
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions, and the following disclaimer,
19  *    without modification, immediately at the beginning of the file.
20  * 2. Redistributions of binary code must retain the above copyright
21  *    notice, this list of conditions, and the following disclaimer,
22  *    without modification, in the accompanying documentation.
23  * 3. The name of the author may not be used to endorse or promote products
24  *    derived from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
30  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *  Written by Sergey Babkin,
39  *      Joint Stock Commercial Bank "Chelindbank"
40  *      (Chelyabinsk, Russia)
41  *      babkin@freebsd.org
42  *
43  *  Assorted hacks to make it more functional and working under 3.0-current.
44  *  Fixed broken routines to prevent processes hanging on closed (thanks
45  *  to Bruce for his patience and assistance). Thanks also to Maxim Bolotin
46  *  <max@run.net> for his patches which did most of the work to get this
47  *  running under 2.2/3.0-current.
48  *  Implemented ioctls: TIOCMSDTRWAIT, TIOCMGDTRWAIT, TIOCTIMESTAMP &
49  *  TIOCDCDTIMESTAMP.
50  *  Sysctl debug flag is now a bitflag, to filter noise during debugging.
51  *      David L. Nugent <davidn@blaze.net.au>
52  *
53  * New-busification by Brian Somers <brian@Awfulhak.org>
54  *
55  * There was a copyright confusion: I thought that having read the
56  * GLPed drivers makes me mentally contaminated but in fact it does
57  * not. Since the Linux driver by Troy De Jongh <troyd@digibd.com> or
58  * <troyd@skypoint.com> was used only to learn the Digi's interface,
59  * I've returned this driver to a BSD-style license. I tried to contact
60  * all the contributors and those who replied agreed with license
61  * change. If you did any contribution when the driver was GPLed and do
62  * not agree with the BSD-style re-licensing please contact me.
63  *  -SB
64  */
65
66 /* How often to run dgmpoll */
67 #define POLLSPERSEC 25
68
69 /* How many charactes can we write to input tty rawq */
70 #define DGB_IBUFSIZE (TTYHOG - 100)
71
72 /* the overall number of ports controlled by this driver */
73
74 #include <sys/param.h>
75
76 #include <sys/systm.h>
77 #include <sys/proc.h>
78 #include <sys/conf.h>
79 #include <sys/dkstat.h>
80 #include <sys/fcntl.h>
81 #include <sys/kernel.h>
82 #include <sys/sysctl.h>
83 #include <sys/malloc.h>
84 #include <sys/sysctl.h>
85 #include <sys/tty.h>
86 #include <sys/bus.h>
87 #include <sys/kobj.h>
88 #include <sys/bus.h>
89 #include <machine/bus.h>
90 #include <sys/rman.h>
91 #include <machine/resource.h>
92
93 #include <machine/clock.h>
94
95 #include <vm/vm.h>
96 #include <vm/pmap.h>
97
98 #include "dgmfep.h"
99 #include "dgmbios.h"
100 #include "dgmreg.h"
101
102 #define CALLOUT_MASK            0x40000
103 #define CONTROL_MASK            0xC0
104 #define CONTROL_INIT_STATE      0x40
105 #define CONTROL_LOCK_STATE      0x80
106 #define UNIT_MASK               0x30000
107 #define PORT_MASK               0x3F
108 #define DEV_TO_UNIT(dev)        (MINOR_TO_UNIT(minor(dev)))
109 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
110 #define MINOR_TO_UNIT(mynor)    (((mynor) & UNIT_MASK) >> 16)
111 #define MINOR_TO_PORT(mynor)    ((mynor) & PORT_MASK)
112 #define IO_SIZE                 0x04
113 #define MEM_SIZE                0x8000
114
115 #define DGM_UNITMASK            0x30000
116 #define DGM_UNIT(unit)          ((unit) << 16)
117
118 struct dgm_softc;
119
120 /* digiboard port structure */
121 struct dgm_p {
122         unsigned enabled : 1;
123
124         struct dgm_softc *sc;  /* parent softc */
125         u_char pnum;           /* port number */
126         u_char omodem;         /* FEP output modem status     */
127         u_char imodem;         /* FEP input modem status      */
128         u_char modemfake;      /* Modem values to be forced   */
129         u_char modem;          /* Force values                */
130         u_char hflow;
131         u_char dsr;
132         u_char dcd;
133         u_char stopc;
134         u_char startc;
135         u_char stopca;
136         u_char startca;
137         u_char fepstopc;
138         u_char fepstartc;
139         u_char fepstopca;
140         u_char fepstartca;
141         u_char txwin;
142         u_char rxwin;
143         ushort fepiflag;
144         ushort fepcflag;
145         ushort fepoflag;
146         ushort txbufhead;
147         ushort txbufsize;
148         ushort rxbufhead;
149         ushort rxbufsize;
150         int close_delay;
151         u_char *txptr;
152         u_char *rxptr;
153         volatile struct board_chan *brdchan;
154         struct tty *tty;
155
156         u_char  active_out;     /* nonzero if the callout device is open */
157         u_int   wopeners;       /* # processes waiting for DCD in open() */
158
159         /* Initial state. */
160         struct termios  it_in;  /* should be in struct tty */
161         struct termios  it_out;
162
163         /* Lock state. */
164         struct termios  lt_in;  /* should be in struct tty */
165         struct termios  lt_out;
166
167         unsigned do_timestamp : 1;
168         unsigned do_dcd_timestamp : 1;
169         struct timeval  timestamp;
170         struct timeval  dcd_timestamp;
171
172         /* flags of state, are used in sleep() too */
173         u_char closing; /* port is being closed now */
174         u_char draining; /* port is being drained now */
175         u_char used;    /* port is being used now */
176         u_char mustdrain; /* data must be waited to drain in dgmparam() */
177 };
178
179 /* Digiboard per-board structure */
180 struct dgm_softc {
181         /* struct board_info */
182         unsigned enabled : 1;
183         u_char unit;                    /* unit number */
184         u_char type;                    /* type of card: PCXE, PCXI, PCXEVE */
185         u_char altpin;                  /* do we need alternate pin setting ? */
186         int numports;                   /* number of ports on card */
187         u_long port;                    /* I/O port */
188         u_char *vmem;                   /* virtual memory address */
189         u_long pmem;                    /* physical memory address */
190         int mem_seg;                    /* internal memory segment */
191         struct dgm_p *ports;            /* ptr to array of port descriptors */
192         struct tty *ttys;               /* ptr to array of TTY structures */
193         volatile struct global_data *mailbox;
194         struct resource *io_res;
195         struct resource *mem_res;
196         int iorid;
197         int mrid;
198         struct callout  toh;            /* poll timeout handle */
199 };
200
201 static void     dgmpoll(void *);
202 static int      dgmprobe(device_t);
203 static int      dgmattach(device_t);
204 static int      dgmdetach(device_t);
205 static int      dgmshutdown(device_t);
206 static void     fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
207                     unsigned);
208 static void     dgmstart(struct tty *);
209 static void     dgmstop(struct tty *, int);
210 static int      dgmparam(struct tty *, struct termios *);
211 static void     dgmhardclose(struct dgm_p *);
212 static void     dgm_drain_or_flush(struct dgm_p *);
213 static int      dgmdrain(struct dgm_p *);
214 static void     dgm_pause(void *);
215 static void     wakeflush(void *);
216 static void     disc_optim(struct tty *, struct termios *);
217
218 static  d_open_t        dgmopen;
219 static  d_close_t       dgmclose;
220 static  d_ioctl_t       dgmioctl;
221
222 static device_method_t dgmmethods[] = {
223         /* Device interface */
224         DEVMETHOD(device_probe, dgmprobe),
225         DEVMETHOD(device_attach, dgmattach),
226         DEVMETHOD(device_detach, dgmdetach),
227         DEVMETHOD(device_shutdown, dgmshutdown),
228         { 0, 0 }
229 };
230
231 static driver_t dgmdriver = {
232         "dgm",
233         dgmmethods,
234         sizeof (struct dgm_softc),
235 };
236
237 static devclass_t dgmdevclass;
238
239 #define CDEV_MAJOR      101
240 static struct cdevsw dgm_cdevsw = {
241         /* name */      "dgm",
242         /* maj */       CDEV_MAJOR,
243         /* flags */     D_TTY | D_KQFILTER,
244         /* port */      NULL,
245         /* clone */     NULL,
246
247         /* open */      dgmopen,
248         /* close */     dgmclose,
249         /* read */      ttyread,
250         /* write */     ttywrite,
251         /* ioctl */     dgmioctl,
252         /* poll */      ttypoll,
253         /* mmap */      nommap,
254         /* strategy */  nostrategy,
255         /* dump */      nodump,
256         /* psize */     nopsize,
257         /* kqfilter */  ttykqfilter
258 };
259
260 static int
261 dgmmodhandler(module_t mod, int event, void *arg)
262 {
263         int res = 0;
264
265         switch (event) {
266         case MOD_LOAD:
267                 break;
268         case MOD_UNLOAD:
269                 break;
270         }
271
272         return res;
273 }
274
275 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
276
277 static  speed_t dgmdefaultrate = TTYDEF_SPEED;
278
279 static  struct speedtab dgmspeedtab[] = {
280         { 0,            FEP_B0 }, /* old (sysV-like) Bx codes */
281         { 50,           FEP_B50 },
282         { 75,           FEP_B75 },
283         { 110,          FEP_B110 },
284         { 134,          FEP_B134 },
285         { 150,          FEP_B150 },
286         { 200,          FEP_B200 },
287         { 300,          FEP_B300 },
288         { 600,          FEP_B600 },
289         { 1200,         FEP_B1200 },
290         { 1800,         FEP_B1800 },
291         { 2400,         FEP_B2400 },
292         { 4800,         FEP_B4800 },
293         { 9600,         FEP_B9600 },
294         { 19200,        FEP_B19200 },
295         { 38400,        FEP_B38400 },
296         { 57600,        (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
297         { 115200,       (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
298         { -1,   -1 }
299 };
300
301 static struct dbgflagtbl {
302         tcflag_t in_mask;
303         tcflag_t in_val;
304         tcflag_t out_val;
305 } dgm_cflags[] = {
306         { PARODD,   PARODD,     FEP_PARODD  },
307         { PARENB,   PARENB,     FEP_PARENB  },
308         { CSTOPB,   CSTOPB,     FEP_CSTOPB  },
309         { CSIZE,    CS5,        FEP_CS6     },
310         { CSIZE,    CS6,        FEP_CS6     },
311         { CSIZE,    CS7,        FEP_CS7     },
312         { CSIZE,    CS8,        FEP_CS8     },
313         { CLOCAL,   CLOCAL,     FEP_CLOCAL  },
314         { (tcflag_t)-1 }
315 }, dgm_iflags[] = {
316         { IGNBRK,   IGNBRK,     FEP_IGNBRK  },
317         { BRKINT,   BRKINT,     FEP_BRKINT  },
318         { IGNPAR,   IGNPAR,     FEP_IGNPAR  },
319         { PARMRK,   PARMRK,     FEP_PARMRK  },
320         { INPCK,    INPCK,      FEP_INPCK   },
321         { ISTRIP,   ISTRIP,     FEP_ISTRIP  },
322         { IXON,     IXON,       FEP_IXON    },
323         { IXOFF,    IXOFF,      FEP_IXOFF   },
324         { IXANY,    IXANY,      FEP_IXANY   },
325         { (tcflag_t)-1 }
326 }, dgm_flow[] = {
327         { CRTSCTS,  CRTSCTS,    CTS|RTS },
328         { CRTSCTS,  CCTS_OFLOW, CTS     },
329         { CRTSCTS,  CRTS_IFLOW, RTS     },
330         { (tcflag_t)-1 }
331 };
332
333 /* xlat bsd termios flags to dgm sys-v style */
334 static tcflag_t
335 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
336 {
337         tcflag_t output = 0;
338         int i;
339
340         for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
341                 if ((input & tbl[i].in_mask) == tbl[i].in_val)
342                         output |= tbl[i].out_val;
343
344         return output;
345 }
346
347 static int dgmdebug = 0;
348 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
349
350 static __inline int setwin(struct dgm_softc *, unsigned);
351 static __inline void hidewin(struct dgm_softc *);
352 static __inline void towin(struct dgm_softc *, int);
353
354 /*Helg: to allow recursive dgm...() calls */
355 typedef struct {
356         /* If we were called and don't want to disturb we need: */
357         int port;       /* write to this port */
358         u_char data;    /* this data on exit */
359         /* or DATA_WINOFF  to close memory window on entry */
360 } BoardMemWinState;     /* so several channels and even boards can coexist */
361
362 #define DATA_WINOFF 0
363 static BoardMemWinState bmws;
364
365 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
366 static u_long validmem[] = {
367         0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
368         0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
369         0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
370         0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
371         0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
372 };
373
374 /* return current memory window state and close window */
375 static BoardMemWinState
376 bmws_get(void)
377 {
378         BoardMemWinState bmwsRet = bmws;
379
380         if (bmws.data != DATA_WINOFF)
381                 outb(bmws.port, bmws.data = DATA_WINOFF);
382         return bmwsRet;
383 }
384
385 /* restore memory window state */
386 static void
387 bmws_set(BoardMemWinState ws)
388 {
389         if (ws.data != bmws.data || ws.port != bmws.port) {
390                 if (bmws.data != DATA_WINOFF)
391                         outb(bmws.port, DATA_WINOFF);
392                 if (ws.data != DATA_WINOFF)
393                         outb(ws.port, ws.data);
394                 bmws = ws;
395         }
396 }
397
398 static __inline int
399 setwin(struct dgm_softc *sc, unsigned int addr)
400 {
401         outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
402         return (addr & 0x7FFF);
403 }
404
405 static __inline void
406 hidewin(struct dgm_softc *sc)
407 {
408         bmws.data = 0;
409         outb(bmws.port = sc->port + 1, bmws.data);
410 }
411
412 static __inline void
413 towin(struct dgm_softc *sc, int win)
414 {
415         outb(bmws.port = sc->port + 1, bmws.data = win);
416 }
417
418 static int
419 dgmprobe(device_t dev)
420 {
421         struct dgm_softc *sc = device_get_softc(dev);
422         int i, v;
423
424         /*
425          * Assign unit number.  Due to bits we use in the minor number for
426          * the various tty types, only 4 units are supported.
427          */
428         sc->unit = device_get_unit(dev);
429         if (sc->unit > 3) {
430                 device_printf(dev, "Too many units, only 4 supported\n");
431                 return(ENXIO);
432         }
433
434         /* Check that we've got a valid i/o address */
435         if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
436                 return (ENXIO);
437         for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
438                 if (sc->port == validio[i])
439                         break;
440         if (i == -1) {
441                 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
442                 return (ENXIO);
443         }
444
445         /* Ditto for our memory address */
446         if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
447                 return (ENXIO);
448         for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
449                 if (sc->pmem == validmem[i])
450                         break;
451         if (i == -1) {
452                 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
453                 return (ENXIO);
454         }
455         if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
456                 device_printf(dev, "0x%lx: Memory address not supported\n",
457                     sc->pmem);
458                 return (ENXIO);
459         }
460         sc->vmem = (u_char *)sc->pmem;
461
462         DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
463             sc->port, sc->pmem);
464
465         /* Temporarily map our io ports */
466         sc->iorid = 0;
467         sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
468             0ul, ~0ul, IO_SIZE, RF_ACTIVE);
469         if (sc->io_res == NULL)
470                 return (ENXIO);
471
472         outb(sc->port, FEPRST);
473         sc->enabled = 0;
474
475         for (i = 0; i < 1000; i++) {
476                 DELAY(1);
477                 if ((inb(sc->port) & FEPMASK) == FEPRST) {
478                         sc->enabled = 1;
479                         DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
480                             sc->unit, i);
481                         break;
482                 }
483         }
484
485         if (!sc->enabled) {
486                 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
487                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
488                 return (ENXIO);
489         }
490
491         /* check type of card and get internal memory characteristics */
492
493         v = inb(sc->port);
494
495         if (!(v & 0x1)) {
496                 int second;
497
498                 outb(sc->port, 1);
499                 second = inb(sc->port);
500                 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
501         } else
502                 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
503
504         sc->type = PCXEM;
505         sc->mem_seg = 0x8000;
506
507         /* Temporarily map our memory too */
508         sc->mrid = 0;
509         sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
510             0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
511         if (sc->mem_res == NULL) {
512                 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
513                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
514                 return (ENXIO);
515         }
516
517         outb(sc->port, FEPCLR); /* drop RESET */
518         hidewin(sc);    /* Helg: to set initial bmws state */
519
520         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
521         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
522
523         bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
524         bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
525
526         DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
527
528         return (0);
529 }
530
531 static int
532 dgmattach(device_t dev)
533 {
534         struct dgm_softc *sc = device_get_softc(dev);
535         int i, t;
536         u_char *mem;
537         u_char *ptr;
538         int addr;
539         struct dgm_p *port;
540         volatile struct board_chan *bc;
541         int shrinkmem;
542         int lowwater;
543         u_long msize, iosize;
544
545         DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
546
547         callout_init(&sc->toh);
548         sc->unit = device_get_unit(dev);
549         bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
550         bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
551         sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
552         sc->type = PCXEM;
553         sc->mem_seg = 0x8000;
554         sc->enabled = 1;
555         sc->type = PCXEM;
556         sc->mem_seg = 0x8000;
557
558         /* Allocate resources (should have been verified in dgmprobe()) */
559         sc->iorid = 0;
560         sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
561             0ul, ~0ul, iosize, RF_ACTIVE);
562         if (sc->io_res == NULL)
563                 return (ENXIO);
564         sc->mrid = 0;
565         sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
566             0ul, ~0ul, msize, RF_ACTIVE);
567         if (sc->mem_res == NULL) {
568                 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
569                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
570                 return (ENXIO);
571         }
572
573         /* map memory */
574         mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
575
576         DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
577             sc->mem_seg);
578
579         outb(sc->port, FEPRST);
580         DELAY(1);
581
582         for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
583                 if (i > 10000) {
584                         device_printf(dev, "1st reset failed\n");
585                         sc->enabled = 0;
586                         hidewin(sc);
587                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
588                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
589                         return (ENXIO);
590                 }
591                 DELAY(1);
592         }
593
594         DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
595
596         t = sc->pmem >> 8;      /* disable windowing */
597         outb(sc->port + 2, t & 0xFF);
598         outb(sc->port + 3, t >> 8);
599
600         mem = sc->vmem;
601
602         /* very short memory test */
603         DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
604
605         addr = setwin(sc, BOTWIN);
606         *(u_long *)(mem + addr) = 0xA55A3CC3;
607         if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
608                 device_printf(dev, "1st memory test failed\n");
609                 sc->enabled = 0;
610                 hidewin(sc);
611                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
612                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
613                 return (ENXIO);
614         }
615
616         DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
617
618         addr = setwin(sc, TOPWIN);
619         *(u_long *)(mem + addr) = 0x5AA5C33C;
620         if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
621                 device_printf(dev, "2nd memory test failed\n");
622                 sc->enabled = 0;
623                 hidewin(sc);
624                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
625                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
626                 return (ENXIO);
627         }
628
629         DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
630
631         addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
632         *(u_long *)(mem + addr) = 0x5AA5C33C;
633         if (*(u_long *)(mem + addr) != 0x5AA5C33C)
634                 device_printf(dev, "3rd (BIOS) memory test failed\n");
635
636         DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
637
638         addr = setwin(sc, MISCGLOBAL);
639         for (i = 0; i < 16; i++)
640                 mem[addr + i] = 0;
641
642         addr = setwin(sc, BIOSOFFSET);
643         ptr = mem + addr;
644         for (i = 0; ptr < mem + msize; i++)
645                 *ptr++ = pcem_bios[i];
646
647         ptr = mem + BIOSOFFSET;
648         for (i = 0; ptr < mem + msize; i++) {
649                 if (*ptr++ != pcem_bios[i]) {
650                         printf("Low BIOS load failed\n");
651                         sc->enabled = 0;
652                         hidewin(sc);
653                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
654                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
655                         return (ENXIO);
656                 }
657         }
658         DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
659
660         addr = setwin(sc, msize);
661         ptr = mem + addr;
662         for (;i < pcem_nbios; i++)
663                 *ptr++ = pcem_bios[i];
664
665         ptr = mem;
666         for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
667                 if (*ptr++ != pcem_bios[i]) {
668                         printf("High BIOS load failed\n");
669                         sc->enabled = 0;
670                         hidewin(sc);
671                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
672                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
673                         return (ENXIO);
674                 }
675         }
676         DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
677         device_printf(dev, "DigiBIOS loaded, initializing");
678
679         addr = setwin(sc, 0);
680
681         *(u_int *)(mem + addr) = 0x0bf00401;
682         *(u_int *)(mem + addr + 4) = 0;
683         *(ushort *)(mem + addr + 0xc00) = 0;
684         outb(sc->port, 0);
685
686         for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
687                 DELAY(10000);
688                 if (i > 3000) {
689                         printf("\nBIOS initialize failed(1)\n");
690                         sc->enabled = 0;
691                         hidewin(sc);
692                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
693                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
694                         return (ENXIO);
695                 }
696         }
697
698         if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
699                 printf("\nBIOS initialize failed(2)\n");
700                 sc->enabled = 0;
701                 hidewin(sc);
702                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
703                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
704                 return (ENXIO);
705         }
706         printf(", DigiBIOS running\n");
707
708         DELAY(10000);
709
710         addr = setwin(sc, BIOSOFFSET);
711         ptr = mem + addr;
712         for (i = 0; i < pcem_ncook; i++)
713                 *ptr++ = pcem_cook[i];
714
715         ptr = mem + BIOSOFFSET;
716         for (i = 0; i < pcem_ncook; i++) {
717                 if (*ptr++ != pcem_cook[i]) {
718                         printf("FEP/OS load failed\n");
719                         sc->enabled = 0;
720                         hidewin(sc);
721                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
722                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
723                         return (ENXIO);
724                 }
725         }
726         device_printf(dev, "FEP/OS loaded, initializing");
727
728         addr = setwin(sc, 0);
729         *(ushort *)(mem + addr + 0xd20) = 0;
730         *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
731         *(u_int *)(mem + addr + 0xc30) = 0x3L;
732         outb(sc->port, 0);
733
734         for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
735                 DELAY(10000);
736                 if (i > 3000) {
737                         printf("\nFEP/OS initialize failed(1)\n");
738                         sc->enabled = 0;
739                         hidewin(sc);
740                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
741                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
742                         return (ENXIO);
743                 }
744         }
745
746         if (*(u_char *)(mem + addr + 0xd21) != 'S') {
747                 printf("\nFEP/OS initialize failed(2)\n");
748                 sc->enabled = 0;
749                 hidewin(sc);
750                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
751                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
752                 return (ENXIO);
753         }
754         printf(", FEP/OS running\n");
755
756         sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
757         device_printf(dev, "%d ports attached\n", sc->numports);
758
759         if (sc->numports > MAX_DGM_PORTS) {
760                 printf("dgm%d: too many ports\n", sc->unit);
761                 sc->enabled = 0;
762                 hidewin(sc);
763                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
764                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
765                 return (ENXIO);
766         }
767
768         MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
769             M_TTYS, M_WAITOK|M_ZERO);
770         MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
771             M_TTYS, M_WAITOK|M_ZERO);
772
773         DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
774         for (i = 0; i < sc->numports; i++)
775                 sc->ports[i].enabled = 1;
776
777         /* We should now init per-port structures */
778         setwin(sc, 0);
779         bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
780         sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
781
782         if (sc->numports < 3)
783                 shrinkmem = 1;
784         else
785                 shrinkmem = 0;
786
787         cdevsw_add(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
788         for (i = 0; i < sc->numports; i++, bc++) {
789                 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
790                 port = &sc->ports[i];
791                 port->sc = sc;
792
793                 port->tty = &sc->ttys[i];
794
795                 port->brdchan = bc;
796
797                 port->dcd = CD;
798                 port->dsr = DSR;
799                 port->pnum = i;
800
801                 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
802                 if (shrinkmem) {
803                         DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
804                         fepcmd(port, SETBUFFER, 32, 0, 0, 0);
805                         shrinkmem = 0;
806                 }
807
808                 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
809                 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
810                 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
811                 port->txwin = FEPWIN | (bc->tseg >> 11);
812                 port->rxwin = FEPWIN | (bc->rseg >> 11);
813
814                 port->txbufhead = 0;
815                 port->rxbufhead = 0;
816                 port->txbufsize = bc->tmax + 1;
817                 port->rxbufsize = bc->rmax + 1;
818
819                 lowwater = (port->txbufsize >= 2000) ?
820                     1024 : (port->txbufsize / 2);
821
822                 setwin(sc, 0);
823                 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
824                     sc->unit, i, lowwater);
825                 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
826                 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
827                     sc->unit, i, port->rxbufsize / 4);
828                 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
829                 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
830                     sc->unit, i, 3 * port->rxbufsize / 4);
831                 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
832
833                 bc->edelay = 100;
834                 bc->idata = 1;
835
836                 port->startc = bc->startc;
837                 port->startca = bc->startca;
838                 port->stopc = bc->stopc;
839                 port->stopca = bc->stopca;
840
841                 /* port->close_delay = 50; */
842                 port->close_delay = 3 * hz;
843                 port->do_timestamp = 0;
844                 port->do_dcd_timestamp = 0;
845
846                 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
847                 /*
848                  * We don't use all the flags from <sys/ttydefaults.h> since
849                  * they are only relevant for logins.  It's important to have
850                  * echo off initially so that the line doesn't start
851                  * blathering before the echo flag can be turned off.
852                  */
853                 port->it_in.c_iflag = TTYDEF_IFLAG;
854                 port->it_in.c_oflag = TTYDEF_OFLAG;
855                 port->it_in.c_cflag = TTYDEF_CFLAG;
856                 port->it_in.c_lflag = TTYDEF_LFLAG;
857                 termioschars(&port->it_in);
858                 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
859                 port->it_out = port->it_in;
860
861                 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
862                 make_dev(&dgm_cdevsw, (sc->unit*65536) + i, UID_ROOT,
863                     GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
864                 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 64, UID_ROOT,
865                     GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
866                 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 128, UID_ROOT,
867                     GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
868                 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262144, UID_UUCP,
869                     GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
870                 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262208, UID_UUCP,
871                     GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
872                 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262272, UID_UUCP,
873                     GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
874         }
875
876         DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
877
878         hidewin(sc);
879
880         /* start the polling function */
881         callout_reset(&sc->toh, hz / POLLSPERSEC,
882                         dgmpoll, (void *)(int)sc->unit);
883
884         DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
885
886         return (0);
887 }
888
889 static int
890 dgmdetach(device_t dev)
891 {
892         struct dgm_softc *sc = device_get_softc(dev);
893         int i;
894
895         for (i = 0; i < sc->numports; i++)
896                 if (sc->ttys[i].t_state & TS_ISOPEN)
897                         return (EBUSY);
898
899         DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
900
901         /*
902          * The cdevsw_remove() call will destroy all associated devices
903          * and dereference any ad-hoc-created devices, but does not
904          * dereference devices created via make_dev().
905          */
906         cdevsw_remove(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
907
908         callout_stop(&sc->toh);
909
910         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
911         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
912
913         FREE(sc->ports, M_TTYS);
914         FREE(sc->ttys, M_TTYS);
915
916         return (0);
917 }
918
919 int
920 dgmshutdown(device_t dev)
921 {
922 #ifdef DEBUG
923         struct dgm_softc *sc = device_get_softc(dev);
924
925         DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
926 #endif
927
928         return 0;
929 }
930
931 /* ARGSUSED */
932 static int
933 dgmopen(dev_t dev, int flag, int mode, struct thread *td)
934 {
935         struct dgm_softc *sc;
936         struct tty *tp;
937         int unit;
938         int mynor;
939         int pnum;
940         struct dgm_p *port;
941         int s, cs;
942         int error;
943         volatile struct board_chan *bc;
944
945         error = 0;
946         mynor = minor(dev);
947         unit = MINOR_TO_UNIT(mynor);
948         pnum = MINOR_TO_PORT(mynor);
949
950         sc = devclass_get_softc(dgmdevclass, unit);
951         if (sc == NULL) {
952                 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
953                     unit);
954                 return ENXIO;
955         }
956
957         DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
958
959         if (!sc->enabled) {
960                 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
961                     unit);
962                 return ENXIO;
963         }
964
965         if (pnum >= sc->numports) {
966                 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
967                     unit, pnum);
968                 return ENXIO;
969         }
970
971         if (mynor & CONTROL_MASK)
972                 return 0;
973
974         tp = &sc->ttys[pnum];
975         dev->si_tty = tp;
976         port = &sc->ports[pnum];
977         bc = port->brdchan;
978
979 open_top:
980         s = spltty();
981
982         while (port->closing) {
983                 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
984
985                 if (error) {
986                         DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
987                             " error = %d\n", unit, pnum, error);
988                         goto out;
989                 }
990         }
991
992         if (tp->t_state & TS_ISOPEN) {
993                 /*
994                  * The device is open, so everything has been initialized.
995                  * Handle conflicts.
996                  */
997                 if (mynor & CALLOUT_MASK) {
998                         if (!port->active_out) {
999                                 error = EBUSY;
1000                                 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1001                                     " BUSY error = %d\n", unit, pnum, error);
1002                                 goto out;
1003                         }
1004                 } else if (port->active_out) {
1005                         if (flag & O_NONBLOCK) {
1006                                 error = EBUSY;
1007                                 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1008                                     " BUSY error = %d\n", unit, pnum, error);
1009                                 goto out;
1010                         }
1011                         error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1012                         if (error != 0) {
1013                                 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1014                                     " error = %d\n", unit, pnum, error);
1015                                 goto out;
1016                         }
1017                         splx(s);
1018                         goto open_top;
1019                 }
1020                 if (tp->t_state & TS_XCLUDE && suser(td)) {
1021                         error = EBUSY;
1022                         goto out;
1023                 }
1024         } else {
1025                 /*
1026                  * The device isn't open, so there are no conflicts.
1027                  * Initialize it.  Initialization is done twice in many
1028                  * cases: to preempt sleeping callin opens if we are
1029                  * callout, and to complete a callin open after DCD rises.
1030                  */
1031                 tp->t_oproc = dgmstart;
1032                 tp->t_param = dgmparam;
1033                 tp->t_stop = dgmstop;
1034                 tp->t_dev = dev;
1035                 tp->t_termios= (mynor & CALLOUT_MASK) ?
1036                                                         port->it_out :
1037                                                         port->it_in;
1038
1039                 cs = splclock();
1040                 setwin(sc, 0);
1041                 port->imodem = bc->mstat;
1042                 bc->rout = bc->rin; /* clear input queue */
1043                 bc->idata = 1;
1044 #ifdef PRINT_BUFSIZE
1045                 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1046                     bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1047 #endif
1048
1049                 hidewin(sc);
1050                 splx(cs);
1051
1052                 port->wopeners++;
1053                 error = dgmparam(tp, &tp->t_termios);
1054                 port->wopeners--;
1055
1056                 if (error != 0) {
1057                         DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1058                             unit, pnum, error);
1059                         goto out;
1060                 }
1061
1062                 /* handle fake DCD for callout devices */
1063                 /* and initial DCD */
1064
1065                 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1066                         linesw[tp->t_line].l_modem(tp, 1);
1067         }
1068
1069         /*
1070          * Wait for DCD if necessary.
1071          */
1072         if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1073             && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1074                 ++port->wopeners;
1075                 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1076                 --port->wopeners;
1077                 if (error != 0) {
1078                         DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1079                             " error = %d\n", unit, pnum, error);
1080                         goto out;
1081                 }
1082                 splx(s);
1083                 goto open_top;
1084         }
1085         error = linesw[tp->t_line].l_open(dev, tp);
1086         disc_optim(tp, &tp->t_termios);
1087         DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1088             unit, pnum, error);
1089
1090         if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1091                 port->active_out = 1;
1092
1093         port->used = 1;
1094
1095         /* If any port is open (i.e. the open() call is completed for it)
1096          * the device is busy
1097          */
1098
1099 out:
1100         disc_optim(tp, &tp->t_termios);
1101         splx(s);
1102
1103         if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1104                 dgmhardclose(port);
1105
1106         DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1107             unit, pnum, error);
1108
1109         return error;
1110 }
1111
1112 /*ARGSUSED*/
1113 static int
1114 dgmclose(dev_t dev, int flag, int mode, struct thread *td)
1115 {
1116         int             mynor;
1117         struct tty      *tp;
1118         int unit, pnum;
1119         struct dgm_softc *sc;
1120         struct dgm_p *port;
1121         int s;
1122         int i;
1123
1124         mynor = minor(dev);
1125         if (mynor & CONTROL_MASK)
1126                 return 0;
1127         unit = MINOR_TO_UNIT(mynor);
1128         pnum = MINOR_TO_PORT(mynor);
1129
1130         sc = devclass_get_softc(dgmdevclass, unit);
1131         tp = &sc->ttys[pnum];
1132         port = sc->ports + pnum;
1133
1134         DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1135
1136         DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1137         dgm_drain_or_flush(port);
1138
1139         s = spltty();
1140
1141         port->closing = 1;
1142         DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1143         linesw[tp->t_line].l_close(tp, flag);
1144         disc_optim(tp, &tp->t_termios);
1145
1146         DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1147         dgmhardclose(port);
1148         DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1149         ttyclose(tp);
1150         port->closing = 0;
1151         wakeup(&port->closing);
1152         port->used = 0;
1153
1154         /* mark the card idle when all ports are closed */
1155
1156         for (i = 0; i < sc->numports; i++)
1157                 if (sc->ports[i].used)
1158                         break;
1159
1160         splx(s);
1161
1162         DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1163
1164         wakeup(TSA_CARR_ON(tp));
1165         wakeup(&port->active_out);
1166         port->active_out = 0;
1167
1168         DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1169
1170         return 0;
1171 }
1172
1173 static void
1174 dgmhardclose(struct dgm_p *port)
1175 {
1176         volatile struct board_chan *bc = port->brdchan;
1177         struct dgm_softc *sc;
1178         int cs;
1179
1180         sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1181         DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1182         cs = splclock();
1183         port->do_timestamp = 0;
1184         setwin(sc, 0);
1185
1186         bc->idata = 0;
1187         bc->iempty = 0;
1188         bc->ilow = 0;
1189         if (port->tty->t_cflag & HUPCL) {
1190                 port->omodem &= ~(RTS|DTR);
1191                 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1192         }
1193
1194         hidewin(sc);
1195         splx(cs);
1196
1197         timeout(dgm_pause, &port->brdchan, hz/2);
1198         tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1199 }
1200
1201 static void
1202 dgm_pause(void *chan)
1203 {
1204         wakeup((caddr_t)chan);
1205 }
1206
1207 static void
1208 dgmpoll(void *unit_c)
1209 {
1210         int unit = (int)unit_c;
1211         int pnum;
1212         struct dgm_p *port;
1213         struct dgm_softc *sc;
1214         int head, tail;
1215         u_char *eventbuf;
1216         int event, mstat, lstat;
1217         volatile struct board_chan *bc;
1218         struct tty *tp;
1219         int rhead, rtail;
1220         int whead, wtail;
1221         int size;
1222         u_char *ptr;
1223         int ocount;
1224         int ibuf_full, obuf_full;
1225         BoardMemWinState ws = bmws_get();
1226
1227         sc = devclass_get_softc(dgmdevclass, unit);
1228         DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1229
1230         if (!sc->enabled) {
1231                 printf("dgm%d: polling of disabled board stopped\n", unit);
1232                 return;
1233         }
1234
1235         setwin(sc, 0);
1236
1237         head = sc->mailbox->ein;
1238         tail = sc->mailbox->eout;
1239
1240         while (head != tail) {
1241                 if (head >= FEP_IMAX - FEP_ISTART
1242                 || tail >= FEP_IMAX - FEP_ISTART
1243                 || (head|tail) & 03 ) {
1244                         printf("dgm%d: event queue's head or tail is wrong!"
1245                             " hd = %d, tl = %d\n", unit, head, tail);
1246                         break;
1247                 }
1248
1249                 eventbuf = sc->vmem + tail + FEP_ISTART;
1250                 pnum = eventbuf[0];
1251                 event = eventbuf[1];
1252                 mstat = eventbuf[2];
1253                 lstat = eventbuf[3];
1254
1255                 port = &sc->ports[pnum];
1256                 bc = port->brdchan;
1257                 tp = &sc->ttys[pnum];
1258
1259                 if (pnum >= sc->numports || !port->enabled) {
1260                         printf("dgm%d: port%d: got event on nonexisting port\n",
1261                             unit, pnum);
1262                 } else if (port->used || port->wopeners > 0 ) {
1263
1264                         int wrapmask = port->rxbufsize - 1;
1265
1266                         if (!(event & ALL_IND))
1267                                 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1268                                         unit, pnum, event, mstat, lstat);
1269
1270                         if (event & DATA_IND) {
1271                                 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1272                                     unit, pnum);
1273
1274                                 rhead = bc->rin & wrapmask;
1275                                 rtail = bc->rout & wrapmask;
1276
1277                                 if (!(tp->t_cflag & CREAD) || !port->used ) {
1278                                         bc->rout = rhead;
1279                                         goto end_of_data;
1280                                 }
1281
1282                                 if (bc->orun) {
1283                                         printf("dgm%d: port%d: overrun\n", unit, pnum);
1284                                         bc->orun = 0;
1285                                 }
1286
1287                                 if (!(tp->t_state & TS_ISOPEN))
1288                                         goto end_of_data;
1289
1290                                 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1291                                         DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1292                                             " p rx head = %d tail = %d\n", unit,
1293                                             pnum, rhead, rtail);
1294
1295                                         if (rhead > rtail)
1296                                                 size = rhead - rtail;
1297                                         else
1298                                                 size = port->rxbufsize - rtail;
1299
1300                                         ptr = port->rxptr + rtail;
1301
1302 /* Helg: */
1303                                         if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1304                                                 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1305                                                 DPRINT1(DB_RXDATA, "*");
1306                                                 ibuf_full = TRUE;
1307                                         }
1308
1309                                         if (size) {
1310                                                 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1311                                                         DPRINT1(DB_RXDATA, "!");
1312                                                         towin(sc, port->rxwin);
1313                                                         tk_nin += size;
1314                                                         tk_rawcc += size;
1315                                                         tp->t_rawcc += size;
1316                                                         b_to_q(ptr, size,
1317                                                             &tp->t_rawq);
1318                                                         setwin(sc, 0);
1319                                                 } else {
1320                                                         int i = size;
1321                                                         unsigned char chr;
1322                                                         do {
1323                                                                 towin(sc, port->rxwin);
1324                                                                 chr = *ptr++;
1325                                                                 hidewin(sc);
1326                                                                (*linesw[tp->t_line].l_rint)(chr, tp);
1327                                                         } while (--i > 0 );
1328                                                         setwin(sc, 0);
1329                                                 }
1330                                         }
1331                                         rtail= (rtail + size) & wrapmask;
1332                                         bc->rout = rtail;
1333                                         rhead = bc->rin & wrapmask;
1334                                         hidewin(sc);
1335                                         ttwakeup(tp);
1336                                         setwin(sc, 0);
1337                                 }
1338                         end_of_data: ;
1339                         }
1340
1341                         if (event & MODEMCHG_IND) {
1342                                 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1343                                     "MODEMCHG_IND\n", unit, pnum);
1344                                 port->imodem = mstat;
1345                                 if (mstat & port->dcd) {
1346                                         hidewin(sc);
1347                                         linesw[tp->t_line].l_modem(tp, 1);
1348                                         setwin(sc, 0);
1349                                         wakeup(TSA_CARR_ON(tp));
1350                                 } else {
1351                                         hidewin(sc);
1352                                         linesw[tp->t_line].l_modem(tp, 0);
1353                                         setwin(sc, 0);
1354                                         if (port->draining) {
1355                                                 port->draining = 0;
1356                                                 wakeup(&port->draining);
1357                                         }
1358                                 }
1359                         }
1360
1361                         if (event & BREAK_IND) {
1362                                 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK))        {
1363                                         DPRINT3(DB_BREAK, "dgm%d: port%d:"
1364                                             " BREAK_IND\n", unit, pnum);
1365                                         hidewin(sc);
1366                                         linesw[tp->t_line].l_rint(TTY_BI, tp);
1367                                         setwin(sc, 0);
1368                                 }
1369                         }
1370
1371 /* Helg: with output flow control */
1372
1373                         if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1374                                 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1375                                     " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1376
1377                                 if ((event & EMPTYTX_IND ) &&
1378                                     tp->t_outq.c_cc == 0 && port->draining) {
1379                                         port->draining = 0;
1380                                         wakeup(&port->draining);
1381                                         bc->ilow = 0;
1382                                         bc->iempty = 0;
1383                                 } else {
1384
1385                                         int wrapmask = port->txbufsize - 1;
1386
1387                                         for (obuf_full = FALSE;
1388                                             tp->t_outq.c_cc != 0 && !obuf_full;
1389                                             ) {
1390                                                 int s;
1391                                                 /* add "last-minute" data to write buffer */
1392                                                 if (!(tp->t_state & TS_BUSY)) {
1393                                                         hidewin(sc);
1394 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
1395                                                         ttwwakeup(tp);
1396 #else
1397                                                         if (tp->t_outq.c_cc <= tp->t_lowat) {
1398                                                                 if (tp->t_state & TS_ASLEEP) {
1399                                                                         tp->t_state &= ~TS_ASLEEP;
1400                                                                         wakeup(TSA_OLOWAT(tp));
1401                                                                 }
1402                                                                 /* selwakeup(&tp->t_wsel); */
1403                                                         }
1404 #endif
1405                                                         setwin(sc, 0);
1406                                                 }
1407                                                 s = spltty();
1408
1409                                         whead = bc->tin & wrapmask;
1410                                         wtail = bc->tout & wrapmask;
1411
1412                                         if (whead < wtail)
1413                                                 size = wtail - whead - 1;
1414                                         else {
1415                                                 size = port->txbufsize - whead;
1416                                                 if (wtail == 0)
1417                                                         size--;
1418                                         }
1419
1420                                         if (size == 0) {
1421                                                 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1422                                                         whead, wtail, size, obuf_full);
1423                                                 bc->iempty = 1;
1424                                                 bc->ilow = 1;
1425                                                 obuf_full = TRUE;
1426                                                 splx(s);
1427                                                 break;
1428                                         }
1429
1430                                         towin(sc, port->txwin);
1431
1432                                         ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1433                                         whead += ocount;
1434
1435                                         setwin(sc, 0);
1436                                         bc->tin = whead;
1437                                         bc->tin = whead & wrapmask;
1438                                         splx(s);
1439                                 }
1440
1441                                 if (obuf_full) {
1442                                         DPRINT1(DB_WR, " +BUSY\n");
1443                                         tp->t_state |= TS_BUSY;
1444                                 } else {
1445                                         DPRINT1(DB_WR, " -BUSY\n");
1446                                         hidewin(sc);
1447 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
1448                                         /* should clear TS_BUSY before ttwwakeup */
1449                                         if (tp->t_state & TS_BUSY)      {
1450                                                 tp->t_state &= ~TS_BUSY;
1451                                                 linesw[tp->t_line].l_start(tp);
1452                                                 ttwwakeup(tp);
1453                                         }
1454 #else
1455                                 if (tp->t_state & TS_ASLEEP) {
1456                                         tp->t_state &= ~TS_ASLEEP;
1457                                         wakeup(TSA_OLOWAT(tp));
1458                                 }
1459                                 tp->t_state &= ~TS_BUSY;
1460 #endif
1461                                         setwin(sc, 0);
1462                                         }
1463                                 }
1464                         }
1465                         bc->idata = 1;   /* require event on incoming data */
1466
1467                 } else {
1468                         bc = port->brdchan;
1469                         DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1470                                 unit, pnum, event);
1471                         bc->rout = bc->rin;
1472                         bc->idata = bc->iempty = bc->ilow = 0;
1473                 }
1474
1475                 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1476         }
1477
1478         sc->mailbox->eout = tail;
1479         bmws_set(ws);
1480
1481         callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1482
1483         DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1484 }
1485
1486 static int
1487 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1488 {
1489         struct dgm_softc *sc;
1490         int unit, pnum;
1491         struct dgm_p *port;
1492         int mynor;
1493         struct tty *tp;
1494         volatile struct board_chan *bc;
1495         int error;
1496         int s, cs;
1497         int tiocm_xxx;
1498
1499 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1500         u_long          oldcmd;
1501         struct termios  term;
1502 #endif
1503
1504         BoardMemWinState ws = bmws_get();
1505
1506         mynor = minor(dev);
1507         unit = MINOR_TO_UNIT(mynor);
1508         pnum = MINOR_TO_PORT(mynor);
1509
1510         sc = devclass_get_softc(dgmdevclass, unit);
1511         port = &sc->ports[pnum];
1512         tp = &sc->ttys[pnum];
1513         bc = port->brdchan;
1514
1515         if (mynor & CONTROL_MASK) {
1516                 struct termios *ct;
1517
1518                 switch (mynor & CONTROL_MASK) {
1519                 case CONTROL_INIT_STATE:
1520                         ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1521                         break;
1522                 case CONTROL_LOCK_STATE:
1523                         ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1524                         break;
1525                 default:
1526                         return (ENODEV);        /* /dev/nodev */
1527                 }
1528                 switch (cmd) {
1529                 case TIOCSETA:
1530                         error = suser(td);
1531                         if (error != 0)
1532                                 return (error);
1533                         *ct = *(struct termios *)data;
1534                         return (0);
1535                 case TIOCGETA:
1536                         *(struct termios *)data = *ct;
1537                         return (0);
1538                 case TIOCGETD:
1539                         *(int *)data = TTYDISC;
1540                         return (0);
1541                 case TIOCGWINSZ:
1542                         bzero(data, sizeof(struct winsize));
1543                         return (0);
1544                 default:
1545                         return (ENOTTY);
1546                 }
1547         }
1548
1549 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1550         term = tp->t_termios;
1551         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1552           DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-ISNOW c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, term.c_cflag, term.c_iflag, term.c_lflag);
1553         }
1554         oldcmd = cmd;
1555         error = ttsetcompat(tp, &cmd, data, &term);
1556         if (error != 0)
1557                 return (error);
1558         if (cmd != oldcmd)
1559                 data = (caddr_t)&term;
1560 #endif
1561
1562         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1563                 int     cc;
1564                 struct termios *dt = (struct termios *)data;
1565                 struct termios *lt = mynor & CALLOUT_MASK
1566                                      ? &port->lt_out : &port->lt_in;
1567
1568                 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-TOSET c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, dt->c_cflag, dt->c_iflag, dt->c_lflag);
1569                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1570                               | (dt->c_iflag & ~lt->c_iflag);
1571                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1572                               | (dt->c_oflag & ~lt->c_oflag);
1573                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1574                               | (dt->c_cflag & ~lt->c_cflag);
1575                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1576                               | (dt->c_lflag & ~lt->c_lflag);
1577                 for (cc = 0; cc < NCCS; ++cc)
1578                         if (lt->c_cc[cc] != 0)
1579                                 dt->c_cc[cc] = tp->t_cc[cc];
1580                 if (lt->c_ispeed != 0)
1581                         dt->c_ispeed = tp->t_ispeed;
1582                 if (lt->c_ospeed != 0)
1583                         dt->c_ospeed = tp->t_ospeed;
1584         }
1585
1586         if (cmd == TIOCSTOP) {
1587                 cs = splclock();
1588                 setwin(sc, 0);
1589                 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1590                 bmws_set(ws);
1591                 splx(cs);
1592                 return 0;
1593         } else if (cmd == TIOCSTART) {
1594                 cs = splclock();
1595                 setwin(sc, 0);
1596                 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1597                 bmws_set(ws);
1598                 splx(cs);
1599                 return 0;
1600         }
1601
1602         if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1603                 port->mustdrain = 1;
1604
1605         error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
1606         if (error != ENOIOCTL)
1607                 return error;
1608         s = spltty();
1609         error = ttioctl(tp, cmd, data, flag);
1610         disc_optim(tp, &tp->t_termios);
1611         port->mustdrain = 0;
1612         if (error != ENOIOCTL) {
1613                 splx(s);
1614                 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1615                         DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-RES c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, tp->t_cflag, tp->t_iflag, tp->t_lflag);
1616                 }
1617                 return error;
1618         }
1619
1620         switch (cmd) {
1621         case TIOCSBRK:
1622 #if 0
1623                 error = dgmdrain(port);
1624
1625                 if (error != 0) {
1626                         splx(s);
1627                         return error;
1628                 }
1629 #endif
1630
1631                 cs = splclock();
1632                 setwin(sc, 0);
1633
1634                 /* now it sends 400 millisecond break because I don't know */
1635                 /* how to send an infinite break */
1636
1637                 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1638                 hidewin(sc);
1639                 splx(cs);
1640                 break;
1641         case TIOCCBRK:
1642                 /* now it's empty */
1643                 break;
1644         case TIOCSDTR:
1645                 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1646                 port->omodem |= DTR;
1647                 cs = splclock();
1648                 setwin(sc, 0);
1649                 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1650
1651                 if (!(bc->mstat & DTR))
1652                         DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1653
1654                 hidewin(sc);
1655                 splx(cs);
1656                 break;
1657         case TIOCCDTR:
1658                 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1659                 port->omodem &= ~DTR;
1660                 cs = splclock();
1661                 setwin(sc, 0);
1662                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1663
1664                 if (bc->mstat & DTR) {
1665                         DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1666                 }
1667
1668                 hidewin(sc);
1669                 splx(cs);
1670                 break;
1671         case TIOCMSET:
1672                 if (*(int *)data & TIOCM_DTR)
1673                         port->omodem |= DTR;
1674                 else
1675                         port->omodem &= ~DTR;
1676
1677                 if (*(int *)data & TIOCM_RTS)
1678                         port->omodem |= RTS;
1679                 else
1680                         port->omodem &= ~RTS;
1681
1682                 cs = splclock();
1683                 setwin(sc, 0);
1684                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1685                 hidewin(sc);
1686                 splx(cs);
1687                 break;
1688         case TIOCMBIS:
1689                 if (*(int *)data & TIOCM_DTR)
1690                         port->omodem |= DTR;
1691
1692                 if (*(int *)data & TIOCM_RTS)
1693                         port->omodem |= RTS;
1694
1695                 cs = splclock();
1696                 setwin(sc, 0);
1697                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1698                 hidewin(sc);
1699                 splx(cs);
1700                 break;
1701         case TIOCMBIC:
1702                 if (*(int *)data & TIOCM_DTR)
1703                         port->omodem &= ~DTR;
1704
1705                 if (*(int *)data & TIOCM_RTS)
1706                         port->omodem &= ~RTS;
1707
1708                 cs = splclock();
1709                 setwin(sc, 0);
1710                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1711                 hidewin(sc);
1712                 splx(cs);
1713                 break;
1714         case TIOCMGET:
1715                 setwin(sc, 0);
1716                 port->imodem = bc->mstat;
1717                 hidewin(sc);
1718
1719                 tiocm_xxx = TIOCM_LE;   /* XXX - always enabled while open */
1720
1721                 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1722
1723                 if (port->imodem & DTR) {
1724                         DPRINT1(DB_MODEM, "DTR ");
1725                         tiocm_xxx |= TIOCM_DTR;
1726                 }
1727                 if (port->imodem & RTS) {
1728                         DPRINT1(DB_MODEM, "RTS ");
1729                         tiocm_xxx |= TIOCM_RTS;
1730                 }
1731                 if (port->imodem & CTS) {
1732                         DPRINT1(DB_MODEM, "CTS ");
1733                         tiocm_xxx |= TIOCM_CTS;
1734                 }
1735                 if (port->imodem & port->dcd) {
1736                         DPRINT1(DB_MODEM, "DCD ");
1737                         tiocm_xxx |= TIOCM_CD;
1738                 }
1739                 if (port->imodem & port->dsr) {
1740                         DPRINT1(DB_MODEM, "DSR ");
1741                         tiocm_xxx |= TIOCM_DSR;
1742                 }
1743                 if (port->imodem & RI) {
1744                         DPRINT1(DB_MODEM, "RI ");
1745                         tiocm_xxx |= TIOCM_RI;
1746                 }
1747                 *(int *)data = tiocm_xxx;
1748                 DPRINT1(DB_MODEM, "--\n");
1749                 break;
1750         case TIOCMSDTRWAIT:
1751                 /* must be root since the wait applies to following logins */
1752                 error = suser(td);
1753                 if (error != 0) {
1754                         splx(s);
1755                         return (error);
1756                 }
1757                 port->close_delay = *(int *)data * hz / 100;
1758                 break;
1759         case TIOCMGDTRWAIT:
1760                 *(int *)data = port->close_delay * 100 / hz;
1761                 break;
1762         case TIOCTIMESTAMP:
1763                 port->do_timestamp = 1;
1764                 *(struct timeval *)data = port->timestamp;
1765                 break;
1766         case TIOCDCDTIMESTAMP:
1767                 port->do_dcd_timestamp = 1;
1768                 *(struct timeval *)data = port->dcd_timestamp;
1769                 break;
1770         default:
1771                 bmws_set(ws);
1772                 splx(s);
1773                 return ENOTTY;
1774         }
1775         bmws_set(ws);
1776         splx(s);
1777
1778         return 0;
1779 }
1780
1781 static void
1782 wakeflush(void *p)
1783 {
1784         struct dgm_p *port = p;
1785
1786         wakeup(&port->draining);
1787 }
1788
1789 /* wait for the output to drain */
1790
1791 static int
1792 dgmdrain(struct dgm_p *port)
1793 {
1794         volatile struct board_chan *bc = port->brdchan;
1795         struct dgm_softc *sc;
1796         int error;
1797         int head, tail;
1798         BoardMemWinState ws = bmws_get();
1799
1800         sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1801
1802         setwin(sc, 0);
1803
1804         bc->iempty = 1;
1805         tail = bc->tout;
1806         head = bc->tin;
1807
1808         while (tail != head) {
1809                 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1810                         port->sc->unit, port->pnum, head, tail);
1811
1812                 hidewin(sc);
1813                 port->draining = 1;
1814                 timeout(wakeflush, port, hz);
1815                 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1816                 port->draining = 0;
1817                 setwin(sc, 0);
1818
1819                 if (error != 0) {
1820                         DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1821                                 port->sc->unit, port->pnum, error);
1822
1823                         bc->iempty = 0;
1824                         bmws_set(ws);
1825                         return error;
1826                 }
1827
1828                 tail = bc->tout;
1829                 head = bc->tin;
1830         }
1831         DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1832                 port->sc->unit, port->pnum, head, tail);
1833         bmws_set(ws);
1834         return 0;
1835 }
1836
1837 /* wait for the output to drain */
1838 /* or simply clear the buffer it it's stopped */
1839
1840 static void
1841 dgm_drain_or_flush(struct dgm_p *port)
1842 {
1843         volatile struct board_chan *bc = port->brdchan;
1844         struct tty *tp = port->tty;
1845         struct dgm_softc *sc;
1846         int error;
1847         int lasttail;
1848         int head, tail;
1849
1850         sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1851         setwin(sc, 0);
1852
1853         lasttail = -1;
1854         bc->iempty = 1;
1855         tail = bc->tout;
1856         head = bc->tin;
1857
1858         while (tail != head /* && tail != lasttail */ ) {
1859                 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1860                         port->sc->unit, port->pnum, head, tail);
1861
1862                 /* if there is no carrier simply clean the buffer */
1863                 if (!(tp->t_state & TS_CARR_ON)) {
1864                         bc->tout = bc->tin = 0;
1865                         bc->iempty = 0;
1866                         hidewin(sc);
1867                         return;
1868                 }
1869
1870                 hidewin(sc);
1871                 port->draining = 1;
1872                 timeout(wakeflush, port, hz);
1873                 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1874                 port->draining = 0;
1875                 setwin(sc, 0);
1876
1877                 if (error != 0) {
1878                         DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1879                             " error = %d\n", port->sc->unit, port->pnum, error);
1880
1881                         /* silently clean the buffer */
1882
1883                         bc->tout = bc->tin = 0;
1884                         bc->iempty = 0;
1885                         hidewin(sc);
1886                         return;
1887                 }
1888
1889                 lasttail = tail;
1890                 tail = bc->tout;
1891                 head = bc->tin;
1892         }
1893         hidewin(sc);
1894         DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1895                         port->sc->unit, port->pnum, head, tail);
1896 }
1897
1898 static int
1899 dgmparam(struct tty *tp, struct termios *t)
1900 {
1901         int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1902         int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1903         volatile struct board_chan *bc;
1904         struct dgm_softc *sc;
1905         struct dgm_p *port;
1906         int cflag;
1907         int head;
1908         int mval;
1909         int iflag;
1910         int hflow;
1911         int cs;
1912         BoardMemWinState ws = bmws_get();
1913
1914         sc = devclass_get_softc(dgmdevclass, unit);
1915         port = &sc->ports[pnum];
1916         bc = port->brdchan;
1917
1918         DPRINT6(DB_PARAM, "dgm%d: port%d: dgmparm c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, t->c_cflag, t->c_iflag, t->c_lflag);
1919
1920         if (port->mustdrain) {
1921                 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1922                 dgmdrain(port);
1923         }
1924
1925         cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1926
1927         if (t->c_ispeed == 0)
1928                 t->c_ispeed = t->c_ospeed;
1929
1930         if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1931                 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1932                 return (EINVAL);
1933         }
1934
1935         cs = splclock();
1936         setwin(sc, 0);
1937
1938         if (cflag == 0) { /* hangup */
1939                 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1940                 head = bc->rin;
1941                 bc->rout = head;
1942                 head = bc->tin;
1943                 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1944                 mval= port->omodem & ~(DTR|RTS);
1945         } else {
1946                 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1947
1948                 if (cflag != port->fepcflag) {
1949                         port->fepcflag = cflag;
1950                         DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1951                                         unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1952                         fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1953                 }
1954                 mval= port->omodem | (DTR|RTS);
1955         }
1956
1957         iflag = dgmflags(dgm_iflags, t->c_iflag);
1958         if (iflag != port->fepiflag) {
1959                 port->fepiflag = iflag;
1960                 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1961                 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1962         }
1963
1964         bc->mint = port->dcd;
1965
1966         hflow = dgmflags(dgm_flow, t->c_cflag);
1967         if (hflow != port->hflow) {
1968                 port->hflow = hflow;
1969                 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1970                 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1971         }
1972
1973         if (port->omodem != mval) {
1974                 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1975                         unit, pnum, mval, port->omodem);
1976                 port->omodem = mval;
1977                 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1978         }
1979
1980         if (port->fepstartc != t->c_cc[VSTART] ||
1981             port->fepstopc != t->c_cc[VSTOP]) {
1982                 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1983                 port->fepstartc = t->c_cc[VSTART];
1984                 port->fepstopc = t->c_cc[VSTOP];
1985                 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1986         }
1987
1988         bmws_set(ws);
1989         splx(cs);
1990
1991         return 0;
1992
1993 }
1994
1995 static void
1996 dgmstart(struct tty *tp)
1997 {
1998         int unit;
1999         int pnum;
2000         struct dgm_p *port;
2001         struct dgm_softc *sc;
2002         volatile struct board_chan *bc;
2003         int head, tail;
2004         int size, ocount;
2005         int s;
2006         int wmask;
2007
2008         BoardMemWinState ws = bmws_get();
2009
2010         unit = MINOR_TO_UNIT(minor(tp->t_dev));
2011         pnum = MINOR_TO_PORT(minor(tp->t_dev));
2012         sc = devclass_get_softc(dgmdevclass, unit);
2013         port = &sc->ports[pnum];
2014         bc = port->brdchan;
2015
2016         wmask = port->txbufsize - 1;
2017
2018         s = spltty();
2019
2020         while (tp->t_outq.c_cc != 0) {
2021                 int cs;
2022 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2023                 ttwwakeup(tp);
2024 #else
2025                 if (tp->t_outq.c_cc <= tp->t_lowat) {
2026                         if (tp->t_state & TS_ASLEEP) {
2027                                 tp->t_state &= ~TS_ASLEEP;
2028                                 wakeup(TSA_OLOWAT(tp));
2029                         }
2030                         /*selwakeup(&tp->t_wsel);*/
2031                 }
2032 #endif
2033                 cs = splclock();
2034                 setwin(sc, 0);
2035
2036                 head = bc->tin & wmask;
2037
2038                 do { tail = bc->tout; } while (tail != bc->tout);
2039                 tail = bc->tout & wmask;
2040
2041                 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2042
2043 #ifdef LEAVE_FREE_CHARS
2044                 if (tail > head) {
2045                         size = tail - head - LEAVE_FREE_CHARS;
2046                         if (size < 0)
2047                                 size = 0;
2048                         else {
2049                                 size = port->txbufsize - head;
2050                                 if (tail + port->txbufsize < head)
2051                                         size = 0;
2052                         }
2053                 }
2054 #else
2055                 if (tail > head)
2056                         size = tail - head - 1;
2057                 else {
2058                         size = port->txbufsize - head;
2059                         if (tail == 0)
2060                                 size--;
2061                 }
2062 #endif
2063
2064                 if (size == 0) {
2065                         bc->iempty = 1;
2066                         bc->ilow = 1;
2067                         splx(cs);
2068                         bmws_set(ws);
2069                         tp->t_state |= TS_BUSY;
2070                         splx(s);
2071                         return;
2072                 }
2073
2074                 towin(sc, port->txwin);
2075
2076                 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2077                 head += ocount;
2078                 if (head >= port->txbufsize)
2079                         head -= port->txbufsize;
2080
2081                 setwin(sc, 0);
2082                 bc->tin = head;
2083
2084                 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2085                     unit, pnum, size, ocount);
2086                 hidewin(sc);
2087                 splx(cs);
2088         }
2089
2090         bmws_set(ws);
2091         splx(s);
2092
2093 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2094         if (tp->t_state & TS_BUSY) {
2095                 tp->t_state &= ~TS_BUSY;
2096                 linesw[tp->t_line].l_start(tp);
2097                 ttwwakeup(tp);
2098         }
2099 #else
2100         if (tp->t_state & TS_ASLEEP) {
2101                 tp->t_state &= ~TS_ASLEEP;
2102                 wakeup(TSA_OLOWAT(tp));
2103         }
2104         tp->t_state& = ~TS_BUSY;
2105 #endif
2106 }
2107
2108 void
2109 dgmstop(struct tty *tp, int rw)
2110 {
2111         int unit;
2112         int pnum;
2113         struct dgm_p *port;
2114         struct dgm_softc *sc;
2115         volatile struct board_chan *bc;
2116         int s;
2117
2118         BoardMemWinState ws = bmws_get();
2119
2120         unit = MINOR_TO_UNIT(minor(tp->t_dev));
2121         pnum = MINOR_TO_PORT(minor(tp->t_dev));
2122
2123         sc = devclass_get_softc(dgmdevclass, unit);
2124         port = &sc->ports[pnum];
2125         bc = port->brdchan;
2126
2127         DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2128
2129         s = spltty();
2130         setwin(sc, 0);
2131
2132         if (rw & FWRITE) {
2133                 /* clear output queue */
2134                 bc->tout = bc->tin = 0;
2135                 bc->ilow = 0;
2136                 bc->iempty = 0;
2137         }
2138         if (rw & FREAD) {
2139                 /* clear input queue */
2140                 bc->rout = bc->rin;
2141                 bc->idata = 1;
2142         }
2143         hidewin(sc);
2144         bmws_set(ws);
2145         splx(s);
2146         dgmstart(tp);
2147 }
2148
2149 static void
2150 fepcmd(struct dgm_p *port,
2151         unsigned cmd,
2152         unsigned op1,
2153         unsigned op2,
2154         unsigned ncmds,
2155         unsigned bytecmd)
2156 {
2157         u_char *mem;
2158         unsigned tail, head;
2159         int count, n;
2160
2161         KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2162         mem = port->sc->vmem;
2163
2164         if (!port->enabled) {
2165                 printf("dgm%d: port%d: FEP command on disabled port\n",
2166                         port->sc->unit, port->pnum);
2167                 return;
2168         }
2169
2170         /* setwin(port->sc, 0); Require this to be set by caller */
2171         head = port->sc->mailbox->cin;
2172
2173         if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2174                 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2175                         port->sc->unit, port->pnum, head);
2176                 return;
2177         }
2178
2179         mem[head + FEP_CSTART] = cmd;
2180         mem[head + FEP_CSTART + 1] = port->pnum;
2181         if (bytecmd) {
2182                 mem[head + FEP_CSTART + 2] = op1;
2183                 mem[head + FEP_CSTART + 3] = op2;
2184         } else {
2185                 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2186                 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2187         }
2188
2189         DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2190                         (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2191
2192         head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2193         port->sc->mailbox->cin = head;
2194
2195         count = FEPTIMEOUT;
2196
2197         while (count-- != 0) {
2198                 head = port->sc->mailbox->cin;
2199                 tail = port->sc->mailbox->cout;
2200
2201                 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2202                 if (n <= ncmds * (sizeof(ushort)*4))
2203                         return;
2204         }
2205         printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2206 }
2207
2208 static void
2209 disc_optim(struct tty *tp, struct termios *t)
2210 {
2211         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2212             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2213             && (!(t->c_iflag & PARMRK)
2214                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2215             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2216             && linesw[tp->t_line].l_rint == ttyinput)
2217                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2218         else
2219                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2220 }