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