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