2 * $FreeBSD: src/sys/dev/dgb/dgm.c,v 1.31.2.3 2001/10/07 09:02:25 brian Exp $
3 * $DragonFly: src/sys/dev/serial/dgb/dgm.c,v 1.17 2008/04/30 17:28:16 dillon Exp $
5 * This driver and the associated header files support the ISA PC/Xem
6 * Digiboards. Its evolutionary roots are described below.
7 * Jack O'Neill <jack@diamond.xtalwind.net>
11 * Stage 1. "Better than nothing".
12 * Stage 2. "Gee, it works!".
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions, and the following disclaimer,
19 * without modification, immediately at the beginning of the file.
20 * 2. Redistributions of binary code must retain the above copyright
21 * notice, this list of conditions, and the following disclaimer,
22 * without modification, in the accompanying documentation.
23 * 3. The name of the author may not be used to endorse or promote products
24 * derived from this software without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * Written by Sergey Babkin,
39 * Joint Stock Commercial Bank "Chelindbank"
40 * (Chelyabinsk, Russia)
43 * Assorted hacks to make it more functional and working under 3.0-current.
44 * Fixed broken routines to prevent processes hanging on closed (thanks
45 * to Bruce for his patience and assistance). Thanks also to Maxim Bolotin
46 * <max@run.net> for his patches which did most of the work to get this
47 * running under 2.2/3.0-current.
48 * Implemented ioctls: TIOCMSDTRWAIT, TIOCMGDTRWAIT, TIOCTIMESTAMP &
50 * Sysctl debug flag is now a bitflag, to filter noise during debugging.
51 * David L. Nugent <davidn@blaze.net.au>
53 * New-busification by Brian Somers <brian@Awfulhak.org>
55 * There was a copyright confusion: I thought that having read the
56 * GLPed drivers makes me mentally contaminated but in fact it does
57 * not. Since the Linux driver by Troy De Jongh <troyd@digibd.com> or
58 * <troyd@skypoint.com> was used only to learn the Digi's interface,
59 * I've returned this driver to a BSD-style license. I tried to contact
60 * all the contributors and those who replied agreed with license
61 * change. If you did any contribution when the driver was GPLed and do
62 * not agree with the BSD-style re-licensing please contact me.
66 /* How often to run dgmpoll */
67 #define POLLSPERSEC 25
69 /* How many charactes can we write to input tty rawq */
70 #define DGB_IBUFSIZE (TTYHOG - 100)
72 /* the overall number of ports controlled by this driver */
74 #include <sys/param.h>
76 #include <sys/systm.h>
80 #include <sys/dkstat.h>
81 #include <sys/fcntl.h>
82 #include <sys/kernel.h>
83 #include <sys/sysctl.h>
84 #include <sys/malloc.h>
85 #include <sys/sysctl.h>
91 #include <sys/thread2.h>
93 #include <machine/clock.h>
102 #define CALLOUT_MASK 0x40000
103 #define CONTROL_MASK 0xC0
104 #define CONTROL_INIT_STATE 0x40
105 #define CONTROL_LOCK_STATE 0x80
106 #define UNIT_MASK 0x30000
107 #define PORT_MASK 0x3F
108 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
109 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
110 #define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK) >> 16)
111 #define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK)
113 #define MEM_SIZE 0x8000
115 #define DGM_UNITMASK 0x30000
116 #define DGM_UNIT(unit) ((unit) << 16)
120 /* digiboard port structure */
122 unsigned enabled : 1;
124 struct dgm_softc *sc; /* parent softc */
125 u_char pnum; /* port number */
126 u_char omodem; /* FEP output modem status */
127 u_char imodem; /* FEP input modem status */
128 u_char modemfake; /* Modem values to be forced */
129 u_char modem; /* Force values */
153 volatile struct board_chan *brdchan;
156 u_char active_out; /* nonzero if the callout device is open */
157 u_int wopeners; /* # processes waiting for DCD in open() */
160 struct termios it_in; /* should be in struct tty */
161 struct termios it_out;
164 struct termios lt_in; /* should be in struct tty */
165 struct termios lt_out;
167 unsigned do_timestamp : 1;
168 unsigned do_dcd_timestamp : 1;
169 struct timeval timestamp;
170 struct timeval dcd_timestamp;
172 /* flags of state, are used in sleep() too */
173 u_char closing; /* port is being closed now */
174 u_char draining; /* port is being drained now */
175 u_char used; /* port is being used now */
176 u_char mustdrain; /* data must be waited to drain in dgmparam() */
178 struct callout hc_timeout;
179 struct callout wf_timeout;
182 /* Digiboard per-board structure */
184 /* struct board_info */
185 unsigned enabled : 1;
186 u_char unit; /* unit number */
187 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
188 u_char altpin; /* do we need alternate pin setting ? */
189 int numports; /* number of ports on card */
190 u_long port; /* I/O port */
191 u_char *vmem; /* virtual memory address */
192 u_long pmem; /* physical memory address */
193 int mem_seg; /* internal memory segment */
195 struct dgm_p *ports; /* ptr to array of port descriptors */
196 struct tty *ttys; /* ptr to array of TTY structures */
197 volatile struct global_data *mailbox;
198 struct resource *io_res;
199 struct resource *mem_res;
202 struct callout toh; /* poll timeout handle */
205 static void dgmpoll(void *);
206 static int dgmprobe(device_t);
207 static int dgmattach(device_t);
208 static int dgmdetach(device_t);
209 static int dgmshutdown(device_t);
210 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
212 static void dgmstart(struct tty *);
213 static void dgmstop(struct tty *, int);
214 static int dgmparam(struct tty *, struct termios *);
215 static void dgmhardclose(struct dgm_p *);
216 static void dgm_drain_or_flush(struct dgm_p *);
217 static int dgmdrain(struct dgm_p *);
218 static void dgm_pause(void *);
219 static void wakeflush(void *);
220 static void disc_optim(struct tty *, struct termios *);
222 static d_open_t dgmopen;
223 static d_close_t dgmclose;
224 static d_ioctl_t dgmioctl;
226 static device_method_t dgmmethods[] = {
227 /* Device interface */
228 DEVMETHOD(device_probe, dgmprobe),
229 DEVMETHOD(device_attach, dgmattach),
230 DEVMETHOD(device_detach, dgmdetach),
231 DEVMETHOD(device_shutdown, dgmshutdown),
235 static driver_t dgmdriver = {
238 sizeof (struct dgm_softc),
241 static devclass_t dgmdevclass;
243 #define CDEV_MAJOR 101
244 static struct dev_ops dgm_ops = {
245 { "dgm", CDEV_MAJOR, D_TTY },
251 .d_kqfilter = ttykqfilter,
252 .d_revoke = ttyrevoke
256 dgmmodhandler(module_t mod, int event, void *arg)
270 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
272 static speed_t dgmdefaultrate = TTYDEF_SPEED;
274 static struct speedtab dgmspeedtab[] = {
275 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
289 { 19200, FEP_B19200 },
290 { 38400, FEP_B38400 },
291 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
292 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
296 static struct dbgflagtbl {
301 { PARODD, PARODD, FEP_PARODD },
302 { PARENB, PARENB, FEP_PARENB },
303 { CSTOPB, CSTOPB, FEP_CSTOPB },
304 { CSIZE, CS5, FEP_CS6 },
305 { CSIZE, CS6, FEP_CS6 },
306 { CSIZE, CS7, FEP_CS7 },
307 { CSIZE, CS8, FEP_CS8 },
308 { CLOCAL, CLOCAL, FEP_CLOCAL },
311 { IGNBRK, IGNBRK, FEP_IGNBRK },
312 { BRKINT, BRKINT, FEP_BRKINT },
313 { IGNPAR, IGNPAR, FEP_IGNPAR },
314 { PARMRK, PARMRK, FEP_PARMRK },
315 { INPCK, INPCK, FEP_INPCK },
316 { ISTRIP, ISTRIP, FEP_ISTRIP },
317 { IXON, IXON, FEP_IXON },
318 { IXOFF, IXOFF, FEP_IXOFF },
319 { IXANY, IXANY, FEP_IXANY },
322 { CRTSCTS, CRTSCTS, CTS|RTS },
323 { CRTSCTS, CCTS_OFLOW, CTS },
324 { CRTSCTS, CRTS_IFLOW, RTS },
328 /* xlat bsd termios flags to dgm sys-v style */
330 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
335 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
336 if ((input & tbl[i].in_mask) == tbl[i].in_val)
337 output |= tbl[i].out_val;
342 static int dgmdebug = 0;
343 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
345 static __inline int setwin(struct dgm_softc *, unsigned);
346 static __inline void hidewin(struct dgm_softc *);
347 static __inline void towin(struct dgm_softc *, int);
349 /*Helg: to allow recursive dgm...() calls */
351 /* If we were called and don't want to disturb we need: */
352 int port; /* write to this port */
353 u_char data; /* this data on exit */
354 /* or DATA_WINOFF to close memory window on entry */
355 } BoardMemWinState; /* so several channels and even boards can coexist */
357 #define DATA_WINOFF 0
358 static BoardMemWinState bmws;
360 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
361 static u_long validmem[] = {
362 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
363 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
364 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
365 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
366 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
369 /* return current memory window state and close window */
370 static BoardMemWinState
373 BoardMemWinState bmwsRet = bmws;
375 if (bmws.data != DATA_WINOFF)
376 outb(bmws.port, bmws.data = DATA_WINOFF);
380 /* restore memory window state */
382 bmws_set(BoardMemWinState ws)
384 if (ws.data != bmws.data || ws.port != bmws.port) {
385 if (bmws.data != DATA_WINOFF)
386 outb(bmws.port, DATA_WINOFF);
387 if (ws.data != DATA_WINOFF)
388 outb(ws.port, ws.data);
394 setwin(struct dgm_softc *sc, unsigned int addr)
396 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
397 return (addr & 0x7FFF);
401 hidewin(struct dgm_softc *sc)
404 outb(bmws.port = sc->port + 1, bmws.data);
408 towin(struct dgm_softc *sc, int win)
410 outb(bmws.port = sc->port + 1, bmws.data = win);
414 dgmprobe(device_t dev)
416 struct dgm_softc *sc = device_get_softc(dev);
420 * Assign unit number. Due to bits we use in the minor number for
421 * the various tty types, only 4 units are supported.
423 sc->unit = device_get_unit(dev);
425 device_printf(dev, "Too many units, only 4 supported\n");
429 /* Check that we've got a valid i/o address */
430 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
432 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
433 if (sc->port == validio[i])
436 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
440 /* Ditto for our memory address */
441 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
443 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
444 if (sc->pmem == validmem[i])
447 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
450 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
451 device_printf(dev, "0x%lx: Memory address not supported\n",
455 sc->vmem = (u_char *)sc->pmem;
457 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
460 /* Temporarily map our io ports */
462 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
463 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
464 if (sc->io_res == NULL)
467 lwkt_gettoken(&tty_token);
468 outb(sc->port, FEPRST);
471 for (i = 0; i < 1000; i++) {
473 if ((inb(sc->port) & FEPMASK) == FEPRST) {
475 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
482 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
483 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
484 lwkt_reltoken(&tty_token);
488 /* check type of card and get internal memory characteristics */
496 second = inb(sc->port);
497 kprintf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
499 kprintf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
502 sc->mem_seg = 0x8000;
504 /* Temporarily map our memory too */
506 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
507 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
508 if (sc->mem_res == NULL) {
509 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
510 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
511 lwkt_reltoken(&tty_token);
515 outb(sc->port, FEPCLR); /* drop RESET */
516 hidewin(sc); /* Helg: to set initial bmws state */
518 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
519 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
521 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
522 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
524 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
526 lwkt_reltoken(&tty_token);
531 dgmattach(device_t dev)
533 struct dgm_softc *sc = device_get_softc(dev);
539 volatile struct board_chan *bc;
542 u_long msize, iosize;
544 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
546 lwkt_gettoken(&tty_token);
547 callout_init_mp(&sc->toh);
548 sc->unit = device_get_unit(dev);
549 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
550 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
551 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
553 sc->mem_seg = 0x8000;
556 sc->mem_seg = 0x8000;
558 /* Allocate resources (should have been verified in dgmprobe()) */
560 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
561 0ul, ~0ul, iosize, RF_ACTIVE);
562 if (sc->io_res == NULL) {
563 lwkt_reltoken(&tty_token);
567 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
568 0ul, ~0ul, msize, RF_ACTIVE);
569 if (sc->mem_res == NULL) {
570 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
571 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
572 lwkt_reltoken(&tty_token);
577 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
580 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
583 outb(sc->port, FEPRST);
586 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
588 device_printf(dev, "1st reset failed\n");
591 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
592 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
593 lwkt_reltoken(&tty_token);
599 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
601 t = sc->pmem >> 8; /* disable windowing */
602 outb(sc->port + 2, t & 0xFF);
603 outb(sc->port + 3, t >> 8);
607 /* very short memory test */
608 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
610 addr = setwin(sc, BOTWIN);
611 *(u_long *)(mem + addr) = 0xA55A3CC3;
612 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
613 device_printf(dev, "1st memory test failed\n");
616 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
617 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
618 lwkt_reltoken(&tty_token);
622 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
624 addr = setwin(sc, TOPWIN);
625 *(u_long *)(mem + addr) = 0x5AA5C33C;
626 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
627 device_printf(dev, "2nd memory test failed\n");
630 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
631 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
632 lwkt_reltoken(&tty_token);
636 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
638 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
639 *(u_long *)(mem + addr) = 0x5AA5C33C;
640 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
641 device_printf(dev, "3rd (BIOS) memory test failed\n");
643 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
645 addr = setwin(sc, MISCGLOBAL);
646 for (i = 0; i < 16; i++)
649 addr = setwin(sc, BIOSOFFSET);
651 for (i = 0; ptr < mem + msize; i++)
652 *ptr++ = pcem_bios[i];
654 ptr = mem + BIOSOFFSET;
655 for (i = 0; ptr < mem + msize; i++) {
656 if (*ptr++ != pcem_bios[i]) {
657 kprintf("Low BIOS load failed\n");
660 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
661 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
662 lwkt_reltoken(&tty_token);
666 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
668 addr = setwin(sc, msize);
670 for (;i < pcem_nbios; i++)
671 *ptr++ = pcem_bios[i];
674 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
675 if (*ptr++ != pcem_bios[i]) {
676 kprintf("High BIOS load failed\n");
679 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
680 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
681 lwkt_reltoken(&tty_token);
685 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
686 device_printf(dev, "DigiBIOS loaded, initializing");
688 addr = setwin(sc, 0);
690 *(u_int *)(mem + addr) = 0x0bf00401;
691 *(u_int *)(mem + addr + 4) = 0;
692 *(ushort *)(mem + addr + 0xc00) = 0;
695 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
698 kprintf("\nBIOS initialize failed(1)\n");
701 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
702 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
703 lwkt_reltoken(&tty_token);
708 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
709 kprintf("\nBIOS initialize failed(2)\n");
712 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
713 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
714 lwkt_reltoken(&tty_token);
717 kprintf(", DigiBIOS running\n");
721 addr = setwin(sc, BIOSOFFSET);
723 for (i = 0; i < pcem_ncook; i++)
724 *ptr++ = pcem_cook[i];
726 ptr = mem + BIOSOFFSET;
727 for (i = 0; i < pcem_ncook; i++) {
728 if (*ptr++ != pcem_cook[i]) {
729 kprintf("FEP/OS load failed\n");
732 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
733 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
734 lwkt_reltoken(&tty_token);
738 device_printf(dev, "FEP/OS loaded, initializing");
740 addr = setwin(sc, 0);
741 *(ushort *)(mem + addr + 0xd20) = 0;
742 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
743 *(u_int *)(mem + addr + 0xc30) = 0x3L;
746 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
749 kprintf("\nFEP/OS initialize failed(1)\n");
752 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
753 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
754 lwkt_reltoken(&tty_token);
759 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
760 kprintf("\nFEP/OS initialize failed(2)\n");
763 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
764 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
765 lwkt_reltoken(&tty_token);
768 kprintf(", FEP/OS running\n");
770 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
771 device_printf(dev, "%d ports attached\n", sc->numports);
773 if (sc->numports > MAX_DGM_PORTS) {
774 kprintf("dgm%d: too many ports\n", sc->unit);
777 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
778 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
779 lwkt_reltoken(&tty_token);
783 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
784 M_TTYS, M_WAITOK|M_ZERO);
785 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
786 M_TTYS, M_WAITOK|M_ZERO);
788 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
789 for (i = 0; i < sc->numports; i++) {
790 sc->ports[i].enabled = 1;
791 callout_init_mp(&sc->ports[i].hc_timeout);
792 callout_init_mp(&sc->ports[i].wf_timeout);
795 /* We should now init per-port structures */
797 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
798 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
800 if (sc->numports < 3)
805 for (i = 0; i < sc->numports; i++, bc++) {
806 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
807 port = &sc->ports[i];
810 port->tty = &sc->ttys[i];
818 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
820 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
821 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
825 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
826 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
827 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
828 port->txwin = FEPWIN | (bc->tseg >> 11);
829 port->rxwin = FEPWIN | (bc->rseg >> 11);
833 port->txbufsize = bc->tmax + 1;
834 port->rxbufsize = bc->rmax + 1;
836 lowwater = (port->txbufsize >= 2000) ?
837 1024 : (port->txbufsize / 2);
840 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
841 sc->unit, i, lowwater);
842 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
843 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
844 sc->unit, i, port->rxbufsize / 4);
845 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
846 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
847 sc->unit, i, 3 * port->rxbufsize / 4);
848 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
853 port->startc = bc->startc;
854 port->startca = bc->startca;
855 port->stopc = bc->stopc;
856 port->stopca = bc->stopca;
858 /* port->close_delay = 50; */
859 port->close_delay = 3 * hz;
860 port->do_timestamp = 0;
861 port->do_dcd_timestamp = 0;
863 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
865 * We don't use all the flags from <sys/ttydefaults.h> since
866 * they are only relevant for logins. It's important to have
867 * echo off initially so that the line doesn't start
868 * blathering before the echo flag can be turned off.
870 port->it_in.c_iflag = TTYDEF_IFLAG;
871 port->it_in.c_oflag = TTYDEF_OFLAG;
872 port->it_in.c_cflag = TTYDEF_CFLAG;
873 port->it_in.c_lflag = TTYDEF_LFLAG;
874 termioschars(&port->it_in);
875 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
876 port->it_out = port->it_in;
878 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
879 make_dev(&dgm_ops, (sc->unit*65536) + i, UID_ROOT,
880 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
881 make_dev(&dgm_ops, sc->unit * 65536 + i + 64, UID_ROOT,
882 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
883 make_dev(&dgm_ops, sc->unit * 65536 + i + 128, UID_ROOT,
884 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
885 make_dev(&dgm_ops, sc->unit * 65536 + i + 262144, UID_UUCP,
886 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
887 make_dev(&dgm_ops, sc->unit * 65536 + i + 262208, UID_UUCP,
888 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
889 make_dev(&dgm_ops, sc->unit * 65536 + i + 262272, UID_UUCP,
890 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
893 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
897 /* start the polling function */
898 callout_reset(&sc->toh, hz / POLLSPERSEC,
899 dgmpoll, (void *)(int)sc->unit);
901 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
903 lwkt_reltoken(&tty_token);
908 dgmdetach(device_t dev)
910 struct dgm_softc *sc = device_get_softc(dev);
913 lwkt_gettoken(&tty_token);
914 for (i = 0; i < sc->numports; i++) {
915 if (sc->ttys[i].t_state & TS_ISOPEN) {
916 lwkt_reltoken(&tty_token);
921 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
924 * The dev_ops_remove() call will destroy all associated devices
925 * and dereference any ad-hoc-created devices, but does not
926 * dereference devices created via make_dev().
928 dev_ops_remove_minor(&dgm_ops/*, DGM_UNITMASK*/, DGM_UNIT(sc->unit));
930 callout_stop(&sc->toh);
932 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
933 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
935 FREE(sc->ports, M_TTYS);
936 FREE(sc->ttys, M_TTYS);
939 pmap_unmapdev((vm_offset_t)sc->vmem, sc->msize);
943 lwkt_reltoken(&tty_token);
948 dgmshutdown(device_t dev)
951 struct dgm_softc *sc = device_get_softc(dev);
953 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
961 dgmopen(struct dev_open_args *ap)
963 cdev_t dev = ap->a_head.a_dev;
964 struct dgm_softc *sc;
971 volatile struct board_chan *bc;
973 lwkt_gettoken(&tty_token);
976 unit = MINOR_TO_UNIT(mynor);
977 pnum = MINOR_TO_PORT(mynor);
979 sc = devclass_get_softc(dgmdevclass, unit);
981 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
983 lwkt_reltoken(&tty_token);
987 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
990 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
992 lwkt_reltoken(&tty_token);
996 if (pnum >= sc->numports) {
997 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
999 lwkt_reltoken(&tty_token);
1003 if (mynor & CONTROL_MASK) {
1004 lwkt_reltoken(&tty_token);
1008 tp = &sc->ttys[pnum];
1010 port = &sc->ports[pnum];
1016 while (port->closing) {
1017 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
1020 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
1021 " error = %d\n", unit, pnum, error);
1026 if (tp->t_state & TS_ISOPEN) {
1028 * The device is open, so everything has been initialized.
1031 if (mynor & CALLOUT_MASK) {
1032 if (!port->active_out) {
1034 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1035 " BUSY error = %d\n", unit, pnum, error);
1038 } else if (port->active_out) {
1039 if (ap->a_oflags & O_NONBLOCK) {
1041 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1042 " BUSY error = %d\n", unit, pnum, error);
1045 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1047 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1048 " error = %d\n", unit, pnum, error);
1054 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
1060 * The device isn't open, so there are no conflicts.
1061 * Initialize it. Initialization is done twice in many
1062 * cases: to preempt sleeping callin opens if we are
1063 * callout, and to complete a callin open after DCD rises.
1065 tp->t_oproc = dgmstart;
1066 tp->t_param = dgmparam;
1067 tp->t_stop = dgmstop;
1069 tp->t_termios= (mynor & CALLOUT_MASK) ?
1075 port->imodem = bc->mstat;
1076 bc->rout = bc->rin; /* clear input queue */
1078 #ifdef PRINT_BUFSIZE
1079 kprintf("dgm buffers tx = %x:%x rx = %x:%x\n",
1080 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1087 error = dgmparam(tp, &tp->t_termios);
1091 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1096 /* handle fake DCD for callout devices */
1097 /* and initial DCD */
1099 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1100 linesw[tp->t_line].l_modem(tp, 1);
1104 * Wait for DCD if necessary.
1106 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1107 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1109 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1112 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1113 " error = %d\n", unit, pnum, error);
1119 error = linesw[tp->t_line].l_open(dev, tp);
1120 disc_optim(tp, &tp->t_termios);
1121 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1124 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1125 port->active_out = 1;
1129 /* If any port is open (i.e. the open() call is completed for it)
1130 * the device is busy
1134 disc_optim(tp, &tp->t_termios);
1137 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1140 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1143 lwkt_reltoken(&tty_token);
1149 dgmclose(struct dev_close_args *ap)
1151 cdev_t dev = ap->a_head.a_dev;
1155 struct dgm_softc *sc;
1160 if (mynor & CONTROL_MASK)
1163 lwkt_gettoken(&tty_token);
1164 unit = MINOR_TO_UNIT(mynor);
1165 pnum = MINOR_TO_PORT(mynor);
1167 sc = devclass_get_softc(dgmdevclass, unit);
1168 tp = &sc->ttys[pnum];
1169 port = sc->ports + pnum;
1171 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1173 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1174 dgm_drain_or_flush(port);
1179 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1180 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1181 disc_optim(tp, &tp->t_termios);
1183 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1185 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1188 wakeup(&port->closing);
1191 /* mark the card idle when all ports are closed */
1193 for (i = 0; i < sc->numports; i++)
1194 if (sc->ports[i].used)
1199 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1201 wakeup(TSA_CARR_ON(tp));
1202 wakeup(&port->active_out);
1203 port->active_out = 0;
1205 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1207 lwkt_reltoken(&tty_token);
1212 * NOTE: Must be called with tty_token held
1215 dgmhardclose(struct dgm_p *port)
1217 volatile struct board_chan *bc = port->brdchan;
1218 struct dgm_softc *sc;
1220 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1221 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1222 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1224 port->do_timestamp = 0;
1230 if (port->tty->t_cflag & HUPCL) {
1231 port->omodem &= ~(RTS|DTR);
1232 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1238 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1239 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1243 dgm_pause(void *chan)
1245 lwkt_gettoken(&tty_token);
1246 wakeup((caddr_t)chan);
1247 lwkt_reltoken(&tty_token);
1251 dgmpoll(void *unit_c)
1253 int unit = (int)unit_c;
1256 struct dgm_softc *sc;
1259 int event, mstat, lstat;
1260 volatile struct board_chan *bc;
1267 int ibuf_full, obuf_full;
1268 BoardMemWinState ws = bmws_get();
1270 lwkt_gettoken(&tty_token);
1271 sc = devclass_get_softc(dgmdevclass, unit);
1272 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1275 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1276 lwkt_reltoken(&tty_token);
1282 head = sc->mailbox->ein;
1283 tail = sc->mailbox->eout;
1285 while (head != tail) {
1286 if (head >= FEP_IMAX - FEP_ISTART
1287 || tail >= FEP_IMAX - FEP_ISTART
1288 || (head|tail) & 03 ) {
1289 kprintf("dgm%d: event queue's head or tail is wrong!"
1290 " hd = %d, tl = %d\n", unit, head, tail);
1294 eventbuf = sc->vmem + tail + FEP_ISTART;
1296 event = eventbuf[1];
1297 mstat = eventbuf[2];
1298 lstat = eventbuf[3];
1300 port = &sc->ports[pnum];
1302 tp = &sc->ttys[pnum];
1304 if (pnum >= sc->numports || !port->enabled) {
1305 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1307 } else if (port->used || port->wopeners > 0 ) {
1309 int wrapmask = port->rxbufsize - 1;
1311 if (!(event & ALL_IND))
1312 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1313 unit, pnum, event, mstat, lstat);
1315 if (event & DATA_IND) {
1316 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1319 rhead = bc->rin & wrapmask;
1320 rtail = bc->rout & wrapmask;
1322 if (!(tp->t_cflag & CREAD) || !port->used ) {
1328 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1332 if (!(tp->t_state & TS_ISOPEN))
1335 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1336 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1337 " p rx head = %d tail = %d\n", unit,
1338 pnum, rhead, rtail);
1341 size = rhead - rtail;
1343 size = port->rxbufsize - rtail;
1345 ptr = port->rxptr + rtail;
1348 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1349 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1350 DPRINT1(DB_RXDATA, "*");
1355 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1356 DPRINT1(DB_RXDATA, "!");
1357 towin(sc, port->rxwin);
1360 tp->t_rawcc += size;
1368 towin(sc, port->rxwin);
1371 (*linesw[tp->t_line].l_rint)(chr, tp);
1376 rtail= (rtail + size) & wrapmask;
1378 rhead = bc->rin & wrapmask;
1386 if (event & MODEMCHG_IND) {
1387 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1388 "MODEMCHG_IND\n", unit, pnum);
1389 port->imodem = mstat;
1390 if (mstat & port->dcd) {
1392 linesw[tp->t_line].l_modem(tp, 1);
1394 wakeup(TSA_CARR_ON(tp));
1397 linesw[tp->t_line].l_modem(tp, 0);
1399 if (port->draining) {
1401 wakeup(&port->draining);
1406 if (event & BREAK_IND) {
1407 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1408 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1409 " BREAK_IND\n", unit, pnum);
1411 linesw[tp->t_line].l_rint(TTY_BI, tp);
1416 /* Helg: with output flow control */
1418 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1419 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1420 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1422 if ((event & EMPTYTX_IND ) &&
1423 tp->t_outq.c_cc == 0 && port->draining) {
1425 wakeup(&port->draining);
1430 int wrapmask = port->txbufsize - 1;
1432 for (obuf_full = FALSE;
1433 tp->t_outq.c_cc != 0 && !obuf_full;
1435 /* add "last-minute" data to write buffer */
1436 if (!(tp->t_state & TS_BUSY)) {
1438 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1439 ttwwakeup(tp); /* Issues KNOTE() */
1441 if (tp->t_outq.c_cc <= tp->t_lowat) {
1442 if (tp->t_state & TS_ASLEEP) {
1443 tp->t_state &= ~TS_ASLEEP;
1444 wakeup(TSA_OLOWAT(tp));
1452 whead = bc->tin & wrapmask;
1453 wtail = bc->tout & wrapmask;
1456 size = wtail - whead - 1;
1458 size = port->txbufsize - whead;
1464 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1465 whead, wtail, size, obuf_full);
1473 towin(sc, port->txwin);
1475 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1480 bc->tin = whead & wrapmask;
1485 DPRINT1(DB_WR, " +BUSY\n");
1486 tp->t_state |= TS_BUSY;
1488 DPRINT1(DB_WR, " -BUSY\n");
1490 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1491 /* should clear TS_BUSY before ttwwakeup */
1492 if (tp->t_state & TS_BUSY) {
1493 tp->t_state &= ~TS_BUSY;
1494 linesw[tp->t_line].l_start(tp);
1498 if (tp->t_state & TS_ASLEEP) {
1499 tp->t_state &= ~TS_ASLEEP;
1500 wakeup(TSA_OLOWAT(tp));
1502 tp->t_state &= ~TS_BUSY;
1508 bc->idata = 1; /* require event on incoming data */
1512 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1515 bc->idata = bc->iempty = bc->ilow = 0;
1518 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1521 sc->mailbox->eout = tail;
1524 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1526 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1527 lwkt_reltoken(&tty_token);
1531 dgmioctl(struct dev_ioctl_args *ap)
1533 cdev_t dev = ap->a_head.a_dev;
1534 u_long cmd = ap->a_cmd;
1535 caddr_t data = ap->a_data;
1536 struct dgm_softc *sc;
1541 volatile struct board_chan *bc;
1545 lwkt_gettoken(&tty_token);
1546 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1548 struct termios term;
1551 BoardMemWinState ws = bmws_get();
1554 unit = MINOR_TO_UNIT(mynor);
1555 pnum = MINOR_TO_PORT(mynor);
1557 sc = devclass_get_softc(dgmdevclass, unit);
1558 port = &sc->ports[pnum];
1559 tp = &sc->ttys[pnum];
1562 if (mynor & CONTROL_MASK) {
1565 switch (mynor & CONTROL_MASK) {
1566 case CONTROL_INIT_STATE:
1567 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1569 case CONTROL_LOCK_STATE:
1570 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1573 return (ENODEV); /* /dev/nodev */
1577 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1579 lwkt_reltoken(&tty_token);
1582 *ct = *(struct termios *)data;
1583 lwkt_reltoken(&tty_token);
1586 *(struct termios *)data = *ct;
1587 lwkt_reltoken(&tty_token);
1590 *(int *)data = TTYDISC;
1591 lwkt_reltoken(&tty_token);
1594 bzero(data, sizeof(struct winsize));
1595 lwkt_reltoken(&tty_token);
1598 lwkt_reltoken(&tty_token);
1603 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1604 term = tp->t_termios;
1605 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1606 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);
1609 error = ttsetcompat(tp, &cmd, data, &term);
1611 lwkt_reltoken(&tty_token);
1615 data = (caddr_t)&term;
1618 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1620 struct termios *dt = (struct termios *)data;
1621 struct termios *lt = mynor & CALLOUT_MASK
1622 ? &port->lt_out : &port->lt_in;
1624 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);
1625 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1626 | (dt->c_iflag & ~lt->c_iflag);
1627 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1628 | (dt->c_oflag & ~lt->c_oflag);
1629 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1630 | (dt->c_cflag & ~lt->c_cflag);
1631 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1632 | (dt->c_lflag & ~lt->c_lflag);
1633 for (cc = 0; cc < NCCS; ++cc)
1634 if (lt->c_cc[cc] != 0)
1635 dt->c_cc[cc] = tp->t_cc[cc];
1636 if (lt->c_ispeed != 0)
1637 dt->c_ispeed = tp->t_ispeed;
1638 if (lt->c_ospeed != 0)
1639 dt->c_ospeed = tp->t_ospeed;
1642 if (cmd == TIOCSTOP) {
1645 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1648 lwkt_reltoken(&tty_token);
1650 } else if (cmd == TIOCSTART) {
1653 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1656 lwkt_reltoken(&tty_token);
1660 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1661 port->mustdrain = 1;
1663 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1664 ap->a_fflag, ap->a_cred);
1665 if (error != ENOIOCTL) {
1666 lwkt_reltoken(&tty_token);
1670 error = ttioctl(tp, cmd, data, ap->a_fflag);
1671 disc_optim(tp, &tp->t_termios);
1672 port->mustdrain = 0;
1673 if (error != ENOIOCTL) {
1675 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1676 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);
1678 lwkt_reltoken(&tty_token);
1685 error = dgmdrain(port);
1689 lwkt_reltoken(&tty_token);
1697 /* now it sends 400 millisecond break because I don't know */
1698 /* how to send an infinite break */
1700 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1705 /* now it's empty */
1708 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1709 port->omodem |= DTR;
1712 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1714 if (!(bc->mstat & DTR))
1715 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1721 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1722 port->omodem &= ~DTR;
1725 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1727 if (bc->mstat & DTR) {
1728 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1735 if (*(int *)data & TIOCM_DTR)
1736 port->omodem |= DTR;
1738 port->omodem &= ~DTR;
1740 if (*(int *)data & TIOCM_RTS)
1741 port->omodem |= RTS;
1743 port->omodem &= ~RTS;
1747 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1752 if (*(int *)data & TIOCM_DTR)
1753 port->omodem |= DTR;
1755 if (*(int *)data & TIOCM_RTS)
1756 port->omodem |= RTS;
1760 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1765 if (*(int *)data & TIOCM_DTR)
1766 port->omodem &= ~DTR;
1768 if (*(int *)data & TIOCM_RTS)
1769 port->omodem &= ~RTS;
1773 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1779 port->imodem = bc->mstat;
1782 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1784 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1786 if (port->imodem & DTR) {
1787 DPRINT1(DB_MODEM, "DTR ");
1788 tiocm_xxx |= TIOCM_DTR;
1790 if (port->imodem & RTS) {
1791 DPRINT1(DB_MODEM, "RTS ");
1792 tiocm_xxx |= TIOCM_RTS;
1794 if (port->imodem & CTS) {
1795 DPRINT1(DB_MODEM, "CTS ");
1796 tiocm_xxx |= TIOCM_CTS;
1798 if (port->imodem & port->dcd) {
1799 DPRINT1(DB_MODEM, "DCD ");
1800 tiocm_xxx |= TIOCM_CD;
1802 if (port->imodem & port->dsr) {
1803 DPRINT1(DB_MODEM, "DSR ");
1804 tiocm_xxx |= TIOCM_DSR;
1806 if (port->imodem & RI) {
1807 DPRINT1(DB_MODEM, "RI ");
1808 tiocm_xxx |= TIOCM_RI;
1810 *(int *)data = tiocm_xxx;
1811 DPRINT1(DB_MODEM, "--\n");
1814 /* must be root since the wait applies to following logins */
1815 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1818 lwkt_reltoken(&tty_token);
1821 port->close_delay = *(int *)data * hz / 100;
1824 *(int *)data = port->close_delay * 100 / hz;
1827 port->do_timestamp = 1;
1828 *(struct timeval *)data = port->timestamp;
1830 case TIOCDCDTIMESTAMP:
1831 port->do_dcd_timestamp = 1;
1832 *(struct timeval *)data = port->dcd_timestamp;
1837 lwkt_reltoken(&tty_token);
1843 lwkt_reltoken(&tty_token);
1850 struct dgm_p *port = p;
1852 lwkt_gettoken(&tty_token);
1853 wakeup(&port->draining);
1854 lwkt_reltoken(&tty_token);
1857 /* wait for the output to drain */
1859 * NOTE: Must be called with tty_token held
1862 dgmdrain(struct dgm_p *port)
1864 volatile struct board_chan *bc = port->brdchan;
1865 struct dgm_softc *sc;
1868 BoardMemWinState ws = bmws_get();
1870 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1871 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1879 while (tail != head) {
1880 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1881 port->sc->unit, port->pnum, head, tail);
1885 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1886 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1891 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1892 port->sc->unit, port->pnum, error);
1902 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1903 port->sc->unit, port->pnum, head, tail);
1908 /* wait for the output to drain */
1909 /* or simply clear the buffer it it's stopped */
1911 * NOTE: Must be called with tty_token held
1914 dgm_drain_or_flush(struct dgm_p *port)
1916 volatile struct board_chan *bc = port->brdchan;
1917 struct tty *tp = port->tty;
1918 struct dgm_softc *sc;
1923 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1924 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1932 while (tail != head /* && tail != lasttail */ ) {
1933 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1934 port->sc->unit, port->pnum, head, tail);
1936 /* if there is no carrier simply clean the buffer */
1937 if (!(tp->t_state & TS_CARR_ON)) {
1938 bc->tout = bc->tin = 0;
1946 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1947 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1952 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1953 " error = %d\n", port->sc->unit, port->pnum, error);
1955 /* silently clean the buffer */
1957 bc->tout = bc->tin = 0;
1968 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1969 port->sc->unit, port->pnum, head, tail);
1973 dgmparam(struct tty *tp, struct termios *t)
1975 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1976 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1977 volatile struct board_chan *bc;
1978 struct dgm_softc *sc;
1985 BoardMemWinState ws = bmws_get();
1987 lwkt_gettoken(&tty_token);
1988 sc = devclass_get_softc(dgmdevclass, unit);
1989 port = &sc->ports[pnum];
1992 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);
1994 if (port->mustdrain) {
1995 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1999 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
2001 if (t->c_ispeed == 0)
2002 t->c_ispeed = t->c_ospeed;
2004 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
2005 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
2006 lwkt_reltoken(&tty_token);
2013 if (cflag == 0) { /* hangup */
2014 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
2018 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
2019 mval= port->omodem & ~(DTR|RTS);
2021 cflag |= dgmflags(dgm_cflags, t->c_cflag);
2023 if (cflag != port->fepcflag) {
2024 port->fepcflag = cflag;
2025 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
2026 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
2027 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
2029 mval= port->omodem | (DTR|RTS);
2032 iflag = dgmflags(dgm_iflags, t->c_iflag);
2033 if (iflag != port->fepiflag) {
2034 port->fepiflag = iflag;
2035 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
2036 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
2039 bc->mint = port->dcd;
2041 hflow = dgmflags(dgm_flow, t->c_cflag);
2042 if (hflow != port->hflow) {
2043 port->hflow = hflow;
2044 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
2045 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
2048 if (port->omodem != mval) {
2049 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
2050 unit, pnum, mval, port->omodem);
2051 port->omodem = mval;
2052 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
2055 if (port->fepstartc != t->c_cc[VSTART] ||
2056 port->fepstopc != t->c_cc[VSTOP]) {
2057 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
2058 port->fepstartc = t->c_cc[VSTART];
2059 port->fepstopc = t->c_cc[VSTOP];
2060 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
2066 lwkt_reltoken(&tty_token);
2072 dgmstart(struct tty *tp)
2077 struct dgm_softc *sc;
2078 volatile struct board_chan *bc;
2083 lwkt_gettoken(&tty_token);
2084 BoardMemWinState ws = bmws_get();
2086 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2087 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2088 sc = devclass_get_softc(dgmdevclass, unit);
2089 port = &sc->ports[pnum];
2092 wmask = port->txbufsize - 1;
2096 while (tp->t_outq.c_cc != 0) {
2097 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2098 ttwwakeup(tp); /* Issues KNOTE() */
2100 if (tp->t_outq.c_cc <= tp->t_lowat) {
2101 if (tp->t_state & TS_ASLEEP) {
2102 tp->t_state &= ~TS_ASLEEP;
2103 wakeup(TSA_OLOWAT(tp));
2110 head = bc->tin & wmask;
2112 do { tail = bc->tout; } while (tail != bc->tout);
2113 tail = bc->tout & wmask;
2115 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2117 #ifdef LEAVE_FREE_CHARS
2119 size = tail - head - LEAVE_FREE_CHARS;
2123 size = port->txbufsize - head;
2124 if (tail + port->txbufsize < head)
2130 size = tail - head - 1;
2132 size = port->txbufsize - head;
2143 tp->t_state |= TS_BUSY;
2145 lwkt_reltoken(&tty_token);
2149 towin(sc, port->txwin);
2151 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2153 if (head >= port->txbufsize)
2154 head -= port->txbufsize;
2159 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2160 unit, pnum, size, ocount);
2168 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2169 if (tp->t_state & TS_BUSY) {
2170 tp->t_state &= ~TS_BUSY;
2171 linesw[tp->t_line].l_start(tp);
2175 if (tp->t_state & TS_ASLEEP) {
2176 tp->t_state &= ~TS_ASLEEP;
2177 wakeup(TSA_OLOWAT(tp));
2179 tp->t_state& = ~TS_BUSY;
2181 lwkt_reltoken(&tty_token);
2185 dgmstop(struct tty *tp, int rw)
2190 struct dgm_softc *sc;
2191 volatile struct board_chan *bc;
2193 lwkt_gettoken(&tty_token);
2194 BoardMemWinState ws = bmws_get();
2196 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2197 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2199 sc = devclass_get_softc(dgmdevclass, unit);
2200 port = &sc->ports[pnum];
2203 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2209 /* clear output queue */
2210 bc->tout = bc->tin = 0;
2215 /* clear input queue */
2223 lwkt_reltoken(&tty_token);
2227 * NOTE: Must be called with tty_token held
2230 fepcmd(struct dgm_p *port,
2238 unsigned tail, head;
2241 ASSERT_LWKT_TOKEN_HELD(&tty_token);
2242 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2243 mem = port->sc->vmem;
2245 if (!port->enabled) {
2246 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2247 port->sc->unit, port->pnum);
2251 /* setwin(port->sc, 0); Require this to be set by caller */
2252 head = port->sc->mailbox->cin;
2254 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2255 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2256 port->sc->unit, port->pnum, head);
2260 mem[head + FEP_CSTART] = cmd;
2261 mem[head + FEP_CSTART + 1] = port->pnum;
2263 mem[head + FEP_CSTART + 2] = op1;
2264 mem[head + FEP_CSTART + 3] = op2;
2266 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2267 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2270 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2271 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2273 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2274 port->sc->mailbox->cin = head;
2278 while (count-- != 0) {
2279 head = port->sc->mailbox->cin;
2280 tail = port->sc->mailbox->cout;
2282 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2283 if (n <= ncmds * (sizeof(ushort)*4))
2286 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2290 disc_optim(struct tty *tp, struct termios *t)
2292 lwkt_gettoken(&tty_token);
2293 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2294 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2295 && (!(t->c_iflag & PARMRK)
2296 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2297 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2298 && linesw[tp->t_line].l_rint == ttyinput)
2299 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2301 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2302 lwkt_reltoken(&tty_token);