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.4 2003/07/19 21:14: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>
98 #include <dev/dgb/dgmfep.h>
99 #include <dev/dgb/dgmbios.h>
100 #include <dev/dgb/dgmreg.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 /* close */ dgmclose,
241 /* write */ ttywrite,
242 /* ioctl */ dgmioctl,
245 /* strategy */ nostrategy,
247 /* maj */ CDEV_MAJOR,
250 /* flags */ D_TTY | D_KQFILTER,
252 /* kqfilter */ ttykqfilter,
256 dgmmodhandler(module_t mod, int event, void *arg)
262 cdevsw_add(&dgm_cdevsw);
266 cdevsw_remove(&dgm_cdevsw);
273 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
275 static speed_t dgmdefaultrate = TTYDEF_SPEED;
277 static struct speedtab dgmspeedtab[] = {
278 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
292 { 19200, FEP_B19200 },
293 { 38400, FEP_B38400 },
294 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
295 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
299 static struct dbgflagtbl {
304 { PARODD, PARODD, FEP_PARODD },
305 { PARENB, PARENB, FEP_PARENB },
306 { CSTOPB, CSTOPB, FEP_CSTOPB },
307 { CSIZE, CS5, FEP_CS6 },
308 { CSIZE, CS6, FEP_CS6 },
309 { CSIZE, CS7, FEP_CS7 },
310 { CSIZE, CS8, FEP_CS8 },
311 { CLOCAL, CLOCAL, FEP_CLOCAL },
314 { IGNBRK, IGNBRK, FEP_IGNBRK },
315 { BRKINT, BRKINT, FEP_BRKINT },
316 { IGNPAR, IGNPAR, FEP_IGNPAR },
317 { PARMRK, PARMRK, FEP_PARMRK },
318 { INPCK, INPCK, FEP_INPCK },
319 { ISTRIP, ISTRIP, FEP_ISTRIP },
320 { IXON, IXON, FEP_IXON },
321 { IXOFF, IXOFF, FEP_IXOFF },
322 { IXANY, IXANY, FEP_IXANY },
325 { CRTSCTS, CRTSCTS, CTS|RTS },
326 { CRTSCTS, CCTS_OFLOW, CTS },
327 { CRTSCTS, CRTS_IFLOW, RTS },
331 /* xlat bsd termios flags to dgm sys-v style */
333 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
338 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
339 if ((input & tbl[i].in_mask) == tbl[i].in_val)
340 output |= tbl[i].out_val;
345 static int dgmdebug = 0;
346 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
348 static __inline int setwin(struct dgm_softc *, unsigned);
349 static __inline void hidewin(struct dgm_softc *);
350 static __inline void towin(struct dgm_softc *, int);
352 /*Helg: to allow recursive dgm...() calls */
354 /* If we were called and don't want to disturb we need: */
355 int port; /* write to this port */
356 u_char data; /* this data on exit */
357 /* or DATA_WINOFF to close memory window on entry */
358 } BoardMemWinState; /* so several channels and even boards can coexist */
360 #define DATA_WINOFF 0
361 static BoardMemWinState bmws;
363 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
364 static u_long validmem[] = {
365 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
366 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
367 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
368 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
369 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
372 /* return current memory window state and close window */
373 static BoardMemWinState
376 BoardMemWinState bmwsRet = bmws;
378 if (bmws.data != DATA_WINOFF)
379 outb(bmws.port, bmws.data = DATA_WINOFF);
383 /* restore memory window state */
385 bmws_set(BoardMemWinState ws)
387 if (ws.data != bmws.data || ws.port != bmws.port) {
388 if (bmws.data != DATA_WINOFF)
389 outb(bmws.port, DATA_WINOFF);
390 if (ws.data != DATA_WINOFF)
391 outb(ws.port, ws.data);
397 setwin(struct dgm_softc *sc, unsigned int addr)
399 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
400 return (addr & 0x7FFF);
404 hidewin(struct dgm_softc *sc)
407 outb(bmws.port = sc->port + 1, bmws.data);
411 towin(struct dgm_softc *sc, int win)
413 outb(bmws.port = sc->port + 1, bmws.data = win);
417 dgmprobe(device_t dev)
419 struct dgm_softc *sc = device_get_softc(dev);
422 sc->unit = device_get_unit(dev);
424 /* Check that we've got a valid i/o address */
425 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
427 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
428 if (sc->port == validio[i])
431 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
435 /* Ditto for our memory address */
436 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
438 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
439 if (sc->pmem == validmem[i])
442 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
445 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
446 device_printf(dev, "0x%lx: Memory address not supported\n",
450 sc->vmem = (u_char *)sc->pmem;
452 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
455 /* Temporarily map our io ports */
457 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
458 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
459 if (sc->io_res == NULL)
462 outb(sc->port, FEPRST);
465 for (i = 0; i < 1000; i++) {
467 if ((inb(sc->port) & FEPMASK) == FEPRST) {
469 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
476 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
477 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
481 /* check type of card and get internal memory characteristics */
489 second = inb(sc->port);
490 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
492 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
495 sc->mem_seg = 0x8000;
497 /* Temporarily map our memory too */
499 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
500 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
501 if (sc->mem_res == NULL) {
502 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
503 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
507 outb(sc->port, FEPCLR); /* drop RESET */
508 hidewin(sc); /* Helg: to set initial bmws state */
510 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
511 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
513 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
514 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
516 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
522 dgmattach(device_t dev)
524 struct dgm_softc *sc = device_get_softc(dev);
530 volatile struct board_chan *bc;
533 u_long msize, iosize;
535 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
537 sc->unit = device_get_unit(dev);
538 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
539 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
540 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
542 sc->mem_seg = 0x8000;
545 sc->mem_seg = 0x8000;
547 /* Allocate resources (should have been verified in dgmprobe()) */
549 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
550 0ul, ~0ul, iosize, RF_ACTIVE);
551 if (sc->io_res == NULL)
554 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
555 0ul, ~0ul, msize, RF_ACTIVE);
556 if (sc->mem_res == NULL) {
557 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
558 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
563 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
565 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
568 outb(sc->port, FEPRST);
571 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
573 device_printf(dev, "1st reset failed\n");
576 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
577 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
583 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
585 t = sc->pmem >> 8; /* disable windowing */
586 outb(sc->port + 2, t & 0xFF);
587 outb(sc->port + 3, t >> 8);
591 /* very short memory test */
592 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
594 addr = setwin(sc, BOTWIN);
595 *(u_long *)(mem + addr) = 0xA55A3CC3;
596 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
597 device_printf(dev, "1st memory test failed\n");
600 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
601 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
605 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
607 addr = setwin(sc, TOPWIN);
608 *(u_long *)(mem + addr) = 0x5AA5C33C;
609 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
610 device_printf(dev, "2nd memory test failed\n");
613 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
614 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
618 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
620 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
621 *(u_long *)(mem + addr) = 0x5AA5C33C;
622 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
623 device_printf(dev, "3rd (BIOS) memory test failed\n");
625 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
627 addr = setwin(sc, MISCGLOBAL);
628 for (i = 0; i < 16; i++)
631 addr = setwin(sc, BIOSOFFSET);
633 for (i = 0; ptr < mem + msize; i++)
634 *ptr++ = pcem_bios[i];
636 ptr = mem + BIOSOFFSET;
637 for (i = 0; ptr < mem + msize; i++) {
638 if (*ptr++ != pcem_bios[i]) {
639 printf("Low BIOS load failed\n");
642 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
643 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
647 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
649 addr = setwin(sc, msize);
651 for (;i < pcem_nbios; i++)
652 *ptr++ = pcem_bios[i];
655 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
656 if (*ptr++ != pcem_bios[i]) {
657 printf("High BIOS load failed\n");
660 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
661 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
665 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
666 device_printf(dev, "DigiBIOS loaded, initializing");
668 addr = setwin(sc, 0);
670 *(u_int *)(mem + addr) = 0x0bf00401;
671 *(u_int *)(mem + addr + 4) = 0;
672 *(ushort *)(mem + addr + 0xc00) = 0;
675 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
678 printf("\nBIOS initialize failed(1)\n");
681 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
682 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
687 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
688 printf("\nBIOS initialize failed(2)\n");
691 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
692 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
695 printf(", DigiBIOS running\n");
699 addr = setwin(sc, BIOSOFFSET);
701 for (i = 0; i < pcem_ncook; i++)
702 *ptr++ = pcem_cook[i];
704 ptr = mem + BIOSOFFSET;
705 for (i = 0; i < pcem_ncook; i++) {
706 if (*ptr++ != pcem_cook[i]) {
707 printf("FEP/OS load failed\n");
710 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
711 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
715 device_printf(dev, "FEP/OS loaded, initializing");
717 addr = setwin(sc, 0);
718 *(ushort *)(mem + addr + 0xd20) = 0;
719 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
720 *(u_int *)(mem + addr + 0xc30) = 0x3L;
723 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
726 printf("\nFEP/OS initialize failed(1)\n");
729 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
730 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
735 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
736 printf("\nFEP/OS initialize failed(2)\n");
739 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
740 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
743 printf(", FEP/OS running\n");
745 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
746 device_printf(dev, "%d ports attached\n", sc->numports);
748 if (sc->numports > MAX_DGM_PORTS) {
749 printf("dgm%d: too many ports\n", sc->unit);
752 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
753 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
757 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
758 M_TTYS, M_WAITOK|M_ZERO);
759 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
760 M_TTYS, M_WAITOK|M_ZERO);
762 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
763 for (i = 0; i < sc->numports; i++)
764 sc->ports[i].enabled = 1;
766 /* We should now init per-port structures */
768 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
769 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
771 if (sc->numports < 3)
776 for (i = 0; i < sc->numports; i++, bc++) {
777 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
778 port = &sc->ports[i];
781 port->tty = &sc->ttys[i];
789 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
791 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
792 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
796 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
797 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
798 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
799 port->txwin = FEPWIN | (bc->tseg >> 11);
800 port->rxwin = FEPWIN | (bc->rseg >> 11);
804 port->txbufsize = bc->tmax + 1;
805 port->rxbufsize = bc->rmax + 1;
807 lowwater = (port->txbufsize >= 2000) ?
808 1024 : (port->txbufsize / 2);
811 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
812 sc->unit, i, lowwater);
813 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
814 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
815 sc->unit, i, port->rxbufsize / 4);
816 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
817 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
818 sc->unit, i, 3 * port->rxbufsize / 4);
819 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
824 port->startc = bc->startc;
825 port->startca = bc->startca;
826 port->stopc = bc->stopc;
827 port->stopca = bc->stopca;
829 /* port->close_delay = 50; */
830 port->close_delay = 3 * hz;
831 port->do_timestamp = 0;
832 port->do_dcd_timestamp = 0;
834 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
836 * We don't use all the flags from <sys/ttydefaults.h> since
837 * they are only relevant for logins. It's important to have
838 * echo off initially so that the line doesn't start
839 * blathering before the echo flag can be turned off.
841 port->it_in.c_iflag = TTYDEF_IFLAG;
842 port->it_in.c_oflag = TTYDEF_OFLAG;
843 port->it_in.c_cflag = TTYDEF_CFLAG;
844 port->it_in.c_lflag = TTYDEF_LFLAG;
845 termioschars(&port->it_in);
846 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
847 port->it_out = port->it_in;
849 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
850 make_dev(&dgm_cdevsw, (sc->unit*65536) + i, UID_ROOT,
851 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
852 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 64, UID_ROOT,
853 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
854 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 128, UID_ROOT,
855 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
856 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262144, UID_UUCP,
857 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
858 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262208, UID_UUCP,
859 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
860 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262272, UID_UUCP,
861 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
864 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
868 /* start the polling function */
869 sc->toh = timeout(dgmpoll, (void *)(int)sc->unit, hz / POLLSPERSEC);
871 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
877 dgmdetach(device_t dev)
879 struct dgm_softc *sc = device_get_softc(dev);
882 for (i = 0; i < sc->numports; i++)
883 if (sc->ttys[i].t_state & TS_ISOPEN)
886 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
888 for (i = 0; i < sc->numports; i++) {
889 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i));
890 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 64));
891 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 128));
892 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262144));
893 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262208));
894 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262272));
897 untimeout(dgmpoll, (void *)(int)sc->unit, sc->toh);
898 callout_handle_init(&sc->toh);
900 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
901 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
903 FREE(sc->ports, M_TTYS);
904 FREE(sc->ttys, M_TTYS);
910 dgmshutdown(device_t dev)
913 struct dgm_softc *sc = device_get_softc(dev);
915 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
923 dgmopen(dev_t dev, int flag, int mode, struct thread *td)
925 struct dgm_softc *sc;
933 volatile struct board_chan *bc;
937 unit = MINOR_TO_UNIT(mynor);
938 pnum = MINOR_TO_PORT(mynor);
940 sc = devclass_get_softc(dgmdevclass, unit);
942 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
947 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
950 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
955 if (pnum >= sc->numports) {
956 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
961 if (mynor & CONTROL_MASK)
964 tp = &sc->ttys[pnum];
966 port = &sc->ports[pnum];
972 while (port->closing) {
973 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
976 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
977 " error = %d\n", unit, pnum, error);
982 if (tp->t_state & TS_ISOPEN) {
984 * The device is open, so everything has been initialized.
987 if (mynor & CALLOUT_MASK) {
988 if (!port->active_out) {
990 DPRINT4(DB_OPEN, "dgm%d: port%d:"
991 " BUSY error = %d\n", unit, pnum, error);
994 } else if (port->active_out) {
995 if (flag & O_NONBLOCK) {
997 DPRINT4(DB_OPEN, "dgm%d: port%d:"
998 " BUSY error = %d\n", unit, pnum, error);
1001 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1003 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1004 " error = %d\n", unit, pnum, error);
1010 if (tp->t_state & TS_XCLUDE && suser(td)) {
1016 * The device isn't open, so there are no conflicts.
1017 * Initialize it. Initialization is done twice in many
1018 * cases: to preempt sleeping callin opens if we are
1019 * callout, and to complete a callin open after DCD rises.
1021 tp->t_oproc = dgmstart;
1022 tp->t_param = dgmparam;
1023 tp->t_stop = dgmstop;
1025 tp->t_termios= (mynor & CALLOUT_MASK) ?
1031 port->imodem = bc->mstat;
1032 bc->rout = bc->rin; /* clear input queue */
1034 #ifdef PRINT_BUFSIZE
1035 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1036 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1043 error = dgmparam(tp, &tp->t_termios);
1047 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1052 /* handle fake DCD for callout devices */
1053 /* and initial DCD */
1055 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1056 linesw[tp->t_line].l_modem(tp, 1);
1060 * Wait for DCD if necessary.
1062 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1063 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1065 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1068 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1069 " error = %d\n", unit, pnum, error);
1075 error = linesw[tp->t_line].l_open(dev, tp);
1076 disc_optim(tp, &tp->t_termios);
1077 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1080 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1081 port->active_out = 1;
1085 /* If any port is open (i.e. the open() call is completed for it)
1086 * the device is busy
1090 disc_optim(tp, &tp->t_termios);
1093 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1096 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1104 dgmclose(dev_t dev, int flag, int mode, struct thread *td)
1109 struct dgm_softc *sc;
1115 if (mynor & CONTROL_MASK)
1117 unit = MINOR_TO_UNIT(mynor);
1118 pnum = MINOR_TO_PORT(mynor);
1120 sc = devclass_get_softc(dgmdevclass, unit);
1121 tp = &sc->ttys[pnum];
1122 port = sc->ports + pnum;
1124 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1126 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1127 dgm_drain_or_flush(port);
1132 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1133 linesw[tp->t_line].l_close(tp, flag);
1134 disc_optim(tp, &tp->t_termios);
1136 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1138 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1141 wakeup(&port->closing);
1144 /* mark the card idle when all ports are closed */
1146 for (i = 0; i < sc->numports; i++)
1147 if (sc->ports[i].used)
1152 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1154 wakeup(TSA_CARR_ON(tp));
1155 wakeup(&port->active_out);
1156 port->active_out = 0;
1158 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1164 dgmhardclose(struct dgm_p *port)
1166 volatile struct board_chan *bc = port->brdchan;
1167 struct dgm_softc *sc;
1170 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1171 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1173 port->do_timestamp = 0;
1179 if (port->tty->t_cflag & HUPCL) {
1180 port->omodem &= ~(RTS|DTR);
1181 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1187 timeout(dgm_pause, &port->brdchan, hz/2);
1188 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1192 dgm_pause(void *chan)
1194 wakeup((caddr_t)chan);
1198 dgmpoll(void *unit_c)
1200 int unit = (int)unit_c;
1203 struct dgm_softc *sc;
1206 int event, mstat, lstat;
1207 volatile struct board_chan *bc;
1214 int ibuf_full, obuf_full;
1215 BoardMemWinState ws = bmws_get();
1217 sc = devclass_get_softc(dgmdevclass, unit);
1218 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1219 callout_handle_init(&sc->toh);
1222 printf("dgm%d: polling of disabled board stopped\n", unit);
1228 head = sc->mailbox->ein;
1229 tail = sc->mailbox->eout;
1231 while (head != tail) {
1232 if (head >= FEP_IMAX - FEP_ISTART
1233 || tail >= FEP_IMAX - FEP_ISTART
1234 || (head|tail) & 03 ) {
1235 printf("dgm%d: event queue's head or tail is wrong!"
1236 " hd = %d, tl = %d\n", unit, head, tail);
1240 eventbuf = sc->vmem + tail + FEP_ISTART;
1242 event = eventbuf[1];
1243 mstat = eventbuf[2];
1244 lstat = eventbuf[3];
1246 port = &sc->ports[pnum];
1248 tp = &sc->ttys[pnum];
1250 if (pnum >= sc->numports || !port->enabled) {
1251 printf("dgm%d: port%d: got event on nonexisting port\n",
1253 } else if (port->used || port->wopeners > 0 ) {
1255 int wrapmask = port->rxbufsize - 1;
1257 if (!(event & ALL_IND))
1258 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1259 unit, pnum, event, mstat, lstat);
1261 if (event & DATA_IND) {
1262 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1265 rhead = bc->rin & wrapmask;
1266 rtail = bc->rout & wrapmask;
1268 if (!(tp->t_cflag & CREAD) || !port->used ) {
1274 printf("dgm%d: port%d: overrun\n", unit, pnum);
1278 if (!(tp->t_state & TS_ISOPEN))
1281 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1282 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1283 " p rx head = %d tail = %d\n", unit,
1284 pnum, rhead, rtail);
1287 size = rhead - rtail;
1289 size = port->rxbufsize - rtail;
1291 ptr = port->rxptr + rtail;
1294 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1295 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1296 DPRINT1(DB_RXDATA, "*");
1301 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1302 DPRINT1(DB_RXDATA, "!");
1303 towin(sc, port->rxwin);
1306 tp->t_rawcc += size;
1314 towin(sc, port->rxwin);
1317 (*linesw[tp->t_line].l_rint)(chr, tp);
1322 rtail= (rtail + size) & wrapmask;
1324 rhead = bc->rin & wrapmask;
1332 if (event & MODEMCHG_IND) {
1333 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1334 "MODEMCHG_IND\n", unit, pnum);
1335 port->imodem = mstat;
1336 if (mstat & port->dcd) {
1338 linesw[tp->t_line].l_modem(tp, 1);
1340 wakeup(TSA_CARR_ON(tp));
1343 linesw[tp->t_line].l_modem(tp, 0);
1345 if (port->draining) {
1347 wakeup(&port->draining);
1352 if (event & BREAK_IND) {
1353 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1354 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1355 " BREAK_IND\n", unit, pnum);
1357 linesw[tp->t_line].l_rint(TTY_BI, tp);
1362 /* Helg: with output flow control */
1364 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1365 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1366 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1368 if ((event & EMPTYTX_IND ) &&
1369 tp->t_outq.c_cc == 0 && port->draining) {
1371 wakeup(&port->draining);
1376 int wrapmask = port->txbufsize - 1;
1378 for (obuf_full = FALSE;
1379 tp->t_outq.c_cc != 0 && !obuf_full;
1382 /* add "last-minute" data to write buffer */
1383 if (!(tp->t_state & TS_BUSY)) {
1385 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1388 if (tp->t_outq.c_cc <= tp->t_lowat) {
1389 if (tp->t_state & TS_ASLEEP) {
1390 tp->t_state &= ~TS_ASLEEP;
1391 wakeup(TSA_OLOWAT(tp));
1393 /* selwakeup(&tp->t_wsel); */
1400 whead = bc->tin & wrapmask;
1401 wtail = bc->tout & wrapmask;
1404 size = wtail - whead - 1;
1406 size = port->txbufsize - whead;
1412 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1413 whead, wtail, size, obuf_full);
1421 towin(sc, port->txwin);
1423 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1428 bc->tin = whead & wrapmask;
1433 DPRINT1(DB_WR, " +BUSY\n");
1434 tp->t_state |= TS_BUSY;
1436 DPRINT1(DB_WR, " -BUSY\n");
1438 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1439 /* should clear TS_BUSY before ttwwakeup */
1440 if (tp->t_state & TS_BUSY) {
1441 tp->t_state &= ~TS_BUSY;
1442 linesw[tp->t_line].l_start(tp);
1446 if (tp->t_state & TS_ASLEEP) {
1447 tp->t_state &= ~TS_ASLEEP;
1448 wakeup(TSA_OLOWAT(tp));
1450 tp->t_state &= ~TS_BUSY;
1456 bc->idata = 1; /* require event on incoming data */
1460 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1463 bc->idata = bc->iempty = bc->ilow = 0;
1466 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1469 sc->mailbox->eout = tail;
1472 sc->toh = timeout(dgmpoll, unit_c, hz / POLLSPERSEC);
1474 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1478 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1480 struct dgm_softc *sc;
1485 volatile struct board_chan *bc;
1490 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1492 struct termios term;
1495 BoardMemWinState ws = bmws_get();
1498 unit = MINOR_TO_UNIT(mynor);
1499 pnum = MINOR_TO_PORT(mynor);
1501 sc = devclass_get_softc(dgmdevclass, unit);
1502 port = &sc->ports[pnum];
1503 tp = &sc->ttys[pnum];
1506 if (mynor & CONTROL_MASK) {
1509 switch (mynor & CONTROL_MASK) {
1510 case CONTROL_INIT_STATE:
1511 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1513 case CONTROL_LOCK_STATE:
1514 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1517 return (ENODEV); /* /dev/nodev */
1524 *ct = *(struct termios *)data;
1527 *(struct termios *)data = *ct;
1530 *(int *)data = TTYDISC;
1533 bzero(data, sizeof(struct winsize));
1540 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1541 term = tp->t_termios;
1542 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1543 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);
1546 error = ttsetcompat(tp, &cmd, data, &term);
1550 data = (caddr_t)&term;
1553 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1555 struct termios *dt = (struct termios *)data;
1556 struct termios *lt = mynor & CALLOUT_MASK
1557 ? &port->lt_out : &port->lt_in;
1559 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);
1560 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1561 | (dt->c_iflag & ~lt->c_iflag);
1562 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1563 | (dt->c_oflag & ~lt->c_oflag);
1564 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1565 | (dt->c_cflag & ~lt->c_cflag);
1566 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1567 | (dt->c_lflag & ~lt->c_lflag);
1568 for (cc = 0; cc < NCCS; ++cc)
1569 if (lt->c_cc[cc] != 0)
1570 dt->c_cc[cc] = tp->t_cc[cc];
1571 if (lt->c_ispeed != 0)
1572 dt->c_ispeed = tp->t_ispeed;
1573 if (lt->c_ospeed != 0)
1574 dt->c_ospeed = tp->t_ospeed;
1577 if (cmd == TIOCSTOP) {
1580 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1584 } else if (cmd == TIOCSTART) {
1587 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1593 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1594 port->mustdrain = 1;
1596 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p);
1597 if (error != ENOIOCTL)
1600 error = ttioctl(tp, cmd, data, flag);
1601 disc_optim(tp, &tp->t_termios);
1602 port->mustdrain = 0;
1603 if (error != ENOIOCTL) {
1605 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1606 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);
1614 error = dgmdrain(port);
1625 /* now it sends 400 millisecond break because I don't know */
1626 /* how to send an infinite break */
1628 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1633 /* now it's empty */
1636 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1637 port->omodem |= DTR;
1640 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1642 if (!(bc->mstat & DTR))
1643 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1649 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1650 port->omodem &= ~DTR;
1653 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1655 if (bc->mstat & DTR) {
1656 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1663 if (*(int *)data & TIOCM_DTR)
1664 port->omodem |= DTR;
1666 port->omodem &= ~DTR;
1668 if (*(int *)data & TIOCM_RTS)
1669 port->omodem |= RTS;
1671 port->omodem &= ~RTS;
1675 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1680 if (*(int *)data & TIOCM_DTR)
1681 port->omodem |= DTR;
1683 if (*(int *)data & TIOCM_RTS)
1684 port->omodem |= RTS;
1688 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1693 if (*(int *)data & TIOCM_DTR)
1694 port->omodem &= ~DTR;
1696 if (*(int *)data & TIOCM_RTS)
1697 port->omodem &= ~RTS;
1701 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1707 port->imodem = bc->mstat;
1710 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1712 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1714 if (port->imodem & DTR) {
1715 DPRINT1(DB_MODEM, "DTR ");
1716 tiocm_xxx |= TIOCM_DTR;
1718 if (port->imodem & RTS) {
1719 DPRINT1(DB_MODEM, "RTS ");
1720 tiocm_xxx |= TIOCM_RTS;
1722 if (port->imodem & CTS) {
1723 DPRINT1(DB_MODEM, "CTS ");
1724 tiocm_xxx |= TIOCM_CTS;
1726 if (port->imodem & port->dcd) {
1727 DPRINT1(DB_MODEM, "DCD ");
1728 tiocm_xxx |= TIOCM_CD;
1730 if (port->imodem & port->dsr) {
1731 DPRINT1(DB_MODEM, "DSR ");
1732 tiocm_xxx |= TIOCM_DSR;
1734 if (port->imodem & RI) {
1735 DPRINT1(DB_MODEM, "RI ");
1736 tiocm_xxx |= TIOCM_RI;
1738 *(int *)data = tiocm_xxx;
1739 DPRINT1(DB_MODEM, "--\n");
1742 /* must be root since the wait applies to following logins */
1748 port->close_delay = *(int *)data * hz / 100;
1751 *(int *)data = port->close_delay * 100 / hz;
1754 port->do_timestamp = 1;
1755 *(struct timeval *)data = port->timestamp;
1757 case TIOCDCDTIMESTAMP:
1758 port->do_dcd_timestamp = 1;
1759 *(struct timeval *)data = port->dcd_timestamp;
1775 struct dgm_p *port = p;
1777 wakeup(&port->draining);
1780 /* wait for the output to drain */
1783 dgmdrain(struct dgm_p *port)
1785 volatile struct board_chan *bc = port->brdchan;
1786 struct dgm_softc *sc;
1789 BoardMemWinState ws = bmws_get();
1791 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1799 while (tail != head) {
1800 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1801 port->sc->unit, port->pnum, head, tail);
1805 timeout(wakeflush, port, hz);
1806 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1811 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1812 port->sc->unit, port->pnum, error);
1822 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1823 port->sc->unit, port->pnum, head, tail);
1828 /* wait for the output to drain */
1829 /* or simply clear the buffer it it's stopped */
1832 dgm_drain_or_flush(struct dgm_p *port)
1834 volatile struct board_chan *bc = port->brdchan;
1835 struct tty *tp = port->tty;
1836 struct dgm_softc *sc;
1841 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1849 while (tail != head /* && tail != lasttail */ ) {
1850 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1851 port->sc->unit, port->pnum, head, tail);
1853 /* if there is no carrier simply clean the buffer */
1854 if (!(tp->t_state & TS_CARR_ON)) {
1855 bc->tout = bc->tin = 0;
1863 timeout(wakeflush, port, hz);
1864 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1869 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1870 " error = %d\n", port->sc->unit, port->pnum, error);
1872 /* silently clean the buffer */
1874 bc->tout = bc->tin = 0;
1885 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1886 port->sc->unit, port->pnum, head, tail);
1890 dgmparam(struct tty *tp, struct termios *t)
1892 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1893 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1894 volatile struct board_chan *bc;
1895 struct dgm_softc *sc;
1903 BoardMemWinState ws = bmws_get();
1905 sc = devclass_get_softc(dgmdevclass, unit);
1906 port = &sc->ports[pnum];
1909 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);
1911 if (port->mustdrain) {
1912 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1916 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1918 if (t->c_ispeed == 0)
1919 t->c_ispeed = t->c_ospeed;
1921 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1922 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1929 if (cflag == 0) { /* hangup */
1930 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1934 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1935 mval= port->omodem & ~(DTR|RTS);
1937 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1939 if (cflag != port->fepcflag) {
1940 port->fepcflag = cflag;
1941 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1942 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1943 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1945 mval= port->omodem | (DTR|RTS);
1948 iflag = dgmflags(dgm_iflags, t->c_iflag);
1949 if (iflag != port->fepiflag) {
1950 port->fepiflag = iflag;
1951 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1952 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1955 bc->mint = port->dcd;
1957 hflow = dgmflags(dgm_flow, t->c_cflag);
1958 if (hflow != port->hflow) {
1959 port->hflow = hflow;
1960 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1961 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1964 if (port->omodem != mval) {
1965 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1966 unit, pnum, mval, port->omodem);
1967 port->omodem = mval;
1968 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1971 if (port->fepstartc != t->c_cc[VSTART] ||
1972 port->fepstopc != t->c_cc[VSTOP]) {
1973 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1974 port->fepstartc = t->c_cc[VSTART];
1975 port->fepstopc = t->c_cc[VSTOP];
1976 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1987 dgmstart(struct tty *tp)
1992 struct dgm_softc *sc;
1993 volatile struct board_chan *bc;
1999 BoardMemWinState ws = bmws_get();
2001 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2002 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2003 sc = devclass_get_softc(dgmdevclass, unit);
2004 port = &sc->ports[pnum];
2007 wmask = port->txbufsize - 1;
2011 while (tp->t_outq.c_cc != 0) {
2013 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2016 if (tp->t_outq.c_cc <= tp->t_lowat) {
2017 if (tp->t_state & TS_ASLEEP) {
2018 tp->t_state &= ~TS_ASLEEP;
2019 wakeup(TSA_OLOWAT(tp));
2021 /*selwakeup(&tp->t_wsel);*/
2027 head = bc->tin & wmask;
2029 do { tail = bc->tout; } while (tail != bc->tout);
2030 tail = bc->tout & wmask;
2032 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2034 #ifdef LEAVE_FREE_CHARS
2036 size = tail - head - LEAVE_FREE_CHARS;
2040 size = port->txbufsize - head;
2041 if (tail + port->txbufsize < head)
2047 size = tail - head - 1;
2049 size = port->txbufsize - head;
2060 tp->t_state |= TS_BUSY;
2065 towin(sc, port->txwin);
2067 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2069 if (head >= port->txbufsize)
2070 head -= port->txbufsize;
2075 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2076 unit, pnum, size, ocount);
2084 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2085 if (tp->t_state & TS_BUSY) {
2086 tp->t_state &= ~TS_BUSY;
2087 linesw[tp->t_line].l_start(tp);
2091 if (tp->t_state & TS_ASLEEP) {
2092 tp->t_state &= ~TS_ASLEEP;
2093 wakeup(TSA_OLOWAT(tp));
2095 tp->t_state& = ~TS_BUSY;
2100 dgmstop(struct tty *tp, int rw)
2105 struct dgm_softc *sc;
2106 volatile struct board_chan *bc;
2109 BoardMemWinState ws = bmws_get();
2111 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2112 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2114 sc = devclass_get_softc(dgmdevclass, unit);
2115 port = &sc->ports[pnum];
2118 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2124 /* clear output queue */
2125 bc->tout = bc->tin = 0;
2130 /* clear input queue */
2141 fepcmd(struct dgm_p *port,
2149 unsigned tail, head;
2152 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2153 mem = port->sc->vmem;
2155 if (!port->enabled) {
2156 printf("dgm%d: port%d: FEP command on disabled port\n",
2157 port->sc->unit, port->pnum);
2161 /* setwin(port->sc, 0); Require this to be set by caller */
2162 head = port->sc->mailbox->cin;
2164 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2165 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2166 port->sc->unit, port->pnum, head);
2170 mem[head + FEP_CSTART] = cmd;
2171 mem[head + FEP_CSTART + 1] = port->pnum;
2173 mem[head + FEP_CSTART + 2] = op1;
2174 mem[head + FEP_CSTART + 3] = op2;
2176 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2177 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2180 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2181 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2183 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2184 port->sc->mailbox->cin = head;
2188 while (count-- != 0) {
2189 head = port->sc->mailbox->cin;
2190 tail = port->sc->mailbox->cout;
2192 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2193 if (n <= ncmds * (sizeof(ushort)*4))
2196 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2200 disc_optim(struct tty *tp, struct termios *t)
2202 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2203 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2204 && (!(t->c_iflag & PARMRK)
2205 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2206 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2207 && linesw[tp->t_line].l_rint == ttyinput)
2208 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2210 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;