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.11 2004/09/19 01:13:33 dillon Exp $
5 * This driver and the associated header files support the ISA PC/Xem
6 * Digiboards. Its evolutionary roots are described below.
7 * Jack O'Neill <jack@diamond.xtalwind.net>
11 * Stage 1. "Better than nothing".
12 * Stage 2. "Gee, it works!".
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions, and the following disclaimer,
19 * without modification, immediately at the beginning of the file.
20 * 2. Redistributions of binary code must retain the above copyright
21 * notice, this list of conditions, and the following disclaimer,
22 * without modification, in the accompanying documentation.
23 * 3. The name of the author may not be used to endorse or promote products
24 * derived from this software without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * Written by Sergey Babkin,
39 * Joint Stock Commercial Bank "Chelindbank"
40 * (Chelyabinsk, Russia)
43 * Assorted hacks to make it more functional and working under 3.0-current.
44 * Fixed broken routines to prevent processes hanging on closed (thanks
45 * to Bruce for his patience and assistance). Thanks also to Maxim Bolotin
46 * <max@run.net> for his patches which did most of the work to get this
47 * running under 2.2/3.0-current.
48 * Implemented ioctls: TIOCMSDTRWAIT, TIOCMGDTRWAIT, TIOCTIMESTAMP &
50 * Sysctl debug flag is now a bitflag, to filter noise during debugging.
51 * David L. Nugent <davidn@blaze.net.au>
53 * New-busification by Brian Somers <brian@Awfulhak.org>
55 * There was a copyright confusion: I thought that having read the
56 * GLPed drivers makes me mentally contaminated but in fact it does
57 * not. Since the Linux driver by Troy De Jongh <troyd@digibd.com> or
58 * <troyd@skypoint.com> was used only to learn the Digi's interface,
59 * I've returned this driver to a BSD-style license. I tried to contact
60 * all the contributors and those who replied agreed with license
61 * change. If you did any contribution when the driver was GPLed and do
62 * not agree with the BSD-style re-licensing please contact me.
66 /* How often to run dgmpoll */
67 #define POLLSPERSEC 25
69 /* How many charactes can we write to input tty rawq */
70 #define DGB_IBUFSIZE (TTYHOG - 100)
72 /* the overall number of ports controlled by this driver */
74 #include <sys/param.h>
76 #include <sys/systm.h>
79 #include <sys/dkstat.h>
80 #include <sys/fcntl.h>
81 #include <sys/kernel.h>
82 #include <sys/sysctl.h>
83 #include <sys/malloc.h>
84 #include <sys/sysctl.h>
89 #include <machine/bus.h>
91 #include <machine/resource.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 */
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 #define CDEV_MAJOR 101
243 static struct cdevsw dgm_cdevsw = {
245 /* maj */ CDEV_MAJOR,
246 /* flags */ D_TTY | D_KQFILTER,
251 /* close */ dgmclose,
253 /* write */ ttywrite,
254 /* ioctl */ dgmioctl,
257 /* strategy */ nostrategy,
260 /* kqfilter */ ttykqfilter
264 dgmmodhandler(module_t mod, int event, void *arg)
278 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
280 static speed_t dgmdefaultrate = TTYDEF_SPEED;
282 static struct speedtab dgmspeedtab[] = {
283 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
297 { 19200, FEP_B19200 },
298 { 38400, FEP_B38400 },
299 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
300 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
304 static struct dbgflagtbl {
309 { PARODD, PARODD, FEP_PARODD },
310 { PARENB, PARENB, FEP_PARENB },
311 { CSTOPB, CSTOPB, FEP_CSTOPB },
312 { CSIZE, CS5, FEP_CS6 },
313 { CSIZE, CS6, FEP_CS6 },
314 { CSIZE, CS7, FEP_CS7 },
315 { CSIZE, CS8, FEP_CS8 },
316 { CLOCAL, CLOCAL, FEP_CLOCAL },
319 { IGNBRK, IGNBRK, FEP_IGNBRK },
320 { BRKINT, BRKINT, FEP_BRKINT },
321 { IGNPAR, IGNPAR, FEP_IGNPAR },
322 { PARMRK, PARMRK, FEP_PARMRK },
323 { INPCK, INPCK, FEP_INPCK },
324 { ISTRIP, ISTRIP, FEP_ISTRIP },
325 { IXON, IXON, FEP_IXON },
326 { IXOFF, IXOFF, FEP_IXOFF },
327 { IXANY, IXANY, FEP_IXANY },
330 { CRTSCTS, CRTSCTS, CTS|RTS },
331 { CRTSCTS, CCTS_OFLOW, CTS },
332 { CRTSCTS, CRTS_IFLOW, RTS },
336 /* xlat bsd termios flags to dgm sys-v style */
338 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
343 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
344 if ((input & tbl[i].in_mask) == tbl[i].in_val)
345 output |= tbl[i].out_val;
350 static int dgmdebug = 0;
351 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
353 static __inline int setwin(struct dgm_softc *, unsigned);
354 static __inline void hidewin(struct dgm_softc *);
355 static __inline void towin(struct dgm_softc *, int);
357 /*Helg: to allow recursive dgm...() calls */
359 /* If we were called and don't want to disturb we need: */
360 int port; /* write to this port */
361 u_char data; /* this data on exit */
362 /* or DATA_WINOFF to close memory window on entry */
363 } BoardMemWinState; /* so several channels and even boards can coexist */
365 #define DATA_WINOFF 0
366 static BoardMemWinState bmws;
368 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
369 static u_long validmem[] = {
370 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
371 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
372 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
373 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
374 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
377 /* return current memory window state and close window */
378 static BoardMemWinState
381 BoardMemWinState bmwsRet = bmws;
383 if (bmws.data != DATA_WINOFF)
384 outb(bmws.port, bmws.data = DATA_WINOFF);
388 /* restore memory window state */
390 bmws_set(BoardMemWinState ws)
392 if (ws.data != bmws.data || ws.port != bmws.port) {
393 if (bmws.data != DATA_WINOFF)
394 outb(bmws.port, DATA_WINOFF);
395 if (ws.data != DATA_WINOFF)
396 outb(ws.port, ws.data);
402 setwin(struct dgm_softc *sc, unsigned int addr)
404 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
405 return (addr & 0x7FFF);
409 hidewin(struct dgm_softc *sc)
412 outb(bmws.port = sc->port + 1, bmws.data);
416 towin(struct dgm_softc *sc, int win)
418 outb(bmws.port = sc->port + 1, bmws.data = win);
422 dgmprobe(device_t dev)
424 struct dgm_softc *sc = device_get_softc(dev);
428 * Assign unit number. Due to bits we use in the minor number for
429 * the various tty types, only 4 units are supported.
431 sc->unit = device_get_unit(dev);
433 device_printf(dev, "Too many units, only 4 supported\n");
437 /* Check that we've got a valid i/o address */
438 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
440 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
441 if (sc->port == validio[i])
444 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
448 /* Ditto for our memory address */
449 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
451 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
452 if (sc->pmem == validmem[i])
455 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
458 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
459 device_printf(dev, "0x%lx: Memory address not supported\n",
463 sc->vmem = (u_char *)sc->pmem;
465 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
468 /* Temporarily map our io ports */
470 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
471 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
472 if (sc->io_res == NULL)
475 outb(sc->port, FEPRST);
478 for (i = 0; i < 1000; i++) {
480 if ((inb(sc->port) & FEPMASK) == FEPRST) {
482 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
489 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
490 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
494 /* check type of card and get internal memory characteristics */
502 second = inb(sc->port);
503 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
505 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
508 sc->mem_seg = 0x8000;
510 /* Temporarily map our memory too */
512 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
513 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
514 if (sc->mem_res == NULL) {
515 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
516 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
520 outb(sc->port, FEPCLR); /* drop RESET */
521 hidewin(sc); /* Helg: to set initial bmws state */
523 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
524 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
526 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
527 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
529 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
535 dgmattach(device_t dev)
537 struct dgm_softc *sc = device_get_softc(dev);
543 volatile struct board_chan *bc;
546 u_long msize, iosize;
548 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
550 callout_init(&sc->toh);
551 sc->unit = device_get_unit(dev);
552 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
553 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
554 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
556 sc->mem_seg = 0x8000;
559 sc->mem_seg = 0x8000;
561 /* Allocate resources (should have been verified in dgmprobe()) */
563 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
564 0ul, ~0ul, iosize, RF_ACTIVE);
565 if (sc->io_res == NULL)
568 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
569 0ul, ~0ul, msize, RF_ACTIVE);
570 if (sc->mem_res == NULL) {
571 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
572 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
577 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
579 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
582 outb(sc->port, FEPRST);
585 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
587 device_printf(dev, "1st reset failed\n");
590 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
591 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
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);
619 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
621 addr = setwin(sc, TOPWIN);
622 *(u_long *)(mem + addr) = 0x5AA5C33C;
623 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
624 device_printf(dev, "2nd memory test failed\n");
627 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
628 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
632 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
634 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
635 *(u_long *)(mem + addr) = 0x5AA5C33C;
636 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
637 device_printf(dev, "3rd (BIOS) memory test failed\n");
639 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
641 addr = setwin(sc, MISCGLOBAL);
642 for (i = 0; i < 16; i++)
645 addr = setwin(sc, BIOSOFFSET);
647 for (i = 0; ptr < mem + msize; i++)
648 *ptr++ = pcem_bios[i];
650 ptr = mem + BIOSOFFSET;
651 for (i = 0; ptr < mem + msize; i++) {
652 if (*ptr++ != pcem_bios[i]) {
653 printf("Low BIOS load failed\n");
656 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
657 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
661 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
663 addr = setwin(sc, msize);
665 for (;i < pcem_nbios; i++)
666 *ptr++ = pcem_bios[i];
669 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
670 if (*ptr++ != pcem_bios[i]) {
671 printf("High BIOS load failed\n");
674 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
675 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
679 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
680 device_printf(dev, "DigiBIOS loaded, initializing");
682 addr = setwin(sc, 0);
684 *(u_int *)(mem + addr) = 0x0bf00401;
685 *(u_int *)(mem + addr + 4) = 0;
686 *(ushort *)(mem + addr + 0xc00) = 0;
689 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
692 printf("\nBIOS initialize failed(1)\n");
695 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
696 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
701 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
702 printf("\nBIOS initialize failed(2)\n");
705 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
706 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
709 printf(", DigiBIOS running\n");
713 addr = setwin(sc, BIOSOFFSET);
715 for (i = 0; i < pcem_ncook; i++)
716 *ptr++ = pcem_cook[i];
718 ptr = mem + BIOSOFFSET;
719 for (i = 0; i < pcem_ncook; i++) {
720 if (*ptr++ != pcem_cook[i]) {
721 printf("FEP/OS load failed\n");
724 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
725 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
729 device_printf(dev, "FEP/OS loaded, initializing");
731 addr = setwin(sc, 0);
732 *(ushort *)(mem + addr + 0xd20) = 0;
733 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
734 *(u_int *)(mem + addr + 0xc30) = 0x3L;
737 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
740 printf("\nFEP/OS initialize failed(1)\n");
743 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
744 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
749 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
750 printf("\nFEP/OS initialize failed(2)\n");
753 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
754 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
757 printf(", FEP/OS running\n");
759 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
760 device_printf(dev, "%d ports attached\n", sc->numports);
762 if (sc->numports > MAX_DGM_PORTS) {
763 printf("dgm%d: too many ports\n", sc->unit);
766 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
767 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
771 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
772 M_TTYS, M_WAITOK|M_ZERO);
773 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
774 M_TTYS, M_WAITOK|M_ZERO);
776 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
777 for (i = 0; i < sc->numports; i++) {
778 sc->ports[i].enabled = 1;
779 callout_init(&sc->ports[i].hc_timeout);
780 callout_init(&sc->ports[i].wf_timeout);
783 /* We should now init per-port structures */
785 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
786 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
788 if (sc->numports < 3)
793 cdevsw_add(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
794 for (i = 0; i < sc->numports; i++, bc++) {
795 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
796 port = &sc->ports[i];
799 port->tty = &sc->ttys[i];
807 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
809 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
810 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
814 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
815 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
816 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
817 port->txwin = FEPWIN | (bc->tseg >> 11);
818 port->rxwin = FEPWIN | (bc->rseg >> 11);
822 port->txbufsize = bc->tmax + 1;
823 port->rxbufsize = bc->rmax + 1;
825 lowwater = (port->txbufsize >= 2000) ?
826 1024 : (port->txbufsize / 2);
829 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
830 sc->unit, i, lowwater);
831 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
832 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
833 sc->unit, i, port->rxbufsize / 4);
834 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
835 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
836 sc->unit, i, 3 * port->rxbufsize / 4);
837 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
842 port->startc = bc->startc;
843 port->startca = bc->startca;
844 port->stopc = bc->stopc;
845 port->stopca = bc->stopca;
847 /* port->close_delay = 50; */
848 port->close_delay = 3 * hz;
849 port->do_timestamp = 0;
850 port->do_dcd_timestamp = 0;
852 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
854 * We don't use all the flags from <sys/ttydefaults.h> since
855 * they are only relevant for logins. It's important to have
856 * echo off initially so that the line doesn't start
857 * blathering before the echo flag can be turned off.
859 port->it_in.c_iflag = TTYDEF_IFLAG;
860 port->it_in.c_oflag = TTYDEF_OFLAG;
861 port->it_in.c_cflag = TTYDEF_CFLAG;
862 port->it_in.c_lflag = TTYDEF_LFLAG;
863 termioschars(&port->it_in);
864 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
865 port->it_out = port->it_in;
867 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
868 make_dev(&dgm_cdevsw, (sc->unit*65536) + i, UID_ROOT,
869 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
870 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 64, UID_ROOT,
871 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
872 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 128, UID_ROOT,
873 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
874 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262144, UID_UUCP,
875 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
876 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262208, UID_UUCP,
877 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
878 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262272, UID_UUCP,
879 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
882 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
886 /* start the polling function */
887 callout_reset(&sc->toh, hz / POLLSPERSEC,
888 dgmpoll, (void *)(int)sc->unit);
890 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
896 dgmdetach(device_t dev)
898 struct dgm_softc *sc = device_get_softc(dev);
901 for (i = 0; i < sc->numports; i++)
902 if (sc->ttys[i].t_state & TS_ISOPEN)
905 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
908 * The cdevsw_remove() call will destroy all associated devices
909 * and dereference any ad-hoc-created devices, but does not
910 * dereference devices created via make_dev().
912 cdevsw_remove(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
914 callout_stop(&sc->toh);
916 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
917 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
919 FREE(sc->ports, M_TTYS);
920 FREE(sc->ttys, M_TTYS);
926 dgmshutdown(device_t dev)
929 struct dgm_softc *sc = device_get_softc(dev);
931 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
939 dgmopen(dev_t dev, int flag, int mode, struct thread *td)
941 struct dgm_softc *sc;
949 volatile struct board_chan *bc;
953 unit = MINOR_TO_UNIT(mynor);
954 pnum = MINOR_TO_PORT(mynor);
956 sc = devclass_get_softc(dgmdevclass, unit);
958 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
963 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
966 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
971 if (pnum >= sc->numports) {
972 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
977 if (mynor & CONTROL_MASK)
980 tp = &sc->ttys[pnum];
982 port = &sc->ports[pnum];
988 while (port->closing) {
989 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
992 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
993 " error = %d\n", unit, pnum, error);
998 if (tp->t_state & TS_ISOPEN) {
1000 * The device is open, so everything has been initialized.
1003 if (mynor & CALLOUT_MASK) {
1004 if (!port->active_out) {
1006 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1007 " BUSY error = %d\n", unit, pnum, error);
1010 } else if (port->active_out) {
1011 if (flag & O_NONBLOCK) {
1013 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1014 " BUSY error = %d\n", unit, pnum, error);
1017 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1019 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1020 " error = %d\n", unit, pnum, error);
1026 if (tp->t_state & TS_XCLUDE && suser(td)) {
1032 * The device isn't open, so there are no conflicts.
1033 * Initialize it. Initialization is done twice in many
1034 * cases: to preempt sleeping callin opens if we are
1035 * callout, and to complete a callin open after DCD rises.
1037 tp->t_oproc = dgmstart;
1038 tp->t_param = dgmparam;
1039 tp->t_stop = dgmstop;
1041 tp->t_termios= (mynor & CALLOUT_MASK) ?
1047 port->imodem = bc->mstat;
1048 bc->rout = bc->rin; /* clear input queue */
1050 #ifdef PRINT_BUFSIZE
1051 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1052 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1059 error = dgmparam(tp, &tp->t_termios);
1063 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1068 /* handle fake DCD for callout devices */
1069 /* and initial DCD */
1071 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1072 linesw[tp->t_line].l_modem(tp, 1);
1076 * Wait for DCD if necessary.
1078 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1079 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1081 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1084 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1085 " error = %d\n", unit, pnum, error);
1091 error = linesw[tp->t_line].l_open(dev, tp);
1092 disc_optim(tp, &tp->t_termios);
1093 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1096 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1097 port->active_out = 1;
1101 /* If any port is open (i.e. the open() call is completed for it)
1102 * the device is busy
1106 disc_optim(tp, &tp->t_termios);
1109 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1112 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1120 dgmclose(dev_t dev, int flag, int mode, struct thread *td)
1125 struct dgm_softc *sc;
1131 if (mynor & CONTROL_MASK)
1133 unit = MINOR_TO_UNIT(mynor);
1134 pnum = MINOR_TO_PORT(mynor);
1136 sc = devclass_get_softc(dgmdevclass, unit);
1137 tp = &sc->ttys[pnum];
1138 port = sc->ports + pnum;
1140 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1142 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1143 dgm_drain_or_flush(port);
1148 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1149 linesw[tp->t_line].l_close(tp, flag);
1150 disc_optim(tp, &tp->t_termios);
1152 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1154 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1157 wakeup(&port->closing);
1160 /* mark the card idle when all ports are closed */
1162 for (i = 0; i < sc->numports; i++)
1163 if (sc->ports[i].used)
1168 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1170 wakeup(TSA_CARR_ON(tp));
1171 wakeup(&port->active_out);
1172 port->active_out = 0;
1174 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1180 dgmhardclose(struct dgm_p *port)
1182 volatile struct board_chan *bc = port->brdchan;
1183 struct dgm_softc *sc;
1186 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1187 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1189 port->do_timestamp = 0;
1195 if (port->tty->t_cflag & HUPCL) {
1196 port->omodem &= ~(RTS|DTR);
1197 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1203 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1204 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1208 dgm_pause(void *chan)
1210 wakeup((caddr_t)chan);
1214 dgmpoll(void *unit_c)
1216 int unit = (int)unit_c;
1219 struct dgm_softc *sc;
1222 int event, mstat, lstat;
1223 volatile struct board_chan *bc;
1230 int ibuf_full, obuf_full;
1231 BoardMemWinState ws = bmws_get();
1233 sc = devclass_get_softc(dgmdevclass, unit);
1234 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1237 printf("dgm%d: polling of disabled board stopped\n", unit);
1243 head = sc->mailbox->ein;
1244 tail = sc->mailbox->eout;
1246 while (head != tail) {
1247 if (head >= FEP_IMAX - FEP_ISTART
1248 || tail >= FEP_IMAX - FEP_ISTART
1249 || (head|tail) & 03 ) {
1250 printf("dgm%d: event queue's head or tail is wrong!"
1251 " hd = %d, tl = %d\n", unit, head, tail);
1255 eventbuf = sc->vmem + tail + FEP_ISTART;
1257 event = eventbuf[1];
1258 mstat = eventbuf[2];
1259 lstat = eventbuf[3];
1261 port = &sc->ports[pnum];
1263 tp = &sc->ttys[pnum];
1265 if (pnum >= sc->numports || !port->enabled) {
1266 printf("dgm%d: port%d: got event on nonexisting port\n",
1268 } else if (port->used || port->wopeners > 0 ) {
1270 int wrapmask = port->rxbufsize - 1;
1272 if (!(event & ALL_IND))
1273 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1274 unit, pnum, event, mstat, lstat);
1276 if (event & DATA_IND) {
1277 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1280 rhead = bc->rin & wrapmask;
1281 rtail = bc->rout & wrapmask;
1283 if (!(tp->t_cflag & CREAD) || !port->used ) {
1289 printf("dgm%d: port%d: overrun\n", unit, pnum);
1293 if (!(tp->t_state & TS_ISOPEN))
1296 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1297 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1298 " p rx head = %d tail = %d\n", unit,
1299 pnum, rhead, rtail);
1302 size = rhead - rtail;
1304 size = port->rxbufsize - rtail;
1306 ptr = port->rxptr + rtail;
1309 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1310 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1311 DPRINT1(DB_RXDATA, "*");
1316 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1317 DPRINT1(DB_RXDATA, "!");
1318 towin(sc, port->rxwin);
1321 tp->t_rawcc += size;
1329 towin(sc, port->rxwin);
1332 (*linesw[tp->t_line].l_rint)(chr, tp);
1337 rtail= (rtail + size) & wrapmask;
1339 rhead = bc->rin & wrapmask;
1347 if (event & MODEMCHG_IND) {
1348 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1349 "MODEMCHG_IND\n", unit, pnum);
1350 port->imodem = mstat;
1351 if (mstat & port->dcd) {
1353 linesw[tp->t_line].l_modem(tp, 1);
1355 wakeup(TSA_CARR_ON(tp));
1358 linesw[tp->t_line].l_modem(tp, 0);
1360 if (port->draining) {
1362 wakeup(&port->draining);
1367 if (event & BREAK_IND) {
1368 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1369 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1370 " BREAK_IND\n", unit, pnum);
1372 linesw[tp->t_line].l_rint(TTY_BI, tp);
1377 /* Helg: with output flow control */
1379 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1380 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1381 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1383 if ((event & EMPTYTX_IND ) &&
1384 tp->t_outq.c_cc == 0 && port->draining) {
1386 wakeup(&port->draining);
1391 int wrapmask = port->txbufsize - 1;
1393 for (obuf_full = FALSE;
1394 tp->t_outq.c_cc != 0 && !obuf_full;
1397 /* add "last-minute" data to write buffer */
1398 if (!(tp->t_state & TS_BUSY)) {
1400 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1403 if (tp->t_outq.c_cc <= tp->t_lowat) {
1404 if (tp->t_state & TS_ASLEEP) {
1405 tp->t_state &= ~TS_ASLEEP;
1406 wakeup(TSA_OLOWAT(tp));
1408 /* selwakeup(&tp->t_wsel); */
1415 whead = bc->tin & wrapmask;
1416 wtail = bc->tout & wrapmask;
1419 size = wtail - whead - 1;
1421 size = port->txbufsize - whead;
1427 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1428 whead, wtail, size, obuf_full);
1436 towin(sc, port->txwin);
1438 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1443 bc->tin = whead & wrapmask;
1448 DPRINT1(DB_WR, " +BUSY\n");
1449 tp->t_state |= TS_BUSY;
1451 DPRINT1(DB_WR, " -BUSY\n");
1453 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1454 /* should clear TS_BUSY before ttwwakeup */
1455 if (tp->t_state & TS_BUSY) {
1456 tp->t_state &= ~TS_BUSY;
1457 linesw[tp->t_line].l_start(tp);
1461 if (tp->t_state & TS_ASLEEP) {
1462 tp->t_state &= ~TS_ASLEEP;
1463 wakeup(TSA_OLOWAT(tp));
1465 tp->t_state &= ~TS_BUSY;
1471 bc->idata = 1; /* require event on incoming data */
1475 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1478 bc->idata = bc->iempty = bc->ilow = 0;
1481 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1484 sc->mailbox->eout = tail;
1487 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1489 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1493 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1495 struct dgm_softc *sc;
1500 volatile struct board_chan *bc;
1505 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1507 struct termios term;
1510 BoardMemWinState ws = bmws_get();
1513 unit = MINOR_TO_UNIT(mynor);
1514 pnum = MINOR_TO_PORT(mynor);
1516 sc = devclass_get_softc(dgmdevclass, unit);
1517 port = &sc->ports[pnum];
1518 tp = &sc->ttys[pnum];
1521 if (mynor & CONTROL_MASK) {
1524 switch (mynor & CONTROL_MASK) {
1525 case CONTROL_INIT_STATE:
1526 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1528 case CONTROL_LOCK_STATE:
1529 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1532 return (ENODEV); /* /dev/nodev */
1539 *ct = *(struct termios *)data;
1542 *(struct termios *)data = *ct;
1545 *(int *)data = TTYDISC;
1548 bzero(data, sizeof(struct winsize));
1555 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1556 term = tp->t_termios;
1557 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1558 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);
1561 error = ttsetcompat(tp, &cmd, data, &term);
1565 data = (caddr_t)&term;
1568 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1570 struct termios *dt = (struct termios *)data;
1571 struct termios *lt = mynor & CALLOUT_MASK
1572 ? &port->lt_out : &port->lt_in;
1574 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);
1575 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1576 | (dt->c_iflag & ~lt->c_iflag);
1577 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1578 | (dt->c_oflag & ~lt->c_oflag);
1579 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1580 | (dt->c_cflag & ~lt->c_cflag);
1581 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1582 | (dt->c_lflag & ~lt->c_lflag);
1583 for (cc = 0; cc < NCCS; ++cc)
1584 if (lt->c_cc[cc] != 0)
1585 dt->c_cc[cc] = tp->t_cc[cc];
1586 if (lt->c_ispeed != 0)
1587 dt->c_ispeed = tp->t_ispeed;
1588 if (lt->c_ospeed != 0)
1589 dt->c_ospeed = tp->t_ospeed;
1592 if (cmd == TIOCSTOP) {
1595 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1599 } else if (cmd == TIOCSTART) {
1602 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1608 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1609 port->mustdrain = 1;
1611 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
1612 if (error != ENOIOCTL)
1615 error = ttioctl(tp, cmd, data, flag);
1616 disc_optim(tp, &tp->t_termios);
1617 port->mustdrain = 0;
1618 if (error != ENOIOCTL) {
1620 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1621 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);
1629 error = dgmdrain(port);
1640 /* now it sends 400 millisecond break because I don't know */
1641 /* how to send an infinite break */
1643 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1648 /* now it's empty */
1651 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1652 port->omodem |= DTR;
1655 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1657 if (!(bc->mstat & DTR))
1658 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1664 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1665 port->omodem &= ~DTR;
1668 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1670 if (bc->mstat & DTR) {
1671 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1678 if (*(int *)data & TIOCM_DTR)
1679 port->omodem |= DTR;
1681 port->omodem &= ~DTR;
1683 if (*(int *)data & TIOCM_RTS)
1684 port->omodem |= RTS;
1686 port->omodem &= ~RTS;
1690 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1695 if (*(int *)data & TIOCM_DTR)
1696 port->omodem |= DTR;
1698 if (*(int *)data & TIOCM_RTS)
1699 port->omodem |= RTS;
1703 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1708 if (*(int *)data & TIOCM_DTR)
1709 port->omodem &= ~DTR;
1711 if (*(int *)data & TIOCM_RTS)
1712 port->omodem &= ~RTS;
1716 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1722 port->imodem = bc->mstat;
1725 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1727 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1729 if (port->imodem & DTR) {
1730 DPRINT1(DB_MODEM, "DTR ");
1731 tiocm_xxx |= TIOCM_DTR;
1733 if (port->imodem & RTS) {
1734 DPRINT1(DB_MODEM, "RTS ");
1735 tiocm_xxx |= TIOCM_RTS;
1737 if (port->imodem & CTS) {
1738 DPRINT1(DB_MODEM, "CTS ");
1739 tiocm_xxx |= TIOCM_CTS;
1741 if (port->imodem & port->dcd) {
1742 DPRINT1(DB_MODEM, "DCD ");
1743 tiocm_xxx |= TIOCM_CD;
1745 if (port->imodem & port->dsr) {
1746 DPRINT1(DB_MODEM, "DSR ");
1747 tiocm_xxx |= TIOCM_DSR;
1749 if (port->imodem & RI) {
1750 DPRINT1(DB_MODEM, "RI ");
1751 tiocm_xxx |= TIOCM_RI;
1753 *(int *)data = tiocm_xxx;
1754 DPRINT1(DB_MODEM, "--\n");
1757 /* must be root since the wait applies to following logins */
1763 port->close_delay = *(int *)data * hz / 100;
1766 *(int *)data = port->close_delay * 100 / hz;
1769 port->do_timestamp = 1;
1770 *(struct timeval *)data = port->timestamp;
1772 case TIOCDCDTIMESTAMP:
1773 port->do_dcd_timestamp = 1;
1774 *(struct timeval *)data = port->dcd_timestamp;
1790 struct dgm_p *port = p;
1792 wakeup(&port->draining);
1795 /* wait for the output to drain */
1798 dgmdrain(struct dgm_p *port)
1800 volatile struct board_chan *bc = port->brdchan;
1801 struct dgm_softc *sc;
1804 BoardMemWinState ws = bmws_get();
1806 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1814 while (tail != head) {
1815 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1816 port->sc->unit, port->pnum, head, tail);
1820 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1821 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1826 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1827 port->sc->unit, port->pnum, error);
1837 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1838 port->sc->unit, port->pnum, head, tail);
1843 /* wait for the output to drain */
1844 /* or simply clear the buffer it it's stopped */
1847 dgm_drain_or_flush(struct dgm_p *port)
1849 volatile struct board_chan *bc = port->brdchan;
1850 struct tty *tp = port->tty;
1851 struct dgm_softc *sc;
1856 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1864 while (tail != head /* && tail != lasttail */ ) {
1865 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1866 port->sc->unit, port->pnum, head, tail);
1868 /* if there is no carrier simply clean the buffer */
1869 if (!(tp->t_state & TS_CARR_ON)) {
1870 bc->tout = bc->tin = 0;
1878 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1879 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1884 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1885 " error = %d\n", port->sc->unit, port->pnum, error);
1887 /* silently clean the buffer */
1889 bc->tout = bc->tin = 0;
1900 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1901 port->sc->unit, port->pnum, head, tail);
1905 dgmparam(struct tty *tp, struct termios *t)
1907 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1908 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1909 volatile struct board_chan *bc;
1910 struct dgm_softc *sc;
1918 BoardMemWinState ws = bmws_get();
1920 sc = devclass_get_softc(dgmdevclass, unit);
1921 port = &sc->ports[pnum];
1924 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);
1926 if (port->mustdrain) {
1927 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1931 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1933 if (t->c_ispeed == 0)
1934 t->c_ispeed = t->c_ospeed;
1936 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1937 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1944 if (cflag == 0) { /* hangup */
1945 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1949 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1950 mval= port->omodem & ~(DTR|RTS);
1952 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1954 if (cflag != port->fepcflag) {
1955 port->fepcflag = cflag;
1956 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1957 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1958 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1960 mval= port->omodem | (DTR|RTS);
1963 iflag = dgmflags(dgm_iflags, t->c_iflag);
1964 if (iflag != port->fepiflag) {
1965 port->fepiflag = iflag;
1966 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1967 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1970 bc->mint = port->dcd;
1972 hflow = dgmflags(dgm_flow, t->c_cflag);
1973 if (hflow != port->hflow) {
1974 port->hflow = hflow;
1975 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1976 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1979 if (port->omodem != mval) {
1980 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1981 unit, pnum, mval, port->omodem);
1982 port->omodem = mval;
1983 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1986 if (port->fepstartc != t->c_cc[VSTART] ||
1987 port->fepstopc != t->c_cc[VSTOP]) {
1988 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1989 port->fepstartc = t->c_cc[VSTART];
1990 port->fepstopc = t->c_cc[VSTOP];
1991 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
2002 dgmstart(struct tty *tp)
2007 struct dgm_softc *sc;
2008 volatile struct board_chan *bc;
2014 BoardMemWinState ws = bmws_get();
2016 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2017 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2018 sc = devclass_get_softc(dgmdevclass, unit);
2019 port = &sc->ports[pnum];
2022 wmask = port->txbufsize - 1;
2026 while (tp->t_outq.c_cc != 0) {
2028 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2031 if (tp->t_outq.c_cc <= tp->t_lowat) {
2032 if (tp->t_state & TS_ASLEEP) {
2033 tp->t_state &= ~TS_ASLEEP;
2034 wakeup(TSA_OLOWAT(tp));
2036 /*selwakeup(&tp->t_wsel);*/
2042 head = bc->tin & wmask;
2044 do { tail = bc->tout; } while (tail != bc->tout);
2045 tail = bc->tout & wmask;
2047 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2049 #ifdef LEAVE_FREE_CHARS
2051 size = tail - head - LEAVE_FREE_CHARS;
2055 size = port->txbufsize - head;
2056 if (tail + port->txbufsize < head)
2062 size = tail - head - 1;
2064 size = port->txbufsize - head;
2075 tp->t_state |= TS_BUSY;
2080 towin(sc, port->txwin);
2082 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2084 if (head >= port->txbufsize)
2085 head -= port->txbufsize;
2090 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2091 unit, pnum, size, ocount);
2099 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2100 if (tp->t_state & TS_BUSY) {
2101 tp->t_state &= ~TS_BUSY;
2102 linesw[tp->t_line].l_start(tp);
2106 if (tp->t_state & TS_ASLEEP) {
2107 tp->t_state &= ~TS_ASLEEP;
2108 wakeup(TSA_OLOWAT(tp));
2110 tp->t_state& = ~TS_BUSY;
2115 dgmstop(struct tty *tp, int rw)
2120 struct dgm_softc *sc;
2121 volatile struct board_chan *bc;
2124 BoardMemWinState ws = bmws_get();
2126 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2127 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2129 sc = devclass_get_softc(dgmdevclass, unit);
2130 port = &sc->ports[pnum];
2133 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2139 /* clear output queue */
2140 bc->tout = bc->tin = 0;
2145 /* clear input queue */
2156 fepcmd(struct dgm_p *port,
2164 unsigned tail, head;
2167 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2168 mem = port->sc->vmem;
2170 if (!port->enabled) {
2171 printf("dgm%d: port%d: FEP command on disabled port\n",
2172 port->sc->unit, port->pnum);
2176 /* setwin(port->sc, 0); Require this to be set by caller */
2177 head = port->sc->mailbox->cin;
2179 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2180 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2181 port->sc->unit, port->pnum, head);
2185 mem[head + FEP_CSTART] = cmd;
2186 mem[head + FEP_CSTART + 1] = port->pnum;
2188 mem[head + FEP_CSTART + 2] = op1;
2189 mem[head + FEP_CSTART + 3] = op2;
2191 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2192 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2195 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2196 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2198 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2199 port->sc->mailbox->cin = head;
2203 while (count-- != 0) {
2204 head = port->sc->mailbox->cin;
2205 tail = port->sc->mailbox->cout;
2207 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2208 if (n <= ncmds * (sizeof(ushort)*4))
2211 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2215 disc_optim(struct tty *tp, struct termios *t)
2217 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2218 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2219 && (!(t->c_iflag & PARMRK)
2220 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2221 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2222 && linesw[tp->t_line].l_rint == ttyinput)
2223 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2225 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;