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.8 2004/05/13 23:49:19 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
117 /* digiboard port structure */
119 unsigned enabled : 1;
121 struct dgm_softc *sc; /* parent softc */
122 u_char pnum; /* port number */
123 u_char omodem; /* FEP output modem status */
124 u_char imodem; /* FEP input modem status */
125 u_char modemfake; /* Modem values to be forced */
126 u_char modem; /* Force values */
150 volatile struct board_chan *brdchan;
153 u_char active_out; /* nonzero if the callout device is open */
154 u_int wopeners; /* # processes waiting for DCD in open() */
157 struct termios it_in; /* should be in struct tty */
158 struct termios it_out;
161 struct termios lt_in; /* should be in struct tty */
162 struct termios lt_out;
164 unsigned do_timestamp : 1;
165 unsigned do_dcd_timestamp : 1;
166 struct timeval timestamp;
167 struct timeval dcd_timestamp;
169 /* flags of state, are used in sleep() too */
170 u_char closing; /* port is being closed now */
171 u_char draining; /* port is being drained now */
172 u_char used; /* port is being used now */
173 u_char mustdrain; /* data must be waited to drain in dgmparam() */
176 /* Digiboard per-board structure */
178 /* struct board_info */
179 unsigned enabled : 1;
180 u_char unit; /* unit number */
181 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
182 u_char altpin; /* do we need alternate pin setting ? */
183 int numports; /* number of ports on card */
184 u_long port; /* I/O port */
185 u_char *vmem; /* virtual memory address */
186 u_long pmem; /* physical memory address */
187 int mem_seg; /* internal memory segment */
188 struct dgm_p *ports; /* ptr to array of port descriptors */
189 struct tty *ttys; /* ptr to array of TTY structures */
190 volatile struct global_data *mailbox;
191 struct resource *io_res;
192 struct resource *mem_res;
195 struct callout_handle toh; /* poll timeout handle */
198 static void dgmpoll(void *);
199 static int dgmprobe(device_t);
200 static int dgmattach(device_t);
201 static int dgmdetach(device_t);
202 static int dgmshutdown(device_t);
203 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
205 static void dgmstart(struct tty *);
206 static void dgmstop(struct tty *, int);
207 static int dgmparam(struct tty *, struct termios *);
208 static void dgmhardclose(struct dgm_p *);
209 static void dgm_drain_or_flush(struct dgm_p *);
210 static int dgmdrain(struct dgm_p *);
211 static void dgm_pause(void *);
212 static void wakeflush(void *);
213 static void disc_optim(struct tty *, struct termios *);
215 static d_open_t dgmopen;
216 static d_close_t dgmclose;
217 static d_ioctl_t dgmioctl;
219 static device_method_t dgmmethods[] = {
220 /* Device interface */
221 DEVMETHOD(device_probe, dgmprobe),
222 DEVMETHOD(device_attach, dgmattach),
223 DEVMETHOD(device_detach, dgmdetach),
224 DEVMETHOD(device_shutdown, dgmshutdown),
228 static driver_t dgmdriver = {
231 sizeof (struct dgm_softc),
234 static devclass_t dgmdevclass;
236 #define CDEV_MAJOR 101
237 static struct cdevsw dgm_cdevsw = {
239 /* maj */ CDEV_MAJOR,
240 /* flags */ D_TTY | D_KQFILTER,
245 /* close */ dgmclose,
247 /* write */ ttywrite,
248 /* ioctl */ dgmioctl,
251 /* strategy */ nostrategy,
254 /* kqfilter */ ttykqfilter
258 dgmmodhandler(module_t mod, int event, void *arg)
264 cdevsw_add(&dgm_cdevsw);
268 cdevsw_remove(&dgm_cdevsw);
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);
424 sc->unit = device_get_unit(dev);
426 /* Check that we've got a valid i/o address */
427 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
429 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
430 if (sc->port == validio[i])
433 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
437 /* Ditto for our memory address */
438 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
440 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
441 if (sc->pmem == validmem[i])
444 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
447 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
448 device_printf(dev, "0x%lx: Memory address not supported\n",
452 sc->vmem = (u_char *)sc->pmem;
454 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
457 /* Temporarily map our io ports */
459 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
460 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
461 if (sc->io_res == NULL)
464 outb(sc->port, FEPRST);
467 for (i = 0; i < 1000; i++) {
469 if ((inb(sc->port) & FEPMASK) == FEPRST) {
471 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
478 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
479 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
483 /* check type of card and get internal memory characteristics */
491 second = inb(sc->port);
492 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
494 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
497 sc->mem_seg = 0x8000;
499 /* Temporarily map our memory too */
501 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
502 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
503 if (sc->mem_res == NULL) {
504 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
505 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
509 outb(sc->port, FEPCLR); /* drop RESET */
510 hidewin(sc); /* Helg: to set initial bmws state */
512 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
513 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
515 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
516 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
518 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
524 dgmattach(device_t dev)
526 struct dgm_softc *sc = device_get_softc(dev);
532 volatile struct board_chan *bc;
535 u_long msize, iosize;
537 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
539 sc->unit = device_get_unit(dev);
540 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
541 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
542 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
544 sc->mem_seg = 0x8000;
547 sc->mem_seg = 0x8000;
549 /* Allocate resources (should have been verified in dgmprobe()) */
551 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
552 0ul, ~0ul, iosize, RF_ACTIVE);
553 if (sc->io_res == NULL)
556 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
557 0ul, ~0ul, msize, RF_ACTIVE);
558 if (sc->mem_res == NULL) {
559 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
560 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
565 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
567 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
570 outb(sc->port, FEPRST);
573 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
575 device_printf(dev, "1st reset failed\n");
578 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
579 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
585 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
587 t = sc->pmem >> 8; /* disable windowing */
588 outb(sc->port + 2, t & 0xFF);
589 outb(sc->port + 3, t >> 8);
593 /* very short memory test */
594 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
596 addr = setwin(sc, BOTWIN);
597 *(u_long *)(mem + addr) = 0xA55A3CC3;
598 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
599 device_printf(dev, "1st memory test failed\n");
602 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
603 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
607 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
609 addr = setwin(sc, TOPWIN);
610 *(u_long *)(mem + addr) = 0x5AA5C33C;
611 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
612 device_printf(dev, "2nd memory test failed\n");
615 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
616 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
620 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
622 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
623 *(u_long *)(mem + addr) = 0x5AA5C33C;
624 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
625 device_printf(dev, "3rd (BIOS) memory test failed\n");
627 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
629 addr = setwin(sc, MISCGLOBAL);
630 for (i = 0; i < 16; i++)
633 addr = setwin(sc, BIOSOFFSET);
635 for (i = 0; ptr < mem + msize; i++)
636 *ptr++ = pcem_bios[i];
638 ptr = mem + BIOSOFFSET;
639 for (i = 0; ptr < mem + msize; i++) {
640 if (*ptr++ != pcem_bios[i]) {
641 printf("Low BIOS load failed\n");
644 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
645 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
649 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
651 addr = setwin(sc, msize);
653 for (;i < pcem_nbios; i++)
654 *ptr++ = pcem_bios[i];
657 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
658 if (*ptr++ != pcem_bios[i]) {
659 printf("High BIOS load failed\n");
662 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
663 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
667 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
668 device_printf(dev, "DigiBIOS loaded, initializing");
670 addr = setwin(sc, 0);
672 *(u_int *)(mem + addr) = 0x0bf00401;
673 *(u_int *)(mem + addr + 4) = 0;
674 *(ushort *)(mem + addr + 0xc00) = 0;
677 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
680 printf("\nBIOS initialize failed(1)\n");
683 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
684 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
689 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
690 printf("\nBIOS initialize failed(2)\n");
693 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
694 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
697 printf(", DigiBIOS running\n");
701 addr = setwin(sc, BIOSOFFSET);
703 for (i = 0; i < pcem_ncook; i++)
704 *ptr++ = pcem_cook[i];
706 ptr = mem + BIOSOFFSET;
707 for (i = 0; i < pcem_ncook; i++) {
708 if (*ptr++ != pcem_cook[i]) {
709 printf("FEP/OS load failed\n");
712 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
713 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
717 device_printf(dev, "FEP/OS loaded, initializing");
719 addr = setwin(sc, 0);
720 *(ushort *)(mem + addr + 0xd20) = 0;
721 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
722 *(u_int *)(mem + addr + 0xc30) = 0x3L;
725 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
728 printf("\nFEP/OS initialize failed(1)\n");
731 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
732 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
737 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
738 printf("\nFEP/OS initialize failed(2)\n");
741 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
742 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
745 printf(", FEP/OS running\n");
747 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
748 device_printf(dev, "%d ports attached\n", sc->numports);
750 if (sc->numports > MAX_DGM_PORTS) {
751 printf("dgm%d: too many ports\n", sc->unit);
754 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
755 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
759 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
760 M_TTYS, M_WAITOK|M_ZERO);
761 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
762 M_TTYS, M_WAITOK|M_ZERO);
764 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
765 for (i = 0; i < sc->numports; i++)
766 sc->ports[i].enabled = 1;
768 /* We should now init per-port structures */
770 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
771 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
773 if (sc->numports < 3)
778 for (i = 0; i < sc->numports; i++, bc++) {
779 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
780 port = &sc->ports[i];
783 port->tty = &sc->ttys[i];
791 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
793 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
794 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
798 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
799 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
800 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
801 port->txwin = FEPWIN | (bc->tseg >> 11);
802 port->rxwin = FEPWIN | (bc->rseg >> 11);
806 port->txbufsize = bc->tmax + 1;
807 port->rxbufsize = bc->rmax + 1;
809 lowwater = (port->txbufsize >= 2000) ?
810 1024 : (port->txbufsize / 2);
813 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
814 sc->unit, i, lowwater);
815 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
816 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
817 sc->unit, i, port->rxbufsize / 4);
818 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
819 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
820 sc->unit, i, 3 * port->rxbufsize / 4);
821 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
826 port->startc = bc->startc;
827 port->startca = bc->startca;
828 port->stopc = bc->stopc;
829 port->stopca = bc->stopca;
831 /* port->close_delay = 50; */
832 port->close_delay = 3 * hz;
833 port->do_timestamp = 0;
834 port->do_dcd_timestamp = 0;
836 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
838 * We don't use all the flags from <sys/ttydefaults.h> since
839 * they are only relevant for logins. It's important to have
840 * echo off initially so that the line doesn't start
841 * blathering before the echo flag can be turned off.
843 port->it_in.c_iflag = TTYDEF_IFLAG;
844 port->it_in.c_oflag = TTYDEF_OFLAG;
845 port->it_in.c_cflag = TTYDEF_CFLAG;
846 port->it_in.c_lflag = TTYDEF_LFLAG;
847 termioschars(&port->it_in);
848 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
849 port->it_out = port->it_in;
851 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
852 make_dev(&dgm_cdevsw, (sc->unit*65536) + i, UID_ROOT,
853 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
854 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 64, UID_ROOT,
855 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
856 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 128, UID_ROOT,
857 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
858 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262144, UID_UUCP,
859 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
860 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262208, UID_UUCP,
861 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
862 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262272, UID_UUCP,
863 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
866 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
870 /* start the polling function */
871 sc->toh = timeout(dgmpoll, (void *)(int)sc->unit, hz / POLLSPERSEC);
873 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
879 dgmdetach(device_t dev)
881 struct dgm_softc *sc = device_get_softc(dev);
884 for (i = 0; i < sc->numports; i++)
885 if (sc->ttys[i].t_state & TS_ISOPEN)
888 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
890 for (i = 0; i < sc->numports; i++) {
891 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i));
892 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 64));
893 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 128));
894 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262144));
895 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262208));
896 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262272));
899 untimeout(dgmpoll, (void *)(int)sc->unit, sc->toh);
900 callout_handle_init(&sc->toh);
902 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
903 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
905 FREE(sc->ports, M_TTYS);
906 FREE(sc->ttys, M_TTYS);
912 dgmshutdown(device_t dev)
915 struct dgm_softc *sc = device_get_softc(dev);
917 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
925 dgmopen(dev_t dev, int flag, int mode, struct thread *td)
927 struct dgm_softc *sc;
935 volatile struct board_chan *bc;
939 unit = MINOR_TO_UNIT(mynor);
940 pnum = MINOR_TO_PORT(mynor);
942 sc = devclass_get_softc(dgmdevclass, unit);
944 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
949 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
952 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
957 if (pnum >= sc->numports) {
958 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
963 if (mynor & CONTROL_MASK)
966 tp = &sc->ttys[pnum];
968 port = &sc->ports[pnum];
974 while (port->closing) {
975 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
978 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
979 " error = %d\n", unit, pnum, error);
984 if (tp->t_state & TS_ISOPEN) {
986 * The device is open, so everything has been initialized.
989 if (mynor & CALLOUT_MASK) {
990 if (!port->active_out) {
992 DPRINT4(DB_OPEN, "dgm%d: port%d:"
993 " BUSY error = %d\n", unit, pnum, error);
996 } else if (port->active_out) {
997 if (flag & O_NONBLOCK) {
999 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1000 " BUSY error = %d\n", unit, pnum, error);
1003 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1005 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1006 " error = %d\n", unit, pnum, error);
1012 if (tp->t_state & TS_XCLUDE && suser(td)) {
1018 * The device isn't open, so there are no conflicts.
1019 * Initialize it. Initialization is done twice in many
1020 * cases: to preempt sleeping callin opens if we are
1021 * callout, and to complete a callin open after DCD rises.
1023 tp->t_oproc = dgmstart;
1024 tp->t_param = dgmparam;
1025 tp->t_stop = dgmstop;
1027 tp->t_termios= (mynor & CALLOUT_MASK) ?
1033 port->imodem = bc->mstat;
1034 bc->rout = bc->rin; /* clear input queue */
1036 #ifdef PRINT_BUFSIZE
1037 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1038 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1045 error = dgmparam(tp, &tp->t_termios);
1049 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1054 /* handle fake DCD for callout devices */
1055 /* and initial DCD */
1057 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1058 linesw[tp->t_line].l_modem(tp, 1);
1062 * Wait for DCD if necessary.
1064 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1065 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1067 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1070 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1071 " error = %d\n", unit, pnum, error);
1077 error = linesw[tp->t_line].l_open(dev, tp);
1078 disc_optim(tp, &tp->t_termios);
1079 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1082 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1083 port->active_out = 1;
1087 /* If any port is open (i.e. the open() call is completed for it)
1088 * the device is busy
1092 disc_optim(tp, &tp->t_termios);
1095 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1098 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1106 dgmclose(dev_t dev, int flag, int mode, struct thread *td)
1111 struct dgm_softc *sc;
1117 if (mynor & CONTROL_MASK)
1119 unit = MINOR_TO_UNIT(mynor);
1120 pnum = MINOR_TO_PORT(mynor);
1122 sc = devclass_get_softc(dgmdevclass, unit);
1123 tp = &sc->ttys[pnum];
1124 port = sc->ports + pnum;
1126 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1128 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1129 dgm_drain_or_flush(port);
1134 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1135 linesw[tp->t_line].l_close(tp, flag);
1136 disc_optim(tp, &tp->t_termios);
1138 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1140 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1143 wakeup(&port->closing);
1146 /* mark the card idle when all ports are closed */
1148 for (i = 0; i < sc->numports; i++)
1149 if (sc->ports[i].used)
1154 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1156 wakeup(TSA_CARR_ON(tp));
1157 wakeup(&port->active_out);
1158 port->active_out = 0;
1160 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1166 dgmhardclose(struct dgm_p *port)
1168 volatile struct board_chan *bc = port->brdchan;
1169 struct dgm_softc *sc;
1172 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1173 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1175 port->do_timestamp = 0;
1181 if (port->tty->t_cflag & HUPCL) {
1182 port->omodem &= ~(RTS|DTR);
1183 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1189 timeout(dgm_pause, &port->brdchan, hz/2);
1190 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1194 dgm_pause(void *chan)
1196 wakeup((caddr_t)chan);
1200 dgmpoll(void *unit_c)
1202 int unit = (int)unit_c;
1205 struct dgm_softc *sc;
1208 int event, mstat, lstat;
1209 volatile struct board_chan *bc;
1216 int ibuf_full, obuf_full;
1217 BoardMemWinState ws = bmws_get();
1219 sc = devclass_get_softc(dgmdevclass, unit);
1220 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1221 callout_handle_init(&sc->toh);
1224 printf("dgm%d: polling of disabled board stopped\n", unit);
1230 head = sc->mailbox->ein;
1231 tail = sc->mailbox->eout;
1233 while (head != tail) {
1234 if (head >= FEP_IMAX - FEP_ISTART
1235 || tail >= FEP_IMAX - FEP_ISTART
1236 || (head|tail) & 03 ) {
1237 printf("dgm%d: event queue's head or tail is wrong!"
1238 " hd = %d, tl = %d\n", unit, head, tail);
1242 eventbuf = sc->vmem + tail + FEP_ISTART;
1244 event = eventbuf[1];
1245 mstat = eventbuf[2];
1246 lstat = eventbuf[3];
1248 port = &sc->ports[pnum];
1250 tp = &sc->ttys[pnum];
1252 if (pnum >= sc->numports || !port->enabled) {
1253 printf("dgm%d: port%d: got event on nonexisting port\n",
1255 } else if (port->used || port->wopeners > 0 ) {
1257 int wrapmask = port->rxbufsize - 1;
1259 if (!(event & ALL_IND))
1260 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1261 unit, pnum, event, mstat, lstat);
1263 if (event & DATA_IND) {
1264 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1267 rhead = bc->rin & wrapmask;
1268 rtail = bc->rout & wrapmask;
1270 if (!(tp->t_cflag & CREAD) || !port->used ) {
1276 printf("dgm%d: port%d: overrun\n", unit, pnum);
1280 if (!(tp->t_state & TS_ISOPEN))
1283 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1284 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1285 " p rx head = %d tail = %d\n", unit,
1286 pnum, rhead, rtail);
1289 size = rhead - rtail;
1291 size = port->rxbufsize - rtail;
1293 ptr = port->rxptr + rtail;
1296 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1297 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1298 DPRINT1(DB_RXDATA, "*");
1303 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1304 DPRINT1(DB_RXDATA, "!");
1305 towin(sc, port->rxwin);
1308 tp->t_rawcc += size;
1316 towin(sc, port->rxwin);
1319 (*linesw[tp->t_line].l_rint)(chr, tp);
1324 rtail= (rtail + size) & wrapmask;
1326 rhead = bc->rin & wrapmask;
1334 if (event & MODEMCHG_IND) {
1335 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1336 "MODEMCHG_IND\n", unit, pnum);
1337 port->imodem = mstat;
1338 if (mstat & port->dcd) {
1340 linesw[tp->t_line].l_modem(tp, 1);
1342 wakeup(TSA_CARR_ON(tp));
1345 linesw[tp->t_line].l_modem(tp, 0);
1347 if (port->draining) {
1349 wakeup(&port->draining);
1354 if (event & BREAK_IND) {
1355 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1356 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1357 " BREAK_IND\n", unit, pnum);
1359 linesw[tp->t_line].l_rint(TTY_BI, tp);
1364 /* Helg: with output flow control */
1366 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1367 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1368 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1370 if ((event & EMPTYTX_IND ) &&
1371 tp->t_outq.c_cc == 0 && port->draining) {
1373 wakeup(&port->draining);
1378 int wrapmask = port->txbufsize - 1;
1380 for (obuf_full = FALSE;
1381 tp->t_outq.c_cc != 0 && !obuf_full;
1384 /* add "last-minute" data to write buffer */
1385 if (!(tp->t_state & TS_BUSY)) {
1387 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1390 if (tp->t_outq.c_cc <= tp->t_lowat) {
1391 if (tp->t_state & TS_ASLEEP) {
1392 tp->t_state &= ~TS_ASLEEP;
1393 wakeup(TSA_OLOWAT(tp));
1395 /* selwakeup(&tp->t_wsel); */
1402 whead = bc->tin & wrapmask;
1403 wtail = bc->tout & wrapmask;
1406 size = wtail - whead - 1;
1408 size = port->txbufsize - whead;
1414 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1415 whead, wtail, size, obuf_full);
1423 towin(sc, port->txwin);
1425 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1430 bc->tin = whead & wrapmask;
1435 DPRINT1(DB_WR, " +BUSY\n");
1436 tp->t_state |= TS_BUSY;
1438 DPRINT1(DB_WR, " -BUSY\n");
1440 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1441 /* should clear TS_BUSY before ttwwakeup */
1442 if (tp->t_state & TS_BUSY) {
1443 tp->t_state &= ~TS_BUSY;
1444 linesw[tp->t_line].l_start(tp);
1448 if (tp->t_state & TS_ASLEEP) {
1449 tp->t_state &= ~TS_ASLEEP;
1450 wakeup(TSA_OLOWAT(tp));
1452 tp->t_state &= ~TS_BUSY;
1458 bc->idata = 1; /* require event on incoming data */
1462 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1465 bc->idata = bc->iempty = bc->ilow = 0;
1468 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1471 sc->mailbox->eout = tail;
1474 sc->toh = timeout(dgmpoll, unit_c, hz / POLLSPERSEC);
1476 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1480 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1482 struct dgm_softc *sc;
1487 volatile struct board_chan *bc;
1492 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1494 struct termios term;
1497 BoardMemWinState ws = bmws_get();
1500 unit = MINOR_TO_UNIT(mynor);
1501 pnum = MINOR_TO_PORT(mynor);
1503 sc = devclass_get_softc(dgmdevclass, unit);
1504 port = &sc->ports[pnum];
1505 tp = &sc->ttys[pnum];
1508 if (mynor & CONTROL_MASK) {
1511 switch (mynor & CONTROL_MASK) {
1512 case CONTROL_INIT_STATE:
1513 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1515 case CONTROL_LOCK_STATE:
1516 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1519 return (ENODEV); /* /dev/nodev */
1526 *ct = *(struct termios *)data;
1529 *(struct termios *)data = *ct;
1532 *(int *)data = TTYDISC;
1535 bzero(data, sizeof(struct winsize));
1542 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1543 term = tp->t_termios;
1544 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1545 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);
1548 error = ttsetcompat(tp, &cmd, data, &term);
1552 data = (caddr_t)&term;
1555 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1557 struct termios *dt = (struct termios *)data;
1558 struct termios *lt = mynor & CALLOUT_MASK
1559 ? &port->lt_out : &port->lt_in;
1561 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);
1562 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1563 | (dt->c_iflag & ~lt->c_iflag);
1564 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1565 | (dt->c_oflag & ~lt->c_oflag);
1566 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1567 | (dt->c_cflag & ~lt->c_cflag);
1568 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1569 | (dt->c_lflag & ~lt->c_lflag);
1570 for (cc = 0; cc < NCCS; ++cc)
1571 if (lt->c_cc[cc] != 0)
1572 dt->c_cc[cc] = tp->t_cc[cc];
1573 if (lt->c_ispeed != 0)
1574 dt->c_ispeed = tp->t_ispeed;
1575 if (lt->c_ospeed != 0)
1576 dt->c_ospeed = tp->t_ospeed;
1579 if (cmd == TIOCSTOP) {
1582 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1586 } else if (cmd == TIOCSTART) {
1589 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1595 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1596 port->mustdrain = 1;
1598 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
1599 if (error != ENOIOCTL)
1602 error = ttioctl(tp, cmd, data, flag);
1603 disc_optim(tp, &tp->t_termios);
1604 port->mustdrain = 0;
1605 if (error != ENOIOCTL) {
1607 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1608 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);
1616 error = dgmdrain(port);
1627 /* now it sends 400 millisecond break because I don't know */
1628 /* how to send an infinite break */
1630 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1635 /* now it's empty */
1638 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1639 port->omodem |= DTR;
1642 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1644 if (!(bc->mstat & DTR))
1645 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1651 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1652 port->omodem &= ~DTR;
1655 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1657 if (bc->mstat & DTR) {
1658 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1665 if (*(int *)data & TIOCM_DTR)
1666 port->omodem |= DTR;
1668 port->omodem &= ~DTR;
1670 if (*(int *)data & TIOCM_RTS)
1671 port->omodem |= RTS;
1673 port->omodem &= ~RTS;
1677 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1682 if (*(int *)data & TIOCM_DTR)
1683 port->omodem |= DTR;
1685 if (*(int *)data & TIOCM_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);
1709 port->imodem = bc->mstat;
1712 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1714 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1716 if (port->imodem & DTR) {
1717 DPRINT1(DB_MODEM, "DTR ");
1718 tiocm_xxx |= TIOCM_DTR;
1720 if (port->imodem & RTS) {
1721 DPRINT1(DB_MODEM, "RTS ");
1722 tiocm_xxx |= TIOCM_RTS;
1724 if (port->imodem & CTS) {
1725 DPRINT1(DB_MODEM, "CTS ");
1726 tiocm_xxx |= TIOCM_CTS;
1728 if (port->imodem & port->dcd) {
1729 DPRINT1(DB_MODEM, "DCD ");
1730 tiocm_xxx |= TIOCM_CD;
1732 if (port->imodem & port->dsr) {
1733 DPRINT1(DB_MODEM, "DSR ");
1734 tiocm_xxx |= TIOCM_DSR;
1736 if (port->imodem & RI) {
1737 DPRINT1(DB_MODEM, "RI ");
1738 tiocm_xxx |= TIOCM_RI;
1740 *(int *)data = tiocm_xxx;
1741 DPRINT1(DB_MODEM, "--\n");
1744 /* must be root since the wait applies to following logins */
1750 port->close_delay = *(int *)data * hz / 100;
1753 *(int *)data = port->close_delay * 100 / hz;
1756 port->do_timestamp = 1;
1757 *(struct timeval *)data = port->timestamp;
1759 case TIOCDCDTIMESTAMP:
1760 port->do_dcd_timestamp = 1;
1761 *(struct timeval *)data = port->dcd_timestamp;
1777 struct dgm_p *port = p;
1779 wakeup(&port->draining);
1782 /* wait for the output to drain */
1785 dgmdrain(struct dgm_p *port)
1787 volatile struct board_chan *bc = port->brdchan;
1788 struct dgm_softc *sc;
1791 BoardMemWinState ws = bmws_get();
1793 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1801 while (tail != head) {
1802 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1803 port->sc->unit, port->pnum, head, tail);
1807 timeout(wakeflush, port, hz);
1808 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1813 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1814 port->sc->unit, port->pnum, error);
1824 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1825 port->sc->unit, port->pnum, head, tail);
1830 /* wait for the output to drain */
1831 /* or simply clear the buffer it it's stopped */
1834 dgm_drain_or_flush(struct dgm_p *port)
1836 volatile struct board_chan *bc = port->brdchan;
1837 struct tty *tp = port->tty;
1838 struct dgm_softc *sc;
1843 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1851 while (tail != head /* && tail != lasttail */ ) {
1852 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1853 port->sc->unit, port->pnum, head, tail);
1855 /* if there is no carrier simply clean the buffer */
1856 if (!(tp->t_state & TS_CARR_ON)) {
1857 bc->tout = bc->tin = 0;
1865 timeout(wakeflush, port, hz);
1866 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1871 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1872 " error = %d\n", port->sc->unit, port->pnum, error);
1874 /* silently clean the buffer */
1876 bc->tout = bc->tin = 0;
1887 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1888 port->sc->unit, port->pnum, head, tail);
1892 dgmparam(struct tty *tp, struct termios *t)
1894 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1895 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1896 volatile struct board_chan *bc;
1897 struct dgm_softc *sc;
1905 BoardMemWinState ws = bmws_get();
1907 sc = devclass_get_softc(dgmdevclass, unit);
1908 port = &sc->ports[pnum];
1911 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);
1913 if (port->mustdrain) {
1914 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1918 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1920 if (t->c_ispeed == 0)
1921 t->c_ispeed = t->c_ospeed;
1923 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1924 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1931 if (cflag == 0) { /* hangup */
1932 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1936 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1937 mval= port->omodem & ~(DTR|RTS);
1939 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1941 if (cflag != port->fepcflag) {
1942 port->fepcflag = cflag;
1943 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1944 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1945 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1947 mval= port->omodem | (DTR|RTS);
1950 iflag = dgmflags(dgm_iflags, t->c_iflag);
1951 if (iflag != port->fepiflag) {
1952 port->fepiflag = iflag;
1953 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1954 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1957 bc->mint = port->dcd;
1959 hflow = dgmflags(dgm_flow, t->c_cflag);
1960 if (hflow != port->hflow) {
1961 port->hflow = hflow;
1962 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1963 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1966 if (port->omodem != mval) {
1967 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1968 unit, pnum, mval, port->omodem);
1969 port->omodem = mval;
1970 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1973 if (port->fepstartc != t->c_cc[VSTART] ||
1974 port->fepstopc != t->c_cc[VSTOP]) {
1975 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1976 port->fepstartc = t->c_cc[VSTART];
1977 port->fepstopc = t->c_cc[VSTOP];
1978 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1989 dgmstart(struct tty *tp)
1994 struct dgm_softc *sc;
1995 volatile struct board_chan *bc;
2001 BoardMemWinState ws = bmws_get();
2003 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2004 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2005 sc = devclass_get_softc(dgmdevclass, unit);
2006 port = &sc->ports[pnum];
2009 wmask = port->txbufsize - 1;
2013 while (tp->t_outq.c_cc != 0) {
2015 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2018 if (tp->t_outq.c_cc <= tp->t_lowat) {
2019 if (tp->t_state & TS_ASLEEP) {
2020 tp->t_state &= ~TS_ASLEEP;
2021 wakeup(TSA_OLOWAT(tp));
2023 /*selwakeup(&tp->t_wsel);*/
2029 head = bc->tin & wmask;
2031 do { tail = bc->tout; } while (tail != bc->tout);
2032 tail = bc->tout & wmask;
2034 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2036 #ifdef LEAVE_FREE_CHARS
2038 size = tail - head - LEAVE_FREE_CHARS;
2042 size = port->txbufsize - head;
2043 if (tail + port->txbufsize < head)
2049 size = tail - head - 1;
2051 size = port->txbufsize - head;
2062 tp->t_state |= TS_BUSY;
2067 towin(sc, port->txwin);
2069 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2071 if (head >= port->txbufsize)
2072 head -= port->txbufsize;
2077 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2078 unit, pnum, size, ocount);
2086 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2087 if (tp->t_state & TS_BUSY) {
2088 tp->t_state &= ~TS_BUSY;
2089 linesw[tp->t_line].l_start(tp);
2093 if (tp->t_state & TS_ASLEEP) {
2094 tp->t_state &= ~TS_ASLEEP;
2095 wakeup(TSA_OLOWAT(tp));
2097 tp->t_state& = ~TS_BUSY;
2102 dgmstop(struct tty *tp, int rw)
2107 struct dgm_softc *sc;
2108 volatile struct board_chan *bc;
2111 BoardMemWinState ws = bmws_get();
2113 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2114 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2116 sc = devclass_get_softc(dgmdevclass, unit);
2117 port = &sc->ports[pnum];
2120 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2126 /* clear output queue */
2127 bc->tout = bc->tin = 0;
2132 /* clear input queue */
2143 fepcmd(struct dgm_p *port,
2151 unsigned tail, head;
2154 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2155 mem = port->sc->vmem;
2157 if (!port->enabled) {
2158 printf("dgm%d: port%d: FEP command on disabled port\n",
2159 port->sc->unit, port->pnum);
2163 /* setwin(port->sc, 0); Require this to be set by caller */
2164 head = port->sc->mailbox->cin;
2166 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2167 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2168 port->sc->unit, port->pnum, head);
2172 mem[head + FEP_CSTART] = cmd;
2173 mem[head + FEP_CSTART + 1] = port->pnum;
2175 mem[head + FEP_CSTART + 2] = op1;
2176 mem[head + FEP_CSTART + 3] = op2;
2178 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2179 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2182 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2183 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2185 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2186 port->sc->mailbox->cin = head;
2190 while (count-- != 0) {
2191 head = port->sc->mailbox->cin;
2192 tail = port->sc->mailbox->cout;
2194 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2195 if (n <= ncmds * (sizeof(ushort)*4))
2198 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2202 disc_optim(struct tty *tp, struct termios *t)
2204 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2205 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2206 && (!(t->c_iflag & PARMRK)
2207 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2208 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2209 && linesw[tp->t_line].l_rint == ttyinput)
2210 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2212 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;