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 },
251 .d_kqfilter = ttykqfilter,
252 .d_revoke = ttyrevoke
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 for (i = 0; i < sc->numports; i++, bc++) {
787 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
788 port = &sc->ports[i];
791 port->tty = &sc->ttys[i];
799 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
801 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
802 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
806 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
807 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
808 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
809 port->txwin = FEPWIN | (bc->tseg >> 11);
810 port->rxwin = FEPWIN | (bc->rseg >> 11);
814 port->txbufsize = bc->tmax + 1;
815 port->rxbufsize = bc->rmax + 1;
817 lowwater = (port->txbufsize >= 2000) ?
818 1024 : (port->txbufsize / 2);
821 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
822 sc->unit, i, lowwater);
823 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
824 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
825 sc->unit, i, port->rxbufsize / 4);
826 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
827 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
828 sc->unit, i, 3 * port->rxbufsize / 4);
829 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
834 port->startc = bc->startc;
835 port->startca = bc->startca;
836 port->stopc = bc->stopc;
837 port->stopca = bc->stopca;
839 /* port->close_delay = 50; */
840 port->close_delay = 3 * hz;
841 port->do_timestamp = 0;
842 port->do_dcd_timestamp = 0;
844 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
846 * We don't use all the flags from <sys/ttydefaults.h> since
847 * they are only relevant for logins. It's important to have
848 * echo off initially so that the line doesn't start
849 * blathering before the echo flag can be turned off.
851 port->it_in.c_iflag = TTYDEF_IFLAG;
852 port->it_in.c_oflag = TTYDEF_OFLAG;
853 port->it_in.c_cflag = TTYDEF_CFLAG;
854 port->it_in.c_lflag = TTYDEF_LFLAG;
855 termioschars(&port->it_in);
856 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
857 port->it_out = port->it_in;
859 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
860 make_dev(&dgm_ops, (sc->unit*65536) + i, UID_ROOT,
861 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
862 make_dev(&dgm_ops, sc->unit * 65536 + i + 64, UID_ROOT,
863 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
864 make_dev(&dgm_ops, sc->unit * 65536 + i + 128, UID_ROOT,
865 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
866 make_dev(&dgm_ops, sc->unit * 65536 + i + 262144, UID_UUCP,
867 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
868 make_dev(&dgm_ops, sc->unit * 65536 + i + 262208, UID_UUCP,
869 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
870 make_dev(&dgm_ops, sc->unit * 65536 + i + 262272, UID_UUCP,
871 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
874 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
878 /* start the polling function */
879 callout_reset(&sc->toh, hz / POLLSPERSEC,
880 dgmpoll, (void *)(int)sc->unit);
882 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
888 dgmdetach(device_t dev)
890 struct dgm_softc *sc = device_get_softc(dev);
893 for (i = 0; i < sc->numports; i++)
894 if (sc->ttys[i].t_state & TS_ISOPEN)
897 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
900 * The dev_ops_remove() call will destroy all associated devices
901 * and dereference any ad-hoc-created devices, but does not
902 * dereference devices created via make_dev().
904 dev_ops_remove_minor(&dgm_ops/*, DGM_UNITMASK*/, DGM_UNIT(sc->unit));
906 callout_stop(&sc->toh);
908 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
909 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
911 FREE(sc->ports, M_TTYS);
912 FREE(sc->ttys, M_TTYS);
915 pmap_unmapdev((vm_offset_t)sc->vmem, sc->msize);
923 dgmshutdown(device_t dev)
926 struct dgm_softc *sc = device_get_softc(dev);
928 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
936 dgmopen(struct dev_open_args *ap)
938 cdev_t dev = ap->a_head.a_dev;
939 struct dgm_softc *sc;
946 volatile struct board_chan *bc;
950 unit = MINOR_TO_UNIT(mynor);
951 pnum = MINOR_TO_PORT(mynor);
953 sc = devclass_get_softc(dgmdevclass, unit);
955 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
960 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
963 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
968 if (pnum >= sc->numports) {
969 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
974 if (mynor & CONTROL_MASK)
977 tp = &sc->ttys[pnum];
979 port = &sc->ports[pnum];
985 while (port->closing) {
986 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
989 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
990 " error = %d\n", unit, pnum, error);
995 if (tp->t_state & TS_ISOPEN) {
997 * The device is open, so everything has been initialized.
1000 if (mynor & CALLOUT_MASK) {
1001 if (!port->active_out) {
1003 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1004 " BUSY error = %d\n", unit, pnum, error);
1007 } else if (port->active_out) {
1008 if (ap->a_oflags & O_NONBLOCK) {
1010 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1011 " BUSY error = %d\n", unit, pnum, error);
1014 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1016 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1017 " error = %d\n", unit, pnum, error);
1023 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
1029 * The device isn't open, so there are no conflicts.
1030 * Initialize it. Initialization is done twice in many
1031 * cases: to preempt sleeping callin opens if we are
1032 * callout, and to complete a callin open after DCD rises.
1034 tp->t_oproc = dgmstart;
1035 tp->t_param = dgmparam;
1036 tp->t_stop = dgmstop;
1038 tp->t_termios= (mynor & CALLOUT_MASK) ?
1044 port->imodem = bc->mstat;
1045 bc->rout = bc->rin; /* clear input queue */
1047 #ifdef PRINT_BUFSIZE
1048 kprintf("dgm buffers tx = %x:%x rx = %x:%x\n",
1049 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1056 error = dgmparam(tp, &tp->t_termios);
1060 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1065 /* handle fake DCD for callout devices */
1066 /* and initial DCD */
1068 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1069 linesw[tp->t_line].l_modem(tp, 1);
1073 * Wait for DCD if necessary.
1075 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1076 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1078 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1081 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1082 " error = %d\n", unit, pnum, error);
1088 error = linesw[tp->t_line].l_open(dev, tp);
1089 disc_optim(tp, &tp->t_termios);
1090 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1093 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1094 port->active_out = 1;
1098 /* If any port is open (i.e. the open() call is completed for it)
1099 * the device is busy
1103 disc_optim(tp, &tp->t_termios);
1106 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1109 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1117 dgmclose(struct dev_close_args *ap)
1119 cdev_t dev = ap->a_head.a_dev;
1123 struct dgm_softc *sc;
1128 if (mynor & CONTROL_MASK)
1130 unit = MINOR_TO_UNIT(mynor);
1131 pnum = MINOR_TO_PORT(mynor);
1133 sc = devclass_get_softc(dgmdevclass, unit);
1134 tp = &sc->ttys[pnum];
1135 port = sc->ports + pnum;
1137 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1139 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1140 dgm_drain_or_flush(port);
1145 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1146 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1147 disc_optim(tp, &tp->t_termios);
1149 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1151 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1154 wakeup(&port->closing);
1157 /* mark the card idle when all ports are closed */
1159 for (i = 0; i < sc->numports; i++)
1160 if (sc->ports[i].used)
1165 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1167 wakeup(TSA_CARR_ON(tp));
1168 wakeup(&port->active_out);
1169 port->active_out = 0;
1171 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1177 dgmhardclose(struct dgm_p *port)
1179 volatile struct board_chan *bc = port->brdchan;
1180 struct dgm_softc *sc;
1182 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1183 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1185 port->do_timestamp = 0;
1191 if (port->tty->t_cflag & HUPCL) {
1192 port->omodem &= ~(RTS|DTR);
1193 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1199 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1200 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1204 dgm_pause(void *chan)
1206 wakeup((caddr_t)chan);
1210 dgmpoll(void *unit_c)
1212 int unit = (int)unit_c;
1215 struct dgm_softc *sc;
1218 int event, mstat, lstat;
1219 volatile struct board_chan *bc;
1226 int ibuf_full, obuf_full;
1227 BoardMemWinState ws = bmws_get();
1229 sc = devclass_get_softc(dgmdevclass, unit);
1230 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1233 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1239 head = sc->mailbox->ein;
1240 tail = sc->mailbox->eout;
1242 while (head != tail) {
1243 if (head >= FEP_IMAX - FEP_ISTART
1244 || tail >= FEP_IMAX - FEP_ISTART
1245 || (head|tail) & 03 ) {
1246 kprintf("dgm%d: event queue's head or tail is wrong!"
1247 " hd = %d, tl = %d\n", unit, head, tail);
1251 eventbuf = sc->vmem + tail + FEP_ISTART;
1253 event = eventbuf[1];
1254 mstat = eventbuf[2];
1255 lstat = eventbuf[3];
1257 port = &sc->ports[pnum];
1259 tp = &sc->ttys[pnum];
1261 if (pnum >= sc->numports || !port->enabled) {
1262 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1264 } else if (port->used || port->wopeners > 0 ) {
1266 int wrapmask = port->rxbufsize - 1;
1268 if (!(event & ALL_IND))
1269 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1270 unit, pnum, event, mstat, lstat);
1272 if (event & DATA_IND) {
1273 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1276 rhead = bc->rin & wrapmask;
1277 rtail = bc->rout & wrapmask;
1279 if (!(tp->t_cflag & CREAD) || !port->used ) {
1285 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1289 if (!(tp->t_state & TS_ISOPEN))
1292 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1293 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1294 " p rx head = %d tail = %d\n", unit,
1295 pnum, rhead, rtail);
1298 size = rhead - rtail;
1300 size = port->rxbufsize - rtail;
1302 ptr = port->rxptr + rtail;
1305 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1306 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1307 DPRINT1(DB_RXDATA, "*");
1312 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1313 DPRINT1(DB_RXDATA, "!");
1314 towin(sc, port->rxwin);
1317 tp->t_rawcc += size;
1325 towin(sc, port->rxwin);
1328 (*linesw[tp->t_line].l_rint)(chr, tp);
1333 rtail= (rtail + size) & wrapmask;
1335 rhead = bc->rin & wrapmask;
1343 if (event & MODEMCHG_IND) {
1344 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1345 "MODEMCHG_IND\n", unit, pnum);
1346 port->imodem = mstat;
1347 if (mstat & port->dcd) {
1349 linesw[tp->t_line].l_modem(tp, 1);
1351 wakeup(TSA_CARR_ON(tp));
1354 linesw[tp->t_line].l_modem(tp, 0);
1356 if (port->draining) {
1358 wakeup(&port->draining);
1363 if (event & BREAK_IND) {
1364 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1365 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1366 " BREAK_IND\n", unit, pnum);
1368 linesw[tp->t_line].l_rint(TTY_BI, tp);
1373 /* Helg: with output flow control */
1375 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1376 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1377 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1379 if ((event & EMPTYTX_IND ) &&
1380 tp->t_outq.c_cc == 0 && port->draining) {
1382 wakeup(&port->draining);
1387 int wrapmask = port->txbufsize - 1;
1389 for (obuf_full = FALSE;
1390 tp->t_outq.c_cc != 0 && !obuf_full;
1392 /* add "last-minute" data to write buffer */
1393 if (!(tp->t_state & TS_BUSY)) {
1395 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1398 if (tp->t_outq.c_cc <= tp->t_lowat) {
1399 if (tp->t_state & TS_ASLEEP) {
1400 tp->t_state &= ~TS_ASLEEP;
1401 wakeup(TSA_OLOWAT(tp));
1403 /* selwakeup(&tp->t_wsel); */
1410 whead = bc->tin & wrapmask;
1411 wtail = bc->tout & wrapmask;
1414 size = wtail - whead - 1;
1416 size = port->txbufsize - whead;
1422 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1423 whead, wtail, size, obuf_full);
1431 towin(sc, port->txwin);
1433 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1438 bc->tin = whead & wrapmask;
1443 DPRINT1(DB_WR, " +BUSY\n");
1444 tp->t_state |= TS_BUSY;
1446 DPRINT1(DB_WR, " -BUSY\n");
1448 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1449 /* should clear TS_BUSY before ttwwakeup */
1450 if (tp->t_state & TS_BUSY) {
1451 tp->t_state &= ~TS_BUSY;
1452 linesw[tp->t_line].l_start(tp);
1456 if (tp->t_state & TS_ASLEEP) {
1457 tp->t_state &= ~TS_ASLEEP;
1458 wakeup(TSA_OLOWAT(tp));
1460 tp->t_state &= ~TS_BUSY;
1466 bc->idata = 1; /* require event on incoming data */
1470 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1473 bc->idata = bc->iempty = bc->ilow = 0;
1476 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1479 sc->mailbox->eout = tail;
1482 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1484 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1488 dgmioctl(struct dev_ioctl_args *ap)
1490 cdev_t dev = ap->a_head.a_dev;
1491 u_long cmd = ap->a_cmd;
1492 caddr_t data = ap->a_data;
1493 struct dgm_softc *sc;
1498 volatile struct board_chan *bc;
1502 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1504 struct termios term;
1507 BoardMemWinState ws = bmws_get();
1510 unit = MINOR_TO_UNIT(mynor);
1511 pnum = MINOR_TO_PORT(mynor);
1513 sc = devclass_get_softc(dgmdevclass, unit);
1514 port = &sc->ports[pnum];
1515 tp = &sc->ttys[pnum];
1518 if (mynor & CONTROL_MASK) {
1521 switch (mynor & CONTROL_MASK) {
1522 case CONTROL_INIT_STATE:
1523 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1525 case CONTROL_LOCK_STATE:
1526 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1529 return (ENODEV); /* /dev/nodev */
1533 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1536 *ct = *(struct termios *)data;
1539 *(struct termios *)data = *ct;
1542 *(int *)data = TTYDISC;
1545 bzero(data, sizeof(struct winsize));
1552 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1553 term = tp->t_termios;
1554 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1555 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);
1558 error = ttsetcompat(tp, &cmd, data, &term);
1562 data = (caddr_t)&term;
1565 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1567 struct termios *dt = (struct termios *)data;
1568 struct termios *lt = mynor & CALLOUT_MASK
1569 ? &port->lt_out : &port->lt_in;
1571 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);
1572 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1573 | (dt->c_iflag & ~lt->c_iflag);
1574 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1575 | (dt->c_oflag & ~lt->c_oflag);
1576 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1577 | (dt->c_cflag & ~lt->c_cflag);
1578 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1579 | (dt->c_lflag & ~lt->c_lflag);
1580 for (cc = 0; cc < NCCS; ++cc)
1581 if (lt->c_cc[cc] != 0)
1582 dt->c_cc[cc] = tp->t_cc[cc];
1583 if (lt->c_ispeed != 0)
1584 dt->c_ispeed = tp->t_ispeed;
1585 if (lt->c_ospeed != 0)
1586 dt->c_ospeed = tp->t_ospeed;
1589 if (cmd == TIOCSTOP) {
1592 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1596 } else if (cmd == TIOCSTART) {
1599 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1605 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1606 port->mustdrain = 1;
1608 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1609 ap->a_fflag, ap->a_cred);
1610 if (error != ENOIOCTL)
1613 error = ttioctl(tp, cmd, data, ap->a_fflag);
1614 disc_optim(tp, &tp->t_termios);
1615 port->mustdrain = 0;
1616 if (error != ENOIOCTL) {
1618 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1619 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);
1627 error = dgmdrain(port);
1638 /* now it sends 400 millisecond break because I don't know */
1639 /* how to send an infinite break */
1641 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1646 /* now it's empty */
1649 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1650 port->omodem |= DTR;
1653 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1655 if (!(bc->mstat & DTR))
1656 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1662 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1663 port->omodem &= ~DTR;
1666 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1668 if (bc->mstat & DTR) {
1669 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1676 if (*(int *)data & TIOCM_DTR)
1677 port->omodem |= DTR;
1679 port->omodem &= ~DTR;
1681 if (*(int *)data & TIOCM_RTS)
1682 port->omodem |= RTS;
1684 port->omodem &= ~RTS;
1688 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1693 if (*(int *)data & TIOCM_DTR)
1694 port->omodem |= DTR;
1696 if (*(int *)data & TIOCM_RTS)
1697 port->omodem |= RTS;
1701 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1706 if (*(int *)data & TIOCM_DTR)
1707 port->omodem &= ~DTR;
1709 if (*(int *)data & TIOCM_RTS)
1710 port->omodem &= ~RTS;
1714 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1720 port->imodem = bc->mstat;
1723 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1725 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1727 if (port->imodem & DTR) {
1728 DPRINT1(DB_MODEM, "DTR ");
1729 tiocm_xxx |= TIOCM_DTR;
1731 if (port->imodem & RTS) {
1732 DPRINT1(DB_MODEM, "RTS ");
1733 tiocm_xxx |= TIOCM_RTS;
1735 if (port->imodem & CTS) {
1736 DPRINT1(DB_MODEM, "CTS ");
1737 tiocm_xxx |= TIOCM_CTS;
1739 if (port->imodem & port->dcd) {
1740 DPRINT1(DB_MODEM, "DCD ");
1741 tiocm_xxx |= TIOCM_CD;
1743 if (port->imodem & port->dsr) {
1744 DPRINT1(DB_MODEM, "DSR ");
1745 tiocm_xxx |= TIOCM_DSR;
1747 if (port->imodem & RI) {
1748 DPRINT1(DB_MODEM, "RI ");
1749 tiocm_xxx |= TIOCM_RI;
1751 *(int *)data = tiocm_xxx;
1752 DPRINT1(DB_MODEM, "--\n");
1755 /* must be root since the wait applies to following logins */
1756 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1761 port->close_delay = *(int *)data * hz / 100;
1764 *(int *)data = port->close_delay * 100 / hz;
1767 port->do_timestamp = 1;
1768 *(struct timeval *)data = port->timestamp;
1770 case TIOCDCDTIMESTAMP:
1771 port->do_dcd_timestamp = 1;
1772 *(struct timeval *)data = port->dcd_timestamp;
1788 struct dgm_p *port = p;
1790 wakeup(&port->draining);
1793 /* wait for the output to drain */
1796 dgmdrain(struct dgm_p *port)
1798 volatile struct board_chan *bc = port->brdchan;
1799 struct dgm_softc *sc;
1802 BoardMemWinState ws = bmws_get();
1804 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1812 while (tail != head) {
1813 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1814 port->sc->unit, port->pnum, head, tail);
1818 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1819 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1824 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1825 port->sc->unit, port->pnum, error);
1835 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1836 port->sc->unit, port->pnum, head, tail);
1841 /* wait for the output to drain */
1842 /* or simply clear the buffer it it's stopped */
1845 dgm_drain_or_flush(struct dgm_p *port)
1847 volatile struct board_chan *bc = port->brdchan;
1848 struct tty *tp = port->tty;
1849 struct dgm_softc *sc;
1854 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1862 while (tail != head /* && tail != lasttail */ ) {
1863 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1864 port->sc->unit, port->pnum, head, tail);
1866 /* if there is no carrier simply clean the buffer */
1867 if (!(tp->t_state & TS_CARR_ON)) {
1868 bc->tout = bc->tin = 0;
1876 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1877 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1882 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1883 " error = %d\n", port->sc->unit, port->pnum, error);
1885 /* silently clean the buffer */
1887 bc->tout = bc->tin = 0;
1898 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1899 port->sc->unit, port->pnum, head, tail);
1903 dgmparam(struct tty *tp, struct termios *t)
1905 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1906 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1907 volatile struct board_chan *bc;
1908 struct dgm_softc *sc;
1915 BoardMemWinState ws = bmws_get();
1917 sc = devclass_get_softc(dgmdevclass, unit);
1918 port = &sc->ports[pnum];
1921 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);
1923 if (port->mustdrain) {
1924 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1928 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1930 if (t->c_ispeed == 0)
1931 t->c_ispeed = t->c_ospeed;
1933 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1934 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1941 if (cflag == 0) { /* hangup */
1942 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1946 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1947 mval= port->omodem & ~(DTR|RTS);
1949 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1951 if (cflag != port->fepcflag) {
1952 port->fepcflag = cflag;
1953 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1954 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1955 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1957 mval= port->omodem | (DTR|RTS);
1960 iflag = dgmflags(dgm_iflags, t->c_iflag);
1961 if (iflag != port->fepiflag) {
1962 port->fepiflag = iflag;
1963 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1964 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1967 bc->mint = port->dcd;
1969 hflow = dgmflags(dgm_flow, t->c_cflag);
1970 if (hflow != port->hflow) {
1971 port->hflow = hflow;
1972 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1973 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1976 if (port->omodem != mval) {
1977 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1978 unit, pnum, mval, port->omodem);
1979 port->omodem = mval;
1980 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1983 if (port->fepstartc != t->c_cc[VSTART] ||
1984 port->fepstopc != t->c_cc[VSTOP]) {
1985 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1986 port->fepstartc = t->c_cc[VSTART];
1987 port->fepstopc = t->c_cc[VSTOP];
1988 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1999 dgmstart(struct tty *tp)
2004 struct dgm_softc *sc;
2005 volatile struct board_chan *bc;
2010 BoardMemWinState ws = bmws_get();
2012 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2013 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2014 sc = devclass_get_softc(dgmdevclass, unit);
2015 port = &sc->ports[pnum];
2018 wmask = port->txbufsize - 1;
2022 while (tp->t_outq.c_cc != 0) {
2023 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2026 if (tp->t_outq.c_cc <= tp->t_lowat) {
2027 if (tp->t_state & TS_ASLEEP) {
2028 tp->t_state &= ~TS_ASLEEP;
2029 wakeup(TSA_OLOWAT(tp));
2031 /*selwakeup(&tp->t_wsel);*/
2037 head = bc->tin & wmask;
2039 do { tail = bc->tout; } while (tail != bc->tout);
2040 tail = bc->tout & wmask;
2042 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2044 #ifdef LEAVE_FREE_CHARS
2046 size = tail - head - LEAVE_FREE_CHARS;
2050 size = port->txbufsize - head;
2051 if (tail + port->txbufsize < head)
2057 size = tail - head - 1;
2059 size = port->txbufsize - head;
2070 tp->t_state |= TS_BUSY;
2075 towin(sc, port->txwin);
2077 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2079 if (head >= port->txbufsize)
2080 head -= port->txbufsize;
2085 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2086 unit, pnum, size, ocount);
2094 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2095 if (tp->t_state & TS_BUSY) {
2096 tp->t_state &= ~TS_BUSY;
2097 linesw[tp->t_line].l_start(tp);
2101 if (tp->t_state & TS_ASLEEP) {
2102 tp->t_state &= ~TS_ASLEEP;
2103 wakeup(TSA_OLOWAT(tp));
2105 tp->t_state& = ~TS_BUSY;
2110 dgmstop(struct tty *tp, int rw)
2115 struct dgm_softc *sc;
2116 volatile struct board_chan *bc;
2118 BoardMemWinState ws = bmws_get();
2120 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2121 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2123 sc = devclass_get_softc(dgmdevclass, unit);
2124 port = &sc->ports[pnum];
2127 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2133 /* clear output queue */
2134 bc->tout = bc->tin = 0;
2139 /* clear input queue */
2150 fepcmd(struct dgm_p *port,
2158 unsigned tail, head;
2161 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2162 mem = port->sc->vmem;
2164 if (!port->enabled) {
2165 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2166 port->sc->unit, port->pnum);
2170 /* setwin(port->sc, 0); Require this to be set by caller */
2171 head = port->sc->mailbox->cin;
2173 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2174 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2175 port->sc->unit, port->pnum, head);
2179 mem[head + FEP_CSTART] = cmd;
2180 mem[head + FEP_CSTART + 1] = port->pnum;
2182 mem[head + FEP_CSTART + 2] = op1;
2183 mem[head + FEP_CSTART + 3] = op2;
2185 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2186 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2189 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2190 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2192 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2193 port->sc->mailbox->cin = head;
2197 while (count-- != 0) {
2198 head = port->sc->mailbox->cin;
2199 tail = port->sc->mailbox->cout;
2201 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2202 if (n <= ncmds * (sizeof(ushort)*4))
2205 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2209 disc_optim(struct tty *tp, struct termios *t)
2211 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2212 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2213 && (!(t->c_iflag & PARMRK)
2214 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2215 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2216 && linesw[tp->t_line].l_rint == ttyinput)
2217 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2219 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;