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.9 2004/05/19 22:52:49 dillon Exp $
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>
11 * Stage 1. "Better than nothing".
12 * Stage 2. "Gee, it works!".
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
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.
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
38 * Written by Sergey Babkin,
39 * Joint Stock Commercial Bank "Chelindbank"
40 * (Chelyabinsk, Russia)
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 &
50 * Sysctl debug flag is now a bitflag, to filter noise during debugging.
51 * David L. Nugent <davidn@blaze.net.au>
53 * New-busification by Brian Somers <brian@Awfulhak.org>
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.
66 /* How often to run dgmpoll */
67 #define POLLSPERSEC 25
69 /* How many charactes can we write to input tty rawq */
70 #define DGB_IBUFSIZE (TTYHOG - 100)
72 /* the overall number of ports controlled by this driver */
74 #include <sys/param.h>
76 #include <sys/systm.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>
89 #include <machine/bus.h>
91 #include <machine/resource.h>
93 #include <machine/clock.h>
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)
113 #define MEM_SIZE 0x8000
115 #define DGM_UNITMASK 0x30000
116 #define DGM_UNIT(unit) ((unit) << 16)
120 /* digiboard port structure */
122 unsigned enabled : 1;
124 struct dgm_softc *sc; /* parent softc */
125 u_char pnum; /* port number */
126 u_char omodem; /* FEP output modem status */
127 u_char imodem; /* FEP input modem status */
128 u_char modemfake; /* Modem values to be forced */
129 u_char modem; /* Force values */
153 volatile struct board_chan *brdchan;
156 u_char active_out; /* nonzero if the callout device is open */
157 u_int wopeners; /* # processes waiting for DCD in open() */
160 struct termios it_in; /* should be in struct tty */
161 struct termios it_out;
164 struct termios lt_in; /* should be in struct tty */
165 struct termios lt_out;
167 unsigned do_timestamp : 1;
168 unsigned do_dcd_timestamp : 1;
169 struct timeval timestamp;
170 struct timeval dcd_timestamp;
172 /* flags of state, are used in sleep() too */
173 u_char closing; /* port is being closed now */
174 u_char draining; /* port is being drained now */
175 u_char used; /* port is being used now */
176 u_char mustdrain; /* data must be waited to drain in dgmparam() */
179 /* Digiboard per-board structure */
181 /* struct board_info */
182 unsigned enabled : 1;
183 u_char unit; /* unit number */
184 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
185 u_char altpin; /* do we need alternate pin setting ? */
186 int numports; /* number of ports on card */
187 u_long port; /* I/O port */
188 u_char *vmem; /* virtual memory address */
189 u_long pmem; /* physical memory address */
190 int mem_seg; /* internal memory segment */
191 struct dgm_p *ports; /* ptr to array of port descriptors */
192 struct tty *ttys; /* ptr to array of TTY structures */
193 volatile struct global_data *mailbox;
194 struct resource *io_res;
195 struct resource *mem_res;
198 struct callout_handle toh; /* poll timeout handle */
201 static void dgmpoll(void *);
202 static int dgmprobe(device_t);
203 static int dgmattach(device_t);
204 static int dgmdetach(device_t);
205 static int dgmshutdown(device_t);
206 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
208 static void dgmstart(struct tty *);
209 static void dgmstop(struct tty *, int);
210 static int dgmparam(struct tty *, struct termios *);
211 static void dgmhardclose(struct dgm_p *);
212 static void dgm_drain_or_flush(struct dgm_p *);
213 static int dgmdrain(struct dgm_p *);
214 static void dgm_pause(void *);
215 static void wakeflush(void *);
216 static void disc_optim(struct tty *, struct termios *);
218 static d_open_t dgmopen;
219 static d_close_t dgmclose;
220 static d_ioctl_t dgmioctl;
222 static device_method_t dgmmethods[] = {
223 /* Device interface */
224 DEVMETHOD(device_probe, dgmprobe),
225 DEVMETHOD(device_attach, dgmattach),
226 DEVMETHOD(device_detach, dgmdetach),
227 DEVMETHOD(device_shutdown, dgmshutdown),
231 static driver_t dgmdriver = {
234 sizeof (struct dgm_softc),
237 static devclass_t dgmdevclass;
239 #define CDEV_MAJOR 101
240 static struct cdevsw dgm_cdevsw = {
242 /* maj */ CDEV_MAJOR,
243 /* flags */ D_TTY | D_KQFILTER,
248 /* close */ dgmclose,
250 /* write */ ttywrite,
251 /* ioctl */ dgmioctl,
254 /* strategy */ nostrategy,
257 /* kqfilter */ ttykqfilter
261 dgmmodhandler(module_t mod, int event, void *arg)
275 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
277 static speed_t dgmdefaultrate = TTYDEF_SPEED;
279 static struct speedtab dgmspeedtab[] = {
280 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
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 */
301 static struct dbgflagtbl {
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 },
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 },
327 { CRTSCTS, CRTSCTS, CTS|RTS },
328 { CRTSCTS, CCTS_OFLOW, CTS },
329 { CRTSCTS, CRTS_IFLOW, RTS },
333 /* xlat bsd termios flags to dgm sys-v style */
335 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
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;
347 static int dgmdebug = 0;
348 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
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);
354 /*Helg: to allow recursive dgm...() calls */
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 */
362 #define DATA_WINOFF 0
363 static BoardMemWinState bmws;
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
374 /* return current memory window state and close window */
375 static BoardMemWinState
378 BoardMemWinState bmwsRet = bmws;
380 if (bmws.data != DATA_WINOFF)
381 outb(bmws.port, bmws.data = DATA_WINOFF);
385 /* restore memory window state */
387 bmws_set(BoardMemWinState ws)
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);
399 setwin(struct dgm_softc *sc, unsigned int addr)
401 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
402 return (addr & 0x7FFF);
406 hidewin(struct dgm_softc *sc)
409 outb(bmws.port = sc->port + 1, bmws.data);
413 towin(struct dgm_softc *sc, int win)
415 outb(bmws.port = sc->port + 1, bmws.data = win);
419 dgmprobe(device_t dev)
421 struct dgm_softc *sc = device_get_softc(dev);
425 * Assign unit number. Due to bits we use in the minor number for
426 * the various tty types, only 4 units are supported.
428 sc->unit = device_get_unit(dev);
430 device_printf(dev, "Too many units, only 4 supported\n");
434 /* Check that we've got a valid i/o address */
435 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
437 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
438 if (sc->port == validio[i])
441 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
445 /* Ditto for our memory address */
446 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
448 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
449 if (sc->pmem == validmem[i])
452 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
455 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
456 device_printf(dev, "0x%lx: Memory address not supported\n",
460 sc->vmem = (u_char *)sc->pmem;
462 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
465 /* Temporarily map our io ports */
467 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
468 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
469 if (sc->io_res == NULL)
472 outb(sc->port, FEPRST);
475 for (i = 0; i < 1000; i++) {
477 if ((inb(sc->port) & FEPMASK) == FEPRST) {
479 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
486 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
487 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
491 /* check type of card and get internal memory characteristics */
499 second = inb(sc->port);
500 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
502 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
505 sc->mem_seg = 0x8000;
507 /* Temporarily map our memory too */
509 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
510 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
511 if (sc->mem_res == NULL) {
512 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
513 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
517 outb(sc->port, FEPCLR); /* drop RESET */
518 hidewin(sc); /* Helg: to set initial bmws state */
520 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
521 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
523 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
524 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
526 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
532 dgmattach(device_t dev)
534 struct dgm_softc *sc = device_get_softc(dev);
540 volatile struct board_chan *bc;
543 u_long msize, iosize;
545 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
547 sc->unit = device_get_unit(dev);
548 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
549 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
550 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
552 sc->mem_seg = 0x8000;
555 sc->mem_seg = 0x8000;
557 /* Allocate resources (should have been verified in dgmprobe()) */
559 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
560 0ul, ~0ul, iosize, RF_ACTIVE);
561 if (sc->io_res == NULL)
564 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
565 0ul, ~0ul, msize, RF_ACTIVE);
566 if (sc->mem_res == NULL) {
567 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
568 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
573 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
575 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
578 outb(sc->port, FEPRST);
581 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
583 device_printf(dev, "1st reset failed\n");
586 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
587 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
593 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
595 t = sc->pmem >> 8; /* disable windowing */
596 outb(sc->port + 2, t & 0xFF);
597 outb(sc->port + 3, t >> 8);
601 /* very short memory test */
602 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
604 addr = setwin(sc, BOTWIN);
605 *(u_long *)(mem + addr) = 0xA55A3CC3;
606 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
607 device_printf(dev, "1st memory test failed\n");
610 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
611 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
615 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
617 addr = setwin(sc, TOPWIN);
618 *(u_long *)(mem + addr) = 0x5AA5C33C;
619 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
620 device_printf(dev, "2nd memory test failed\n");
623 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
624 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
628 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
630 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
631 *(u_long *)(mem + addr) = 0x5AA5C33C;
632 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
633 device_printf(dev, "3rd (BIOS) memory test failed\n");
635 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
637 addr = setwin(sc, MISCGLOBAL);
638 for (i = 0; i < 16; i++)
641 addr = setwin(sc, BIOSOFFSET);
643 for (i = 0; ptr < mem + msize; i++)
644 *ptr++ = pcem_bios[i];
646 ptr = mem + BIOSOFFSET;
647 for (i = 0; ptr < mem + msize; i++) {
648 if (*ptr++ != pcem_bios[i]) {
649 printf("Low BIOS load failed\n");
652 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
653 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
657 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
659 addr = setwin(sc, msize);
661 for (;i < pcem_nbios; i++)
662 *ptr++ = pcem_bios[i];
665 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
666 if (*ptr++ != pcem_bios[i]) {
667 printf("High BIOS load failed\n");
670 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
671 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
675 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
676 device_printf(dev, "DigiBIOS loaded, initializing");
678 addr = setwin(sc, 0);
680 *(u_int *)(mem + addr) = 0x0bf00401;
681 *(u_int *)(mem + addr + 4) = 0;
682 *(ushort *)(mem + addr + 0xc00) = 0;
685 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
688 printf("\nBIOS initialize failed(1)\n");
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);
697 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
698 printf("\nBIOS initialize failed(2)\n");
701 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
702 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
705 printf(", DigiBIOS running\n");
709 addr = setwin(sc, BIOSOFFSET);
711 for (i = 0; i < pcem_ncook; i++)
712 *ptr++ = pcem_cook[i];
714 ptr = mem + BIOSOFFSET;
715 for (i = 0; i < pcem_ncook; i++) {
716 if (*ptr++ != pcem_cook[i]) {
717 printf("FEP/OS load failed\n");
720 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
721 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
725 device_printf(dev, "FEP/OS loaded, initializing");
727 addr = setwin(sc, 0);
728 *(ushort *)(mem + addr + 0xd20) = 0;
729 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
730 *(u_int *)(mem + addr + 0xc30) = 0x3L;
733 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
736 printf("\nFEP/OS initialize failed(1)\n");
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);
745 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
746 printf("\nFEP/OS initialize failed(2)\n");
749 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
750 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
753 printf(", FEP/OS running\n");
755 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
756 device_printf(dev, "%d ports attached\n", sc->numports);
758 if (sc->numports > MAX_DGM_PORTS) {
759 printf("dgm%d: too many ports\n", sc->unit);
762 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
763 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
767 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
768 M_TTYS, M_WAITOK|M_ZERO);
769 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
770 M_TTYS, M_WAITOK|M_ZERO);
772 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
773 for (i = 0; i < sc->numports; i++)
774 sc->ports[i].enabled = 1;
776 /* We should now init per-port structures */
778 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
779 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
781 if (sc->numports < 3)
786 cdevsw_add(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
787 for (i = 0; i < sc->numports; i++, bc++) {
788 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
789 port = &sc->ports[i];
792 port->tty = &sc->ttys[i];
800 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
802 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
803 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
807 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
808 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
809 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
810 port->txwin = FEPWIN | (bc->tseg >> 11);
811 port->rxwin = FEPWIN | (bc->rseg >> 11);
815 port->txbufsize = bc->tmax + 1;
816 port->rxbufsize = bc->rmax + 1;
818 lowwater = (port->txbufsize >= 2000) ?
819 1024 : (port->txbufsize / 2);
822 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
823 sc->unit, i, lowwater);
824 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
825 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
826 sc->unit, i, port->rxbufsize / 4);
827 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
828 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
829 sc->unit, i, 3 * port->rxbufsize / 4);
830 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
835 port->startc = bc->startc;
836 port->startca = bc->startca;
837 port->stopc = bc->stopc;
838 port->stopca = bc->stopca;
840 /* port->close_delay = 50; */
841 port->close_delay = 3 * hz;
842 port->do_timestamp = 0;
843 port->do_dcd_timestamp = 0;
845 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
847 * We don't use all the flags from <sys/ttydefaults.h> since
848 * they are only relevant for logins. It's important to have
849 * echo off initially so that the line doesn't start
850 * blathering before the echo flag can be turned off.
852 port->it_in.c_iflag = TTYDEF_IFLAG;
853 port->it_in.c_oflag = TTYDEF_OFLAG;
854 port->it_in.c_cflag = TTYDEF_CFLAG;
855 port->it_in.c_lflag = TTYDEF_LFLAG;
856 termioschars(&port->it_in);
857 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
858 port->it_out = port->it_in;
860 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
861 make_dev(&dgm_cdevsw, (sc->unit*65536) + i, UID_ROOT,
862 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
863 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 64, UID_ROOT,
864 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
865 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 128, UID_ROOT,
866 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
867 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262144, UID_UUCP,
868 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
869 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262208, UID_UUCP,
870 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
871 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262272, UID_UUCP,
872 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
875 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
879 /* start the polling function */
880 sc->toh = timeout(dgmpoll, (void *)(int)sc->unit, hz / POLLSPERSEC);
882 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
888 dgmdetach(device_t dev)
890 struct dgm_softc *sc = device_get_softc(dev);
893 for (i = 0; i < sc->numports; i++)
894 if (sc->ttys[i].t_state & TS_ISOPEN)
897 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
900 * The cdevsw_remove() call will destroy all associated devices
901 * and dereference any ad-hoc-created devices, but does not
902 * dereference devices created via make_dev().
904 cdevsw_remove(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
906 untimeout(dgmpoll, (void *)(int)sc->unit, sc->toh);
907 callout_handle_init(&sc->toh);
909 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
910 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
912 FREE(sc->ports, M_TTYS);
913 FREE(sc->ttys, M_TTYS);
919 dgmshutdown(device_t dev)
922 struct dgm_softc *sc = device_get_softc(dev);
924 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
932 dgmopen(dev_t dev, int flag, int mode, struct thread *td)
934 struct dgm_softc *sc;
942 volatile struct board_chan *bc;
946 unit = MINOR_TO_UNIT(mynor);
947 pnum = MINOR_TO_PORT(mynor);
949 sc = devclass_get_softc(dgmdevclass, unit);
951 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
956 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
959 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
964 if (pnum >= sc->numports) {
965 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
970 if (mynor & CONTROL_MASK)
973 tp = &sc->ttys[pnum];
975 port = &sc->ports[pnum];
981 while (port->closing) {
982 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
985 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
986 " error = %d\n", unit, pnum, error);
991 if (tp->t_state & TS_ISOPEN) {
993 * The device is open, so everything has been initialized.
996 if (mynor & CALLOUT_MASK) {
997 if (!port->active_out) {
999 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1000 " BUSY error = %d\n", unit, pnum, error);
1003 } else if (port->active_out) {
1004 if (flag & O_NONBLOCK) {
1006 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1007 " BUSY error = %d\n", unit, pnum, error);
1010 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1012 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1013 " error = %d\n", unit, pnum, error);
1019 if (tp->t_state & TS_XCLUDE && suser(td)) {
1025 * The device isn't open, so there are no conflicts.
1026 * Initialize it. Initialization is done twice in many
1027 * cases: to preempt sleeping callin opens if we are
1028 * callout, and to complete a callin open after DCD rises.
1030 tp->t_oproc = dgmstart;
1031 tp->t_param = dgmparam;
1032 tp->t_stop = dgmstop;
1034 tp->t_termios= (mynor & CALLOUT_MASK) ?
1040 port->imodem = bc->mstat;
1041 bc->rout = bc->rin; /* clear input queue */
1043 #ifdef PRINT_BUFSIZE
1044 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1045 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1052 error = dgmparam(tp, &tp->t_termios);
1056 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1061 /* handle fake DCD for callout devices */
1062 /* and initial DCD */
1064 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1065 linesw[tp->t_line].l_modem(tp, 1);
1069 * Wait for DCD if necessary.
1071 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1072 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1074 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1077 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1078 " error = %d\n", unit, pnum, error);
1084 error = linesw[tp->t_line].l_open(dev, tp);
1085 disc_optim(tp, &tp->t_termios);
1086 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1089 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1090 port->active_out = 1;
1094 /* If any port is open (i.e. the open() call is completed for it)
1095 * the device is busy
1099 disc_optim(tp, &tp->t_termios);
1102 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1105 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1113 dgmclose(dev_t dev, int flag, int mode, struct thread *td)
1118 struct dgm_softc *sc;
1124 if (mynor & CONTROL_MASK)
1126 unit = MINOR_TO_UNIT(mynor);
1127 pnum = MINOR_TO_PORT(mynor);
1129 sc = devclass_get_softc(dgmdevclass, unit);
1130 tp = &sc->ttys[pnum];
1131 port = sc->ports + pnum;
1133 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1135 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1136 dgm_drain_or_flush(port);
1141 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1142 linesw[tp->t_line].l_close(tp, flag);
1143 disc_optim(tp, &tp->t_termios);
1145 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1147 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1150 wakeup(&port->closing);
1153 /* mark the card idle when all ports are closed */
1155 for (i = 0; i < sc->numports; i++)
1156 if (sc->ports[i].used)
1161 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1163 wakeup(TSA_CARR_ON(tp));
1164 wakeup(&port->active_out);
1165 port->active_out = 0;
1167 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1173 dgmhardclose(struct dgm_p *port)
1175 volatile struct board_chan *bc = port->brdchan;
1176 struct dgm_softc *sc;
1179 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1180 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1182 port->do_timestamp = 0;
1188 if (port->tty->t_cflag & HUPCL) {
1189 port->omodem &= ~(RTS|DTR);
1190 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1196 timeout(dgm_pause, &port->brdchan, hz/2);
1197 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1201 dgm_pause(void *chan)
1203 wakeup((caddr_t)chan);
1207 dgmpoll(void *unit_c)
1209 int unit = (int)unit_c;
1212 struct dgm_softc *sc;
1215 int event, mstat, lstat;
1216 volatile struct board_chan *bc;
1223 int ibuf_full, obuf_full;
1224 BoardMemWinState ws = bmws_get();
1226 sc = devclass_get_softc(dgmdevclass, unit);
1227 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1228 callout_handle_init(&sc->toh);
1231 printf("dgm%d: polling of disabled board stopped\n", unit);
1237 head = sc->mailbox->ein;
1238 tail = sc->mailbox->eout;
1240 while (head != tail) {
1241 if (head >= FEP_IMAX - FEP_ISTART
1242 || tail >= FEP_IMAX - FEP_ISTART
1243 || (head|tail) & 03 ) {
1244 printf("dgm%d: event queue's head or tail is wrong!"
1245 " hd = %d, tl = %d\n", unit, head, tail);
1249 eventbuf = sc->vmem + tail + FEP_ISTART;
1251 event = eventbuf[1];
1252 mstat = eventbuf[2];
1253 lstat = eventbuf[3];
1255 port = &sc->ports[pnum];
1257 tp = &sc->ttys[pnum];
1259 if (pnum >= sc->numports || !port->enabled) {
1260 printf("dgm%d: port%d: got event on nonexisting port\n",
1262 } else if (port->used || port->wopeners > 0 ) {
1264 int wrapmask = port->rxbufsize - 1;
1266 if (!(event & ALL_IND))
1267 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1268 unit, pnum, event, mstat, lstat);
1270 if (event & DATA_IND) {
1271 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1274 rhead = bc->rin & wrapmask;
1275 rtail = bc->rout & wrapmask;
1277 if (!(tp->t_cflag & CREAD) || !port->used ) {
1283 printf("dgm%d: port%d: overrun\n", unit, pnum);
1287 if (!(tp->t_state & TS_ISOPEN))
1290 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1291 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1292 " p rx head = %d tail = %d\n", unit,
1293 pnum, rhead, rtail);
1296 size = rhead - rtail;
1298 size = port->rxbufsize - rtail;
1300 ptr = port->rxptr + rtail;
1303 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1304 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1305 DPRINT1(DB_RXDATA, "*");
1310 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1311 DPRINT1(DB_RXDATA, "!");
1312 towin(sc, port->rxwin);
1315 tp->t_rawcc += size;
1323 towin(sc, port->rxwin);
1326 (*linesw[tp->t_line].l_rint)(chr, tp);
1331 rtail= (rtail + size) & wrapmask;
1333 rhead = bc->rin & wrapmask;
1341 if (event & MODEMCHG_IND) {
1342 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1343 "MODEMCHG_IND\n", unit, pnum);
1344 port->imodem = mstat;
1345 if (mstat & port->dcd) {
1347 linesw[tp->t_line].l_modem(tp, 1);
1349 wakeup(TSA_CARR_ON(tp));
1352 linesw[tp->t_line].l_modem(tp, 0);
1354 if (port->draining) {
1356 wakeup(&port->draining);
1361 if (event & BREAK_IND) {
1362 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1363 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1364 " BREAK_IND\n", unit, pnum);
1366 linesw[tp->t_line].l_rint(TTY_BI, tp);
1371 /* Helg: with output flow control */
1373 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1374 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1375 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1377 if ((event & EMPTYTX_IND ) &&
1378 tp->t_outq.c_cc == 0 && port->draining) {
1380 wakeup(&port->draining);
1385 int wrapmask = port->txbufsize - 1;
1387 for (obuf_full = FALSE;
1388 tp->t_outq.c_cc != 0 && !obuf_full;
1391 /* add "last-minute" data to write buffer */
1392 if (!(tp->t_state & TS_BUSY)) {
1394 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1397 if (tp->t_outq.c_cc <= tp->t_lowat) {
1398 if (tp->t_state & TS_ASLEEP) {
1399 tp->t_state &= ~TS_ASLEEP;
1400 wakeup(TSA_OLOWAT(tp));
1402 /* selwakeup(&tp->t_wsel); */
1409 whead = bc->tin & wrapmask;
1410 wtail = bc->tout & wrapmask;
1413 size = wtail - whead - 1;
1415 size = port->txbufsize - whead;
1421 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1422 whead, wtail, size, obuf_full);
1430 towin(sc, port->txwin);
1432 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1437 bc->tin = whead & wrapmask;
1442 DPRINT1(DB_WR, " +BUSY\n");
1443 tp->t_state |= TS_BUSY;
1445 DPRINT1(DB_WR, " -BUSY\n");
1447 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1448 /* should clear TS_BUSY before ttwwakeup */
1449 if (tp->t_state & TS_BUSY) {
1450 tp->t_state &= ~TS_BUSY;
1451 linesw[tp->t_line].l_start(tp);
1455 if (tp->t_state & TS_ASLEEP) {
1456 tp->t_state &= ~TS_ASLEEP;
1457 wakeup(TSA_OLOWAT(tp));
1459 tp->t_state &= ~TS_BUSY;
1465 bc->idata = 1; /* require event on incoming data */
1469 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1472 bc->idata = bc->iempty = bc->ilow = 0;
1475 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1478 sc->mailbox->eout = tail;
1481 sc->toh = timeout(dgmpoll, unit_c, hz / POLLSPERSEC);
1483 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1487 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1489 struct dgm_softc *sc;
1494 volatile struct board_chan *bc;
1499 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1501 struct termios term;
1504 BoardMemWinState ws = bmws_get();
1507 unit = MINOR_TO_UNIT(mynor);
1508 pnum = MINOR_TO_PORT(mynor);
1510 sc = devclass_get_softc(dgmdevclass, unit);
1511 port = &sc->ports[pnum];
1512 tp = &sc->ttys[pnum];
1515 if (mynor & CONTROL_MASK) {
1518 switch (mynor & CONTROL_MASK) {
1519 case CONTROL_INIT_STATE:
1520 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1522 case CONTROL_LOCK_STATE:
1523 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1526 return (ENODEV); /* /dev/nodev */
1533 *ct = *(struct termios *)data;
1536 *(struct termios *)data = *ct;
1539 *(int *)data = TTYDISC;
1542 bzero(data, sizeof(struct winsize));
1549 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1550 term = tp->t_termios;
1551 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1552 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-ISNOW c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, term.c_cflag, term.c_iflag, term.c_lflag);
1555 error = ttsetcompat(tp, &cmd, data, &term);
1559 data = (caddr_t)&term;
1562 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1564 struct termios *dt = (struct termios *)data;
1565 struct termios *lt = mynor & CALLOUT_MASK
1566 ? &port->lt_out : &port->lt_in;
1568 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);
1569 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1570 | (dt->c_iflag & ~lt->c_iflag);
1571 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1572 | (dt->c_oflag & ~lt->c_oflag);
1573 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1574 | (dt->c_cflag & ~lt->c_cflag);
1575 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1576 | (dt->c_lflag & ~lt->c_lflag);
1577 for (cc = 0; cc < NCCS; ++cc)
1578 if (lt->c_cc[cc] != 0)
1579 dt->c_cc[cc] = tp->t_cc[cc];
1580 if (lt->c_ispeed != 0)
1581 dt->c_ispeed = tp->t_ispeed;
1582 if (lt->c_ospeed != 0)
1583 dt->c_ospeed = tp->t_ospeed;
1586 if (cmd == TIOCSTOP) {
1589 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1593 } else if (cmd == TIOCSTART) {
1596 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1602 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1603 port->mustdrain = 1;
1605 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
1606 if (error != ENOIOCTL)
1609 error = ttioctl(tp, cmd, data, flag);
1610 disc_optim(tp, &tp->t_termios);
1611 port->mustdrain = 0;
1612 if (error != ENOIOCTL) {
1614 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1615 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);
1623 error = dgmdrain(port);
1634 /* now it sends 400 millisecond break because I don't know */
1635 /* how to send an infinite break */
1637 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1642 /* now it's empty */
1645 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1646 port->omodem |= DTR;
1649 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1651 if (!(bc->mstat & DTR))
1652 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1658 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1659 port->omodem &= ~DTR;
1662 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1664 if (bc->mstat & DTR) {
1665 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1672 if (*(int *)data & TIOCM_DTR)
1673 port->omodem |= DTR;
1675 port->omodem &= ~DTR;
1677 if (*(int *)data & TIOCM_RTS)
1678 port->omodem |= RTS;
1680 port->omodem &= ~RTS;
1684 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1689 if (*(int *)data & TIOCM_DTR)
1690 port->omodem |= DTR;
1692 if (*(int *)data & TIOCM_RTS)
1693 port->omodem |= RTS;
1697 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1702 if (*(int *)data & TIOCM_DTR)
1703 port->omodem &= ~DTR;
1705 if (*(int *)data & TIOCM_RTS)
1706 port->omodem &= ~RTS;
1710 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1716 port->imodem = bc->mstat;
1719 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1721 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1723 if (port->imodem & DTR) {
1724 DPRINT1(DB_MODEM, "DTR ");
1725 tiocm_xxx |= TIOCM_DTR;
1727 if (port->imodem & RTS) {
1728 DPRINT1(DB_MODEM, "RTS ");
1729 tiocm_xxx |= TIOCM_RTS;
1731 if (port->imodem & CTS) {
1732 DPRINT1(DB_MODEM, "CTS ");
1733 tiocm_xxx |= TIOCM_CTS;
1735 if (port->imodem & port->dcd) {
1736 DPRINT1(DB_MODEM, "DCD ");
1737 tiocm_xxx |= TIOCM_CD;
1739 if (port->imodem & port->dsr) {
1740 DPRINT1(DB_MODEM, "DSR ");
1741 tiocm_xxx |= TIOCM_DSR;
1743 if (port->imodem & RI) {
1744 DPRINT1(DB_MODEM, "RI ");
1745 tiocm_xxx |= TIOCM_RI;
1747 *(int *)data = tiocm_xxx;
1748 DPRINT1(DB_MODEM, "--\n");
1751 /* must be root since the wait applies to following logins */
1757 port->close_delay = *(int *)data * hz / 100;
1760 *(int *)data = port->close_delay * 100 / hz;
1763 port->do_timestamp = 1;
1764 *(struct timeval *)data = port->timestamp;
1766 case TIOCDCDTIMESTAMP:
1767 port->do_dcd_timestamp = 1;
1768 *(struct timeval *)data = port->dcd_timestamp;
1784 struct dgm_p *port = p;
1786 wakeup(&port->draining);
1789 /* wait for the output to drain */
1792 dgmdrain(struct dgm_p *port)
1794 volatile struct board_chan *bc = port->brdchan;
1795 struct dgm_softc *sc;
1798 BoardMemWinState ws = bmws_get();
1800 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1808 while (tail != head) {
1809 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1810 port->sc->unit, port->pnum, head, tail);
1814 timeout(wakeflush, port, hz);
1815 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1820 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1821 port->sc->unit, port->pnum, error);
1831 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1832 port->sc->unit, port->pnum, head, tail);
1837 /* wait for the output to drain */
1838 /* or simply clear the buffer it it's stopped */
1841 dgm_drain_or_flush(struct dgm_p *port)
1843 volatile struct board_chan *bc = port->brdchan;
1844 struct tty *tp = port->tty;
1845 struct dgm_softc *sc;
1850 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1858 while (tail != head /* && tail != lasttail */ ) {
1859 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1860 port->sc->unit, port->pnum, head, tail);
1862 /* if there is no carrier simply clean the buffer */
1863 if (!(tp->t_state & TS_CARR_ON)) {
1864 bc->tout = bc->tin = 0;
1872 timeout(wakeflush, port, hz);
1873 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1878 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1879 " error = %d\n", port->sc->unit, port->pnum, error);
1881 /* silently clean the buffer */
1883 bc->tout = bc->tin = 0;
1894 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1895 port->sc->unit, port->pnum, head, tail);
1899 dgmparam(struct tty *tp, struct termios *t)
1901 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1902 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1903 volatile struct board_chan *bc;
1904 struct dgm_softc *sc;
1912 BoardMemWinState ws = bmws_get();
1914 sc = devclass_get_softc(dgmdevclass, unit);
1915 port = &sc->ports[pnum];
1918 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);
1920 if (port->mustdrain) {
1921 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1925 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1927 if (t->c_ispeed == 0)
1928 t->c_ispeed = t->c_ospeed;
1930 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1931 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1938 if (cflag == 0) { /* hangup */
1939 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1943 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1944 mval= port->omodem & ~(DTR|RTS);
1946 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1948 if (cflag != port->fepcflag) {
1949 port->fepcflag = cflag;
1950 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1951 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1952 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1954 mval= port->omodem | (DTR|RTS);
1957 iflag = dgmflags(dgm_iflags, t->c_iflag);
1958 if (iflag != port->fepiflag) {
1959 port->fepiflag = iflag;
1960 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1961 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1964 bc->mint = port->dcd;
1966 hflow = dgmflags(dgm_flow, t->c_cflag);
1967 if (hflow != port->hflow) {
1968 port->hflow = hflow;
1969 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1970 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1973 if (port->omodem != mval) {
1974 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1975 unit, pnum, mval, port->omodem);
1976 port->omodem = mval;
1977 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1980 if (port->fepstartc != t->c_cc[VSTART] ||
1981 port->fepstopc != t->c_cc[VSTOP]) {
1982 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1983 port->fepstartc = t->c_cc[VSTART];
1984 port->fepstopc = t->c_cc[VSTOP];
1985 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1996 dgmstart(struct tty *tp)
2001 struct dgm_softc *sc;
2002 volatile struct board_chan *bc;
2008 BoardMemWinState ws = bmws_get();
2010 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2011 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2012 sc = devclass_get_softc(dgmdevclass, unit);
2013 port = &sc->ports[pnum];
2016 wmask = port->txbufsize - 1;
2020 while (tp->t_outq.c_cc != 0) {
2022 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2025 if (tp->t_outq.c_cc <= tp->t_lowat) {
2026 if (tp->t_state & TS_ASLEEP) {
2027 tp->t_state &= ~TS_ASLEEP;
2028 wakeup(TSA_OLOWAT(tp));
2030 /*selwakeup(&tp->t_wsel);*/
2036 head = bc->tin & wmask;
2038 do { tail = bc->tout; } while (tail != bc->tout);
2039 tail = bc->tout & wmask;
2041 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2043 #ifdef LEAVE_FREE_CHARS
2045 size = tail - head - LEAVE_FREE_CHARS;
2049 size = port->txbufsize - head;
2050 if (tail + port->txbufsize < head)
2056 size = tail - head - 1;
2058 size = port->txbufsize - head;
2069 tp->t_state |= TS_BUSY;
2074 towin(sc, port->txwin);
2076 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2078 if (head >= port->txbufsize)
2079 head -= port->txbufsize;
2084 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2085 unit, pnum, size, ocount);
2093 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2094 if (tp->t_state & TS_BUSY) {
2095 tp->t_state &= ~TS_BUSY;
2096 linesw[tp->t_line].l_start(tp);
2100 if (tp->t_state & TS_ASLEEP) {
2101 tp->t_state &= ~TS_ASLEEP;
2102 wakeup(TSA_OLOWAT(tp));
2104 tp->t_state& = ~TS_BUSY;
2109 dgmstop(struct tty *tp, int rw)
2114 struct dgm_softc *sc;
2115 volatile struct board_chan *bc;
2118 BoardMemWinState ws = bmws_get();
2120 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2121 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2123 sc = devclass_get_softc(dgmdevclass, unit);
2124 port = &sc->ports[pnum];
2127 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2133 /* clear output queue */
2134 bc->tout = bc->tin = 0;
2139 /* clear input queue */
2150 fepcmd(struct dgm_p *port,
2158 unsigned tail, head;
2161 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2162 mem = port->sc->vmem;
2164 if (!port->enabled) {
2165 printf("dgm%d: port%d: FEP command on disabled port\n",
2166 port->sc->unit, port->pnum);
2170 /* setwin(port->sc, 0); Require this to be set by caller */
2171 head = port->sc->mailbox->cin;
2173 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2174 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2175 port->sc->unit, port->pnum, head);
2179 mem[head + FEP_CSTART] = cmd;
2180 mem[head + FEP_CSTART + 1] = port->pnum;
2182 mem[head + FEP_CSTART + 2] = op1;
2183 mem[head + FEP_CSTART + 3] = op2;
2185 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2186 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2189 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2190 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2192 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2193 port->sc->mailbox->cin = head;
2197 while (count-- != 0) {
2198 head = port->sc->mailbox->cin;
2199 tail = port->sc->mailbox->cout;
2201 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2202 if (n <= ncmds * (sizeof(ushort)*4))
2205 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2209 disc_optim(struct tty *tp, struct termios *t)
2211 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2212 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2213 && (!(t->c_iflag & PARMRK)
2214 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2215 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2216 && linesw[tp->t_line].l_rint == ttyinput)
2217 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2219 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;