2 * $FreeBSD: src/sys/dev/dgb/dgm.c,v 1.31.2.3 2001/10/07 09:02:25 brian Exp $
4 * This driver and the associated header files support the ISA PC/Xem
5 * Digiboards. Its evolutionary roots are described below.
6 * Jack O'Neill <jack@diamond.xtalwind.net>
10 * Stage 1. "Better than nothing".
11 * Stage 2. "Gee, it works!".
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions, and the following disclaimer,
18 * without modification, immediately at the beginning of the file.
19 * 2. Redistributions of binary code must retain the above copyright
20 * notice, this list of conditions, and the following disclaimer,
21 * without modification, in the accompanying documentation.
22 * 3. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * Written by Sergey Babkin,
38 * Joint Stock Commercial Bank "Chelindbank"
39 * (Chelyabinsk, Russia)
42 * Assorted hacks to make it more functional and working under 3.0-current.
43 * Fixed broken routines to prevent processes hanging on closed (thanks
44 * to Bruce for his patience and assistance). Thanks also to Maxim Bolotin
45 * <max@run.net> for his patches which did most of the work to get this
46 * running under 2.2/3.0-current.
47 * Implemented ioctls: TIOCMSDTRWAIT, TIOCMGDTRWAIT, TIOCTIMESTAMP &
49 * Sysctl debug flag is now a bitflag, to filter noise during debugging.
50 * David L. Nugent <davidn@blaze.net.au>
52 * New-busification by Brian Somers <brian@Awfulhak.org>
54 * There was a copyright confusion: I thought that having read the
55 * GLPed drivers makes me mentally contaminated but in fact it does
56 * not. Since the Linux driver by Troy De Jongh <troyd@digibd.com> or
57 * <troyd@skypoint.com> was used only to learn the Digi's interface,
58 * I've returned this driver to a BSD-style license. I tried to contact
59 * all the contributors and those who replied agreed with license
60 * change. If you did any contribution when the driver was GPLed and do
61 * not agree with the BSD-style re-licensing please contact me.
65 /* How often to run dgmpoll */
66 #define POLLSPERSEC 25
68 /* How many charactes can we write to input tty rawq */
69 #define DGB_IBUFSIZE (TTYHOG - 100)
71 /* the overall number of ports controlled by this driver */
73 #include <sys/param.h>
75 #include <sys/systm.h>
79 #include <sys/dkstat.h>
80 #include <sys/fcntl.h>
81 #include <sys/kernel.h>
82 #include <sys/sysctl.h>
83 #include <sys/malloc.h>
84 #include <sys/sysctl.h>
90 #include <sys/thread2.h>
92 #include <machine/clock.h>
101 #define CALLOUT_MASK 0x40000
102 #define CONTROL_MASK 0xC0
103 #define CONTROL_INIT_STATE 0x40
104 #define CONTROL_LOCK_STATE 0x80
105 #define UNIT_MASK 0x30000
106 #define PORT_MASK 0x3F
107 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
108 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
109 #define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK) >> 16)
110 #define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK)
112 #define MEM_SIZE 0x8000
114 #define DGM_UNITMASK 0x30000
115 #define DGM_UNIT(unit) ((unit) << 16)
119 /* digiboard port structure */
121 unsigned enabled : 1;
123 struct dgm_softc *sc; /* parent softc */
124 u_char pnum; /* port number */
125 u_char omodem; /* FEP output modem status */
126 u_char imodem; /* FEP input modem status */
127 u_char modemfake; /* Modem values to be forced */
128 u_char modem; /* Force values */
152 volatile struct board_chan *brdchan;
155 u_char active_out; /* nonzero if the callout device is open */
156 u_int wopeners; /* # processes waiting for DCD in open() */
159 struct termios it_in; /* should be in struct tty */
160 struct termios it_out;
163 struct termios lt_in; /* should be in struct tty */
164 struct termios lt_out;
166 unsigned do_timestamp : 1;
167 unsigned do_dcd_timestamp : 1;
168 struct timeval timestamp;
169 struct timeval dcd_timestamp;
171 /* flags of state, are used in sleep() too */
172 u_char closing; /* port is being closed now */
173 u_char draining; /* port is being drained now */
174 u_char used; /* port is being used now */
175 u_char mustdrain; /* data must be waited to drain in dgmparam() */
177 struct callout hc_timeout;
178 struct callout wf_timeout;
181 /* Digiboard per-board structure */
183 /* struct board_info */
184 unsigned enabled : 1;
185 u_char unit; /* unit number */
186 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
187 u_char altpin; /* do we need alternate pin setting ? */
188 int numports; /* number of ports on card */
189 u_long port; /* I/O port */
190 u_char *vmem; /* virtual memory address */
191 u_long pmem; /* physical memory address */
192 int mem_seg; /* internal memory segment */
194 struct dgm_p *ports; /* ptr to array of port descriptors */
195 struct tty *ttys; /* ptr to array of TTY structures */
196 volatile struct global_data *mailbox;
197 struct resource *io_res;
198 struct resource *mem_res;
201 struct callout toh; /* poll timeout handle */
204 static void dgmpoll(void *);
205 static int dgmprobe(device_t);
206 static int dgmattach(device_t);
207 static int dgmdetach(device_t);
208 static int dgmshutdown(device_t);
209 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
211 static void dgmstart(struct tty *);
212 static void dgmstop(struct tty *, int);
213 static int dgmparam(struct tty *, struct termios *);
214 static void dgmhardclose(struct dgm_p *);
215 static void dgm_drain_or_flush(struct dgm_p *);
216 static int dgmdrain(struct dgm_p *);
217 static void dgm_pause(void *);
218 static void wakeflush(void *);
219 static void disc_optim(struct tty *, struct termios *);
221 static d_open_t dgmopen;
222 static d_close_t dgmclose;
223 static d_ioctl_t dgmioctl;
225 static device_method_t dgmmethods[] = {
226 /* Device interface */
227 DEVMETHOD(device_probe, dgmprobe),
228 DEVMETHOD(device_attach, dgmattach),
229 DEVMETHOD(device_detach, dgmdetach),
230 DEVMETHOD(device_shutdown, dgmshutdown),
234 static driver_t dgmdriver = {
237 sizeof (struct dgm_softc),
240 static devclass_t dgmdevclass;
242 static struct dev_ops dgm_ops = {
249 .d_kqfilter = ttykqfilter,
250 .d_revoke = ttyrevoke
254 dgmmodhandler(module_t mod, int event, void *arg)
268 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
270 static speed_t dgmdefaultrate = TTYDEF_SPEED;
272 static struct speedtab dgmspeedtab[] = {
273 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
287 { 19200, FEP_B19200 },
288 { 38400, FEP_B38400 },
289 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
290 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
294 static struct dbgflagtbl {
299 { PARODD, PARODD, FEP_PARODD },
300 { PARENB, PARENB, FEP_PARENB },
301 { CSTOPB, CSTOPB, FEP_CSTOPB },
302 { CSIZE, CS5, FEP_CS6 },
303 { CSIZE, CS6, FEP_CS6 },
304 { CSIZE, CS7, FEP_CS7 },
305 { CSIZE, CS8, FEP_CS8 },
306 { CLOCAL, CLOCAL, FEP_CLOCAL },
309 { IGNBRK, IGNBRK, FEP_IGNBRK },
310 { BRKINT, BRKINT, FEP_BRKINT },
311 { IGNPAR, IGNPAR, FEP_IGNPAR },
312 { PARMRK, PARMRK, FEP_PARMRK },
313 { INPCK, INPCK, FEP_INPCK },
314 { ISTRIP, ISTRIP, FEP_ISTRIP },
315 { IXON, IXON, FEP_IXON },
316 { IXOFF, IXOFF, FEP_IXOFF },
317 { IXANY, IXANY, FEP_IXANY },
320 { CRTSCTS, CRTSCTS, CTS|RTS },
321 { CRTSCTS, CCTS_OFLOW, CTS },
322 { CRTSCTS, CRTS_IFLOW, RTS },
326 /* xlat bsd termios flags to dgm sys-v style */
328 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
333 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
334 if ((input & tbl[i].in_mask) == tbl[i].in_val)
335 output |= tbl[i].out_val;
340 static int dgmdebug = 0;
341 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
343 static __inline int setwin(struct dgm_softc *, unsigned);
344 static __inline void hidewin(struct dgm_softc *);
345 static __inline void towin(struct dgm_softc *, int);
347 /*Helg: to allow recursive dgm...() calls */
349 /* If we were called and don't want to disturb we need: */
350 int port; /* write to this port */
351 u_char data; /* this data on exit */
352 /* or DATA_WINOFF to close memory window on entry */
353 } BoardMemWinState; /* so several channels and even boards can coexist */
355 #define DATA_WINOFF 0
356 static BoardMemWinState bmws;
358 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
359 static u_long validmem[] = {
360 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
361 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
362 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
363 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
364 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
367 /* return current memory window state and close window */
368 static BoardMemWinState
371 BoardMemWinState bmwsRet = bmws;
373 if (bmws.data != DATA_WINOFF)
374 outb(bmws.port, bmws.data = DATA_WINOFF);
378 /* restore memory window state */
380 bmws_set(BoardMemWinState ws)
382 if (ws.data != bmws.data || ws.port != bmws.port) {
383 if (bmws.data != DATA_WINOFF)
384 outb(bmws.port, DATA_WINOFF);
385 if (ws.data != DATA_WINOFF)
386 outb(ws.port, ws.data);
392 setwin(struct dgm_softc *sc, unsigned int addr)
394 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
395 return (addr & 0x7FFF);
399 hidewin(struct dgm_softc *sc)
402 outb(bmws.port = sc->port + 1, bmws.data);
406 towin(struct dgm_softc *sc, int win)
408 outb(bmws.port = sc->port + 1, bmws.data = win);
412 dgmprobe(device_t dev)
414 struct dgm_softc *sc = device_get_softc(dev);
418 * Assign unit number. Due to bits we use in the minor number for
419 * the various tty types, only 4 units are supported.
421 sc->unit = device_get_unit(dev);
423 device_printf(dev, "Too many units, only 4 supported\n");
427 /* Check that we've got a valid i/o address */
428 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
430 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
431 if (sc->port == validio[i])
434 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
438 /* Ditto for our memory address */
439 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
441 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
442 if (sc->pmem == validmem[i])
445 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
448 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
449 device_printf(dev, "0x%lx: Memory address not supported\n",
453 sc->vmem = (u_char *)sc->pmem;
455 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
458 /* Temporarily map our io ports */
460 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
461 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
462 if (sc->io_res == NULL)
465 lwkt_gettoken(&tty_token);
466 outb(sc->port, FEPRST);
469 for (i = 0; i < 1000; i++) {
471 if ((inb(sc->port) & FEPMASK) == FEPRST) {
473 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
480 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
481 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
482 lwkt_reltoken(&tty_token);
486 /* check type of card and get internal memory characteristics */
494 second = inb(sc->port);
495 kprintf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
497 kprintf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
500 sc->mem_seg = 0x8000;
502 /* Temporarily map our memory too */
504 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
505 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
506 if (sc->mem_res == NULL) {
507 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
508 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
509 lwkt_reltoken(&tty_token);
513 outb(sc->port, FEPCLR); /* drop RESET */
514 hidewin(sc); /* Helg: to set initial bmws state */
516 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
517 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
519 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
520 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
522 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
524 lwkt_reltoken(&tty_token);
529 dgmattach(device_t dev)
531 struct dgm_softc *sc = device_get_softc(dev);
537 volatile struct board_chan *bc;
540 u_long msize, iosize;
542 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
544 lwkt_gettoken(&tty_token);
545 callout_init_mp(&sc->toh);
546 sc->unit = device_get_unit(dev);
547 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
548 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
549 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
551 sc->mem_seg = 0x8000;
554 sc->mem_seg = 0x8000;
556 /* Allocate resources (should have been verified in dgmprobe()) */
558 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
559 0ul, ~0ul, iosize, RF_ACTIVE);
560 if (sc->io_res == NULL) {
561 lwkt_reltoken(&tty_token);
565 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
566 0ul, ~0ul, msize, RF_ACTIVE);
567 if (sc->mem_res == NULL) {
568 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
569 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
570 lwkt_reltoken(&tty_token);
575 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
578 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
581 outb(sc->port, FEPRST);
584 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
586 device_printf(dev, "1st reset failed\n");
589 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
590 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
591 lwkt_reltoken(&tty_token);
597 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
599 t = sc->pmem >> 8; /* disable windowing */
600 outb(sc->port + 2, t & 0xFF);
601 outb(sc->port + 3, t >> 8);
605 /* very short memory test */
606 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
608 addr = setwin(sc, BOTWIN);
609 *(u_long *)(mem + addr) = 0xA55A3CC3;
610 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
611 device_printf(dev, "1st memory test failed\n");
614 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
615 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
616 lwkt_reltoken(&tty_token);
620 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
622 addr = setwin(sc, TOPWIN);
623 *(u_long *)(mem + addr) = 0x5AA5C33C;
624 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
625 device_printf(dev, "2nd memory test failed\n");
628 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
629 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
630 lwkt_reltoken(&tty_token);
634 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
636 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
637 *(u_long *)(mem + addr) = 0x5AA5C33C;
638 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
639 device_printf(dev, "3rd (BIOS) memory test failed\n");
641 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
643 addr = setwin(sc, MISCGLOBAL);
644 for (i = 0; i < 16; i++)
647 addr = setwin(sc, BIOSOFFSET);
649 for (i = 0; ptr < mem + msize; i++)
650 *ptr++ = pcem_bios[i];
652 ptr = mem + BIOSOFFSET;
653 for (i = 0; ptr < mem + msize; i++) {
654 if (*ptr++ != pcem_bios[i]) {
655 kprintf("Low BIOS load failed\n");
658 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
659 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
660 lwkt_reltoken(&tty_token);
664 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
666 addr = setwin(sc, msize);
668 for (;i < pcem_nbios; i++)
669 *ptr++ = pcem_bios[i];
672 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
673 if (*ptr++ != pcem_bios[i]) {
674 kprintf("High BIOS load failed\n");
677 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
678 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
679 lwkt_reltoken(&tty_token);
683 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
684 device_printf(dev, "DigiBIOS loaded, initializing");
686 addr = setwin(sc, 0);
688 *(u_int *)(mem + addr) = 0x0bf00401;
689 *(u_int *)(mem + addr + 4) = 0;
690 *(ushort *)(mem + addr + 0xc00) = 0;
693 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
696 kprintf("\nBIOS initialize failed(1)\n");
699 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
700 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
701 lwkt_reltoken(&tty_token);
706 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
707 kprintf("\nBIOS initialize failed(2)\n");
710 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
711 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
712 lwkt_reltoken(&tty_token);
715 kprintf(", DigiBIOS running\n");
719 addr = setwin(sc, BIOSOFFSET);
721 for (i = 0; i < pcem_ncook; i++)
722 *ptr++ = pcem_cook[i];
724 ptr = mem + BIOSOFFSET;
725 for (i = 0; i < pcem_ncook; i++) {
726 if (*ptr++ != pcem_cook[i]) {
727 kprintf("FEP/OS load failed\n");
730 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
731 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
732 lwkt_reltoken(&tty_token);
736 device_printf(dev, "FEP/OS loaded, initializing");
738 addr = setwin(sc, 0);
739 *(ushort *)(mem + addr + 0xd20) = 0;
740 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
741 *(u_int *)(mem + addr + 0xc30) = 0x3L;
744 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
747 kprintf("\nFEP/OS initialize failed(1)\n");
750 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
751 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
752 lwkt_reltoken(&tty_token);
757 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
758 kprintf("\nFEP/OS initialize failed(2)\n");
761 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
762 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
763 lwkt_reltoken(&tty_token);
766 kprintf(", FEP/OS running\n");
768 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
769 device_printf(dev, "%d ports attached\n", sc->numports);
771 if (sc->numports > MAX_DGM_PORTS) {
772 kprintf("dgm%d: too many ports\n", sc->unit);
775 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
776 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
777 lwkt_reltoken(&tty_token);
781 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
782 M_TTYS, M_WAITOK|M_ZERO);
783 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
784 M_TTYS, M_WAITOK|M_ZERO);
786 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
787 for (i = 0; i < sc->numports; i++) {
788 sc->ports[i].enabled = 1;
789 callout_init_mp(&sc->ports[i].hc_timeout);
790 callout_init_mp(&sc->ports[i].wf_timeout);
793 /* We should now init per-port structures */
795 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
796 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
798 if (sc->numports < 3)
803 for (i = 0; i < sc->numports; i++, bc++) {
804 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
805 port = &sc->ports[i];
808 port->tty = &sc->ttys[i];
816 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
818 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
819 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
823 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
824 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
825 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
826 port->txwin = FEPWIN | (bc->tseg >> 11);
827 port->rxwin = FEPWIN | (bc->rseg >> 11);
831 port->txbufsize = bc->tmax + 1;
832 port->rxbufsize = bc->rmax + 1;
834 lowwater = (port->txbufsize >= 2000) ?
835 1024 : (port->txbufsize / 2);
838 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
839 sc->unit, i, lowwater);
840 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
841 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
842 sc->unit, i, port->rxbufsize / 4);
843 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
844 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
845 sc->unit, i, 3 * port->rxbufsize / 4);
846 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
851 port->startc = bc->startc;
852 port->startca = bc->startca;
853 port->stopc = bc->stopc;
854 port->stopca = bc->stopca;
856 /* port->close_delay = 50; */
857 port->close_delay = 3 * hz;
858 port->do_timestamp = 0;
859 port->do_dcd_timestamp = 0;
861 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
863 * We don't use all the flags from <sys/ttydefaults.h> since
864 * they are only relevant for logins. It's important to have
865 * echo off initially so that the line doesn't start
866 * blathering before the echo flag can be turned off.
868 port->it_in.c_iflag = TTYDEF_IFLAG;
869 port->it_in.c_oflag = TTYDEF_OFLAG;
870 port->it_in.c_cflag = TTYDEF_CFLAG;
871 port->it_in.c_lflag = TTYDEF_LFLAG;
872 termioschars(&port->it_in);
873 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
874 port->it_out = port->it_in;
876 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
877 make_dev(&dgm_ops, (sc->unit*65536) + i, UID_ROOT,
878 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
879 make_dev(&dgm_ops, sc->unit * 65536 + i + 64, UID_ROOT,
880 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
881 make_dev(&dgm_ops, sc->unit * 65536 + i + 128, UID_ROOT,
882 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
883 make_dev(&dgm_ops, sc->unit * 65536 + i + 262144, UID_UUCP,
884 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
885 make_dev(&dgm_ops, sc->unit * 65536 + i + 262208, UID_UUCP,
886 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
887 make_dev(&dgm_ops, sc->unit * 65536 + i + 262272, UID_UUCP,
888 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
891 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
895 /* start the polling function */
896 callout_reset(&sc->toh, hz / POLLSPERSEC,
897 dgmpoll, (void *)(int)sc->unit);
899 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
901 lwkt_reltoken(&tty_token);
906 dgmdetach(device_t dev)
908 struct dgm_softc *sc = device_get_softc(dev);
911 lwkt_gettoken(&tty_token);
912 for (i = 0; i < sc->numports; i++) {
913 if (sc->ttys[i].t_state & TS_ISOPEN) {
914 lwkt_reltoken(&tty_token);
919 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
922 * The dev_ops_remove() call will destroy all associated devices
923 * and dereference any ad-hoc-created devices, but does not
924 * dereference devices created via make_dev().
926 dev_ops_remove_minor(&dgm_ops/*, DGM_UNITMASK*/, DGM_UNIT(sc->unit));
928 callout_stop(&sc->toh);
930 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
931 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
933 FREE(sc->ports, M_TTYS);
934 FREE(sc->ttys, M_TTYS);
937 pmap_unmapdev((vm_offset_t)sc->vmem, sc->msize);
941 lwkt_reltoken(&tty_token);
946 dgmshutdown(device_t dev)
949 struct dgm_softc *sc = device_get_softc(dev);
951 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
959 dgmopen(struct dev_open_args *ap)
961 cdev_t dev = ap->a_head.a_dev;
962 struct dgm_softc *sc;
969 volatile struct board_chan *bc;
971 lwkt_gettoken(&tty_token);
974 unit = MINOR_TO_UNIT(mynor);
975 pnum = MINOR_TO_PORT(mynor);
977 sc = devclass_get_softc(dgmdevclass, unit);
979 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
981 lwkt_reltoken(&tty_token);
985 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
988 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
990 lwkt_reltoken(&tty_token);
994 if (pnum >= sc->numports) {
995 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
997 lwkt_reltoken(&tty_token);
1001 if (mynor & CONTROL_MASK) {
1002 lwkt_reltoken(&tty_token);
1006 tp = &sc->ttys[pnum];
1008 port = &sc->ports[pnum];
1014 while (port->closing) {
1015 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
1018 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
1019 " error = %d\n", unit, pnum, error);
1024 if (tp->t_state & TS_ISOPEN) {
1026 * The device is open, so everything has been initialized.
1029 if (mynor & CALLOUT_MASK) {
1030 if (!port->active_out) {
1032 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1033 " BUSY error = %d\n", unit, pnum, error);
1036 } else if (port->active_out) {
1037 if (ap->a_oflags & O_NONBLOCK) {
1039 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1040 " BUSY error = %d\n", unit, pnum, error);
1043 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1045 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1046 " error = %d\n", unit, pnum, error);
1052 if (tp->t_state & TS_XCLUDE && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
1058 * The device isn't open, so there are no conflicts.
1059 * Initialize it. Initialization is done twice in many
1060 * cases: to preempt sleeping callin opens if we are
1061 * callout, and to complete a callin open after DCD rises.
1063 tp->t_oproc = dgmstart;
1064 tp->t_param = dgmparam;
1065 tp->t_stop = dgmstop;
1067 tp->t_termios= (mynor & CALLOUT_MASK) ?
1073 port->imodem = bc->mstat;
1074 bc->rout = bc->rin; /* clear input queue */
1076 #ifdef PRINT_BUFSIZE
1077 kprintf("dgm buffers tx = %x:%x rx = %x:%x\n",
1078 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1085 error = dgmparam(tp, &tp->t_termios);
1089 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1094 /* handle fake DCD for callout devices */
1095 /* and initial DCD */
1097 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1098 linesw[tp->t_line].l_modem(tp, 1);
1102 * Wait for DCD if necessary.
1104 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1105 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1107 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1110 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1111 " error = %d\n", unit, pnum, error);
1117 error = linesw[tp->t_line].l_open(dev, tp);
1118 disc_optim(tp, &tp->t_termios);
1119 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1122 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1123 port->active_out = 1;
1127 /* If any port is open (i.e. the open() call is completed for it)
1128 * the device is busy
1132 disc_optim(tp, &tp->t_termios);
1135 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1138 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1141 lwkt_reltoken(&tty_token);
1147 dgmclose(struct dev_close_args *ap)
1149 cdev_t dev = ap->a_head.a_dev;
1153 struct dgm_softc *sc;
1158 if (mynor & CONTROL_MASK)
1161 lwkt_gettoken(&tty_token);
1162 unit = MINOR_TO_UNIT(mynor);
1163 pnum = MINOR_TO_PORT(mynor);
1165 sc = devclass_get_softc(dgmdevclass, unit);
1166 tp = &sc->ttys[pnum];
1167 port = sc->ports + pnum;
1169 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1171 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1172 dgm_drain_or_flush(port);
1177 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1178 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1179 disc_optim(tp, &tp->t_termios);
1181 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1183 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1186 wakeup(&port->closing);
1189 /* mark the card idle when all ports are closed */
1191 for (i = 0; i < sc->numports; i++)
1192 if (sc->ports[i].used)
1197 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1199 wakeup(TSA_CARR_ON(tp));
1200 wakeup(&port->active_out);
1201 port->active_out = 0;
1203 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1205 lwkt_reltoken(&tty_token);
1210 * NOTE: Must be called with tty_token held
1213 dgmhardclose(struct dgm_p *port)
1215 volatile struct board_chan *bc = port->brdchan;
1216 struct dgm_softc *sc;
1218 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1219 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1220 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1222 port->do_timestamp = 0;
1228 if (port->tty->t_cflag & HUPCL) {
1229 port->omodem &= ~(RTS|DTR);
1230 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1236 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1237 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1241 dgm_pause(void *chan)
1243 lwkt_gettoken(&tty_token);
1244 wakeup((caddr_t)chan);
1245 lwkt_reltoken(&tty_token);
1249 dgmpoll(void *unit_c)
1251 int unit = (int)unit_c;
1254 struct dgm_softc *sc;
1257 int event, mstat, lstat;
1258 volatile struct board_chan *bc;
1265 int ibuf_full, obuf_full;
1266 BoardMemWinState ws = bmws_get();
1268 lwkt_gettoken(&tty_token);
1269 sc = devclass_get_softc(dgmdevclass, unit);
1270 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1273 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1274 lwkt_reltoken(&tty_token);
1280 head = sc->mailbox->ein;
1281 tail = sc->mailbox->eout;
1283 while (head != tail) {
1284 if (head >= FEP_IMAX - FEP_ISTART
1285 || tail >= FEP_IMAX - FEP_ISTART
1286 || (head|tail) & 03 ) {
1287 kprintf("dgm%d: event queue's head or tail is wrong!"
1288 " hd = %d, tl = %d\n", unit, head, tail);
1292 eventbuf = sc->vmem + tail + FEP_ISTART;
1294 event = eventbuf[1];
1295 mstat = eventbuf[2];
1296 lstat = eventbuf[3];
1298 port = &sc->ports[pnum];
1300 tp = &sc->ttys[pnum];
1302 if (pnum >= sc->numports || !port->enabled) {
1303 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1305 } else if (port->used || port->wopeners > 0 ) {
1307 int wrapmask = port->rxbufsize - 1;
1309 if (!(event & ALL_IND))
1310 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1311 unit, pnum, event, mstat, lstat);
1313 if (event & DATA_IND) {
1314 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1317 rhead = bc->rin & wrapmask;
1318 rtail = bc->rout & wrapmask;
1320 if (!(tp->t_cflag & CREAD) || !port->used ) {
1326 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1330 if (!(tp->t_state & TS_ISOPEN))
1333 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1334 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1335 " p rx head = %d tail = %d\n", unit,
1336 pnum, rhead, rtail);
1339 size = rhead - rtail;
1341 size = port->rxbufsize - rtail;
1343 ptr = port->rxptr + rtail;
1346 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1347 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1348 DPRINT1(DB_RXDATA, "*");
1353 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1354 DPRINT1(DB_RXDATA, "!");
1355 towin(sc, port->rxwin);
1358 tp->t_rawcc += size;
1366 towin(sc, port->rxwin);
1369 (*linesw[tp->t_line].l_rint)(chr, tp);
1374 rtail= (rtail + size) & wrapmask;
1376 rhead = bc->rin & wrapmask;
1384 if (event & MODEMCHG_IND) {
1385 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1386 "MODEMCHG_IND\n", unit, pnum);
1387 port->imodem = mstat;
1388 if (mstat & port->dcd) {
1390 linesw[tp->t_line].l_modem(tp, 1);
1392 wakeup(TSA_CARR_ON(tp));
1395 linesw[tp->t_line].l_modem(tp, 0);
1397 if (port->draining) {
1399 wakeup(&port->draining);
1404 if (event & BREAK_IND) {
1405 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1406 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1407 " BREAK_IND\n", unit, pnum);
1409 linesw[tp->t_line].l_rint(TTY_BI, tp);
1414 /* Helg: with output flow control */
1416 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1417 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1418 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1420 if ((event & EMPTYTX_IND ) &&
1421 tp->t_outq.c_cc == 0 && port->draining) {
1423 wakeup(&port->draining);
1428 int wrapmask = port->txbufsize - 1;
1430 for (obuf_full = FALSE;
1431 tp->t_outq.c_cc != 0 && !obuf_full;
1433 /* add "last-minute" data to write buffer */
1434 if (!(tp->t_state & TS_BUSY)) {
1436 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1437 ttwwakeup(tp); /* Issues KNOTE() */
1439 if (tp->t_outq.c_cc <= tp->t_lowat) {
1440 if (tp->t_state & TS_ASLEEP) {
1441 tp->t_state &= ~TS_ASLEEP;
1442 wakeup(TSA_OLOWAT(tp));
1450 whead = bc->tin & wrapmask;
1451 wtail = bc->tout & wrapmask;
1454 size = wtail - whead - 1;
1456 size = port->txbufsize - whead;
1462 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1463 whead, wtail, size, obuf_full);
1471 towin(sc, port->txwin);
1473 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1478 bc->tin = whead & wrapmask;
1483 DPRINT1(DB_WR, " +BUSY\n");
1484 tp->t_state |= TS_BUSY;
1486 DPRINT1(DB_WR, " -BUSY\n");
1488 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1489 /* should clear TS_BUSY before ttwwakeup */
1490 if (tp->t_state & TS_BUSY) {
1491 tp->t_state &= ~TS_BUSY;
1492 linesw[tp->t_line].l_start(tp);
1496 if (tp->t_state & TS_ASLEEP) {
1497 tp->t_state &= ~TS_ASLEEP;
1498 wakeup(TSA_OLOWAT(tp));
1500 tp->t_state &= ~TS_BUSY;
1506 bc->idata = 1; /* require event on incoming data */
1510 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1513 bc->idata = bc->iempty = bc->ilow = 0;
1516 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1519 sc->mailbox->eout = tail;
1522 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1524 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1525 lwkt_reltoken(&tty_token);
1529 dgmioctl(struct dev_ioctl_args *ap)
1531 cdev_t dev = ap->a_head.a_dev;
1532 u_long cmd = ap->a_cmd;
1533 caddr_t data = ap->a_data;
1534 struct dgm_softc *sc;
1539 volatile struct board_chan *bc;
1543 lwkt_gettoken(&tty_token);
1544 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1546 struct termios term;
1549 BoardMemWinState ws = bmws_get();
1552 unit = MINOR_TO_UNIT(mynor);
1553 pnum = MINOR_TO_PORT(mynor);
1555 sc = devclass_get_softc(dgmdevclass, unit);
1556 port = &sc->ports[pnum];
1557 tp = &sc->ttys[pnum];
1560 if (mynor & CONTROL_MASK) {
1563 switch (mynor & CONTROL_MASK) {
1564 case CONTROL_INIT_STATE:
1565 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1567 case CONTROL_LOCK_STATE:
1568 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1571 return (ENODEV); /* /dev/nodev */
1575 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1577 lwkt_reltoken(&tty_token);
1580 *ct = *(struct termios *)data;
1581 lwkt_reltoken(&tty_token);
1584 *(struct termios *)data = *ct;
1585 lwkt_reltoken(&tty_token);
1588 *(int *)data = TTYDISC;
1589 lwkt_reltoken(&tty_token);
1592 bzero(data, sizeof(struct winsize));
1593 lwkt_reltoken(&tty_token);
1596 lwkt_reltoken(&tty_token);
1601 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1602 term = tp->t_termios;
1603 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1604 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);
1607 error = ttsetcompat(tp, &cmd, data, &term);
1609 lwkt_reltoken(&tty_token);
1613 data = (caddr_t)&term;
1616 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1618 struct termios *dt = (struct termios *)data;
1619 struct termios *lt = mynor & CALLOUT_MASK
1620 ? &port->lt_out : &port->lt_in;
1622 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);
1623 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1624 | (dt->c_iflag & ~lt->c_iflag);
1625 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1626 | (dt->c_oflag & ~lt->c_oflag);
1627 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1628 | (dt->c_cflag & ~lt->c_cflag);
1629 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1630 | (dt->c_lflag & ~lt->c_lflag);
1631 for (cc = 0; cc < NCCS; ++cc)
1632 if (lt->c_cc[cc] != 0)
1633 dt->c_cc[cc] = tp->t_cc[cc];
1634 if (lt->c_ispeed != 0)
1635 dt->c_ispeed = tp->t_ispeed;
1636 if (lt->c_ospeed != 0)
1637 dt->c_ospeed = tp->t_ospeed;
1640 if (cmd == TIOCSTOP) {
1643 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1646 lwkt_reltoken(&tty_token);
1648 } else if (cmd == TIOCSTART) {
1651 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1654 lwkt_reltoken(&tty_token);
1658 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1659 port->mustdrain = 1;
1661 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1662 ap->a_fflag, ap->a_cred);
1663 if (error != ENOIOCTL) {
1664 lwkt_reltoken(&tty_token);
1668 error = ttioctl(tp, cmd, data, ap->a_fflag);
1669 disc_optim(tp, &tp->t_termios);
1670 port->mustdrain = 0;
1671 if (error != ENOIOCTL) {
1673 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1674 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);
1676 lwkt_reltoken(&tty_token);
1683 error = dgmdrain(port);
1687 lwkt_reltoken(&tty_token);
1695 /* now it sends 400 millisecond break because I don't know */
1696 /* how to send an infinite break */
1698 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1703 /* now it's empty */
1706 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1707 port->omodem |= DTR;
1710 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1712 if (!(bc->mstat & DTR))
1713 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1719 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1720 port->omodem &= ~DTR;
1723 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1725 if (bc->mstat & DTR) {
1726 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1733 if (*(int *)data & TIOCM_DTR)
1734 port->omodem |= DTR;
1736 port->omodem &= ~DTR;
1738 if (*(int *)data & TIOCM_RTS)
1739 port->omodem |= RTS;
1741 port->omodem &= ~RTS;
1745 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1750 if (*(int *)data & TIOCM_DTR)
1751 port->omodem |= DTR;
1753 if (*(int *)data & TIOCM_RTS)
1754 port->omodem |= RTS;
1758 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1763 if (*(int *)data & TIOCM_DTR)
1764 port->omodem &= ~DTR;
1766 if (*(int *)data & TIOCM_RTS)
1767 port->omodem &= ~RTS;
1771 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1777 port->imodem = bc->mstat;
1780 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1782 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1784 if (port->imodem & DTR) {
1785 DPRINT1(DB_MODEM, "DTR ");
1786 tiocm_xxx |= TIOCM_DTR;
1788 if (port->imodem & RTS) {
1789 DPRINT1(DB_MODEM, "RTS ");
1790 tiocm_xxx |= TIOCM_RTS;
1792 if (port->imodem & CTS) {
1793 DPRINT1(DB_MODEM, "CTS ");
1794 tiocm_xxx |= TIOCM_CTS;
1796 if (port->imodem & port->dcd) {
1797 DPRINT1(DB_MODEM, "DCD ");
1798 tiocm_xxx |= TIOCM_CD;
1800 if (port->imodem & port->dsr) {
1801 DPRINT1(DB_MODEM, "DSR ");
1802 tiocm_xxx |= TIOCM_DSR;
1804 if (port->imodem & RI) {
1805 DPRINT1(DB_MODEM, "RI ");
1806 tiocm_xxx |= TIOCM_RI;
1808 *(int *)data = tiocm_xxx;
1809 DPRINT1(DB_MODEM, "--\n");
1812 /* must be root since the wait applies to following logins */
1813 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1816 lwkt_reltoken(&tty_token);
1819 port->close_delay = *(int *)data * hz / 100;
1822 *(int *)data = port->close_delay * 100 / hz;
1825 port->do_timestamp = 1;
1826 *(struct timeval *)data = port->timestamp;
1828 case TIOCDCDTIMESTAMP:
1829 port->do_dcd_timestamp = 1;
1830 *(struct timeval *)data = port->dcd_timestamp;
1835 lwkt_reltoken(&tty_token);
1841 lwkt_reltoken(&tty_token);
1848 struct dgm_p *port = p;
1850 lwkt_gettoken(&tty_token);
1851 wakeup(&port->draining);
1852 lwkt_reltoken(&tty_token);
1855 /* wait for the output to drain */
1857 * NOTE: Must be called with tty_token held
1860 dgmdrain(struct dgm_p *port)
1862 volatile struct board_chan *bc = port->brdchan;
1863 struct dgm_softc *sc;
1866 BoardMemWinState ws = bmws_get();
1868 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1869 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1877 while (tail != head) {
1878 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1879 port->sc->unit, port->pnum, head, tail);
1883 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1884 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1889 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1890 port->sc->unit, port->pnum, error);
1900 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1901 port->sc->unit, port->pnum, head, tail);
1906 /* wait for the output to drain */
1907 /* or simply clear the buffer it it's stopped */
1909 * NOTE: Must be called with tty_token held
1912 dgm_drain_or_flush(struct dgm_p *port)
1914 volatile struct board_chan *bc = port->brdchan;
1915 struct tty *tp = port->tty;
1916 struct dgm_softc *sc;
1921 ASSERT_LWKT_TOKEN_HELD(&tty_token);
1922 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1930 while (tail != head /* && tail != lasttail */ ) {
1931 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1932 port->sc->unit, port->pnum, head, tail);
1934 /* if there is no carrier simply clean the buffer */
1935 if (!(tp->t_state & TS_CARR_ON)) {
1936 bc->tout = bc->tin = 0;
1944 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1945 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1950 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1951 " error = %d\n", port->sc->unit, port->pnum, error);
1953 /* silently clean the buffer */
1955 bc->tout = bc->tin = 0;
1966 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1967 port->sc->unit, port->pnum, head, tail);
1971 dgmparam(struct tty *tp, struct termios *t)
1973 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1974 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1975 volatile struct board_chan *bc;
1976 struct dgm_softc *sc;
1983 BoardMemWinState ws = bmws_get();
1985 lwkt_gettoken(&tty_token);
1986 sc = devclass_get_softc(dgmdevclass, unit);
1987 port = &sc->ports[pnum];
1990 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);
1992 if (port->mustdrain) {
1993 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1997 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1999 if (t->c_ispeed == 0)
2000 t->c_ispeed = t->c_ospeed;
2002 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
2003 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
2004 lwkt_reltoken(&tty_token);
2011 if (cflag == 0) { /* hangup */
2012 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
2016 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
2017 mval= port->omodem & ~(DTR|RTS);
2019 cflag |= dgmflags(dgm_cflags, t->c_cflag);
2021 if (cflag != port->fepcflag) {
2022 port->fepcflag = cflag;
2023 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
2024 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
2025 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
2027 mval= port->omodem | (DTR|RTS);
2030 iflag = dgmflags(dgm_iflags, t->c_iflag);
2031 if (iflag != port->fepiflag) {
2032 port->fepiflag = iflag;
2033 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
2034 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
2037 bc->mint = port->dcd;
2039 hflow = dgmflags(dgm_flow, t->c_cflag);
2040 if (hflow != port->hflow) {
2041 port->hflow = hflow;
2042 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
2043 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
2046 if (port->omodem != mval) {
2047 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
2048 unit, pnum, mval, port->omodem);
2049 port->omodem = mval;
2050 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
2053 if (port->fepstartc != t->c_cc[VSTART] ||
2054 port->fepstopc != t->c_cc[VSTOP]) {
2055 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
2056 port->fepstartc = t->c_cc[VSTART];
2057 port->fepstopc = t->c_cc[VSTOP];
2058 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
2064 lwkt_reltoken(&tty_token);
2070 dgmstart(struct tty *tp)
2075 struct dgm_softc *sc;
2076 volatile struct board_chan *bc;
2081 lwkt_gettoken(&tty_token);
2082 BoardMemWinState ws = bmws_get();
2084 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2085 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2086 sc = devclass_get_softc(dgmdevclass, unit);
2087 port = &sc->ports[pnum];
2090 wmask = port->txbufsize - 1;
2094 while (tp->t_outq.c_cc != 0) {
2095 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2096 ttwwakeup(tp); /* Issues KNOTE() */
2098 if (tp->t_outq.c_cc <= tp->t_lowat) {
2099 if (tp->t_state & TS_ASLEEP) {
2100 tp->t_state &= ~TS_ASLEEP;
2101 wakeup(TSA_OLOWAT(tp));
2108 head = bc->tin & wmask;
2110 do { tail = bc->tout; } while (tail != bc->tout);
2111 tail = bc->tout & wmask;
2113 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2115 #ifdef LEAVE_FREE_CHARS
2117 size = tail - head - LEAVE_FREE_CHARS;
2121 size = port->txbufsize - head;
2122 if (tail + port->txbufsize < head)
2128 size = tail - head - 1;
2130 size = port->txbufsize - head;
2141 tp->t_state |= TS_BUSY;
2143 lwkt_reltoken(&tty_token);
2147 towin(sc, port->txwin);
2149 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2151 if (head >= port->txbufsize)
2152 head -= port->txbufsize;
2157 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2158 unit, pnum, size, ocount);
2166 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2167 if (tp->t_state & TS_BUSY) {
2168 tp->t_state &= ~TS_BUSY;
2169 linesw[tp->t_line].l_start(tp);
2173 if (tp->t_state & TS_ASLEEP) {
2174 tp->t_state &= ~TS_ASLEEP;
2175 wakeup(TSA_OLOWAT(tp));
2177 tp->t_state& = ~TS_BUSY;
2179 lwkt_reltoken(&tty_token);
2183 dgmstop(struct tty *tp, int rw)
2188 struct dgm_softc *sc;
2189 volatile struct board_chan *bc;
2191 lwkt_gettoken(&tty_token);
2192 BoardMemWinState ws = bmws_get();
2194 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2195 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2197 sc = devclass_get_softc(dgmdevclass, unit);
2198 port = &sc->ports[pnum];
2201 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2207 /* clear output queue */
2208 bc->tout = bc->tin = 0;
2213 /* clear input queue */
2221 lwkt_reltoken(&tty_token);
2225 * NOTE: Must be called with tty_token held
2228 fepcmd(struct dgm_p *port,
2236 unsigned tail, head;
2239 ASSERT_LWKT_TOKEN_HELD(&tty_token);
2240 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2241 mem = port->sc->vmem;
2243 if (!port->enabled) {
2244 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2245 port->sc->unit, port->pnum);
2249 /* setwin(port->sc, 0); Require this to be set by caller */
2250 head = port->sc->mailbox->cin;
2252 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2253 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2254 port->sc->unit, port->pnum, head);
2258 mem[head + FEP_CSTART] = cmd;
2259 mem[head + FEP_CSTART + 1] = port->pnum;
2261 mem[head + FEP_CSTART + 2] = op1;
2262 mem[head + FEP_CSTART + 3] = op2;
2264 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2265 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2268 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2269 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2271 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2272 port->sc->mailbox->cin = head;
2276 while (count-- != 0) {
2277 head = port->sc->mailbox->cin;
2278 tail = port->sc->mailbox->cout;
2280 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2281 if (n <= ncmds * (sizeof(ushort)*4))
2284 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2288 disc_optim(struct tty *tp, struct termios *t)
2290 lwkt_gettoken(&tty_token);
2291 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2292 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2293 && (!(t->c_iflag & PARMRK)
2294 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2295 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2296 && linesw[tp->t_line].l_rint == ttyinput)
2297 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2299 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2300 lwkt_reltoken(&tty_token);