proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / dev / serial / dgb / dgm.c
CommitLineData
984263bc
MD
1/*-
2 * $FreeBSD: src/sys/dev/dgb/dgm.c,v 1.31.2.3 2001/10/07 09:02:25 brian Exp $
dadab5e9 3 * $DragonFly: src/sys/dev/serial/dgb/dgm.c,v 1.3 2003/06/25 03:55:47 dillon Exp $
984263bc
MD
4 *
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>
8 *
9 * Digiboard driver.
10 *
11 * Stage 1. "Better than nothing".
12 * Stage 2. "Gee, it works!".
13 *
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.
25 *
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.
37 *
38 * Written by Sergey Babkin,
39 * Joint Stock Commercial Bank "Chelindbank"
40 * (Chelyabinsk, Russia)
41 * babkin@freebsd.org
42 *
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>
52 *
53 * New-busification by Brian Somers <brian@Awfulhak.org>
54 *
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
64 */
65
66/* How often to run dgmpoll */
67#define POLLSPERSEC 25
68
69/* How many charactes can we write to input tty rawq */
70#define DGB_IBUFSIZE (TTYHOG - 100)
71
72/* the overall number of ports controlled by this driver */
73
74#include <sys/param.h>
75
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 <machine/bus.h>
90#include <sys/rman.h>
91#include <machine/resource.h>
92
93#include <machine/clock.h>
94
95#include <vm/vm.h>
96#include <vm/pmap.h>
97
98#include <dev/dgb/dgmfep.h>
99#include <dev/dgb/dgmbios.h>
100#include <dev/dgb/dgmreg.h>
101
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)
112#define IO_SIZE 0x04
113#define MEM_SIZE 0x8000
114
115struct dgm_softc;
116
117/* digiboard port structure */
118struct dgm_p {
119 unsigned enabled : 1;
120
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 */
127 u_char hflow;
128 u_char dsr;
129 u_char dcd;
130 u_char stopc;
131 u_char startc;
132 u_char stopca;
133 u_char startca;
134 u_char fepstopc;
135 u_char fepstartc;
136 u_char fepstopca;
137 u_char fepstartca;
138 u_char txwin;
139 u_char rxwin;
140 ushort fepiflag;
141 ushort fepcflag;
142 ushort fepoflag;
143 ushort txbufhead;
144 ushort txbufsize;
145 ushort rxbufhead;
146 ushort rxbufsize;
147 int close_delay;
148 u_char *txptr;
149 u_char *rxptr;
150 volatile struct board_chan *brdchan;
151 struct tty *tty;
152
153 u_char active_out; /* nonzero if the callout device is open */
154 u_int wopeners; /* # processes waiting for DCD in open() */
155
156 /* Initial state. */
157 struct termios it_in; /* should be in struct tty */
158 struct termios it_out;
159
160 /* Lock state. */
161 struct termios lt_in; /* should be in struct tty */
162 struct termios lt_out;
163
164 unsigned do_timestamp : 1;
165 unsigned do_dcd_timestamp : 1;
166 struct timeval timestamp;
167 struct timeval dcd_timestamp;
168
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() */
174};
175
176/* Digiboard per-board structure */
177struct dgm_softc {
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;
193 int iorid;
194 int mrid;
195 struct callout_handle toh; /* poll timeout handle */
196};
197
198static void dgmpoll(void *);
199static int dgmprobe(device_t);
200static int dgmattach(device_t);
201static int dgmdetach(device_t);
202static int dgmshutdown(device_t);
203static void fepcmd(struct dgm_p *, unsigned, unsigned, unsigned, unsigned,
204 unsigned);
205static void dgmstart(struct tty *);
206static void dgmstop(struct tty *, int);
207static int dgmparam(struct tty *, struct termios *);
208static void dgmhardclose(struct dgm_p *);
209static void dgm_drain_or_flush(struct dgm_p *);
210static int dgmdrain(struct dgm_p *);
211static void dgm_pause(void *);
212static void wakeflush(void *);
213static void disc_optim(struct tty *, struct termios *);
214
215static d_open_t dgmopen;
216static d_close_t dgmclose;
217static d_ioctl_t dgmioctl;
218
219static 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),
225 { 0, 0 }
226};
227
228static driver_t dgmdriver = {
229 "dgm",
230 dgmmethods,
231 sizeof (struct dgm_softc),
232};
233
234static devclass_t dgmdevclass;
235
236#define CDEV_MAJOR 101
237static struct cdevsw dgm_cdevsw = {
238 /* open */ dgmopen,
239 /* close */ dgmclose,
240 /* read */ ttyread,
241 /* write */ ttywrite,
242 /* ioctl */ dgmioctl,
243 /* poll */ ttypoll,
244 /* mmap */ nommap,
245 /* strategy */ nostrategy,
246 /* name */ "dgm",
247 /* maj */ CDEV_MAJOR,
248 /* dump */ nodump,
249 /* psize */ nopsize,
250 /* flags */ D_TTY | D_KQFILTER,
251 /* bmaj */ -1,
252 /* kqfilter */ ttykqfilter,
253};
254
255static int
256dgmmodhandler(module_t mod, int event, void *arg)
257{
258 int res = 0;
259
260 switch (event) {
261 case MOD_LOAD:
262 cdevsw_add(&dgm_cdevsw);
263 break;
264
265 case MOD_UNLOAD:
266 cdevsw_remove(&dgm_cdevsw);
267 break;
268 }
269
270 return res;
271}
272
273DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
274
275static speed_t dgmdefaultrate = TTYDEF_SPEED;
276
277static struct speedtab dgmspeedtab[] = {
278 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
279 { 50, FEP_B50 },
280 { 75, FEP_B75 },
281 { 110, FEP_B110 },
282 { 134, FEP_B134 },
283 { 150, FEP_B150 },
284 { 200, FEP_B200 },
285 { 300, FEP_B300 },
286 { 600, FEP_B600 },
287 { 1200, FEP_B1200 },
288 { 1800, FEP_B1800 },
289 { 2400, FEP_B2400 },
290 { 4800, FEP_B4800 },
291 { 9600, FEP_B9600 },
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 */
296 { -1, -1 }
297};
298
299static struct dbgflagtbl {
300 tcflag_t in_mask;
301 tcflag_t in_val;
302 tcflag_t out_val;
303} dgm_cflags[] = {
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 },
312 { (tcflag_t)-1 }
313}, dgm_iflags[] = {
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 },
323 { (tcflag_t)-1 }
324}, dgm_flow[] = {
325 { CRTSCTS, CRTSCTS, CTS|RTS },
326 { CRTSCTS, CCTS_OFLOW, CTS },
327 { CRTSCTS, CRTS_IFLOW, RTS },
328 { (tcflag_t)-1 }
329};
330
331/* xlat bsd termios flags to dgm sys-v style */
332static tcflag_t
333dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
334{
335 tcflag_t output = 0;
336 int i;
337
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;
341
342 return output;
343}
344
345static int dgmdebug = 0;
346SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
347
348static __inline int setwin(struct dgm_softc *, unsigned);
349static __inline void hidewin(struct dgm_softc *);
350static __inline void towin(struct dgm_softc *, int);
351
352/*Helg: to allow recursive dgm...() calls */
353typedef struct {
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 */
359
360#define DATA_WINOFF 0
361static BoardMemWinState bmws;
362
363static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
364static 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
370};
371
372/* return current memory window state and close window */
373static BoardMemWinState
374bmws_get(void)
375{
376 BoardMemWinState bmwsRet = bmws;
377
378 if (bmws.data != DATA_WINOFF)
379 outb(bmws.port, bmws.data = DATA_WINOFF);
380 return bmwsRet;
381}
382
383/* restore memory window state */
384static void
385bmws_set(BoardMemWinState ws)
386{
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);
392 bmws = ws;
393 }
394}
395
396static __inline int
397setwin(struct dgm_softc *sc, unsigned int addr)
398{
399 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
400 return (addr & 0x7FFF);
401}
402
403static __inline void
404hidewin(struct dgm_softc *sc)
405{
406 bmws.data = 0;
407 outb(bmws.port = sc->port + 1, bmws.data);
408}
409
410static __inline void
411towin(struct dgm_softc *sc, int win)
412{
413 outb(bmws.port = sc->port + 1, bmws.data = win);
414}
415
416static int
417dgmprobe(device_t dev)
418{
419 struct dgm_softc *sc = device_get_softc(dev);
420 int i, v;
421
422 sc->unit = device_get_unit(dev);
423
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)
426 return (ENXIO);
427 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
428 if (sc->port == validio[i])
429 break;
430 if (i == -1) {
431 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
432 return (ENXIO);
433 }
434
435 /* Ditto for our memory address */
436 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
437 return (ENXIO);
438 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
439 if (sc->pmem == validmem[i])
440 break;
441 if (i == -1) {
442 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
443 return (ENXIO);
444 }
445 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
446 device_printf(dev, "0x%lx: Memory address not supported\n",
447 sc->pmem);
448 return (ENXIO);
449 }
450 sc->vmem = (u_char *)sc->pmem;
451
452 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
453 sc->port, sc->pmem);
454
455 /* Temporarily map our io ports */
456 sc->iorid = 0;
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)
460 return (ENXIO);
461
462 outb(sc->port, FEPRST);
463 sc->enabled = 0;
464
465 for (i = 0; i < 1000; i++) {
466 DELAY(1);
467 if ((inb(sc->port) & FEPMASK) == FEPRST) {
468 sc->enabled = 1;
469 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
470 sc->unit, i);
471 break;
472 }
473 }
474
475 if (!sc->enabled) {
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);
478 return (ENXIO);
479 }
480
481 /* check type of card and get internal memory characteristics */
482
483 v = inb(sc->port);
484
485 if (!(v & 0x1)) {
486 int second;
487
488 outb(sc->port, 1);
489 second = inb(sc->port);
490 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
491 } else
492 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
493
494 sc->type = PCXEM;
495 sc->mem_seg = 0x8000;
496
497 /* Temporarily map our memory too */
498 sc->mrid = 0;
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);
504 return (ENXIO);
505 }
506
507 outb(sc->port, FEPCLR); /* drop RESET */
508 hidewin(sc); /* Helg: to set initial bmws state */
509
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);
512
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);
515
516 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
517
518 return (0);
519}
520
521static int
522dgmattach(device_t dev)
523{
524 struct dgm_softc *sc = device_get_softc(dev);
525 int i, t;
526 u_char *mem;
527 u_char *ptr;
528 int addr;
529 struct dgm_p *port;
530 volatile struct board_chan *bc;
531 int shrinkmem;
532 int lowwater;
533 u_long msize, iosize;
534
535 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
536
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);
541 sc->type = PCXEM;
542 sc->mem_seg = 0x8000;
543 sc->enabled = 1;
544 sc->type = PCXEM;
545 sc->mem_seg = 0x8000;
546
547 /* Allocate resources (should have been verified in dgmprobe()) */
548 sc->iorid = 0;
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)
552 return (ENXIO);
553 sc->mrid = 0;
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);
559 return (ENXIO);
560 }
561
562 /* map memory */
563 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
564
565 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
566 sc->mem_seg);
567
568 outb(sc->port, FEPRST);
569 DELAY(1);
570
571 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
572 if (i > 10000) {
573 device_printf(dev, "1st reset failed\n");
574 sc->enabled = 0;
575 hidewin(sc);
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);
578 return (ENXIO);
579 }
580 DELAY(1);
581 }
582
583 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
584
585 t = sc->pmem >> 8; /* disable windowing */
586 outb(sc->port + 2, t & 0xFF);
587 outb(sc->port + 3, t >> 8);
588
589 mem = sc->vmem;
590
591 /* very short memory test */
592 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
593
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");
598 sc->enabled = 0;
599 hidewin(sc);
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);
602 return (ENXIO);
603 }
604
605 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
606
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");
611 sc->enabled = 0;
612 hidewin(sc);
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);
615 return (ENXIO);
616 }
617
618 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
619
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");
624
625 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
626
627 addr = setwin(sc, MISCGLOBAL);
628 for (i = 0; i < 16; i++)
629 mem[addr + i] = 0;
630
631 addr = setwin(sc, BIOSOFFSET);
632 ptr = mem + addr;
633 for (i = 0; ptr < mem + msize; i++)
634 *ptr++ = pcem_bios[i];
635
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");
640 sc->enabled = 0;
641 hidewin(sc);
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);
644 return (ENXIO);
645 }
646 }
647 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
648
649 addr = setwin(sc, msize);
650 ptr = mem + addr;
651 for (;i < pcem_nbios; i++)
652 *ptr++ = pcem_bios[i];
653
654 ptr = mem;
655 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
656 if (*ptr++ != pcem_bios[i]) {
657 printf("High BIOS load failed\n");
658 sc->enabled = 0;
659 hidewin(sc);
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);
662 return (ENXIO);
663 }
664 }
665 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
666 device_printf(dev, "DigiBIOS loaded, initializing");
667
668 addr = setwin(sc, 0);
669
670 *(u_int *)(mem + addr) = 0x0bf00401;
671 *(u_int *)(mem + addr + 4) = 0;
672 *(ushort *)(mem + addr + 0xc00) = 0;
673 outb(sc->port, 0);
674
675 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
676 DELAY(10000);
677 if (i > 3000) {
678 printf("\nBIOS initialize failed(1)\n");
679 sc->enabled = 0;
680 hidewin(sc);
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);
683 return (ENXIO);
684 }
685 }
686
687 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
688 printf("\nBIOS initialize failed(2)\n");
689 sc->enabled = 0;
690 hidewin(sc);
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);
693 return (ENXIO);
694 }
695 printf(", DigiBIOS running\n");
696
697 DELAY(10000);
698
699 addr = setwin(sc, BIOSOFFSET);
700 ptr = mem + addr;
701 for (i = 0; i < pcem_ncook; i++)
702 *ptr++ = pcem_cook[i];
703
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");
708 sc->enabled = 0;
709 hidewin(sc);
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);
712 return (ENXIO);
713 }
714 }
715 device_printf(dev, "FEP/OS loaded, initializing");
716
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;
721 outb(sc->port, 0);
722
723 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
724 DELAY(10000);
725 if (i > 3000) {
726 printf("\nFEP/OS initialize failed(1)\n");
727 sc->enabled = 0;
728 hidewin(sc);
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);
731 return (ENXIO);
732 }
733 }
734
735 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
736 printf("\nFEP/OS initialize failed(2)\n");
737 sc->enabled = 0;
738 hidewin(sc);
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);
741 return (ENXIO);
742 }
743 printf(", FEP/OS running\n");
744
745 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
746 device_printf(dev, "%d ports attached\n", sc->numports);
747
748 if (sc->numports > MAX_DGM_PORTS) {
749 printf("dgm%d: too many ports\n", sc->unit);
750 sc->enabled = 0;
751 hidewin(sc);
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);
754 return (ENXIO);
755 }
756
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);
761
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;
765
766 /* We should now init per-port structures */
767 setwin(sc, 0);
768 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
769 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
770
771 if (sc->numports < 3)
772 shrinkmem = 1;
773 else
774 shrinkmem = 0;
775
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];
779 port->sc = sc;
780
781 port->tty = &sc->ttys[i];
782
783 port->brdchan = bc;
784
785 port->dcd = CD;
786 port->dsr = DSR;
787 port->pnum = i;
788
789 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
790 if (shrinkmem) {
791 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
792 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
793 shrinkmem = 0;
794 }
795
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);
801
802 port->txbufhead = 0;
803 port->rxbufhead = 0;
804 port->txbufsize = bc->tmax + 1;
805 port->rxbufsize = bc->rmax + 1;
806
807 lowwater = (port->txbufsize >= 2000) ?
808 1024 : (port->txbufsize / 2);
809
810 setwin(sc, 0);
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);
820
821 bc->edelay = 100;
822 bc->idata = 1;
823
824 port->startc = bc->startc;
825 port->startca = bc->startca;
826 port->stopc = bc->stopc;
827 port->stopca = bc->stopca;
828
829 /* port->close_delay = 50; */
830 port->close_delay = 3 * hz;
831 port->do_timestamp = 0;
832 port->do_dcd_timestamp = 0;
833
834 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
835 /*
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.
840 */
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;
848
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);
862 }
863
864 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
865
866 hidewin(sc);
867
868 /* start the polling function */
869 sc->toh = timeout(dgmpoll, (void *)(int)sc->unit, hz / POLLSPERSEC);
870
871 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
872
873 return (0);
874}
875
876static int
877dgmdetach(device_t dev)
878{
879 struct dgm_softc *sc = device_get_softc(dev);
880 int i;
881
882 for (i = 0; i < sc->numports; i++)
883 if (sc->ttys[i].t_state & TS_ISOPEN)
884 return (EBUSY);
885
886 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
887
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));
895 }
896
897 untimeout(dgmpoll, (void *)(int)sc->unit, sc->toh);
898 callout_handle_init(&sc->toh);
899
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);
902
903 FREE(sc->ports, M_TTYS);
904 FREE(sc->ttys, M_TTYS);
905
906 return (0);
907}
908
909int
910dgmshutdown(device_t dev)
911{
912#ifdef DEBUG
913 struct dgm_softc *sc = device_get_softc(dev);
914
915 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
916#endif
917
918 return 0;
919}
920
921/* ARGSUSED */
922static int
dadab5e9 923dgmopen(dev_t dev, int flag, int mode, struct thread *td)
984263bc
MD
924{
925 struct dgm_softc *sc;
926 struct tty *tp;
927 int unit;
928 int mynor;
929 int pnum;
930 struct dgm_p *port;
931 int s, cs;
932 int error;
933 volatile struct board_chan *bc;
934
935 error = 0;
936 mynor = minor(dev);
937 unit = MINOR_TO_UNIT(mynor);
938 pnum = MINOR_TO_PORT(mynor);
939
940 sc = devclass_get_softc(dgmdevclass, unit);
941 if (sc == NULL) {
942 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
943 unit);
944 return ENXIO;
945 }
946
947 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
948
949 if (!sc->enabled) {
950 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
951 unit);
952 return ENXIO;
953 }
954
955 if (pnum >= sc->numports) {
956 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
957 unit, pnum);
958 return ENXIO;
959 }
960
961 if (mynor & CONTROL_MASK)
962 return 0;
963
964 tp = &sc->ttys[pnum];
965 dev->si_tty = tp;
966 port = &sc->ports[pnum];
967 bc = port->brdchan;
968
969open_top:
970 s = spltty();
971
972 while (port->closing) {
973 error = tsleep(&port->closing, TTOPRI|PCATCH, "dgocl", 0);
974
975 if (error) {
976 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
977 " error = %d\n", unit, pnum, error);
978 goto out;
979 }
980 }
981
982 if (tp->t_state & TS_ISOPEN) {
983 /*
984 * The device is open, so everything has been initialized.
985 * Handle conflicts.
986 */
987 if (mynor & CALLOUT_MASK) {
988 if (!port->active_out) {
989 error = EBUSY;
990 DPRINT4(DB_OPEN, "dgm%d: port%d:"
991 " BUSY error = %d\n", unit, pnum, error);
992 goto out;
993 }
994 } else if (port->active_out) {
995 if (flag & O_NONBLOCK) {
996 error = EBUSY;
997 DPRINT4(DB_OPEN, "dgm%d: port%d:"
998 " BUSY error = %d\n", unit, pnum, error);
999 goto out;
1000 }
1001 error = tsleep(&port->active_out,
1002 TTIPRI | PCATCH, "dgmi", 0);
1003 if (error != 0) {
1004 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1005 " error = %d\n", unit, pnum, error);
1006 goto out;
1007 }
1008 splx(s);
1009 goto open_top;
1010 }
dadab5e9 1011 if (tp->t_state & TS_XCLUDE && suser(td)) {
984263bc
MD
1012 error = EBUSY;
1013 goto out;
1014 }
1015 } else {
1016 /*
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.
1021 */
1022 tp->t_oproc = dgmstart;
1023 tp->t_param = dgmparam;
1024 tp->t_stop = dgmstop;
1025 tp->t_dev = dev;
1026 tp->t_termios= (mynor & CALLOUT_MASK) ?
1027 port->it_out :
1028 port->it_in;
1029
1030 cs = splclock();
1031 setwin(sc, 0);
1032 port->imodem = bc->mstat;
1033 bc->rout = bc->rin; /* clear input queue */
1034 bc->idata = 1;
1035#ifdef PRINT_BUFSIZE
1036 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1037 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1038#endif
1039
1040 hidewin(sc);
1041 splx(cs);
1042
1043 port->wopeners++;
1044 error = dgmparam(tp, &tp->t_termios);
1045 port->wopeners--;
1046
1047 if (error != 0) {
1048 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1049 unit, pnum, error);
1050 goto out;
1051 }
1052
1053 /* handle fake DCD for callout devices */
1054 /* and initial DCD */
1055
1056 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1057 linesw[tp->t_line].l_modem(tp, 1);
1058 }
1059
1060 /*
1061 * Wait for DCD if necessary.
1062 */
1063 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1064 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1065 ++port->wopeners;
1066 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "dgdcd", 0);
1067 --port->wopeners;
1068 if (error != 0) {
1069 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1070 " error = %d\n", unit, pnum, error);
1071 goto out;
1072 }
1073 splx(s);
1074 goto open_top;
1075 }
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",
1079 unit, pnum, error);
1080
1081 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1082 port->active_out = 1;
1083
1084 port->used = 1;
1085
1086 /* If any port is open (i.e. the open() call is completed for it)
1087 * the device is busy
1088 */
1089
1090out:
1091 disc_optim(tp, &tp->t_termios);
1092 splx(s);
1093
1094 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1095 dgmhardclose(port);
1096
1097 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1098 unit, pnum, error);
1099
1100 return error;
1101}
1102
1103/*ARGSUSED*/
1104static int
dadab5e9 1105dgmclose(dev_t dev, int flag, int mode, struct thread *td)
984263bc
MD
1106{
1107 int mynor;
1108 struct tty *tp;
1109 int unit, pnum;
1110 struct dgm_softc *sc;
1111 struct dgm_p *port;
1112 int s;
1113 int i;
1114
1115 mynor = minor(dev);
1116 if (mynor & CONTROL_MASK)
1117 return 0;
1118 unit = MINOR_TO_UNIT(mynor);
1119 pnum = MINOR_TO_PORT(mynor);
1120
1121 sc = devclass_get_softc(dgmdevclass, unit);
1122 tp = &sc->ttys[pnum];
1123 port = sc->ports + pnum;
1124
1125 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1126
1127 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1128 dgm_drain_or_flush(port);
1129
1130 s = spltty();
1131
1132 port->closing = 1;
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);
1136
1137 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1138 dgmhardclose(port);
1139 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1140 ttyclose(tp);
1141 port->closing = 0;
1142 wakeup(&port->closing);
1143 port->used = 0;
1144
1145 /* mark the card idle when all ports are closed */
1146
1147 for (i = 0; i < sc->numports; i++)
1148 if (sc->ports[i].used)
1149 break;
1150
1151 splx(s);
1152
1153 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1154
1155 wakeup(TSA_CARR_ON(tp));
1156 wakeup(&port->active_out);
1157 port->active_out = 0;
1158
1159 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1160
1161 return 0;
1162}
1163
1164static void
1165dgmhardclose(struct dgm_p *port)
1166{
1167 volatile struct board_chan *bc = port->brdchan;
1168 struct dgm_softc *sc;
1169 int cs;
1170
1171 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1172 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1173 cs = splclock();
1174 port->do_timestamp = 0;
1175 setwin(sc, 0);
1176
1177 bc->idata = 0;
1178 bc->iempty = 0;
1179 bc->ilow = 0;
1180 if (port->tty->t_cflag & HUPCL) {
1181 port->omodem &= ~(RTS|DTR);
1182 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1183 }
1184
1185 hidewin(sc);
1186 splx(cs);
1187
1188 timeout(dgm_pause, &port->brdchan, hz/2);
1189 tsleep(&port->brdchan, TTIPRI | PCATCH, "dgclo", 0);
1190}
1191
1192static void
1193dgm_pause(void *chan)
1194{
1195 wakeup((caddr_t)chan);
1196}
1197
1198static void
1199dgmpoll(void *unit_c)
1200{
1201 int unit = (int)unit_c;
1202 int pnum;
1203 struct dgm_p *port;
1204 struct dgm_softc *sc;
1205 int head, tail;
1206 u_char *eventbuf;
1207 int event, mstat, lstat;
1208 volatile struct board_chan *bc;
1209 struct tty *tp;
1210 int rhead, rtail;
1211 int whead, wtail;
1212 int size;
1213 u_char *ptr;
1214 int ocount;
1215 int ibuf_full, obuf_full;
1216 BoardMemWinState ws = bmws_get();
1217
1218 sc = devclass_get_softc(dgmdevclass, unit);
1219 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1220 callout_handle_init(&sc->toh);
1221
1222 if (!sc->enabled) {
1223 printf("dgm%d: polling of disabled board stopped\n", unit);
1224 return;
1225 }
1226
1227 setwin(sc, 0);
1228
1229 head = sc->mailbox->ein;
1230 tail = sc->mailbox->eout;
1231
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);
1238 break;
1239 }
1240
1241 eventbuf = sc->vmem + tail + FEP_ISTART;
1242 pnum = eventbuf[0];
1243 event = eventbuf[1];
1244 mstat = eventbuf[2];
1245 lstat = eventbuf[3];
1246
1247 port = &sc->ports[pnum];
1248 bc = port->brdchan;
1249 tp = &sc->ttys[pnum];
1250
1251 if (pnum >= sc->numports || !port->enabled) {
1252 printf("dgm%d: port%d: got event on nonexisting port\n",
1253 unit, pnum);
1254 } else if (port->used || port->wopeners > 0 ) {
1255
1256 int wrapmask = port->rxbufsize - 1;
1257
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);
1261
1262 if (event & DATA_IND) {
1263 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1264 unit, pnum);
1265
1266 rhead = bc->rin & wrapmask;
1267 rtail = bc->rout & wrapmask;
1268
1269 if (!(tp->t_cflag & CREAD) || !port->used ) {
1270 bc->rout = rhead;
1271 goto end_of_data;
1272 }
1273
1274 if (bc->orun) {
1275 printf("dgm%d: port%d: overrun\n", unit, pnum);
1276 bc->orun = 0;
1277 }
1278
1279 if (!(tp->t_state & TS_ISOPEN))
1280 goto end_of_data;
1281
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);
1286
1287 if (rhead > rtail)
1288 size = rhead - rtail;
1289 else
1290 size = port->rxbufsize - rtail;
1291
1292 ptr = port->rxptr + rtail;
1293
1294/* Helg: */
1295 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1296 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1297 DPRINT1(DB_RXDATA, "*");
1298 ibuf_full = TRUE;
1299 }
1300
1301 if (size) {
1302 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1303 DPRINT1(DB_RXDATA, "!");
1304 towin(sc, port->rxwin);
1305 tk_nin += size;
1306 tk_rawcc += size;
1307 tp->t_rawcc += size;
1308 b_to_q(ptr, size,
1309 &tp->t_rawq);
1310 setwin(sc, 0);
1311 } else {
1312 int i = size;
1313 unsigned char chr;
1314 do {
1315 towin(sc, port->rxwin);
1316 chr = *ptr++;
1317 hidewin(sc);
1318 (*linesw[tp->t_line].l_rint)(chr, tp);
1319 } while (--i > 0 );
1320 setwin(sc, 0);
1321 }
1322 }
1323 rtail= (rtail + size) & wrapmask;
1324 bc->rout = rtail;
1325 rhead = bc->rin & wrapmask;
1326 hidewin(sc);
1327 ttwakeup(tp);
1328 setwin(sc, 0);
1329 }
1330 end_of_data: ;
1331 }
1332
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) {
1338 hidewin(sc);
1339 linesw[tp->t_line].l_modem(tp, 1);
1340 setwin(sc, 0);
1341 wakeup(TSA_CARR_ON(tp));
1342 } else {
1343 hidewin(sc);
1344 linesw[tp->t_line].l_modem(tp, 0);
1345 setwin(sc, 0);
1346 if (port->draining) {
1347 port->draining = 0;
1348 wakeup(&port->draining);
1349 }
1350 }
1351 }
1352
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);
1357 hidewin(sc);
1358 linesw[tp->t_line].l_rint(TTY_BI, tp);
1359 setwin(sc, 0);
1360 }
1361 }
1362
1363/* Helg: with output flow control */
1364
1365 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1366 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1367 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1368
1369 if ((event & EMPTYTX_IND ) &&
1370 tp->t_outq.c_cc == 0 && port->draining) {
1371 port->draining = 0;
1372 wakeup(&port->draining);
1373 bc->ilow = 0;
1374 bc->iempty = 0;
1375 } else {
1376
1377 int wrapmask = port->txbufsize - 1;
1378
1379 for (obuf_full = FALSE;
1380 tp->t_outq.c_cc != 0 && !obuf_full;
1381 ) {
1382 int s;
1383 /* add "last-minute" data to write buffer */
1384 if (!(tp->t_state & TS_BUSY)) {
1385 hidewin(sc);
1386#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1387 ttwwakeup(tp);
1388#else
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));
1393 }
1394 /* selwakeup(&tp->t_wsel); */
1395 }
1396#endif
1397 setwin(sc, 0);
1398 }
1399 s = spltty();
1400
1401 whead = bc->tin & wrapmask;
1402 wtail = bc->tout & wrapmask;
1403
1404 if (whead < wtail)
1405 size = wtail - whead - 1;
1406 else {
1407 size = port->txbufsize - whead;
1408 if (wtail == 0)
1409 size--;
1410 }
1411
1412 if (size == 0) {
1413 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1414 whead, wtail, size, obuf_full);
1415 bc->iempty = 1;
1416 bc->ilow = 1;
1417 obuf_full = TRUE;
1418 splx(s);
1419 break;
1420 }
1421
1422 towin(sc, port->txwin);
1423
1424 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1425 whead += ocount;
1426
1427 setwin(sc, 0);
1428 bc->tin = whead;
1429 bc->tin = whead & wrapmask;
1430 splx(s);
1431 }
1432
1433 if (obuf_full) {
1434 DPRINT1(DB_WR, " +BUSY\n");
1435 tp->t_state |= TS_BUSY;
1436 } else {
1437 DPRINT1(DB_WR, " -BUSY\n");
1438 hidewin(sc);
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);
1444 ttwwakeup(tp);
1445 }
1446#else
1447 if (tp->t_state & TS_ASLEEP) {
1448 tp->t_state &= ~TS_ASLEEP;
1449 wakeup(TSA_OLOWAT(tp));
1450 }
1451 tp->t_state &= ~TS_BUSY;
1452#endif
1453 setwin(sc, 0);
1454 }
1455 }
1456 }
1457 bc->idata = 1; /* require event on incoming data */
1458
1459 } else {
1460 bc = port->brdchan;
1461 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1462 unit, pnum, event);
1463 bc->rout = bc->rin;
1464 bc->idata = bc->iempty = bc->ilow = 0;
1465 }
1466
1467 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1468 }
1469
1470 sc->mailbox->eout = tail;
1471 bmws_set(ws);
1472
1473 sc->toh = timeout(dgmpoll, unit_c, hz / POLLSPERSEC);
1474
1475 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1476}
1477
1478static int
dadab5e9 1479dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
984263bc
MD
1480{
1481 struct dgm_softc *sc;
1482 int unit, pnum;
1483 struct dgm_p *port;
1484 int mynor;
1485 struct tty *tp;
1486 volatile struct board_chan *bc;
1487 int error;
1488 int s, cs;
1489 int tiocm_xxx;
1490
1491#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1492 u_long oldcmd;
1493 struct termios term;
1494#endif
1495
1496 BoardMemWinState ws = bmws_get();
1497
1498 mynor = minor(dev);
1499 unit = MINOR_TO_UNIT(mynor);
1500 pnum = MINOR_TO_PORT(mynor);
1501
1502 sc = devclass_get_softc(dgmdevclass, unit);
1503 port = &sc->ports[pnum];
1504 tp = &sc->ttys[pnum];
1505 bc = port->brdchan;
1506
1507 if (mynor & CONTROL_MASK) {
1508 struct termios *ct;
1509
1510 switch (mynor & CONTROL_MASK) {
1511 case CONTROL_INIT_STATE:
1512 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1513 break;
1514 case CONTROL_LOCK_STATE:
1515 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1516 break;
1517 default:
1518 return (ENODEV); /* /dev/nodev */
1519 }
1520 switch (cmd) {
1521 case TIOCSETA:
dadab5e9 1522 error = suser(td);
984263bc
MD
1523 if (error != 0)
1524 return (error);
1525 *ct = *(struct termios *)data;
1526 return (0);
1527 case TIOCGETA:
1528 *(struct termios *)data = *ct;
1529 return (0);
1530 case TIOCGETD:
1531 *(int *)data = TTYDISC;
1532 return (0);
1533 case TIOCGWINSZ:
1534 bzero(data, sizeof(struct winsize));
1535 return (0);
1536 default:
1537 return (ENOTTY);
1538 }
1539 }
1540
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);
1545 }
1546 oldcmd = cmd;
1547 error = ttsetcompat(tp, &cmd, data, &term);
1548 if (error != 0)
1549 return (error);
1550 if (cmd != oldcmd)
1551 data = (caddr_t)&term;
1552#endif
1553
1554 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1555 int cc;
1556 struct termios *dt = (struct termios *)data;
1557 struct termios *lt = mynor & CALLOUT_MASK
1558 ? &port->lt_out : &port->lt_in;
1559
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;
1576 }
1577
1578 if (cmd == TIOCSTOP) {
1579 cs = splclock();
1580 setwin(sc, 0);
1581 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1582 bmws_set(ws);
1583 splx(cs);
1584 return 0;
1585 } else if (cmd == TIOCSTART) {
1586 cs = splclock();
1587 setwin(sc, 0);
1588 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1589 bmws_set(ws);
1590 splx(cs);
1591 return 0;
1592 }
1593
1594 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1595 port->mustdrain = 1;
1596
1597 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p);
1598 if (error != ENOIOCTL)
1599 return error;
1600 s = spltty();
1601 error = ttioctl(tp, cmd, data, flag);
1602 disc_optim(tp, &tp->t_termios);
1603 port->mustdrain = 0;
1604 if (error != ENOIOCTL) {
1605 splx(s);
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);
1608 }
1609 return error;
1610 }
1611
1612 switch (cmd) {
1613 case TIOCSBRK:
1614#if 0
1615 error = dgmdrain(port);
1616
1617 if (error != 0) {
1618 splx(s);
1619 return error;
1620 }
1621#endif
1622
1623 cs = splclock();
1624 setwin(sc, 0);
1625
1626 /* now it sends 400 millisecond break because I don't know */
1627 /* how to send an infinite break */
1628
1629 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1630 hidewin(sc);
1631 splx(cs);
1632 break;
1633 case TIOCCBRK:
1634 /* now it's empty */
1635 break;
1636 case TIOCSDTR:
1637 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1638 port->omodem |= DTR;
1639 cs = splclock();
1640 setwin(sc, 0);
1641 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1642
1643 if (!(bc->mstat & DTR))
1644 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1645
1646 hidewin(sc);
1647 splx(cs);
1648 break;
1649 case TIOCCDTR:
1650 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1651 port->omodem &= ~DTR;
1652 cs = splclock();
1653 setwin(sc, 0);
1654 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1655
1656 if (bc->mstat & DTR) {
1657 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1658 }
1659
1660 hidewin(sc);
1661 splx(cs);
1662 break;
1663 case TIOCMSET:
1664 if (*(int *)data & TIOCM_DTR)
1665 port->omodem |= DTR;
1666 else
1667 port->omodem &= ~DTR;
1668
1669 if (*(int *)data & TIOCM_RTS)
1670 port->omodem |= RTS;
1671 else
1672 port->omodem &= ~RTS;
1673
1674 cs = splclock();
1675 setwin(sc, 0);
1676 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1677 hidewin(sc);
1678 splx(cs);
1679 break;
1680 case TIOCMBIS:
1681 if (*(int *)data & TIOCM_DTR)
1682 port->omodem |= DTR;
1683
1684 if (*(int *)data & TIOCM_RTS)
1685 port->omodem |= RTS;
1686
1687 cs = splclock();
1688 setwin(sc, 0);
1689 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1690 hidewin(sc);
1691 splx(cs);
1692 break;
1693 case TIOCMBIC:
1694 if (*(int *)data & TIOCM_DTR)
1695 port->omodem &= ~DTR;
1696
1697 if (*(int *)data & TIOCM_RTS)
1698 port->omodem &= ~RTS;
1699
1700 cs = splclock();
1701 setwin(sc, 0);
1702 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1703 hidewin(sc);
1704 splx(cs);
1705 break;
1706 case TIOCMGET:
1707 setwin(sc, 0);
1708 port->imodem = bc->mstat;
1709 hidewin(sc);
1710
1711 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1712
1713 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1714
1715 if (port->imodem & DTR) {
1716 DPRINT1(DB_MODEM, "DTR ");
1717 tiocm_xxx |= TIOCM_DTR;
1718 }
1719 if (port->imodem & RTS) {
1720 DPRINT1(DB_MODEM, "RTS ");
1721 tiocm_xxx |= TIOCM_RTS;
1722 }
1723 if (port->imodem & CTS) {
1724 DPRINT1(DB_MODEM, "CTS ");
1725 tiocm_xxx |= TIOCM_CTS;
1726 }
1727 if (port->imodem & port->dcd) {
1728 DPRINT1(DB_MODEM, "DCD ");
1729 tiocm_xxx |= TIOCM_CD;
1730 }
1731 if (port->imodem & port->dsr) {
1732 DPRINT1(DB_MODEM, "DSR ");
1733 tiocm_xxx |= TIOCM_DSR;
1734 }
1735 if (port->imodem & RI) {
1736 DPRINT1(DB_MODEM, "RI ");
1737 tiocm_xxx |= TIOCM_RI;
1738 }
1739 *(int *)data = tiocm_xxx;
1740 DPRINT1(DB_MODEM, "--\n");
1741 break;
1742 case TIOCMSDTRWAIT:
1743 /* must be root since the wait applies to following logins */
dadab5e9 1744 error = suser(td);
984263bc
MD
1745 if (error != 0) {
1746 splx(s);
1747 return (error);
1748 }
1749 port->close_delay = *(int *)data * hz / 100;
1750 break;
1751 case TIOCMGDTRWAIT:
1752 *(int *)data = port->close_delay * 100 / hz;
1753 break;
1754 case TIOCTIMESTAMP:
1755 port->do_timestamp = 1;
1756 *(struct timeval *)data = port->timestamp;
1757 break;
1758 case TIOCDCDTIMESTAMP:
1759 port->do_dcd_timestamp = 1;
1760 *(struct timeval *)data = port->dcd_timestamp;
1761 break;
1762 default:
1763 bmws_set(ws);
1764 splx(s);
1765 return ENOTTY;
1766 }
1767 bmws_set(ws);
1768 splx(s);
1769
1770 return 0;
1771}
1772
1773static void
1774wakeflush(void *p)
1775{
1776 struct dgm_p *port = p;
1777
1778 wakeup(&port->draining);
1779}
1780
1781/* wait for the output to drain */
1782
1783static int
1784dgmdrain(struct dgm_p *port)
1785{
1786 volatile struct board_chan *bc = port->brdchan;
1787 struct dgm_softc *sc;
1788 int error;
1789 int head, tail;
1790 BoardMemWinState ws = bmws_get();
1791
1792 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1793
1794 setwin(sc, 0);
1795
1796 bc->iempty = 1;
1797 tail = bc->tout;
1798 head = bc->tin;
1799
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);
1803
1804 hidewin(sc);
1805 port->draining = 1;
1806 timeout(wakeflush, port, hz);
1807 error = tsleep(&port->draining, TTIPRI | PCATCH, "dgdrn", 0);
1808 port->draining = 0;
1809 setwin(sc, 0);
1810
1811 if (error != 0) {
1812 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1813 port->sc->unit, port->pnum, error);
1814
1815 bc->iempty = 0;
1816 bmws_set(ws);
1817 return error;
1818 }
1819
1820 tail = bc->tout;
1821 head = bc->tin;
1822 }
1823 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1824 port->sc->unit, port->pnum, head, tail);
1825 bmws_set(ws);
1826 return 0;
1827}
1828
1829/* wait for the output to drain */
1830/* or simply clear the buffer it it's stopped */
1831
1832static void
1833dgm_drain_or_flush(struct dgm_p *port)
1834{
1835 volatile struct board_chan *bc = port->brdchan;
1836 struct tty *tp = port->tty;
1837 struct dgm_softc *sc;
1838 int error;
1839 int lasttail;
1840 int head, tail;
1841
1842 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1843 setwin(sc, 0);
1844
1845 lasttail = -1;
1846 bc->iempty = 1;
1847 tail = bc->tout;
1848 head = bc->tin;
1849
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);
1853
1854 /* if there is no carrier simply clean the buffer */
1855 if (!(tp->t_state & TS_CARR_ON)) {
1856 bc->tout = bc->tin = 0;
1857 bc->iempty = 0;
1858 hidewin(sc);
1859 return;
1860 }
1861
1862 hidewin(sc);
1863 port->draining = 1;
1864 timeout(wakeflush, port, hz);
1865 error = tsleep(&port->draining, TTIPRI | PCATCH, "dgfls", 0);
1866 port->draining = 0;
1867 setwin(sc, 0);
1868
1869 if (error != 0) {
1870 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1871 " error = %d\n", port->sc->unit, port->pnum, error);
1872
1873 /* silently clean the buffer */
1874
1875 bc->tout = bc->tin = 0;
1876 bc->iempty = 0;
1877 hidewin(sc);
1878 return;
1879 }
1880
1881 lasttail = tail;
1882 tail = bc->tout;
1883 head = bc->tin;
1884 }
1885 hidewin(sc);
1886 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1887 port->sc->unit, port->pnum, head, tail);
1888}
1889
1890static int
1891dgmparam(struct tty *tp, struct termios *t)
1892{
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;
1897 struct dgm_p *port;
1898 int cflag;
1899 int head;
1900 int mval;
1901 int iflag;
1902 int hflow;
1903 int cs;
1904 BoardMemWinState ws = bmws_get();
1905
1906 sc = devclass_get_softc(dgmdevclass, unit);
1907 port = &sc->ports[pnum];
1908 bc = port->brdchan;
1909
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);
1911
1912 if (port->mustdrain) {
1913 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1914 dgmdrain(port);
1915 }
1916
1917 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1918
1919 if (t->c_ispeed == 0)
1920 t->c_ispeed = t->c_ospeed;
1921
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);
1924 return (EINVAL);
1925 }
1926
1927 cs = splclock();
1928 setwin(sc, 0);
1929
1930 if (cflag == 0) { /* hangup */
1931 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1932 head = bc->rin;
1933 bc->rout = head;
1934 head = bc->tin;
1935 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1936 mval= port->omodem & ~(DTR|RTS);
1937 } else {
1938 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1939
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);
1945 }
1946 mval= port->omodem | (DTR|RTS);
1947 }
1948
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);
1954 }
1955
1956 bc->mint = port->dcd;
1957
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);
1963 }
1964
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);
1970 }
1971
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);
1978 }
1979
1980 bmws_set(ws);
1981 splx(cs);
1982
1983 return 0;
1984
1985}
1986
1987static void
1988dgmstart(struct tty *tp)
1989{
1990 int unit;
1991 int pnum;
1992 struct dgm_p *port;
1993 struct dgm_softc *sc;
1994 volatile struct board_chan *bc;
1995 int head, tail;
1996 int size, ocount;
1997 int s;
1998 int wmask;
1999
2000 BoardMemWinState ws = bmws_get();
2001
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];
2006 bc = port->brdchan;
2007
2008 wmask = port->txbufsize - 1;
2009
2010 s = spltty();
2011
2012 while (tp->t_outq.c_cc != 0) {
2013 int cs;
2014#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2015 ttwwakeup(tp);
2016#else
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));
2021 }
2022 /*selwakeup(&tp->t_wsel);*/
2023 }
2024#endif
2025 cs = splclock();
2026 setwin(sc, 0);
2027
2028 head = bc->tin & wmask;
2029
2030 do { tail = bc->tout; } while (tail != bc->tout);
2031 tail = bc->tout & wmask;
2032
2033 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2034
2035#ifdef LEAVE_FREE_CHARS
2036 if (tail > head) {
2037 size = tail - head - LEAVE_FREE_CHARS;
2038 if (size < 0)
2039 size = 0;
2040 else {
2041 size = port->txbufsize - head;
2042 if (tail + port->txbufsize < head)
2043 size = 0;
2044 }
2045 }
2046#else
2047 if (tail > head)
2048 size = tail - head - 1;
2049 else {
2050 size = port->txbufsize - head;
2051 if (tail == 0)
2052 size--;
2053 }
2054#endif
2055
2056 if (size == 0) {
2057 bc->iempty = 1;
2058 bc->ilow = 1;
2059 splx(cs);
2060 bmws_set(ws);
2061 tp->t_state |= TS_BUSY;
2062 splx(s);
2063 return;
2064 }
2065
2066 towin(sc, port->txwin);
2067
2068 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2069 head += ocount;
2070 if (head >= port->txbufsize)
2071 head -= port->txbufsize;
2072
2073 setwin(sc, 0);
2074 bc->tin = head;
2075
2076 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2077 unit, pnum, size, ocount);
2078 hidewin(sc);
2079 splx(cs);
2080 }
2081
2082 bmws_set(ws);
2083 splx(s);
2084
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);
2089 ttwwakeup(tp);
2090 }
2091#else
2092 if (tp->t_state & TS_ASLEEP) {
2093 tp->t_state &= ~TS_ASLEEP;
2094 wakeup(TSA_OLOWAT(tp));
2095 }
2096 tp->t_state& = ~TS_BUSY;
2097#endif
2098}
2099
2100void
2101dgmstop(struct tty *tp, int rw)
2102{
2103 int unit;
2104 int pnum;
2105 struct dgm_p *port;
2106 struct dgm_softc *sc;
2107 volatile struct board_chan *bc;
2108 int s;
2109
2110 BoardMemWinState ws = bmws_get();
2111
2112 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2113 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2114
2115 sc = devclass_get_softc(dgmdevclass, unit);
2116 port = &sc->ports[pnum];
2117 bc = port->brdchan;
2118
2119 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2120
2121 s = spltty();
2122 setwin(sc, 0);
2123
2124 if (rw & FWRITE) {
2125 /* clear output queue */
2126 bc->tout = bc->tin = 0;
2127 bc->ilow = 0;
2128 bc->iempty = 0;
2129 }
2130 if (rw & FREAD) {
2131 /* clear input queue */
2132 bc->rout = bc->rin;
2133 bc->idata = 1;
2134 }
2135 hidewin(sc);
2136 bmws_set(ws);
2137 splx(s);
2138 dgmstart(tp);
2139}
2140
2141static void
2142fepcmd(struct dgm_p *port,
2143 unsigned cmd,
2144 unsigned op1,
2145 unsigned op2,
2146 unsigned ncmds,
2147 unsigned bytecmd)
2148{
2149 u_char *mem;
2150 unsigned tail, head;
2151 int count, n;
2152
2153 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2154 mem = port->sc->vmem;
2155
2156 if (!port->enabled) {
2157 printf("dgm%d: port%d: FEP command on disabled port\n",
2158 port->sc->unit, port->pnum);
2159 return;
2160 }
2161
2162 /* setwin(port->sc, 0); Require this to be set by caller */
2163 head = port->sc->mailbox->cin;
2164
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);
2168 return;
2169 }
2170
2171 mem[head + FEP_CSTART] = cmd;
2172 mem[head + FEP_CSTART + 1] = port->pnum;
2173 if (bytecmd) {
2174 mem[head + FEP_CSTART + 2] = op1;
2175 mem[head + FEP_CSTART + 3] = op2;
2176 } else {
2177 mem[head + FEP_CSTART + 2] = op1 & 0xff;
2178 mem[head + FEP_CSTART + 3] = (op1 >> 8) & 0xff;
2179 }
2180
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]);
2183
2184 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2185 port->sc->mailbox->cin = head;
2186
2187 count = FEPTIMEOUT;
2188
2189 while (count-- != 0) {
2190 head = port->sc->mailbox->cin;
2191 tail = port->sc->mailbox->cout;
2192
2193 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2194 if (n <= ncmds * (sizeof(ushort)*4))
2195 return;
2196 }
2197 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2198}
2199
2200static void
2201disc_optim(struct tty *tp, struct termios *t)
2202{
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;
2210 else
2211 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2212}