kernel - Remove D_KQFILTER flag
[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/priv.h>
79 #include <sys/conf.h>
80 #include <sys/dkstat.h>
81 #include <sys/fcntl.h>
82 #include <sys/kernel.h>
83 #include <sys/sysctl.h>
84 #include <sys/malloc.h>
85 #include <sys/sysctl.h>
86 #include <sys/tty.h>
87 #include <sys/bus.h>
88 #include <sys/kobj.h>
89 #include <sys/bus.h>
90 #include <sys/rman.h>
91 #include <sys/thread2.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         u_long msize;
195         struct dgm_p *ports;            /* ptr to array of port descriptors */
196         struct tty *ttys;               /* ptr to array of TTY structures */
197         volatile struct global_data *mailbox;
198         struct resource *io_res;
199         struct resource *mem_res;
200         int iorid;
201         int mrid;
202         struct callout  toh;            /* poll timeout handle */
203 };
204
205 static void     dgmpoll(void *);
206 static int      dgmprobe(device_t);
207 static int      dgmattach(device_t);
208 static int      dgmdetach(device_t);
209 static int      dgmshutdown(device_t);
210 static void     fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
211                     unsigned);
212 static void     dgmstart(struct tty *);
213 static void     dgmstop(struct tty *, int);
214 static int      dgmparam(struct tty *, struct termios *);
215 static void     dgmhardclose(struct dgm_p *);
216 static void     dgm_drain_or_flush(struct dgm_p *);
217 static int      dgmdrain(struct dgm_p *);
218 static void     dgm_pause(void *);
219 static void     wakeflush(void *);
220 static void     disc_optim(struct tty *, struct termios *);
221
222 static  d_open_t        dgmopen;
223 static  d_close_t       dgmclose;
224 static  d_ioctl_t       dgmioctl;
225
226 static device_method_t dgmmethods[] = {
227         /* Device interface */
228         DEVMETHOD(device_probe, dgmprobe),
229         DEVMETHOD(device_attach, dgmattach),
230         DEVMETHOD(device_detach, dgmdetach),
231         DEVMETHOD(device_shutdown, dgmshutdown),
232         { 0, 0 }
233 };
234
235 static driver_t dgmdriver = {
236         "dgm",
237         dgmmethods,
238         sizeof (struct dgm_softc),
239 };
240
241 static devclass_t dgmdevclass;
242
243 #define CDEV_MAJOR      101
244 static struct dev_ops dgm_ops = {
245         { "dgm", CDEV_MAJOR, D_TTY },
246         .d_open =       dgmopen,
247         .d_close =      dgmclose,
248         .d_read =       ttyread,
249         .d_write =      ttywrite,
250         .d_ioctl =      dgmioctl,
251         .d_kqfilter =   ttykqfilter,
252         .d_revoke =     ttyrevoke
253 };
254
255 static int
256 dgmmodhandler(module_t mod, int event, void *arg)
257 {
258         int res = 0;
259
260         switch (event) {
261         case MOD_LOAD:
262                 break;
263         case MOD_UNLOAD:
264                 break;
265         }
266
267         return res;
268 }
269
270 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
271
272 static  speed_t dgmdefaultrate = TTYDEF_SPEED;
273
274 static  struct speedtab dgmspeedtab[] = {
275         { 0,            FEP_B0 }, /* old (sysV-like) Bx codes */
276         { 50,           FEP_B50 },
277         { 75,           FEP_B75 },
278         { 110,          FEP_B110 },
279         { 134,          FEP_B134 },
280         { 150,          FEP_B150 },
281         { 200,          FEP_B200 },
282         { 300,          FEP_B300 },
283         { 600,          FEP_B600 },
284         { 1200,         FEP_B1200 },
285         { 1800,         FEP_B1800 },
286         { 2400,         FEP_B2400 },
287         { 4800,         FEP_B4800 },
288         { 9600,         FEP_B9600 },
289         { 19200,        FEP_B19200 },
290         { 38400,        FEP_B38400 },
291         { 57600,        (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
292         { 115200,       (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
293         { -1,   -1 }
294 };
295
296 static struct dbgflagtbl {
297         tcflag_t in_mask;
298         tcflag_t in_val;
299         tcflag_t out_val;
300 } dgm_cflags[] = {
301         { PARODD,   PARODD,     FEP_PARODD  },
302         { PARENB,   PARENB,     FEP_PARENB  },
303         { CSTOPB,   CSTOPB,     FEP_CSTOPB  },
304         { CSIZE,    CS5,        FEP_CS6     },
305         { CSIZE,    CS6,        FEP_CS6     },
306         { CSIZE,    CS7,        FEP_CS7     },
307         { CSIZE,    CS8,        FEP_CS8     },
308         { CLOCAL,   CLOCAL,     FEP_CLOCAL  },
309         { (tcflag_t)-1 }
310 }, dgm_iflags[] = {
311         { IGNBRK,   IGNBRK,     FEP_IGNBRK  },
312         { BRKINT,   BRKINT,     FEP_BRKINT  },
313         { IGNPAR,   IGNPAR,     FEP_IGNPAR  },
314         { PARMRK,   PARMRK,     FEP_PARMRK  },
315         { INPCK,    INPCK,      FEP_INPCK   },
316         { ISTRIP,   ISTRIP,     FEP_ISTRIP  },
317         { IXON,     IXON,       FEP_IXON    },
318         { IXOFF,    IXOFF,      FEP_IXOFF   },
319         { IXANY,    IXANY,      FEP_IXANY   },
320         { (tcflag_t)-1 }
321 }, dgm_flow[] = {
322         { CRTSCTS,  CRTSCTS,    CTS|RTS },
323         { CRTSCTS,  CCTS_OFLOW, CTS     },
324         { CRTSCTS,  CRTS_IFLOW, RTS     },
325         { (tcflag_t)-1 }
326 };
327
328 /* xlat bsd termios flags to dgm sys-v style */
329 static tcflag_t
330 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
331 {
332         tcflag_t output = 0;
333         int i;
334
335         for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
336                 if ((input & tbl[i].in_mask) == tbl[i].in_val)
337                         output |= tbl[i].out_val;
338
339         return output;
340 }
341
342 static int dgmdebug = 0;
343 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
344
345 static __inline int setwin(struct dgm_softc *, unsigned);
346 static __inline void hidewin(struct dgm_softc *);
347 static __inline void towin(struct dgm_softc *, int);
348
349 /*Helg: to allow recursive dgm...() calls */
350 typedef struct {
351         /* If we were called and don't want to disturb we need: */
352         int port;       /* write to this port */
353         u_char data;    /* this data on exit */
354         /* or DATA_WINOFF  to close memory window on entry */
355 } BoardMemWinState;     /* so several channels and even boards can coexist */
356
357 #define DATA_WINOFF 0
358 static BoardMemWinState bmws;
359
360 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
361 static u_long validmem[] = {
362         0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
363         0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
364         0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
365         0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
366         0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
367 };
368
369 /* return current memory window state and close window */
370 static BoardMemWinState
371 bmws_get(void)
372 {
373         BoardMemWinState bmwsRet = bmws;
374
375         if (bmws.data != DATA_WINOFF)
376                 outb(bmws.port, bmws.data = DATA_WINOFF);
377         return bmwsRet;
378 }
379
380 /* restore memory window state */
381 static void
382 bmws_set(BoardMemWinState ws)
383 {
384         if (ws.data != bmws.data || ws.port != bmws.port) {
385                 if (bmws.data != DATA_WINOFF)
386                         outb(bmws.port, DATA_WINOFF);
387                 if (ws.data != DATA_WINOFF)
388                         outb(ws.port, ws.data);
389                 bmws = ws;
390         }
391 }
392
393 static __inline int
394 setwin(struct dgm_softc *sc, unsigned int addr)
395 {
396         outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
397         return (addr & 0x7FFF);
398 }
399
400 static __inline void
401 hidewin(struct dgm_softc *sc)
402 {
403         bmws.data = 0;
404         outb(bmws.port = sc->port + 1, bmws.data);
405 }
406
407 static __inline void
408 towin(struct dgm_softc *sc, int win)
409 {
410         outb(bmws.port = sc->port + 1, bmws.data = win);
411 }
412
413 static int
414 dgmprobe(device_t dev)
415 {
416         struct dgm_softc *sc = device_get_softc(dev);
417         int i, v;
418
419         /*
420          * Assign unit number.  Due to bits we use in the minor number for
421          * the various tty types, only 4 units are supported.
422          */
423         sc->unit = device_get_unit(dev);
424         if (sc->unit > 3) {
425                 device_printf(dev, "Too many units, only 4 supported\n");
426                 return(ENXIO);
427         }
428
429         /* Check that we've got a valid i/o address */
430         if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
431                 return (ENXIO);
432         for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
433                 if (sc->port == validio[i])
434                         break;
435         if (i == -1) {
436                 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
437                 return (ENXIO);
438         }
439
440         /* Ditto for our memory address */
441         if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
442                 return (ENXIO);
443         for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
444                 if (sc->pmem == validmem[i])
445                         break;
446         if (i == -1) {
447                 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
448                 return (ENXIO);
449         }
450         if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
451                 device_printf(dev, "0x%lx: Memory address not supported\n",
452                     sc->pmem);
453                 return (ENXIO);
454         }
455         sc->vmem = (u_char *)sc->pmem;
456
457         DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
458             sc->port, sc->pmem);
459
460         /* Temporarily map our io ports */
461         sc->iorid = 0;
462         sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
463             0ul, ~0ul, IO_SIZE, RF_ACTIVE);
464         if (sc->io_res == NULL)
465                 return (ENXIO);
466
467         outb(sc->port, FEPRST);
468         sc->enabled = 0;
469
470         for (i = 0; i < 1000; i++) {
471                 DELAY(1);
472                 if ((inb(sc->port) & FEPMASK) == FEPRST) {
473                         sc->enabled = 1;
474                         DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
475                             sc->unit, i);
476                         break;
477                 }
478         }
479
480         if (!sc->enabled) {
481                 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
482                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
483                 return (ENXIO);
484         }
485
486         /* check type of card and get internal memory characteristics */
487
488         v = inb(sc->port);
489
490         if (!(v & 0x1)) {
491                 int second;
492
493                 outb(sc->port, 1);
494                 second = inb(sc->port);
495                 kprintf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
496         } else
497                 kprintf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
498
499         sc->type = PCXEM;
500         sc->mem_seg = 0x8000;
501
502         /* Temporarily map our memory too */
503         sc->mrid = 0;
504         sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
505             0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
506         if (sc->mem_res == NULL) {
507                 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
508                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
509                 return (ENXIO);
510         }
511
512         outb(sc->port, FEPCLR); /* drop RESET */
513         hidewin(sc);    /* Helg: to set initial bmws state */
514
515         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
516         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
517
518         bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
519         bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
520
521         DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
522
523         return (0);
524 }
525
526 static int
527 dgmattach(device_t dev)
528 {
529         struct dgm_softc *sc = device_get_softc(dev);
530         int i, t;
531         u_char *mem;
532         u_char *ptr;
533         int addr;
534         struct dgm_p *port;
535         volatile struct board_chan *bc;
536         int shrinkmem;
537         int lowwater;
538         u_long msize, iosize;
539
540         DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
541
542         callout_init(&sc->toh);
543         sc->unit = device_get_unit(dev);
544         bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
545         bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
546         sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
547         sc->type = PCXEM;
548         sc->mem_seg = 0x8000;
549         sc->enabled = 1;
550         sc->type = PCXEM;
551         sc->mem_seg = 0x8000;
552
553         /* Allocate resources (should have been verified in dgmprobe()) */
554         sc->iorid = 0;
555         sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
556             0ul, ~0ul, iosize, RF_ACTIVE);
557         if (sc->io_res == NULL)
558                 return (ENXIO);
559         sc->mrid = 0;
560         sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
561             0ul, ~0ul, msize, RF_ACTIVE);
562         if (sc->mem_res == NULL) {
563                 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
564                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
565                 return (ENXIO);
566         }
567
568         /* map memory */
569         mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
570         sc->msize = msize;
571
572         DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
573             sc->mem_seg);
574
575         outb(sc->port, FEPRST);
576         DELAY(1);
577
578         for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
579                 if (i > 10000) {
580                         device_printf(dev, "1st reset failed\n");
581                         sc->enabled = 0;
582                         hidewin(sc);
583                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
584                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
585                         return (ENXIO);
586                 }
587                 DELAY(1);
588         }
589
590         DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
591
592         t = sc->pmem >> 8;      /* disable windowing */
593         outb(sc->port + 2, t & 0xFF);
594         outb(sc->port + 3, t >> 8);
595
596         mem = sc->vmem;
597
598         /* very short memory test */
599         DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
600
601         addr = setwin(sc, BOTWIN);
602         *(u_long *)(mem + addr) = 0xA55A3CC3;
603         if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
604                 device_printf(dev, "1st memory test failed\n");
605                 sc->enabled = 0;
606                 hidewin(sc);
607                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
608                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
609                 return (ENXIO);
610         }
611
612         DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
613
614         addr = setwin(sc, TOPWIN);
615         *(u_long *)(mem + addr) = 0x5AA5C33C;
616         if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
617                 device_printf(dev, "2nd memory test failed\n");
618                 sc->enabled = 0;
619                 hidewin(sc);
620                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
621                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
622                 return (ENXIO);
623         }
624
625         DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
626
627         addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
628         *(u_long *)(mem + addr) = 0x5AA5C33C;
629         if (*(u_long *)(mem + addr) != 0x5AA5C33C)
630                 device_printf(dev, "3rd (BIOS) memory test failed\n");
631
632         DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
633
634         addr = setwin(sc, MISCGLOBAL);
635         for (i = 0; i < 16; i++)
636                 mem[addr + i] = 0;
637
638         addr = setwin(sc, BIOSOFFSET);
639         ptr = mem + addr;
640         for (i = 0; ptr < mem + msize; i++)
641                 *ptr++ = pcem_bios[i];
642
643         ptr = mem + BIOSOFFSET;
644         for (i = 0; ptr < mem + msize; i++) {
645                 if (*ptr++ != pcem_bios[i]) {
646                         kprintf("Low BIOS load failed\n");
647                         sc->enabled = 0;
648                         hidewin(sc);
649                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
650                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
651                         return (ENXIO);
652                 }
653         }
654         DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
655
656         addr = setwin(sc, msize);
657         ptr = mem + addr;
658         for (;i < pcem_nbios; i++)
659                 *ptr++ = pcem_bios[i];
660
661         ptr = mem;
662         for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
663                 if (*ptr++ != pcem_bios[i]) {
664                         kprintf("High BIOS load failed\n");
665                         sc->enabled = 0;
666                         hidewin(sc);
667                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
668                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
669                         return (ENXIO);
670                 }
671         }
672         DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
673         device_printf(dev, "DigiBIOS loaded, initializing");
674
675         addr = setwin(sc, 0);
676
677         *(u_int *)(mem + addr) = 0x0bf00401;
678         *(u_int *)(mem + addr + 4) = 0;
679         *(ushort *)(mem + addr + 0xc00) = 0;
680         outb(sc->port, 0);
681
682         for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
683                 DELAY(10000);
684                 if (i > 3000) {
685                         kprintf("\nBIOS initialize failed(1)\n");
686                         sc->enabled = 0;
687                         hidewin(sc);
688                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
689                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
690                         return (ENXIO);
691                 }
692         }
693
694         if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
695                 kprintf("\nBIOS initialize failed(2)\n");
696                 sc->enabled = 0;
697                 hidewin(sc);
698                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
699                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
700                 return (ENXIO);
701         }
702         kprintf(", DigiBIOS running\n");
703
704         DELAY(10000);
705
706         addr = setwin(sc, BIOSOFFSET);
707         ptr = mem + addr;
708         for (i = 0; i < pcem_ncook; i++)
709                 *ptr++ = pcem_cook[i];
710
711         ptr = mem + BIOSOFFSET;
712         for (i = 0; i < pcem_ncook; i++) {
713                 if (*ptr++ != pcem_cook[i]) {
714                         kprintf("FEP/OS load failed\n");
715                         sc->enabled = 0;
716                         hidewin(sc);
717                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
718                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
719                         return (ENXIO);
720                 }
721         }
722         device_printf(dev, "FEP/OS loaded, initializing");
723
724         addr = setwin(sc, 0);
725         *(ushort *)(mem + addr + 0xd20) = 0;
726         *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
727         *(u_int *)(mem + addr + 0xc30) = 0x3L;
728         outb(sc->port, 0);
729
730         for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
731                 DELAY(10000);
732                 if (i > 3000) {
733                         kprintf("\nFEP/OS initialize failed(1)\n");
734                         sc->enabled = 0;
735                         hidewin(sc);
736                         bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
737                         bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
738                         return (ENXIO);
739                 }
740         }
741
742         if (*(u_char *)(mem + addr + 0xd21) != 'S') {
743                 kprintf("\nFEP/OS initialize failed(2)\n");
744                 sc->enabled = 0;
745                 hidewin(sc);
746                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
747                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
748                 return (ENXIO);
749         }
750         kprintf(", FEP/OS running\n");
751
752         sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
753         device_printf(dev, "%d ports attached\n", sc->numports);
754
755         if (sc->numports > MAX_DGM_PORTS) {
756                 kprintf("dgm%d: too many ports\n", sc->unit);
757                 sc->enabled = 0;
758                 hidewin(sc);
759                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
760                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
761                 return (ENXIO);
762         }
763
764         MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
765             M_TTYS, M_WAITOK|M_ZERO);
766         MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
767             M_TTYS, M_WAITOK|M_ZERO);
768
769         DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
770         for (i = 0; i < sc->numports; i++) {
771                 sc->ports[i].enabled = 1;
772                 callout_init(&sc->ports[i].hc_timeout);
773                 callout_init(&sc->ports[i].wf_timeout);
774         }
775
776         /* We should now init per-port structures */
777         setwin(sc, 0);
778         bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
779         sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
780
781         if (sc->numports < 3)
782                 shrinkmem = 1;
783         else
784                 shrinkmem = 0;
785
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_minor(&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((vm_offset_t)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 && priv_check_cred(ap->a_cred, PRIV_ROOT, 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); /* Issues KNOTE() */
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                                                         }
1404 #endif
1405                                                         setwin(sc, 0);
1406                                                 }
1407                                                 crit_enter();
1408
1409                                         whead = bc->tin & wrapmask;
1410                                         wtail = bc->tout & wrapmask;
1411
1412                                         if (whead < wtail)
1413                                                 size = wtail - whead - 1;
1414                                         else {
1415                                                 size = port->txbufsize - whead;
1416                                                 if (wtail == 0)
1417                                                         size--;
1418                                         }
1419
1420                                         if (size == 0) {
1421                                                 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1422                                                         whead, wtail, size, obuf_full);
1423                                                 bc->iempty = 1;
1424                                                 bc->ilow = 1;
1425                                                 obuf_full = TRUE;
1426                                                 crit_exit();
1427                                                 break;
1428                                         }
1429
1430                                         towin(sc, port->txwin);
1431
1432                                         ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1433                                         whead += ocount;
1434
1435                                         setwin(sc, 0);
1436                                         bc->tin = whead;
1437                                         bc->tin = whead & wrapmask;
1438                                         crit_exit();
1439                                 }
1440
1441                                 if (obuf_full) {
1442                                         DPRINT1(DB_WR, " +BUSY\n");
1443                                         tp->t_state |= TS_BUSY;
1444                                 } else {
1445                                         DPRINT1(DB_WR, " -BUSY\n");
1446                                         hidewin(sc);
1447 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
1448                                         /* should clear TS_BUSY before ttwwakeup */
1449                                         if (tp->t_state & TS_BUSY)      {
1450                                                 tp->t_state &= ~TS_BUSY;
1451                                                 linesw[tp->t_line].l_start(tp);
1452                                                 ttwwakeup(tp);
1453                                         }
1454 #else
1455                                 if (tp->t_state & TS_ASLEEP) {
1456                                         tp->t_state &= ~TS_ASLEEP;
1457                                         wakeup(TSA_OLOWAT(tp));
1458                                 }
1459                                 tp->t_state &= ~TS_BUSY;
1460 #endif
1461                                         setwin(sc, 0);
1462                                         }
1463                                 }
1464                         }
1465                         bc->idata = 1;   /* require event on incoming data */
1466
1467                 } else {
1468                         bc = port->brdchan;
1469                         DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1470                                 unit, pnum, event);
1471                         bc->rout = bc->rin;
1472                         bc->idata = bc->iempty = bc->ilow = 0;
1473                 }
1474
1475                 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1476         }
1477
1478         sc->mailbox->eout = tail;
1479         bmws_set(ws);
1480
1481         callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1482
1483         DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1484 }
1485
1486 static int
1487 dgmioctl(struct dev_ioctl_args *ap)
1488 {
1489         cdev_t dev = ap->a_head.a_dev;
1490         u_long cmd = ap->a_cmd;
1491         caddr_t data = ap->a_data;
1492         struct dgm_softc *sc;
1493         int unit, pnum;
1494         struct dgm_p *port;
1495         int mynor;
1496         struct tty *tp;
1497         volatile struct board_chan *bc;
1498         int error;
1499         int tiocm_xxx;
1500
1501 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1502         u_long          oldcmd;
1503         struct termios  term;
1504 #endif
1505
1506         BoardMemWinState ws = bmws_get();
1507
1508         mynor = minor(dev);
1509         unit = MINOR_TO_UNIT(mynor);
1510         pnum = MINOR_TO_PORT(mynor);
1511
1512         sc = devclass_get_softc(dgmdevclass, unit);
1513         port = &sc->ports[pnum];
1514         tp = &sc->ttys[pnum];
1515         bc = port->brdchan;
1516
1517         if (mynor & CONTROL_MASK) {
1518                 struct termios *ct;
1519
1520                 switch (mynor & CONTROL_MASK) {
1521                 case CONTROL_INIT_STATE:
1522                         ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1523                         break;
1524                 case CONTROL_LOCK_STATE:
1525                         ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1526                         break;
1527                 default:
1528                         return (ENODEV);        /* /dev/nodev */
1529                 }
1530                 switch (cmd) {
1531                 case TIOCSETA:
1532                         error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1533                         if (error != 0)
1534                                 return (error);
1535                         *ct = *(struct termios *)data;
1536                         return (0);
1537                 case TIOCGETA:
1538                         *(struct termios *)data = *ct;
1539                         return (0);
1540                 case TIOCGETD:
1541                         *(int *)data = TTYDISC;
1542                         return (0);
1543                 case TIOCGWINSZ:
1544                         bzero(data, sizeof(struct winsize));
1545                         return (0);
1546                 default:
1547                         return (ENOTTY);
1548                 }
1549         }
1550
1551 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1552         term = tp->t_termios;
1553         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1554           DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-ISNOW c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, term.c_cflag, term.c_iflag, term.c_lflag);
1555         }
1556         oldcmd = cmd;
1557         error = ttsetcompat(tp, &cmd, data, &term);
1558         if (error != 0)
1559                 return (error);
1560         if (cmd != oldcmd)
1561                 data = (caddr_t)&term;
1562 #endif
1563
1564         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1565                 int     cc;
1566                 struct termios *dt = (struct termios *)data;
1567                 struct termios *lt = mynor & CALLOUT_MASK
1568                                      ? &port->lt_out : &port->lt_in;
1569
1570                 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-TOSET c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, dt->c_cflag, dt->c_iflag, dt->c_lflag);
1571                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1572                               | (dt->c_iflag & ~lt->c_iflag);
1573                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1574                               | (dt->c_oflag & ~lt->c_oflag);
1575                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1576                               | (dt->c_cflag & ~lt->c_cflag);
1577                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1578                               | (dt->c_lflag & ~lt->c_lflag);
1579                 for (cc = 0; cc < NCCS; ++cc)
1580                         if (lt->c_cc[cc] != 0)
1581                                 dt->c_cc[cc] = tp->t_cc[cc];
1582                 if (lt->c_ispeed != 0)
1583                         dt->c_ispeed = tp->t_ispeed;
1584                 if (lt->c_ospeed != 0)
1585                         dt->c_ospeed = tp->t_ospeed;
1586         }
1587
1588         if (cmd == TIOCSTOP) {
1589                 crit_enter();
1590                 setwin(sc, 0);
1591                 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1592                 bmws_set(ws);
1593                 crit_exit();
1594                 return 0;
1595         } else if (cmd == TIOCSTART) {
1596                 crit_enter();
1597                 setwin(sc, 0);
1598                 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1599                 bmws_set(ws);
1600                 crit_exit();
1601                 return 0;
1602         }
1603
1604         if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1605                 port->mustdrain = 1;
1606
1607         error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1608                                            ap->a_fflag, ap->a_cred);
1609         if (error != ENOIOCTL)
1610                 return error;
1611         crit_enter();
1612         error = ttioctl(tp, cmd, data, ap->a_fflag);
1613         disc_optim(tp, &tp->t_termios);
1614         port->mustdrain = 0;
1615         if (error != ENOIOCTL) {
1616                 crit_exit();
1617                 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1618                         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);
1619                 }
1620                 return error;
1621         }
1622
1623         switch (cmd) {
1624         case TIOCSBRK:
1625 #if 0
1626                 error = dgmdrain(port);
1627
1628                 if (error != 0) {
1629                         crit_exit();
1630                         return error;
1631                 }
1632 #endif
1633
1634                 crit_enter();
1635                 setwin(sc, 0);
1636
1637                 /* now it sends 400 millisecond break because I don't know */
1638                 /* how to send an infinite break */
1639
1640                 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1641                 hidewin(sc);
1642                 crit_exit();
1643                 break;
1644         case TIOCCBRK:
1645                 /* now it's empty */
1646                 break;
1647         case TIOCSDTR:
1648                 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1649                 port->omodem |= DTR;
1650                 crit_enter();
1651                 setwin(sc, 0);
1652                 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1653
1654                 if (!(bc->mstat & DTR))
1655                         DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1656
1657                 hidewin(sc);
1658                 crit_exit();
1659                 break;
1660         case TIOCCDTR:
1661                 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1662                 port->omodem &= ~DTR;
1663                 crit_enter();
1664                 setwin(sc, 0);
1665                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1666
1667                 if (bc->mstat & DTR) {
1668                         DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1669                 }
1670
1671                 hidewin(sc);
1672                 crit_exit();
1673                 break;
1674         case TIOCMSET:
1675                 if (*(int *)data & TIOCM_DTR)
1676                         port->omodem |= DTR;
1677                 else
1678                         port->omodem &= ~DTR;
1679
1680                 if (*(int *)data & TIOCM_RTS)
1681                         port->omodem |= RTS;
1682                 else
1683                         port->omodem &= ~RTS;
1684
1685                 crit_enter();
1686                 setwin(sc, 0);
1687                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1688                 hidewin(sc);
1689                 crit_exit();
1690                 break;
1691         case TIOCMBIS:
1692                 if (*(int *)data & TIOCM_DTR)
1693                         port->omodem |= DTR;
1694
1695                 if (*(int *)data & TIOCM_RTS)
1696                         port->omodem |= RTS;
1697
1698                 crit_enter();
1699                 setwin(sc, 0);
1700                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1701                 hidewin(sc);
1702                 crit_exit();
1703                 break;
1704         case TIOCMBIC:
1705                 if (*(int *)data & TIOCM_DTR)
1706                         port->omodem &= ~DTR;
1707
1708                 if (*(int *)data & TIOCM_RTS)
1709                         port->omodem &= ~RTS;
1710
1711                 crit_enter();
1712                 setwin(sc, 0);
1713                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1714                 hidewin(sc);
1715                 crit_exit();
1716                 break;
1717         case TIOCMGET:
1718                 setwin(sc, 0);
1719                 port->imodem = bc->mstat;
1720                 hidewin(sc);
1721
1722                 tiocm_xxx = TIOCM_LE;   /* XXX - always enabled while open */
1723
1724                 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1725
1726                 if (port->imodem & DTR) {
1727                         DPRINT1(DB_MODEM, "DTR ");
1728                         tiocm_xxx |= TIOCM_DTR;
1729                 }
1730                 if (port->imodem & RTS) {
1731                         DPRINT1(DB_MODEM, "RTS ");
1732                         tiocm_xxx |= TIOCM_RTS;
1733                 }
1734                 if (port->imodem & CTS) {
1735                         DPRINT1(DB_MODEM, "CTS ");
1736                         tiocm_xxx |= TIOCM_CTS;
1737                 }
1738                 if (port->imodem & port->dcd) {
1739                         DPRINT1(DB_MODEM, "DCD ");
1740                         tiocm_xxx |= TIOCM_CD;
1741                 }
1742                 if (port->imodem & port->dsr) {
1743                         DPRINT1(DB_MODEM, "DSR ");
1744                         tiocm_xxx |= TIOCM_DSR;
1745                 }
1746                 if (port->imodem & RI) {
1747                         DPRINT1(DB_MODEM, "RI ");
1748                         tiocm_xxx |= TIOCM_RI;
1749                 }
1750                 *(int *)data = tiocm_xxx;
1751                 DPRINT1(DB_MODEM, "--\n");
1752                 break;
1753         case TIOCMSDTRWAIT:
1754                 /* must be root since the wait applies to following logins */
1755                 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1756                 if (error != 0) {
1757                         crit_exit();
1758                         return (error);
1759                 }
1760                 port->close_delay = *(int *)data * hz / 100;
1761                 break;
1762         case TIOCMGDTRWAIT:
1763                 *(int *)data = port->close_delay * 100 / hz;
1764                 break;
1765         case TIOCTIMESTAMP:
1766                 port->do_timestamp = 1;
1767                 *(struct timeval *)data = port->timestamp;
1768                 break;
1769         case TIOCDCDTIMESTAMP:
1770                 port->do_dcd_timestamp = 1;
1771                 *(struct timeval *)data = port->dcd_timestamp;
1772                 break;
1773         default:
1774                 bmws_set(ws);
1775                 crit_exit();
1776                 return ENOTTY;
1777         }
1778         bmws_set(ws);
1779         crit_exit();
1780
1781         return 0;
1782 }
1783
1784 static void
1785 wakeflush(void *p)
1786 {
1787         struct dgm_p *port = p;
1788
1789         wakeup(&port->draining);
1790 }
1791
1792 /* wait for the output to drain */
1793
1794 static int
1795 dgmdrain(struct dgm_p *port)
1796 {
1797         volatile struct board_chan *bc = port->brdchan;
1798         struct dgm_softc *sc;
1799         int error;
1800         int head, tail;
1801         BoardMemWinState ws = bmws_get();
1802
1803         sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1804
1805         setwin(sc, 0);
1806
1807         bc->iempty = 1;
1808         tail = bc->tout;
1809         head = bc->tin;
1810
1811         while (tail != head) {
1812                 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1813                         port->sc->unit, port->pnum, head, tail);
1814
1815                 hidewin(sc);
1816                 port->draining = 1;
1817                 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1818                 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1819                 port->draining = 0;
1820                 setwin(sc, 0);
1821
1822                 if (error != 0) {
1823                         DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1824                                 port->sc->unit, port->pnum, error);
1825
1826                         bc->iempty = 0;
1827                         bmws_set(ws);
1828                         return error;
1829                 }
1830
1831                 tail = bc->tout;
1832                 head = bc->tin;
1833         }
1834         DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1835                 port->sc->unit, port->pnum, head, tail);
1836         bmws_set(ws);
1837         return 0;
1838 }
1839
1840 /* wait for the output to drain */
1841 /* or simply clear the buffer it it's stopped */
1842
1843 static void
1844 dgm_drain_or_flush(struct dgm_p *port)
1845 {
1846         volatile struct board_chan *bc = port->brdchan;
1847         struct tty *tp = port->tty;
1848         struct dgm_softc *sc;
1849         int error;
1850         int lasttail;
1851         int head, tail;
1852
1853         sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1854         setwin(sc, 0);
1855
1856         lasttail = -1;
1857         bc->iempty = 1;
1858         tail = bc->tout;
1859         head = bc->tin;
1860
1861         while (tail != head /* && tail != lasttail */ ) {
1862                 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1863                         port->sc->unit, port->pnum, head, tail);
1864
1865                 /* if there is no carrier simply clean the buffer */
1866                 if (!(tp->t_state & TS_CARR_ON)) {
1867                         bc->tout = bc->tin = 0;
1868                         bc->iempty = 0;
1869                         hidewin(sc);
1870                         return;
1871                 }
1872
1873                 hidewin(sc);
1874                 port->draining = 1;
1875                 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1876                 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1877                 port->draining = 0;
1878                 setwin(sc, 0);
1879
1880                 if (error != 0) {
1881                         DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1882                             " error = %d\n", port->sc->unit, port->pnum, error);
1883
1884                         /* silently clean the buffer */
1885
1886                         bc->tout = bc->tin = 0;
1887                         bc->iempty = 0;
1888                         hidewin(sc);
1889                         return;
1890                 }
1891
1892                 lasttail = tail;
1893                 tail = bc->tout;
1894                 head = bc->tin;
1895         }
1896         hidewin(sc);
1897         DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1898                         port->sc->unit, port->pnum, head, tail);
1899 }
1900
1901 static int
1902 dgmparam(struct tty *tp, struct termios *t)
1903 {
1904         int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1905         int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1906         volatile struct board_chan *bc;
1907         struct dgm_softc *sc;
1908         struct dgm_p *port;
1909         int cflag;
1910         int head;
1911         int mval;
1912         int iflag;
1913         int hflow;
1914         BoardMemWinState ws = bmws_get();
1915
1916         sc = devclass_get_softc(dgmdevclass, unit);
1917         port = &sc->ports[pnum];
1918         bc = port->brdchan;
1919
1920         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);
1921
1922         if (port->mustdrain) {
1923                 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1924                 dgmdrain(port);
1925         }
1926
1927         cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1928
1929         if (t->c_ispeed == 0)
1930                 t->c_ispeed = t->c_ospeed;
1931
1932         if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1933                 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1934                 return (EINVAL);
1935         }
1936
1937         crit_enter();
1938         setwin(sc, 0);
1939
1940         if (cflag == 0) { /* hangup */
1941                 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1942                 head = bc->rin;
1943                 bc->rout = head;
1944                 head = bc->tin;
1945                 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1946                 mval= port->omodem & ~(DTR|RTS);
1947         } else {
1948                 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1949
1950                 if (cflag != port->fepcflag) {
1951                         port->fepcflag = cflag;
1952                         DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1953                                         unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1954                         fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1955                 }
1956                 mval= port->omodem | (DTR|RTS);
1957         }
1958
1959         iflag = dgmflags(dgm_iflags, t->c_iflag);
1960         if (iflag != port->fepiflag) {
1961                 port->fepiflag = iflag;
1962                 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1963                 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1964         }
1965
1966         bc->mint = port->dcd;
1967
1968         hflow = dgmflags(dgm_flow, t->c_cflag);
1969         if (hflow != port->hflow) {
1970                 port->hflow = hflow;
1971                 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1972                 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1973         }
1974
1975         if (port->omodem != mval) {
1976                 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1977                         unit, pnum, mval, port->omodem);
1978                 port->omodem = mval;
1979                 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1980         }
1981
1982         if (port->fepstartc != t->c_cc[VSTART] ||
1983             port->fepstopc != t->c_cc[VSTOP]) {
1984                 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1985                 port->fepstartc = t->c_cc[VSTART];
1986                 port->fepstopc = t->c_cc[VSTOP];
1987                 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1988         }
1989
1990         bmws_set(ws);
1991         crit_exit();
1992
1993         return 0;
1994
1995 }
1996
1997 static void
1998 dgmstart(struct tty *tp)
1999 {
2000         int unit;
2001         int pnum;
2002         struct dgm_p *port;
2003         struct dgm_softc *sc;
2004         volatile struct board_chan *bc;
2005         int head, tail;
2006         int size, ocount;
2007         int wmask;
2008
2009         BoardMemWinState ws = bmws_get();
2010
2011         unit = MINOR_TO_UNIT(minor(tp->t_dev));
2012         pnum = MINOR_TO_PORT(minor(tp->t_dev));
2013         sc = devclass_get_softc(dgmdevclass, unit);
2014         port = &sc->ports[pnum];
2015         bc = port->brdchan;
2016
2017         wmask = port->txbufsize - 1;
2018
2019         crit_enter();
2020
2021         while (tp->t_outq.c_cc != 0) {
2022 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2023                 ttwwakeup(tp); /* Issues KNOTE() */
2024 #else
2025                 if (tp->t_outq.c_cc <= tp->t_lowat) {
2026                         if (tp->t_state & TS_ASLEEP) {
2027                                 tp->t_state &= ~TS_ASLEEP;
2028                                 wakeup(TSA_OLOWAT(tp));
2029                         }
2030                 }
2031 #endif
2032                 crit_enter();
2033                 setwin(sc, 0);
2034
2035                 head = bc->tin & wmask;
2036
2037                 do { tail = bc->tout; } while (tail != bc->tout);
2038                 tail = bc->tout & wmask;
2039
2040                 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2041
2042 #ifdef LEAVE_FREE_CHARS
2043                 if (tail > head) {
2044                         size = tail - head - LEAVE_FREE_CHARS;
2045                         if (size < 0)
2046                                 size = 0;
2047                         else {
2048                                 size = port->txbufsize - head;
2049                                 if (tail + port->txbufsize < head)
2050                                         size = 0;
2051                         }
2052                 }
2053 #else
2054                 if (tail > head)
2055                         size = tail - head - 1;
2056                 else {
2057                         size = port->txbufsize - head;
2058                         if (tail == 0)
2059                                 size--;
2060                 }
2061 #endif
2062
2063                 if (size == 0) {
2064                         bc->iempty = 1;
2065                         bc->ilow = 1;
2066                         crit_exit();
2067                         bmws_set(ws);
2068                         tp->t_state |= TS_BUSY;
2069                         crit_exit();
2070                         return;
2071                 }
2072
2073                 towin(sc, port->txwin);
2074
2075                 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2076                 head += ocount;
2077                 if (head >= port->txbufsize)
2078                         head -= port->txbufsize;
2079
2080                 setwin(sc, 0);
2081                 bc->tin = head;
2082
2083                 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2084                     unit, pnum, size, ocount);
2085                 hidewin(sc);
2086                 crit_exit();
2087         }
2088
2089         bmws_set(ws);
2090         crit_exit();
2091
2092 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2093         if (tp->t_state & TS_BUSY) {
2094                 tp->t_state &= ~TS_BUSY;
2095                 linesw[tp->t_line].l_start(tp);
2096                 ttwwakeup(tp);
2097         }
2098 #else
2099         if (tp->t_state & TS_ASLEEP) {
2100                 tp->t_state &= ~TS_ASLEEP;
2101                 wakeup(TSA_OLOWAT(tp));
2102         }
2103         tp->t_state& = ~TS_BUSY;
2104 #endif
2105 }
2106
2107 void
2108 dgmstop(struct tty *tp, int rw)
2109 {
2110         int unit;
2111         int pnum;
2112         struct dgm_p *port;
2113         struct dgm_softc *sc;
2114         volatile struct board_chan *bc;
2115
2116         BoardMemWinState ws = bmws_get();
2117
2118         unit = MINOR_TO_UNIT(minor(tp->t_dev));
2119         pnum = MINOR_TO_PORT(minor(tp->t_dev));
2120
2121         sc = devclass_get_softc(dgmdevclass, unit);
2122         port = &sc->ports[pnum];
2123         bc = port->brdchan;
2124
2125         DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2126
2127         crit_enter();
2128         setwin(sc, 0);
2129
2130         if (rw & FWRITE) {
2131                 /* clear output queue */
2132                 bc->tout = bc->tin = 0;
2133                 bc->ilow = 0;
2134                 bc->iempty = 0;
2135         }
2136         if (rw & FREAD) {
2137                 /* clear input queue */
2138                 bc->rout = bc->rin;
2139                 bc->idata = 1;
2140         }
2141         hidewin(sc);
2142         bmws_set(ws);
2143         crit_exit();
2144         dgmstart(tp);
2145 }
2146
2147 static void
2148 fepcmd(struct dgm_p *port,
2149         unsigned cmd,
2150         unsigned op1,
2151         unsigned op2,
2152         unsigned ncmds,
2153         unsigned bytecmd)
2154 {
2155         u_char *mem;
2156         unsigned tail, head;
2157         int count, n;
2158
2159         KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2160         mem = port->sc->vmem;
2161
2162         if (!port->enabled) {
2163                 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2164                         port->sc->unit, port->pnum);
2165                 return;
2166         }
2167
2168         /* setwin(port->sc, 0); Require this to be set by caller */
2169         head = port->sc->mailbox->cin;
2170
2171         if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2172                 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2173                         port->sc->unit, port->pnum, head);
2174                 return;
2175         }
2176
2177         mem[head + FEP_CSTART] = cmd;
2178         mem[head + FEP_CSTART + 1] = port->pnum;
2179         if (bytecmd) {
2180                 mem[head + FEP_CSTART + 2] = op1;
2181                 mem[head + FEP_CSTART + 3] = op2;
2182         } else {
2183                 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2184                 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2185         }
2186
2187         DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2188                         (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2189
2190         head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2191         port->sc->mailbox->cin = head;
2192
2193         count = FEPTIMEOUT;
2194
2195         while (count-- != 0) {
2196                 head = port->sc->mailbox->cin;
2197                 tail = port->sc->mailbox->cout;
2198
2199                 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2200                 if (n <= ncmds * (sizeof(ushort)*4))
2201                         return;
2202         }
2203         kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2204 }
2205
2206 static void
2207 disc_optim(struct tty *tp, struct termios *t)
2208 {
2209         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2210             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2211             && (!(t->c_iflag & PARMRK)
2212                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2213             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2214             && linesw[tp->t_line].l_rint == ttyinput)
2215                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2216         else
2217                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2218 }