Rename printf -> kprintf in sys/ and add some defines where necessary
[dragonfly/vkernel-mp.git] / sys / dev / serial / dgb / dgm.c
blob23f35e57344cfcebcf4a0925b8b1cb96bffb1d1a
1 /*-
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.16 2006/12/23 00:26:24 swildner 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>
9 * Digiboard driver.
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
16 * are met:
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
36 * SUCH DAMAGE.
38 * Written by Sergey Babkin,
39 * Joint Stock Commercial Bank "Chelindbank"
40 * (Chelyabinsk, Russia)
41 * babkin@freebsd.org
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 &
49 * TIOCDCDTIMESTAMP.
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.
63 * -SB
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>
77 #include <sys/proc.h>
78 #include <sys/conf.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>
85 #include <sys/tty.h>
86 #include <sys/bus.h>
87 #include <sys/kobj.h>
88 #include <sys/bus.h>
89 #include <sys/rman.h>
90 #include <sys/thread2.h>
92 #include <machine/clock.h>
94 #include <vm/vm.h>
95 #include <vm/pmap.h>
97 #include "dgmfep.h"
98 #include "dgmbios.h"
99 #include "dgmreg.h"
101 #define CALLOUT_MASK 0x40000
102 #define CONTROL_MASK 0xC0
103 #define CONTROL_INIT_STATE 0x40
104 #define CONTROL_LOCK_STATE 0x80
105 #define UNIT_MASK 0x30000
106 #define PORT_MASK 0x3F
107 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
108 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
109 #define MINOR_TO_UNIT(mynor) (((mynor) & UNIT_MASK) >> 16)
110 #define MINOR_TO_PORT(mynor) ((mynor) & PORT_MASK)
111 #define IO_SIZE 0x04
112 #define MEM_SIZE 0x8000
114 #define DGM_UNITMASK 0x30000
115 #define DGM_UNIT(unit) ((unit) << 16)
117 struct dgm_softc;
119 /* digiboard port structure */
120 struct dgm_p {
121 unsigned enabled : 1;
123 struct dgm_softc *sc; /* parent softc */
124 u_char pnum; /* port number */
125 u_char omodem; /* FEP output modem status */
126 u_char imodem; /* FEP input modem status */
127 u_char modemfake; /* Modem values to be forced */
128 u_char modem; /* Force values */
129 u_char hflow;
130 u_char dsr;
131 u_char dcd;
132 u_char stopc;
133 u_char startc;
134 u_char stopca;
135 u_char startca;
136 u_char fepstopc;
137 u_char fepstartc;
138 u_char fepstopca;
139 u_char fepstartca;
140 u_char txwin;
141 u_char rxwin;
142 ushort fepiflag;
143 ushort fepcflag;
144 ushort fepoflag;
145 ushort txbufhead;
146 ushort txbufsize;
147 ushort rxbufhead;
148 ushort rxbufsize;
149 int close_delay;
150 u_char *txptr;
151 u_char *rxptr;
152 volatile struct board_chan *brdchan;
153 struct tty *tty;
155 u_char active_out; /* nonzero if the callout device is open */
156 u_int wopeners; /* # processes waiting for DCD in open() */
158 /* Initial state. */
159 struct termios it_in; /* should be in struct tty */
160 struct termios it_out;
162 /* Lock state. */
163 struct termios lt_in; /* should be in struct tty */
164 struct termios lt_out;
166 unsigned do_timestamp : 1;
167 unsigned do_dcd_timestamp : 1;
168 struct timeval timestamp;
169 struct timeval dcd_timestamp;
171 /* flags of state, are used in sleep() too */
172 u_char closing; /* port is being closed now */
173 u_char draining; /* port is being drained now */
174 u_char used; /* port is being used now */
175 u_char mustdrain; /* data must be waited to drain in dgmparam() */
177 struct callout hc_timeout;
178 struct callout wf_timeout;
181 /* Digiboard per-board structure */
182 struct dgm_softc {
183 /* struct board_info */
184 unsigned enabled : 1;
185 u_char unit; /* unit number */
186 u_char type; /* type of card: PCXE, PCXI, PCXEVE */
187 u_char altpin; /* do we need alternate pin setting ? */
188 int numports; /* number of ports on card */
189 u_long port; /* I/O port */
190 u_char *vmem; /* virtual memory address */
191 u_long pmem; /* physical memory address */
192 int mem_seg; /* internal memory segment */
193 struct dgm_p *ports; /* ptr to array of port descriptors */
194 struct tty *ttys; /* ptr to array of TTY structures */
195 volatile struct global_data *mailbox;
196 struct resource *io_res;
197 struct resource *mem_res;
198 int iorid;
199 int mrid;
200 struct callout toh; /* poll timeout handle */
203 static void dgmpoll(void *);
204 static int dgmprobe(device_t);
205 static int dgmattach(device_t);
206 static int dgmdetach(device_t);
207 static int dgmshutdown(device_t);
208 static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
209 unsigned);
210 static void dgmstart(struct tty *);
211 static void dgmstop(struct tty *, int);
212 static int dgmparam(struct tty *, struct termios *);
213 static void dgmhardclose(struct dgm_p *);
214 static void dgm_drain_or_flush(struct dgm_p *);
215 static int dgmdrain(struct dgm_p *);
216 static void dgm_pause(void *);
217 static void wakeflush(void *);
218 static void disc_optim(struct tty *, struct termios *);
220 static d_open_t dgmopen;
221 static d_close_t dgmclose;
222 static d_ioctl_t dgmioctl;
224 static device_method_t dgmmethods[] = {
225 /* Device interface */
226 DEVMETHOD(device_probe, dgmprobe),
227 DEVMETHOD(device_attach, dgmattach),
228 DEVMETHOD(device_detach, dgmdetach),
229 DEVMETHOD(device_shutdown, dgmshutdown),
230 { 0, 0 }
233 static driver_t dgmdriver = {
234 "dgm",
235 dgmmethods,
236 sizeof (struct dgm_softc),
239 static devclass_t dgmdevclass;
241 #define CDEV_MAJOR 101
242 static struct dev_ops dgm_ops = {
243 { "dgm", CDEV_MAJOR, D_TTY | D_KQFILTER },
244 .d_open = dgmopen,
245 .d_close = dgmclose,
246 .d_read = ttyread,
247 .d_write = ttywrite,
248 .d_ioctl = dgmioctl,
249 .d_poll = ttypoll,
250 .d_kqfilter = ttykqfilter
253 static int
254 dgmmodhandler(module_t mod, int event, void *arg)
256 int res = 0;
258 switch (event) {
259 case MOD_LOAD:
260 break;
261 case MOD_UNLOAD:
262 break;
265 return res;
268 DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
270 static speed_t dgmdefaultrate = TTYDEF_SPEED;
272 static struct speedtab dgmspeedtab[] = {
273 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
274 { 50, FEP_B50 },
275 { 75, FEP_B75 },
276 { 110, FEP_B110 },
277 { 134, FEP_B134 },
278 { 150, FEP_B150 },
279 { 200, FEP_B200 },
280 { 300, FEP_B300 },
281 { 600, FEP_B600 },
282 { 1200, FEP_B1200 },
283 { 1800, FEP_B1800 },
284 { 2400, FEP_B2400 },
285 { 4800, FEP_B4800 },
286 { 9600, FEP_B9600 },
287 { 19200, FEP_B19200 },
288 { 38400, FEP_B38400 },
289 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
290 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
291 { -1, -1 }
294 static struct dbgflagtbl {
295 tcflag_t in_mask;
296 tcflag_t in_val;
297 tcflag_t out_val;
298 } dgm_cflags[] = {
299 { PARODD, PARODD, FEP_PARODD },
300 { PARENB, PARENB, FEP_PARENB },
301 { CSTOPB, CSTOPB, FEP_CSTOPB },
302 { CSIZE, CS5, FEP_CS6 },
303 { CSIZE, CS6, FEP_CS6 },
304 { CSIZE, CS7, FEP_CS7 },
305 { CSIZE, CS8, FEP_CS8 },
306 { CLOCAL, CLOCAL, FEP_CLOCAL },
307 { (tcflag_t)-1 }
308 }, dgm_iflags[] = {
309 { IGNBRK, IGNBRK, FEP_IGNBRK },
310 { BRKINT, BRKINT, FEP_BRKINT },
311 { IGNPAR, IGNPAR, FEP_IGNPAR },
312 { PARMRK, PARMRK, FEP_PARMRK },
313 { INPCK, INPCK, FEP_INPCK },
314 { ISTRIP, ISTRIP, FEP_ISTRIP },
315 { IXON, IXON, FEP_IXON },
316 { IXOFF, IXOFF, FEP_IXOFF },
317 { IXANY, IXANY, FEP_IXANY },
318 { (tcflag_t)-1 }
319 }, dgm_flow[] = {
320 { CRTSCTS, CRTSCTS, CTS|RTS },
321 { CRTSCTS, CCTS_OFLOW, CTS },
322 { CRTSCTS, CRTS_IFLOW, RTS },
323 { (tcflag_t)-1 }
326 /* xlat bsd termios flags to dgm sys-v style */
327 static tcflag_t
328 dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
330 tcflag_t output = 0;
331 int i;
333 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
334 if ((input & tbl[i].in_mask) == tbl[i].in_val)
335 output |= tbl[i].out_val;
337 return output;
340 static int dgmdebug = 0;
341 SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
343 static __inline int setwin(struct dgm_softc *, unsigned);
344 static __inline void hidewin(struct dgm_softc *);
345 static __inline void towin(struct dgm_softc *, int);
347 /*Helg: to allow recursive dgm...() calls */
348 typedef struct {
349 /* If we were called and don't want to disturb we need: */
350 int port; /* write to this port */
351 u_char data; /* this data on exit */
352 /* or DATA_WINOFF to close memory window on entry */
353 } BoardMemWinState; /* so several channels and even boards can coexist */
355 #define DATA_WINOFF 0
356 static BoardMemWinState bmws;
358 static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
359 static u_long validmem[] = {
360 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
361 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
362 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
363 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
364 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
367 /* return current memory window state and close window */
368 static BoardMemWinState
369 bmws_get(void)
371 BoardMemWinState bmwsRet = bmws;
373 if (bmws.data != DATA_WINOFF)
374 outb(bmws.port, bmws.data = DATA_WINOFF);
375 return bmwsRet;
378 /* restore memory window state */
379 static void
380 bmws_set(BoardMemWinState ws)
382 if (ws.data != bmws.data || ws.port != bmws.port) {
383 if (bmws.data != DATA_WINOFF)
384 outb(bmws.port, DATA_WINOFF);
385 if (ws.data != DATA_WINOFF)
386 outb(ws.port, ws.data);
387 bmws = ws;
391 static __inline int
392 setwin(struct dgm_softc *sc, unsigned int addr)
394 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
395 return (addr & 0x7FFF);
398 static __inline void
399 hidewin(struct dgm_softc *sc)
401 bmws.data = 0;
402 outb(bmws.port = sc->port + 1, bmws.data);
405 static __inline void
406 towin(struct dgm_softc *sc, int win)
408 outb(bmws.port = sc->port + 1, bmws.data = win);
411 static int
412 dgmprobe(device_t dev)
414 struct dgm_softc *sc = device_get_softc(dev);
415 int i, v;
418 * Assign unit number. Due to bits we use in the minor number for
419 * the various tty types, only 4 units are supported.
421 sc->unit = device_get_unit(dev);
422 if (sc->unit > 3) {
423 device_printf(dev, "Too many units, only 4 supported\n");
424 return(ENXIO);
427 /* Check that we've got a valid i/o address */
428 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
429 return (ENXIO);
430 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
431 if (sc->port == validio[i])
432 break;
433 if (i == -1) {
434 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
435 return (ENXIO);
438 /* Ditto for our memory address */
439 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
440 return (ENXIO);
441 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
442 if (sc->pmem == validmem[i])
443 break;
444 if (i == -1) {
445 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
446 return (ENXIO);
448 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
449 device_printf(dev, "0x%lx: Memory address not supported\n",
450 sc->pmem);
451 return (ENXIO);
453 sc->vmem = (u_char *)sc->pmem;
455 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
456 sc->port, sc->pmem);
458 /* Temporarily map our io ports */
459 sc->iorid = 0;
460 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
461 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
462 if (sc->io_res == NULL)
463 return (ENXIO);
465 outb(sc->port, FEPRST);
466 sc->enabled = 0;
468 for (i = 0; i < 1000; i++) {
469 DELAY(1);
470 if ((inb(sc->port) & FEPMASK) == FEPRST) {
471 sc->enabled = 1;
472 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
473 sc->unit, i);
474 break;
478 if (!sc->enabled) {
479 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
480 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
481 return (ENXIO);
484 /* check type of card and get internal memory characteristics */
486 v = inb(sc->port);
488 if (!(v & 0x1)) {
489 int second;
491 outb(sc->port, 1);
492 second = inb(sc->port);
493 kprintf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
494 } else
495 kprintf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
497 sc->type = PCXEM;
498 sc->mem_seg = 0x8000;
500 /* Temporarily map our memory too */
501 sc->mrid = 0;
502 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
503 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
504 if (sc->mem_res == NULL) {
505 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
506 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
507 return (ENXIO);
510 outb(sc->port, FEPCLR); /* drop RESET */
511 hidewin(sc); /* Helg: to set initial bmws state */
513 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
514 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
516 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
517 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
519 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
521 return (0);
524 static int
525 dgmattach(device_t dev)
527 struct dgm_softc *sc = device_get_softc(dev);
528 int i, t;
529 u_char *mem;
530 u_char *ptr;
531 int addr;
532 struct dgm_p *port;
533 volatile struct board_chan *bc;
534 int shrinkmem;
535 int lowwater;
536 u_long msize, iosize;
538 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
540 callout_init(&sc->toh);
541 sc->unit = device_get_unit(dev);
542 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
543 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
544 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
545 sc->type = PCXEM;
546 sc->mem_seg = 0x8000;
547 sc->enabled = 1;
548 sc->type = PCXEM;
549 sc->mem_seg = 0x8000;
551 /* Allocate resources (should have been verified in dgmprobe()) */
552 sc->iorid = 0;
553 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
554 0ul, ~0ul, iosize, RF_ACTIVE);
555 if (sc->io_res == NULL)
556 return (ENXIO);
557 sc->mrid = 0;
558 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
559 0ul, ~0ul, msize, RF_ACTIVE);
560 if (sc->mem_res == NULL) {
561 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
562 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
563 return (ENXIO);
566 /* map memory */
567 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
569 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
570 sc->mem_seg);
572 outb(sc->port, FEPRST);
573 DELAY(1);
575 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
576 if (i > 10000) {
577 device_printf(dev, "1st reset failed\n");
578 sc->enabled = 0;
579 hidewin(sc);
580 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
581 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
582 return (ENXIO);
584 DELAY(1);
587 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
589 t = sc->pmem >> 8; /* disable windowing */
590 outb(sc->port + 2, t & 0xFF);
591 outb(sc->port + 3, t >> 8);
593 mem = sc->vmem;
595 /* very short memory test */
596 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
598 addr = setwin(sc, BOTWIN);
599 *(u_long *)(mem + addr) = 0xA55A3CC3;
600 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
601 device_printf(dev, "1st memory test failed\n");
602 sc->enabled = 0;
603 hidewin(sc);
604 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
605 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
606 return (ENXIO);
609 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
611 addr = setwin(sc, TOPWIN);
612 *(u_long *)(mem + addr) = 0x5AA5C33C;
613 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
614 device_printf(dev, "2nd memory test failed\n");
615 sc->enabled = 0;
616 hidewin(sc);
617 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
618 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
619 return (ENXIO);
622 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
624 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
625 *(u_long *)(mem + addr) = 0x5AA5C33C;
626 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
627 device_printf(dev, "3rd (BIOS) memory test failed\n");
629 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
631 addr = setwin(sc, MISCGLOBAL);
632 for (i = 0; i < 16; i++)
633 mem[addr + i] = 0;
635 addr = setwin(sc, BIOSOFFSET);
636 ptr = mem + addr;
637 for (i = 0; ptr < mem + msize; i++)
638 *ptr++ = pcem_bios[i];
640 ptr = mem + BIOSOFFSET;
641 for (i = 0; ptr < mem + msize; i++) {
642 if (*ptr++ != pcem_bios[i]) {
643 kprintf("Low BIOS load failed\n");
644 sc->enabled = 0;
645 hidewin(sc);
646 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
647 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
648 return (ENXIO);
651 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
653 addr = setwin(sc, msize);
654 ptr = mem + addr;
655 for (;i < pcem_nbios; i++)
656 *ptr++ = pcem_bios[i];
658 ptr = mem;
659 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
660 if (*ptr++ != pcem_bios[i]) {
661 kprintf("High BIOS load failed\n");
662 sc->enabled = 0;
663 hidewin(sc);
664 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
665 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
666 return (ENXIO);
669 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
670 device_printf(dev, "DigiBIOS loaded, initializing");
672 addr = setwin(sc, 0);
674 *(u_int *)(mem + addr) = 0x0bf00401;
675 *(u_int *)(mem + addr + 4) = 0;
676 *(ushort *)(mem + addr + 0xc00) = 0;
677 outb(sc->port, 0);
679 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
680 DELAY(10000);
681 if (i > 3000) {
682 kprintf("\nBIOS initialize failed(1)\n");
683 sc->enabled = 0;
684 hidewin(sc);
685 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
686 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
687 return (ENXIO);
691 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
692 kprintf("\nBIOS initialize failed(2)\n");
693 sc->enabled = 0;
694 hidewin(sc);
695 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
696 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
697 return (ENXIO);
699 kprintf(", DigiBIOS running\n");
701 DELAY(10000);
703 addr = setwin(sc, BIOSOFFSET);
704 ptr = mem + addr;
705 for (i = 0; i < pcem_ncook; i++)
706 *ptr++ = pcem_cook[i];
708 ptr = mem + BIOSOFFSET;
709 for (i = 0; i < pcem_ncook; i++) {
710 if (*ptr++ != pcem_cook[i]) {
711 kprintf("FEP/OS load failed\n");
712 sc->enabled = 0;
713 hidewin(sc);
714 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
715 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
716 return (ENXIO);
719 device_printf(dev, "FEP/OS loaded, initializing");
721 addr = setwin(sc, 0);
722 *(ushort *)(mem + addr + 0xd20) = 0;
723 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
724 *(u_int *)(mem + addr + 0xc30) = 0x3L;
725 outb(sc->port, 0);
727 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
728 DELAY(10000);
729 if (i > 3000) {
730 kprintf("\nFEP/OS initialize failed(1)\n");
731 sc->enabled = 0;
732 hidewin(sc);
733 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
734 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
735 return (ENXIO);
739 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
740 kprintf("\nFEP/OS initialize failed(2)\n");
741 sc->enabled = 0;
742 hidewin(sc);
743 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
744 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
745 return (ENXIO);
747 kprintf(", FEP/OS running\n");
749 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
750 device_printf(dev, "%d ports attached\n", sc->numports);
752 if (sc->numports > MAX_DGM_PORTS) {
753 kprintf("dgm%d: too many ports\n", sc->unit);
754 sc->enabled = 0;
755 hidewin(sc);
756 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
757 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
758 return (ENXIO);
761 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
762 M_TTYS, M_WAITOK|M_ZERO);
763 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
764 M_TTYS, M_WAITOK|M_ZERO);
766 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
767 for (i = 0; i < sc->numports; i++) {
768 sc->ports[i].enabled = 1;
769 callout_init(&sc->ports[i].hc_timeout);
770 callout_init(&sc->ports[i].wf_timeout);
773 /* We should now init per-port structures */
774 setwin(sc, 0);
775 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
776 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
778 if (sc->numports < 3)
779 shrinkmem = 1;
780 else
781 shrinkmem = 0;
783 dev_ops_add(&dgm_ops, DGM_UNITMASK, DGM_UNIT(sc->unit));
784 for (i = 0; i < sc->numports; i++, bc++) {
785 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
786 port = &sc->ports[i];
787 port->sc = sc;
789 port->tty = &sc->ttys[i];
791 port->brdchan = bc;
793 port->dcd = CD;
794 port->dsr = DSR;
795 port->pnum = i;
797 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
798 if (shrinkmem) {
799 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
800 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
801 shrinkmem = 0;
804 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
805 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
806 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
807 port->txwin = FEPWIN | (bc->tseg >> 11);
808 port->rxwin = FEPWIN | (bc->rseg >> 11);
810 port->txbufhead = 0;
811 port->rxbufhead = 0;
812 port->txbufsize = bc->tmax + 1;
813 port->rxbufsize = bc->rmax + 1;
815 lowwater = (port->txbufsize >= 2000) ?
816 1024 : (port->txbufsize / 2);
818 setwin(sc, 0);
819 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
820 sc->unit, i, lowwater);
821 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
822 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
823 sc->unit, i, port->rxbufsize / 4);
824 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
825 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
826 sc->unit, i, 3 * port->rxbufsize / 4);
827 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
829 bc->edelay = 100;
830 bc->idata = 1;
832 port->startc = bc->startc;
833 port->startca = bc->startca;
834 port->stopc = bc->stopc;
835 port->stopca = bc->stopca;
837 /* port->close_delay = 50; */
838 port->close_delay = 3 * hz;
839 port->do_timestamp = 0;
840 port->do_dcd_timestamp = 0;
842 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
844 * We don't use all the flags from <sys/ttydefaults.h> since
845 * they are only relevant for logins. It's important to have
846 * echo off initially so that the line doesn't start
847 * blathering before the echo flag can be turned off.
849 port->it_in.c_iflag = TTYDEF_IFLAG;
850 port->it_in.c_oflag = TTYDEF_OFLAG;
851 port->it_in.c_cflag = TTYDEF_CFLAG;
852 port->it_in.c_lflag = TTYDEF_LFLAG;
853 termioschars(&port->it_in);
854 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
855 port->it_out = port->it_in;
857 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
858 make_dev(&dgm_ops, (sc->unit*65536) + i, UID_ROOT,
859 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
860 make_dev(&dgm_ops, sc->unit * 65536 + i + 64, UID_ROOT,
861 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
862 make_dev(&dgm_ops, sc->unit * 65536 + i + 128, UID_ROOT,
863 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
864 make_dev(&dgm_ops, sc->unit * 65536 + i + 262144, UID_UUCP,
865 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
866 make_dev(&dgm_ops, sc->unit * 65536 + i + 262208, UID_UUCP,
867 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
868 make_dev(&dgm_ops, sc->unit * 65536 + i + 262272, UID_UUCP,
869 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
872 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
874 hidewin(sc);
876 /* start the polling function */
877 callout_reset(&sc->toh, hz / POLLSPERSEC,
878 dgmpoll, (void *)(int)sc->unit);
880 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
882 return (0);
885 static int
886 dgmdetach(device_t dev)
888 struct dgm_softc *sc = device_get_softc(dev);
889 int i;
891 for (i = 0; i < sc->numports; i++)
892 if (sc->ttys[i].t_state & TS_ISOPEN)
893 return (EBUSY);
895 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
898 * The dev_ops_remove() call will destroy all associated devices
899 * and dereference any ad-hoc-created devices, but does not
900 * dereference devices created via make_dev().
902 dev_ops_remove(&dgm_ops, DGM_UNITMASK, DGM_UNIT(sc->unit));
904 callout_stop(&sc->toh);
906 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
907 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
909 FREE(sc->ports, M_TTYS);
910 FREE(sc->ttys, M_TTYS);
912 return (0);
916 dgmshutdown(device_t dev)
918 #ifdef DEBUG
919 struct dgm_softc *sc = device_get_softc(dev);
921 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
922 #endif
924 return 0;
927 /* ARGSUSED */
928 static int
929 dgmopen(struct dev_open_args *ap)
931 cdev_t dev = ap->a_head.a_dev;
932 struct dgm_softc *sc;
933 struct tty *tp;
934 int unit;
935 int mynor;
936 int pnum;
937 struct dgm_p *port;
938 int error;
939 volatile struct board_chan *bc;
941 error = 0;
942 mynor = minor(dev);
943 unit = MINOR_TO_UNIT(mynor);
944 pnum = MINOR_TO_PORT(mynor);
946 sc = devclass_get_softc(dgmdevclass, unit);
947 if (sc == NULL) {
948 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
949 unit);
950 return ENXIO;
953 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
955 if (!sc->enabled) {
956 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
957 unit);
958 return ENXIO;
961 if (pnum >= sc->numports) {
962 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
963 unit, pnum);
964 return ENXIO;
967 if (mynor & CONTROL_MASK)
968 return 0;
970 tp = &sc->ttys[pnum];
971 dev->si_tty = tp;
972 port = &sc->ports[pnum];
973 bc = port->brdchan;
975 open_top:
976 crit_enter();
978 while (port->closing) {
979 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
981 if (error) {
982 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
983 " error = %d\n", unit, pnum, error);
984 goto out;
988 if (tp->t_state & TS_ISOPEN) {
990 * The device is open, so everything has been initialized.
991 * Handle conflicts.
993 if (mynor & CALLOUT_MASK) {
994 if (!port->active_out) {
995 error = EBUSY;
996 DPRINT4(DB_OPEN, "dgm%d: port%d:"
997 " BUSY error = %d\n", unit, pnum, error);
998 goto out;
1000 } else if (port->active_out) {
1001 if (ap->a_oflags & O_NONBLOCK) {
1002 error = EBUSY;
1003 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1004 " BUSY error = %d\n", unit, pnum, error);
1005 goto out;
1007 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
1008 if (error != 0) {
1009 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1010 " error = %d\n", unit, pnum, error);
1011 goto out;
1013 crit_exit();
1014 goto open_top;
1016 if (tp->t_state & TS_XCLUDE && suser_cred(ap->a_cred, 0)) {
1017 error = EBUSY;
1018 goto out;
1020 } else {
1022 * The device isn't open, so there are no conflicts.
1023 * Initialize it. Initialization is done twice in many
1024 * cases: to preempt sleeping callin opens if we are
1025 * callout, and to complete a callin open after DCD rises.
1027 tp->t_oproc = dgmstart;
1028 tp->t_param = dgmparam;
1029 tp->t_stop = dgmstop;
1030 tp->t_dev = dev;
1031 tp->t_termios= (mynor & CALLOUT_MASK) ?
1032 port->it_out :
1033 port->it_in;
1035 crit_enter();
1036 setwin(sc, 0);
1037 port->imodem = bc->mstat;
1038 bc->rout = bc->rin; /* clear input queue */
1039 bc->idata = 1;
1040 #ifdef PRINT_BUFSIZE
1041 kprintf("dgm buffers tx = %x:%x rx = %x:%x\n",
1042 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1043 #endif
1045 hidewin(sc);
1046 crit_exit();
1048 port->wopeners++;
1049 error = dgmparam(tp, &tp->t_termios);
1050 port->wopeners--;
1052 if (error != 0) {
1053 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1054 unit, pnum, error);
1055 goto out;
1058 /* handle fake DCD for callout devices */
1059 /* and initial DCD */
1061 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1062 linesw[tp->t_line].l_modem(tp, 1);
1066 * Wait for DCD if necessary.
1068 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1069 && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1070 ++port->wopeners;
1071 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1072 --port->wopeners;
1073 if (error != 0) {
1074 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1075 " error = %d\n", unit, pnum, error);
1076 goto out;
1078 crit_exit();
1079 goto open_top;
1081 error = linesw[tp->t_line].l_open(dev, tp);
1082 disc_optim(tp, &tp->t_termios);
1083 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1084 unit, pnum, error);
1086 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1087 port->active_out = 1;
1089 port->used = 1;
1091 /* If any port is open (i.e. the open() call is completed for it)
1092 * the device is busy
1095 out:
1096 disc_optim(tp, &tp->t_termios);
1097 crit_exit();
1099 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1100 dgmhardclose(port);
1102 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1103 unit, pnum, error);
1105 return error;
1108 /*ARGSUSED*/
1109 static int
1110 dgmclose(struct dev_close_args *ap)
1112 cdev_t dev = ap->a_head.a_dev;
1113 int mynor;
1114 struct tty *tp;
1115 int unit, pnum;
1116 struct dgm_softc *sc;
1117 struct dgm_p *port;
1118 int i;
1120 mynor = minor(dev);
1121 if (mynor & CONTROL_MASK)
1122 return 0;
1123 unit = MINOR_TO_UNIT(mynor);
1124 pnum = MINOR_TO_PORT(mynor);
1126 sc = devclass_get_softc(dgmdevclass, unit);
1127 tp = &sc->ttys[pnum];
1128 port = sc->ports + pnum;
1130 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1132 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1133 dgm_drain_or_flush(port);
1135 crit_enter();
1137 port->closing = 1;
1138 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1139 linesw[tp->t_line].l_close(tp, ap->a_fflag);
1140 disc_optim(tp, &tp->t_termios);
1142 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1143 dgmhardclose(port);
1144 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1145 ttyclose(tp);
1146 port->closing = 0;
1147 wakeup(&port->closing);
1148 port->used = 0;
1150 /* mark the card idle when all ports are closed */
1152 for (i = 0; i < sc->numports; i++)
1153 if (sc->ports[i].used)
1154 break;
1156 crit_exit();
1158 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1160 wakeup(TSA_CARR_ON(tp));
1161 wakeup(&port->active_out);
1162 port->active_out = 0;
1164 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1166 return 0;
1169 static void
1170 dgmhardclose(struct dgm_p *port)
1172 volatile struct board_chan *bc = port->brdchan;
1173 struct dgm_softc *sc;
1175 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1176 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1177 crit_enter();
1178 port->do_timestamp = 0;
1179 setwin(sc, 0);
1181 bc->idata = 0;
1182 bc->iempty = 0;
1183 bc->ilow = 0;
1184 if (port->tty->t_cflag & HUPCL) {
1185 port->omodem &= ~(RTS|DTR);
1186 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1189 hidewin(sc);
1190 crit_exit();
1192 callout_reset(&port->hc_timeout, hz / 2, dgm_pause, &port->brdchan);
1193 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1196 static void
1197 dgm_pause(void *chan)
1199 wakeup((caddr_t)chan);
1202 static void
1203 dgmpoll(void *unit_c)
1205 int unit = (int)unit_c;
1206 int pnum;
1207 struct dgm_p *port;
1208 struct dgm_softc *sc;
1209 int head, tail;
1210 u_char *eventbuf;
1211 int event, mstat, lstat;
1212 volatile struct board_chan *bc;
1213 struct tty *tp;
1214 int rhead, rtail;
1215 int whead, wtail;
1216 int size;
1217 u_char *ptr;
1218 int ocount;
1219 int ibuf_full, obuf_full;
1220 BoardMemWinState ws = bmws_get();
1222 sc = devclass_get_softc(dgmdevclass, unit);
1223 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1225 if (!sc->enabled) {
1226 kprintf("dgm%d: polling of disabled board stopped\n", unit);
1227 return;
1230 setwin(sc, 0);
1232 head = sc->mailbox->ein;
1233 tail = sc->mailbox->eout;
1235 while (head != tail) {
1236 if (head >= FEP_IMAX - FEP_ISTART
1237 || tail >= FEP_IMAX - FEP_ISTART
1238 || (head|tail) & 03 ) {
1239 kprintf("dgm%d: event queue's head or tail is wrong!"
1240 " hd = %d, tl = %d\n", unit, head, tail);
1241 break;
1244 eventbuf = sc->vmem + tail + FEP_ISTART;
1245 pnum = eventbuf[0];
1246 event = eventbuf[1];
1247 mstat = eventbuf[2];
1248 lstat = eventbuf[3];
1250 port = &sc->ports[pnum];
1251 bc = port->brdchan;
1252 tp = &sc->ttys[pnum];
1254 if (pnum >= sc->numports || !port->enabled) {
1255 kprintf("dgm%d: port%d: got event on nonexisting port\n",
1256 unit, pnum);
1257 } else if (port->used || port->wopeners > 0 ) {
1259 int wrapmask = port->rxbufsize - 1;
1261 if (!(event & ALL_IND))
1262 kprintf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1263 unit, pnum, event, mstat, lstat);
1265 if (event & DATA_IND) {
1266 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1267 unit, pnum);
1269 rhead = bc->rin & wrapmask;
1270 rtail = bc->rout & wrapmask;
1272 if (!(tp->t_cflag & CREAD) || !port->used ) {
1273 bc->rout = rhead;
1274 goto end_of_data;
1277 if (bc->orun) {
1278 kprintf("dgm%d: port%d: overrun\n", unit, pnum);
1279 bc->orun = 0;
1282 if (!(tp->t_state & TS_ISOPEN))
1283 goto end_of_data;
1285 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1286 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1287 " p rx head = %d tail = %d\n", unit,
1288 pnum, rhead, rtail);
1290 if (rhead > rtail)
1291 size = rhead - rtail;
1292 else
1293 size = port->rxbufsize - rtail;
1295 ptr = port->rxptr + rtail;
1297 /* Helg: */
1298 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1299 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1300 DPRINT1(DB_RXDATA, "*");
1301 ibuf_full = TRUE;
1304 if (size) {
1305 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1306 DPRINT1(DB_RXDATA, "!");
1307 towin(sc, port->rxwin);
1308 tk_nin += size;
1309 tk_rawcc += size;
1310 tp->t_rawcc += size;
1311 b_to_q(ptr, size,
1312 &tp->t_rawq);
1313 setwin(sc, 0);
1314 } else {
1315 int i = size;
1316 unsigned char chr;
1317 do {
1318 towin(sc, port->rxwin);
1319 chr = *ptr++;
1320 hidewin(sc);
1321 (*linesw[tp->t_line].l_rint)(chr, tp);
1322 } while (--i > 0 );
1323 setwin(sc, 0);
1326 rtail= (rtail + size) & wrapmask;
1327 bc->rout = rtail;
1328 rhead = bc->rin & wrapmask;
1329 hidewin(sc);
1330 ttwakeup(tp);
1331 setwin(sc, 0);
1333 end_of_data: ;
1336 if (event & MODEMCHG_IND) {
1337 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1338 "MODEMCHG_IND\n", unit, pnum);
1339 port->imodem = mstat;
1340 if (mstat & port->dcd) {
1341 hidewin(sc);
1342 linesw[tp->t_line].l_modem(tp, 1);
1343 setwin(sc, 0);
1344 wakeup(TSA_CARR_ON(tp));
1345 } else {
1346 hidewin(sc);
1347 linesw[tp->t_line].l_modem(tp, 0);
1348 setwin(sc, 0);
1349 if (port->draining) {
1350 port->draining = 0;
1351 wakeup(&port->draining);
1356 if (event & BREAK_IND) {
1357 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1358 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1359 " BREAK_IND\n", unit, pnum);
1360 hidewin(sc);
1361 linesw[tp->t_line].l_rint(TTY_BI, tp);
1362 setwin(sc, 0);
1366 /* Helg: with output flow control */
1368 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1369 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1370 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1372 if ((event & EMPTYTX_IND ) &&
1373 tp->t_outq.c_cc == 0 && port->draining) {
1374 port->draining = 0;
1375 wakeup(&port->draining);
1376 bc->ilow = 0;
1377 bc->iempty = 0;
1378 } else {
1380 int wrapmask = port->txbufsize - 1;
1382 for (obuf_full = FALSE;
1383 tp->t_outq.c_cc != 0 && !obuf_full;
1385 /* add "last-minute" data to write buffer */
1386 if (!(tp->t_state & TS_BUSY)) {
1387 hidewin(sc);
1388 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1389 ttwwakeup(tp);
1390 #else
1391 if (tp->t_outq.c_cc <= tp->t_lowat) {
1392 if (tp->t_state & TS_ASLEEP) {
1393 tp->t_state &= ~TS_ASLEEP;
1394 wakeup(TSA_OLOWAT(tp));
1396 /* selwakeup(&tp->t_wsel); */
1398 #endif
1399 setwin(sc, 0);
1401 crit_enter();
1403 whead = bc->tin & wrapmask;
1404 wtail = bc->tout & wrapmask;
1406 if (whead < wtail)
1407 size = wtail - whead - 1;
1408 else {
1409 size = port->txbufsize - whead;
1410 if (wtail == 0)
1411 size--;
1414 if (size == 0) {
1415 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1416 whead, wtail, size, obuf_full);
1417 bc->iempty = 1;
1418 bc->ilow = 1;
1419 obuf_full = TRUE;
1420 crit_exit();
1421 break;
1424 towin(sc, port->txwin);
1426 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1427 whead += ocount;
1429 setwin(sc, 0);
1430 bc->tin = whead;
1431 bc->tin = whead & wrapmask;
1432 crit_exit();
1435 if (obuf_full) {
1436 DPRINT1(DB_WR, " +BUSY\n");
1437 tp->t_state |= TS_BUSY;
1438 } else {
1439 DPRINT1(DB_WR, " -BUSY\n");
1440 hidewin(sc);
1441 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1442 /* should clear TS_BUSY before ttwwakeup */
1443 if (tp->t_state & TS_BUSY) {
1444 tp->t_state &= ~TS_BUSY;
1445 linesw[tp->t_line].l_start(tp);
1446 ttwwakeup(tp);
1448 #else
1449 if (tp->t_state & TS_ASLEEP) {
1450 tp->t_state &= ~TS_ASLEEP;
1451 wakeup(TSA_OLOWAT(tp));
1453 tp->t_state &= ~TS_BUSY;
1454 #endif
1455 setwin(sc, 0);
1459 bc->idata = 1; /* require event on incoming data */
1461 } else {
1462 bc = port->brdchan;
1463 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1464 unit, pnum, event);
1465 bc->rout = bc->rin;
1466 bc->idata = bc->iempty = bc->ilow = 0;
1469 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1472 sc->mailbox->eout = tail;
1473 bmws_set(ws);
1475 callout_reset(&sc->toh, hz / POLLSPERSEC, dgmpoll, unit_c);
1477 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1480 static int
1481 dgmioctl(struct dev_ioctl_args *ap)
1483 cdev_t dev = ap->a_head.a_dev;
1484 u_long cmd = ap->a_cmd;
1485 caddr_t data = ap->a_data;
1486 struct dgm_softc *sc;
1487 int unit, pnum;
1488 struct dgm_p *port;
1489 int mynor;
1490 struct tty *tp;
1491 volatile struct board_chan *bc;
1492 int error;
1493 int tiocm_xxx;
1495 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1496 u_long oldcmd;
1497 struct termios term;
1498 #endif
1500 BoardMemWinState ws = bmws_get();
1502 mynor = minor(dev);
1503 unit = MINOR_TO_UNIT(mynor);
1504 pnum = MINOR_TO_PORT(mynor);
1506 sc = devclass_get_softc(dgmdevclass, unit);
1507 port = &sc->ports[pnum];
1508 tp = &sc->ttys[pnum];
1509 bc = port->brdchan;
1511 if (mynor & CONTROL_MASK) {
1512 struct termios *ct;
1514 switch (mynor & CONTROL_MASK) {
1515 case CONTROL_INIT_STATE:
1516 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1517 break;
1518 case CONTROL_LOCK_STATE:
1519 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1520 break;
1521 default:
1522 return (ENODEV); /* /dev/nodev */
1524 switch (cmd) {
1525 case TIOCSETA:
1526 error = suser_cred(ap->a_cred, 0);
1527 if (error != 0)
1528 return (error);
1529 *ct = *(struct termios *)data;
1530 return (0);
1531 case TIOCGETA:
1532 *(struct termios *)data = *ct;
1533 return (0);
1534 case TIOCGETD:
1535 *(int *)data = TTYDISC;
1536 return (0);
1537 case TIOCGWINSZ:
1538 bzero(data, sizeof(struct winsize));
1539 return (0);
1540 default:
1541 return (ENOTTY);
1545 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1546 term = tp->t_termios;
1547 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1548 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);
1550 oldcmd = cmd;
1551 error = ttsetcompat(tp, &cmd, data, &term);
1552 if (error != 0)
1553 return (error);
1554 if (cmd != oldcmd)
1555 data = (caddr_t)&term;
1556 #endif
1558 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1559 int cc;
1560 struct termios *dt = (struct termios *)data;
1561 struct termios *lt = mynor & CALLOUT_MASK
1562 ? &port->lt_out : &port->lt_in;
1564 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);
1565 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1566 | (dt->c_iflag & ~lt->c_iflag);
1567 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1568 | (dt->c_oflag & ~lt->c_oflag);
1569 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1570 | (dt->c_cflag & ~lt->c_cflag);
1571 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1572 | (dt->c_lflag & ~lt->c_lflag);
1573 for (cc = 0; cc < NCCS; ++cc)
1574 if (lt->c_cc[cc] != 0)
1575 dt->c_cc[cc] = tp->t_cc[cc];
1576 if (lt->c_ispeed != 0)
1577 dt->c_ispeed = tp->t_ispeed;
1578 if (lt->c_ospeed != 0)
1579 dt->c_ospeed = tp->t_ospeed;
1582 if (cmd == TIOCSTOP) {
1583 crit_enter();
1584 setwin(sc, 0);
1585 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1586 bmws_set(ws);
1587 crit_exit();
1588 return 0;
1589 } else if (cmd == TIOCSTART) {
1590 crit_enter();
1591 setwin(sc, 0);
1592 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1593 bmws_set(ws);
1594 crit_exit();
1595 return 0;
1598 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1599 port->mustdrain = 1;
1601 error = linesw[tp->t_line].l_ioctl(tp, cmd, data,
1602 ap->a_fflag, ap->a_cred);
1603 if (error != ENOIOCTL)
1604 return error;
1605 crit_enter();
1606 error = ttioctl(tp, cmd, data, ap->a_fflag);
1607 disc_optim(tp, &tp->t_termios);
1608 port->mustdrain = 0;
1609 if (error != ENOIOCTL) {
1610 crit_exit();
1611 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1612 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 return error;
1617 switch (cmd) {
1618 case TIOCSBRK:
1619 #if 0
1620 error = dgmdrain(port);
1622 if (error != 0) {
1623 crit_exit();
1624 return error;
1626 #endif
1628 crit_enter();
1629 setwin(sc, 0);
1631 /* now it sends 400 millisecond break because I don't know */
1632 /* how to send an infinite break */
1634 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1635 hidewin(sc);
1636 crit_exit();
1637 break;
1638 case TIOCCBRK:
1639 /* now it's empty */
1640 break;
1641 case TIOCSDTR:
1642 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1643 port->omodem |= DTR;
1644 crit_enter();
1645 setwin(sc, 0);
1646 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1648 if (!(bc->mstat & DTR))
1649 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1651 hidewin(sc);
1652 crit_exit();
1653 break;
1654 case TIOCCDTR:
1655 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1656 port->omodem &= ~DTR;
1657 crit_enter();
1658 setwin(sc, 0);
1659 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1661 if (bc->mstat & DTR) {
1662 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1665 hidewin(sc);
1666 crit_exit();
1667 break;
1668 case TIOCMSET:
1669 if (*(int *)data & TIOCM_DTR)
1670 port->omodem |= DTR;
1671 else
1672 port->omodem &= ~DTR;
1674 if (*(int *)data & TIOCM_RTS)
1675 port->omodem |= RTS;
1676 else
1677 port->omodem &= ~RTS;
1679 crit_enter();
1680 setwin(sc, 0);
1681 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1682 hidewin(sc);
1683 crit_exit();
1684 break;
1685 case TIOCMBIS:
1686 if (*(int *)data & TIOCM_DTR)
1687 port->omodem |= DTR;
1689 if (*(int *)data & TIOCM_RTS)
1690 port->omodem |= RTS;
1692 crit_enter();
1693 setwin(sc, 0);
1694 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1695 hidewin(sc);
1696 crit_exit();
1697 break;
1698 case TIOCMBIC:
1699 if (*(int *)data & TIOCM_DTR)
1700 port->omodem &= ~DTR;
1702 if (*(int *)data & TIOCM_RTS)
1703 port->omodem &= ~RTS;
1705 crit_enter();
1706 setwin(sc, 0);
1707 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1708 hidewin(sc);
1709 crit_exit();
1710 break;
1711 case TIOCMGET:
1712 setwin(sc, 0);
1713 port->imodem = bc->mstat;
1714 hidewin(sc);
1716 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1718 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1720 if (port->imodem & DTR) {
1721 DPRINT1(DB_MODEM, "DTR ");
1722 tiocm_xxx |= TIOCM_DTR;
1724 if (port->imodem & RTS) {
1725 DPRINT1(DB_MODEM, "RTS ");
1726 tiocm_xxx |= TIOCM_RTS;
1728 if (port->imodem & CTS) {
1729 DPRINT1(DB_MODEM, "CTS ");
1730 tiocm_xxx |= TIOCM_CTS;
1732 if (port->imodem & port->dcd) {
1733 DPRINT1(DB_MODEM, "DCD ");
1734 tiocm_xxx |= TIOCM_CD;
1736 if (port->imodem & port->dsr) {
1737 DPRINT1(DB_MODEM, "DSR ");
1738 tiocm_xxx |= TIOCM_DSR;
1740 if (port->imodem & RI) {
1741 DPRINT1(DB_MODEM, "RI ");
1742 tiocm_xxx |= TIOCM_RI;
1744 *(int *)data = tiocm_xxx;
1745 DPRINT1(DB_MODEM, "--\n");
1746 break;
1747 case TIOCMSDTRWAIT:
1748 /* must be root since the wait applies to following logins */
1749 error = suser_cred(ap->a_cred, 0);
1750 if (error != 0) {
1751 crit_exit();
1752 return (error);
1754 port->close_delay = *(int *)data * hz / 100;
1755 break;
1756 case TIOCMGDTRWAIT:
1757 *(int *)data = port->close_delay * 100 / hz;
1758 break;
1759 case TIOCTIMESTAMP:
1760 port->do_timestamp = 1;
1761 *(struct timeval *)data = port->timestamp;
1762 break;
1763 case TIOCDCDTIMESTAMP:
1764 port->do_dcd_timestamp = 1;
1765 *(struct timeval *)data = port->dcd_timestamp;
1766 break;
1767 default:
1768 bmws_set(ws);
1769 crit_exit();
1770 return ENOTTY;
1772 bmws_set(ws);
1773 crit_exit();
1775 return 0;
1778 static void
1779 wakeflush(void *p)
1781 struct dgm_p *port = p;
1783 wakeup(&port->draining);
1786 /* wait for the output to drain */
1788 static int
1789 dgmdrain(struct dgm_p *port)
1791 volatile struct board_chan *bc = port->brdchan;
1792 struct dgm_softc *sc;
1793 int error;
1794 int head, tail;
1795 BoardMemWinState ws = bmws_get();
1797 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1799 setwin(sc, 0);
1801 bc->iempty = 1;
1802 tail = bc->tout;
1803 head = bc->tin;
1805 while (tail != head) {
1806 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1807 port->sc->unit, port->pnum, head, tail);
1809 hidewin(sc);
1810 port->draining = 1;
1811 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1812 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
1813 port->draining = 0;
1814 setwin(sc, 0);
1816 if (error != 0) {
1817 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1818 port->sc->unit, port->pnum, error);
1820 bc->iempty = 0;
1821 bmws_set(ws);
1822 return error;
1825 tail = bc->tout;
1826 head = bc->tin;
1828 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1829 port->sc->unit, port->pnum, head, tail);
1830 bmws_set(ws);
1831 return 0;
1834 /* wait for the output to drain */
1835 /* or simply clear the buffer it it's stopped */
1837 static void
1838 dgm_drain_or_flush(struct dgm_p *port)
1840 volatile struct board_chan *bc = port->brdchan;
1841 struct tty *tp = port->tty;
1842 struct dgm_softc *sc;
1843 int error;
1844 int lasttail;
1845 int head, tail;
1847 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1848 setwin(sc, 0);
1850 lasttail = -1;
1851 bc->iempty = 1;
1852 tail = bc->tout;
1853 head = bc->tin;
1855 while (tail != head /* && tail != lasttail */ ) {
1856 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1857 port->sc->unit, port->pnum, head, tail);
1859 /* if there is no carrier simply clean the buffer */
1860 if (!(tp->t_state & TS_CARR_ON)) {
1861 bc->tout = bc->tin = 0;
1862 bc->iempty = 0;
1863 hidewin(sc);
1864 return;
1867 hidewin(sc);
1868 port->draining = 1;
1869 callout_reset(&port->wf_timeout, hz, wakeflush, port);
1870 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
1871 port->draining = 0;
1872 setwin(sc, 0);
1874 if (error != 0) {
1875 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1876 " error = %d\n", port->sc->unit, port->pnum, error);
1878 /* silently clean the buffer */
1880 bc->tout = bc->tin = 0;
1881 bc->iempty = 0;
1882 hidewin(sc);
1883 return;
1886 lasttail = tail;
1887 tail = bc->tout;
1888 head = bc->tin;
1890 hidewin(sc);
1891 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1892 port->sc->unit, port->pnum, head, tail);
1895 static int
1896 dgmparam(struct tty *tp, struct termios *t)
1898 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1899 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1900 volatile struct board_chan *bc;
1901 struct dgm_softc *sc;
1902 struct dgm_p *port;
1903 int cflag;
1904 int head;
1905 int mval;
1906 int iflag;
1907 int hflow;
1908 BoardMemWinState ws = bmws_get();
1910 sc = devclass_get_softc(dgmdevclass, unit);
1911 port = &sc->ports[pnum];
1912 bc = port->brdchan;
1914 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);
1916 if (port->mustdrain) {
1917 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1918 dgmdrain(port);
1921 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1923 if (t->c_ispeed == 0)
1924 t->c_ispeed = t->c_ospeed;
1926 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1927 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1928 return (EINVAL);
1931 crit_enter();
1932 setwin(sc, 0);
1934 if (cflag == 0) { /* hangup */
1935 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1936 head = bc->rin;
1937 bc->rout = head;
1938 head = bc->tin;
1939 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1940 mval= port->omodem & ~(DTR|RTS);
1941 } else {
1942 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1944 if (cflag != port->fepcflag) {
1945 port->fepcflag = cflag;
1946 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1947 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1948 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1950 mval= port->omodem | (DTR|RTS);
1953 iflag = dgmflags(dgm_iflags, t->c_iflag);
1954 if (iflag != port->fepiflag) {
1955 port->fepiflag = iflag;
1956 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1957 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1960 bc->mint = port->dcd;
1962 hflow = dgmflags(dgm_flow, t->c_cflag);
1963 if (hflow != port->hflow) {
1964 port->hflow = hflow;
1965 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1966 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1969 if (port->omodem != mval) {
1970 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1971 unit, pnum, mval, port->omodem);
1972 port->omodem = mval;
1973 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1976 if (port->fepstartc != t->c_cc[VSTART] ||
1977 port->fepstopc != t->c_cc[VSTOP]) {
1978 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1979 port->fepstartc = t->c_cc[VSTART];
1980 port->fepstopc = t->c_cc[VSTOP];
1981 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1984 bmws_set(ws);
1985 crit_exit();
1987 return 0;
1991 static void
1992 dgmstart(struct tty *tp)
1994 int unit;
1995 int pnum;
1996 struct dgm_p *port;
1997 struct dgm_softc *sc;
1998 volatile struct board_chan *bc;
1999 int head, tail;
2000 int size, ocount;
2001 int wmask;
2003 BoardMemWinState ws = bmws_get();
2005 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2006 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2007 sc = devclass_get_softc(dgmdevclass, unit);
2008 port = &sc->ports[pnum];
2009 bc = port->brdchan;
2011 wmask = port->txbufsize - 1;
2013 crit_enter();
2015 while (tp->t_outq.c_cc != 0) {
2016 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2017 ttwwakeup(tp);
2018 #else
2019 if (tp->t_outq.c_cc <= tp->t_lowat) {
2020 if (tp->t_state & TS_ASLEEP) {
2021 tp->t_state &= ~TS_ASLEEP;
2022 wakeup(TSA_OLOWAT(tp));
2024 /*selwakeup(&tp->t_wsel);*/
2026 #endif
2027 crit_enter();
2028 setwin(sc, 0);
2030 head = bc->tin & wmask;
2032 do { tail = bc->tout; } while (tail != bc->tout);
2033 tail = bc->tout & wmask;
2035 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2037 #ifdef LEAVE_FREE_CHARS
2038 if (tail > head) {
2039 size = tail - head - LEAVE_FREE_CHARS;
2040 if (size < 0)
2041 size = 0;
2042 else {
2043 size = port->txbufsize - head;
2044 if (tail + port->txbufsize < head)
2045 size = 0;
2048 #else
2049 if (tail > head)
2050 size = tail - head - 1;
2051 else {
2052 size = port->txbufsize - head;
2053 if (tail == 0)
2054 size--;
2056 #endif
2058 if (size == 0) {
2059 bc->iempty = 1;
2060 bc->ilow = 1;
2061 crit_exit();
2062 bmws_set(ws);
2063 tp->t_state |= TS_BUSY;
2064 crit_exit();
2065 return;
2068 towin(sc, port->txwin);
2070 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2071 head += ocount;
2072 if (head >= port->txbufsize)
2073 head -= port->txbufsize;
2075 setwin(sc, 0);
2076 bc->tin = head;
2078 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2079 unit, pnum, size, ocount);
2080 hidewin(sc);
2081 crit_exit();
2084 bmws_set(ws);
2085 crit_exit();
2087 #ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2088 if (tp->t_state & TS_BUSY) {
2089 tp->t_state &= ~TS_BUSY;
2090 linesw[tp->t_line].l_start(tp);
2091 ttwwakeup(tp);
2093 #else
2094 if (tp->t_state & TS_ASLEEP) {
2095 tp->t_state &= ~TS_ASLEEP;
2096 wakeup(TSA_OLOWAT(tp));
2098 tp->t_state& = ~TS_BUSY;
2099 #endif
2102 void
2103 dgmstop(struct tty *tp, int rw)
2105 int unit;
2106 int pnum;
2107 struct dgm_p *port;
2108 struct dgm_softc *sc;
2109 volatile struct board_chan *bc;
2111 BoardMemWinState ws = bmws_get();
2113 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2114 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2116 sc = devclass_get_softc(dgmdevclass, unit);
2117 port = &sc->ports[pnum];
2118 bc = port->brdchan;
2120 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2122 crit_enter();
2123 setwin(sc, 0);
2125 if (rw & FWRITE) {
2126 /* clear output queue */
2127 bc->tout = bc->tin = 0;
2128 bc->ilow = 0;
2129 bc->iempty = 0;
2131 if (rw & FREAD) {
2132 /* clear input queue */
2133 bc->rout = bc->rin;
2134 bc->idata = 1;
2136 hidewin(sc);
2137 bmws_set(ws);
2138 crit_exit();
2139 dgmstart(tp);
2142 static void
2143 fepcmd(struct dgm_p *port,
2144 unsigned cmd,
2145 unsigned op1,
2146 unsigned op2,
2147 unsigned ncmds,
2148 unsigned bytecmd)
2150 u_char *mem;
2151 unsigned tail, head;
2152 int count, n;
2154 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2155 mem = port->sc->vmem;
2157 if (!port->enabled) {
2158 kprintf("dgm%d: port%d: FEP command on disabled port\n",
2159 port->sc->unit, port->pnum);
2160 return;
2163 /* setwin(port->sc, 0); Require this to be set by caller */
2164 head = port->sc->mailbox->cin;
2166 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2167 kprintf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2168 port->sc->unit, port->pnum, head);
2169 return;
2172 mem[head + FEP_CSTART] = cmd;
2173 mem[head + FEP_CSTART + 1] = port->pnum;
2174 if (bytecmd) {
2175 mem[head + FEP_CSTART + 2] = op1;
2176 mem[head + FEP_CSTART + 3] = op2;
2177 } else {
2178 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2179 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2182 DPRINT7(DB_FEP, "dgm%d: port%d: %s cmd = 0x%x op1 = 0x%x op2 = 0x%x\n", port->sc->unit, port->pnum,
2183 (bytecmd)?"byte":"word", cmd, mem[head + FEP_CSTART + 2], mem[head + FEP_CSTART + 3]);
2185 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2186 port->sc->mailbox->cin = head;
2188 count = FEPTIMEOUT;
2190 while (count-- != 0) {
2191 head = port->sc->mailbox->cin;
2192 tail = port->sc->mailbox->cout;
2194 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2195 if (n <= ncmds * (sizeof(ushort)*4))
2196 return;
2198 kprintf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2201 static void
2202 disc_optim(struct tty *tp, struct termios *t)
2204 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2205 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2206 && (!(t->c_iflag & PARMRK)
2207 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2208 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2209 && linesw[tp->t_line].l_rint == ttyinput)
2210 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2211 else
2212 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;