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