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