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.10 2004/09/18 19:54:26 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() */
179 /* Digiboard per-board structure */
181 /* struct board_info */
182 unsigned enabled : 1;
183 u_char unit; /* unit number */
184 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
185 u_char altpin; /* do we need alternate pin setting ? */
186 int numports; /* number of ports on card */
187 u_long port; /* I/O port */
188 u_char *vmem; /* virtual memory address */
189 u_long pmem; /* physical memory address */
190 int mem_seg; /* internal memory segment */
191 struct dgm_p *ports; /* ptr to array of port descriptors */
192 struct tty *ttys; /* ptr to array of TTY structures */
193 volatile struct global_data *mailbox;
194 struct resource *io_res;
195 struct resource *mem_res;
198 struct callout toh; /* poll timeout handle */
201 static void dgmpoll(void *);
202 static int dgmprobe(device_t);
203 static int dgmattach(device_t);
204 static int dgmdetach(device_t);
205 static int dgmshutdown(device_t);
206 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
208 static void dgmstart(struct tty *);
209 static void dgmstop(struct tty *, int);
210 static int dgmparam(struct tty *, struct termios *);
211 static void dgmhardclose(struct dgm_p *);
212 static void dgm_drain_or_flush(struct dgm_p *);
213 static int dgmdrain(struct dgm_p *);
214 static void dgm_pause(void *);
215 static void wakeflush(void *);
216 static void disc_optim(struct tty *, struct termios *);
218 static d_open_t dgmopen;
219 static d_close_t dgmclose;
220 static d_ioctl_t dgmioctl;
222 static device_method_t dgmmethods[] = {
223 /* Device interface */
224 DEVMETHOD(device_probe, dgmprobe),
225 DEVMETHOD(device_attach, dgmattach),
226 DEVMETHOD(device_detach, dgmdetach),
227 DEVMETHOD(device_shutdown, dgmshutdown),
231 static driver_t dgmdriver = {
234 sizeof (struct dgm_softc),
237 static devclass_t dgmdevclass;
239 #define CDEV_MAJOR 101
240 static struct cdevsw dgm_cdevsw = {
242 /* maj */ CDEV_MAJOR,
243 /* flags */ D_TTY | D_KQFILTER,
248 /* close */ dgmclose,
250 /* write */ ttywrite,
251 /* ioctl */ dgmioctl,
254 /* strategy */ nostrategy,
257 /* kqfilter */ ttykqfilter
261 dgmmodhandler(module_t mod, int event, void *arg)
275 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
277 static speed_t dgmdefaultrate = TTYDEF_SPEED;
279 static struct speedtab dgmspeedtab[] = {
280 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
294 { 19200, FEP_B19200 },
295 { 38400, FEP_B38400 },
296 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
297 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
301 static struct dbgflagtbl {
306 { PARODD, PARODD, FEP_PARODD },
307 { PARENB, PARENB, FEP_PARENB },
308 { CSTOPB, CSTOPB, FEP_CSTOPB },
309 { CSIZE, CS5, FEP_CS6 },
310 { CSIZE, CS6, FEP_CS6 },
311 { CSIZE, CS7, FEP_CS7 },
312 { CSIZE, CS8, FEP_CS8 },
313 { CLOCAL, CLOCAL, FEP_CLOCAL },
316 { IGNBRK, IGNBRK, FEP_IGNBRK },
317 { BRKINT, BRKINT, FEP_BRKINT },
318 { IGNPAR, IGNPAR, FEP_IGNPAR },
319 { PARMRK, PARMRK, FEP_PARMRK },
320 { INPCK, INPCK, FEP_INPCK },
321 { ISTRIP, ISTRIP, FEP_ISTRIP },
322 { IXON, IXON, FEP_IXON },
323 { IXOFF, IXOFF, FEP_IXOFF },
324 { IXANY, IXANY, FEP_IXANY },
327 { CRTSCTS, CRTSCTS, CTS|RTS },
328 { CRTSCTS, CCTS_OFLOW, CTS },
329 { CRTSCTS, CRTS_IFLOW, RTS },
333 /* xlat bsd termios flags to dgm sys-v style */
335 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
340 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
341 if ((input & tbl[i].in_mask) == tbl[i].in_val)
342 output |= tbl[i].out_val;
347 static int dgmdebug = 0;
348 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
350 static __inline int setwin(struct dgm_softc *, unsigned);
351 static __inline void hidewin(struct dgm_softc *);
352 static __inline void towin(struct dgm_softc *, int);
354 /*Helg: to allow recursive dgm...() calls */
356 /* If we were called and don't want to disturb we need: */
357 int port; /* write to this port */
358 u_char data; /* this data on exit */
359 /* or DATA_WINOFF to close memory window on entry */
360 } BoardMemWinState; /* so several channels and even boards can coexist */
362 #define DATA_WINOFF 0
363 static BoardMemWinState bmws;
365 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
366 static u_long validmem[] = {
367 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
368 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
369 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
370 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
371 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
374 /* return current memory window state and close window */
375 static BoardMemWinState
378 BoardMemWinState bmwsRet = bmws;
380 if (bmws.data != DATA_WINOFF)
381 outb(bmws.port, bmws.data = DATA_WINOFF);
385 /* restore memory window state */
387 bmws_set(BoardMemWinState ws)
389 if (ws.data != bmws.data || ws.port != bmws.port) {
390 if (bmws.data != DATA_WINOFF)
391 outb(bmws.port, DATA_WINOFF);
392 if (ws.data != DATA_WINOFF)
393 outb(ws.port, ws.data);
399 setwin(struct dgm_softc *sc, unsigned int addr)
401 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
402 return (addr & 0x7FFF);
406 hidewin(struct dgm_softc *sc)
409 outb(bmws.port = sc->port + 1, bmws.data);
413 towin(struct dgm_softc *sc, int win)
415 outb(bmws.port = sc->port + 1, bmws.data = win);
419 dgmprobe(device_t dev)
421 struct dgm_softc *sc = device_get_softc(dev);
425 * Assign unit number. Due to bits we use in the minor number for
426 * the various tty types, only 4 units are supported.
428 sc->unit = device_get_unit(dev);
430 device_printf(dev, "Too many units, only 4 supported\n");
434 /* Check that we've got a valid i/o address */
435 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
437 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
438 if (sc->port == validio[i])
441 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
445 /* Ditto for our memory address */
446 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
448 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
449 if (sc->pmem == validmem[i])
452 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
455 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
456 device_printf(dev, "0x%lx: Memory address not supported\n",
460 sc->vmem = (u_char *)sc->pmem;
462 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
465 /* Temporarily map our io ports */
467 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
468 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
469 if (sc->io_res == NULL)
472 outb(sc->port, FEPRST);
475 for (i = 0; i < 1000; i++) {
477 if ((inb(sc->port) & FEPMASK) == FEPRST) {
479 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
486 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
487 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
491 /* check type of card and get internal memory characteristics */
499 second = inb(sc->port);
500 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
502 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
505 sc->mem_seg = 0x8000;
507 /* Temporarily map our memory too */
509 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
510 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
511 if (sc->mem_res == NULL) {
512 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
513 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
517 outb(sc->port, FEPCLR); /* drop RESET */
518 hidewin(sc); /* Helg: to set initial bmws state */
520 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
521 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
523 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
524 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
526 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
532 dgmattach(device_t dev)
534 struct dgm_softc *sc = device_get_softc(dev);
540 volatile struct board_chan *bc;
543 u_long msize, iosize;
545 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
547 callout_init(&sc->toh);
548 sc->unit = device_get_unit(dev);
549 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
550 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
551 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
553 sc->mem_seg = 0x8000;
556 sc->mem_seg = 0x8000;
558 /* Allocate resources (should have been verified in dgmprobe()) */
560 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
561 0ul, ~0ul, iosize, RF_ACTIVE);
562 if (sc->io_res == NULL)
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);
574 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
576 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
579 outb(sc->port, FEPRST);
582 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
584 device_printf(dev, "1st reset failed\n");
587 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
588 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
594 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
596 t = sc->pmem >> 8; /* disable windowing */
597 outb(sc->port + 2, t & 0xFF);
598 outb(sc->port + 3, t >> 8);
602 /* very short memory test */
603 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
605 addr = setwin(sc, BOTWIN);
606 *(u_long *)(mem + addr) = 0xA55A3CC3;
607 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
608 device_printf(dev, "1st memory test failed\n");
611 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
612 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
616 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
618 addr = setwin(sc, TOPWIN);
619 *(u_long *)(mem + addr) = 0x5AA5C33C;
620 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
621 device_printf(dev, "2nd memory test failed\n");
624 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
625 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
629 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
631 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
632 *(u_long *)(mem + addr) = 0x5AA5C33C;
633 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
634 device_printf(dev, "3rd (BIOS) memory test failed\n");
636 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
638 addr = setwin(sc, MISCGLOBAL);
639 for (i = 0; i < 16; i++)
642 addr = setwin(sc, BIOSOFFSET);
644 for (i = 0; ptr < mem + msize; i++)
645 *ptr++ = pcem_bios[i];
647 ptr = mem + BIOSOFFSET;
648 for (i = 0; ptr < mem + msize; i++) {
649 if (*ptr++ != pcem_bios[i]) {
650 printf("Low BIOS load failed\n");
653 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
654 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
658 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
660 addr = setwin(sc, msize);
662 for (;i < pcem_nbios; i++)
663 *ptr++ = pcem_bios[i];
666 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
667 if (*ptr++ != pcem_bios[i]) {
668 printf("High BIOS load failed\n");
671 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
672 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
676 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
677 device_printf(dev, "DigiBIOS loaded, initializing");
679 addr = setwin(sc, 0);
681 *(u_int *)(mem + addr) = 0x0bf00401;
682 *(u_int *)(mem + addr + 4) = 0;
683 *(ushort *)(mem + addr + 0xc00) = 0;
686 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
689 printf("\nBIOS initialize failed(1)\n");
692 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
693 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
698 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
699 printf("\nBIOS initialize failed(2)\n");
702 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
703 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
706 printf(", DigiBIOS running\n");
710 addr = setwin(sc, BIOSOFFSET);
712 for (i = 0; i < pcem_ncook; i++)
713 *ptr++ = pcem_cook[i];
715 ptr = mem + BIOSOFFSET;
716 for (i = 0; i < pcem_ncook; i++) {
717 if (*ptr++ != pcem_cook[i]) {
718 printf("FEP/OS load failed\n");
721 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
722 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
726 device_printf(dev, "FEP/OS loaded, initializing");
728 addr = setwin(sc, 0);
729 *(ushort *)(mem + addr + 0xd20) = 0;
730 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
731 *(u_int *)(mem + addr + 0xc30) = 0x3L;
734 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
737 printf("\nFEP/OS initialize failed(1)\n");
740 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
741 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
746 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
747 printf("\nFEP/OS initialize failed(2)\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);
754 printf(", FEP/OS running\n");
756 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
757 device_printf(dev, "%d ports attached\n", sc->numports);
759 if (sc->numports > MAX_DGM_PORTS) {
760 printf("dgm%d: too many ports\n", sc->unit);
763 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
764 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
768 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
769 M_TTYS, M_WAITOK|M_ZERO);
770 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
771 M_TTYS, M_WAITOK|M_ZERO);
773 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
774 for (i = 0; i < sc->numports; i++)
775 sc->ports[i].enabled = 1;
777 /* We should now init per-port structures */
779 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
780 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
782 if (sc->numports < 3)
787 cdevsw_add(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
788 for (i = 0; i < sc->numports; i++, bc++) {
789 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
790 port = &sc->ports[i];
793 port->tty = &sc->ttys[i];
801 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
803 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
804 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
808 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
809 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
810 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
811 port->txwin = FEPWIN | (bc->tseg >> 11);
812 port->rxwin = FEPWIN | (bc->rseg >> 11);
816 port->txbufsize = bc->tmax + 1;
817 port->rxbufsize = bc->rmax + 1;
819 lowwater = (port->txbufsize >= 2000) ?
820 1024 : (port->txbufsize / 2);
823 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
824 sc->unit, i, lowwater);
825 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
826 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
827 sc->unit, i, port->rxbufsize / 4);
828 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
829 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
830 sc->unit, i, 3 * port->rxbufsize / 4);
831 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
836 port->startc = bc->startc;
837 port->startca = bc->startca;
838 port->stopc = bc->stopc;
839 port->stopca = bc->stopca;
841 /* port->close_delay = 50; */
842 port->close_delay = 3 * hz;
843 port->do_timestamp = 0;
844 port->do_dcd_timestamp = 0;
846 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
848 * We don't use all the flags from <sys/ttydefaults.h> since
849 * they are only relevant for logins. It's important to have
850 * echo off initially so that the line doesn't start
851 * blathering before the echo flag can be turned off.
853 port->it_in.c_iflag = TTYDEF_IFLAG;
854 port->it_in.c_oflag = TTYDEF_OFLAG;
855 port->it_in.c_cflag = TTYDEF_CFLAG;
856 port->it_in.c_lflag = TTYDEF_LFLAG;
857 termioschars(&port->it_in);
858 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
859 port->it_out = port->it_in;
861 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
862 make_dev(&dgm_cdevsw, (sc->unit*65536) + i, UID_ROOT,
863 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
864 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 64, UID_ROOT,
865 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
866 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 128, UID_ROOT,
867 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
868 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262144, UID_UUCP,
869 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
870 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262208, UID_UUCP,
871 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
872 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262272, UID_UUCP,
873 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
876 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
880 /* start the polling function */
881 callout_reset(&sc->toh, hz / POLLSPERSEC,
882 dgmpoll, (void *)(int)sc->unit);
884 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
890 dgmdetach(device_t dev)
892 struct dgm_softc *sc = device_get_softc(dev);
895 for (i = 0; i < sc->numports; i++)
896 if (sc->ttys[i].t_state & TS_ISOPEN)
899 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
902 * The cdevsw_remove() call will destroy all associated devices
903 * and dereference any ad-hoc-created devices, but does not
904 * dereference devices created via make_dev().
906 cdevsw_remove(&dgm_cdevsw, DGM_UNITMASK, DGM_UNIT(sc->unit));
908 callout_stop(&sc->toh);
910 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
911 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
913 FREE(sc->ports, M_TTYS);
914 FREE(sc->ttys, M_TTYS);
920 dgmshutdown(device_t dev)
923 struct dgm_softc *sc = device_get_softc(dev);
925 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
933 dgmopen(dev_t dev, int flag, int mode, struct thread *td)
935 struct dgm_softc *sc;
943 volatile struct board_chan *bc;
947 unit = MINOR_TO_UNIT(mynor);
948 pnum = MINOR_TO_PORT(mynor);
950 sc = devclass_get_softc(dgmdevclass, unit);
952 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
957 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
960 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
965 if (pnum >= sc->numports) {
966 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
971 if (mynor & CONTROL_MASK)
974 tp = &sc->ttys[pnum];
976 port = &sc->ports[pnum];
982 while (port->closing) {
983 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
986 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
987 " error = %d\n", unit, pnum, error);
992 if (tp->t_state & TS_ISOPEN) {
994 * The device is open, so everything has been initialized.
997 if (mynor & CALLOUT_MASK) {
998 if (!port->active_out) {
1000 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1001 " BUSY error = %d\n", unit, pnum, error);
1004 } else if (port->active_out) {
1005 if (flag & O_NONBLOCK) {
1007 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1008 " BUSY error = %d\n", unit, pnum, error);
1011 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1013 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1014 " error = %d\n", unit, pnum, error);
1020 if (tp->t_state & TS_XCLUDE && suser(td)) {
1026 * The device isn't open, so there are no conflicts.
1027 * Initialize it. Initialization is done twice in many
1028 * cases: to preempt sleeping callin opens if we are
1029 * callout, and to complete a callin open after DCD rises.
1031 tp->t_oproc = dgmstart;
1032 tp->t_param = dgmparam;
1033 tp->t_stop = dgmstop;
1035 tp->t_termios= (mynor & CALLOUT_MASK) ?
1041 port->imodem = bc->mstat;
1042 bc->rout = bc->rin; /* clear input queue */
1044 #ifdef PRINT_BUFSIZE
1045 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1046 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1053 error = dgmparam(tp, &tp->t_termios);
1057 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1062 /* handle fake DCD for callout devices */
1063 /* and initial DCD */
1065 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1066 linesw[tp->t_line].l_modem(tp, 1);
1070 * Wait for DCD if necessary.
1072 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1073 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1075 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1078 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1079 " error = %d\n", unit, pnum, error);
1085 error = linesw[tp->t_line].l_open(dev, tp);
1086 disc_optim(tp, &tp->t_termios);
1087 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1090 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1091 port->active_out = 1;
1095 /* If any port is open (i.e. the open() call is completed for it)
1096 * the device is busy
1100 disc_optim(tp, &tp->t_termios);
1103 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1106 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1114 dgmclose(dev_t dev, int flag, int mode, struct thread *td)
1119 struct dgm_softc *sc;
1125 if (mynor & CONTROL_MASK)
1127 unit = MINOR_TO_UNIT(mynor);
1128 pnum = MINOR_TO_PORT(mynor);
1130 sc = devclass_get_softc(dgmdevclass, unit);
1131 tp = &sc->ttys[pnum];
1132 port = sc->ports + pnum;
1134 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1136 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1137 dgm_drain_or_flush(port);
1142 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1143 linesw[tp->t_line].l_close(tp, flag);
1144 disc_optim(tp, &tp->t_termios);
1146 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1148 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1151 wakeup(&port->closing);
1154 /* mark the card idle when all ports are closed */
1156 for (i = 0; i < sc->numports; i++)
1157 if (sc->ports[i].used)
1162 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1164 wakeup(TSA_CARR_ON(tp));
1165 wakeup(&port->active_out);
1166 port->active_out = 0;
1168 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1174 dgmhardclose(struct dgm_p *port)
1176 volatile struct board_chan *bc = port->brdchan;
1177 struct dgm_softc *sc;
1180 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1181 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1183 port->do_timestamp = 0;
1189 if (port->tty->t_cflag & HUPCL) {
1190 port->omodem &= ~(RTS|DTR);
1191 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1197 timeout(dgm_pause, &port->brdchan, hz/2);
1198 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1202 dgm_pause(void *chan)
1204 wakeup((caddr_t)chan);
1208 dgmpoll(void *unit_c)
1210 int unit = (int)unit_c;
1213 struct dgm_softc *sc;
1216 int event, mstat, lstat;
1217 volatile struct board_chan *bc;
1224 int ibuf_full, obuf_full;
1225 BoardMemWinState ws = bmws_get();
1227 sc = devclass_get_softc(dgmdevclass, unit);
1228 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1231 printf("dgm%d: polling of disabled board stopped\n", unit);
1237 head = sc->mailbox->ein;
1238 tail = sc->mailbox->eout;
1240 while (head != tail) {
1241 if (head >= FEP_IMAX - FEP_ISTART
1242 || tail >= FEP_IMAX - FEP_ISTART
1243 || (head|tail) & 03 ) {
1244 printf("dgm%d: event queue's head or tail is wrong!"
1245 " hd = %d, tl = %d\n", unit, head, tail);
1249 eventbuf = sc->vmem + tail + FEP_ISTART;
1251 event = eventbuf[1];
1252 mstat = eventbuf[2];
1253 lstat = eventbuf[3];
1255 port = &sc->ports[pnum];
1257 tp = &sc->ttys[pnum];
1259 if (pnum >= sc->numports || !port->enabled) {
1260 printf("dgm%d: port%d: got event on nonexisting port\n",
1262 } else if (port->used || port->wopeners > 0 ) {
1264 int wrapmask = port->rxbufsize - 1;
1266 if (!(event & ALL_IND))
1267 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1268 unit, pnum, event, mstat, lstat);
1270 if (event & DATA_IND) {
1271 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1274 rhead = bc->rin & wrapmask;
1275 rtail = bc->rout & wrapmask;
1277 if (!(tp->t_cflag & CREAD) || !port->used ) {
1283 printf("dgm%d: port%d: overrun\n", unit, pnum);
1287 if (!(tp->t_state & TS_ISOPEN))
1290 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1291 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1292 " p rx head = %d tail = %d\n", unit,
1293 pnum, rhead, rtail);
1296 size = rhead - rtail;
1298 size = port->rxbufsize - rtail;
1300 ptr = port->rxptr + rtail;
1303 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1304 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1305 DPRINT1(DB_RXDATA, "*");
1310 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1311 DPRINT1(DB_RXDATA, "!");
1312 towin(sc, port->rxwin);
1315 tp->t_rawcc += size;
1323 towin(sc, port->rxwin);
1326 (*linesw[tp->t_line].l_rint)(chr, tp);
1331 rtail= (rtail + size) & wrapmask;
1333 rhead = bc->rin & wrapmask;
1341 if (event & MODEMCHG_IND) {
1342 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1343 "MODEMCHG_IND\n", unit, pnum);
1344 port->imodem = mstat;
1345 if (mstat & port->dcd) {
1347 linesw[tp->t_line].l_modem(tp, 1);
1349 wakeup(TSA_CARR_ON(tp));
1352 linesw[tp->t_line].l_modem(tp, 0);
1354 if (port->draining) {
1356 wakeup(&port->draining);
1361 if (event & BREAK_IND) {
1362 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1363 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1364 " BREAK_IND\n", unit, pnum);
1366 linesw[tp->t_line].l_rint(TTY_BI, tp);
1371 /* Helg: with output flow control */
1373 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1374 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1375 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1377 if ((event & EMPTYTX_IND ) &&
1378 tp->t_outq.c_cc == 0 && port->draining) {
1380 wakeup(&port->draining);
1385 int wrapmask = port->txbufsize - 1;
1387 for (obuf_full = FALSE;
1388 tp->t_outq.c_cc != 0 && !obuf_full;
1391 /* add "last-minute" data to write buffer */
1392 if (!(tp->t_state & TS_BUSY)) {
1394 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1397 if (tp->t_outq.c_cc <= tp->t_lowat) {
1398 if (tp->t_state & TS_ASLEEP) {
1399 tp->t_state &= ~TS_ASLEEP;
1400 wakeup(TSA_OLOWAT(tp));
1402 /* selwakeup(&tp->t_wsel); */
1409 whead = bc->tin & wrapmask;
1410 wtail = bc->tout & wrapmask;
1413 size = wtail - whead - 1;
1415 size = port->txbufsize - whead;
1421 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1422 whead, wtail, size, obuf_full);
1430 towin(sc, port->txwin);
1432 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1437 bc->tin = whead & wrapmask;
1442 DPRINT1(DB_WR, " +BUSY\n");
1443 tp->t_state |= TS_BUSY;
1445 DPRINT1(DB_WR, " -BUSY\n");
1447 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1448 /* should clear TS_BUSY before ttwwakeup */
1449 if (tp->t_state & TS_BUSY) {
1450 tp->t_state &= ~TS_BUSY;
1451 linesw[tp->t_line].l_start(tp);
1455 if (tp->t_state & TS_ASLEEP) {
1456 tp->t_state &= ~TS_ASLEEP;
1457 wakeup(TSA_OLOWAT(tp));
1459 tp->t_state &= ~TS_BUSY;
1465 bc->idata = 1; /* require event on incoming data */
1469 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1472 bc->idata = bc->iempty = bc->ilow = 0;
1475 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1478 sc->mailbox->eout = tail;
1481 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1483 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1487 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1489 struct dgm_softc *sc;
1494 volatile struct board_chan *bc;
1499 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1501 struct termios term;
1504 BoardMemWinState ws = bmws_get();
1507 unit = MINOR_TO_UNIT(mynor);
1508 pnum = MINOR_TO_PORT(mynor);
1510 sc = devclass_get_softc(dgmdevclass, unit);
1511 port = &sc->ports[pnum];
1512 tp = &sc->ttys[pnum];
1515 if (mynor & CONTROL_MASK) {
1518 switch (mynor & CONTROL_MASK) {
1519 case CONTROL_INIT_STATE:
1520 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1522 case CONTROL_LOCK_STATE:
1523 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1526 return (ENODEV); /* /dev/nodev */
1533 *ct = *(struct termios *)data;
1536 *(struct termios *)data = *ct;
1539 *(int *)data = TTYDISC;
1542 bzero(data, sizeof(struct winsize));
1549 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1550 term = tp->t_termios;
1551 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1552 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);
1555 error = ttsetcompat(tp, &cmd, data, &term);
1559 data = (caddr_t)&term;
1562 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1564 struct termios *dt = (struct termios *)data;
1565 struct termios *lt = mynor & CALLOUT_MASK
1566 ? &port->lt_out : &port->lt_in;
1568 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);
1569 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1570 | (dt->c_iflag & ~lt->c_iflag);
1571 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1572 | (dt->c_oflag & ~lt->c_oflag);
1573 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1574 | (dt->c_cflag & ~lt->c_cflag);
1575 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1576 | (dt->c_lflag & ~lt->c_lflag);
1577 for (cc = 0; cc < NCCS; ++cc)
1578 if (lt->c_cc[cc] != 0)
1579 dt->c_cc[cc] = tp->t_cc[cc];
1580 if (lt->c_ispeed != 0)
1581 dt->c_ispeed = tp->t_ispeed;
1582 if (lt->c_ospeed != 0)
1583 dt->c_ospeed = tp->t_ospeed;
1586 if (cmd == TIOCSTOP) {
1589 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1593 } else if (cmd == TIOCSTART) {
1596 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1602 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1603 port->mustdrain = 1;
1605 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
1606 if (error != ENOIOCTL)
1609 error = ttioctl(tp, cmd, data, flag);
1610 disc_optim(tp, &tp->t_termios);
1611 port->mustdrain = 0;
1612 if (error != ENOIOCTL) {
1614 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1615 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);
1623 error = dgmdrain(port);
1634 /* now it sends 400 millisecond break because I don't know */
1635 /* how to send an infinite break */
1637 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1642 /* now it's empty */
1645 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1646 port->omodem |= DTR;
1649 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1651 if (!(bc->mstat & DTR))
1652 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1658 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1659 port->omodem &= ~DTR;
1662 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1664 if (bc->mstat & DTR) {
1665 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1672 if (*(int *)data & TIOCM_DTR)
1673 port->omodem |= DTR;
1675 port->omodem &= ~DTR;
1677 if (*(int *)data & TIOCM_RTS)
1678 port->omodem |= RTS;
1680 port->omodem &= ~RTS;
1684 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1689 if (*(int *)data & TIOCM_DTR)
1690 port->omodem |= DTR;
1692 if (*(int *)data & TIOCM_RTS)
1693 port->omodem |= RTS;
1697 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1702 if (*(int *)data & TIOCM_DTR)
1703 port->omodem &= ~DTR;
1705 if (*(int *)data & TIOCM_RTS)
1706 port->omodem &= ~RTS;
1710 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1716 port->imodem = bc->mstat;
1719 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1721 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1723 if (port->imodem & DTR) {
1724 DPRINT1(DB_MODEM, "DTR ");
1725 tiocm_xxx |= TIOCM_DTR;
1727 if (port->imodem & RTS) {
1728 DPRINT1(DB_MODEM, "RTS ");
1729 tiocm_xxx |= TIOCM_RTS;
1731 if (port->imodem & CTS) {
1732 DPRINT1(DB_MODEM, "CTS ");
1733 tiocm_xxx |= TIOCM_CTS;
1735 if (port->imodem & port->dcd) {
1736 DPRINT1(DB_MODEM, "DCD ");
1737 tiocm_xxx |= TIOCM_CD;
1739 if (port->imodem & port->dsr) {
1740 DPRINT1(DB_MODEM, "DSR ");
1741 tiocm_xxx |= TIOCM_DSR;
1743 if (port->imodem & RI) {
1744 DPRINT1(DB_MODEM, "RI ");
1745 tiocm_xxx |= TIOCM_RI;
1747 *(int *)data = tiocm_xxx;
1748 DPRINT1(DB_MODEM, "--\n");
1751 /* must be root since the wait applies to following logins */
1757 port->close_delay = *(int *)data * hz / 100;
1760 *(int *)data = port->close_delay * 100 / hz;
1763 port->do_timestamp = 1;
1764 *(struct timeval *)data = port->timestamp;
1766 case TIOCDCDTIMESTAMP:
1767 port->do_dcd_timestamp = 1;
1768 *(struct timeval *)data = port->dcd_timestamp;
1784 struct dgm_p *port = p;
1786 wakeup(&port->draining);
1789 /* wait for the output to drain */
1792 dgmdrain(struct dgm_p *port)
1794 volatile struct board_chan *bc = port->brdchan;
1795 struct dgm_softc *sc;
1798 BoardMemWinState ws = bmws_get();
1800 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1808 while (tail != head) {
1809 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1810 port->sc->unit, port->pnum, head, tail);
1814 timeout(wakeflush, port, hz);
1815 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1820 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1821 port->sc->unit, port->pnum, error);
1831 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1832 port->sc->unit, port->pnum, head, tail);
1837 /* wait for the output to drain */
1838 /* or simply clear the buffer it it's stopped */
1841 dgm_drain_or_flush(struct dgm_p *port)
1843 volatile struct board_chan *bc = port->brdchan;
1844 struct tty *tp = port->tty;
1845 struct dgm_softc *sc;
1850 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1858 while (tail != head /* && tail != lasttail */ ) {
1859 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1860 port->sc->unit, port->pnum, head, tail);
1862 /* if there is no carrier simply clean the buffer */
1863 if (!(tp->t_state & TS_CARR_ON)) {
1864 bc->tout = bc->tin = 0;
1872 timeout(wakeflush, port, hz);
1873 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1878 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1879 " error = %d\n", port->sc->unit, port->pnum, error);
1881 /* silently clean the buffer */
1883 bc->tout = bc->tin = 0;
1894 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1895 port->sc->unit, port->pnum, head, tail);
1899 dgmparam(struct tty *tp, struct termios *t)
1901 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1902 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1903 volatile struct board_chan *bc;
1904 struct dgm_softc *sc;
1912 BoardMemWinState ws = bmws_get();
1914 sc = devclass_get_softc(dgmdevclass, unit);
1915 port = &sc->ports[pnum];
1918 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);
1920 if (port->mustdrain) {
1921 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1925 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1927 if (t->c_ispeed == 0)
1928 t->c_ispeed = t->c_ospeed;
1930 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1931 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1938 if (cflag == 0) { /* hangup */
1939 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1943 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1944 mval= port->omodem & ~(DTR|RTS);
1946 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1948 if (cflag != port->fepcflag) {
1949 port->fepcflag = cflag;
1950 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1951 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1952 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1954 mval= port->omodem | (DTR|RTS);
1957 iflag = dgmflags(dgm_iflags, t->c_iflag);
1958 if (iflag != port->fepiflag) {
1959 port->fepiflag = iflag;
1960 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1961 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1964 bc->mint = port->dcd;
1966 hflow = dgmflags(dgm_flow, t->c_cflag);
1967 if (hflow != port->hflow) {
1968 port->hflow = hflow;
1969 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1970 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1973 if (port->omodem != mval) {
1974 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1975 unit, pnum, mval, port->omodem);
1976 port->omodem = mval;
1977 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1980 if (port->fepstartc != t->c_cc[VSTART] ||
1981 port->fepstopc != t->c_cc[VSTOP]) {
1982 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1983 port->fepstartc = t->c_cc[VSTART];
1984 port->fepstopc = t->c_cc[VSTOP];
1985 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1996 dgmstart(struct tty *tp)
2001 struct dgm_softc *sc;
2002 volatile struct board_chan *bc;
2008 BoardMemWinState ws = bmws_get();
2010 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2011 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2012 sc = devclass_get_softc(dgmdevclass, unit);
2013 port = &sc->ports[pnum];
2016 wmask = port->txbufsize - 1;
2020 while (tp->t_outq.c_cc != 0) {
2022 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2025 if (tp->t_outq.c_cc <= tp->t_lowat) {
2026 if (tp->t_state & TS_ASLEEP) {
2027 tp->t_state &= ~TS_ASLEEP;
2028 wakeup(TSA_OLOWAT(tp));
2030 /*selwakeup(&tp->t_wsel);*/
2036 head = bc->tin & wmask;
2038 do { tail = bc->tout; } while (tail != bc->tout);
2039 tail = bc->tout & wmask;
2041 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2043 #ifdef LEAVE_FREE_CHARS
2045 size = tail - head - LEAVE_FREE_CHARS;
2049 size = port->txbufsize - head;
2050 if (tail + port->txbufsize < head)
2056 size = tail - head - 1;
2058 size = port->txbufsize - head;
2069 tp->t_state |= TS_BUSY;
2074 towin(sc, port->txwin);
2076 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2078 if (head >= port->txbufsize)
2079 head -= port->txbufsize;
2084 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2085 unit, pnum, size, ocount);
2093 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2094 if (tp->t_state & TS_BUSY) {
2095 tp->t_state &= ~TS_BUSY;
2096 linesw[tp->t_line].l_start(tp);
2100 if (tp->t_state & TS_ASLEEP) {
2101 tp->t_state &= ~TS_ASLEEP;
2102 wakeup(TSA_OLOWAT(tp));
2104 tp->t_state& = ~TS_BUSY;
2109 dgmstop(struct tty *tp, int rw)
2114 struct dgm_softc *sc;
2115 volatile struct board_chan *bc;
2118 BoardMemWinState ws = bmws_get();
2120 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2121 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2123 sc = devclass_get_softc(dgmdevclass, unit);
2124 port = &sc->ports[pnum];
2127 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2133 /* clear output queue */
2134 bc->tout = bc->tin = 0;
2139 /* clear input queue */
2150 fepcmd(struct dgm_p *port,
2158 unsigned tail, head;
2161 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2162 mem = port->sc->vmem;
2164 if (!port->enabled) {
2165 printf("dgm%d: port%d: FEP command on disabled port\n",
2166 port->sc->unit, port->pnum);
2170 /* setwin(port->sc, 0); Require this to be set by caller */
2171 head = port->sc->mailbox->cin;
2173 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2174 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2175 port->sc->unit, port->pnum, head);
2179 mem[head + FEP_CSTART] = cmd;
2180 mem[head + FEP_CSTART + 1] = port->pnum;
2182 mem[head + FEP_CSTART + 2] = op1;
2183 mem[head + FEP_CSTART + 3] = op2;
2185 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2186 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2189 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2190 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2192 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2193 port->sc->mailbox->cin = head;
2197 while (count-- != 0) {
2198 head = port->sc->mailbox->cin;
2199 tail = port->sc->mailbox->cout;
2201 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2202 if (n <= ncmds * (sizeof(ushort)*4))
2205 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2209 disc_optim(struct tty *tp, struct termios *t)
2211 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2212 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2213 && (!(t->c_iflag & PARMRK)
2214 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2215 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2216 && linesw[tp->t_line].l_rint == ttyinput)
2217 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2219 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;