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
256 dgmmodhandler(module_t mod, int event, void *arg)
270 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
272 static speed_t dgmdefaultrate = TTYDEF_SPEED;
274 static struct speedtab dgmspeedtab[] = {
275 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
289 { 19200, FEP_B19200 },
290 { 38400, FEP_B38400 },
291 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
292 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
296 static struct dbgflagtbl {
301 { PARODD, PARODD, FEP_PARODD },
302 { PARENB, PARENB, FEP_PARENB },
303 { CSTOPB, CSTOPB, FEP_CSTOPB },
304 { CSIZE, CS5, FEP_CS6 },
305 { CSIZE, CS6, FEP_CS6 },
306 { CSIZE, CS7, FEP_CS7 },
307 { CSIZE, CS8, FEP_CS8 },
308 { CLOCAL, CLOCAL, FEP_CLOCAL },
311 { IGNBRK, IGNBRK, FEP_IGNBRK },
312 { BRKINT, BRKINT, FEP_BRKINT },
313 { IGNPAR, IGNPAR, FEP_IGNPAR },
314 { PARMRK, PARMRK, FEP_PARMRK },
315 { INPCK, INPCK, FEP_INPCK },
316 { ISTRIP, ISTRIP, FEP_ISTRIP },
317 { IXON, IXON, FEP_IXON },
318 { IXOFF, IXOFF, FEP_IXOFF },
319 { IXANY, IXANY, FEP_IXANY },
322 { CRTSCTS, CRTSCTS, CTS|RTS },
323 { CRTSCTS, CCTS_OFLOW, CTS },
324 { CRTSCTS, CRTS_IFLOW, RTS },
328 /* xlat bsd termios flags to dgm sys-v style */
330 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
335 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
336 if ((input & tbl[i].in_mask) == tbl[i].in_val)
337 output |= tbl[i].out_val;
342 static int dgmdebug = 0;
343 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
345 static __inline int setwin(struct dgm_softc *, unsigned);
346 static __inline void hidewin(struct dgm_softc *);
347 static __inline void towin(struct dgm_softc *, int);
349 /*Helg: to allow recursive dgm...() calls */
351 /* If we were called and don't want to disturb we need: */
352 int port; /* write to this port */
353 u_char data; /* this data on exit */
354 /* or DATA_WINOFF to close memory window on entry */
355 } BoardMemWinState; /* so several channels and even boards can coexist */
357 #define DATA_WINOFF 0
358 static BoardMemWinState bmws;
360 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
361 static u_long validmem[] = {
362 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
363 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
364 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
365 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
366 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
369 /* return current memory window state and close window */
370 static BoardMemWinState
373 BoardMemWinState bmwsRet = bmws;
375 if (bmws.data != DATA_WINOFF)
376 outb(bmws.port, bmws.data = DATA_WINOFF);
380 /* restore memory window state */
382 bmws_set(BoardMemWinState ws)
384 if (ws.data != bmws.data || ws.port != bmws.port) {
385 if (bmws.data != DATA_WINOFF)
386 outb(bmws.port, DATA_WINOFF);
387 if (ws.data != DATA_WINOFF)
388 outb(ws.port, ws.data);
394 setwin(struct dgm_softc *sc, unsigned int addr)
396 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
397 return (addr & 0x7FFF);
401 hidewin(struct dgm_softc *sc)
404 outb(bmws.port = sc->port + 1, bmws.data);
408 towin(struct dgm_softc *sc, int win)
410 outb(bmws.port = sc->port + 1, bmws.data = win);
414 dgmprobe(device_t dev)
416 struct dgm_softc *sc = device_get_softc(dev);
420 * Assign unit number. Due to bits we use in the minor number for
421 * the various tty types, only 4 units are supported.
423 sc->unit = device_get_unit(dev);
425 device_printf(dev, "Too many units, only 4 supported\n");
429 /* Check that we've got a valid i/o address */
430 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
432 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
433 if (sc->port == validio[i])
436 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
440 /* Ditto for our memory address */
441 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
443 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
444 if (sc->pmem == validmem[i])
447 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
450 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
451 device_printf(dev, "0x%lx: Memory address not supported\n",
455 sc->vmem = (u_char *)sc->pmem;
457 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
460 /* Temporarily map our io ports */
462 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
463 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
464 if (sc->io_res == NULL)
467 outb(sc->port, FEPRST);
470 for (i = 0; i < 1000; i++) {
472 if ((inb(sc->port) & FEPMASK) == FEPRST) {
474 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
481 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
482 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
486 /* check type of card and get internal memory characteristics */
494 second = inb(sc->port);
495 kprintf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
497 kprintf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
500 sc->mem_seg = 0x8000;
502 /* Temporarily map our memory too */
504 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
505 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
506 if (sc->mem_res == NULL) {
507 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
508 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
512 outb(sc->port, FEPCLR); /* drop RESET */
513 hidewin(sc); /* Helg: to set initial bmws state */
515 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
516 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
518 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
519 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
521 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
527 dgmattach(device_t dev)
529 struct dgm_softc *sc = device_get_softc(dev);
535 volatile struct board_chan *bc;
538 u_long msize, iosize;
540 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
542 callout_init(&sc->toh);
543 sc->unit = device_get_unit(dev);
544 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
545 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
546 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
548 sc->mem_seg = 0x8000;
551 sc->mem_seg = 0x8000;
553 /* Allocate resources (should have been verified in dgmprobe()) */
555 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
556 0ul, ~0ul, iosize, RF_ACTIVE);
557 if (sc->io_res == NULL)
560 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
561 0ul, ~0ul, msize, RF_ACTIVE);
562 if (sc->mem_res == NULL) {
563 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
564 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
569 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
572 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
575 outb(sc->port, FEPRST);
578 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
580 device_printf(dev, "1st reset failed\n");
583 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
584 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
590 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
592 t = sc->pmem >> 8; /* disable windowing */
593 outb(sc->port + 2, t & 0xFF);
594 outb(sc->port + 3, t >> 8);
598 /* very short memory test */
599 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
601 addr = setwin(sc, BOTWIN);
602 *(u_long *)(mem + addr) = 0xA55A3CC3;
603 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
604 device_printf(dev, "1st memory test failed\n");
607 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
608 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
612 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
614 addr = setwin(sc, TOPWIN);
615 *(u_long *)(mem + addr) = 0x5AA5C33C;
616 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
617 device_printf(dev, "2nd memory test failed\n");
620 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
621 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
625 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
627 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
628 *(u_long *)(mem + addr) = 0x5AA5C33C;
629 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
630 device_printf(dev, "3rd (BIOS) memory test failed\n");
632 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
634 addr = setwin(sc, MISCGLOBAL);
635 for (i = 0; i < 16; i++)
638 addr = setwin(sc, BIOSOFFSET);
640 for (i = 0; ptr < mem + msize; i++)
641 *ptr++ = pcem_bios[i];
643 ptr = mem + BIOSOFFSET;
644 for (i = 0; ptr < mem + msize; i++) {
645 if (*ptr++ != pcem_bios[i]) {
646 kprintf("Low BIOS load failed\n");
649 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
650 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
654 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
656 addr = setwin(sc, msize);
658 for (;i < pcem_nbios; i++)
659 *ptr++ = pcem_bios[i];
662 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
663 if (*ptr++ != pcem_bios[i]) {
664 kprintf("High BIOS load failed\n");
667 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
668 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
672 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
673 device_printf(dev, "DigiBIOS loaded, initializing");
675 addr = setwin(sc, 0);
677 *(u_int *)(mem + addr) = 0x0bf00401;
678 *(u_int *)(mem + addr + 4) = 0;
679 *(ushort *)(mem + addr + 0xc00) = 0;
682 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
685 kprintf("\nBIOS initialize failed(1)\n");
688 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
689 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
694 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
695 kprintf("\nBIOS initialize failed(2)\n");
698 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
699 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
702 kprintf(", DigiBIOS running\n");
706 addr = setwin(sc, BIOSOFFSET);
708 for (i = 0; i < pcem_ncook; i++)
709 *ptr++ = pcem_cook[i];
711 ptr = mem + BIOSOFFSET;
712 for (i = 0; i < pcem_ncook; i++) {
713 if (*ptr++ != pcem_cook[i]) {
714 kprintf("FEP/OS load failed\n");
717 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
718 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
722 device_printf(dev, "FEP/OS loaded, initializing");
724 addr = setwin(sc, 0);
725 *(ushort *)(mem + addr + 0xd20) = 0;
726 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
727 *(u_int *)(mem + addr + 0xc30) = 0x3L;
730 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
733 kprintf("\nFEP/OS initialize failed(1)\n");
736 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
737 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
742 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
743 kprintf("\nFEP/OS initialize failed(2)\n");
746 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
747 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
750 kprintf(", FEP/OS running\n");
752 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
753 device_printf(dev, "%d ports attached\n", sc->numports);
755 if (sc->numports > MAX_DGM_PORTS) {
756 kprintf("dgm%d: too many ports\n", sc->unit);
759 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
760 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
764 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
765 M_TTYS, M_WAITOK|M_ZERO);
766 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
767 M_TTYS, M_WAITOK|M_ZERO);
769 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
770 for (i = 0; i < sc->numports; i++) {
771 sc->ports[i].enabled = 1;
772 callout_init(&sc->ports[i].hc_timeout);
773 callout_init(&sc->ports[i].wf_timeout);
776 /* We should now init per-port structures */
778 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
779 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
781 if (sc->numports < 3)
786 dev_ops_add(&dgm_ops, DGM_UNITMASK, DGM_UNIT(sc->unit));
787 for (i = 0; i < sc->numports; i++, bc++) {
788 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
789 port = &sc->ports[i];
792 port->tty = &sc->ttys[i];
800 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
802 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
803 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
807 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
808 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
809 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
810 port->txwin = FEPWIN | (bc->tseg >> 11);
811 port->rxwin = FEPWIN | (bc->rseg >> 11);
815 port->txbufsize = bc->tmax + 1;
816 port->rxbufsize = bc->rmax + 1;
818 lowwater = (port->txbufsize >= 2000) ?
819 1024 : (port->txbufsize / 2);
822 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
823 sc->unit, i, lowwater);
824 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
825 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
826 sc->unit, i, port->rxbufsize / 4);
827 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
828 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
829 sc->unit, i, 3 * port->rxbufsize / 4);
830 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
835 port->startc = bc->startc;
836 port->startca = bc->startca;
837 port->stopc = bc->stopc;
838 port->stopca = bc->stopca;
840 /* port->close_delay = 50; */
841 port->close_delay = 3 * hz;
842 port->do_timestamp = 0;
843 port->do_dcd_timestamp = 0;
845 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
847 * We don't use all the flags from <sys/ttydefaults.h> since
848 * they are only relevant for logins. It's important to have
849 * echo off initially so that the line doesn't start
850 * blathering before the echo flag can be turned off.
852 port->it_in.c_iflag = TTYDEF_IFLAG;
853 port->it_in.c_oflag = TTYDEF_OFLAG;
854 port->it_in.c_cflag = TTYDEF_CFLAG;
855 port->it_in.c_lflag = TTYDEF_LFLAG;
856 termioschars(&port->it_in);
857 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
858 port->it_out = port->it_in;
860 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
861 make_dev(&dgm_ops, (sc->unit*65536) + i, UID_ROOT,
862 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
863 make_dev(&dgm_ops, sc->unit * 65536 + i + 64, UID_ROOT,
864 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
865 make_dev(&dgm_ops, sc->unit * 65536 + i + 128, UID_ROOT,
866 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
867 make_dev(&dgm_ops, sc->unit * 65536 + i + 262144, UID_UUCP,
868 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
869 make_dev(&dgm_ops, sc->unit * 65536 + i + 262208, UID_UUCP,
870 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
871 make_dev(&dgm_ops, sc->unit * 65536 + i + 262272, UID_UUCP,
872 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
875 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
879 /* start the polling function */
880 callout_reset(&sc->toh, hz / POLLSPERSEC,
881 dgmpoll, (void *)(int)sc->unit);
883 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
889 dgmdetach(device_t dev)
891 struct dgm_softc *sc = device_get_softc(dev);
894 for (i = 0; i < sc->numports; i++)
895 if (sc->ttys[i].t_state & TS_ISOPEN)
898 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
901 * The dev_ops_remove() call will destroy all associated devices
902 * and dereference any ad-hoc-created devices, but does not
903 * dereference devices created via make_dev().
905 dev_ops_remove(&dgm_ops, DGM_UNITMASK, DGM_UNIT(sc->unit));
907 callout_stop(&sc->toh);
909 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
910 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
912 FREE(sc->ports, M_TTYS);
913 FREE(sc->ttys, M_TTYS);
916 pmap_unmapdev(sc->vmem, sc->msize);
924 dgmshutdown(device_t dev)
927 struct dgm_softc *sc = device_get_softc(dev);
929 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
937 dgmopen(struct dev_open_args *ap)
939 cdev_t dev = ap->a_head.a_dev;
940 struct dgm_softc *sc;
947 volatile struct board_chan *bc;
951 unit = MINOR_TO_UNIT(mynor);
952 pnum = MINOR_TO_PORT(mynor);
954 sc = devclass_get_softc(dgmdevclass, unit);
956 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
961 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
964 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
969 if (pnum >= sc->numports) {
970 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
975 if (mynor & CONTROL_MASK)
978 tp = &sc->ttys[pnum];
980 port = &sc->ports[pnum];
986 while (port->closing) {
987 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
990 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
991 " error = %d\n", unit, pnum, error);
996 if (tp->t_state & TS_ISOPEN) {
998 * The device is open, so everything has been initialized.
1001 if (mynor & CALLOUT_MASK) {
1002 if (!port->active_out) {
1004 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1005 " BUSY error = %d\n", unit, pnum, error);
1008 } else if (port->active_out) {
1009 if (ap->a_oflags & O_NONBLOCK) {
1011 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1012 " BUSY error = %d\n", unit, pnum, error);
1015 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1017 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1018 " error = %d\n", unit, pnum, error);
1024 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
1030 * The device isn't open, so there are no conflicts.
1031 * Initialize it. Initialization is done twice in many
1032 * cases: to preempt sleeping callin opens if we are
1033 * callout, and to complete a callin open after DCD rises.
1035 tp->t_oproc = dgmstart;
1036 tp->t_param = dgmparam;
1037 tp->t_stop = dgmstop;
1039 tp->t_termios= (mynor & CALLOUT_MASK) ?
1045 port->imodem = bc->mstat;
1046 bc->rout = bc->rin; /* clear input queue */
1048 #ifdef PRINT_BUFSIZE
1049 kprintf("dgm buffers tx = %x:%x rx = %x:%x\n",
1050 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1057 error = dgmparam(tp, &tp->t_termios);
1061 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1066 /* handle fake DCD for callout devices */
1067 /* and initial DCD */
1069 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1070 linesw[tp->t_line].l_modem(tp, 1);
1074 * Wait for DCD if necessary.
1076 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1077 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1079 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1082 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1083 " error = %d\n", unit, pnum, error);
1089 error = linesw[tp->t_line].l_open(dev, tp);
1090 disc_optim(tp, &tp->t_termios);
1091 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1094 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1095 port->active_out = 1;
1099 /* If any port is open (i.e. the open() call is completed for it)
1100 * the device is busy
1104 disc_optim(tp, &tp->t_termios);
1107 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1110 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1118 dgmclose(struct dev_close_args *ap)
1120 cdev_t dev = ap->a_head.a_dev;
1124 struct dgm_softc *sc;
1129 if (mynor & CONTROL_MASK)
1131 unit = MINOR_TO_UNIT(mynor);
1132 pnum = MINOR_TO_PORT(mynor);
1134 sc = devclass_get_softc(dgmdevclass, unit);
1135 tp = &sc->ttys[pnum];
1136 port = sc->ports + pnum;
1138 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1140 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1141 dgm_drain_or_flush(port);
1146 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1147 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1148 disc_optim(tp, &tp->t_termios);
1150 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1152 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1155 wakeup(&port->closing);
1158 /* mark the card idle when all ports are closed */
1160 for (i = 0; i < sc->numports; i++)
1161 if (sc->ports[i].used)
1166 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1168 wakeup(TSA_CARR_ON(tp));
1169 wakeup(&port->active_out);
1170 port->active_out = 0;
1172 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1178 dgmhardclose(struct dgm_p *port)
1180 volatile struct board_chan *bc = port->brdchan;
1181 struct dgm_softc *sc;
1183 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1184 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1186 port->do_timestamp = 0;
1192 if (port->tty->t_cflag & HUPCL) {
1193 port->omodem &= ~(RTS|DTR);
1194 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1200 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1201 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1205 dgm_pause(void *chan)
1207 wakeup((caddr_t)chan);
1211 dgmpoll(void *unit_c)
1213 int unit = (int)unit_c;
1216 struct dgm_softc *sc;
1219 int event, mstat, lstat;
1220 volatile struct board_chan *bc;
1227 int ibuf_full, obuf_full;
1228 BoardMemWinState ws = bmws_get();
1230 sc = devclass_get_softc(dgmdevclass, unit);
1231 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1234 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1240 head = sc->mailbox->ein;
1241 tail = sc->mailbox->eout;
1243 while (head != tail) {
1244 if (head >= FEP_IMAX - FEP_ISTART
1245 || tail >= FEP_IMAX - FEP_ISTART
1246 || (head|tail) & 03 ) {
1247 kprintf("dgm%d: event queue's head or tail is wrong!"
1248 " hd = %d, tl = %d\n", unit, head, tail);
1252 eventbuf = sc->vmem + tail + FEP_ISTART;
1254 event = eventbuf[1];
1255 mstat = eventbuf[2];
1256 lstat = eventbuf[3];
1258 port = &sc->ports[pnum];
1260 tp = &sc->ttys[pnum];
1262 if (pnum >= sc->numports || !port->enabled) {
1263 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1265 } else if (port->used || port->wopeners > 0 ) {
1267 int wrapmask = port->rxbufsize - 1;
1269 if (!(event & ALL_IND))
1270 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1271 unit, pnum, event, mstat, lstat);
1273 if (event & DATA_IND) {
1274 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1277 rhead = bc->rin & wrapmask;
1278 rtail = bc->rout & wrapmask;
1280 if (!(tp->t_cflag & CREAD) || !port->used ) {
1286 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1290 if (!(tp->t_state & TS_ISOPEN))
1293 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1294 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1295 " p rx head = %d tail = %d\n", unit,
1296 pnum, rhead, rtail);
1299 size = rhead - rtail;
1301 size = port->rxbufsize - rtail;
1303 ptr = port->rxptr + rtail;
1306 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1307 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1308 DPRINT1(DB_RXDATA, "*");
1313 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1314 DPRINT1(DB_RXDATA, "!");
1315 towin(sc, port->rxwin);
1318 tp->t_rawcc += size;
1326 towin(sc, port->rxwin);
1329 (*linesw[tp->t_line].l_rint)(chr, tp);
1334 rtail= (rtail + size) & wrapmask;
1336 rhead = bc->rin & wrapmask;
1344 if (event & MODEMCHG_IND) {
1345 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1346 "MODEMCHG_IND\n", unit, pnum);
1347 port->imodem = mstat;
1348 if (mstat & port->dcd) {
1350 linesw[tp->t_line].l_modem(tp, 1);
1352 wakeup(TSA_CARR_ON(tp));
1355 linesw[tp->t_line].l_modem(tp, 0);
1357 if (port->draining) {
1359 wakeup(&port->draining);
1364 if (event & BREAK_IND) {
1365 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1366 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1367 " BREAK_IND\n", unit, pnum);
1369 linesw[tp->t_line].l_rint(TTY_BI, tp);
1374 /* Helg: with output flow control */
1376 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1377 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1378 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1380 if ((event & EMPTYTX_IND ) &&
1381 tp->t_outq.c_cc == 0 && port->draining) {
1383 wakeup(&port->draining);
1388 int wrapmask = port->txbufsize - 1;
1390 for (obuf_full = FALSE;
1391 tp->t_outq.c_cc != 0 && !obuf_full;
1393 /* add "last-minute" data to write buffer */
1394 if (!(tp->t_state & TS_BUSY)) {
1396 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1399 if (tp->t_outq.c_cc <= tp->t_lowat) {
1400 if (tp->t_state & TS_ASLEEP) {
1401 tp->t_state &= ~TS_ASLEEP;
1402 wakeup(TSA_OLOWAT(tp));
1404 /* selwakeup(&tp->t_wsel); */
1411 whead = bc->tin & wrapmask;
1412 wtail = bc->tout & wrapmask;
1415 size = wtail - whead - 1;
1417 size = port->txbufsize - whead;
1423 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1424 whead, wtail, size, obuf_full);
1432 towin(sc, port->txwin);
1434 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1439 bc->tin = whead & wrapmask;
1444 DPRINT1(DB_WR, " +BUSY\n");
1445 tp->t_state |= TS_BUSY;
1447 DPRINT1(DB_WR, " -BUSY\n");
1449 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1450 /* should clear TS_BUSY before ttwwakeup */
1451 if (tp->t_state & TS_BUSY) {
1452 tp->t_state &= ~TS_BUSY;
1453 linesw[tp->t_line].l_start(tp);
1457 if (tp->t_state & TS_ASLEEP) {
1458 tp->t_state &= ~TS_ASLEEP;
1459 wakeup(TSA_OLOWAT(tp));
1461 tp->t_state &= ~TS_BUSY;
1467 bc->idata = 1; /* require event on incoming data */
1471 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1474 bc->idata = bc->iempty = bc->ilow = 0;
1477 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1480 sc->mailbox->eout = tail;
1483 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1485 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1489 dgmioctl(struct dev_ioctl_args *ap)
1491 cdev_t dev = ap->a_head.a_dev;
1492 u_long cmd = ap->a_cmd;
1493 caddr_t data = ap->a_data;
1494 struct dgm_softc *sc;
1499 volatile struct board_chan *bc;
1503 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1505 struct termios term;
1508 BoardMemWinState ws = bmws_get();
1511 unit = MINOR_TO_UNIT(mynor);
1512 pnum = MINOR_TO_PORT(mynor);
1514 sc = devclass_get_softc(dgmdevclass, unit);
1515 port = &sc->ports[pnum];
1516 tp = &sc->ttys[pnum];
1519 if (mynor & CONTROL_MASK) {
1522 switch (mynor & CONTROL_MASK) {
1523 case CONTROL_INIT_STATE:
1524 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1526 case CONTROL_LOCK_STATE:
1527 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1530 return (ENODEV); /* /dev/nodev */
1534 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1537 *ct = *(struct termios *)data;
1540 *(struct termios *)data = *ct;
1543 *(int *)data = TTYDISC;
1546 bzero(data, sizeof(struct winsize));
1553 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1554 term = tp->t_termios;
1555 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1556 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-ISNOW c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, term.c_cflag, term.c_iflag, term.c_lflag);
1559 error = ttsetcompat(tp, &cmd, data, &term);
1563 data = (caddr_t)&term;
1566 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1568 struct termios *dt = (struct termios *)data;
1569 struct termios *lt = mynor & CALLOUT_MASK
1570 ? &port->lt_out : &port->lt_in;
1572 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-TOSET c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, dt->c_cflag, dt->c_iflag, dt->c_lflag);
1573 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1574 | (dt->c_iflag & ~lt->c_iflag);
1575 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1576 | (dt->c_oflag & ~lt->c_oflag);
1577 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1578 | (dt->c_cflag & ~lt->c_cflag);
1579 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1580 | (dt->c_lflag & ~lt->c_lflag);
1581 for (cc = 0; cc < NCCS; ++cc)
1582 if (lt->c_cc[cc] != 0)
1583 dt->c_cc[cc] = tp->t_cc[cc];
1584 if (lt->c_ispeed != 0)
1585 dt->c_ispeed = tp->t_ispeed;
1586 if (lt->c_ospeed != 0)
1587 dt->c_ospeed = tp->t_ospeed;
1590 if (cmd == TIOCSTOP) {
1593 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1597 } else if (cmd == TIOCSTART) {
1600 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1606 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1607 port->mustdrain = 1;
1609 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1610 ap->a_fflag, ap->a_cred);
1611 if (error != ENOIOCTL)
1614 error = ttioctl(tp, cmd, data, ap->a_fflag);
1615 disc_optim(tp, &tp->t_termios);
1616 port->mustdrain = 0;
1617 if (error != ENOIOCTL) {
1619 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1620 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-RES c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, tp->t_cflag, tp->t_iflag, tp->t_lflag);
1628 error = dgmdrain(port);
1639 /* now it sends 400 millisecond break because I don't know */
1640 /* how to send an infinite break */
1642 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1647 /* now it's empty */
1650 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1651 port->omodem |= DTR;
1654 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1656 if (!(bc->mstat & DTR))
1657 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1663 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1664 port->omodem &= ~DTR;
1667 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1669 if (bc->mstat & DTR) {
1670 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1677 if (*(int *)data & TIOCM_DTR)
1678 port->omodem |= DTR;
1680 port->omodem &= ~DTR;
1682 if (*(int *)data & TIOCM_RTS)
1683 port->omodem |= RTS;
1685 port->omodem &= ~RTS;
1689 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1694 if (*(int *)data & TIOCM_DTR)
1695 port->omodem |= DTR;
1697 if (*(int *)data & TIOCM_RTS)
1698 port->omodem |= RTS;
1702 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1707 if (*(int *)data & TIOCM_DTR)
1708 port->omodem &= ~DTR;
1710 if (*(int *)data & TIOCM_RTS)
1711 port->omodem &= ~RTS;
1715 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1721 port->imodem = bc->mstat;
1724 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1726 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1728 if (port->imodem & DTR) {
1729 DPRINT1(DB_MODEM, "DTR ");
1730 tiocm_xxx |= TIOCM_DTR;
1732 if (port->imodem & RTS) {
1733 DPRINT1(DB_MODEM, "RTS ");
1734 tiocm_xxx |= TIOCM_RTS;
1736 if (port->imodem & CTS) {
1737 DPRINT1(DB_MODEM, "CTS ");
1738 tiocm_xxx |= TIOCM_CTS;
1740 if (port->imodem & port->dcd) {
1741 DPRINT1(DB_MODEM, "DCD ");
1742 tiocm_xxx |= TIOCM_CD;
1744 if (port->imodem & port->dsr) {
1745 DPRINT1(DB_MODEM, "DSR ");
1746 tiocm_xxx |= TIOCM_DSR;
1748 if (port->imodem & RI) {
1749 DPRINT1(DB_MODEM, "RI ");
1750 tiocm_xxx |= TIOCM_RI;
1752 *(int *)data = tiocm_xxx;
1753 DPRINT1(DB_MODEM, "--\n");
1756 /* must be root since the wait applies to following logins */
1757 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1762 port->close_delay = *(int *)data * hz / 100;
1765 *(int *)data = port->close_delay * 100 / hz;
1768 port->do_timestamp = 1;
1769 *(struct timeval *)data = port->timestamp;
1771 case TIOCDCDTIMESTAMP:
1772 port->do_dcd_timestamp = 1;
1773 *(struct timeval *)data = port->dcd_timestamp;
1789 struct dgm_p *port = p;
1791 wakeup(&port->draining);
1794 /* wait for the output to drain */
1797 dgmdrain(struct dgm_p *port)
1799 volatile struct board_chan *bc = port->brdchan;
1800 struct dgm_softc *sc;
1803 BoardMemWinState ws = bmws_get();
1805 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1813 while (tail != head) {
1814 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1815 port->sc->unit, port->pnum, head, tail);
1819 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1820 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1825 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1826 port->sc->unit, port->pnum, error);
1836 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1837 port->sc->unit, port->pnum, head, tail);
1842 /* wait for the output to drain */
1843 /* or simply clear the buffer it it's stopped */
1846 dgm_drain_or_flush(struct dgm_p *port)
1848 volatile struct board_chan *bc = port->brdchan;
1849 struct tty *tp = port->tty;
1850 struct dgm_softc *sc;
1855 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1863 while (tail != head /* && tail != lasttail */ ) {
1864 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1865 port->sc->unit, port->pnum, head, tail);
1867 /* if there is no carrier simply clean the buffer */
1868 if (!(tp->t_state & TS_CARR_ON)) {
1869 bc->tout = bc->tin = 0;
1877 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1878 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1883 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1884 " error = %d\n", port->sc->unit, port->pnum, error);
1886 /* silently clean the buffer */
1888 bc->tout = bc->tin = 0;
1899 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1900 port->sc->unit, port->pnum, head, tail);
1904 dgmparam(struct tty *tp, struct termios *t)
1906 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1907 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1908 volatile struct board_chan *bc;
1909 struct dgm_softc *sc;
1916 BoardMemWinState ws = bmws_get();
1918 sc = devclass_get_softc(dgmdevclass, unit);
1919 port = &sc->ports[pnum];
1922 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmparm c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, t->c_cflag, t->c_iflag, t->c_lflag);
1924 if (port->mustdrain) {
1925 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1929 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1931 if (t->c_ispeed == 0)
1932 t->c_ispeed = t->c_ospeed;
1934 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1935 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1942 if (cflag == 0) { /* hangup */
1943 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1947 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1948 mval= port->omodem & ~(DTR|RTS);
1950 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1952 if (cflag != port->fepcflag) {
1953 port->fepcflag = cflag;
1954 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1955 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1956 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1958 mval= port->omodem | (DTR|RTS);
1961 iflag = dgmflags(dgm_iflags, t->c_iflag);
1962 if (iflag != port->fepiflag) {
1963 port->fepiflag = iflag;
1964 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1965 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1968 bc->mint = port->dcd;
1970 hflow = dgmflags(dgm_flow, t->c_cflag);
1971 if (hflow != port->hflow) {
1972 port->hflow = hflow;
1973 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1974 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1977 if (port->omodem != mval) {
1978 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1979 unit, pnum, mval, port->omodem);
1980 port->omodem = mval;
1981 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1984 if (port->fepstartc != t->c_cc[VSTART] ||
1985 port->fepstopc != t->c_cc[VSTOP]) {
1986 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1987 port->fepstartc = t->c_cc[VSTART];
1988 port->fepstopc = t->c_cc[VSTOP];
1989 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
2000 dgmstart(struct tty *tp)
2005 struct dgm_softc *sc;
2006 volatile struct board_chan *bc;
2011 BoardMemWinState ws = bmws_get();
2013 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2014 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2015 sc = devclass_get_softc(dgmdevclass, unit);
2016 port = &sc->ports[pnum];
2019 wmask = port->txbufsize - 1;
2023 while (tp->t_outq.c_cc != 0) {
2024 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2027 if (tp->t_outq.c_cc <= tp->t_lowat) {
2028 if (tp->t_state & TS_ASLEEP) {
2029 tp->t_state &= ~TS_ASLEEP;
2030 wakeup(TSA_OLOWAT(tp));
2032 /*selwakeup(&tp->t_wsel);*/
2038 head = bc->tin & wmask;
2040 do { tail = bc->tout; } while (tail != bc->tout);
2041 tail = bc->tout & wmask;
2043 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2045 #ifdef LEAVE_FREE_CHARS
2047 size = tail - head - LEAVE_FREE_CHARS;
2051 size = port->txbufsize - head;
2052 if (tail + port->txbufsize < head)
2058 size = tail - head - 1;
2060 size = port->txbufsize - head;
2071 tp->t_state |= TS_BUSY;
2076 towin(sc, port->txwin);
2078 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2080 if (head >= port->txbufsize)
2081 head -= port->txbufsize;
2086 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2087 unit, pnum, size, ocount);
2095 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2096 if (tp->t_state & TS_BUSY) {
2097 tp->t_state &= ~TS_BUSY;
2098 linesw[tp->t_line].l_start(tp);
2102 if (tp->t_state & TS_ASLEEP) {
2103 tp->t_state &= ~TS_ASLEEP;
2104 wakeup(TSA_OLOWAT(tp));
2106 tp->t_state& = ~TS_BUSY;
2111 dgmstop(struct tty *tp, int rw)
2116 struct dgm_softc *sc;
2117 volatile struct board_chan *bc;
2119 BoardMemWinState ws = bmws_get();
2121 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2122 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2124 sc = devclass_get_softc(dgmdevclass, unit);
2125 port = &sc->ports[pnum];
2128 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2134 /* clear output queue */
2135 bc->tout = bc->tin = 0;
2140 /* clear input queue */
2151 fepcmd(struct dgm_p *port,
2159 unsigned tail, head;
2162 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2163 mem = port->sc->vmem;
2165 if (!port->enabled) {
2166 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2167 port->sc->unit, port->pnum);
2171 /* setwin(port->sc, 0); Require this to be set by caller */
2172 head = port->sc->mailbox->cin;
2174 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2175 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2176 port->sc->unit, port->pnum, head);
2180 mem[head + FEP_CSTART] = cmd;
2181 mem[head + FEP_CSTART + 1] = port->pnum;
2183 mem[head + FEP_CSTART + 2] = op1;
2184 mem[head + FEP_CSTART + 3] = op2;
2186 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2187 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2190 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2191 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2193 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2194 port->sc->mailbox->cin = head;
2198 while (count-- != 0) {
2199 head = port->sc->mailbox->cin;
2200 tail = port->sc->mailbox->cout;
2202 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2203 if (n <= ncmds * (sizeof(ushort)*4))
2206 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2210 disc_optim(struct tty *tp, struct termios *t)
2212 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2213 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2214 && (!(t->c_iflag & PARMRK)
2215 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2216 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2217 && linesw[tp->t_line].l_rint == ttyinput)
2218 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2220 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;