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