proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[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.3 2003/06/25 03:55:47 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, TTOPRI|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,
1002                             TTIPRI | PCATCH, "dgmi", 0);
1003                         if (error != 0) {
1004                                 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1005                                     " error = %d\n", unit, pnum, error);
1006                                 goto out;
1007                         }
1008                         splx(s);
1009                         goto open_top;
1010                 }
1011                 if (tp->t_state & TS_XCLUDE && suser(td)) {
1012                         error = EBUSY;
1013                         goto out;
1014                 }
1015         } else {
1016                 /*
1017                  * The device isn't open, so there are no conflicts.
1018                  * Initialize it.  Initialization is done twice in many
1019                  * cases: to preempt sleeping callin opens if we are
1020                  * callout, and to complete a callin open after DCD rises.
1021                  */
1022                 tp->t_oproc = dgmstart;
1023                 tp->t_param = dgmparam;
1024                 tp->t_stop = dgmstop;
1025                 tp->t_dev = dev;
1026                 tp->t_termios= (mynor & CALLOUT_MASK) ?
1027                                                         port->it_out :
1028                                                         port->it_in;
1029
1030                 cs = splclock();
1031                 setwin(sc, 0);
1032                 port->imodem = bc->mstat;
1033                 bc->rout = bc->rin; /* clear input queue */
1034                 bc->idata = 1;
1035 #ifdef PRINT_BUFSIZE
1036                 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1037                     bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1038 #endif
1039
1040                 hidewin(sc);
1041                 splx(cs);
1042
1043                 port->wopeners++;
1044                 error = dgmparam(tp, &tp->t_termios);
1045                 port->wopeners--;
1046
1047                 if (error != 0) {
1048                         DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1049                             unit, pnum, error);
1050                         goto out;
1051                 }
1052
1053                 /* handle fake DCD for callout devices */
1054                 /* and initial DCD */
1055
1056                 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1057                         linesw[tp->t_line].l_modem(tp, 1);
1058         }
1059
1060         /*
1061          * Wait for DCD if necessary.
1062          */
1063         if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1064             && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1065                 ++port->wopeners;
1066                 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "dgdcd", 0);
1067                 --port->wopeners;
1068                 if (error != 0) {
1069                         DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1070                             " error = %d\n", unit, pnum, error);
1071                         goto out;
1072                 }
1073                 splx(s);
1074                 goto open_top;
1075         }
1076         error = linesw[tp->t_line].l_open(dev, tp);
1077         disc_optim(tp, &tp->t_termios);
1078         DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1079             unit, pnum, error);
1080
1081         if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1082                 port->active_out = 1;
1083
1084         port->used = 1;
1085
1086         /* If any port is open (i.e. the open() call is completed for it)
1087          * the device is busy
1088          */
1089
1090 out:
1091         disc_optim(tp, &tp->t_termios);
1092         splx(s);
1093
1094         if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1095                 dgmhardclose(port);
1096
1097         DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1098             unit, pnum, error);
1099
1100         return error;
1101 }
1102
1103 /*ARGSUSED*/
1104 static int
1105 dgmclose(dev_t dev, int flag, int mode, struct thread *td)
1106 {
1107         int             mynor;
1108         struct tty      *tp;
1109         int unit, pnum;
1110         struct dgm_softc *sc;
1111         struct dgm_p *port;
1112         int s;
1113         int i;
1114
1115         mynor = minor(dev);
1116         if (mynor & CONTROL_MASK)
1117                 return 0;
1118         unit = MINOR_TO_UNIT(mynor);
1119         pnum = MINOR_TO_PORT(mynor);
1120
1121         sc = devclass_get_softc(dgmdevclass, unit);
1122         tp = &sc->ttys[pnum];
1123         port = sc->ports + pnum;
1124
1125         DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1126
1127         DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1128         dgm_drain_or_flush(port);
1129
1130         s = spltty();
1131
1132         port->closing = 1;
1133         DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1134         linesw[tp->t_line].l_close(tp, flag);
1135         disc_optim(tp, &tp->t_termios);
1136
1137         DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1138         dgmhardclose(port);
1139         DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1140         ttyclose(tp);
1141         port->closing = 0;
1142         wakeup(&port->closing);
1143         port->used = 0;
1144
1145         /* mark the card idle when all ports are closed */
1146
1147         for (i = 0; i < sc->numports; i++)
1148                 if (sc->ports[i].used)
1149                         break;
1150
1151         splx(s);
1152
1153         DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1154
1155         wakeup(TSA_CARR_ON(tp));
1156         wakeup(&port->active_out);
1157         port->active_out = 0;
1158
1159         DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1160
1161         return 0;
1162 }
1163
1164 static void
1165 dgmhardclose(struct dgm_p *port)
1166 {
1167         volatile struct board_chan *bc = port->brdchan;
1168         struct dgm_softc *sc;
1169         int cs;
1170
1171         sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1172         DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1173         cs = splclock();
1174         port->do_timestamp = 0;
1175         setwin(sc, 0);
1176
1177         bc->idata = 0;
1178         bc->iempty = 0;
1179         bc->ilow = 0;
1180         if (port->tty->t_cflag & HUPCL) {
1181                 port->omodem &= ~(RTS|DTR);
1182                 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1183         }
1184
1185         hidewin(sc);
1186         splx(cs);
1187
1188         timeout(dgm_pause, &port->brdchan, hz/2);
1189         tsleep(&port->brdchan, TTIPRI | PCATCH, "dgclo", 0);
1190 }
1191
1192 static void
1193 dgm_pause(void *chan)
1194 {
1195         wakeup((caddr_t)chan);
1196 }
1197
1198 static void
1199 dgmpoll(void *unit_c)
1200 {
1201         int unit = (int)unit_c;
1202         int pnum;
1203         struct dgm_p *port;
1204         struct dgm_softc *sc;
1205         int head, tail;
1206         u_char *eventbuf;
1207         int event, mstat, lstat;
1208         volatile struct board_chan *bc;
1209         struct tty *tp;
1210         int rhead, rtail;
1211         int whead, wtail;
1212         int size;
1213         u_char *ptr;
1214         int ocount;
1215         int ibuf_full, obuf_full;
1216         BoardMemWinState ws = bmws_get();
1217
1218         sc = devclass_get_softc(dgmdevclass, unit);
1219         DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1220         callout_handle_init(&sc->toh);
1221
1222         if (!sc->enabled) {
1223                 printf("dgm%d: polling of disabled board stopped\n", unit);
1224                 return;
1225         }
1226
1227         setwin(sc, 0);
1228
1229         head = sc->mailbox->ein;
1230         tail = sc->mailbox->eout;
1231
1232         while (head != tail) {
1233                 if (head >= FEP_IMAX - FEP_ISTART
1234                 || tail >= FEP_IMAX - FEP_ISTART
1235                 || (head|tail) & 03 ) {
1236                         printf("dgm%d: event queue's head or tail is wrong!"
1237                             " hd = %d, tl = %d\n", unit, head, tail);
1238                         break;
1239                 }
1240
1241                 eventbuf = sc->vmem + tail + FEP_ISTART;
1242                 pnum = eventbuf[0];
1243                 event = eventbuf[1];
1244                 mstat = eventbuf[2];
1245                 lstat = eventbuf[3];
1246
1247                 port = &sc->ports[pnum];
1248                 bc = port->brdchan;
1249                 tp = &sc->ttys[pnum];
1250
1251                 if (pnum >= sc->numports || !port->enabled) {
1252                         printf("dgm%d: port%d: got event on nonexisting port\n",
1253                             unit, pnum);
1254                 } else if (port->used || port->wopeners > 0 ) {
1255
1256                         int wrapmask = port->rxbufsize - 1;
1257
1258                         if (!(event & ALL_IND))
1259                                 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1260                                         unit, pnum, event, mstat, lstat);
1261
1262                         if (event & DATA_IND) {
1263                                 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1264                                     unit, pnum);
1265
1266                                 rhead = bc->rin & wrapmask;
1267                                 rtail = bc->rout & wrapmask;
1268
1269                                 if (!(tp->t_cflag & CREAD) || !port->used ) {
1270                                         bc->rout = rhead;
1271                                         goto end_of_data;
1272                                 }
1273
1274                                 if (bc->orun) {
1275                                         printf("dgm%d: port%d: overrun\n", unit, pnum);
1276                                         bc->orun = 0;
1277                                 }
1278
1279                                 if (!(tp->t_state & TS_ISOPEN))
1280                                         goto end_of_data;
1281
1282                                 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1283                                         DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1284                                             " p rx head = %d tail = %d\n", unit,
1285                                             pnum, rhead, rtail);
1286
1287                                         if (rhead > rtail)
1288                                                 size = rhead - rtail;
1289                                         else
1290                                                 size = port->rxbufsize - rtail;
1291
1292                                         ptr = port->rxptr + rtail;
1293
1294 /* Helg: */
1295                                         if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1296                                                 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1297                                                 DPRINT1(DB_RXDATA, "*");
1298                                                 ibuf_full = TRUE;
1299                                         }
1300
1301                                         if (size) {
1302                                                 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1303                                                         DPRINT1(DB_RXDATA, "!");
1304                                                         towin(sc, port->rxwin);
1305                                                         tk_nin += size;
1306                                                         tk_rawcc += size;
1307                                                         tp->t_rawcc += size;
1308                                                         b_to_q(ptr, size,
1309                                                             &tp->t_rawq);
1310                                                         setwin(sc, 0);
1311                                                 } else {
1312                                                         int i = size;
1313                                                         unsigned char chr;
1314                                                         do {
1315                                                                 towin(sc, port->rxwin);
1316                                                                 chr = *ptr++;
1317                                                                 hidewin(sc);
1318                                                                (*linesw[tp->t_line].l_rint)(chr, tp);
1319                                                         } while (--i > 0 );
1320                                                         setwin(sc, 0);
1321                                                 }
1322                                         }
1323                                         rtail= (rtail + size) & wrapmask;
1324                                         bc->rout = rtail;
1325                                         rhead = bc->rin & wrapmask;
1326                                         hidewin(sc);
1327                                         ttwakeup(tp);
1328                                         setwin(sc, 0);
1329                                 }
1330                         end_of_data: ;
1331                         }
1332
1333                         if (event & MODEMCHG_IND) {
1334                                 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1335                                     "MODEMCHG_IND\n", unit, pnum);
1336                                 port->imodem = mstat;
1337                                 if (mstat & port->dcd) {
1338                                         hidewin(sc);
1339                                         linesw[tp->t_line].l_modem(tp, 1);
1340                                         setwin(sc, 0);
1341                                         wakeup(TSA_CARR_ON(tp));
1342                                 } else {
1343                                         hidewin(sc);
1344                                         linesw[tp->t_line].l_modem(tp, 0);
1345                                         setwin(sc, 0);
1346                                         if (port->draining) {
1347                                                 port->draining = 0;
1348                                                 wakeup(&port->draining);
1349                                         }
1350                                 }
1351                         }
1352
1353                         if (event & BREAK_IND) {
1354                                 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK))        {
1355                                         DPRINT3(DB_BREAK, "dgm%d: port%d:"
1356                                             " BREAK_IND\n", unit, pnum);
1357                                         hidewin(sc);
1358                                         linesw[tp->t_line].l_rint(TTY_BI, tp);
1359                                         setwin(sc, 0);
1360                                 }
1361                         }
1362
1363 /* Helg: with output flow control */
1364
1365                         if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1366                                 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1367                                     " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1368
1369                                 if ((event & EMPTYTX_IND ) &&
1370                                     tp->t_outq.c_cc == 0 && port->draining) {
1371                                         port->draining = 0;
1372                                         wakeup(&port->draining);
1373                                         bc->ilow = 0;
1374                                         bc->iempty = 0;
1375                                 } else {
1376
1377                                         int wrapmask = port->txbufsize - 1;
1378
1379                                         for (obuf_full = FALSE;
1380                                             tp->t_outq.c_cc != 0 && !obuf_full;
1381                                             ) {
1382                                                 int s;
1383                                                 /* add "last-minute" data to write buffer */
1384                                                 if (!(tp->t_state & TS_BUSY)) {
1385                                                         hidewin(sc);
1386 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
1387                                                         ttwwakeup(tp);
1388 #else
1389                                                         if (tp->t_outq.c_cc <= tp->t_lowat) {
1390                                                                 if (tp->t_state & TS_ASLEEP) {
1391                                                                         tp->t_state &= ~TS_ASLEEP;
1392                                                                         wakeup(TSA_OLOWAT(tp));
1393                                                                 }
1394                                                                 /* selwakeup(&tp->t_wsel); */
1395                                                         }
1396 #endif
1397                                                         setwin(sc, 0);
1398                                                 }
1399                                                 s = spltty();
1400
1401                                         whead = bc->tin & wrapmask;
1402                                         wtail = bc->tout & wrapmask;
1403
1404                                         if (whead < wtail)
1405                                                 size = wtail - whead - 1;
1406                                         else {
1407                                                 size = port->txbufsize - whead;
1408                                                 if (wtail == 0)
1409                                                         size--;
1410                                         }
1411
1412                                         if (size == 0) {
1413                                                 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1414                                                         whead, wtail, size, obuf_full);
1415                                                 bc->iempty = 1;
1416                                                 bc->ilow = 1;
1417                                                 obuf_full = TRUE;
1418                                                 splx(s);
1419                                                 break;
1420                                         }
1421
1422                                         towin(sc, port->txwin);
1423
1424                                         ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1425                                         whead += ocount;
1426
1427                                         setwin(sc, 0);
1428                                         bc->tin = whead;
1429                                         bc->tin = whead & wrapmask;
1430                                         splx(s);
1431                                 }
1432
1433                                 if (obuf_full) {
1434                                         DPRINT1(DB_WR, " +BUSY\n");
1435                                         tp->t_state |= TS_BUSY;
1436                                 } else {
1437                                         DPRINT1(DB_WR, " -BUSY\n");
1438                                         hidewin(sc);
1439 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
1440                                         /* should clear TS_BUSY before ttwwakeup */
1441                                         if (tp->t_state & TS_BUSY)      {
1442                                                 tp->t_state &= ~TS_BUSY;
1443                                                 linesw[tp->t_line].l_start(tp);
1444                                                 ttwwakeup(tp);
1445                                         }
1446 #else
1447                                 if (tp->t_state & TS_ASLEEP) {
1448                                         tp->t_state &= ~TS_ASLEEP;
1449                                         wakeup(TSA_OLOWAT(tp));
1450                                 }
1451                                 tp->t_state &= ~TS_BUSY;
1452 #endif
1453                                         setwin(sc, 0);
1454                                         }
1455                                 }
1456                         }
1457                         bc->idata = 1;   /* require event on incoming data */
1458
1459                 } else {
1460                         bc = port->brdchan;
1461                         DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1462                                 unit, pnum, event);
1463                         bc->rout = bc->rin;
1464                         bc->idata = bc->iempty = bc->ilow = 0;
1465                 }
1466
1467                 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1468         }
1469
1470         sc->mailbox->eout = tail;
1471         bmws_set(ws);
1472
1473         sc->toh = timeout(dgmpoll, unit_c, hz / POLLSPERSEC);
1474
1475         DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1476 }
1477
1478 static int
1479 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1480 {
1481         struct dgm_softc *sc;
1482         int unit, pnum;
1483         struct dgm_p *port;
1484         int mynor;
1485         struct tty *tp;
1486         volatile struct board_chan *bc;
1487         int error;
1488         int s, cs;
1489         int tiocm_xxx;
1490
1491 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1492         u_long          oldcmd;
1493         struct termios  term;
1494 #endif
1495
1496         BoardMemWinState ws = bmws_get();
1497
1498         mynor = minor(dev);
1499         unit = MINOR_TO_UNIT(mynor);
1500         pnum = MINOR_TO_PORT(mynor);
1501
1502         sc = devclass_get_softc(dgmdevclass, unit);
1503         port = &sc->ports[pnum];
1504         tp = &sc->ttys[pnum];
1505         bc = port->brdchan;
1506
1507         if (mynor & CONTROL_MASK) {
1508                 struct termios *ct;
1509
1510                 switch (mynor & CONTROL_MASK) {
1511                 case CONTROL_INIT_STATE:
1512                         ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1513                         break;
1514                 case CONTROL_LOCK_STATE:
1515                         ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1516                         break;
1517                 default:
1518                         return (ENODEV);        /* /dev/nodev */
1519                 }
1520                 switch (cmd) {
1521                 case TIOCSETA:
1522                         error = suser(td);
1523                         if (error != 0)
1524                                 return (error);
1525                         *ct = *(struct termios *)data;
1526                         return (0);
1527                 case TIOCGETA:
1528                         *(struct termios *)data = *ct;
1529                         return (0);
1530                 case TIOCGETD:
1531                         *(int *)data = TTYDISC;
1532                         return (0);
1533                 case TIOCGWINSZ:
1534                         bzero(data, sizeof(struct winsize));
1535                         return (0);
1536                 default:
1537                         return (ENOTTY);
1538                 }
1539         }
1540
1541 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1542         term = tp->t_termios;
1543         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1544           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);
1545         }
1546         oldcmd = cmd;
1547         error = ttsetcompat(tp, &cmd, data, &term);
1548         if (error != 0)
1549                 return (error);
1550         if (cmd != oldcmd)
1551                 data = (caddr_t)&term;
1552 #endif
1553
1554         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1555                 int     cc;
1556                 struct termios *dt = (struct termios *)data;
1557                 struct termios *lt = mynor & CALLOUT_MASK
1558                                      ? &port->lt_out : &port->lt_in;
1559
1560                 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);
1561                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1562                               | (dt->c_iflag & ~lt->c_iflag);
1563                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1564                               | (dt->c_oflag & ~lt->c_oflag);
1565                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1566                               | (dt->c_cflag & ~lt->c_cflag);
1567                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1568                               | (dt->c_lflag & ~lt->c_lflag);
1569                 for (cc = 0; cc < NCCS; ++cc)
1570                         if (lt->c_cc[cc] != 0)
1571                                 dt->c_cc[cc] = tp->t_cc[cc];
1572                 if (lt->c_ispeed != 0)
1573                         dt->c_ispeed = tp->t_ispeed;
1574                 if (lt->c_ospeed != 0)
1575                         dt->c_ospeed = tp->t_ospeed;
1576         }
1577
1578         if (cmd == TIOCSTOP) {
1579                 cs = splclock();
1580                 setwin(sc, 0);
1581                 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1582                 bmws_set(ws);
1583                 splx(cs);
1584                 return 0;
1585         } else if (cmd == TIOCSTART) {
1586                 cs = splclock();
1587                 setwin(sc, 0);
1588                 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1589                 bmws_set(ws);
1590                 splx(cs);
1591                 return 0;
1592         }
1593
1594         if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1595                 port->mustdrain = 1;
1596
1597         error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p);
1598         if (error != ENOIOCTL)
1599                 return error;
1600         s = spltty();
1601         error = ttioctl(tp, cmd, data, flag);
1602         disc_optim(tp, &tp->t_termios);
1603         port->mustdrain = 0;
1604         if (error != ENOIOCTL) {
1605                 splx(s);
1606                 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1607                         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);
1608                 }
1609                 return error;
1610         }
1611
1612         switch (cmd) {
1613         case TIOCSBRK:
1614 #if 0
1615                 error = dgmdrain(port);
1616
1617                 if (error != 0) {
1618                         splx(s);
1619                         return error;
1620                 }
1621 #endif
1622
1623                 cs = splclock();
1624                 setwin(sc, 0);
1625
1626                 /* now it sends 400 millisecond break because I don't know */
1627                 /* how to send an infinite break */
1628
1629                 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1630                 hidewin(sc);
1631                 splx(cs);
1632                 break;
1633         case TIOCCBRK:
1634                 /* now it's empty */
1635                 break;
1636         case TIOCSDTR:
1637                 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1638                 port->omodem |= DTR;
1639                 cs = splclock();
1640                 setwin(sc, 0);
1641                 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1642
1643                 if (!(bc->mstat & DTR))
1644                         DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1645
1646                 hidewin(sc);
1647                 splx(cs);
1648                 break;
1649         case TIOCCDTR:
1650                 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1651                 port->omodem &= ~DTR;
1652                 cs = splclock();
1653                 setwin(sc, 0);
1654                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1655
1656                 if (bc->mstat & DTR) {
1657                         DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1658                 }
1659
1660                 hidewin(sc);
1661                 splx(cs);
1662                 break;
1663         case TIOCMSET:
1664                 if (*(int *)data & TIOCM_DTR)
1665                         port->omodem |= DTR;
1666                 else
1667                         port->omodem &= ~DTR;
1668
1669                 if (*(int *)data & TIOCM_RTS)
1670                         port->omodem |= RTS;
1671                 else
1672                         port->omodem &= ~RTS;
1673
1674                 cs = splclock();
1675                 setwin(sc, 0);
1676                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1677                 hidewin(sc);
1678                 splx(cs);
1679                 break;
1680         case TIOCMBIS:
1681                 if (*(int *)data & TIOCM_DTR)
1682                         port->omodem |= DTR;
1683
1684                 if (*(int *)data & TIOCM_RTS)
1685                         port->omodem |= RTS;
1686
1687                 cs = splclock();
1688                 setwin(sc, 0);
1689                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1690                 hidewin(sc);
1691                 splx(cs);
1692                 break;
1693         case TIOCMBIC:
1694                 if (*(int *)data & TIOCM_DTR)
1695                         port->omodem &= ~DTR;
1696
1697                 if (*(int *)data & TIOCM_RTS)
1698                         port->omodem &= ~RTS;
1699
1700                 cs = splclock();
1701                 setwin(sc, 0);
1702                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1703                 hidewin(sc);
1704                 splx(cs);
1705                 break;
1706         case TIOCMGET:
1707                 setwin(sc, 0);
1708                 port->imodem = bc->mstat;
1709                 hidewin(sc);
1710
1711                 tiocm_xxx = TIOCM_LE;   /* XXX - always enabled while open */
1712
1713                 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1714
1715                 if (port->imodem & DTR) {
1716                         DPRINT1(DB_MODEM, "DTR ");
1717                         tiocm_xxx |= TIOCM_DTR;
1718                 }
1719                 if (port->imodem & RTS) {
1720                         DPRINT1(DB_MODEM, "RTS ");
1721                         tiocm_xxx |= TIOCM_RTS;
1722                 }
1723                 if (port->imodem & CTS) {
1724                         DPRINT1(DB_MODEM, "CTS ");
1725                         tiocm_xxx |= TIOCM_CTS;
1726                 }
1727                 if (port->imodem & port->dcd) {
1728                         DPRINT1(DB_MODEM, "DCD ");
1729                         tiocm_xxx |= TIOCM_CD;
1730                 }
1731                 if (port->imodem & port->dsr) {
1732                         DPRINT1(DB_MODEM, "DSR ");
1733                         tiocm_xxx |= TIOCM_DSR;
1734                 }
1735                 if (port->imodem & RI) {
1736                         DPRINT1(DB_MODEM, "RI ");
1737                         tiocm_xxx |= TIOCM_RI;
1738                 }
1739                 *(int *)data = tiocm_xxx;
1740                 DPRINT1(DB_MODEM, "--\n");
1741                 break;
1742         case TIOCMSDTRWAIT:
1743                 /* must be root since the wait applies to following logins */
1744                 error = suser(td);
1745                 if (error != 0) {
1746                         splx(s);
1747                         return (error);
1748                 }
1749                 port->close_delay = *(int *)data * hz / 100;
1750                 break;
1751         case TIOCMGDTRWAIT:
1752                 *(int *)data = port->close_delay * 100 / hz;
1753                 break;
1754         case TIOCTIMESTAMP:
1755                 port->do_timestamp = 1;
1756                 *(struct timeval *)data = port->timestamp;
1757                 break;
1758         case TIOCDCDTIMESTAMP:
1759                 port->do_dcd_timestamp = 1;
1760                 *(struct timeval *)data = port->dcd_timestamp;
1761                 break;
1762         default:
1763                 bmws_set(ws);
1764                 splx(s);
1765                 return ENOTTY;
1766         }
1767         bmws_set(ws);
1768         splx(s);
1769
1770         return 0;
1771 }
1772
1773 static void
1774 wakeflush(void *p)
1775 {
1776         struct dgm_p *port = p;
1777
1778         wakeup(&port->draining);
1779 }
1780
1781 /* wait for the output to drain */
1782
1783 static int
1784 dgmdrain(struct dgm_p *port)
1785 {
1786         volatile struct board_chan *bc = port->brdchan;
1787         struct dgm_softc *sc;
1788         int error;
1789         int head, tail;
1790         BoardMemWinState ws = bmws_get();
1791
1792         sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1793
1794         setwin(sc, 0);
1795
1796         bc->iempty = 1;
1797         tail = bc->tout;
1798         head = bc->tin;
1799
1800         while (tail != head) {
1801                 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1802                         port->sc->unit, port->pnum, head, tail);
1803
1804                 hidewin(sc);
1805                 port->draining = 1;
1806                 timeout(wakeflush, port, hz);
1807                 error = tsleep(&port->draining, TTIPRI | PCATCH, "dgdrn", 0);
1808                 port->draining = 0;
1809                 setwin(sc, 0);
1810
1811                 if (error != 0) {
1812                         DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1813                                 port->sc->unit, port->pnum, error);
1814
1815                         bc->iempty = 0;
1816                         bmws_set(ws);
1817                         return error;
1818                 }
1819
1820                 tail = bc->tout;
1821                 head = bc->tin;
1822         }
1823         DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1824                 port->sc->unit, port->pnum, head, tail);
1825         bmws_set(ws);
1826         return 0;
1827 }
1828
1829 /* wait for the output to drain */
1830 /* or simply clear the buffer it it's stopped */
1831
1832 static void
1833 dgm_drain_or_flush(struct dgm_p *port)
1834 {
1835         volatile struct board_chan *bc = port->brdchan;
1836         struct tty *tp = port->tty;
1837         struct dgm_softc *sc;
1838         int error;
1839         int lasttail;
1840         int head, tail;
1841
1842         sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1843         setwin(sc, 0);
1844
1845         lasttail = -1;
1846         bc->iempty = 1;
1847         tail = bc->tout;
1848         head = bc->tin;
1849
1850         while (tail != head /* && tail != lasttail */ ) {
1851                 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1852                         port->sc->unit, port->pnum, head, tail);
1853
1854                 /* if there is no carrier simply clean the buffer */
1855                 if (!(tp->t_state & TS_CARR_ON)) {
1856                         bc->tout = bc->tin = 0;
1857                         bc->iempty = 0;
1858                         hidewin(sc);
1859                         return;
1860                 }
1861
1862                 hidewin(sc);
1863                 port->draining = 1;
1864                 timeout(wakeflush, port, hz);
1865                 error = tsleep(&port->draining, TTIPRI | PCATCH, "dgfls", 0);
1866                 port->draining = 0;
1867                 setwin(sc, 0);
1868
1869                 if (error != 0) {
1870                         DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1871                             " error = %d\n", port->sc->unit, port->pnum, error);
1872
1873                         /* silently clean the buffer */
1874
1875                         bc->tout = bc->tin = 0;
1876                         bc->iempty = 0;
1877                         hidewin(sc);
1878                         return;
1879                 }
1880
1881                 lasttail = tail;
1882                 tail = bc->tout;
1883                 head = bc->tin;
1884         }
1885         hidewin(sc);
1886         DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1887                         port->sc->unit, port->pnum, head, tail);
1888 }
1889
1890 static int
1891 dgmparam(struct tty *tp, struct termios *t)
1892 {
1893         int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1894         int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1895         volatile struct board_chan *bc;
1896         struct dgm_softc *sc;
1897         struct dgm_p *port;
1898         int cflag;
1899         int head;
1900         int mval;
1901         int iflag;
1902         int hflow;
1903         int cs;
1904         BoardMemWinState ws = bmws_get();
1905
1906         sc = devclass_get_softc(dgmdevclass, unit);
1907         port = &sc->ports[pnum];
1908         bc = port->brdchan;
1909
1910         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);
1911
1912         if (port->mustdrain) {
1913                 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1914                 dgmdrain(port);
1915         }
1916
1917         cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1918
1919         if (t->c_ispeed == 0)
1920                 t->c_ispeed = t->c_ospeed;
1921
1922         if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1923                 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1924                 return (EINVAL);
1925         }
1926
1927         cs = splclock();
1928         setwin(sc, 0);
1929
1930         if (cflag == 0) { /* hangup */
1931                 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1932                 head = bc->rin;
1933                 bc->rout = head;
1934                 head = bc->tin;
1935                 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1936                 mval= port->omodem & ~(DTR|RTS);
1937         } else {
1938                 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1939
1940                 if (cflag != port->fepcflag) {
1941                         port->fepcflag = cflag;
1942                         DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1943                                         unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1944                         fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1945                 }
1946                 mval= port->omodem | (DTR|RTS);
1947         }
1948
1949         iflag = dgmflags(dgm_iflags, t->c_iflag);
1950         if (iflag != port->fepiflag) {
1951                 port->fepiflag = iflag;
1952                 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1953                 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1954         }
1955
1956         bc->mint = port->dcd;
1957
1958         hflow = dgmflags(dgm_flow, t->c_cflag);
1959         if (hflow != port->hflow) {
1960                 port->hflow = hflow;
1961                 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1962                 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1963         }
1964
1965         if (port->omodem != mval) {
1966                 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1967                         unit, pnum, mval, port->omodem);
1968                 port->omodem = mval;
1969                 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1970         }
1971
1972         if (port->fepstartc != t->c_cc[VSTART] ||
1973             port->fepstopc != t->c_cc[VSTOP]) {
1974                 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1975                 port->fepstartc = t->c_cc[VSTART];
1976                 port->fepstopc = t->c_cc[VSTOP];
1977                 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1978         }
1979
1980         bmws_set(ws);
1981         splx(cs);
1982
1983         return 0;
1984
1985 }
1986
1987 static void
1988 dgmstart(struct tty *tp)
1989 {
1990         int unit;
1991         int pnum;
1992         struct dgm_p *port;
1993         struct dgm_softc *sc;
1994         volatile struct board_chan *bc;
1995         int head, tail;
1996         int size, ocount;
1997         int s;
1998         int wmask;
1999
2000         BoardMemWinState ws = bmws_get();
2001
2002         unit = MINOR_TO_UNIT(minor(tp->t_dev));
2003         pnum = MINOR_TO_PORT(minor(tp->t_dev));
2004         sc = devclass_get_softc(dgmdevclass, unit);
2005         port = &sc->ports[pnum];
2006         bc = port->brdchan;
2007
2008         wmask = port->txbufsize - 1;
2009
2010         s = spltty();
2011
2012         while (tp->t_outq.c_cc != 0) {
2013                 int cs;
2014 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2015                 ttwwakeup(tp);
2016 #else
2017                 if (tp->t_outq.c_cc <= tp->t_lowat) {
2018                         if (tp->t_state & TS_ASLEEP) {
2019                                 tp->t_state &= ~TS_ASLEEP;
2020                                 wakeup(TSA_OLOWAT(tp));
2021                         }
2022                         /*selwakeup(&tp->t_wsel);*/
2023                 }
2024 #endif
2025                 cs = splclock();
2026                 setwin(sc, 0);
2027
2028                 head = bc->tin & wmask;
2029
2030                 do { tail = bc->tout; } while (tail != bc->tout);
2031                 tail = bc->tout & wmask;
2032
2033                 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2034
2035 #ifdef LEAVE_FREE_CHARS
2036                 if (tail > head) {
2037                         size = tail - head - LEAVE_FREE_CHARS;
2038                         if (size < 0)
2039                                 size = 0;
2040                         else {
2041                                 size = port->txbufsize - head;
2042                                 if (tail + port->txbufsize < head)
2043                                         size = 0;
2044                         }
2045                 }
2046 #else
2047                 if (tail > head)
2048                         size = tail - head - 1;
2049                 else {
2050                         size = port->txbufsize - head;
2051                         if (tail == 0)
2052                                 size--;
2053                 }
2054 #endif
2055
2056                 if (size == 0) {
2057                         bc->iempty = 1;
2058                         bc->ilow = 1;
2059                         splx(cs);
2060                         bmws_set(ws);
2061                         tp->t_state |= TS_BUSY;
2062                         splx(s);
2063                         return;
2064                 }
2065
2066                 towin(sc, port->txwin);
2067
2068                 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2069                 head += ocount;
2070                 if (head >= port->txbufsize)
2071                         head -= port->txbufsize;
2072
2073                 setwin(sc, 0);
2074                 bc->tin = head;
2075
2076                 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2077                     unit, pnum, size, ocount);
2078                 hidewin(sc);
2079                 splx(cs);
2080         }
2081
2082         bmws_set(ws);
2083         splx(s);
2084
2085 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2086         if (tp->t_state & TS_BUSY) {
2087                 tp->t_state &= ~TS_BUSY;
2088                 linesw[tp->t_line].l_start(tp);
2089                 ttwwakeup(tp);
2090         }
2091 #else
2092         if (tp->t_state & TS_ASLEEP) {
2093                 tp->t_state &= ~TS_ASLEEP;
2094                 wakeup(TSA_OLOWAT(tp));
2095         }
2096         tp->t_state& = ~TS_BUSY;
2097 #endif
2098 }
2099
2100 void
2101 dgmstop(struct tty *tp, int rw)
2102 {
2103         int unit;
2104         int pnum;
2105         struct dgm_p *port;
2106         struct dgm_softc *sc;
2107         volatile struct board_chan *bc;
2108         int s;
2109
2110         BoardMemWinState ws = bmws_get();
2111
2112         unit = MINOR_TO_UNIT(minor(tp->t_dev));
2113         pnum = MINOR_TO_PORT(minor(tp->t_dev));
2114
2115         sc = devclass_get_softc(dgmdevclass, unit);
2116         port = &sc->ports[pnum];
2117         bc = port->brdchan;
2118
2119         DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2120
2121         s = spltty();
2122         setwin(sc, 0);
2123
2124         if (rw & FWRITE) {
2125                 /* clear output queue */
2126                 bc->tout = bc->tin = 0;
2127                 bc->ilow = 0;
2128                 bc->iempty = 0;
2129         }
2130         if (rw & FREAD) {
2131                 /* clear input queue */
2132                 bc->rout = bc->rin;
2133                 bc->idata = 1;
2134         }
2135         hidewin(sc);
2136         bmws_set(ws);
2137         splx(s);
2138         dgmstart(tp);
2139 }
2140
2141 static void
2142 fepcmd(struct dgm_p *port,
2143         unsigned cmd,
2144         unsigned op1,
2145         unsigned op2,
2146         unsigned ncmds,
2147         unsigned bytecmd)
2148 {
2149         u_char *mem;
2150         unsigned tail, head;
2151         int count, n;
2152
2153         KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2154         mem = port->sc->vmem;
2155
2156         if (!port->enabled) {
2157                 printf("dgm%d: port%d: FEP command on disabled port\n",
2158                         port->sc->unit, port->pnum);
2159                 return;
2160         }
2161
2162         /* setwin(port->sc, 0); Require this to be set by caller */
2163         head = port->sc->mailbox->cin;
2164
2165         if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2166                 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2167                         port->sc->unit, port->pnum, head);
2168                 return;
2169         }
2170
2171         mem[head + FEP_CSTART] = cmd;
2172         mem[head + FEP_CSTART + 1] = port->pnum;
2173         if (bytecmd) {
2174                 mem[head + FEP_CSTART + 2] = op1;
2175                 mem[head + FEP_CSTART + 3] = op2;
2176         } else {
2177                 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2178                 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2179         }
2180
2181         DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2182                         (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2183
2184         head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2185         port->sc->mailbox->cin = head;
2186
2187         count = FEPTIMEOUT;
2188
2189         while (count-- != 0) {
2190                 head = port->sc->mailbox->cin;
2191                 tail = port->sc->mailbox->cout;
2192
2193                 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2194                 if (n <= ncmds * (sizeof(ushort)*4))
2195                         return;
2196         }
2197         printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2198 }
2199
2200 static void
2201 disc_optim(struct tty *tp, struct termios *t)
2202 {
2203         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2204             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2205             && (!(t->c_iflag & PARMRK)
2206                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2207             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2208             && linesw[tp->t_line].l_rint == ttyinput)
2209                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2210         else
2211                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2212 }