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.16 2006/12/22 23:26:24 swildner 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>
79 #include <sys/dkstat.h>
80 #include <sys/fcntl.h>
81 #include <sys/kernel.h>
82 #include <sys/sysctl.h>
83 #include <sys/malloc.h>
84 #include <sys/sysctl.h>
90 #include <sys/thread2.h>
92 #include <machine/clock.h>
101 #define CALLOUT_MASK 0x40000
102 #define CONTROL_MASK 0xC0
103 #define CONTROL_INIT_STATE 0x40
104 #define CONTROL_LOCK_STATE 0x80
105 #define UNIT_MASK 0x30000
106 #define PORT_MASK 0x3F
107 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
108 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
109 #define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK) >> 16)
110 #define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK)
112 #define MEM_SIZE 0x8000
114 #define DGM_UNITMASK 0x30000
115 #define DGM_UNIT(unit) ((unit) << 16)
119 /* digiboard port structure */
121 unsigned enabled : 1;
123 struct dgm_softc *sc; /* parent softc */
124 u_char pnum; /* port number */
125 u_char omodem; /* FEP output modem status */
126 u_char imodem; /* FEP input modem status */
127 u_char modemfake; /* Modem values to be forced */
128 u_char modem; /* Force values */
152 volatile struct board_chan *brdchan;
155 u_char active_out; /* nonzero if the callout device is open */
156 u_int wopeners; /* # processes waiting for DCD in open() */
159 struct termios it_in; /* should be in struct tty */
160 struct termios it_out;
163 struct termios lt_in; /* should be in struct tty */
164 struct termios lt_out;
166 unsigned do_timestamp : 1;
167 unsigned do_dcd_timestamp : 1;
168 struct timeval timestamp;
169 struct timeval dcd_timestamp;
171 /* flags of state, are used in sleep() too */
172 u_char closing; /* port is being closed now */
173 u_char draining; /* port is being drained now */
174 u_char used; /* port is being used now */
175 u_char mustdrain; /* data must be waited to drain in dgmparam() */
177 struct callout hc_timeout;
178 struct callout wf_timeout;
181 /* Digiboard per-board structure */
183 /* struct board_info */
184 unsigned enabled : 1;
185 u_char unit; /* unit number */
186 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
187 u_char altpin; /* do we need alternate pin setting ? */
188 int numports; /* number of ports on card */
189 u_long port; /* I/O port */
190 u_char *vmem; /* virtual memory address */
191 u_long pmem; /* physical memory address */
192 int mem_seg; /* internal memory segment */
193 struct dgm_p *ports; /* ptr to array of port descriptors */
194 struct tty *ttys; /* ptr to array of TTY structures */
195 volatile struct global_data *mailbox;
196 struct resource *io_res;
197 struct resource *mem_res;
200 struct callout toh; /* poll timeout handle */
203 static void dgmpoll(void *);
204 static int dgmprobe(device_t);
205 static int dgmattach(device_t);
206 static int dgmdetach(device_t);
207 static int dgmshutdown(device_t);
208 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
210 static void dgmstart(struct tty *);
211 static void dgmstop(struct tty *, int);
212 static int dgmparam(struct tty *, struct termios *);
213 static void dgmhardclose(struct dgm_p *);
214 static void dgm_drain_or_flush(struct dgm_p *);
215 static int dgmdrain(struct dgm_p *);
216 static void dgm_pause(void *);
217 static void wakeflush(void *);
218 static void disc_optim(struct tty *, struct termios *);
220 static d_open_t dgmopen;
221 static d_close_t dgmclose;
222 static d_ioctl_t dgmioctl;
224 static device_method_t dgmmethods[] = {
225 /* Device interface */
226 DEVMETHOD(device_probe, dgmprobe),
227 DEVMETHOD(device_attach, dgmattach),
228 DEVMETHOD(device_detach, dgmdetach),
229 DEVMETHOD(device_shutdown, dgmshutdown),
233 static driver_t dgmdriver = {
236 sizeof (struct dgm_softc),
239 static devclass_t dgmdevclass;
241 #define CDEV_MAJOR 101
242 static struct dev_ops dgm_ops = {
243 { "dgm", CDEV_MAJOR, D_TTY | D_KQFILTER },
250 .d_kqfilter = ttykqfilter
254 dgmmodhandler(module_t mod, int event, void *arg)
268 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
270 static speed_t dgmdefaultrate = TTYDEF_SPEED;
272 static struct speedtab dgmspeedtab[] = {
273 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
287 { 19200, FEP_B19200 },
288 { 38400, FEP_B38400 },
289 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
290 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
294 static struct dbgflagtbl {
299 { PARODD, PARODD, FEP_PARODD },
300 { PARENB, PARENB, FEP_PARENB },
301 { CSTOPB, CSTOPB, FEP_CSTOPB },
302 { CSIZE, CS5, FEP_CS6 },
303 { CSIZE, CS6, FEP_CS6 },
304 { CSIZE, CS7, FEP_CS7 },
305 { CSIZE, CS8, FEP_CS8 },
306 { CLOCAL, CLOCAL, FEP_CLOCAL },
309 { IGNBRK, IGNBRK, FEP_IGNBRK },
310 { BRKINT, BRKINT, FEP_BRKINT },
311 { IGNPAR, IGNPAR, FEP_IGNPAR },
312 { PARMRK, PARMRK, FEP_PARMRK },
313 { INPCK, INPCK, FEP_INPCK },
314 { ISTRIP, ISTRIP, FEP_ISTRIP },
315 { IXON, IXON, FEP_IXON },
316 { IXOFF, IXOFF, FEP_IXOFF },
317 { IXANY, IXANY, FEP_IXANY },
320 { CRTSCTS, CRTSCTS, CTS|RTS },
321 { CRTSCTS, CCTS_OFLOW, CTS },
322 { CRTSCTS, CRTS_IFLOW, RTS },
326 /* xlat bsd termios flags to dgm sys-v style */
328 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
333 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
334 if ((input & tbl[i].in_mask) == tbl[i].in_val)
335 output |= tbl[i].out_val;
340 static int dgmdebug = 0;
341 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
343 static __inline int setwin(struct dgm_softc *, unsigned);
344 static __inline void hidewin(struct dgm_softc *);
345 static __inline void towin(struct dgm_softc *, int);
347 /*Helg: to allow recursive dgm...() calls */
349 /* If we were called and don't want to disturb we need: */
350 int port; /* write to this port */
351 u_char data; /* this data on exit */
352 /* or DATA_WINOFF to close memory window on entry */
353 } BoardMemWinState; /* so several channels and even boards can coexist */
355 #define DATA_WINOFF 0
356 static BoardMemWinState bmws;
358 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
359 static u_long validmem[] = {
360 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
361 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
362 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
363 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
364 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
367 /* return current memory window state and close window */
368 static BoardMemWinState
371 BoardMemWinState bmwsRet = bmws;
373 if (bmws.data != DATA_WINOFF)
374 outb(bmws.port, bmws.data = DATA_WINOFF);
378 /* restore memory window state */
380 bmws_set(BoardMemWinState ws)
382 if (ws.data != bmws.data || ws.port != bmws.port) {
383 if (bmws.data != DATA_WINOFF)
384 outb(bmws.port, DATA_WINOFF);
385 if (ws.data != DATA_WINOFF)
386 outb(ws.port, ws.data);
392 setwin(struct dgm_softc *sc, unsigned int addr)
394 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
395 return (addr & 0x7FFF);
399 hidewin(struct dgm_softc *sc)
402 outb(bmws.port = sc->port + 1, bmws.data);
406 towin(struct dgm_softc *sc, int win)
408 outb(bmws.port = sc->port + 1, bmws.data = win);
412 dgmprobe(device_t dev)
414 struct dgm_softc *sc = device_get_softc(dev);
418 * Assign unit number. Due to bits we use in the minor number for
419 * the various tty types, only 4 units are supported.
421 sc->unit = device_get_unit(dev);
423 device_printf(dev, "Too many units, only 4 supported\n");
427 /* Check that we've got a valid i/o address */
428 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
430 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
431 if (sc->port == validio[i])
434 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
438 /* Ditto for our memory address */
439 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
441 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
442 if (sc->pmem == validmem[i])
445 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
448 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
449 device_printf(dev, "0x%lx: Memory address not supported\n",
453 sc->vmem = (u_char *)sc->pmem;
455 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
458 /* Temporarily map our io ports */
460 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
461 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
462 if (sc->io_res == NULL)
465 outb(sc->port, FEPRST);
468 for (i = 0; i < 1000; i++) {
470 if ((inb(sc->port) & FEPMASK) == FEPRST) {
472 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
479 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
480 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
484 /* check type of card and get internal memory characteristics */
492 second = inb(sc->port);
493 kprintf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
495 kprintf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
498 sc->mem_seg = 0x8000;
500 /* Temporarily map our memory too */
502 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
503 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
504 if (sc->mem_res == NULL) {
505 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
506 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
510 outb(sc->port, FEPCLR); /* drop RESET */
511 hidewin(sc); /* Helg: to set initial bmws state */
513 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
514 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
516 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
517 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
519 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
525 dgmattach(device_t dev)
527 struct dgm_softc *sc = device_get_softc(dev);
533 volatile struct board_chan *bc;
536 u_long msize, iosize;
538 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
540 callout_init(&sc->toh);
541 sc->unit = device_get_unit(dev);
542 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
543 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
544 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
546 sc->mem_seg = 0x8000;
549 sc->mem_seg = 0x8000;
551 /* Allocate resources (should have been verified in dgmprobe()) */
553 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
554 0ul, ~0ul, iosize, RF_ACTIVE);
555 if (sc->io_res == NULL)
558 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
559 0ul, ~0ul, msize, RF_ACTIVE);
560 if (sc->mem_res == NULL) {
561 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
562 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
567 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
569 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
572 outb(sc->port, FEPRST);
575 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
577 device_printf(dev, "1st reset failed\n");
580 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
581 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
587 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
589 t = sc->pmem >> 8; /* disable windowing */
590 outb(sc->port + 2, t & 0xFF);
591 outb(sc->port + 3, t >> 8);
595 /* very short memory test */
596 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
598 addr = setwin(sc, BOTWIN);
599 *(u_long *)(mem + addr) = 0xA55A3CC3;
600 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
601 device_printf(dev, "1st memory test failed\n");
604 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
605 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
609 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
611 addr = setwin(sc, TOPWIN);
612 *(u_long *)(mem + addr) = 0x5AA5C33C;
613 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
614 device_printf(dev, "2nd memory test failed\n");
617 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
618 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
622 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
624 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
625 *(u_long *)(mem + addr) = 0x5AA5C33C;
626 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
627 device_printf(dev, "3rd (BIOS) memory test failed\n");
629 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
631 addr = setwin(sc, MISCGLOBAL);
632 for (i = 0; i < 16; i++)
635 addr = setwin(sc, BIOSOFFSET);
637 for (i = 0; ptr < mem + msize; i++)
638 *ptr++ = pcem_bios[i];
640 ptr = mem + BIOSOFFSET;
641 for (i = 0; ptr < mem + msize; i++) {
642 if (*ptr++ != pcem_bios[i]) {
643 kprintf("Low BIOS load failed\n");
646 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
647 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
651 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
653 addr = setwin(sc, msize);
655 for (;i < pcem_nbios; i++)
656 *ptr++ = pcem_bios[i];
659 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
660 if (*ptr++ != pcem_bios[i]) {
661 kprintf("High BIOS load failed\n");
664 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
665 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
669 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
670 device_printf(dev, "DigiBIOS loaded, initializing");
672 addr = setwin(sc, 0);
674 *(u_int *)(mem + addr) = 0x0bf00401;
675 *(u_int *)(mem + addr + 4) = 0;
676 *(ushort *)(mem + addr + 0xc00) = 0;
679 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
682 kprintf("\nBIOS initialize failed(1)\n");
685 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
686 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
691 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
692 kprintf("\nBIOS initialize failed(2)\n");
695 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
696 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
699 kprintf(", DigiBIOS running\n");
703 addr = setwin(sc, BIOSOFFSET);
705 for (i = 0; i < pcem_ncook; i++)
706 *ptr++ = pcem_cook[i];
708 ptr = mem + BIOSOFFSET;
709 for (i = 0; i < pcem_ncook; i++) {
710 if (*ptr++ != pcem_cook[i]) {
711 kprintf("FEP/OS load failed\n");
714 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
715 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
719 device_printf(dev, "FEP/OS loaded, initializing");
721 addr = setwin(sc, 0);
722 *(ushort *)(mem + addr + 0xd20) = 0;
723 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
724 *(u_int *)(mem + addr + 0xc30) = 0x3L;
727 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
730 kprintf("\nFEP/OS initialize failed(1)\n");
733 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
734 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
739 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
740 kprintf("\nFEP/OS initialize failed(2)\n");
743 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
744 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
747 kprintf(", FEP/OS running\n");
749 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
750 device_printf(dev, "%d ports attached\n", sc->numports);
752 if (sc->numports > MAX_DGM_PORTS) {
753 kprintf("dgm%d: too many ports\n", sc->unit);
756 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
757 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
761 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
762 M_TTYS, M_WAITOK|M_ZERO);
763 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
764 M_TTYS, M_WAITOK|M_ZERO);
766 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
767 for (i = 0; i < sc->numports; i++) {
768 sc->ports[i].enabled = 1;
769 callout_init(&sc->ports[i].hc_timeout);
770 callout_init(&sc->ports[i].wf_timeout);
773 /* We should now init per-port structures */
775 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
776 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
778 if (sc->numports < 3)
783 dev_ops_add(&dgm_ops, DGM_UNITMASK, DGM_UNIT(sc->unit));
784 for (i = 0; i < sc->numports; i++, bc++) {
785 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
786 port = &sc->ports[i];
789 port->tty = &sc->ttys[i];
797 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
799 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
800 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
804 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
805 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
806 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
807 port->txwin = FEPWIN | (bc->tseg >> 11);
808 port->rxwin = FEPWIN | (bc->rseg >> 11);
812 port->txbufsize = bc->tmax + 1;
813 port->rxbufsize = bc->rmax + 1;
815 lowwater = (port->txbufsize >= 2000) ?
816 1024 : (port->txbufsize / 2);
819 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
820 sc->unit, i, lowwater);
821 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
822 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
823 sc->unit, i, port->rxbufsize / 4);
824 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
825 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
826 sc->unit, i, 3 * port->rxbufsize / 4);
827 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
832 port->startc = bc->startc;
833 port->startca = bc->startca;
834 port->stopc = bc->stopc;
835 port->stopca = bc->stopca;
837 /* port->close_delay = 50; */
838 port->close_delay = 3 * hz;
839 port->do_timestamp = 0;
840 port->do_dcd_timestamp = 0;
842 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
844 * We don't use all the flags from <sys/ttydefaults.h> since
845 * they are only relevant for logins. It's important to have
846 * echo off initially so that the line doesn't start
847 * blathering before the echo flag can be turned off.
849 port->it_in.c_iflag = TTYDEF_IFLAG;
850 port->it_in.c_oflag = TTYDEF_OFLAG;
851 port->it_in.c_cflag = TTYDEF_CFLAG;
852 port->it_in.c_lflag = TTYDEF_LFLAG;
853 termioschars(&port->it_in);
854 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
855 port->it_out = port->it_in;
857 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
858 make_dev(&dgm_ops, (sc->unit*65536) + i, UID_ROOT,
859 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
860 make_dev(&dgm_ops, sc->unit * 65536 + i + 64, UID_ROOT,
861 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
862 make_dev(&dgm_ops, sc->unit * 65536 + i + 128, UID_ROOT,
863 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
864 make_dev(&dgm_ops, sc->unit * 65536 + i + 262144, UID_UUCP,
865 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
866 make_dev(&dgm_ops, sc->unit * 65536 + i + 262208, UID_UUCP,
867 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
868 make_dev(&dgm_ops, sc->unit * 65536 + i + 262272, UID_UUCP,
869 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
872 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
876 /* start the polling function */
877 callout_reset(&sc->toh, hz / POLLSPERSEC,
878 dgmpoll, (void *)(int)sc->unit);
880 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
886 dgmdetach(device_t dev)
888 struct dgm_softc *sc = device_get_softc(dev);
891 for (i = 0; i < sc->numports; i++)
892 if (sc->ttys[i].t_state & TS_ISOPEN)
895 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
898 * The dev_ops_remove() call will destroy all associated devices
899 * and dereference any ad-hoc-created devices, but does not
900 * dereference devices created via make_dev().
902 dev_ops_remove(&dgm_ops, DGM_UNITMASK, DGM_UNIT(sc->unit));
904 callout_stop(&sc->toh);
906 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
907 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
909 FREE(sc->ports, M_TTYS);
910 FREE(sc->ttys, M_TTYS);
916 dgmshutdown(device_t dev)
919 struct dgm_softc *sc = device_get_softc(dev);
921 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
929 dgmopen(struct dev_open_args *ap)
931 cdev_t dev = ap->a_head.a_dev;
932 struct dgm_softc *sc;
939 volatile struct board_chan *bc;
943 unit = MINOR_TO_UNIT(mynor);
944 pnum = MINOR_TO_PORT(mynor);
946 sc = devclass_get_softc(dgmdevclass, unit);
948 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
953 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
956 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
961 if (pnum >= sc->numports) {
962 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
967 if (mynor & CONTROL_MASK)
970 tp = &sc->ttys[pnum];
972 port = &sc->ports[pnum];
978 while (port->closing) {
979 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
982 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
983 " error = %d\n", unit, pnum, error);
988 if (tp->t_state & TS_ISOPEN) {
990 * The device is open, so everything has been initialized.
993 if (mynor & CALLOUT_MASK) {
994 if (!port->active_out) {
996 DPRINT4(DB_OPEN, "dgm%d: port%d:"
997 " BUSY error = %d\n", unit, pnum, error);
1000 } else if (port->active_out) {
1001 if (ap->a_oflags & O_NONBLOCK) {
1003 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1004 " BUSY error = %d\n", unit, pnum, error);
1007 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1009 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1010 " error = %d\n", unit, pnum, error);
1016 if (tp->t_state & TS_XCLUDE && suser_cred(ap->a_cred, 0)) {
1022 * The device isn't open, so there are no conflicts.
1023 * Initialize it. Initialization is done twice in many
1024 * cases: to preempt sleeping callin opens if we are
1025 * callout, and to complete a callin open after DCD rises.
1027 tp->t_oproc = dgmstart;
1028 tp->t_param = dgmparam;
1029 tp->t_stop = dgmstop;
1031 tp->t_termios= (mynor & CALLOUT_MASK) ?
1037 port->imodem = bc->mstat;
1038 bc->rout = bc->rin; /* clear input queue */
1040 #ifdef PRINT_BUFSIZE
1041 kprintf("dgm buffers tx = %x:%x rx = %x:%x\n",
1042 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1049 error = dgmparam(tp, &tp->t_termios);
1053 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1058 /* handle fake DCD for callout devices */
1059 /* and initial DCD */
1061 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1062 linesw[tp->t_line].l_modem(tp, 1);
1066 * Wait for DCD if necessary.
1068 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1069 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1071 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1074 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1075 " error = %d\n", unit, pnum, error);
1081 error = linesw[tp->t_line].l_open(dev, tp);
1082 disc_optim(tp, &tp->t_termios);
1083 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1086 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1087 port->active_out = 1;
1091 /* If any port is open (i.e. the open() call is completed for it)
1092 * the device is busy
1096 disc_optim(tp, &tp->t_termios);
1099 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1102 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1110 dgmclose(struct dev_close_args *ap)
1112 cdev_t dev = ap->a_head.a_dev;
1116 struct dgm_softc *sc;
1121 if (mynor & CONTROL_MASK)
1123 unit = MINOR_TO_UNIT(mynor);
1124 pnum = MINOR_TO_PORT(mynor);
1126 sc = devclass_get_softc(dgmdevclass, unit);
1127 tp = &sc->ttys[pnum];
1128 port = sc->ports + pnum;
1130 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1132 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1133 dgm_drain_or_flush(port);
1138 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1139 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1140 disc_optim(tp, &tp->t_termios);
1142 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1144 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1147 wakeup(&port->closing);
1150 /* mark the card idle when all ports are closed */
1152 for (i = 0; i < sc->numports; i++)
1153 if (sc->ports[i].used)
1158 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1160 wakeup(TSA_CARR_ON(tp));
1161 wakeup(&port->active_out);
1162 port->active_out = 0;
1164 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1170 dgmhardclose(struct dgm_p *port)
1172 volatile struct board_chan *bc = port->brdchan;
1173 struct dgm_softc *sc;
1175 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1176 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1178 port->do_timestamp = 0;
1184 if (port->tty->t_cflag & HUPCL) {
1185 port->omodem &= ~(RTS|DTR);
1186 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1192 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1193 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1197 dgm_pause(void *chan)
1199 wakeup((caddr_t)chan);
1203 dgmpoll(void *unit_c)
1205 int unit = (int)unit_c;
1208 struct dgm_softc *sc;
1211 int event, mstat, lstat;
1212 volatile struct board_chan *bc;
1219 int ibuf_full, obuf_full;
1220 BoardMemWinState ws = bmws_get();
1222 sc = devclass_get_softc(dgmdevclass, unit);
1223 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1226 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1232 head = sc->mailbox->ein;
1233 tail = sc->mailbox->eout;
1235 while (head != tail) {
1236 if (head >= FEP_IMAX - FEP_ISTART
1237 || tail >= FEP_IMAX - FEP_ISTART
1238 || (head|tail) & 03 ) {
1239 kprintf("dgm%d: event queue's head or tail is wrong!"
1240 " hd = %d, tl = %d\n", unit, head, tail);
1244 eventbuf = sc->vmem + tail + FEP_ISTART;
1246 event = eventbuf[1];
1247 mstat = eventbuf[2];
1248 lstat = eventbuf[3];
1250 port = &sc->ports[pnum];
1252 tp = &sc->ttys[pnum];
1254 if (pnum >= sc->numports || !port->enabled) {
1255 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1257 } else if (port->used || port->wopeners > 0 ) {
1259 int wrapmask = port->rxbufsize - 1;
1261 if (!(event & ALL_IND))
1262 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1263 unit, pnum, event, mstat, lstat);
1265 if (event & DATA_IND) {
1266 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1269 rhead = bc->rin & wrapmask;
1270 rtail = bc->rout & wrapmask;
1272 if (!(tp->t_cflag & CREAD) || !port->used ) {
1278 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1282 if (!(tp->t_state & TS_ISOPEN))
1285 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1286 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1287 " p rx head = %d tail = %d\n", unit,
1288 pnum, rhead, rtail);
1291 size = rhead - rtail;
1293 size = port->rxbufsize - rtail;
1295 ptr = port->rxptr + rtail;
1298 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1299 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1300 DPRINT1(DB_RXDATA, "*");
1305 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1306 DPRINT1(DB_RXDATA, "!");
1307 towin(sc, port->rxwin);
1310 tp->t_rawcc += size;
1318 towin(sc, port->rxwin);
1321 (*linesw[tp->t_line].l_rint)(chr, tp);
1326 rtail= (rtail + size) & wrapmask;
1328 rhead = bc->rin & wrapmask;
1336 if (event & MODEMCHG_IND) {
1337 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1338 "MODEMCHG_IND\n", unit, pnum);
1339 port->imodem = mstat;
1340 if (mstat & port->dcd) {
1342 linesw[tp->t_line].l_modem(tp, 1);
1344 wakeup(TSA_CARR_ON(tp));
1347 linesw[tp->t_line].l_modem(tp, 0);
1349 if (port->draining) {
1351 wakeup(&port->draining);
1356 if (event & BREAK_IND) {
1357 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1358 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1359 " BREAK_IND\n", unit, pnum);
1361 linesw[tp->t_line].l_rint(TTY_BI, tp);
1366 /* Helg: with output flow control */
1368 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1369 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1370 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1372 if ((event & EMPTYTX_IND ) &&
1373 tp->t_outq.c_cc == 0 && port->draining) {
1375 wakeup(&port->draining);
1380 int wrapmask = port->txbufsize - 1;
1382 for (obuf_full = FALSE;
1383 tp->t_outq.c_cc != 0 && !obuf_full;
1385 /* add "last-minute" data to write buffer */
1386 if (!(tp->t_state & TS_BUSY)) {
1388 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1391 if (tp->t_outq.c_cc <= tp->t_lowat) {
1392 if (tp->t_state & TS_ASLEEP) {
1393 tp->t_state &= ~TS_ASLEEP;
1394 wakeup(TSA_OLOWAT(tp));
1396 /* selwakeup(&tp->t_wsel); */
1403 whead = bc->tin & wrapmask;
1404 wtail = bc->tout & wrapmask;
1407 size = wtail - whead - 1;
1409 size = port->txbufsize - whead;
1415 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1416 whead, wtail, size, obuf_full);
1424 towin(sc, port->txwin);
1426 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1431 bc->tin = whead & wrapmask;
1436 DPRINT1(DB_WR, " +BUSY\n");
1437 tp->t_state |= TS_BUSY;
1439 DPRINT1(DB_WR, " -BUSY\n");
1441 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1442 /* should clear TS_BUSY before ttwwakeup */
1443 if (tp->t_state & TS_BUSY) {
1444 tp->t_state &= ~TS_BUSY;
1445 linesw[tp->t_line].l_start(tp);
1449 if (tp->t_state & TS_ASLEEP) {
1450 tp->t_state &= ~TS_ASLEEP;
1451 wakeup(TSA_OLOWAT(tp));
1453 tp->t_state &= ~TS_BUSY;
1459 bc->idata = 1; /* require event on incoming data */
1463 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1466 bc->idata = bc->iempty = bc->ilow = 0;
1469 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1472 sc->mailbox->eout = tail;
1475 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1477 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1481 dgmioctl(struct dev_ioctl_args *ap)
1483 cdev_t dev = ap->a_head.a_dev;
1484 u_long cmd = ap->a_cmd;
1485 caddr_t data = ap->a_data;
1486 struct dgm_softc *sc;
1491 volatile struct board_chan *bc;
1495 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1497 struct termios term;
1500 BoardMemWinState ws = bmws_get();
1503 unit = MINOR_TO_UNIT(mynor);
1504 pnum = MINOR_TO_PORT(mynor);
1506 sc = devclass_get_softc(dgmdevclass, unit);
1507 port = &sc->ports[pnum];
1508 tp = &sc->ttys[pnum];
1511 if (mynor & CONTROL_MASK) {
1514 switch (mynor & CONTROL_MASK) {
1515 case CONTROL_INIT_STATE:
1516 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1518 case CONTROL_LOCK_STATE:
1519 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1522 return (ENODEV); /* /dev/nodev */
1526 error = suser_cred(ap->a_cred, 0);
1529 *ct = *(struct termios *)data;
1532 *(struct termios *)data = *ct;
1535 *(int *)data = TTYDISC;
1538 bzero(data, sizeof(struct winsize));
1545 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1546 term = tp->t_termios;
1547 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1548 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);
1551 error = ttsetcompat(tp, &cmd, data, &term);
1555 data = (caddr_t)&term;
1558 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1560 struct termios *dt = (struct termios *)data;
1561 struct termios *lt = mynor & CALLOUT_MASK
1562 ? &port->lt_out : &port->lt_in;
1564 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);
1565 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1566 | (dt->c_iflag & ~lt->c_iflag);
1567 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1568 | (dt->c_oflag & ~lt->c_oflag);
1569 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1570 | (dt->c_cflag & ~lt->c_cflag);
1571 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1572 | (dt->c_lflag & ~lt->c_lflag);
1573 for (cc = 0; cc < NCCS; ++cc)
1574 if (lt->c_cc[cc] != 0)
1575 dt->c_cc[cc] = tp->t_cc[cc];
1576 if (lt->c_ispeed != 0)
1577 dt->c_ispeed = tp->t_ispeed;
1578 if (lt->c_ospeed != 0)
1579 dt->c_ospeed = tp->t_ospeed;
1582 if (cmd == TIOCSTOP) {
1585 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1589 } else if (cmd == TIOCSTART) {
1592 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1598 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1599 port->mustdrain = 1;
1601 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1602 ap->a_fflag, ap->a_cred);
1603 if (error != ENOIOCTL)
1606 error = ttioctl(tp, cmd, data, ap->a_fflag);
1607 disc_optim(tp, &tp->t_termios);
1608 port->mustdrain = 0;
1609 if (error != ENOIOCTL) {
1611 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1612 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);
1620 error = dgmdrain(port);
1631 /* now it sends 400 millisecond break because I don't know */
1632 /* how to send an infinite break */
1634 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1639 /* now it's empty */
1642 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1643 port->omodem |= DTR;
1646 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1648 if (!(bc->mstat & DTR))
1649 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1655 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1656 port->omodem &= ~DTR;
1659 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1661 if (bc->mstat & DTR) {
1662 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1669 if (*(int *)data & TIOCM_DTR)
1670 port->omodem |= DTR;
1672 port->omodem &= ~DTR;
1674 if (*(int *)data & TIOCM_RTS)
1675 port->omodem |= RTS;
1677 port->omodem &= ~RTS;
1681 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1686 if (*(int *)data & TIOCM_DTR)
1687 port->omodem |= DTR;
1689 if (*(int *)data & TIOCM_RTS)
1690 port->omodem |= RTS;
1694 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1699 if (*(int *)data & TIOCM_DTR)
1700 port->omodem &= ~DTR;
1702 if (*(int *)data & TIOCM_RTS)
1703 port->omodem &= ~RTS;
1707 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1713 port->imodem = bc->mstat;
1716 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1718 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1720 if (port->imodem & DTR) {
1721 DPRINT1(DB_MODEM, "DTR ");
1722 tiocm_xxx |= TIOCM_DTR;
1724 if (port->imodem & RTS) {
1725 DPRINT1(DB_MODEM, "RTS ");
1726 tiocm_xxx |= TIOCM_RTS;
1728 if (port->imodem & CTS) {
1729 DPRINT1(DB_MODEM, "CTS ");
1730 tiocm_xxx |= TIOCM_CTS;
1732 if (port->imodem & port->dcd) {
1733 DPRINT1(DB_MODEM, "DCD ");
1734 tiocm_xxx |= TIOCM_CD;
1736 if (port->imodem & port->dsr) {
1737 DPRINT1(DB_MODEM, "DSR ");
1738 tiocm_xxx |= TIOCM_DSR;
1740 if (port->imodem & RI) {
1741 DPRINT1(DB_MODEM, "RI ");
1742 tiocm_xxx |= TIOCM_RI;
1744 *(int *)data = tiocm_xxx;
1745 DPRINT1(DB_MODEM, "--\n");
1748 /* must be root since the wait applies to following logins */
1749 error = suser_cred(ap->a_cred, 0);
1754 port->close_delay = *(int *)data * hz / 100;
1757 *(int *)data = port->close_delay * 100 / hz;
1760 port->do_timestamp = 1;
1761 *(struct timeval *)data = port->timestamp;
1763 case TIOCDCDTIMESTAMP:
1764 port->do_dcd_timestamp = 1;
1765 *(struct timeval *)data = port->dcd_timestamp;
1781 struct dgm_p *port = p;
1783 wakeup(&port->draining);
1786 /* wait for the output to drain */
1789 dgmdrain(struct dgm_p *port)
1791 volatile struct board_chan *bc = port->brdchan;
1792 struct dgm_softc *sc;
1795 BoardMemWinState ws = bmws_get();
1797 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1805 while (tail != head) {
1806 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1807 port->sc->unit, port->pnum, head, tail);
1811 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1812 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1817 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1818 port->sc->unit, port->pnum, error);
1828 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1829 port->sc->unit, port->pnum, head, tail);
1834 /* wait for the output to drain */
1835 /* or simply clear the buffer it it's stopped */
1838 dgm_drain_or_flush(struct dgm_p *port)
1840 volatile struct board_chan *bc = port->brdchan;
1841 struct tty *tp = port->tty;
1842 struct dgm_softc *sc;
1847 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1855 while (tail != head /* && tail != lasttail */ ) {
1856 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1857 port->sc->unit, port->pnum, head, tail);
1859 /* if there is no carrier simply clean the buffer */
1860 if (!(tp->t_state & TS_CARR_ON)) {
1861 bc->tout = bc->tin = 0;
1869 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1870 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1875 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1876 " error = %d\n", port->sc->unit, port->pnum, error);
1878 /* silently clean the buffer */
1880 bc->tout = bc->tin = 0;
1891 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1892 port->sc->unit, port->pnum, head, tail);
1896 dgmparam(struct tty *tp, struct termios *t)
1898 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1899 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1900 volatile struct board_chan *bc;
1901 struct dgm_softc *sc;
1908 BoardMemWinState ws = bmws_get();
1910 sc = devclass_get_softc(dgmdevclass, unit);
1911 port = &sc->ports[pnum];
1914 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);
1916 if (port->mustdrain) {
1917 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1921 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1923 if (t->c_ispeed == 0)
1924 t->c_ispeed = t->c_ospeed;
1926 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1927 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1934 if (cflag == 0) { /* hangup */
1935 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1939 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1940 mval= port->omodem & ~(DTR|RTS);
1942 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1944 if (cflag != port->fepcflag) {
1945 port->fepcflag = cflag;
1946 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1947 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1948 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1950 mval= port->omodem | (DTR|RTS);
1953 iflag = dgmflags(dgm_iflags, t->c_iflag);
1954 if (iflag != port->fepiflag) {
1955 port->fepiflag = iflag;
1956 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1957 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1960 bc->mint = port->dcd;
1962 hflow = dgmflags(dgm_flow, t->c_cflag);
1963 if (hflow != port->hflow) {
1964 port->hflow = hflow;
1965 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1966 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1969 if (port->omodem != mval) {
1970 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1971 unit, pnum, mval, port->omodem);
1972 port->omodem = mval;
1973 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1976 if (port->fepstartc != t->c_cc[VSTART] ||
1977 port->fepstopc != t->c_cc[VSTOP]) {
1978 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1979 port->fepstartc = t->c_cc[VSTART];
1980 port->fepstopc = t->c_cc[VSTOP];
1981 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1992 dgmstart(struct tty *tp)
1997 struct dgm_softc *sc;
1998 volatile struct board_chan *bc;
2003 BoardMemWinState ws = bmws_get();
2005 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2006 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2007 sc = devclass_get_softc(dgmdevclass, unit);
2008 port = &sc->ports[pnum];
2011 wmask = port->txbufsize - 1;
2015 while (tp->t_outq.c_cc != 0) {
2016 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2019 if (tp->t_outq.c_cc <= tp->t_lowat) {
2020 if (tp->t_state & TS_ASLEEP) {
2021 tp->t_state &= ~TS_ASLEEP;
2022 wakeup(TSA_OLOWAT(tp));
2024 /*selwakeup(&tp->t_wsel);*/
2030 head = bc->tin & wmask;
2032 do { tail = bc->tout; } while (tail != bc->tout);
2033 tail = bc->tout & wmask;
2035 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2037 #ifdef LEAVE_FREE_CHARS
2039 size = tail - head - LEAVE_FREE_CHARS;
2043 size = port->txbufsize - head;
2044 if (tail + port->txbufsize < head)
2050 size = tail - head - 1;
2052 size = port->txbufsize - head;
2063 tp->t_state |= TS_BUSY;
2068 towin(sc, port->txwin);
2070 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2072 if (head >= port->txbufsize)
2073 head -= port->txbufsize;
2078 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2079 unit, pnum, size, ocount);
2087 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2088 if (tp->t_state & TS_BUSY) {
2089 tp->t_state &= ~TS_BUSY;
2090 linesw[tp->t_line].l_start(tp);
2094 if (tp->t_state & TS_ASLEEP) {
2095 tp->t_state &= ~TS_ASLEEP;
2096 wakeup(TSA_OLOWAT(tp));
2098 tp->t_state& = ~TS_BUSY;
2103 dgmstop(struct tty *tp, int rw)
2108 struct dgm_softc *sc;
2109 volatile struct board_chan *bc;
2111 BoardMemWinState ws = bmws_get();
2113 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2114 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2116 sc = devclass_get_softc(dgmdevclass, unit);
2117 port = &sc->ports[pnum];
2120 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2126 /* clear output queue */
2127 bc->tout = bc->tin = 0;
2132 /* clear input queue */
2143 fepcmd(struct dgm_p *port,
2151 unsigned tail, head;
2154 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2155 mem = port->sc->vmem;
2157 if (!port->enabled) {
2158 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2159 port->sc->unit, port->pnum);
2163 /* setwin(port->sc, 0); Require this to be set by caller */
2164 head = port->sc->mailbox->cin;
2166 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2167 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2168 port->sc->unit, port->pnum, head);
2172 mem[head + FEP_CSTART] = cmd;
2173 mem[head + FEP_CSTART + 1] = port->pnum;
2175 mem[head + FEP_CSTART + 2] = op1;
2176 mem[head + FEP_CSTART + 3] = op2;
2178 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2179 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2182 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2183 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2185 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2186 port->sc->mailbox->cin = head;
2190 while (count-- != 0) {
2191 head = port->sc->mailbox->cin;
2192 tail = port->sc->mailbox->cout;
2194 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2195 if (n <= ncmds * (sizeof(ushort)*4))
2198 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2202 disc_optim(struct tty *tp, struct termios *t)
2204 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2205 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2206 && (!(t->c_iflag & PARMRK)
2207 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2208 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2209 && linesw[tp->t_line].l_rint == ttyinput)
2210 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2212 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;