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.17 2008/04/30 17:28:16 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>
80 #include <sys/dkstat.h>
81 #include <sys/fcntl.h>
82 #include <sys/kernel.h>
83 #include <sys/sysctl.h>
84 #include <sys/malloc.h>
85 #include <sys/sysctl.h>
91 #include <sys/thread2.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() */
178 struct callout hc_timeout;
179 struct callout wf_timeout;
182 /* Digiboard per-board structure */
184 /* struct board_info */
185 unsigned enabled : 1;
186 u_char unit; /* unit number */
187 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
188 u_char altpin; /* do we need alternate pin setting ? */
189 int numports; /* number of ports on card */
190 u_long port; /* I/O port */
191 u_char *vmem; /* virtual memory address */
192 u_long pmem; /* physical memory address */
193 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 dev_ops dgm_ops = {
245 { "dgm", CDEV_MAJOR, D_TTY | D_KQFILTER },
252 .d_kqfilter = ttykqfilter,
253 .d_revoke = ttyrevoke
257 dgmmodhandler(module_t mod, int event, void *arg)
271 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
273 static speed_t dgmdefaultrate = TTYDEF_SPEED;
275 static struct speedtab dgmspeedtab[] = {
276 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
290 { 19200, FEP_B19200 },
291 { 38400, FEP_B38400 },
292 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
293 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
297 static struct dbgflagtbl {
302 { PARODD, PARODD, FEP_PARODD },
303 { PARENB, PARENB, FEP_PARENB },
304 { CSTOPB, CSTOPB, FEP_CSTOPB },
305 { CSIZE, CS5, FEP_CS6 },
306 { CSIZE, CS6, FEP_CS6 },
307 { CSIZE, CS7, FEP_CS7 },
308 { CSIZE, CS8, FEP_CS8 },
309 { CLOCAL, CLOCAL, FEP_CLOCAL },
312 { IGNBRK, IGNBRK, FEP_IGNBRK },
313 { BRKINT, BRKINT, FEP_BRKINT },
314 { IGNPAR, IGNPAR, FEP_IGNPAR },
315 { PARMRK, PARMRK, FEP_PARMRK },
316 { INPCK, INPCK, FEP_INPCK },
317 { ISTRIP, ISTRIP, FEP_ISTRIP },
318 { IXON, IXON, FEP_IXON },
319 { IXOFF, IXOFF, FEP_IXOFF },
320 { IXANY, IXANY, FEP_IXANY },
323 { CRTSCTS, CRTSCTS, CTS|RTS },
324 { CRTSCTS, CCTS_OFLOW, CTS },
325 { CRTSCTS, CRTS_IFLOW, RTS },
329 /* xlat bsd termios flags to dgm sys-v style */
331 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
336 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
337 if ((input & tbl[i].in_mask) == tbl[i].in_val)
338 output |= tbl[i].out_val;
343 static int dgmdebug = 0;
344 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
346 static __inline int setwin(struct dgm_softc *, unsigned);
347 static __inline void hidewin(struct dgm_softc *);
348 static __inline void towin(struct dgm_softc *, int);
350 /*Helg: to allow recursive dgm...() calls */
352 /* If we were called and don't want to disturb we need: */
353 int port; /* write to this port */
354 u_char data; /* this data on exit */
355 /* or DATA_WINOFF to close memory window on entry */
356 } BoardMemWinState; /* so several channels and even boards can coexist */
358 #define DATA_WINOFF 0
359 static BoardMemWinState bmws;
361 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
362 static u_long validmem[] = {
363 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
364 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
365 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
366 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
367 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
370 /* return current memory window state and close window */
371 static BoardMemWinState
374 BoardMemWinState bmwsRet = bmws;
376 if (bmws.data != DATA_WINOFF)
377 outb(bmws.port, bmws.data = DATA_WINOFF);
381 /* restore memory window state */
383 bmws_set(BoardMemWinState ws)
385 if (ws.data != bmws.data || ws.port != bmws.port) {
386 if (bmws.data != DATA_WINOFF)
387 outb(bmws.port, DATA_WINOFF);
388 if (ws.data != DATA_WINOFF)
389 outb(ws.port, ws.data);
395 setwin(struct dgm_softc *sc, unsigned int addr)
397 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
398 return (addr & 0x7FFF);
402 hidewin(struct dgm_softc *sc)
405 outb(bmws.port = sc->port + 1, bmws.data);
409 towin(struct dgm_softc *sc, int win)
411 outb(bmws.port = sc->port + 1, bmws.data = win);
415 dgmprobe(device_t dev)
417 struct dgm_softc *sc = device_get_softc(dev);
421 * Assign unit number. Due to bits we use in the minor number for
422 * the various tty types, only 4 units are supported.
424 sc->unit = device_get_unit(dev);
426 device_printf(dev, "Too many units, only 4 supported\n");
430 /* Check that we've got a valid i/o address */
431 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
433 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
434 if (sc->port == validio[i])
437 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
441 /* Ditto for our memory address */
442 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
444 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
445 if (sc->pmem == validmem[i])
448 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
451 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
452 device_printf(dev, "0x%lx: Memory address not supported\n",
456 sc->vmem = (u_char *)sc->pmem;
458 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
461 /* Temporarily map our io ports */
463 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
464 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
465 if (sc->io_res == NULL)
468 outb(sc->port, FEPRST);
471 for (i = 0; i < 1000; i++) {
473 if ((inb(sc->port) & FEPMASK) == FEPRST) {
475 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
482 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
483 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
487 /* check type of card and get internal memory characteristics */
495 second = inb(sc->port);
496 kprintf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
498 kprintf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
501 sc->mem_seg = 0x8000;
503 /* Temporarily map our memory too */
505 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
506 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
507 if (sc->mem_res == NULL) {
508 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
509 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
513 outb(sc->port, FEPCLR); /* drop RESET */
514 hidewin(sc); /* Helg: to set initial bmws state */
516 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
517 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
519 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
520 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
522 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
528 dgmattach(device_t dev)
530 struct dgm_softc *sc = device_get_softc(dev);
536 volatile struct board_chan *bc;
539 u_long msize, iosize;
541 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
543 callout_init(&sc->toh);
544 sc->unit = device_get_unit(dev);
545 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
546 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
547 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
549 sc->mem_seg = 0x8000;
552 sc->mem_seg = 0x8000;
554 /* Allocate resources (should have been verified in dgmprobe()) */
556 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
557 0ul, ~0ul, iosize, RF_ACTIVE);
558 if (sc->io_res == NULL)
561 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
562 0ul, ~0ul, msize, RF_ACTIVE);
563 if (sc->mem_res == NULL) {
564 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
565 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
570 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
573 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
576 outb(sc->port, FEPRST);
579 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
581 device_printf(dev, "1st reset failed\n");
584 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
585 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
591 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
593 t = sc->pmem >> 8; /* disable windowing */
594 outb(sc->port + 2, t & 0xFF);
595 outb(sc->port + 3, t >> 8);
599 /* very short memory test */
600 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
602 addr = setwin(sc, BOTWIN);
603 *(u_long *)(mem + addr) = 0xA55A3CC3;
604 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
605 device_printf(dev, "1st memory test failed\n");
608 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
609 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
613 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
615 addr = setwin(sc, TOPWIN);
616 *(u_long *)(mem + addr) = 0x5AA5C33C;
617 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
618 device_printf(dev, "2nd memory test failed\n");
621 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
622 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
626 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
628 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
629 *(u_long *)(mem + addr) = 0x5AA5C33C;
630 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
631 device_printf(dev, "3rd (BIOS) memory test failed\n");
633 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
635 addr = setwin(sc, MISCGLOBAL);
636 for (i = 0; i < 16; i++)
639 addr = setwin(sc, BIOSOFFSET);
641 for (i = 0; ptr < mem + msize; i++)
642 *ptr++ = pcem_bios[i];
644 ptr = mem + BIOSOFFSET;
645 for (i = 0; ptr < mem + msize; i++) {
646 if (*ptr++ != pcem_bios[i]) {
647 kprintf("Low BIOS load failed\n");
650 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
651 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
655 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
657 addr = setwin(sc, msize);
659 for (;i < pcem_nbios; i++)
660 *ptr++ = pcem_bios[i];
663 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
664 if (*ptr++ != pcem_bios[i]) {
665 kprintf("High BIOS load failed\n");
668 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
669 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
673 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
674 device_printf(dev, "DigiBIOS loaded, initializing");
676 addr = setwin(sc, 0);
678 *(u_int *)(mem + addr) = 0x0bf00401;
679 *(u_int *)(mem + addr + 4) = 0;
680 *(ushort *)(mem + addr + 0xc00) = 0;
683 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
686 kprintf("\nBIOS initialize failed(1)\n");
689 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
690 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
695 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
696 kprintf("\nBIOS initialize failed(2)\n");
699 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
700 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
703 kprintf(", DigiBIOS running\n");
707 addr = setwin(sc, BIOSOFFSET);
709 for (i = 0; i < pcem_ncook; i++)
710 *ptr++ = pcem_cook[i];
712 ptr = mem + BIOSOFFSET;
713 for (i = 0; i < pcem_ncook; i++) {
714 if (*ptr++ != pcem_cook[i]) {
715 kprintf("FEP/OS load failed\n");
718 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
719 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
723 device_printf(dev, "FEP/OS loaded, initializing");
725 addr = setwin(sc, 0);
726 *(ushort *)(mem + addr + 0xd20) = 0;
727 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
728 *(u_int *)(mem + addr + 0xc30) = 0x3L;
731 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
734 kprintf("\nFEP/OS initialize failed(1)\n");
737 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
738 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
743 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
744 kprintf("\nFEP/OS initialize failed(2)\n");
747 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
748 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
751 kprintf(", FEP/OS running\n");
753 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
754 device_printf(dev, "%d ports attached\n", sc->numports);
756 if (sc->numports > MAX_DGM_PORTS) {
757 kprintf("dgm%d: too many ports\n", sc->unit);
760 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
761 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
765 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
766 M_TTYS, M_WAITOK|M_ZERO);
767 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
768 M_TTYS, M_WAITOK|M_ZERO);
770 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
771 for (i = 0; i < sc->numports; i++) {
772 sc->ports[i].enabled = 1;
773 callout_init(&sc->ports[i].hc_timeout);
774 callout_init(&sc->ports[i].wf_timeout);
777 /* We should now init per-port structures */
779 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
780 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
782 if (sc->numports < 3)
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_ops, (sc->unit*65536) + i, UID_ROOT,
862 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
863 make_dev(&dgm_ops, sc->unit * 65536 + i + 64, UID_ROOT,
864 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
865 make_dev(&dgm_ops, sc->unit * 65536 + i + 128, UID_ROOT,
866 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
867 make_dev(&dgm_ops, sc->unit * 65536 + i + 262144, UID_UUCP,
868 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
869 make_dev(&dgm_ops, sc->unit * 65536 + i + 262208, UID_UUCP,
870 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
871 make_dev(&dgm_ops, 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 callout_reset(&sc->toh, hz / POLLSPERSEC,
881 dgmpoll, (void *)(int)sc->unit);
883 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
889 dgmdetach(device_t dev)
891 struct dgm_softc *sc = device_get_softc(dev);
894 for (i = 0; i < sc->numports; i++)
895 if (sc->ttys[i].t_state & TS_ISOPEN)
898 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
901 * The dev_ops_remove() call will destroy all associated devices
902 * and dereference any ad-hoc-created devices, but does not
903 * dereference devices created via make_dev().
905 dev_ops_remove_minor(&dgm_ops/*, DGM_UNITMASK*/, DGM_UNIT(sc->unit));
907 callout_stop(&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);
916 pmap_unmapdev((vm_offset_t)sc->vmem, sc->msize);
924 dgmshutdown(device_t dev)
927 struct dgm_softc *sc = device_get_softc(dev);
929 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
937 dgmopen(struct dev_open_args *ap)
939 cdev_t dev = ap->a_head.a_dev;
940 struct dgm_softc *sc;
947 volatile struct board_chan *bc;
951 unit = MINOR_TO_UNIT(mynor);
952 pnum = MINOR_TO_PORT(mynor);
954 sc = devclass_get_softc(dgmdevclass, unit);
956 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
961 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
964 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
969 if (pnum >= sc->numports) {
970 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
975 if (mynor & CONTROL_MASK)
978 tp = &sc->ttys[pnum];
980 port = &sc->ports[pnum];
986 while (port->closing) {
987 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
990 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
991 " error = %d\n", unit, pnum, error);
996 if (tp->t_state & TS_ISOPEN) {
998 * The device is open, so everything has been initialized.
1001 if (mynor & CALLOUT_MASK) {
1002 if (!port->active_out) {
1004 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1005 " BUSY error = %d\n", unit, pnum, error);
1008 } else if (port->active_out) {
1009 if (ap->a_oflags & O_NONBLOCK) {
1011 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1012 " BUSY error = %d\n", unit, pnum, error);
1015 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1017 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1018 " error = %d\n", unit, pnum, error);
1024 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
1030 * The device isn't open, so there are no conflicts.
1031 * Initialize it. Initialization is done twice in many
1032 * cases: to preempt sleeping callin opens if we are
1033 * callout, and to complete a callin open after DCD rises.
1035 tp->t_oproc = dgmstart;
1036 tp->t_param = dgmparam;
1037 tp->t_stop = dgmstop;
1039 tp->t_termios= (mynor & CALLOUT_MASK) ?
1045 port->imodem = bc->mstat;
1046 bc->rout = bc->rin; /* clear input queue */
1048 #ifdef PRINT_BUFSIZE
1049 kprintf("dgm buffers tx = %x:%x rx = %x:%x\n",
1050 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1057 error = dgmparam(tp, &tp->t_termios);
1061 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1066 /* handle fake DCD for callout devices */
1067 /* and initial DCD */
1069 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1070 linesw[tp->t_line].l_modem(tp, 1);
1074 * Wait for DCD if necessary.
1076 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1077 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1079 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1082 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1083 " error = %d\n", unit, pnum, error);
1089 error = linesw[tp->t_line].l_open(dev, tp);
1090 disc_optim(tp, &tp->t_termios);
1091 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1094 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1095 port->active_out = 1;
1099 /* If any port is open (i.e. the open() call is completed for it)
1100 * the device is busy
1104 disc_optim(tp, &tp->t_termios);
1107 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1110 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1118 dgmclose(struct dev_close_args *ap)
1120 cdev_t dev = ap->a_head.a_dev;
1124 struct dgm_softc *sc;
1129 if (mynor & CONTROL_MASK)
1131 unit = MINOR_TO_UNIT(mynor);
1132 pnum = MINOR_TO_PORT(mynor);
1134 sc = devclass_get_softc(dgmdevclass, unit);
1135 tp = &sc->ttys[pnum];
1136 port = sc->ports + pnum;
1138 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1140 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1141 dgm_drain_or_flush(port);
1146 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1147 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1148 disc_optim(tp, &tp->t_termios);
1150 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1152 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1155 wakeup(&port->closing);
1158 /* mark the card idle when all ports are closed */
1160 for (i = 0; i < sc->numports; i++)
1161 if (sc->ports[i].used)
1166 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1168 wakeup(TSA_CARR_ON(tp));
1169 wakeup(&port->active_out);
1170 port->active_out = 0;
1172 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1178 dgmhardclose(struct dgm_p *port)
1180 volatile struct board_chan *bc = port->brdchan;
1181 struct dgm_softc *sc;
1183 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1184 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1186 port->do_timestamp = 0;
1192 if (port->tty->t_cflag & HUPCL) {
1193 port->omodem &= ~(RTS|DTR);
1194 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1200 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1201 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1205 dgm_pause(void *chan)
1207 wakeup((caddr_t)chan);
1211 dgmpoll(void *unit_c)
1213 int unit = (int)unit_c;
1216 struct dgm_softc *sc;
1219 int event, mstat, lstat;
1220 volatile struct board_chan *bc;
1227 int ibuf_full, obuf_full;
1228 BoardMemWinState ws = bmws_get();
1230 sc = devclass_get_softc(dgmdevclass, unit);
1231 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1234 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1240 head = sc->mailbox->ein;
1241 tail = sc->mailbox->eout;
1243 while (head != tail) {
1244 if (head >= FEP_IMAX - FEP_ISTART
1245 || tail >= FEP_IMAX - FEP_ISTART
1246 || (head|tail) & 03 ) {
1247 kprintf("dgm%d: event queue's head or tail is wrong!"
1248 " hd = %d, tl = %d\n", unit, head, tail);
1252 eventbuf = sc->vmem + tail + FEP_ISTART;
1254 event = eventbuf[1];
1255 mstat = eventbuf[2];
1256 lstat = eventbuf[3];
1258 port = &sc->ports[pnum];
1260 tp = &sc->ttys[pnum];
1262 if (pnum >= sc->numports || !port->enabled) {
1263 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1265 } else if (port->used || port->wopeners > 0 ) {
1267 int wrapmask = port->rxbufsize - 1;
1269 if (!(event & ALL_IND))
1270 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1271 unit, pnum, event, mstat, lstat);
1273 if (event & DATA_IND) {
1274 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1277 rhead = bc->rin & wrapmask;
1278 rtail = bc->rout & wrapmask;
1280 if (!(tp->t_cflag & CREAD) || !port->used ) {
1286 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1290 if (!(tp->t_state & TS_ISOPEN))
1293 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1294 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1295 " p rx head = %d tail = %d\n", unit,
1296 pnum, rhead, rtail);
1299 size = rhead - rtail;
1301 size = port->rxbufsize - rtail;
1303 ptr = port->rxptr + rtail;
1306 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1307 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1308 DPRINT1(DB_RXDATA, "*");
1313 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1314 DPRINT1(DB_RXDATA, "!");
1315 towin(sc, port->rxwin);
1318 tp->t_rawcc += size;
1326 towin(sc, port->rxwin);
1329 (*linesw[tp->t_line].l_rint)(chr, tp);
1334 rtail= (rtail + size) & wrapmask;
1336 rhead = bc->rin & wrapmask;
1344 if (event & MODEMCHG_IND) {
1345 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1346 "MODEMCHG_IND\n", unit, pnum);
1347 port->imodem = mstat;
1348 if (mstat & port->dcd) {
1350 linesw[tp->t_line].l_modem(tp, 1);
1352 wakeup(TSA_CARR_ON(tp));
1355 linesw[tp->t_line].l_modem(tp, 0);
1357 if (port->draining) {
1359 wakeup(&port->draining);
1364 if (event & BREAK_IND) {
1365 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1366 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1367 " BREAK_IND\n", unit, pnum);
1369 linesw[tp->t_line].l_rint(TTY_BI, tp);
1374 /* Helg: with output flow control */
1376 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1377 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1378 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1380 if ((event & EMPTYTX_IND ) &&
1381 tp->t_outq.c_cc == 0 && port->draining) {
1383 wakeup(&port->draining);
1388 int wrapmask = port->txbufsize - 1;
1390 for (obuf_full = FALSE;
1391 tp->t_outq.c_cc != 0 && !obuf_full;
1393 /* add "last-minute" data to write buffer */
1394 if (!(tp->t_state & TS_BUSY)) {
1396 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1399 if (tp->t_outq.c_cc <= tp->t_lowat) {
1400 if (tp->t_state & TS_ASLEEP) {
1401 tp->t_state &= ~TS_ASLEEP;
1402 wakeup(TSA_OLOWAT(tp));
1404 /* selwakeup(&tp->t_wsel); */
1411 whead = bc->tin & wrapmask;
1412 wtail = bc->tout & wrapmask;
1415 size = wtail - whead - 1;
1417 size = port->txbufsize - whead;
1423 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1424 whead, wtail, size, obuf_full);
1432 towin(sc, port->txwin);
1434 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1439 bc->tin = whead & wrapmask;
1444 DPRINT1(DB_WR, " +BUSY\n");
1445 tp->t_state |= TS_BUSY;
1447 DPRINT1(DB_WR, " -BUSY\n");
1449 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1450 /* should clear TS_BUSY before ttwwakeup */
1451 if (tp->t_state & TS_BUSY) {
1452 tp->t_state &= ~TS_BUSY;
1453 linesw[tp->t_line].l_start(tp);
1457 if (tp->t_state & TS_ASLEEP) {
1458 tp->t_state &= ~TS_ASLEEP;
1459 wakeup(TSA_OLOWAT(tp));
1461 tp->t_state &= ~TS_BUSY;
1467 bc->idata = 1; /* require event on incoming data */
1471 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1474 bc->idata = bc->iempty = bc->ilow = 0;
1477 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1480 sc->mailbox->eout = tail;
1483 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1485 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1489 dgmioctl(struct dev_ioctl_args *ap)
1491 cdev_t dev = ap->a_head.a_dev;
1492 u_long cmd = ap->a_cmd;
1493 caddr_t data = ap->a_data;
1494 struct dgm_softc *sc;
1499 volatile struct board_chan *bc;
1503 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1505 struct termios term;
1508 BoardMemWinState ws = bmws_get();
1511 unit = MINOR_TO_UNIT(mynor);
1512 pnum = MINOR_TO_PORT(mynor);
1514 sc = devclass_get_softc(dgmdevclass, unit);
1515 port = &sc->ports[pnum];
1516 tp = &sc->ttys[pnum];
1519 if (mynor & CONTROL_MASK) {
1522 switch (mynor & CONTROL_MASK) {
1523 case CONTROL_INIT_STATE:
1524 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1526 case CONTROL_LOCK_STATE:
1527 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1530 return (ENODEV); /* /dev/nodev */
1534 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1537 *ct = *(struct termios *)data;
1540 *(struct termios *)data = *ct;
1543 *(int *)data = TTYDISC;
1546 bzero(data, sizeof(struct winsize));
1553 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1554 term = tp->t_termios;
1555 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1556 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);
1559 error = ttsetcompat(tp, &cmd, data, &term);
1563 data = (caddr_t)&term;
1566 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1568 struct termios *dt = (struct termios *)data;
1569 struct termios *lt = mynor & CALLOUT_MASK
1570 ? &port->lt_out : &port->lt_in;
1572 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);
1573 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1574 | (dt->c_iflag & ~lt->c_iflag);
1575 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1576 | (dt->c_oflag & ~lt->c_oflag);
1577 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1578 | (dt->c_cflag & ~lt->c_cflag);
1579 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1580 | (dt->c_lflag & ~lt->c_lflag);
1581 for (cc = 0; cc < NCCS; ++cc)
1582 if (lt->c_cc[cc] != 0)
1583 dt->c_cc[cc] = tp->t_cc[cc];
1584 if (lt->c_ispeed != 0)
1585 dt->c_ispeed = tp->t_ispeed;
1586 if (lt->c_ospeed != 0)
1587 dt->c_ospeed = tp->t_ospeed;
1590 if (cmd == TIOCSTOP) {
1593 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1597 } else if (cmd == TIOCSTART) {
1600 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1606 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1607 port->mustdrain = 1;
1609 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1610 ap->a_fflag, ap->a_cred);
1611 if (error != ENOIOCTL)
1614 error = ttioctl(tp, cmd, data, ap->a_fflag);
1615 disc_optim(tp, &tp->t_termios);
1616 port->mustdrain = 0;
1617 if (error != ENOIOCTL) {
1619 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1620 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);
1628 error = dgmdrain(port);
1639 /* now it sends 400 millisecond break because I don't know */
1640 /* how to send an infinite break */
1642 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1647 /* now it's empty */
1650 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1651 port->omodem |= DTR;
1654 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1656 if (!(bc->mstat & DTR))
1657 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1663 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1664 port->omodem &= ~DTR;
1667 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1669 if (bc->mstat & DTR) {
1670 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1677 if (*(int *)data & TIOCM_DTR)
1678 port->omodem |= DTR;
1680 port->omodem &= ~DTR;
1682 if (*(int *)data & TIOCM_RTS)
1683 port->omodem |= RTS;
1685 port->omodem &= ~RTS;
1689 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1694 if (*(int *)data & TIOCM_DTR)
1695 port->omodem |= DTR;
1697 if (*(int *)data & TIOCM_RTS)
1698 port->omodem |= RTS;
1702 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1707 if (*(int *)data & TIOCM_DTR)
1708 port->omodem &= ~DTR;
1710 if (*(int *)data & TIOCM_RTS)
1711 port->omodem &= ~RTS;
1715 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1721 port->imodem = bc->mstat;
1724 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1726 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1728 if (port->imodem & DTR) {
1729 DPRINT1(DB_MODEM, "DTR ");
1730 tiocm_xxx |= TIOCM_DTR;
1732 if (port->imodem & RTS) {
1733 DPRINT1(DB_MODEM, "RTS ");
1734 tiocm_xxx |= TIOCM_RTS;
1736 if (port->imodem & CTS) {
1737 DPRINT1(DB_MODEM, "CTS ");
1738 tiocm_xxx |= TIOCM_CTS;
1740 if (port->imodem & port->dcd) {
1741 DPRINT1(DB_MODEM, "DCD ");
1742 tiocm_xxx |= TIOCM_CD;
1744 if (port->imodem & port->dsr) {
1745 DPRINT1(DB_MODEM, "DSR ");
1746 tiocm_xxx |= TIOCM_DSR;
1748 if (port->imodem & RI) {
1749 DPRINT1(DB_MODEM, "RI ");
1750 tiocm_xxx |= TIOCM_RI;
1752 *(int *)data = tiocm_xxx;
1753 DPRINT1(DB_MODEM, "--\n");
1756 /* must be root since the wait applies to following logins */
1757 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1762 port->close_delay = *(int *)data * hz / 100;
1765 *(int *)data = port->close_delay * 100 / hz;
1768 port->do_timestamp = 1;
1769 *(struct timeval *)data = port->timestamp;
1771 case TIOCDCDTIMESTAMP:
1772 port->do_dcd_timestamp = 1;
1773 *(struct timeval *)data = port->dcd_timestamp;
1789 struct dgm_p *port = p;
1791 wakeup(&port->draining);
1794 /* wait for the output to drain */
1797 dgmdrain(struct dgm_p *port)
1799 volatile struct board_chan *bc = port->brdchan;
1800 struct dgm_softc *sc;
1803 BoardMemWinState ws = bmws_get();
1805 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1813 while (tail != head) {
1814 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1815 port->sc->unit, port->pnum, head, tail);
1819 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1820 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1825 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1826 port->sc->unit, port->pnum, error);
1836 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1837 port->sc->unit, port->pnum, head, tail);
1842 /* wait for the output to drain */
1843 /* or simply clear the buffer it it's stopped */
1846 dgm_drain_or_flush(struct dgm_p *port)
1848 volatile struct board_chan *bc = port->brdchan;
1849 struct tty *tp = port->tty;
1850 struct dgm_softc *sc;
1855 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1863 while (tail != head /* && tail != lasttail */ ) {
1864 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1865 port->sc->unit, port->pnum, head, tail);
1867 /* if there is no carrier simply clean the buffer */
1868 if (!(tp->t_state & TS_CARR_ON)) {
1869 bc->tout = bc->tin = 0;
1877 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1878 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1883 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1884 " error = %d\n", port->sc->unit, port->pnum, error);
1886 /* silently clean the buffer */
1888 bc->tout = bc->tin = 0;
1899 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1900 port->sc->unit, port->pnum, head, tail);
1904 dgmparam(struct tty *tp, struct termios *t)
1906 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1907 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1908 volatile struct board_chan *bc;
1909 struct dgm_softc *sc;
1916 BoardMemWinState ws = bmws_get();
1918 sc = devclass_get_softc(dgmdevclass, unit);
1919 port = &sc->ports[pnum];
1922 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);
1924 if (port->mustdrain) {
1925 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1929 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1931 if (t->c_ispeed == 0)
1932 t->c_ispeed = t->c_ospeed;
1934 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1935 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1942 if (cflag == 0) { /* hangup */
1943 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1947 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1948 mval= port->omodem & ~(DTR|RTS);
1950 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1952 if (cflag != port->fepcflag) {
1953 port->fepcflag = cflag;
1954 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1955 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1956 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1958 mval= port->omodem | (DTR|RTS);
1961 iflag = dgmflags(dgm_iflags, t->c_iflag);
1962 if (iflag != port->fepiflag) {
1963 port->fepiflag = iflag;
1964 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1965 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1968 bc->mint = port->dcd;
1970 hflow = dgmflags(dgm_flow, t->c_cflag);
1971 if (hflow != port->hflow) {
1972 port->hflow = hflow;
1973 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1974 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1977 if (port->omodem != mval) {
1978 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1979 unit, pnum, mval, port->omodem);
1980 port->omodem = mval;
1981 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1984 if (port->fepstartc != t->c_cc[VSTART] ||
1985 port->fepstopc != t->c_cc[VSTOP]) {
1986 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1987 port->fepstartc = t->c_cc[VSTART];
1988 port->fepstopc = t->c_cc[VSTOP];
1989 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
2000 dgmstart(struct tty *tp)
2005 struct dgm_softc *sc;
2006 volatile struct board_chan *bc;
2011 BoardMemWinState ws = bmws_get();
2013 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2014 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2015 sc = devclass_get_softc(dgmdevclass, unit);
2016 port = &sc->ports[pnum];
2019 wmask = port->txbufsize - 1;
2023 while (tp->t_outq.c_cc != 0) {
2024 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2027 if (tp->t_outq.c_cc <= tp->t_lowat) {
2028 if (tp->t_state & TS_ASLEEP) {
2029 tp->t_state &= ~TS_ASLEEP;
2030 wakeup(TSA_OLOWAT(tp));
2032 /*selwakeup(&tp->t_wsel);*/
2038 head = bc->tin & wmask;
2040 do { tail = bc->tout; } while (tail != bc->tout);
2041 tail = bc->tout & wmask;
2043 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2045 #ifdef LEAVE_FREE_CHARS
2047 size = tail - head - LEAVE_FREE_CHARS;
2051 size = port->txbufsize - head;
2052 if (tail + port->txbufsize < head)
2058 size = tail - head - 1;
2060 size = port->txbufsize - head;
2071 tp->t_state |= TS_BUSY;
2076 towin(sc, port->txwin);
2078 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2080 if (head >= port->txbufsize)
2081 head -= port->txbufsize;
2086 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2087 unit, pnum, size, ocount);
2095 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2096 if (tp->t_state & TS_BUSY) {
2097 tp->t_state &= ~TS_BUSY;
2098 linesw[tp->t_line].l_start(tp);
2102 if (tp->t_state & TS_ASLEEP) {
2103 tp->t_state &= ~TS_ASLEEP;
2104 wakeup(TSA_OLOWAT(tp));
2106 tp->t_state& = ~TS_BUSY;
2111 dgmstop(struct tty *tp, int rw)
2116 struct dgm_softc *sc;
2117 volatile struct board_chan *bc;
2119 BoardMemWinState ws = bmws_get();
2121 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2122 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2124 sc = devclass_get_softc(dgmdevclass, unit);
2125 port = &sc->ports[pnum];
2128 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2134 /* clear output queue */
2135 bc->tout = bc->tin = 0;
2140 /* clear input queue */
2151 fepcmd(struct dgm_p *port,
2159 unsigned tail, head;
2162 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2163 mem = port->sc->vmem;
2165 if (!port->enabled) {
2166 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2167 port->sc->unit, port->pnum);
2171 /* setwin(port->sc, 0); Require this to be set by caller */
2172 head = port->sc->mailbox->cin;
2174 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2175 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2176 port->sc->unit, port->pnum, head);
2180 mem[head + FEP_CSTART] = cmd;
2181 mem[head + FEP_CSTART + 1] = port->pnum;
2183 mem[head + FEP_CSTART + 2] = op1;
2184 mem[head + FEP_CSTART + 3] = op2;
2186 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2187 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2190 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2191 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2193 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2194 port->sc->mailbox->cin = head;
2198 while (count-- != 0) {
2199 head = port->sc->mailbox->cin;
2200 tail = port->sc->mailbox->cout;
2202 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2203 if (n <= ncmds * (sizeof(ushort)*4))
2206 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2210 disc_optim(struct tty *tp, struct termios *t)
2212 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2213 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2214 && (!(t->c_iflag & PARMRK)
2215 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2216 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2217 && linesw[tp->t_line].l_rint == ttyinput)
2218 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2220 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;