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.2 2003/06/17 04:28:23 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 proc *p)
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, TTOPRI|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,
1002 TTIPRI | PCATCH, "dgmi", 0);
1004 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1005 " error = %d\n", unit, pnum, error);
1011 if (tp->t_state & TS_XCLUDE && suser(p)) {
1017 * The device isn't open, so there are no conflicts.
1018 * Initialize it. Initialization is done twice in many
1019 * cases: to preempt sleeping callin opens if we are
1020 * callout, and to complete a callin open after DCD rises.
1022 tp->t_oproc = dgmstart;
1023 tp->t_param = dgmparam;
1024 tp->t_stop = dgmstop;
1026 tp->t_termios= (mynor & CALLOUT_MASK) ?
1032 port->imodem = bc->mstat;
1033 bc->rout = bc->rin; /* clear input queue */
1035 #ifdef PRINT_BUFSIZE
1036 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1037 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1044 error = dgmparam(tp, &tp->t_termios);
1048 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1053 /* handle fake DCD for callout devices */
1054 /* and initial DCD */
1056 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1057 linesw[tp->t_line].l_modem(tp, 1);
1061 * Wait for DCD if necessary.
1063 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1064 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1066 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "dgdcd", 0);
1069 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1070 " error = %d\n", unit, pnum, error);
1076 error = linesw[tp->t_line].l_open(dev, tp);
1077 disc_optim(tp, &tp->t_termios);
1078 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1081 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1082 port->active_out = 1;
1086 /* If any port is open (i.e. the open() call is completed for it)
1087 * the device is busy
1091 disc_optim(tp, &tp->t_termios);
1094 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1097 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1105 dgmclose(dev_t dev, int flag, int mode, struct proc *p)
1110 struct dgm_softc *sc;
1116 if (mynor & CONTROL_MASK)
1118 unit = MINOR_TO_UNIT(mynor);
1119 pnum = MINOR_TO_PORT(mynor);
1121 sc = devclass_get_softc(dgmdevclass, unit);
1122 tp = &sc->ttys[pnum];
1123 port = sc->ports + pnum;
1125 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1127 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1128 dgm_drain_or_flush(port);
1133 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1134 linesw[tp->t_line].l_close(tp, flag);
1135 disc_optim(tp, &tp->t_termios);
1137 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1139 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1142 wakeup(&port->closing);
1145 /* mark the card idle when all ports are closed */
1147 for (i = 0; i < sc->numports; i++)
1148 if (sc->ports[i].used)
1153 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1155 wakeup(TSA_CARR_ON(tp));
1156 wakeup(&port->active_out);
1157 port->active_out = 0;
1159 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1165 dgmhardclose(struct dgm_p *port)
1167 volatile struct board_chan *bc = port->brdchan;
1168 struct dgm_softc *sc;
1171 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1172 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1174 port->do_timestamp = 0;
1180 if (port->tty->t_cflag & HUPCL) {
1181 port->omodem &= ~(RTS|DTR);
1182 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1188 timeout(dgm_pause, &port->brdchan, hz/2);
1189 tsleep(&port->brdchan, TTIPRI | PCATCH, "dgclo", 0);
1193 dgm_pause(void *chan)
1195 wakeup((caddr_t)chan);
1199 dgmpoll(void *unit_c)
1201 int unit = (int)unit_c;
1204 struct dgm_softc *sc;
1207 int event, mstat, lstat;
1208 volatile struct board_chan *bc;
1215 int ibuf_full, obuf_full;
1216 BoardMemWinState ws = bmws_get();
1218 sc = devclass_get_softc(dgmdevclass, unit);
1219 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1220 callout_handle_init(&sc->toh);
1223 printf("dgm%d: polling of disabled board stopped\n", unit);
1229 head = sc->mailbox->ein;
1230 tail = sc->mailbox->eout;
1232 while (head != tail) {
1233 if (head >= FEP_IMAX - FEP_ISTART
1234 || tail >= FEP_IMAX - FEP_ISTART
1235 || (head|tail) & 03 ) {
1236 printf("dgm%d: event queue's head or tail is wrong!"
1237 " hd = %d, tl = %d\n", unit, head, tail);
1241 eventbuf = sc->vmem + tail + FEP_ISTART;
1243 event = eventbuf[1];
1244 mstat = eventbuf[2];
1245 lstat = eventbuf[3];
1247 port = &sc->ports[pnum];
1249 tp = &sc->ttys[pnum];
1251 if (pnum >= sc->numports || !port->enabled) {
1252 printf("dgm%d: port%d: got event on nonexisting port\n",
1254 } else if (port->used || port->wopeners > 0 ) {
1256 int wrapmask = port->rxbufsize - 1;
1258 if (!(event & ALL_IND))
1259 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1260 unit, pnum, event, mstat, lstat);
1262 if (event & DATA_IND) {
1263 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1266 rhead = bc->rin & wrapmask;
1267 rtail = bc->rout & wrapmask;
1269 if (!(tp->t_cflag & CREAD) || !port->used ) {
1275 printf("dgm%d: port%d: overrun\n", unit, pnum);
1279 if (!(tp->t_state & TS_ISOPEN))
1282 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1283 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1284 " p rx head = %d tail = %d\n", unit,
1285 pnum, rhead, rtail);
1288 size = rhead - rtail;
1290 size = port->rxbufsize - rtail;
1292 ptr = port->rxptr + rtail;
1295 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1296 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1297 DPRINT1(DB_RXDATA, "*");
1302 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1303 DPRINT1(DB_RXDATA, "!");
1304 towin(sc, port->rxwin);
1307 tp->t_rawcc += size;
1315 towin(sc, port->rxwin);
1318 (*linesw[tp->t_line].l_rint)(chr, tp);
1323 rtail= (rtail + size) & wrapmask;
1325 rhead = bc->rin & wrapmask;
1333 if (event & MODEMCHG_IND) {
1334 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1335 "MODEMCHG_IND\n", unit, pnum);
1336 port->imodem = mstat;
1337 if (mstat & port->dcd) {
1339 linesw[tp->t_line].l_modem(tp, 1);
1341 wakeup(TSA_CARR_ON(tp));
1344 linesw[tp->t_line].l_modem(tp, 0);
1346 if (port->draining) {
1348 wakeup(&port->draining);
1353 if (event & BREAK_IND) {
1354 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1355 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1356 " BREAK_IND\n", unit, pnum);
1358 linesw[tp->t_line].l_rint(TTY_BI, tp);
1363 /* Helg: with output flow control */
1365 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1366 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1367 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1369 if ((event & EMPTYTX_IND ) &&
1370 tp->t_outq.c_cc == 0 && port->draining) {
1372 wakeup(&port->draining);
1377 int wrapmask = port->txbufsize - 1;
1379 for (obuf_full = FALSE;
1380 tp->t_outq.c_cc != 0 && !obuf_full;
1383 /* add "last-minute" data to write buffer */
1384 if (!(tp->t_state & TS_BUSY)) {
1386 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1389 if (tp->t_outq.c_cc <= tp->t_lowat) {
1390 if (tp->t_state & TS_ASLEEP) {
1391 tp->t_state &= ~TS_ASLEEP;
1392 wakeup(TSA_OLOWAT(tp));
1394 /* selwakeup(&tp->t_wsel); */
1401 whead = bc->tin & wrapmask;
1402 wtail = bc->tout & wrapmask;
1405 size = wtail - whead - 1;
1407 size = port->txbufsize - whead;
1413 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1414 whead, wtail, size, obuf_full);
1422 towin(sc, port->txwin);
1424 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1429 bc->tin = whead & wrapmask;
1434 DPRINT1(DB_WR, " +BUSY\n");
1435 tp->t_state |= TS_BUSY;
1437 DPRINT1(DB_WR, " -BUSY\n");
1439 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1440 /* should clear TS_BUSY before ttwwakeup */
1441 if (tp->t_state & TS_BUSY) {
1442 tp->t_state &= ~TS_BUSY;
1443 linesw[tp->t_line].l_start(tp);
1447 if (tp->t_state & TS_ASLEEP) {
1448 tp->t_state &= ~TS_ASLEEP;
1449 wakeup(TSA_OLOWAT(tp));
1451 tp->t_state &= ~TS_BUSY;
1457 bc->idata = 1; /* require event on incoming data */
1461 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1464 bc->idata = bc->iempty = bc->ilow = 0;
1467 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1470 sc->mailbox->eout = tail;
1473 sc->toh = timeout(dgmpoll, unit_c, hz / POLLSPERSEC);
1475 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1479 dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1481 struct dgm_softc *sc;
1486 volatile struct board_chan *bc;
1491 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1493 struct termios term;
1496 BoardMemWinState ws = bmws_get();
1499 unit = MINOR_TO_UNIT(mynor);
1500 pnum = MINOR_TO_PORT(mynor);
1502 sc = devclass_get_softc(dgmdevclass, unit);
1503 port = &sc->ports[pnum];
1504 tp = &sc->ttys[pnum];
1507 if (mynor & CONTROL_MASK) {
1510 switch (mynor & CONTROL_MASK) {
1511 case CONTROL_INIT_STATE:
1512 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1514 case CONTROL_LOCK_STATE:
1515 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1518 return (ENODEV); /* /dev/nodev */
1525 *ct = *(struct termios *)data;
1528 *(struct termios *)data = *ct;
1531 *(int *)data = TTYDISC;
1534 bzero(data, sizeof(struct winsize));
1541 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1542 term = tp->t_termios;
1543 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1544 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);
1547 error = ttsetcompat(tp, &cmd, data, &term);
1551 data = (caddr_t)&term;
1554 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1556 struct termios *dt = (struct termios *)data;
1557 struct termios *lt = mynor & CALLOUT_MASK
1558 ? &port->lt_out : &port->lt_in;
1560 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);
1561 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1562 | (dt->c_iflag & ~lt->c_iflag);
1563 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1564 | (dt->c_oflag & ~lt->c_oflag);
1565 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1566 | (dt->c_cflag & ~lt->c_cflag);
1567 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1568 | (dt->c_lflag & ~lt->c_lflag);
1569 for (cc = 0; cc < NCCS; ++cc)
1570 if (lt->c_cc[cc] != 0)
1571 dt->c_cc[cc] = tp->t_cc[cc];
1572 if (lt->c_ispeed != 0)
1573 dt->c_ispeed = tp->t_ispeed;
1574 if (lt->c_ospeed != 0)
1575 dt->c_ospeed = tp->t_ospeed;
1578 if (cmd == TIOCSTOP) {
1581 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1585 } else if (cmd == TIOCSTART) {
1588 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1594 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1595 port->mustdrain = 1;
1597 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p);
1598 if (error != ENOIOCTL)
1601 error = ttioctl(tp, cmd, data, flag);
1602 disc_optim(tp, &tp->t_termios);
1603 port->mustdrain = 0;
1604 if (error != ENOIOCTL) {
1606 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1607 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);
1615 error = dgmdrain(port);
1626 /* now it sends 400 millisecond break because I don't know */
1627 /* how to send an infinite break */
1629 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1634 /* now it's empty */
1637 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1638 port->omodem |= DTR;
1641 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1643 if (!(bc->mstat & DTR))
1644 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1650 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1651 port->omodem &= ~DTR;
1654 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1656 if (bc->mstat & DTR) {
1657 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1664 if (*(int *)data & TIOCM_DTR)
1665 port->omodem |= DTR;
1667 port->omodem &= ~DTR;
1669 if (*(int *)data & TIOCM_RTS)
1670 port->omodem |= RTS;
1672 port->omodem &= ~RTS;
1676 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1681 if (*(int *)data & TIOCM_DTR)
1682 port->omodem |= DTR;
1684 if (*(int *)data & TIOCM_RTS)
1685 port->omodem |= RTS;
1689 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1694 if (*(int *)data & TIOCM_DTR)
1695 port->omodem &= ~DTR;
1697 if (*(int *)data & TIOCM_RTS)
1698 port->omodem &= ~RTS;
1702 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1708 port->imodem = bc->mstat;
1711 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1713 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1715 if (port->imodem & DTR) {
1716 DPRINT1(DB_MODEM, "DTR ");
1717 tiocm_xxx |= TIOCM_DTR;
1719 if (port->imodem & RTS) {
1720 DPRINT1(DB_MODEM, "RTS ");
1721 tiocm_xxx |= TIOCM_RTS;
1723 if (port->imodem & CTS) {
1724 DPRINT1(DB_MODEM, "CTS ");
1725 tiocm_xxx |= TIOCM_CTS;
1727 if (port->imodem & port->dcd) {
1728 DPRINT1(DB_MODEM, "DCD ");
1729 tiocm_xxx |= TIOCM_CD;
1731 if (port->imodem & port->dsr) {
1732 DPRINT1(DB_MODEM, "DSR ");
1733 tiocm_xxx |= TIOCM_DSR;
1735 if (port->imodem & RI) {
1736 DPRINT1(DB_MODEM, "RI ");
1737 tiocm_xxx |= TIOCM_RI;
1739 *(int *)data = tiocm_xxx;
1740 DPRINT1(DB_MODEM, "--\n");
1743 /* must be root since the wait applies to following logins */
1749 port->close_delay = *(int *)data * hz / 100;
1752 *(int *)data = port->close_delay * 100 / hz;
1755 port->do_timestamp = 1;
1756 *(struct timeval *)data = port->timestamp;
1758 case TIOCDCDTIMESTAMP:
1759 port->do_dcd_timestamp = 1;
1760 *(struct timeval *)data = port->dcd_timestamp;
1776 struct dgm_p *port = p;
1778 wakeup(&port->draining);
1781 /* wait for the output to drain */
1784 dgmdrain(struct dgm_p *port)
1786 volatile struct board_chan *bc = port->brdchan;
1787 struct dgm_softc *sc;
1790 BoardMemWinState ws = bmws_get();
1792 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1800 while (tail != head) {
1801 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1802 port->sc->unit, port->pnum, head, tail);
1806 timeout(wakeflush, port, hz);
1807 error = tsleep(&port->draining, TTIPRI | PCATCH, "dgdrn", 0);
1812 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1813 port->sc->unit, port->pnum, error);
1823 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1824 port->sc->unit, port->pnum, head, tail);
1829 /* wait for the output to drain */
1830 /* or simply clear the buffer it it's stopped */
1833 dgm_drain_or_flush(struct dgm_p *port)
1835 volatile struct board_chan *bc = port->brdchan;
1836 struct tty *tp = port->tty;
1837 struct dgm_softc *sc;
1842 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1850 while (tail != head /* && tail != lasttail */ ) {
1851 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1852 port->sc->unit, port->pnum, head, tail);
1854 /* if there is no carrier simply clean the buffer */
1855 if (!(tp->t_state & TS_CARR_ON)) {
1856 bc->tout = bc->tin = 0;
1864 timeout(wakeflush, port, hz);
1865 error = tsleep(&port->draining, TTIPRI | PCATCH, "dgfls", 0);
1870 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1871 " error = %d\n", port->sc->unit, port->pnum, error);
1873 /* silently clean the buffer */
1875 bc->tout = bc->tin = 0;
1886 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1887 port->sc->unit, port->pnum, head, tail);
1891 dgmparam(struct tty *tp, struct termios *t)
1893 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1894 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1895 volatile struct board_chan *bc;
1896 struct dgm_softc *sc;
1904 BoardMemWinState ws = bmws_get();
1906 sc = devclass_get_softc(dgmdevclass, unit);
1907 port = &sc->ports[pnum];
1910 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);
1912 if (port->mustdrain) {
1913 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1917 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1919 if (t->c_ispeed == 0)
1920 t->c_ispeed = t->c_ospeed;
1922 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1923 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1930 if (cflag == 0) { /* hangup */
1931 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1935 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1936 mval= port->omodem & ~(DTR|RTS);
1938 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1940 if (cflag != port->fepcflag) {
1941 port->fepcflag = cflag;
1942 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1943 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1944 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1946 mval= port->omodem | (DTR|RTS);
1949 iflag = dgmflags(dgm_iflags, t->c_iflag);
1950 if (iflag != port->fepiflag) {
1951 port->fepiflag = iflag;
1952 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1953 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1956 bc->mint = port->dcd;
1958 hflow = dgmflags(dgm_flow, t->c_cflag);
1959 if (hflow != port->hflow) {
1960 port->hflow = hflow;
1961 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1962 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1965 if (port->omodem != mval) {
1966 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1967 unit, pnum, mval, port->omodem);
1968 port->omodem = mval;
1969 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1972 if (port->fepstartc != t->c_cc[VSTART] ||
1973 port->fepstopc != t->c_cc[VSTOP]) {
1974 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1975 port->fepstartc = t->c_cc[VSTART];
1976 port->fepstopc = t->c_cc[VSTOP];
1977 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1988 dgmstart(struct tty *tp)
1993 struct dgm_softc *sc;
1994 volatile struct board_chan *bc;
2000 BoardMemWinState ws = bmws_get();
2002 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2003 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2004 sc = devclass_get_softc(dgmdevclass, unit);
2005 port = &sc->ports[pnum];
2008 wmask = port->txbufsize - 1;
2012 while (tp->t_outq.c_cc != 0) {
2014 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2017 if (tp->t_outq.c_cc <= tp->t_lowat) {
2018 if (tp->t_state & TS_ASLEEP) {
2019 tp->t_state &= ~TS_ASLEEP;
2020 wakeup(TSA_OLOWAT(tp));
2022 /*selwakeup(&tp->t_wsel);*/
2028 head = bc->tin & wmask;
2030 do { tail = bc->tout; } while (tail != bc->tout);
2031 tail = bc->tout & wmask;
2033 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2035 #ifdef LEAVE_FREE_CHARS
2037 size = tail - head - LEAVE_FREE_CHARS;
2041 size = port->txbufsize - head;
2042 if (tail + port->txbufsize < head)
2048 size = tail - head - 1;
2050 size = port->txbufsize - head;
2061 tp->t_state |= TS_BUSY;
2066 towin(sc, port->txwin);
2068 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2070 if (head >= port->txbufsize)
2071 head -= port->txbufsize;
2076 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2077 unit, pnum, size, ocount);
2085 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2086 if (tp->t_state & TS_BUSY) {
2087 tp->t_state &= ~TS_BUSY;
2088 linesw[tp->t_line].l_start(tp);
2092 if (tp->t_state & TS_ASLEEP) {
2093 tp->t_state &= ~TS_ASLEEP;
2094 wakeup(TSA_OLOWAT(tp));
2096 tp->t_state& = ~TS_BUSY;
2101 dgmstop(struct tty *tp, int rw)
2106 struct dgm_softc *sc;
2107 volatile struct board_chan *bc;
2110 BoardMemWinState ws = bmws_get();
2112 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2113 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2115 sc = devclass_get_softc(dgmdevclass, unit);
2116 port = &sc->ports[pnum];
2119 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2125 /* clear output queue */
2126 bc->tout = bc->tin = 0;
2131 /* clear input queue */
2142 fepcmd(struct dgm_p *port,
2150 unsigned tail, head;
2153 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2154 mem = port->sc->vmem;
2156 if (!port->enabled) {
2157 printf("dgm%d: port%d: FEP command on disabled port\n",
2158 port->sc->unit, port->pnum);
2162 /* setwin(port->sc, 0); Require this to be set by caller */
2163 head = port->sc->mailbox->cin;
2165 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2166 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2167 port->sc->unit, port->pnum, head);
2171 mem[head + FEP_CSTART] = cmd;
2172 mem[head + FEP_CSTART + 1] = port->pnum;
2174 mem[head + FEP_CSTART + 2] = op1;
2175 mem[head + FEP_CSTART + 3] = op2;
2177 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2178 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2181 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2182 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2184 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2185 port->sc->mailbox->cin = head;
2189 while (count-- != 0) {
2190 head = port->sc->mailbox->cin;
2191 tail = port->sc->mailbox->cout;
2193 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2194 if (n <= ncmds * (sizeof(ushort)*4))
2197 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2201 disc_optim(struct tty *tp, struct termios *t)
2203 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2204 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2205 && (!(t->c_iflag & PARMRK)
2206 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2207 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2208 && linesw[tp->t_line].l_rint == ttyinput)
2209 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2211 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;