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.12 2005/06/16 16:03:10 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>
90 #include <sys/thread2.h>
91 #include <machine/bus.h>
92 #include <machine/resource.h>
94 #include <machine/clock.h>
103 #define CALLOUT_MASK 0x40000
104 #define CONTROL_MASK 0xC0
105 #define CONTROL_INIT_STATE 0x40
106 #define CONTROL_LOCK_STATE 0x80
107 #define UNIT_MASK 0x30000
108 #define PORT_MASK 0x3F
109 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
110 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
111 #define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK) >> 16)
112 #define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK)
114 #define MEM_SIZE 0x8000
116 #define DGM_UNITMASK 0x30000
117 #define DGM_UNIT(unit) ((unit) << 16)
121 /* digiboard port structure */
123 unsigned enabled : 1;
125 struct dgm_softc *sc; /* parent softc */
126 u_char pnum; /* port number */
127 u_char omodem; /* FEP output modem status */
128 u_char imodem; /* FEP input modem status */
129 u_char modemfake; /* Modem values to be forced */
130 u_char modem; /* Force values */
154 volatile struct board_chan *brdchan;
157 u_char active_out; /* nonzero if the callout device is open */
158 u_int wopeners; /* # processes waiting for DCD in open() */
161 struct termios it_in; /* should be in struct tty */
162 struct termios it_out;
165 struct termios lt_in; /* should be in struct tty */
166 struct termios lt_out;
168 unsigned do_timestamp : 1;
169 unsigned do_dcd_timestamp : 1;
170 struct timeval timestamp;
171 struct timeval dcd_timestamp;
173 /* flags of state, are used in sleep() too */
174 u_char closing; /* port is being closed now */
175 u_char draining; /* port is being drained now */
176 u_char used; /* port is being used now */
177 u_char mustdrain; /* data must be waited to drain in dgmparam() */
179 struct callout hc_timeout;
180 struct callout wf_timeout;
183 /* Digiboard per-board structure */
185 /* struct board_info */
186 unsigned enabled : 1;
187 u_char unit; /* unit number */
188 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
189 u_char altpin; /* do we need alternate pin setting ? */
190 int numports; /* number of ports on card */
191 u_long port; /* I/O port */
192 u_char *vmem; /* virtual memory address */
193 u_long pmem; /* physical memory address */
194 int mem_seg; /* internal memory segment */
195 struct dgm_p *ports; /* ptr to array of port descriptors */
196 struct tty *ttys; /* ptr to array of TTY structures */
197 volatile struct global_data *mailbox;
198 struct resource *io_res;
199 struct resource *mem_res;
202 struct callout toh; /* poll timeout handle */
205 static void dgmpoll(void *);
206 static int dgmprobe(device_t);
207 static int dgmattach(device_t);
208 static int dgmdetach(device_t);
209 static int dgmshutdown(device_t);
210 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
212 static void dgmstart(struct tty *);
213 static void dgmstop(struct tty *, int);
214 static int dgmparam(struct tty *, struct termios *);
215 static void dgmhardclose(struct dgm_p *);
216 static void dgm_drain_or_flush(struct dgm_p *);
217 static int dgmdrain(struct dgm_p *);
218 static void dgm_pause(void *);
219 static void wakeflush(void *);
220 static void disc_optim(struct tty *, struct termios *);
222 static d_open_t dgmopen;
223 static d_close_t dgmclose;
224 static d_ioctl_t dgmioctl;
226 static device_method_t dgmmethods[] = {
227 /* Device interface */
228 DEVMETHOD(device_probe, dgmprobe),
229 DEVMETHOD(device_attach, dgmattach),
230 DEVMETHOD(device_detach, dgmdetach),
231 DEVMETHOD(device_shutdown, dgmshutdown),
235 static driver_t dgmdriver = {
238 sizeof (struct dgm_softc),
241 static devclass_t dgmdevclass;
243 #define CDEV_MAJOR 101
244 static struct cdevsw dgm_cdevsw = {
246 /* maj */ CDEV_MAJOR,
247 /* flags */ D_TTY | D_KQFILTER,
252 /* close */ dgmclose,
254 /* write */ ttywrite,
255 /* ioctl */ dgmioctl,
258 /* strategy */ nostrategy,
261 /* kqfilter */ ttykqfilter
265 dgmmodhandler(module_t mod, int event, void *arg)
279 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
281 static speed_t dgmdefaultrate = TTYDEF_SPEED;
283 static struct speedtab dgmspeedtab[] = {
284 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
298 { 19200, FEP_B19200 },
299 { 38400, FEP_B38400 },
300 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
301 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
305 static struct dbgflagtbl {
310 { PARODD, PARODD, FEP_PARODD },
311 { PARENB, PARENB, FEP_PARENB },
312 { CSTOPB, CSTOPB, FEP_CSTOPB },
313 { CSIZE, CS5, FEP_CS6 },
314 { CSIZE, CS6, FEP_CS6 },
315 { CSIZE, CS7, FEP_CS7 },
316 { CSIZE, CS8, FEP_CS8 },
317 { CLOCAL, CLOCAL, FEP_CLOCAL },
320 { IGNBRK, IGNBRK, FEP_IGNBRK },
321 { BRKINT, BRKINT, FEP_BRKINT },
322 { IGNPAR, IGNPAR, FEP_IGNPAR },
323 { PARMRK, PARMRK, FEP_PARMRK },
324 { INPCK, INPCK, FEP_INPCK },
325 { ISTRIP, ISTRIP, FEP_ISTRIP },
326 { IXON, IXON, FEP_IXON },
327 { IXOFF, IXOFF, FEP_IXOFF },
328 { IXANY, IXANY, FEP_IXANY },
331 { CRTSCTS, CRTSCTS, CTS|RTS },
332 { CRTSCTS, CCTS_OFLOW, CTS },
333 { CRTSCTS, CRTS_IFLOW, RTS },
337 /* xlat bsd termios flags to dgm sys-v style */
339 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
344 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
345 if ((input & tbl[i].in_mask) == tbl[i].in_val)
346 output |= tbl[i].out_val;
351 static int dgmdebug = 0;
352 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
354 static __inline int setwin(struct dgm_softc *, unsigned);
355 static __inline void hidewin(struct dgm_softc *);
356 static __inline void towin(struct dgm_softc *, int);
358 /*Helg: to allow recursive dgm...() calls */
360 /* If we were called and don't want to disturb we need: */
361 int port; /* write to this port */
362 u_char data; /* this data on exit */
363 /* or DATA_WINOFF to close memory window on entry */
364 } BoardMemWinState; /* so several channels and even boards can coexist */
366 #define DATA_WINOFF 0
367 static BoardMemWinState bmws;
369 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
370 static u_long validmem[] = {
371 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
372 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
373 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
374 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
375 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
378 /* return current memory window state and close window */
379 static BoardMemWinState
382 BoardMemWinState bmwsRet = bmws;
384 if (bmws.data != DATA_WINOFF)
385 outb(bmws.port, bmws.data = DATA_WINOFF);
389 /* restore memory window state */
391 bmws_set(BoardMemWinState ws)
393 if (ws.data != bmws.data || ws.port != bmws.port) {
394 if (bmws.data != DATA_WINOFF)
395 outb(bmws.port, DATA_WINOFF);
396 if (ws.data != DATA_WINOFF)
397 outb(ws.port, ws.data);
403 setwin(struct dgm_softc *sc, unsigned int addr)
405 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
406 return (addr & 0x7FFF);
410 hidewin(struct dgm_softc *sc)
413 outb(bmws.port = sc->port + 1, bmws.data);
417 towin(struct dgm_softc *sc, int win)
419 outb(bmws.port = sc->port + 1, bmws.data = win);
423 dgmprobe(device_t dev)
425 struct dgm_softc *sc = device_get_softc(dev);
429 * Assign unit number. Due to bits we use in the minor number for
430 * the various tty types, only 4 units are supported.
432 sc->unit = device_get_unit(dev);
434 device_printf(dev, "Too many units, only 4 supported\n");
438 /* Check that we've got a valid i/o address */
439 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
441 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
442 if (sc->port == validio[i])
445 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
449 /* Ditto for our memory address */
450 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
452 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
453 if (sc->pmem == validmem[i])
456 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
459 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
460 device_printf(dev, "0x%lx: Memory address not supported\n",
464 sc->vmem = (u_char *)sc->pmem;
466 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
469 /* Temporarily map our io ports */
471 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
472 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
473 if (sc->io_res == NULL)
476 outb(sc->port, FEPRST);
479 for (i = 0; i < 1000; i++) {
481 if ((inb(sc->port) & FEPMASK) == FEPRST) {
483 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
490 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
491 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
495 /* check type of card and get internal memory characteristics */
503 second = inb(sc->port);
504 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
506 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
509 sc->mem_seg = 0x8000;
511 /* Temporarily map our memory too */
513 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
514 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
515 if (sc->mem_res == NULL) {
516 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
517 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
521 outb(sc->port, FEPCLR); /* drop RESET */
522 hidewin(sc); /* Helg: to set initial bmws state */
524 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
525 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
527 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
528 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
530 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
536 dgmattach(device_t dev)
538 struct dgm_softc *sc = device_get_softc(dev);
544 volatile struct board_chan *bc;
547 u_long msize, iosize;
549 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
551 callout_init(&sc->toh);
552 sc->unit = device_get_unit(dev);
553 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
554 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
555 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
557 sc->mem_seg = 0x8000;
560 sc->mem_seg = 0x8000;
562 /* Allocate resources (should have been verified in dgmprobe()) */
564 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
565 0ul, ~0ul, iosize, RF_ACTIVE);
566 if (sc->io_res == NULL)
569 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
570 0ul, ~0ul, msize, RF_ACTIVE);
571 if (sc->mem_res == NULL) {
572 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
573 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
578 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
580 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
583 outb(sc->port, FEPRST);
586 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
588 device_printf(dev, "1st reset failed\n");
591 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
592 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
598 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
600 t = sc->pmem >> 8; /* disable windowing */
601 outb(sc->port + 2, t & 0xFF);
602 outb(sc->port + 3, t >> 8);
606 /* very short memory test */
607 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
609 addr = setwin(sc, BOTWIN);
610 *(u_long *)(mem + addr) = 0xA55A3CC3;
611 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
612 device_printf(dev, "1st memory test failed\n");
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);
620 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
622 addr = setwin(sc, TOPWIN);
623 *(u_long *)(mem + addr) = 0x5AA5C33C;
624 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
625 device_printf(dev, "2nd memory test failed\n");
628 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
629 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
633 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
635 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
636 *(u_long *)(mem + addr) = 0x5AA5C33C;
637 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
638 device_printf(dev, "3rd (BIOS) memory test failed\n");
640 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
642 addr = setwin(sc, MISCGLOBAL);
643 for (i = 0; i < 16; i++)
646 addr = setwin(sc, BIOSOFFSET);
648 for (i = 0; ptr < mem + msize; i++)
649 *ptr++ = pcem_bios[i];
651 ptr = mem + BIOSOFFSET;
652 for (i = 0; ptr < mem + msize; i++) {
653 if (*ptr++ != pcem_bios[i]) {
654 printf("Low BIOS load failed\n");
657 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
658 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
662 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
664 addr = setwin(sc, msize);
666 for (;i < pcem_nbios; i++)
667 *ptr++ = pcem_bios[i];
670 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
671 if (*ptr++ != pcem_bios[i]) {
672 printf("High BIOS load failed\n");
675 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
676 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
680 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
681 device_printf(dev, "DigiBIOS loaded, initializing");
683 addr = setwin(sc, 0);
685 *(u_int *)(mem + addr) = 0x0bf00401;
686 *(u_int *)(mem + addr + 4) = 0;
687 *(ushort *)(mem + addr + 0xc00) = 0;
690 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
693 printf("\nBIOS initialize failed(1)\n");
696 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
697 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
702 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
703 printf("\nBIOS initialize failed(2)\n");
706 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
707 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
710 printf(", DigiBIOS running\n");
714 addr = setwin(sc, BIOSOFFSET);
716 for (i = 0; i < pcem_ncook; i++)
717 *ptr++ = pcem_cook[i];
719 ptr = mem + BIOSOFFSET;
720 for (i = 0; i < pcem_ncook; i++) {
721 if (*ptr++ != pcem_cook[i]) {
722 printf("FEP/OS load failed\n");
725 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
726 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
730 device_printf(dev, "FEP/OS loaded, initializing");
732 addr = setwin(sc, 0);
733 *(ushort *)(mem + addr + 0xd20) = 0;
734 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
735 *(u_int *)(mem + addr + 0xc30) = 0x3L;
738 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
741 printf("\nFEP/OS initialize failed(1)\n");
744 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
745 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
750 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
751 printf("\nFEP/OS initialize failed(2)\n");
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);
758 printf(", FEP/OS running\n");
760 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
761 device_printf(dev, "%d ports attached\n", sc->numports);
763 if (sc->numports > MAX_DGM_PORTS) {
764 printf("dgm%d: too many ports\n", sc->unit);
767 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
768 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
772 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
773 M_TTYS, M_WAITOK|M_ZERO);
774 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
775 M_TTYS, M_WAITOK|M_ZERO);
777 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
778 for (i = 0; i < sc->numports; i++) {
779 sc->ports[i].enabled = 1;
780 callout_init(&sc->ports[i].hc_timeout);
781 callout_init(&sc->ports[i].wf_timeout);
784 /* We should now init per-port structures */
786 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
787 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
789 if (sc->numports < 3)
794 cdevsw_add(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
795 for (i = 0; i < sc->numports; i++, bc++) {
796 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
797 port = &sc->ports[i];
800 port->tty = &sc->ttys[i];
808 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
810 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
811 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
815 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
816 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
817 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
818 port->txwin = FEPWIN | (bc->tseg >> 11);
819 port->rxwin = FEPWIN | (bc->rseg >> 11);
823 port->txbufsize = bc->tmax + 1;
824 port->rxbufsize = bc->rmax + 1;
826 lowwater = (port->txbufsize >= 2000) ?
827 1024 : (port->txbufsize / 2);
830 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
831 sc->unit, i, lowwater);
832 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
833 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
834 sc->unit, i, port->rxbufsize / 4);
835 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
836 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
837 sc->unit, i, 3 * port->rxbufsize / 4);
838 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
843 port->startc = bc->startc;
844 port->startca = bc->startca;
845 port->stopc = bc->stopc;
846 port->stopca = bc->stopca;
848 /* port->close_delay = 50; */
849 port->close_delay = 3 * hz;
850 port->do_timestamp = 0;
851 port->do_dcd_timestamp = 0;
853 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
855 * We don't use all the flags from <sys/ttydefaults.h> since
856 * they are only relevant for logins. It's important to have
857 * echo off initially so that the line doesn't start
858 * blathering before the echo flag can be turned off.
860 port->it_in.c_iflag = TTYDEF_IFLAG;
861 port->it_in.c_oflag = TTYDEF_OFLAG;
862 port->it_in.c_cflag = TTYDEF_CFLAG;
863 port->it_in.c_lflag = TTYDEF_LFLAG;
864 termioschars(&port->it_in);
865 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
866 port->it_out = port->it_in;
868 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
869 make_dev(&dgm_cdevsw, (sc->unit*65536) + i, UID_ROOT,
870 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
871 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 64, UID_ROOT,
872 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
873 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 128, UID_ROOT,
874 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
875 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262144, UID_UUCP,
876 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
877 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262208, UID_UUCP,
878 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
879 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262272, UID_UUCP,
880 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
883 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
887 /* start the polling function */
888 callout_reset(&sc->toh, hz / POLLSPERSEC,
889 dgmpoll, (void *)(int)sc->unit);
891 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
897 dgmdetach(device_t dev)
899 struct dgm_softc *sc = device_get_softc(dev);
902 for (i = 0; i < sc->numports; i++)
903 if (sc->ttys[i].t_state & TS_ISOPEN)
906 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
909 * The cdevsw_remove() call will destroy all associated devices
910 * and dereference any ad-hoc-created devices, but does not
911 * dereference devices created via make_dev().
913 cdevsw_remove(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
915 callout_stop(&sc->toh);
917 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
918 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
920 FREE(sc->ports, M_TTYS);
921 FREE(sc->ttys, M_TTYS);
927 dgmshutdown(device_t dev)
930 struct dgm_softc *sc = device_get_softc(dev);
932 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
940 dgmopen(dev_t dev, int flag, int mode, struct thread *td)
942 struct dgm_softc *sc;
949 volatile struct board_chan *bc;
953 unit = MINOR_TO_UNIT(mynor);
954 pnum = MINOR_TO_PORT(mynor);
956 sc = devclass_get_softc(dgmdevclass, unit);
958 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
963 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
966 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
971 if (pnum >= sc->numports) {
972 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
977 if (mynor & CONTROL_MASK)
980 tp = &sc->ttys[pnum];
982 port = &sc->ports[pnum];
988 while (port->closing) {
989 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
992 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
993 " error = %d\n", unit, pnum, error);
998 if (tp->t_state & TS_ISOPEN) {
1000 * The device is open, so everything has been initialized.
1003 if (mynor & CALLOUT_MASK) {
1004 if (!port->active_out) {
1006 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1007 " BUSY error = %d\n", unit, pnum, error);
1010 } else if (port->active_out) {
1011 if (flag & O_NONBLOCK) {
1013 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1014 " BUSY error = %d\n", unit, pnum, error);
1017 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1019 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1020 " error = %d\n", unit, pnum, error);
1026 if (tp->t_state & TS_XCLUDE && suser(td)) {
1032 * The device isn't open, so there are no conflicts.
1033 * Initialize it. Initialization is done twice in many
1034 * cases: to preempt sleeping callin opens if we are
1035 * callout, and to complete a callin open after DCD rises.
1037 tp->t_oproc = dgmstart;
1038 tp->t_param = dgmparam;
1039 tp->t_stop = dgmstop;
1041 tp->t_termios= (mynor & CALLOUT_MASK) ?
1047 port->imodem = bc->mstat;
1048 bc->rout = bc->rin; /* clear input queue */
1050 #ifdef PRINT_BUFSIZE
1051 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1052 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1059 error = dgmparam(tp, &tp->t_termios);
1063 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1068 /* handle fake DCD for callout devices */
1069 /* and initial DCD */
1071 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1072 linesw[tp->t_line].l_modem(tp, 1);
1076 * Wait for DCD if necessary.
1078 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1079 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1081 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1084 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1085 " error = %d\n", unit, pnum, error);
1091 error = linesw[tp->t_line].l_open(dev, tp);
1092 disc_optim(tp, &tp->t_termios);
1093 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1096 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1097 port->active_out = 1;
1101 /* If any port is open (i.e. the open() call is completed for it)
1102 * the device is busy
1106 disc_optim(tp, &tp->t_termios);
1109 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1112 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1120 dgmclose(dev_t dev, int flag, int mode, struct thread *td)
1125 struct dgm_softc *sc;
1130 if (mynor & CONTROL_MASK)
1132 unit = MINOR_TO_UNIT(mynor);
1133 pnum = MINOR_TO_PORT(mynor);
1135 sc = devclass_get_softc(dgmdevclass, unit);
1136 tp = &sc->ttys[pnum];
1137 port = sc->ports + pnum;
1139 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1141 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1142 dgm_drain_or_flush(port);
1147 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1148 linesw[tp->t_line].l_close(tp, flag);
1149 disc_optim(tp, &tp->t_termios);
1151 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1153 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1156 wakeup(&port->closing);
1159 /* mark the card idle when all ports are closed */
1161 for (i = 0; i < sc->numports; i++)
1162 if (sc->ports[i].used)
1167 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1169 wakeup(TSA_CARR_ON(tp));
1170 wakeup(&port->active_out);
1171 port->active_out = 0;
1173 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1179 dgmhardclose(struct dgm_p *port)
1181 volatile struct board_chan *bc = port->brdchan;
1182 struct dgm_softc *sc;
1184 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1185 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1187 port->do_timestamp = 0;
1193 if (port->tty->t_cflag & HUPCL) {
1194 port->omodem &= ~(RTS|DTR);
1195 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1201 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1202 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1206 dgm_pause(void *chan)
1208 wakeup((caddr_t)chan);
1212 dgmpoll(void *unit_c)
1214 int unit = (int)unit_c;
1217 struct dgm_softc *sc;
1220 int event, mstat, lstat;
1221 volatile struct board_chan *bc;
1228 int ibuf_full, obuf_full;
1229 BoardMemWinState ws = bmws_get();
1231 sc = devclass_get_softc(dgmdevclass, unit);
1232 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1235 printf("dgm%d: polling of disabled board stopped\n", unit);
1241 head = sc->mailbox->ein;
1242 tail = sc->mailbox->eout;
1244 while (head != tail) {
1245 if (head >= FEP_IMAX - FEP_ISTART
1246 || tail >= FEP_IMAX - FEP_ISTART
1247 || (head|tail) & 03 ) {
1248 printf("dgm%d: event queue's head or tail is wrong!"
1249 " hd = %d, tl = %d\n", unit, head, tail);
1253 eventbuf = sc->vmem + tail + FEP_ISTART;
1255 event = eventbuf[1];
1256 mstat = eventbuf[2];
1257 lstat = eventbuf[3];
1259 port = &sc->ports[pnum];
1261 tp = &sc->ttys[pnum];
1263 if (pnum >= sc->numports || !port->enabled) {
1264 printf("dgm%d: port%d: got event on nonexisting port\n",
1266 } else if (port->used || port->wopeners > 0 ) {
1268 int wrapmask = port->rxbufsize - 1;
1270 if (!(event & ALL_IND))
1271 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1272 unit, pnum, event, mstat, lstat);
1274 if (event & DATA_IND) {
1275 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1278 rhead = bc->rin & wrapmask;
1279 rtail = bc->rout & wrapmask;
1281 if (!(tp->t_cflag & CREAD) || !port->used ) {
1287 printf("dgm%d: port%d: overrun\n", unit, pnum);
1291 if (!(tp->t_state & TS_ISOPEN))
1294 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1295 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1296 " p rx head = %d tail = %d\n", unit,
1297 pnum, rhead, rtail);
1300 size = rhead - rtail;
1302 size = port->rxbufsize - rtail;
1304 ptr = port->rxptr + rtail;
1307 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1308 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1309 DPRINT1(DB_RXDATA, "*");
1314 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1315 DPRINT1(DB_RXDATA, "!");
1316 towin(sc, port->rxwin);
1319 tp->t_rawcc += size;
1327 towin(sc, port->rxwin);
1330 (*linesw[tp->t_line].l_rint)(chr, tp);
1335 rtail= (rtail + size) & wrapmask;
1337 rhead = bc->rin & wrapmask;
1345 if (event & MODEMCHG_IND) {
1346 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1347 "MODEMCHG_IND\n", unit, pnum);
1348 port->imodem = mstat;
1349 if (mstat & port->dcd) {
1351 linesw[tp->t_line].l_modem(tp, 1);
1353 wakeup(TSA_CARR_ON(tp));
1356 linesw[tp->t_line].l_modem(tp, 0);
1358 if (port->draining) {
1360 wakeup(&port->draining);
1365 if (event & BREAK_IND) {
1366 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1367 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1368 " BREAK_IND\n", unit, pnum);
1370 linesw[tp->t_line].l_rint(TTY_BI, tp);
1375 /* Helg: with output flow control */
1377 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1378 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1379 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1381 if ((event & EMPTYTX_IND ) &&
1382 tp->t_outq.c_cc == 0 && port->draining) {
1384 wakeup(&port->draining);
1389 int wrapmask = port->txbufsize - 1;
1391 for (obuf_full = FALSE;
1392 tp->t_outq.c_cc != 0 && !obuf_full;
1394 /* add "last-minute" data to write buffer */
1395 if (!(tp->t_state & TS_BUSY)) {
1397 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1400 if (tp->t_outq.c_cc <= tp->t_lowat) {
1401 if (tp->t_state & TS_ASLEEP) {
1402 tp->t_state &= ~TS_ASLEEP;
1403 wakeup(TSA_OLOWAT(tp));
1405 /* selwakeup(&tp->t_wsel); */
1412 whead = bc->tin & wrapmask;
1413 wtail = bc->tout & wrapmask;
1416 size = wtail - whead - 1;
1418 size = port->txbufsize - whead;
1424 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1425 whead, wtail, size, obuf_full);
1433 towin(sc, port->txwin);
1435 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1440 bc->tin = whead & wrapmask;
1445 DPRINT1(DB_WR, " +BUSY\n");
1446 tp->t_state |= TS_BUSY;
1448 DPRINT1(DB_WR, " -BUSY\n");
1450 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1451 /* should clear TS_BUSY before ttwwakeup */
1452 if (tp->t_state & TS_BUSY) {
1453 tp->t_state &= ~TS_BUSY;
1454 linesw[tp->t_line].l_start(tp);
1458 if (tp->t_state & TS_ASLEEP) {
1459 tp->t_state &= ~TS_ASLEEP;
1460 wakeup(TSA_OLOWAT(tp));
1462 tp->t_state &= ~TS_BUSY;
1468 bc->idata = 1; /* require event on incoming data */
1472 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1475 bc->idata = bc->iempty = bc->ilow = 0;
1478 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1481 sc->mailbox->eout = tail;
1484 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1486 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1490 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1492 struct dgm_softc *sc;
1497 volatile struct board_chan *bc;
1501 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1503 struct termios term;
1506 BoardMemWinState ws = bmws_get();
1509 unit = MINOR_TO_UNIT(mynor);
1510 pnum = MINOR_TO_PORT(mynor);
1512 sc = devclass_get_softc(dgmdevclass, unit);
1513 port = &sc->ports[pnum];
1514 tp = &sc->ttys[pnum];
1517 if (mynor & CONTROL_MASK) {
1520 switch (mynor & CONTROL_MASK) {
1521 case CONTROL_INIT_STATE:
1522 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1524 case CONTROL_LOCK_STATE:
1525 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1528 return (ENODEV); /* /dev/nodev */
1535 *ct = *(struct termios *)data;
1538 *(struct termios *)data = *ct;
1541 *(int *)data = TTYDISC;
1544 bzero(data, sizeof(struct winsize));
1551 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1552 term = tp->t_termios;
1553 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1554 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-ISNOW c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, term.c_cflag, term.c_iflag, term.c_lflag);
1557 error = ttsetcompat(tp, &cmd, data, &term);
1561 data = (caddr_t)&term;
1564 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1566 struct termios *dt = (struct termios *)data;
1567 struct termios *lt = mynor & CALLOUT_MASK
1568 ? &port->lt_out : &port->lt_in;
1570 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-TOSET c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, dt->c_cflag, dt->c_iflag, dt->c_lflag);
1571 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1572 | (dt->c_iflag & ~lt->c_iflag);
1573 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1574 | (dt->c_oflag & ~lt->c_oflag);
1575 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1576 | (dt->c_cflag & ~lt->c_cflag);
1577 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1578 | (dt->c_lflag & ~lt->c_lflag);
1579 for (cc = 0; cc < NCCS; ++cc)
1580 if (lt->c_cc[cc] != 0)
1581 dt->c_cc[cc] = tp->t_cc[cc];
1582 if (lt->c_ispeed != 0)
1583 dt->c_ispeed = tp->t_ispeed;
1584 if (lt->c_ospeed != 0)
1585 dt->c_ospeed = tp->t_ospeed;
1588 if (cmd == TIOCSTOP) {
1591 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1595 } else if (cmd == TIOCSTART) {
1598 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1604 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1605 port->mustdrain = 1;
1607 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
1608 if (error != ENOIOCTL)
1611 error = ttioctl(tp, cmd, data, flag);
1612 disc_optim(tp, &tp->t_termios);
1613 port->mustdrain = 0;
1614 if (error != ENOIOCTL) {
1616 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1617 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);
1625 error = dgmdrain(port);
1636 /* now it sends 400 millisecond break because I don't know */
1637 /* how to send an infinite break */
1639 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1644 /* now it's empty */
1647 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1648 port->omodem |= DTR;
1651 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1653 if (!(bc->mstat & DTR))
1654 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1660 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1661 port->omodem &= ~DTR;
1664 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1666 if (bc->mstat & DTR) {
1667 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1674 if (*(int *)data & TIOCM_DTR)
1675 port->omodem |= DTR;
1677 port->omodem &= ~DTR;
1679 if (*(int *)data & TIOCM_RTS)
1680 port->omodem |= RTS;
1682 port->omodem &= ~RTS;
1686 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1691 if (*(int *)data & TIOCM_DTR)
1692 port->omodem |= DTR;
1694 if (*(int *)data & TIOCM_RTS)
1695 port->omodem |= RTS;
1699 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1704 if (*(int *)data & TIOCM_DTR)
1705 port->omodem &= ~DTR;
1707 if (*(int *)data & TIOCM_RTS)
1708 port->omodem &= ~RTS;
1712 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1718 port->imodem = bc->mstat;
1721 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1723 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1725 if (port->imodem & DTR) {
1726 DPRINT1(DB_MODEM, "DTR ");
1727 tiocm_xxx |= TIOCM_DTR;
1729 if (port->imodem & RTS) {
1730 DPRINT1(DB_MODEM, "RTS ");
1731 tiocm_xxx |= TIOCM_RTS;
1733 if (port->imodem & CTS) {
1734 DPRINT1(DB_MODEM, "CTS ");
1735 tiocm_xxx |= TIOCM_CTS;
1737 if (port->imodem & port->dcd) {
1738 DPRINT1(DB_MODEM, "DCD ");
1739 tiocm_xxx |= TIOCM_CD;
1741 if (port->imodem & port->dsr) {
1742 DPRINT1(DB_MODEM, "DSR ");
1743 tiocm_xxx |= TIOCM_DSR;
1745 if (port->imodem & RI) {
1746 DPRINT1(DB_MODEM, "RI ");
1747 tiocm_xxx |= TIOCM_RI;
1749 *(int *)data = tiocm_xxx;
1750 DPRINT1(DB_MODEM, "--\n");
1753 /* must be root since the wait applies to following logins */
1759 port->close_delay = *(int *)data * hz / 100;
1762 *(int *)data = port->close_delay * 100 / hz;
1765 port->do_timestamp = 1;
1766 *(struct timeval *)data = port->timestamp;
1768 case TIOCDCDTIMESTAMP:
1769 port->do_dcd_timestamp = 1;
1770 *(struct timeval *)data = port->dcd_timestamp;
1786 struct dgm_p *port = p;
1788 wakeup(&port->draining);
1791 /* wait for the output to drain */
1794 dgmdrain(struct dgm_p *port)
1796 volatile struct board_chan *bc = port->brdchan;
1797 struct dgm_softc *sc;
1800 BoardMemWinState ws = bmws_get();
1802 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1810 while (tail != head) {
1811 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1812 port->sc->unit, port->pnum, head, tail);
1816 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1817 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1822 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1823 port->sc->unit, port->pnum, error);
1833 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1834 port->sc->unit, port->pnum, head, tail);
1839 /* wait for the output to drain */
1840 /* or simply clear the buffer it it's stopped */
1843 dgm_drain_or_flush(struct dgm_p *port)
1845 volatile struct board_chan *bc = port->brdchan;
1846 struct tty *tp = port->tty;
1847 struct dgm_softc *sc;
1852 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1860 while (tail != head /* && tail != lasttail */ ) {
1861 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1862 port->sc->unit, port->pnum, head, tail);
1864 /* if there is no carrier simply clean the buffer */
1865 if (!(tp->t_state & TS_CARR_ON)) {
1866 bc->tout = bc->tin = 0;
1874 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1875 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1880 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1881 " error = %d\n", port->sc->unit, port->pnum, error);
1883 /* silently clean the buffer */
1885 bc->tout = bc->tin = 0;
1896 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1897 port->sc->unit, port->pnum, head, tail);
1901 dgmparam(struct tty *tp, struct termios *t)
1903 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1904 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1905 volatile struct board_chan *bc;
1906 struct dgm_softc *sc;
1913 BoardMemWinState ws = bmws_get();
1915 sc = devclass_get_softc(dgmdevclass, unit);
1916 port = &sc->ports[pnum];
1919 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmparm c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, t->c_cflag, t->c_iflag, t->c_lflag);
1921 if (port->mustdrain) {
1922 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1926 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1928 if (t->c_ispeed == 0)
1929 t->c_ispeed = t->c_ospeed;
1931 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1932 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1939 if (cflag == 0) { /* hangup */
1940 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1944 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1945 mval= port->omodem & ~(DTR|RTS);
1947 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1949 if (cflag != port->fepcflag) {
1950 port->fepcflag = cflag;
1951 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1952 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1953 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1955 mval= port->omodem | (DTR|RTS);
1958 iflag = dgmflags(dgm_iflags, t->c_iflag);
1959 if (iflag != port->fepiflag) {
1960 port->fepiflag = iflag;
1961 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1962 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1965 bc->mint = port->dcd;
1967 hflow = dgmflags(dgm_flow, t->c_cflag);
1968 if (hflow != port->hflow) {
1969 port->hflow = hflow;
1970 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1971 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1974 if (port->omodem != mval) {
1975 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1976 unit, pnum, mval, port->omodem);
1977 port->omodem = mval;
1978 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1981 if (port->fepstartc != t->c_cc[VSTART] ||
1982 port->fepstopc != t->c_cc[VSTOP]) {
1983 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1984 port->fepstartc = t->c_cc[VSTART];
1985 port->fepstopc = t->c_cc[VSTOP];
1986 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1997 dgmstart(struct tty *tp)
2002 struct dgm_softc *sc;
2003 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) {
2021 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2024 if (tp->t_outq.c_cc <= tp->t_lowat) {
2025 if (tp->t_state & TS_ASLEEP) {
2026 tp->t_state &= ~TS_ASLEEP;
2027 wakeup(TSA_OLOWAT(tp));
2029 /*selwakeup(&tp->t_wsel);*/
2035 head = bc->tin & wmask;
2037 do { tail = bc->tout; } while (tail != bc->tout);
2038 tail = bc->tout & wmask;
2040 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2042 #ifdef LEAVE_FREE_CHARS
2044 size = tail - head - LEAVE_FREE_CHARS;
2048 size = port->txbufsize - head;
2049 if (tail + port->txbufsize < head)
2055 size = tail - head - 1;
2057 size = port->txbufsize - head;
2068 tp->t_state |= TS_BUSY;
2073 towin(sc, port->txwin);
2075 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2077 if (head >= port->txbufsize)
2078 head -= port->txbufsize;
2083 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2084 unit, pnum, size, ocount);
2092 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2093 if (tp->t_state & TS_BUSY) {
2094 tp->t_state &= ~TS_BUSY;
2095 linesw[tp->t_line].l_start(tp);
2099 if (tp->t_state & TS_ASLEEP) {
2100 tp->t_state &= ~TS_ASLEEP;
2101 wakeup(TSA_OLOWAT(tp));
2103 tp->t_state& = ~TS_BUSY;
2108 dgmstop(struct tty *tp, int rw)
2113 struct dgm_softc *sc;
2114 volatile struct board_chan *bc;
2116 BoardMemWinState ws = bmws_get();
2118 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2119 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2121 sc = devclass_get_softc(dgmdevclass, unit);
2122 port = &sc->ports[pnum];
2125 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2131 /* clear output queue */
2132 bc->tout = bc->tin = 0;
2137 /* clear input queue */
2148 fepcmd(struct dgm_p *port,
2156 unsigned tail, head;
2159 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2160 mem = port->sc->vmem;
2162 if (!port->enabled) {
2163 printf("dgm%d: port%d: FEP command on disabled port\n",
2164 port->sc->unit, port->pnum);
2168 /* setwin(port->sc, 0); Require this to be set by caller */
2169 head = port->sc->mailbox->cin;
2171 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2172 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2173 port->sc->unit, port->pnum, head);
2177 mem[head + FEP_CSTART] = cmd;
2178 mem[head + FEP_CSTART + 1] = port->pnum;
2180 mem[head + FEP_CSTART + 2] = op1;
2181 mem[head + FEP_CSTART + 3] = op2;
2183 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2184 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2187 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2188 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2190 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2191 port->sc->mailbox->cin = head;
2195 while (count-- != 0) {
2196 head = port->sc->mailbox->cin;
2197 tail = port->sc->mailbox->cout;
2199 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2200 if (n <= ncmds * (sizeof(ushort)*4))
2203 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2207 disc_optim(struct tty *tp, struct termios *t)
2209 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2210 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2211 && (!(t->c_iflag & PARMRK)
2212 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2213 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2214 && linesw[tp->t_line].l_rint == ttyinput)
2215 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2217 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;