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 dev_ops_add(&dgm_ops, DGM_UNITMASK, DGM_UNIT(sc->unit));
788 for (i = 0; i < sc->numports; i++, bc++) {
789 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
790 port = &sc->ports[i];
793 port->tty = &sc->ttys[i];
801 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
803 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
804 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
808 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
809 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
810 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
811 port->txwin = FEPWIN | (bc->tseg >> 11);
812 port->rxwin = FEPWIN | (bc->rseg >> 11);
816 port->txbufsize = bc->tmax + 1;
817 port->rxbufsize = bc->rmax + 1;
819 lowwater = (port->txbufsize >= 2000) ?
820 1024 : (port->txbufsize / 2);
823 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
824 sc->unit, i, lowwater);
825 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
826 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
827 sc->unit, i, port->rxbufsize / 4);
828 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
829 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
830 sc->unit, i, 3 * port->rxbufsize / 4);
831 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
836 port->startc = bc->startc;
837 port->startca = bc->startca;
838 port->stopc = bc->stopc;
839 port->stopca = bc->stopca;
841 /* port->close_delay = 50; */
842 port->close_delay = 3 * hz;
843 port->do_timestamp = 0;
844 port->do_dcd_timestamp = 0;
846 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
848 * We don't use all the flags from <sys/ttydefaults.h> since
849 * they are only relevant for logins. It's important to have
850 * echo off initially so that the line doesn't start
851 * blathering before the echo flag can be turned off.
853 port->it_in.c_iflag = TTYDEF_IFLAG;
854 port->it_in.c_oflag = TTYDEF_OFLAG;
855 port->it_in.c_cflag = TTYDEF_CFLAG;
856 port->it_in.c_lflag = TTYDEF_LFLAG;
857 termioschars(&port->it_in);
858 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
859 port->it_out = port->it_in;
861 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
862 make_dev(&dgm_ops, (sc->unit*65536) + i, UID_ROOT,
863 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
864 make_dev(&dgm_ops, sc->unit * 65536 + i + 64, UID_ROOT,
865 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
866 make_dev(&dgm_ops, sc->unit * 65536 + i + 128, UID_ROOT,
867 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
868 make_dev(&dgm_ops, sc->unit * 65536 + i + 262144, UID_UUCP,
869 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
870 make_dev(&dgm_ops, sc->unit * 65536 + i + 262208, UID_UUCP,
871 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
872 make_dev(&dgm_ops, sc->unit * 65536 + i + 262272, UID_UUCP,
873 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
876 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
880 /* start the polling function */
881 callout_reset(&sc->toh, hz / POLLSPERSEC,
882 dgmpoll, (void *)(int)sc->unit);
884 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
890 dgmdetach(device_t dev)
892 struct dgm_softc *sc = device_get_softc(dev);
895 for (i = 0; i < sc->numports; i++)
896 if (sc->ttys[i].t_state & TS_ISOPEN)
899 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
902 * The dev_ops_remove() call will destroy all associated devices
903 * and dereference any ad-hoc-created devices, but does not
904 * dereference devices created via make_dev().
906 kprintf("devfs: Please check that only the right dgm devices were removed!!!!\n");
907 dev_ops_remove_minor(&dgm_ops/*, DGM_UNITMASK*/, DGM_UNIT(sc->unit));
909 callout_stop(&sc->toh);
911 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
912 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
914 FREE(sc->ports, M_TTYS);
915 FREE(sc->ttys, M_TTYS);
918 pmap_unmapdev(sc->vmem, sc->msize);
926 dgmshutdown(device_t dev)
929 struct dgm_softc *sc = device_get_softc(dev);
931 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
939 dgmopen(struct dev_open_args *ap)
941 cdev_t dev = ap->a_head.a_dev;
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 (ap->a_oflags & 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 && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
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 kprintf("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) && !(ap->a_oflags & 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(struct dev_close_args *ap)
1122 cdev_t dev = ap->a_head.a_dev;
1126 struct dgm_softc *sc;
1131 if (mynor & CONTROL_MASK)
1133 unit = MINOR_TO_UNIT(mynor);
1134 pnum = MINOR_TO_PORT(mynor);
1136 sc = devclass_get_softc(dgmdevclass, unit);
1137 tp = &sc->ttys[pnum];
1138 port = sc->ports + pnum;
1140 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1142 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1143 dgm_drain_or_flush(port);
1148 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1149 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1150 disc_optim(tp, &tp->t_termios);
1152 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1154 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1157 wakeup(&port->closing);
1160 /* mark the card idle when all ports are closed */
1162 for (i = 0; i < sc->numports; i++)
1163 if (sc->ports[i].used)
1168 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1170 wakeup(TSA_CARR_ON(tp));
1171 wakeup(&port->active_out);
1172 port->active_out = 0;
1174 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1180 dgmhardclose(struct dgm_p *port)
1182 volatile struct board_chan *bc = port->brdchan;
1183 struct dgm_softc *sc;
1185 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1186 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1188 port->do_timestamp = 0;
1194 if (port->tty->t_cflag & HUPCL) {
1195 port->omodem &= ~(RTS|DTR);
1196 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1202 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1203 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1207 dgm_pause(void *chan)
1209 wakeup((caddr_t)chan);
1213 dgmpoll(void *unit_c)
1215 int unit = (int)unit_c;
1218 struct dgm_softc *sc;
1221 int event, mstat, lstat;
1222 volatile struct board_chan *bc;
1229 int ibuf_full, obuf_full;
1230 BoardMemWinState ws = bmws_get();
1232 sc = devclass_get_softc(dgmdevclass, unit);
1233 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1236 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1242 head = sc->mailbox->ein;
1243 tail = sc->mailbox->eout;
1245 while (head != tail) {
1246 if (head >= FEP_IMAX - FEP_ISTART
1247 || tail >= FEP_IMAX - FEP_ISTART
1248 || (head|tail) & 03 ) {
1249 kprintf("dgm%d: event queue's head or tail is wrong!"
1250 " hd = %d, tl = %d\n", unit, head, tail);
1254 eventbuf = sc->vmem + tail + FEP_ISTART;
1256 event = eventbuf[1];
1257 mstat = eventbuf[2];
1258 lstat = eventbuf[3];
1260 port = &sc->ports[pnum];
1262 tp = &sc->ttys[pnum];
1264 if (pnum >= sc->numports || !port->enabled) {
1265 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1267 } else if (port->used || port->wopeners > 0 ) {
1269 int wrapmask = port->rxbufsize - 1;
1271 if (!(event & ALL_IND))
1272 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1273 unit, pnum, event, mstat, lstat);
1275 if (event & DATA_IND) {
1276 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1279 rhead = bc->rin & wrapmask;
1280 rtail = bc->rout & wrapmask;
1282 if (!(tp->t_cflag & CREAD) || !port->used ) {
1288 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1292 if (!(tp->t_state & TS_ISOPEN))
1295 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1296 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1297 " p rx head = %d tail = %d\n", unit,
1298 pnum, rhead, rtail);
1301 size = rhead - rtail;
1303 size = port->rxbufsize - rtail;
1305 ptr = port->rxptr + rtail;
1308 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1309 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1310 DPRINT1(DB_RXDATA, "*");
1315 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1316 DPRINT1(DB_RXDATA, "!");
1317 towin(sc, port->rxwin);
1320 tp->t_rawcc += size;
1328 towin(sc, port->rxwin);
1331 (*linesw[tp->t_line].l_rint)(chr, tp);
1336 rtail= (rtail + size) & wrapmask;
1338 rhead = bc->rin & wrapmask;
1346 if (event & MODEMCHG_IND) {
1347 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1348 "MODEMCHG_IND\n", unit, pnum);
1349 port->imodem = mstat;
1350 if (mstat & port->dcd) {
1352 linesw[tp->t_line].l_modem(tp, 1);
1354 wakeup(TSA_CARR_ON(tp));
1357 linesw[tp->t_line].l_modem(tp, 0);
1359 if (port->draining) {
1361 wakeup(&port->draining);
1366 if (event & BREAK_IND) {
1367 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1368 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1369 " BREAK_IND\n", unit, pnum);
1371 linesw[tp->t_line].l_rint(TTY_BI, tp);
1376 /* Helg: with output flow control */
1378 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1379 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1380 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1382 if ((event & EMPTYTX_IND ) &&
1383 tp->t_outq.c_cc == 0 && port->draining) {
1385 wakeup(&port->draining);
1390 int wrapmask = port->txbufsize - 1;
1392 for (obuf_full = FALSE;
1393 tp->t_outq.c_cc != 0 && !obuf_full;
1395 /* add "last-minute" data to write buffer */
1396 if (!(tp->t_state & TS_BUSY)) {
1398 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1401 if (tp->t_outq.c_cc <= tp->t_lowat) {
1402 if (tp->t_state & TS_ASLEEP) {
1403 tp->t_state &= ~TS_ASLEEP;
1404 wakeup(TSA_OLOWAT(tp));
1406 /* selwakeup(&tp->t_wsel); */
1413 whead = bc->tin & wrapmask;
1414 wtail = bc->tout & wrapmask;
1417 size = wtail - whead - 1;
1419 size = port->txbufsize - whead;
1425 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1426 whead, wtail, size, obuf_full);
1434 towin(sc, port->txwin);
1436 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1441 bc->tin = whead & wrapmask;
1446 DPRINT1(DB_WR, " +BUSY\n");
1447 tp->t_state |= TS_BUSY;
1449 DPRINT1(DB_WR, " -BUSY\n");
1451 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1452 /* should clear TS_BUSY before ttwwakeup */
1453 if (tp->t_state & TS_BUSY) {
1454 tp->t_state &= ~TS_BUSY;
1455 linesw[tp->t_line].l_start(tp);
1459 if (tp->t_state & TS_ASLEEP) {
1460 tp->t_state &= ~TS_ASLEEP;
1461 wakeup(TSA_OLOWAT(tp));
1463 tp->t_state &= ~TS_BUSY;
1469 bc->idata = 1; /* require event on incoming data */
1473 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1476 bc->idata = bc->iempty = bc->ilow = 0;
1479 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1482 sc->mailbox->eout = tail;
1485 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1487 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1491 dgmioctl(struct dev_ioctl_args *ap)
1493 cdev_t dev = ap->a_head.a_dev;
1494 u_long cmd = ap->a_cmd;
1495 caddr_t data = ap->a_data;
1496 struct dgm_softc *sc;
1501 volatile struct board_chan *bc;
1505 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1507 struct termios term;
1510 BoardMemWinState ws = bmws_get();
1513 unit = MINOR_TO_UNIT(mynor);
1514 pnum = MINOR_TO_PORT(mynor);
1516 sc = devclass_get_softc(dgmdevclass, unit);
1517 port = &sc->ports[pnum];
1518 tp = &sc->ttys[pnum];
1521 if (mynor & CONTROL_MASK) {
1524 switch (mynor & CONTROL_MASK) {
1525 case CONTROL_INIT_STATE:
1526 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1528 case CONTROL_LOCK_STATE:
1529 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1532 return (ENODEV); /* /dev/nodev */
1536 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1539 *ct = *(struct termios *)data;
1542 *(struct termios *)data = *ct;
1545 *(int *)data = TTYDISC;
1548 bzero(data, sizeof(struct winsize));
1555 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1556 term = tp->t_termios;
1557 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1558 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);
1561 error = ttsetcompat(tp, &cmd, data, &term);
1565 data = (caddr_t)&term;
1568 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1570 struct termios *dt = (struct termios *)data;
1571 struct termios *lt = mynor & CALLOUT_MASK
1572 ? &port->lt_out : &port->lt_in;
1574 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);
1575 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1576 | (dt->c_iflag & ~lt->c_iflag);
1577 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1578 | (dt->c_oflag & ~lt->c_oflag);
1579 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1580 | (dt->c_cflag & ~lt->c_cflag);
1581 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1582 | (dt->c_lflag & ~lt->c_lflag);
1583 for (cc = 0; cc < NCCS; ++cc)
1584 if (lt->c_cc[cc] != 0)
1585 dt->c_cc[cc] = tp->t_cc[cc];
1586 if (lt->c_ispeed != 0)
1587 dt->c_ispeed = tp->t_ispeed;
1588 if (lt->c_ospeed != 0)
1589 dt->c_ospeed = tp->t_ospeed;
1592 if (cmd == TIOCSTOP) {
1595 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1599 } else if (cmd == TIOCSTART) {
1602 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1608 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1609 port->mustdrain = 1;
1611 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1612 ap->a_fflag, ap->a_cred);
1613 if (error != ENOIOCTL)
1616 error = ttioctl(tp, cmd, data, ap->a_fflag);
1617 disc_optim(tp, &tp->t_termios);
1618 port->mustdrain = 0;
1619 if (error != ENOIOCTL) {
1621 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1622 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);
1630 error = dgmdrain(port);
1641 /* now it sends 400 millisecond break because I don't know */
1642 /* how to send an infinite break */
1644 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1649 /* now it's empty */
1652 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1653 port->omodem |= DTR;
1656 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1658 if (!(bc->mstat & DTR))
1659 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1665 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1666 port->omodem &= ~DTR;
1669 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1671 if (bc->mstat & DTR) {
1672 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1679 if (*(int *)data & TIOCM_DTR)
1680 port->omodem |= DTR;
1682 port->omodem &= ~DTR;
1684 if (*(int *)data & TIOCM_RTS)
1685 port->omodem |= RTS;
1687 port->omodem &= ~RTS;
1691 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1696 if (*(int *)data & TIOCM_DTR)
1697 port->omodem |= DTR;
1699 if (*(int *)data & TIOCM_RTS)
1700 port->omodem |= RTS;
1704 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1709 if (*(int *)data & TIOCM_DTR)
1710 port->omodem &= ~DTR;
1712 if (*(int *)data & TIOCM_RTS)
1713 port->omodem &= ~RTS;
1717 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1723 port->imodem = bc->mstat;
1726 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1728 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1730 if (port->imodem & DTR) {
1731 DPRINT1(DB_MODEM, "DTR ");
1732 tiocm_xxx |= TIOCM_DTR;
1734 if (port->imodem & RTS) {
1735 DPRINT1(DB_MODEM, "RTS ");
1736 tiocm_xxx |= TIOCM_RTS;
1738 if (port->imodem & CTS) {
1739 DPRINT1(DB_MODEM, "CTS ");
1740 tiocm_xxx |= TIOCM_CTS;
1742 if (port->imodem & port->dcd) {
1743 DPRINT1(DB_MODEM, "DCD ");
1744 tiocm_xxx |= TIOCM_CD;
1746 if (port->imodem & port->dsr) {
1747 DPRINT1(DB_MODEM, "DSR ");
1748 tiocm_xxx |= TIOCM_DSR;
1750 if (port->imodem & RI) {
1751 DPRINT1(DB_MODEM, "RI ");
1752 tiocm_xxx |= TIOCM_RI;
1754 *(int *)data = tiocm_xxx;
1755 DPRINT1(DB_MODEM, "--\n");
1758 /* must be root since the wait applies to following logins */
1759 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1764 port->close_delay = *(int *)data * hz / 100;
1767 *(int *)data = port->close_delay * 100 / hz;
1770 port->do_timestamp = 1;
1771 *(struct timeval *)data = port->timestamp;
1773 case TIOCDCDTIMESTAMP:
1774 port->do_dcd_timestamp = 1;
1775 *(struct timeval *)data = port->dcd_timestamp;
1791 struct dgm_p *port = p;
1793 wakeup(&port->draining);
1796 /* wait for the output to drain */
1799 dgmdrain(struct dgm_p *port)
1801 volatile struct board_chan *bc = port->brdchan;
1802 struct dgm_softc *sc;
1805 BoardMemWinState ws = bmws_get();
1807 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1815 while (tail != head) {
1816 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1817 port->sc->unit, port->pnum, head, tail);
1821 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1822 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1827 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1828 port->sc->unit, port->pnum, error);
1838 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1839 port->sc->unit, port->pnum, head, tail);
1844 /* wait for the output to drain */
1845 /* or simply clear the buffer it it's stopped */
1848 dgm_drain_or_flush(struct dgm_p *port)
1850 volatile struct board_chan *bc = port->brdchan;
1851 struct tty *tp = port->tty;
1852 struct dgm_softc *sc;
1857 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1865 while (tail != head /* && tail != lasttail */ ) {
1866 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1867 port->sc->unit, port->pnum, head, tail);
1869 /* if there is no carrier simply clean the buffer */
1870 if (!(tp->t_state & TS_CARR_ON)) {
1871 bc->tout = bc->tin = 0;
1879 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1880 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1885 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1886 " error = %d\n", port->sc->unit, port->pnum, error);
1888 /* silently clean the buffer */
1890 bc->tout = bc->tin = 0;
1901 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1902 port->sc->unit, port->pnum, head, tail);
1906 dgmparam(struct tty *tp, struct termios *t)
1908 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1909 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1910 volatile struct board_chan *bc;
1911 struct dgm_softc *sc;
1918 BoardMemWinState ws = bmws_get();
1920 sc = devclass_get_softc(dgmdevclass, unit);
1921 port = &sc->ports[pnum];
1924 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);
1926 if (port->mustdrain) {
1927 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1931 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1933 if (t->c_ispeed == 0)
1934 t->c_ispeed = t->c_ospeed;
1936 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1937 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1944 if (cflag == 0) { /* hangup */
1945 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1949 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1950 mval= port->omodem & ~(DTR|RTS);
1952 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1954 if (cflag != port->fepcflag) {
1955 port->fepcflag = cflag;
1956 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1957 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1958 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1960 mval= port->omodem | (DTR|RTS);
1963 iflag = dgmflags(dgm_iflags, t->c_iflag);
1964 if (iflag != port->fepiflag) {
1965 port->fepiflag = iflag;
1966 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1967 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1970 bc->mint = port->dcd;
1972 hflow = dgmflags(dgm_flow, t->c_cflag);
1973 if (hflow != port->hflow) {
1974 port->hflow = hflow;
1975 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1976 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1979 if (port->omodem != mval) {
1980 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1981 unit, pnum, mval, port->omodem);
1982 port->omodem = mval;
1983 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1986 if (port->fepstartc != t->c_cc[VSTART] ||
1987 port->fepstopc != t->c_cc[VSTOP]) {
1988 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1989 port->fepstartc = t->c_cc[VSTART];
1990 port->fepstopc = t->c_cc[VSTOP];
1991 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
2002 dgmstart(struct tty *tp)
2007 struct dgm_softc *sc;
2008 volatile struct board_chan *bc;
2013 BoardMemWinState ws = bmws_get();
2015 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2016 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2017 sc = devclass_get_softc(dgmdevclass, unit);
2018 port = &sc->ports[pnum];
2021 wmask = port->txbufsize - 1;
2025 while (tp->t_outq.c_cc != 0) {
2026 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2029 if (tp->t_outq.c_cc <= tp->t_lowat) {
2030 if (tp->t_state & TS_ASLEEP) {
2031 tp->t_state &= ~TS_ASLEEP;
2032 wakeup(TSA_OLOWAT(tp));
2034 /*selwakeup(&tp->t_wsel);*/
2040 head = bc->tin & wmask;
2042 do { tail = bc->tout; } while (tail != bc->tout);
2043 tail = bc->tout & wmask;
2045 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2047 #ifdef LEAVE_FREE_CHARS
2049 size = tail - head - LEAVE_FREE_CHARS;
2053 size = port->txbufsize - head;
2054 if (tail + port->txbufsize < head)
2060 size = tail - head - 1;
2062 size = port->txbufsize - head;
2073 tp->t_state |= TS_BUSY;
2078 towin(sc, port->txwin);
2080 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2082 if (head >= port->txbufsize)
2083 head -= port->txbufsize;
2088 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2089 unit, pnum, size, ocount);
2097 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2098 if (tp->t_state & TS_BUSY) {
2099 tp->t_state &= ~TS_BUSY;
2100 linesw[tp->t_line].l_start(tp);
2104 if (tp->t_state & TS_ASLEEP) {
2105 tp->t_state &= ~TS_ASLEEP;
2106 wakeup(TSA_OLOWAT(tp));
2108 tp->t_state& = ~TS_BUSY;
2113 dgmstop(struct tty *tp, int rw)
2118 struct dgm_softc *sc;
2119 volatile struct board_chan *bc;
2121 BoardMemWinState ws = bmws_get();
2123 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2124 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2126 sc = devclass_get_softc(dgmdevclass, unit);
2127 port = &sc->ports[pnum];
2130 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2136 /* clear output queue */
2137 bc->tout = bc->tin = 0;
2142 /* clear input queue */
2153 fepcmd(struct dgm_p *port,
2161 unsigned tail, head;
2164 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2165 mem = port->sc->vmem;
2167 if (!port->enabled) {
2168 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2169 port->sc->unit, port->pnum);
2173 /* setwin(port->sc, 0); Require this to be set by caller */
2174 head = port->sc->mailbox->cin;
2176 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2177 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2178 port->sc->unit, port->pnum, head);
2182 mem[head + FEP_CSTART] = cmd;
2183 mem[head + FEP_CSTART + 1] = port->pnum;
2185 mem[head + FEP_CSTART + 2] = op1;
2186 mem[head + FEP_CSTART + 3] = op2;
2188 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2189 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2192 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2193 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2195 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2196 port->sc->mailbox->cin = head;
2200 while (count-- != 0) {
2201 head = port->sc->mailbox->cin;
2202 tail = port->sc->mailbox->cout;
2204 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2205 if (n <= ncmds * (sizeof(ushort)*4))
2208 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2212 disc_optim(struct tty *tp, struct termios *t)
2214 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2215 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2216 && (!(t->c_iflag & PARMRK)
2217 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2218 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2219 && linesw[tp->t_line].l_rint == ttyinput)
2220 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2222 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;