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 kprintf("devfs: Please check that only the right dgm devices were removed!!!!\n");
906 dev_ops_remove_minor(&dgm_ops/*, DGM_UNITMASK*/, DGM_UNIT(sc->unit));
908 callout_stop(&sc->toh);
910 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
911 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
913 FREE(sc->ports, M_TTYS);
914 FREE(sc->ttys, M_TTYS);
917 pmap_unmapdev((vm_offset_t)sc->vmem, sc->msize);
925 dgmshutdown(device_t dev)
928 struct dgm_softc *sc = device_get_softc(dev);
930 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
938 dgmopen(struct dev_open_args *ap)
940 cdev_t dev = ap->a_head.a_dev;
941 struct dgm_softc *sc;
948 volatile struct board_chan *bc;
952 unit = MINOR_TO_UNIT(mynor);
953 pnum = MINOR_TO_PORT(mynor);
955 sc = devclass_get_softc(dgmdevclass, unit);
957 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
962 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
965 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
970 if (pnum >= sc->numports) {
971 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
976 if (mynor & CONTROL_MASK)
979 tp = &sc->ttys[pnum];
981 port = &sc->ports[pnum];
987 while (port->closing) {
988 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
991 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
992 " error = %d\n", unit, pnum, error);
997 if (tp->t_state & TS_ISOPEN) {
999 * The device is open, so everything has been initialized.
1002 if (mynor & CALLOUT_MASK) {
1003 if (!port->active_out) {
1005 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1006 " BUSY error = %d\n", unit, pnum, error);
1009 } else if (port->active_out) {
1010 if (ap->a_oflags & O_NONBLOCK) {
1012 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1013 " BUSY error = %d\n", unit, pnum, error);
1016 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1018 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1019 " error = %d\n", unit, pnum, error);
1025 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
1031 * The device isn't open, so there are no conflicts.
1032 * Initialize it. Initialization is done twice in many
1033 * cases: to preempt sleeping callin opens if we are
1034 * callout, and to complete a callin open after DCD rises.
1036 tp->t_oproc = dgmstart;
1037 tp->t_param = dgmparam;
1038 tp->t_stop = dgmstop;
1040 tp->t_termios= (mynor & CALLOUT_MASK) ?
1046 port->imodem = bc->mstat;
1047 bc->rout = bc->rin; /* clear input queue */
1049 #ifdef PRINT_BUFSIZE
1050 kprintf("dgm buffers tx = %x:%x rx = %x:%x\n",
1051 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1058 error = dgmparam(tp, &tp->t_termios);
1062 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1067 /* handle fake DCD for callout devices */
1068 /* and initial DCD */
1070 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1071 linesw[tp->t_line].l_modem(tp, 1);
1075 * Wait for DCD if necessary.
1077 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1078 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1080 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1083 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1084 " error = %d\n", unit, pnum, error);
1090 error = linesw[tp->t_line].l_open(dev, tp);
1091 disc_optim(tp, &tp->t_termios);
1092 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1095 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1096 port->active_out = 1;
1100 /* If any port is open (i.e. the open() call is completed for it)
1101 * the device is busy
1105 disc_optim(tp, &tp->t_termios);
1108 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1111 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1119 dgmclose(struct dev_close_args *ap)
1121 cdev_t dev = ap->a_head.a_dev;
1125 struct dgm_softc *sc;
1130 if (mynor & CONTROL_MASK)
1132 unit = MINOR_TO_UNIT(mynor);
1133 pnum = MINOR_TO_PORT(mynor);
1135 sc = devclass_get_softc(dgmdevclass, unit);
1136 tp = &sc->ttys[pnum];
1137 port = sc->ports + pnum;
1139 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1141 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1142 dgm_drain_or_flush(port);
1147 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1148 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1149 disc_optim(tp, &tp->t_termios);
1151 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1153 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1156 wakeup(&port->closing);
1159 /* mark the card idle when all ports are closed */
1161 for (i = 0; i < sc->numports; i++)
1162 if (sc->ports[i].used)
1167 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1169 wakeup(TSA_CARR_ON(tp));
1170 wakeup(&port->active_out);
1171 port->active_out = 0;
1173 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1179 dgmhardclose(struct dgm_p *port)
1181 volatile struct board_chan *bc = port->brdchan;
1182 struct dgm_softc *sc;
1184 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1185 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1187 port->do_timestamp = 0;
1193 if (port->tty->t_cflag & HUPCL) {
1194 port->omodem &= ~(RTS|DTR);
1195 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1201 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1202 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1206 dgm_pause(void *chan)
1208 wakeup((caddr_t)chan);
1212 dgmpoll(void *unit_c)
1214 int unit = (int)unit_c;
1217 struct dgm_softc *sc;
1220 int event, mstat, lstat;
1221 volatile struct board_chan *bc;
1228 int ibuf_full, obuf_full;
1229 BoardMemWinState ws = bmws_get();
1231 sc = devclass_get_softc(dgmdevclass, unit);
1232 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1235 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1241 head = sc->mailbox->ein;
1242 tail = sc->mailbox->eout;
1244 while (head != tail) {
1245 if (head >= FEP_IMAX - FEP_ISTART
1246 || tail >= FEP_IMAX - FEP_ISTART
1247 || (head|tail) & 03 ) {
1248 kprintf("dgm%d: event queue's head or tail is wrong!"
1249 " hd = %d, tl = %d\n", unit, head, tail);
1253 eventbuf = sc->vmem + tail + FEP_ISTART;
1255 event = eventbuf[1];
1256 mstat = eventbuf[2];
1257 lstat = eventbuf[3];
1259 port = &sc->ports[pnum];
1261 tp = &sc->ttys[pnum];
1263 if (pnum >= sc->numports || !port->enabled) {
1264 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1266 } else if (port->used || port->wopeners > 0 ) {
1268 int wrapmask = port->rxbufsize - 1;
1270 if (!(event & ALL_IND))
1271 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1272 unit, pnum, event, mstat, lstat);
1274 if (event & DATA_IND) {
1275 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1278 rhead = bc->rin & wrapmask;
1279 rtail = bc->rout & wrapmask;
1281 if (!(tp->t_cflag & CREAD) || !port->used ) {
1287 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1291 if (!(tp->t_state & TS_ISOPEN))
1294 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1295 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1296 " p rx head = %d tail = %d\n", unit,
1297 pnum, rhead, rtail);
1300 size = rhead - rtail;
1302 size = port->rxbufsize - rtail;
1304 ptr = port->rxptr + rtail;
1307 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1308 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1309 DPRINT1(DB_RXDATA, "*");
1314 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1315 DPRINT1(DB_RXDATA, "!");
1316 towin(sc, port->rxwin);
1319 tp->t_rawcc += size;
1327 towin(sc, port->rxwin);
1330 (*linesw[tp->t_line].l_rint)(chr, tp);
1335 rtail= (rtail + size) & wrapmask;
1337 rhead = bc->rin & wrapmask;
1345 if (event & MODEMCHG_IND) {
1346 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1347 "MODEMCHG_IND\n", unit, pnum);
1348 port->imodem = mstat;
1349 if (mstat & port->dcd) {
1351 linesw[tp->t_line].l_modem(tp, 1);
1353 wakeup(TSA_CARR_ON(tp));
1356 linesw[tp->t_line].l_modem(tp, 0);
1358 if (port->draining) {
1360 wakeup(&port->draining);
1365 if (event & BREAK_IND) {
1366 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1367 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1368 " BREAK_IND\n", unit, pnum);
1370 linesw[tp->t_line].l_rint(TTY_BI, tp);
1375 /* Helg: with output flow control */
1377 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1378 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1379 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1381 if ((event & EMPTYTX_IND ) &&
1382 tp->t_outq.c_cc == 0 && port->draining) {
1384 wakeup(&port->draining);
1389 int wrapmask = port->txbufsize - 1;
1391 for (obuf_full = FALSE;
1392 tp->t_outq.c_cc != 0 && !obuf_full;
1394 /* add "last-minute" data to write buffer */
1395 if (!(tp->t_state & TS_BUSY)) {
1397 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1400 if (tp->t_outq.c_cc <= tp->t_lowat) {
1401 if (tp->t_state & TS_ASLEEP) {
1402 tp->t_state &= ~TS_ASLEEP;
1403 wakeup(TSA_OLOWAT(tp));
1405 /* selwakeup(&tp->t_wsel); */
1412 whead = bc->tin & wrapmask;
1413 wtail = bc->tout & wrapmask;
1416 size = wtail - whead - 1;
1418 size = port->txbufsize - whead;
1424 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1425 whead, wtail, size, obuf_full);
1433 towin(sc, port->txwin);
1435 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1440 bc->tin = whead & wrapmask;
1445 DPRINT1(DB_WR, " +BUSY\n");
1446 tp->t_state |= TS_BUSY;
1448 DPRINT1(DB_WR, " -BUSY\n");
1450 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1451 /* should clear TS_BUSY before ttwwakeup */
1452 if (tp->t_state & TS_BUSY) {
1453 tp->t_state &= ~TS_BUSY;
1454 linesw[tp->t_line].l_start(tp);
1458 if (tp->t_state & TS_ASLEEP) {
1459 tp->t_state &= ~TS_ASLEEP;
1460 wakeup(TSA_OLOWAT(tp));
1462 tp->t_state &= ~TS_BUSY;
1468 bc->idata = 1; /* require event on incoming data */
1472 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1475 bc->idata = bc->iempty = bc->ilow = 0;
1478 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1481 sc->mailbox->eout = tail;
1484 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1486 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1490 dgmioctl(struct dev_ioctl_args *ap)
1492 cdev_t dev = ap->a_head.a_dev;
1493 u_long cmd = ap->a_cmd;
1494 caddr_t data = ap->a_data;
1495 struct dgm_softc *sc;
1500 volatile struct board_chan *bc;
1504 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1506 struct termios term;
1509 BoardMemWinState ws = bmws_get();
1512 unit = MINOR_TO_UNIT(mynor);
1513 pnum = MINOR_TO_PORT(mynor);
1515 sc = devclass_get_softc(dgmdevclass, unit);
1516 port = &sc->ports[pnum];
1517 tp = &sc->ttys[pnum];
1520 if (mynor & CONTROL_MASK) {
1523 switch (mynor & CONTROL_MASK) {
1524 case CONTROL_INIT_STATE:
1525 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1527 case CONTROL_LOCK_STATE:
1528 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1531 return (ENODEV); /* /dev/nodev */
1535 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1538 *ct = *(struct termios *)data;
1541 *(struct termios *)data = *ct;
1544 *(int *)data = TTYDISC;
1547 bzero(data, sizeof(struct winsize));
1554 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1555 term = tp->t_termios;
1556 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1557 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);
1560 error = ttsetcompat(tp, &cmd, data, &term);
1564 data = (caddr_t)&term;
1567 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1569 struct termios *dt = (struct termios *)data;
1570 struct termios *lt = mynor & CALLOUT_MASK
1571 ? &port->lt_out : &port->lt_in;
1573 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);
1574 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1575 | (dt->c_iflag & ~lt->c_iflag);
1576 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1577 | (dt->c_oflag & ~lt->c_oflag);
1578 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1579 | (dt->c_cflag & ~lt->c_cflag);
1580 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1581 | (dt->c_lflag & ~lt->c_lflag);
1582 for (cc = 0; cc < NCCS; ++cc)
1583 if (lt->c_cc[cc] != 0)
1584 dt->c_cc[cc] = tp->t_cc[cc];
1585 if (lt->c_ispeed != 0)
1586 dt->c_ispeed = tp->t_ispeed;
1587 if (lt->c_ospeed != 0)
1588 dt->c_ospeed = tp->t_ospeed;
1591 if (cmd == TIOCSTOP) {
1594 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1598 } else if (cmd == TIOCSTART) {
1601 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1607 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1608 port->mustdrain = 1;
1610 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1611 ap->a_fflag, ap->a_cred);
1612 if (error != ENOIOCTL)
1615 error = ttioctl(tp, cmd, data, ap->a_fflag);
1616 disc_optim(tp, &tp->t_termios);
1617 port->mustdrain = 0;
1618 if (error != ENOIOCTL) {
1620 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1621 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);
1629 error = dgmdrain(port);
1640 /* now it sends 400 millisecond break because I don't know */
1641 /* how to send an infinite break */
1643 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1648 /* now it's empty */
1651 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1652 port->omodem |= DTR;
1655 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1657 if (!(bc->mstat & DTR))
1658 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1664 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1665 port->omodem &= ~DTR;
1668 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1670 if (bc->mstat & DTR) {
1671 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1678 if (*(int *)data & TIOCM_DTR)
1679 port->omodem |= DTR;
1681 port->omodem &= ~DTR;
1683 if (*(int *)data & TIOCM_RTS)
1684 port->omodem |= RTS;
1686 port->omodem &= ~RTS;
1690 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1695 if (*(int *)data & TIOCM_DTR)
1696 port->omodem |= DTR;
1698 if (*(int *)data & TIOCM_RTS)
1699 port->omodem |= RTS;
1703 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1708 if (*(int *)data & TIOCM_DTR)
1709 port->omodem &= ~DTR;
1711 if (*(int *)data & TIOCM_RTS)
1712 port->omodem &= ~RTS;
1716 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1722 port->imodem = bc->mstat;
1725 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1727 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1729 if (port->imodem & DTR) {
1730 DPRINT1(DB_MODEM, "DTR ");
1731 tiocm_xxx |= TIOCM_DTR;
1733 if (port->imodem & RTS) {
1734 DPRINT1(DB_MODEM, "RTS ");
1735 tiocm_xxx |= TIOCM_RTS;
1737 if (port->imodem & CTS) {
1738 DPRINT1(DB_MODEM, "CTS ");
1739 tiocm_xxx |= TIOCM_CTS;
1741 if (port->imodem & port->dcd) {
1742 DPRINT1(DB_MODEM, "DCD ");
1743 tiocm_xxx |= TIOCM_CD;
1745 if (port->imodem & port->dsr) {
1746 DPRINT1(DB_MODEM, "DSR ");
1747 tiocm_xxx |= TIOCM_DSR;
1749 if (port->imodem & RI) {
1750 DPRINT1(DB_MODEM, "RI ");
1751 tiocm_xxx |= TIOCM_RI;
1753 *(int *)data = tiocm_xxx;
1754 DPRINT1(DB_MODEM, "--\n");
1757 /* must be root since the wait applies to following logins */
1758 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1763 port->close_delay = *(int *)data * hz / 100;
1766 *(int *)data = port->close_delay * 100 / hz;
1769 port->do_timestamp = 1;
1770 *(struct timeval *)data = port->timestamp;
1772 case TIOCDCDTIMESTAMP:
1773 port->do_dcd_timestamp = 1;
1774 *(struct timeval *)data = port->dcd_timestamp;
1790 struct dgm_p *port = p;
1792 wakeup(&port->draining);
1795 /* wait for the output to drain */
1798 dgmdrain(struct dgm_p *port)
1800 volatile struct board_chan *bc = port->brdchan;
1801 struct dgm_softc *sc;
1804 BoardMemWinState ws = bmws_get();
1806 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1814 while (tail != head) {
1815 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1816 port->sc->unit, port->pnum, head, tail);
1820 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1821 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1826 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1827 port->sc->unit, port->pnum, error);
1837 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1838 port->sc->unit, port->pnum, head, tail);
1843 /* wait for the output to drain */
1844 /* or simply clear the buffer it it's stopped */
1847 dgm_drain_or_flush(struct dgm_p *port)
1849 volatile struct board_chan *bc = port->brdchan;
1850 struct tty *tp = port->tty;
1851 struct dgm_softc *sc;
1856 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1864 while (tail != head /* && tail != lasttail */ ) {
1865 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1866 port->sc->unit, port->pnum, head, tail);
1868 /* if there is no carrier simply clean the buffer */
1869 if (!(tp->t_state & TS_CARR_ON)) {
1870 bc->tout = bc->tin = 0;
1878 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1879 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1884 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1885 " error = %d\n", port->sc->unit, port->pnum, error);
1887 /* silently clean the buffer */
1889 bc->tout = bc->tin = 0;
1900 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1901 port->sc->unit, port->pnum, head, tail);
1905 dgmparam(struct tty *tp, struct termios *t)
1907 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1908 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1909 volatile struct board_chan *bc;
1910 struct dgm_softc *sc;
1917 BoardMemWinState ws = bmws_get();
1919 sc = devclass_get_softc(dgmdevclass, unit);
1920 port = &sc->ports[pnum];
1923 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);
1925 if (port->mustdrain) {
1926 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1930 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1932 if (t->c_ispeed == 0)
1933 t->c_ispeed = t->c_ospeed;
1935 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1936 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1943 if (cflag == 0) { /* hangup */
1944 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1948 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1949 mval= port->omodem & ~(DTR|RTS);
1951 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1953 if (cflag != port->fepcflag) {
1954 port->fepcflag = cflag;
1955 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1956 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1957 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1959 mval= port->omodem | (DTR|RTS);
1962 iflag = dgmflags(dgm_iflags, t->c_iflag);
1963 if (iflag != port->fepiflag) {
1964 port->fepiflag = iflag;
1965 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1966 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1969 bc->mint = port->dcd;
1971 hflow = dgmflags(dgm_flow, t->c_cflag);
1972 if (hflow != port->hflow) {
1973 port->hflow = hflow;
1974 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1975 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1978 if (port->omodem != mval) {
1979 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1980 unit, pnum, mval, port->omodem);
1981 port->omodem = mval;
1982 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1985 if (port->fepstartc != t->c_cc[VSTART] ||
1986 port->fepstopc != t->c_cc[VSTOP]) {
1987 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1988 port->fepstartc = t->c_cc[VSTART];
1989 port->fepstopc = t->c_cc[VSTOP];
1990 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
2001 dgmstart(struct tty *tp)
2006 struct dgm_softc *sc;
2007 volatile struct board_chan *bc;
2012 BoardMemWinState ws = bmws_get();
2014 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2015 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2016 sc = devclass_get_softc(dgmdevclass, unit);
2017 port = &sc->ports[pnum];
2020 wmask = port->txbufsize - 1;
2024 while (tp->t_outq.c_cc != 0) {
2025 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2028 if (tp->t_outq.c_cc <= tp->t_lowat) {
2029 if (tp->t_state & TS_ASLEEP) {
2030 tp->t_state &= ~TS_ASLEEP;
2031 wakeup(TSA_OLOWAT(tp));
2033 /*selwakeup(&tp->t_wsel);*/
2039 head = bc->tin & wmask;
2041 do { tail = bc->tout; } while (tail != bc->tout);
2042 tail = bc->tout & wmask;
2044 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2046 #ifdef LEAVE_FREE_CHARS
2048 size = tail - head - LEAVE_FREE_CHARS;
2052 size = port->txbufsize - head;
2053 if (tail + port->txbufsize < head)
2059 size = tail - head - 1;
2061 size = port->txbufsize - head;
2072 tp->t_state |= TS_BUSY;
2077 towin(sc, port->txwin);
2079 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2081 if (head >= port->txbufsize)
2082 head -= port->txbufsize;
2087 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2088 unit, pnum, size, ocount);
2096 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2097 if (tp->t_state & TS_BUSY) {
2098 tp->t_state &= ~TS_BUSY;
2099 linesw[tp->t_line].l_start(tp);
2103 if (tp->t_state & TS_ASLEEP) {
2104 tp->t_state &= ~TS_ASLEEP;
2105 wakeup(TSA_OLOWAT(tp));
2107 tp->t_state& = ~TS_BUSY;
2112 dgmstop(struct tty *tp, int rw)
2117 struct dgm_softc *sc;
2118 volatile struct board_chan *bc;
2120 BoardMemWinState ws = bmws_get();
2122 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2123 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2125 sc = devclass_get_softc(dgmdevclass, unit);
2126 port = &sc->ports[pnum];
2129 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2135 /* clear output queue */
2136 bc->tout = bc->tin = 0;
2141 /* clear input queue */
2152 fepcmd(struct dgm_p *port,
2160 unsigned tail, head;
2163 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2164 mem = port->sc->vmem;
2166 if (!port->enabled) {
2167 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2168 port->sc->unit, port->pnum);
2172 /* setwin(port->sc, 0); Require this to be set by caller */
2173 head = port->sc->mailbox->cin;
2175 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2176 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2177 port->sc->unit, port->pnum, head);
2181 mem[head + FEP_CSTART] = cmd;
2182 mem[head + FEP_CSTART + 1] = port->pnum;
2184 mem[head + FEP_CSTART + 2] = op1;
2185 mem[head + FEP_CSTART + 3] = op2;
2187 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2188 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2191 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2192 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2194 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2195 port->sc->mailbox->cin = head;
2199 while (count-- != 0) {
2200 head = port->sc->mailbox->cin;
2201 tail = port->sc->mailbox->cout;
2203 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2204 if (n <= ncmds * (sizeof(ushort)*4))
2207 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2211 disc_optim(struct tty *tp, struct termios *t)
2213 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2214 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2215 && (!(t->c_iflag & PARMRK)
2216 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2217 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2218 && linesw[tp->t_line].l_rint == ttyinput)
2219 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2221 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;