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.14 2006/09/10 01:26:36 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>
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>
91 #include <machine/bus.h>
92 #include <machine/resource.h>
94 #include <machine/clock.h>
103 #define CALLOUT_MASK 0x40000
104 #define CONTROL_MASK 0xC0
105 #define CONTROL_INIT_STATE 0x40
106 #define CONTROL_LOCK_STATE 0x80
107 #define UNIT_MASK 0x30000
108 #define PORT_MASK 0x3F
109 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
110 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
111 #define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK) >> 16)
112 #define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK)
114 #define MEM_SIZE 0x8000
116 #define DGM_UNITMASK 0x30000
117 #define DGM_UNIT(unit) ((unit) << 16)
121 /* digiboard port structure */
123 unsigned enabled : 1;
125 struct dgm_softc *sc; /* parent softc */
126 u_char pnum; /* port number */
127 u_char omodem; /* FEP output modem status */
128 u_char imodem; /* FEP input modem status */
129 u_char modemfake; /* Modem values to be forced */
130 u_char modem; /* Force values */
154 volatile struct board_chan *brdchan;
157 u_char active_out; /* nonzero if the callout device is open */
158 u_int wopeners; /* # processes waiting for DCD in open() */
161 struct termios it_in; /* should be in struct tty */
162 struct termios it_out;
165 struct termios lt_in; /* should be in struct tty */
166 struct termios lt_out;
168 unsigned do_timestamp : 1;
169 unsigned do_dcd_timestamp : 1;
170 struct timeval timestamp;
171 struct timeval dcd_timestamp;
173 /* flags of state, are used in sleep() too */
174 u_char closing; /* port is being closed now */
175 u_char draining; /* port is being drained now */
176 u_char used; /* port is being used now */
177 u_char mustdrain; /* data must be waited to drain in dgmparam() */
179 struct callout hc_timeout;
180 struct callout wf_timeout;
183 /* Digiboard per-board structure */
185 /* struct board_info */
186 unsigned enabled : 1;
187 u_char unit; /* unit number */
188 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
189 u_char altpin; /* do we need alternate pin setting ? */
190 int numports; /* number of ports on card */
191 u_long port; /* I/O port */
192 u_char *vmem; /* virtual memory address */
193 u_long pmem; /* physical memory address */
194 int mem_seg; /* internal memory segment */
195 struct dgm_p *ports; /* ptr to array of port descriptors */
196 struct tty *ttys; /* ptr to array of TTY structures */
197 volatile struct global_data *mailbox;
198 struct resource *io_res;
199 struct resource *mem_res;
202 struct callout toh; /* poll timeout handle */
205 static void dgmpoll(void *);
206 static int dgmprobe(device_t);
207 static int dgmattach(device_t);
208 static int dgmdetach(device_t);
209 static int dgmshutdown(device_t);
210 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
212 static void dgmstart(struct tty *);
213 static void dgmstop(struct tty *, int);
214 static int dgmparam(struct tty *, struct termios *);
215 static void dgmhardclose(struct dgm_p *);
216 static void dgm_drain_or_flush(struct dgm_p *);
217 static int dgmdrain(struct dgm_p *);
218 static void dgm_pause(void *);
219 static void wakeflush(void *);
220 static void disc_optim(struct tty *, struct termios *);
222 static d_open_t dgmopen;
223 static d_close_t dgmclose;
224 static d_ioctl_t dgmioctl;
226 static device_method_t dgmmethods[] = {
227 /* Device interface */
228 DEVMETHOD(device_probe, dgmprobe),
229 DEVMETHOD(device_attach, dgmattach),
230 DEVMETHOD(device_detach, dgmdetach),
231 DEVMETHOD(device_shutdown, dgmshutdown),
235 static driver_t dgmdriver = {
238 sizeof (struct dgm_softc),
241 static devclass_t dgmdevclass;
243 #define CDEV_MAJOR 101
244 static struct dev_ops dgm_ops = {
245 { "dgm", CDEV_MAJOR, D_TTY | D_KQFILTER },
252 .d_kqfilter = ttykqfilter
256 dgmmodhandler(module_t mod, int event, void *arg)
270 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
272 static speed_t dgmdefaultrate = TTYDEF_SPEED;
274 static struct speedtab dgmspeedtab[] = {
275 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
289 { 19200, FEP_B19200 },
290 { 38400, FEP_B38400 },
291 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
292 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
296 static struct dbgflagtbl {
301 { PARODD, PARODD, FEP_PARODD },
302 { PARENB, PARENB, FEP_PARENB },
303 { CSTOPB, CSTOPB, FEP_CSTOPB },
304 { CSIZE, CS5, FEP_CS6 },
305 { CSIZE, CS6, FEP_CS6 },
306 { CSIZE, CS7, FEP_CS7 },
307 { CSIZE, CS8, FEP_CS8 },
308 { CLOCAL, CLOCAL, FEP_CLOCAL },
311 { IGNBRK, IGNBRK, FEP_IGNBRK },
312 { BRKINT, BRKINT, FEP_BRKINT },
313 { IGNPAR, IGNPAR, FEP_IGNPAR },
314 { PARMRK, PARMRK, FEP_PARMRK },
315 { INPCK, INPCK, FEP_INPCK },
316 { ISTRIP, ISTRIP, FEP_ISTRIP },
317 { IXON, IXON, FEP_IXON },
318 { IXOFF, IXOFF, FEP_IXOFF },
319 { IXANY, IXANY, FEP_IXANY },
322 { CRTSCTS, CRTSCTS, CTS|RTS },
323 { CRTSCTS, CCTS_OFLOW, CTS },
324 { CRTSCTS, CRTS_IFLOW, RTS },
328 /* xlat bsd termios flags to dgm sys-v style */
330 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
335 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
336 if ((input & tbl[i].in_mask) == tbl[i].in_val)
337 output |= tbl[i].out_val;
342 static int dgmdebug = 0;
343 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
345 static __inline int setwin(struct dgm_softc *, unsigned);
346 static __inline void hidewin(struct dgm_softc *);
347 static __inline void towin(struct dgm_softc *, int);
349 /*Helg: to allow recursive dgm...() calls */
351 /* If we were called and don't want to disturb we need: */
352 int port; /* write to this port */
353 u_char data; /* this data on exit */
354 /* or DATA_WINOFF to close memory window on entry */
355 } BoardMemWinState; /* so several channels and even boards can coexist */
357 #define DATA_WINOFF 0
358 static BoardMemWinState bmws;
360 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
361 static u_long validmem[] = {
362 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
363 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
364 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
365 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
366 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
369 /* return current memory window state and close window */
370 static BoardMemWinState
373 BoardMemWinState bmwsRet = bmws;
375 if (bmws.data != DATA_WINOFF)
376 outb(bmws.port, bmws.data = DATA_WINOFF);
380 /* restore memory window state */
382 bmws_set(BoardMemWinState ws)
384 if (ws.data != bmws.data || ws.port != bmws.port) {
385 if (bmws.data != DATA_WINOFF)
386 outb(bmws.port, DATA_WINOFF);
387 if (ws.data != DATA_WINOFF)
388 outb(ws.port, ws.data);
394 setwin(struct dgm_softc *sc, unsigned int addr)
396 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
397 return (addr & 0x7FFF);
401 hidewin(struct dgm_softc *sc)
404 outb(bmws.port = sc->port + 1, bmws.data);
408 towin(struct dgm_softc *sc, int win)
410 outb(bmws.port = sc->port + 1, bmws.data = win);
414 dgmprobe(device_t dev)
416 struct dgm_softc *sc = device_get_softc(dev);
420 * Assign unit number. Due to bits we use in the minor number for
421 * the various tty types, only 4 units are supported.
423 sc->unit = device_get_unit(dev);
425 device_printf(dev, "Too many units, only 4 supported\n");
429 /* Check that we've got a valid i/o address */
430 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
432 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
433 if (sc->port == validio[i])
436 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
440 /* Ditto for our memory address */
441 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
443 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
444 if (sc->pmem == validmem[i])
447 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
450 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
451 device_printf(dev, "0x%lx: Memory address not supported\n",
455 sc->vmem = (u_char *)sc->pmem;
457 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
460 /* Temporarily map our io ports */
462 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
463 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
464 if (sc->io_res == NULL)
467 outb(sc->port, FEPRST);
470 for (i = 0; i < 1000; i++) {
472 if ((inb(sc->port) & FEPMASK) == FEPRST) {
474 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
481 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
482 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
486 /* check type of card and get internal memory characteristics */
494 second = inb(sc->port);
495 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
497 printf("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);
571 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
574 outb(sc->port, FEPRST);
577 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
579 device_printf(dev, "1st reset failed\n");
582 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
583 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
589 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
591 t = sc->pmem >> 8; /* disable windowing */
592 outb(sc->port + 2, t & 0xFF);
593 outb(sc->port + 3, t >> 8);
597 /* very short memory test */
598 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
600 addr = setwin(sc, BOTWIN);
601 *(u_long *)(mem + addr) = 0xA55A3CC3;
602 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
603 device_printf(dev, "1st memory test failed\n");
606 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
607 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
611 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
613 addr = setwin(sc, TOPWIN);
614 *(u_long *)(mem + addr) = 0x5AA5C33C;
615 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
616 device_printf(dev, "2nd memory test failed\n");
619 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
620 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
624 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
626 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
627 *(u_long *)(mem + addr) = 0x5AA5C33C;
628 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
629 device_printf(dev, "3rd (BIOS) memory test failed\n");
631 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
633 addr = setwin(sc, MISCGLOBAL);
634 for (i = 0; i < 16; i++)
637 addr = setwin(sc, BIOSOFFSET);
639 for (i = 0; ptr < mem + msize; i++)
640 *ptr++ = pcem_bios[i];
642 ptr = mem + BIOSOFFSET;
643 for (i = 0; ptr < mem + msize; i++) {
644 if (*ptr++ != pcem_bios[i]) {
645 printf("Low BIOS load failed\n");
648 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
649 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
653 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
655 addr = setwin(sc, msize);
657 for (;i < pcem_nbios; i++)
658 *ptr++ = pcem_bios[i];
661 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
662 if (*ptr++ != pcem_bios[i]) {
663 printf("High BIOS load failed\n");
666 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
667 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
671 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
672 device_printf(dev, "DigiBIOS loaded, initializing");
674 addr = setwin(sc, 0);
676 *(u_int *)(mem + addr) = 0x0bf00401;
677 *(u_int *)(mem + addr + 4) = 0;
678 *(ushort *)(mem + addr + 0xc00) = 0;
681 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
684 printf("\nBIOS initialize failed(1)\n");
687 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
688 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
693 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
694 printf("\nBIOS initialize failed(2)\n");
697 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
698 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
701 printf(", DigiBIOS running\n");
705 addr = setwin(sc, BIOSOFFSET);
707 for (i = 0; i < pcem_ncook; i++)
708 *ptr++ = pcem_cook[i];
710 ptr = mem + BIOSOFFSET;
711 for (i = 0; i < pcem_ncook; i++) {
712 if (*ptr++ != pcem_cook[i]) {
713 printf("FEP/OS load failed\n");
716 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
717 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
721 device_printf(dev, "FEP/OS loaded, initializing");
723 addr = setwin(sc, 0);
724 *(ushort *)(mem + addr + 0xd20) = 0;
725 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
726 *(u_int *)(mem + addr + 0xc30) = 0x3L;
729 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
732 printf("\nFEP/OS initialize failed(1)\n");
735 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
736 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
741 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
742 printf("\nFEP/OS initialize failed(2)\n");
745 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
746 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
749 printf(", FEP/OS running\n");
751 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
752 device_printf(dev, "%d ports attached\n", sc->numports);
754 if (sc->numports > MAX_DGM_PORTS) {
755 printf("dgm%d: too many ports\n", sc->unit);
758 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
759 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
763 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
764 M_TTYS, M_WAITOK|M_ZERO);
765 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
766 M_TTYS, M_WAITOK|M_ZERO);
768 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
769 for (i = 0; i < sc->numports; i++) {
770 sc->ports[i].enabled = 1;
771 callout_init(&sc->ports[i].hc_timeout);
772 callout_init(&sc->ports[i].wf_timeout);
775 /* We should now init per-port structures */
777 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
778 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
780 if (sc->numports < 3)
785 dev_ops_add(&dgm_ops, DGM_UNITMASK, DGM_UNIT(sc->unit));
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(&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);
918 dgmshutdown(device_t dev)
921 struct dgm_softc *sc = device_get_softc(dev);
923 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
931 dgmopen(struct dev_open_args *ap)
933 cdev_t dev = ap->a_head.a_dev;
934 struct dgm_softc *sc;
941 volatile struct board_chan *bc;
945 unit = MINOR_TO_UNIT(mynor);
946 pnum = MINOR_TO_PORT(mynor);
948 sc = devclass_get_softc(dgmdevclass, unit);
950 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
955 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
958 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
963 if (pnum >= sc->numports) {
964 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
969 if (mynor & CONTROL_MASK)
972 tp = &sc->ttys[pnum];
974 port = &sc->ports[pnum];
980 while (port->closing) {
981 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
984 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
985 " error = %d\n", unit, pnum, error);
990 if (tp->t_state & TS_ISOPEN) {
992 * The device is open, so everything has been initialized.
995 if (mynor & CALLOUT_MASK) {
996 if (!port->active_out) {
998 DPRINT4(DB_OPEN, "dgm%d: port%d:"
999 " BUSY error = %d\n", unit, pnum, error);
1002 } else if (port->active_out) {
1003 if (ap->a_oflags & O_NONBLOCK) {
1005 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1006 " BUSY error = %d\n", unit, pnum, error);
1009 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1011 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1012 " error = %d\n", unit, pnum, error);
1018 if (tp->t_state & TS_XCLUDE && suser_cred(ap->a_cred, 0)) {
1024 * The device isn't open, so there are no conflicts.
1025 * Initialize it. Initialization is done twice in many
1026 * cases: to preempt sleeping callin opens if we are
1027 * callout, and to complete a callin open after DCD rises.
1029 tp->t_oproc = dgmstart;
1030 tp->t_param = dgmparam;
1031 tp->t_stop = dgmstop;
1033 tp->t_termios= (mynor & CALLOUT_MASK) ?
1039 port->imodem = bc->mstat;
1040 bc->rout = bc->rin; /* clear input queue */
1042 #ifdef PRINT_BUFSIZE
1043 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1044 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1051 error = dgmparam(tp, &tp->t_termios);
1055 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1060 /* handle fake DCD for callout devices */
1061 /* and initial DCD */
1063 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1064 linesw[tp->t_line].l_modem(tp, 1);
1068 * Wait for DCD if necessary.
1070 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1071 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1073 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1076 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1077 " error = %d\n", unit, pnum, error);
1083 error = linesw[tp->t_line].l_open(dev, tp);
1084 disc_optim(tp, &tp->t_termios);
1085 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1088 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1089 port->active_out = 1;
1093 /* If any port is open (i.e. the open() call is completed for it)
1094 * the device is busy
1098 disc_optim(tp, &tp->t_termios);
1101 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1104 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1112 dgmclose(struct dev_close_args *ap)
1114 cdev_t dev = ap->a_head.a_dev;
1118 struct dgm_softc *sc;
1123 if (mynor & CONTROL_MASK)
1125 unit = MINOR_TO_UNIT(mynor);
1126 pnum = MINOR_TO_PORT(mynor);
1128 sc = devclass_get_softc(dgmdevclass, unit);
1129 tp = &sc->ttys[pnum];
1130 port = sc->ports + pnum;
1132 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1134 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1135 dgm_drain_or_flush(port);
1140 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1141 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1142 disc_optim(tp, &tp->t_termios);
1144 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1146 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1149 wakeup(&port->closing);
1152 /* mark the card idle when all ports are closed */
1154 for (i = 0; i < sc->numports; i++)
1155 if (sc->ports[i].used)
1160 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1162 wakeup(TSA_CARR_ON(tp));
1163 wakeup(&port->active_out);
1164 port->active_out = 0;
1166 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1172 dgmhardclose(struct dgm_p *port)
1174 volatile struct board_chan *bc = port->brdchan;
1175 struct dgm_softc *sc;
1177 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1178 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1180 port->do_timestamp = 0;
1186 if (port->tty->t_cflag & HUPCL) {
1187 port->omodem &= ~(RTS|DTR);
1188 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1194 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1195 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1199 dgm_pause(void *chan)
1201 wakeup((caddr_t)chan);
1205 dgmpoll(void *unit_c)
1207 int unit = (int)unit_c;
1210 struct dgm_softc *sc;
1213 int event, mstat, lstat;
1214 volatile struct board_chan *bc;
1221 int ibuf_full, obuf_full;
1222 BoardMemWinState ws = bmws_get();
1224 sc = devclass_get_softc(dgmdevclass, unit);
1225 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1228 printf("dgm%d: polling of disabled board stopped\n", unit);
1234 head = sc->mailbox->ein;
1235 tail = sc->mailbox->eout;
1237 while (head != tail) {
1238 if (head >= FEP_IMAX - FEP_ISTART
1239 || tail >= FEP_IMAX - FEP_ISTART
1240 || (head|tail) & 03 ) {
1241 printf("dgm%d: event queue's head or tail is wrong!"
1242 " hd = %d, tl = %d\n", unit, head, tail);
1246 eventbuf = sc->vmem + tail + FEP_ISTART;
1248 event = eventbuf[1];
1249 mstat = eventbuf[2];
1250 lstat = eventbuf[3];
1252 port = &sc->ports[pnum];
1254 tp = &sc->ttys[pnum];
1256 if (pnum >= sc->numports || !port->enabled) {
1257 printf("dgm%d: port%d: got event on nonexisting port\n",
1259 } else if (port->used || port->wopeners > 0 ) {
1261 int wrapmask = port->rxbufsize - 1;
1263 if (!(event & ALL_IND))
1264 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1265 unit, pnum, event, mstat, lstat);
1267 if (event & DATA_IND) {
1268 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1271 rhead = bc->rin & wrapmask;
1272 rtail = bc->rout & wrapmask;
1274 if (!(tp->t_cflag & CREAD) || !port->used ) {
1280 printf("dgm%d: port%d: overrun\n", unit, pnum);
1284 if (!(tp->t_state & TS_ISOPEN))
1287 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1288 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1289 " p rx head = %d tail = %d\n", unit,
1290 pnum, rhead, rtail);
1293 size = rhead - rtail;
1295 size = port->rxbufsize - rtail;
1297 ptr = port->rxptr + rtail;
1300 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1301 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1302 DPRINT1(DB_RXDATA, "*");
1307 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1308 DPRINT1(DB_RXDATA, "!");
1309 towin(sc, port->rxwin);
1312 tp->t_rawcc += size;
1320 towin(sc, port->rxwin);
1323 (*linesw[tp->t_line].l_rint)(chr, tp);
1328 rtail= (rtail + size) & wrapmask;
1330 rhead = bc->rin & wrapmask;
1338 if (event & MODEMCHG_IND) {
1339 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1340 "MODEMCHG_IND\n", unit, pnum);
1341 port->imodem = mstat;
1342 if (mstat & port->dcd) {
1344 linesw[tp->t_line].l_modem(tp, 1);
1346 wakeup(TSA_CARR_ON(tp));
1349 linesw[tp->t_line].l_modem(tp, 0);
1351 if (port->draining) {
1353 wakeup(&port->draining);
1358 if (event & BREAK_IND) {
1359 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1360 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1361 " BREAK_IND\n", unit, pnum);
1363 linesw[tp->t_line].l_rint(TTY_BI, tp);
1368 /* Helg: with output flow control */
1370 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1371 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1372 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1374 if ((event & EMPTYTX_IND ) &&
1375 tp->t_outq.c_cc == 0 && port->draining) {
1377 wakeup(&port->draining);
1382 int wrapmask = port->txbufsize - 1;
1384 for (obuf_full = FALSE;
1385 tp->t_outq.c_cc != 0 && !obuf_full;
1387 /* add "last-minute" data to write buffer */
1388 if (!(tp->t_state & TS_BUSY)) {
1390 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1393 if (tp->t_outq.c_cc <= tp->t_lowat) {
1394 if (tp->t_state & TS_ASLEEP) {
1395 tp->t_state &= ~TS_ASLEEP;
1396 wakeup(TSA_OLOWAT(tp));
1398 /* selwakeup(&tp->t_wsel); */
1405 whead = bc->tin & wrapmask;
1406 wtail = bc->tout & wrapmask;
1409 size = wtail - whead - 1;
1411 size = port->txbufsize - whead;
1417 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1418 whead, wtail, size, obuf_full);
1426 towin(sc, port->txwin);
1428 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1433 bc->tin = whead & wrapmask;
1438 DPRINT1(DB_WR, " +BUSY\n");
1439 tp->t_state |= TS_BUSY;
1441 DPRINT1(DB_WR, " -BUSY\n");
1443 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1444 /* should clear TS_BUSY before ttwwakeup */
1445 if (tp->t_state & TS_BUSY) {
1446 tp->t_state &= ~TS_BUSY;
1447 linesw[tp->t_line].l_start(tp);
1451 if (tp->t_state & TS_ASLEEP) {
1452 tp->t_state &= ~TS_ASLEEP;
1453 wakeup(TSA_OLOWAT(tp));
1455 tp->t_state &= ~TS_BUSY;
1461 bc->idata = 1; /* require event on incoming data */
1465 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1468 bc->idata = bc->iempty = bc->ilow = 0;
1471 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1474 sc->mailbox->eout = tail;
1477 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1479 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1483 dgmioctl(struct dev_ioctl_args *ap)
1485 cdev_t dev = ap->a_head.a_dev;
1486 u_long cmd = ap->a_cmd;
1487 caddr_t data = ap->a_data;
1488 struct dgm_softc *sc;
1493 volatile struct board_chan *bc;
1497 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1499 struct termios term;
1502 BoardMemWinState ws = bmws_get();
1505 unit = MINOR_TO_UNIT(mynor);
1506 pnum = MINOR_TO_PORT(mynor);
1508 sc = devclass_get_softc(dgmdevclass, unit);
1509 port = &sc->ports[pnum];
1510 tp = &sc->ttys[pnum];
1513 if (mynor & CONTROL_MASK) {
1516 switch (mynor & CONTROL_MASK) {
1517 case CONTROL_INIT_STATE:
1518 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1520 case CONTROL_LOCK_STATE:
1521 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1524 return (ENODEV); /* /dev/nodev */
1528 error = suser_cred(ap->a_cred, 0);
1531 *ct = *(struct termios *)data;
1534 *(struct termios *)data = *ct;
1537 *(int *)data = TTYDISC;
1540 bzero(data, sizeof(struct winsize));
1547 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1548 term = tp->t_termios;
1549 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1550 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);
1553 error = ttsetcompat(tp, &cmd, data, &term);
1557 data = (caddr_t)&term;
1560 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1562 struct termios *dt = (struct termios *)data;
1563 struct termios *lt = mynor & CALLOUT_MASK
1564 ? &port->lt_out : &port->lt_in;
1566 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);
1567 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1568 | (dt->c_iflag & ~lt->c_iflag);
1569 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1570 | (dt->c_oflag & ~lt->c_oflag);
1571 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1572 | (dt->c_cflag & ~lt->c_cflag);
1573 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1574 | (dt->c_lflag & ~lt->c_lflag);
1575 for (cc = 0; cc < NCCS; ++cc)
1576 if (lt->c_cc[cc] != 0)
1577 dt->c_cc[cc] = tp->t_cc[cc];
1578 if (lt->c_ispeed != 0)
1579 dt->c_ispeed = tp->t_ispeed;
1580 if (lt->c_ospeed != 0)
1581 dt->c_ospeed = tp->t_ospeed;
1584 if (cmd == TIOCSTOP) {
1587 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1591 } else if (cmd == TIOCSTART) {
1594 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1600 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1601 port->mustdrain = 1;
1603 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1604 ap->a_fflag, ap->a_cred);
1605 if (error != ENOIOCTL)
1608 error = ttioctl(tp, cmd, data, ap->a_fflag);
1609 disc_optim(tp, &tp->t_termios);
1610 port->mustdrain = 0;
1611 if (error != ENOIOCTL) {
1613 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1614 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);
1622 error = dgmdrain(port);
1633 /* now it sends 400 millisecond break because I don't know */
1634 /* how to send an infinite break */
1636 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1641 /* now it's empty */
1644 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1645 port->omodem |= DTR;
1648 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1650 if (!(bc->mstat & DTR))
1651 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1657 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1658 port->omodem &= ~DTR;
1661 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1663 if (bc->mstat & DTR) {
1664 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1671 if (*(int *)data & TIOCM_DTR)
1672 port->omodem |= DTR;
1674 port->omodem &= ~DTR;
1676 if (*(int *)data & TIOCM_RTS)
1677 port->omodem |= RTS;
1679 port->omodem &= ~RTS;
1683 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1688 if (*(int *)data & TIOCM_DTR)
1689 port->omodem |= DTR;
1691 if (*(int *)data & TIOCM_RTS)
1692 port->omodem |= RTS;
1696 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1701 if (*(int *)data & TIOCM_DTR)
1702 port->omodem &= ~DTR;
1704 if (*(int *)data & TIOCM_RTS)
1705 port->omodem &= ~RTS;
1709 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1715 port->imodem = bc->mstat;
1718 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1720 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1722 if (port->imodem & DTR) {
1723 DPRINT1(DB_MODEM, "DTR ");
1724 tiocm_xxx |= TIOCM_DTR;
1726 if (port->imodem & RTS) {
1727 DPRINT1(DB_MODEM, "RTS ");
1728 tiocm_xxx |= TIOCM_RTS;
1730 if (port->imodem & CTS) {
1731 DPRINT1(DB_MODEM, "CTS ");
1732 tiocm_xxx |= TIOCM_CTS;
1734 if (port->imodem & port->dcd) {
1735 DPRINT1(DB_MODEM, "DCD ");
1736 tiocm_xxx |= TIOCM_CD;
1738 if (port->imodem & port->dsr) {
1739 DPRINT1(DB_MODEM, "DSR ");
1740 tiocm_xxx |= TIOCM_DSR;
1742 if (port->imodem & RI) {
1743 DPRINT1(DB_MODEM, "RI ");
1744 tiocm_xxx |= TIOCM_RI;
1746 *(int *)data = tiocm_xxx;
1747 DPRINT1(DB_MODEM, "--\n");
1750 /* must be root since the wait applies to following logins */
1751 error = suser_cred(ap->a_cred, 0);
1756 port->close_delay = *(int *)data * hz / 100;
1759 *(int *)data = port->close_delay * 100 / hz;
1762 port->do_timestamp = 1;
1763 *(struct timeval *)data = port->timestamp;
1765 case TIOCDCDTIMESTAMP:
1766 port->do_dcd_timestamp = 1;
1767 *(struct timeval *)data = port->dcd_timestamp;
1783 struct dgm_p *port = p;
1785 wakeup(&port->draining);
1788 /* wait for the output to drain */
1791 dgmdrain(struct dgm_p *port)
1793 volatile struct board_chan *bc = port->brdchan;
1794 struct dgm_softc *sc;
1797 BoardMemWinState ws = bmws_get();
1799 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1807 while (tail != head) {
1808 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1809 port->sc->unit, port->pnum, head, tail);
1813 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1814 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1819 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1820 port->sc->unit, port->pnum, error);
1830 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1831 port->sc->unit, port->pnum, head, tail);
1836 /* wait for the output to drain */
1837 /* or simply clear the buffer it it's stopped */
1840 dgm_drain_or_flush(struct dgm_p *port)
1842 volatile struct board_chan *bc = port->brdchan;
1843 struct tty *tp = port->tty;
1844 struct dgm_softc *sc;
1849 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1857 while (tail != head /* && tail != lasttail */ ) {
1858 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1859 port->sc->unit, port->pnum, head, tail);
1861 /* if there is no carrier simply clean the buffer */
1862 if (!(tp->t_state & TS_CARR_ON)) {
1863 bc->tout = bc->tin = 0;
1871 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1872 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1877 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1878 " error = %d\n", port->sc->unit, port->pnum, error);
1880 /* silently clean the buffer */
1882 bc->tout = bc->tin = 0;
1893 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1894 port->sc->unit, port->pnum, head, tail);
1898 dgmparam(struct tty *tp, struct termios *t)
1900 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1901 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1902 volatile struct board_chan *bc;
1903 struct dgm_softc *sc;
1910 BoardMemWinState ws = bmws_get();
1912 sc = devclass_get_softc(dgmdevclass, unit);
1913 port = &sc->ports[pnum];
1916 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);
1918 if (port->mustdrain) {
1919 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1923 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1925 if (t->c_ispeed == 0)
1926 t->c_ispeed = t->c_ospeed;
1928 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1929 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1936 if (cflag == 0) { /* hangup */
1937 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1941 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1942 mval= port->omodem & ~(DTR|RTS);
1944 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1946 if (cflag != port->fepcflag) {
1947 port->fepcflag = cflag;
1948 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1949 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1950 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1952 mval= port->omodem | (DTR|RTS);
1955 iflag = dgmflags(dgm_iflags, t->c_iflag);
1956 if (iflag != port->fepiflag) {
1957 port->fepiflag = iflag;
1958 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1959 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1962 bc->mint = port->dcd;
1964 hflow = dgmflags(dgm_flow, t->c_cflag);
1965 if (hflow != port->hflow) {
1966 port->hflow = hflow;
1967 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1968 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1971 if (port->omodem != mval) {
1972 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1973 unit, pnum, mval, port->omodem);
1974 port->omodem = mval;
1975 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1978 if (port->fepstartc != t->c_cc[VSTART] ||
1979 port->fepstopc != t->c_cc[VSTOP]) {
1980 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1981 port->fepstartc = t->c_cc[VSTART];
1982 port->fepstopc = t->c_cc[VSTOP];
1983 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1994 dgmstart(struct tty *tp)
1999 struct dgm_softc *sc;
2000 volatile struct board_chan *bc;
2005 BoardMemWinState ws = bmws_get();
2007 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2008 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2009 sc = devclass_get_softc(dgmdevclass, unit);
2010 port = &sc->ports[pnum];
2013 wmask = port->txbufsize - 1;
2017 while (tp->t_outq.c_cc != 0) {
2018 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2021 if (tp->t_outq.c_cc <= tp->t_lowat) {
2022 if (tp->t_state & TS_ASLEEP) {
2023 tp->t_state &= ~TS_ASLEEP;
2024 wakeup(TSA_OLOWAT(tp));
2026 /*selwakeup(&tp->t_wsel);*/
2032 head = bc->tin & wmask;
2034 do { tail = bc->tout; } while (tail != bc->tout);
2035 tail = bc->tout & wmask;
2037 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2039 #ifdef LEAVE_FREE_CHARS
2041 size = tail - head - LEAVE_FREE_CHARS;
2045 size = port->txbufsize - head;
2046 if (tail + port->txbufsize < head)
2052 size = tail - head - 1;
2054 size = port->txbufsize - head;
2065 tp->t_state |= TS_BUSY;
2070 towin(sc, port->txwin);
2072 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2074 if (head >= port->txbufsize)
2075 head -= port->txbufsize;
2080 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2081 unit, pnum, size, ocount);
2089 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2090 if (tp->t_state & TS_BUSY) {
2091 tp->t_state &= ~TS_BUSY;
2092 linesw[tp->t_line].l_start(tp);
2096 if (tp->t_state & TS_ASLEEP) {
2097 tp->t_state &= ~TS_ASLEEP;
2098 wakeup(TSA_OLOWAT(tp));
2100 tp->t_state& = ~TS_BUSY;
2105 dgmstop(struct tty *tp, int rw)
2110 struct dgm_softc *sc;
2111 volatile struct board_chan *bc;
2113 BoardMemWinState ws = bmws_get();
2115 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2116 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2118 sc = devclass_get_softc(dgmdevclass, unit);
2119 port = &sc->ports[pnum];
2122 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2128 /* clear output queue */
2129 bc->tout = bc->tin = 0;
2134 /* clear input queue */
2145 fepcmd(struct dgm_p *port,
2153 unsigned tail, head;
2156 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2157 mem = port->sc->vmem;
2159 if (!port->enabled) {
2160 printf("dgm%d: port%d: FEP command on disabled port\n",
2161 port->sc->unit, port->pnum);
2165 /* setwin(port->sc, 0); Require this to be set by caller */
2166 head = port->sc->mailbox->cin;
2168 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2169 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2170 port->sc->unit, port->pnum, head);
2174 mem[head + FEP_CSTART] = cmd;
2175 mem[head + FEP_CSTART + 1] = port->pnum;
2177 mem[head + FEP_CSTART + 2] = op1;
2178 mem[head + FEP_CSTART + 3] = op2;
2180 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2181 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2184 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2185 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2187 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2188 port->sc->mailbox->cin = head;
2192 while (count-- != 0) {
2193 head = port->sc->mailbox->cin;
2194 tail = port->sc->mailbox->cout;
2196 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2197 if (n <= ncmds * (sizeof(ushort)*4))
2200 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2204 disc_optim(struct tty *tp, struct termios *t)
2206 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2207 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2208 && (!(t->c_iflag & PARMRK)
2209 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2210 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2211 && linesw[tp->t_line].l_rint == ttyinput)
2212 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2214 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;