LINT build test. Aggregated source code adjustments to bring most of the
[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 $
7b95be2a 3 * $DragonFly: src/sys/dev/serial/dgb/dgm.c,v 1.6 2003/07/21 07:57:40 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 = {
fabb8ceb
MD
238 /* name */ "dgm",
239 /* maj */ CDEV_MAJOR,
240 /* flags */ D_TTY | D_KQFILTER,
241 /* port */ NULL,
242 /* autoq */ 0,
243
984263bc
MD
244 /* open */ dgmopen,
245 /* close */ dgmclose,
246 /* read */ ttyread,
247 /* write */ ttywrite,
248 /* ioctl */ dgmioctl,
249 /* poll */ ttypoll,
250 /* mmap */ nommap,
251 /* strategy */ nostrategy,
984263bc
MD
252 /* dump */ nodump,
253 /* psize */ nopsize,
fabb8ceb 254 /* kqfilter */ ttykqfilter
984263bc
MD
255};
256
257static int
258dgmmodhandler(module_t mod, int event, void *arg)
259{
260 int res = 0;
261
262 switch (event) {
263 case MOD_LOAD:
264 cdevsw_add(&dgm_cdevsw);
265 break;
266
267 case MOD_UNLOAD:
268 cdevsw_remove(&dgm_cdevsw);
269 break;
270 }
271
272 return res;
273}
274
275DRIVER_MODULE(dgm, isa, dgmdriver, dgmdevclass, dgmmodhandler, 0);
276
277static speed_t dgmdefaultrate = TTYDEF_SPEED;
278
279static struct speedtab dgmspeedtab[] = {
280 { 0, FEP_B0 }, /* old (sysV-like) Bx codes */
281 { 50, FEP_B50 },
282 { 75, FEP_B75 },
283 { 110, FEP_B110 },
284 { 134, FEP_B134 },
285 { 150, FEP_B150 },
286 { 200, FEP_B200 },
287 { 300, FEP_B300 },
288 { 600, FEP_B600 },
289 { 1200, FEP_B1200 },
290 { 1800, FEP_B1800 },
291 { 2400, FEP_B2400 },
292 { 4800, FEP_B4800 },
293 { 9600, FEP_B9600 },
294 { 19200, FEP_B19200 },
295 { 38400, FEP_B38400 },
296 { 57600, (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
297 { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
298 { -1, -1 }
299};
300
301static struct dbgflagtbl {
302 tcflag_t in_mask;
303 tcflag_t in_val;
304 tcflag_t out_val;
305} dgm_cflags[] = {
306 { PARODD, PARODD, FEP_PARODD },
307 { PARENB, PARENB, FEP_PARENB },
308 { CSTOPB, CSTOPB, FEP_CSTOPB },
309 { CSIZE, CS5, FEP_CS6 },
310 { CSIZE, CS6, FEP_CS6 },
311 { CSIZE, CS7, FEP_CS7 },
312 { CSIZE, CS8, FEP_CS8 },
313 { CLOCAL, CLOCAL, FEP_CLOCAL },
314 { (tcflag_t)-1 }
315}, dgm_iflags[] = {
316 { IGNBRK, IGNBRK, FEP_IGNBRK },
317 { BRKINT, BRKINT, FEP_BRKINT },
318 { IGNPAR, IGNPAR, FEP_IGNPAR },
319 { PARMRK, PARMRK, FEP_PARMRK },
320 { INPCK, INPCK, FEP_INPCK },
321 { ISTRIP, ISTRIP, FEP_ISTRIP },
322 { IXON, IXON, FEP_IXON },
323 { IXOFF, IXOFF, FEP_IXOFF },
324 { IXANY, IXANY, FEP_IXANY },
325 { (tcflag_t)-1 }
326}, dgm_flow[] = {
327 { CRTSCTS, CRTSCTS, CTS|RTS },
328 { CRTSCTS, CCTS_OFLOW, CTS },
329 { CRTSCTS, CRTS_IFLOW, RTS },
330 { (tcflag_t)-1 }
331};
332
333/* xlat bsd termios flags to dgm sys-v style */
334static tcflag_t
335dgmflags(struct dbgflagtbl *tbl, tcflag_t input)
336{
337 tcflag_t output = 0;
338 int i;
339
340 for (i = 0; tbl[i].in_mask != (tcflag_t)-1; i++)
341 if ((input & tbl[i].in_mask) == tbl[i].in_val)
342 output |= tbl[i].out_val;
343
344 return output;
345}
346
347static int dgmdebug = 0;
348SYSCTL_INT(_debug, OID_AUTO, dgm_debug, CTLFLAG_RW, &dgmdebug, 0, "");
349
350static __inline int setwin(struct dgm_softc *, unsigned);
351static __inline void hidewin(struct dgm_softc *);
352static __inline void towin(struct dgm_softc *, int);
353
354/*Helg: to allow recursive dgm...() calls */
355typedef struct {
356 /* If we were called and don't want to disturb we need: */
357 int port; /* write to this port */
358 u_char data; /* this data on exit */
359 /* or DATA_WINOFF to close memory window on entry */
360} BoardMemWinState; /* so several channels and even boards can coexist */
361
362#define DATA_WINOFF 0
363static BoardMemWinState bmws;
364
365static u_long validio[] = { 0x104, 0x114, 0x124, 0x204, 0x224, 0x304, 0x324 };
366static u_long validmem[] = {
367 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
368 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
369 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
370 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
371 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
372};
373
374/* return current memory window state and close window */
375static BoardMemWinState
376bmws_get(void)
377{
378 BoardMemWinState bmwsRet = bmws;
379
380 if (bmws.data != DATA_WINOFF)
381 outb(bmws.port, bmws.data = DATA_WINOFF);
382 return bmwsRet;
383}
384
385/* restore memory window state */
386static void
387bmws_set(BoardMemWinState ws)
388{
389 if (ws.data != bmws.data || ws.port != bmws.port) {
390 if (bmws.data != DATA_WINOFF)
391 outb(bmws.port, DATA_WINOFF);
392 if (ws.data != DATA_WINOFF)
393 outb(ws.port, ws.data);
394 bmws = ws;
395 }
396}
397
398static __inline int
399setwin(struct dgm_softc *sc, unsigned int addr)
400{
401 outb(bmws.port = sc->port + 1, bmws.data = FEPWIN|(addr >> 15));
402 return (addr & 0x7FFF);
403}
404
405static __inline void
406hidewin(struct dgm_softc *sc)
407{
408 bmws.data = 0;
409 outb(bmws.port = sc->port + 1, bmws.data);
410}
411
412static __inline void
413towin(struct dgm_softc *sc, int win)
414{
415 outb(bmws.port = sc->port + 1, bmws.data = win);
416}
417
418static int
419dgmprobe(device_t dev)
420{
421 struct dgm_softc *sc = device_get_softc(dev);
422 int i, v;
423
424 sc->unit = device_get_unit(dev);
425
426 /* Check that we've got a valid i/o address */
427 if ((sc->port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
428 return (ENXIO);
429 for (i = sizeof (validio) / sizeof (validio[0]) - 1; i >= 0; i--)
430 if (sc->port == validio[i])
431 break;
432 if (i == -1) {
433 device_printf(dev, "0x%03lx: Invalid i/o address\n", sc->port);
434 return (ENXIO);
435 }
436
437 /* Ditto for our memory address */
438 if ((sc->pmem = bus_get_resource_start(dev, SYS_RES_MEMORY, 0)) == 0)
439 return (ENXIO);
440 for (i = sizeof (validmem) / sizeof (validmem[0]) - 1; i >= 0; i--)
441 if (sc->pmem == validmem[i])
442 break;
443 if (i == -1) {
444 device_printf(dev, "0x%lx: Invalid memory address\n", sc->pmem);
445 return (ENXIO);
446 }
447 if ((sc->pmem & 0xFFFFFFul) != sc->pmem) {
448 device_printf(dev, "0x%lx: Memory address not supported\n",
449 sc->pmem);
450 return (ENXIO);
451 }
452 sc->vmem = (u_char *)sc->pmem;
453
454 DPRINT4(DB_INFO, "dgm%d: port 0x%lx mem 0x%lx\n", sc->unit,
455 sc->port, sc->pmem);
456
457 /* Temporarily map our io ports */
458 sc->iorid = 0;
459 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
460 0ul, ~0ul, IO_SIZE, RF_ACTIVE);
461 if (sc->io_res == NULL)
462 return (ENXIO);
463
464 outb(sc->port, FEPRST);
465 sc->enabled = 0;
466
467 for (i = 0; i < 1000; i++) {
468 DELAY(1);
469 if ((inb(sc->port) & FEPMASK) == FEPRST) {
470 sc->enabled = 1;
471 DPRINT3(DB_EXCEPT, "dgm%d: got reset after %d us\n",
472 sc->unit, i);
473 break;
474 }
475 }
476
477 if (!sc->enabled) {
478 DPRINT2(DB_EXCEPT, "dgm%d: failed to respond\n", sc->unit);
479 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
480 return (ENXIO);
481 }
482
483 /* check type of card and get internal memory characteristics */
484
485 v = inb(sc->port);
486
487 if (!(v & 0x1)) {
488 int second;
489
490 outb(sc->port, 1);
491 second = inb(sc->port);
492 printf("dgm%d: PC/Xem (type %d, %d)\n", sc->unit, v, second);
493 } else
494 printf("dgm%d: PC/Xem (type %d)\n", sc->unit, v);
495
496 sc->type = PCXEM;
497 sc->mem_seg = 0x8000;
498
499 /* Temporarily map our memory too */
500 sc->mrid = 0;
501 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
502 0ul, ~0ul, MEM_SIZE, RF_ALLOCATED);
503 if (sc->mem_res == NULL) {
504 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
505 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
506 return (ENXIO);
507 }
508
509 outb(sc->port, FEPCLR); /* drop RESET */
510 hidewin(sc); /* Helg: to set initial bmws state */
511
512 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
513 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
514
515 bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port, IO_SIZE);
516 bus_set_resource(dev, SYS_RES_MEMORY, 0, sc->pmem, MEM_SIZE);
517
518 DPRINT2(DB_INFO, "dgm%d: Probe returns 0\n", sc->unit);
519
520 return (0);
521}
522
523static int
524dgmattach(device_t dev)
525{
526 struct dgm_softc *sc = device_get_softc(dev);
527 int i, t;
528 u_char *mem;
529 u_char *ptr;
530 int addr;
531 struct dgm_p *port;
532 volatile struct board_chan *bc;
533 int shrinkmem;
534 int lowwater;
535 u_long msize, iosize;
536
537 DPRINT2(DB_INFO, "dbg%d: attaching\n", device_get_unit(dev));
538
539 sc->unit = device_get_unit(dev);
540 bus_get_resource(dev, SYS_RES_IOPORT, 0, &sc->port, &iosize);
541 bus_get_resource(dev, SYS_RES_MEMORY, 0, &sc->pmem, &msize);
542 sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN);
543 sc->type = PCXEM;
544 sc->mem_seg = 0x8000;
545 sc->enabled = 1;
546 sc->type = PCXEM;
547 sc->mem_seg = 0x8000;
548
549 /* Allocate resources (should have been verified in dgmprobe()) */
550 sc->iorid = 0;
551 sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid,
552 0ul, ~0ul, iosize, RF_ACTIVE);
553 if (sc->io_res == NULL)
554 return (ENXIO);
555 sc->mrid = 0;
556 sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mrid,
557 0ul, ~0ul, msize, RF_ACTIVE);
558 if (sc->mem_res == NULL) {
559 device_printf(dev, "0x%lx: Memory range is in use\n", sc->pmem);
560 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
561 return (ENXIO);
562 }
563
564 /* map memory */
565 mem = sc->vmem = pmap_mapdev(sc->pmem, msize);
566
567 DPRINT3(DB_INFO, "dgm%d: internal memory segment 0x%x\n", sc->unit,
568 sc->mem_seg);
569
570 outb(sc->port, FEPRST);
571 DELAY(1);
572
573 for (i = 0; (inb(sc->port) & FEPMASK) != FEPRST; i++) {
574 if (i > 10000) {
575 device_printf(dev, "1st reset failed\n");
576 sc->enabled = 0;
577 hidewin(sc);
578 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
579 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
580 return (ENXIO);
581 }
582 DELAY(1);
583 }
584
585 DPRINT3(DB_INFO, "dgm%d: got reset after %d us\n", sc->unit, i);
586
587 t = sc->pmem >> 8; /* disable windowing */
588 outb(sc->port + 2, t & 0xFF);
589 outb(sc->port + 3, t >> 8);
590
591 mem = sc->vmem;
592
593 /* very short memory test */
594 DPRINT2(DB_INFO, "dbg%d: short memory test\n", sc->unit);
595
596 addr = setwin(sc, BOTWIN);
597 *(u_long *)(mem + addr) = 0xA55A3CC3;
598 if (*(u_long *)(mem + addr) != 0xA55A3CC3) {
599 device_printf(dev, "1st memory test failed\n");
600 sc->enabled = 0;
601 hidewin(sc);
602 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
603 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
604 return (ENXIO);
605 }
606
607 DPRINT2(DB_INFO, "dbg%d: 1st memory test ok\n", sc->unit);
608
609 addr = setwin(sc, TOPWIN);
610 *(u_long *)(mem + addr) = 0x5AA5C33C;
611 if (*(u_long *)(mem + addr) != 0x5AA5C33C) {
612 device_printf(dev, "2nd memory test failed\n");
613 sc->enabled = 0;
614 hidewin(sc);
615 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
616 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
617 return (ENXIO);
618 }
619
620 DPRINT2(DB_INFO, "dbg%d: 2nd memory test ok\n", sc->unit);
621
622 addr = setwin(sc, BIOSCODE + ((0xF000 - sc->mem_seg) << 4));
623 *(u_long *)(mem + addr) = 0x5AA5C33C;
624 if (*(u_long *)(mem + addr) != 0x5AA5C33C)
625 device_printf(dev, "3rd (BIOS) memory test failed\n");
626
627 DPRINT2(DB_INFO, "dbg%d: 3rd memory test ok\n", sc->unit);
628
629 addr = setwin(sc, MISCGLOBAL);
630 for (i = 0; i < 16; i++)
631 mem[addr + i] = 0;
632
633 addr = setwin(sc, BIOSOFFSET);
634 ptr = mem + addr;
635 for (i = 0; ptr < mem + msize; i++)
636 *ptr++ = pcem_bios[i];
637
638 ptr = mem + BIOSOFFSET;
639 for (i = 0; ptr < mem + msize; i++) {
640 if (*ptr++ != pcem_bios[i]) {
641 printf("Low BIOS load failed\n");
642 sc->enabled = 0;
643 hidewin(sc);
644 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
645 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
646 return (ENXIO);
647 }
648 }
649 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 1 loaded\n", sc->unit);
650
651 addr = setwin(sc, msize);
652 ptr = mem + addr;
653 for (;i < pcem_nbios; i++)
654 *ptr++ = pcem_bios[i];
655
656 ptr = mem;
657 for (i = msize - BIOSOFFSET; i < pcem_nbios; i++) {
658 if (*ptr++ != pcem_bios[i]) {
659 printf("High BIOS load failed\n");
660 sc->enabled = 0;
661 hidewin(sc);
662 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
663 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
664 return (ENXIO);
665 }
666 }
667 DPRINT2(DB_INFO, "dbg%d: pcem_bios seg 2 loaded\n", sc->unit);
668 device_printf(dev, "DigiBIOS loaded, initializing");
669
670 addr = setwin(sc, 0);
671
672 *(u_int *)(mem + addr) = 0x0bf00401;
673 *(u_int *)(mem + addr + 4) = 0;
674 *(ushort *)(mem + addr + 0xc00) = 0;
675 outb(sc->port, 0);
676
677 for (i = 0; *(u_char *)(mem + addr + 0xc00) != 0x47; i++) {
678 DELAY(10000);
679 if (i > 3000) {
680 printf("\nBIOS initialize failed(1)\n");
681 sc->enabled = 0;
682 hidewin(sc);
683 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
684 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
685 return (ENXIO);
686 }
687 }
688
689 if (*(u_char *)(mem + addr + 0xc01) != 0x44) {
690 printf("\nBIOS initialize failed(2)\n");
691 sc->enabled = 0;
692 hidewin(sc);
693 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
694 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
695 return (ENXIO);
696 }
697 printf(", DigiBIOS running\n");
698
699 DELAY(10000);
700
701 addr = setwin(sc, BIOSOFFSET);
702 ptr = mem + addr;
703 for (i = 0; i < pcem_ncook; i++)
704 *ptr++ = pcem_cook[i];
705
706 ptr = mem + BIOSOFFSET;
707 for (i = 0; i < pcem_ncook; i++) {
708 if (*ptr++ != pcem_cook[i]) {
709 printf("FEP/OS load failed\n");
710 sc->enabled = 0;
711 hidewin(sc);
712 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
713 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
714 return (ENXIO);
715 }
716 }
717 device_printf(dev, "FEP/OS loaded, initializing");
718
719 addr = setwin(sc, 0);
720 *(ushort *)(mem + addr + 0xd20) = 0;
721 *(u_int *)(mem + addr + 0xc34) = 0xbfc01004;
722 *(u_int *)(mem + addr + 0xc30) = 0x3L;
723 outb(sc->port, 0);
724
725 for (i = 0; *(u_char *)(mem + addr + 0xd20) != 'O'; i++) {
726 DELAY(10000);
727 if (i > 3000) {
728 printf("\nFEP/OS initialize failed(1)\n");
729 sc->enabled = 0;
730 hidewin(sc);
731 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
732 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
733 return (ENXIO);
734 }
735 }
736
737 if (*(u_char *)(mem + addr + 0xd21) != 'S') {
738 printf("\nFEP/OS initialize failed(2)\n");
739 sc->enabled = 0;
740 hidewin(sc);
741 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
742 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
743 return (ENXIO);
744 }
745 printf(", FEP/OS running\n");
746
747 sc->numports = *(ushort *)(mem + setwin(sc, NPORT));
748 device_printf(dev, "%d ports attached\n", sc->numports);
749
750 if (sc->numports > MAX_DGM_PORTS) {
751 printf("dgm%d: too many ports\n", sc->unit);
752 sc->enabled = 0;
753 hidewin(sc);
754 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
755 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
756 return (ENXIO);
757 }
758
759 MALLOC(sc->ports, struct dgm_p *, sizeof (*sc->ports) * sc->numports,
760 M_TTYS, M_WAITOK|M_ZERO);
761 MALLOC(sc->ttys, struct tty *, sizeof (*sc->ttys) * sc->numports,
762 M_TTYS, M_WAITOK|M_ZERO);
763
764 DPRINT3(DB_INFO, "dgm%d: enable %d ports\n", sc->unit, sc->numports);
765 for (i = 0; i < sc->numports; i++)
766 sc->ports[i].enabled = 1;
767
768 /* We should now init per-port structures */
769 setwin(sc, 0);
770 bc = (volatile struct board_chan *)(mem + CHANSTRUCT);
771 sc->mailbox = (volatile struct global_data *)(mem + FEP_GLOBAL);
772
773 if (sc->numports < 3)
774 shrinkmem = 1;
775 else
776 shrinkmem = 0;
777
778 for (i = 0; i < sc->numports; i++, bc++) {
779 DPRINT3(DB_INFO, "dgm%d: Set up port %d\n", sc->unit, i);
780 port = &sc->ports[i];
781 port->sc = sc;
782
783 port->tty = &sc->ttys[i];
784
785 port->brdchan = bc;
786
787 port->dcd = CD;
788 port->dsr = DSR;
789 port->pnum = i;
790
791 DPRINT3(DB_INFO, "dgm%d port %d: shrinkmem ?\n", sc->unit, i);
792 if (shrinkmem) {
793 DPRINT2(DB_INFO, "dgm%d: shrinking memory\n", sc->unit);
794 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
795 shrinkmem = 0;
796 }
797
798 DPRINT3(DB_INFO, "dgm%d port %d: assign ptrs\n", sc->unit, i);
799 port->txptr = mem + ((bc->tseg << 4) & 0x7FFF);
800 port->rxptr = mem + ((bc->rseg << 4) & 0x7FFF);
801 port->txwin = FEPWIN | (bc->tseg >> 11);
802 port->rxwin = FEPWIN | (bc->rseg >> 11);
803
804 port->txbufhead = 0;
805 port->rxbufhead = 0;
806 port->txbufsize = bc->tmax + 1;
807 port->rxbufsize = bc->rmax + 1;
808
809 lowwater = (port->txbufsize >= 2000) ?
810 1024 : (port->txbufsize / 2);
811
812 setwin(sc, 0);
813 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd STXLWATER %d\n",
814 sc->unit, i, lowwater);
815 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
816 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXLWATER %d\n",
817 sc->unit, i, port->rxbufsize / 4);
818 fepcmd(port, SRXLWATER, port->rxbufsize / 4, 0, 10, 0);
819 DPRINT4(DB_INFO, "dgm%d port %d: fepcmd SRXHWATER %d\n",
820 sc->unit, i, 3 * port->rxbufsize / 4);
821 fepcmd(port, SRXHWATER, 3 * port->rxbufsize / 4, 0, 10, 0);
822
823 bc->edelay = 100;
824 bc->idata = 1;
825
826 port->startc = bc->startc;
827 port->startca = bc->startca;
828 port->stopc = bc->stopc;
829 port->stopca = bc->stopca;
830
831 /* port->close_delay = 50; */
832 port->close_delay = 3 * hz;
833 port->do_timestamp = 0;
834 port->do_dcd_timestamp = 0;
835
836 DPRINT3(DB_INFO, "dgm%d port %d: setup flags\n", sc->unit, i);
837 /*
838 * We don't use all the flags from <sys/ttydefaults.h> since
839 * they are only relevant for logins. It's important to have
840 * echo off initially so that the line doesn't start
841 * blathering before the echo flag can be turned off.
842 */
843 port->it_in.c_iflag = TTYDEF_IFLAG;
844 port->it_in.c_oflag = TTYDEF_OFLAG;
845 port->it_in.c_cflag = TTYDEF_CFLAG;
846 port->it_in.c_lflag = TTYDEF_LFLAG;
847 termioschars(&port->it_in);
848 port->it_in.c_ispeed = port->it_in.c_ospeed = dgmdefaultrate;
849 port->it_out = port->it_in;
850
851 DPRINT3(DB_INFO, "dgm%d port %d: make devices\n", sc->unit, i);
852 make_dev(&dgm_cdevsw, (sc->unit*65536) + i, UID_ROOT,
853 GID_WHEEL, 0600, "ttyM%d%x", sc->unit, i + 0xa0);
854 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 64, UID_ROOT,
855 GID_WHEEL, 0600, "ttyiM%d%x", sc->unit, i + 0xa0);
856 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 128, UID_ROOT,
857 GID_WHEEL, 0600, "ttylM%d%x", sc->unit, i + 0xa0);
858 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262144, UID_UUCP,
859 GID_DIALER, 0660, "cuaM%d%x", sc->unit, i + 0xa0);
860 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262208, UID_UUCP,
861 GID_DIALER, 0660, "cuaiM%d%x", sc->unit, i + 0xa0);
862 make_dev(&dgm_cdevsw, sc->unit * 65536 + i + 262272, UID_UUCP,
863 GID_DIALER, 0660, "cualM%d%x", sc->unit, i + 0xa0);
864 }
865
866 DPRINT3(DB_INFO, "dgm%d: %d device nodes created\n", sc->unit, sc->numports);
867
868 hidewin(sc);
869
870 /* start the polling function */
871 sc->toh = timeout(dgmpoll, (void *)(int)sc->unit, hz / POLLSPERSEC);
872
873 DPRINT2(DB_INFO, "dgm%d: poll thread started\n", sc->unit);
874
875 return (0);
876}
877
878static int
879dgmdetach(device_t dev)
880{
881 struct dgm_softc *sc = device_get_softc(dev);
882 int i;
883
884 for (i = 0; i < sc->numports; i++)
885 if (sc->ttys[i].t_state & TS_ISOPEN)
886 return (EBUSY);
887
888 DPRINT2(DB_INFO, "dgm%d: detach\n", sc->unit);
889
890 for (i = 0; i < sc->numports; i++) {
891 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i));
892 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 64));
893 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 128));
894 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262144));
895 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262208));
896 destroy_dev(makedev(CDEV_MAJOR, sc->unit * 65536 + i + 262272));
897 }
898
899 untimeout(dgmpoll, (void *)(int)sc->unit, sc->toh);
900 callout_handle_init(&sc->toh);
901
902 bus_release_resource(dev, SYS_RES_MEMORY, sc->mrid, sc->mem_res);
903 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->io_res);
904
905 FREE(sc->ports, M_TTYS);
906 FREE(sc->ttys, M_TTYS);
907
908 return (0);
909}
910
911int
912dgmshutdown(device_t dev)
913{
914#ifdef DEBUG
915 struct dgm_softc *sc = device_get_softc(dev);
916
917 DPRINT2(DB_INFO, "dgm%d: shutdown\n", sc->unit);
918#endif
919
920 return 0;
921}
922
923/* ARGSUSED */
924static int
dadab5e9 925dgmopen(dev_t dev, int flag, int mode, struct thread *td)
984263bc
MD
926{
927 struct dgm_softc *sc;
928 struct tty *tp;
929 int unit;
930 int mynor;
931 int pnum;
932 struct dgm_p *port;
933 int s, cs;
934 int error;
935 volatile struct board_chan *bc;
936
937 error = 0;
938 mynor = minor(dev);
939 unit = MINOR_TO_UNIT(mynor);
940 pnum = MINOR_TO_PORT(mynor);
941
942 sc = devclass_get_softc(dgmdevclass, unit);
943 if (sc == NULL) {
944 DPRINT2(DB_EXCEPT, "dgm%d: try to open a nonexisting card\n",
945 unit);
946 return ENXIO;
947 }
948
949 DPRINT2(DB_INFO, "dgm%d: open\n", sc->unit);
950
951 if (!sc->enabled) {
952 DPRINT2(DB_EXCEPT, "dgm%d: try to open a disabled card\n",
953 unit);
954 return ENXIO;
955 }
956
957 if (pnum >= sc->numports) {
958 DPRINT3(DB_EXCEPT, "dgm%d: try to open non-existing port %d\n",
959 unit, pnum);
960 return ENXIO;
961 }
962
963 if (mynor & CONTROL_MASK)
964 return 0;
965
966 tp = &sc->ttys[pnum];
967 dev->si_tty = tp;
968 port = &sc->ports[pnum];
969 bc = port->brdchan;
970
971open_top:
972 s = spltty();
973
974 while (port->closing) {
377d4740 975 error = tsleep(&port->closing, PCATCH, "dgocl", 0);
984263bc
MD
976
977 if (error) {
978 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgocl)"
979 " error = %d\n", unit, pnum, error);
980 goto out;
981 }
982 }
983
984 if (tp->t_state & TS_ISOPEN) {
985 /*
986 * The device is open, so everything has been initialized.
987 * Handle conflicts.
988 */
989 if (mynor & CALLOUT_MASK) {
990 if (!port->active_out) {
991 error = EBUSY;
992 DPRINT4(DB_OPEN, "dgm%d: port%d:"
993 " BUSY error = %d\n", unit, pnum, error);
994 goto out;
995 }
996 } else if (port->active_out) {
997 if (flag & O_NONBLOCK) {
998 error = EBUSY;
999 DPRINT4(DB_OPEN, "dgm%d: port%d:"
1000 " BUSY error = %d\n", unit, pnum, error);
1001 goto out;
1002 }
377d4740 1003 error = tsleep(&port->active_out, PCATCH, "dgmi", 0);
984263bc
MD
1004 if (error != 0) {
1005 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgmi)"
1006 " error = %d\n", unit, pnum, error);
1007 goto out;
1008 }
1009 splx(s);
1010 goto open_top;
1011 }
dadab5e9 1012 if (tp->t_state & TS_XCLUDE && suser(td)) {
984263bc
MD
1013 error = EBUSY;
1014 goto out;
1015 }
1016 } else {
1017 /*
1018 * The device isn't open, so there are no conflicts.
1019 * Initialize it. Initialization is done twice in many
1020 * cases: to preempt sleeping callin opens if we are
1021 * callout, and to complete a callin open after DCD rises.
1022 */
1023 tp->t_oproc = dgmstart;
1024 tp->t_param = dgmparam;
1025 tp->t_stop = dgmstop;
1026 tp->t_dev = dev;
1027 tp->t_termios= (mynor & CALLOUT_MASK) ?
1028 port->it_out :
1029 port->it_in;
1030
1031 cs = splclock();
1032 setwin(sc, 0);
1033 port->imodem = bc->mstat;
1034 bc->rout = bc->rin; /* clear input queue */
1035 bc->idata = 1;
1036#ifdef PRINT_BUFSIZE
1037 printf("dgm buffers tx = %x:%x rx = %x:%x\n",
1038 bc->tseg, bc->tmax, bc->rseg, bc->rmax);
1039#endif
1040
1041 hidewin(sc);
1042 splx(cs);
1043
1044 port->wopeners++;
1045 error = dgmparam(tp, &tp->t_termios);
1046 port->wopeners--;
1047
1048 if (error != 0) {
1049 DPRINT4(DB_OPEN, "dgm%d: port%d: dgmparam error = %d\n",
1050 unit, pnum, error);
1051 goto out;
1052 }
1053
1054 /* handle fake DCD for callout devices */
1055 /* and initial DCD */
1056
1057 if ((port->imodem & port->dcd) || mynor & CALLOUT_MASK)
1058 linesw[tp->t_line].l_modem(tp, 1);
1059 }
1060
1061 /*
1062 * Wait for DCD if necessary.
1063 */
1064 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1065 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1066 ++port->wopeners;
377d4740 1067 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
984263bc
MD
1068 --port->wopeners;
1069 if (error != 0) {
1070 DPRINT4(DB_OPEN, "dgm%d: port%d: tsleep(dgdcd)"
1071 " error = %d\n", unit, pnum, error);
1072 goto out;
1073 }
1074 splx(s);
1075 goto open_top;
1076 }
1077 error = linesw[tp->t_line].l_open(dev, tp);
1078 disc_optim(tp, &tp->t_termios);
1079 DPRINT4(DB_OPEN, "dgm%d: port%d: l_open error = %d\n",
1080 unit, pnum, error);
1081
1082 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1083 port->active_out = 1;
1084
1085 port->used = 1;
1086
1087 /* If any port is open (i.e. the open() call is completed for it)
1088 * the device is busy
1089 */
1090
1091out:
1092 disc_optim(tp, &tp->t_termios);
1093 splx(s);
1094
1095 if (!(tp->t_state & TS_ISOPEN) && port->wopeners == 0)
1096 dgmhardclose(port);
1097
1098 DPRINT4(DB_OPEN, "dgm%d: port%d: open() returns %d\n",
1099 unit, pnum, error);
1100
1101 return error;
1102}
1103
1104/*ARGSUSED*/
1105static int
dadab5e9 1106dgmclose(dev_t dev, int flag, int mode, struct thread *td)
984263bc
MD
1107{
1108 int mynor;
1109 struct tty *tp;
1110 int unit, pnum;
1111 struct dgm_softc *sc;
1112 struct dgm_p *port;
1113 int s;
1114 int i;
1115
1116 mynor = minor(dev);
1117 if (mynor & CONTROL_MASK)
1118 return 0;
1119 unit = MINOR_TO_UNIT(mynor);
1120 pnum = MINOR_TO_PORT(mynor);
1121
1122 sc = devclass_get_softc(dgmdevclass, unit);
1123 tp = &sc->ttys[pnum];
1124 port = sc->ports + pnum;
1125
1126 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing\n", unit, pnum);
1127
1128 DPRINT3(DB_CLOSE, "dgm%d: port%d: draining port\n", unit, pnum);
1129 dgm_drain_or_flush(port);
1130
1131 s = spltty();
1132
1133 port->closing = 1;
1134 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing line disc\n", unit, pnum);
1135 linesw[tp->t_line].l_close(tp, flag);
1136 disc_optim(tp, &tp->t_termios);
1137
1138 DPRINT3(DB_CLOSE, "dgm%d: port%d: hard closing\n", unit, pnum);
1139 dgmhardclose(port);
1140 DPRINT3(DB_CLOSE, "dgm%d: port%d: closing tty\n", unit, pnum);
1141 ttyclose(tp);
1142 port->closing = 0;
1143 wakeup(&port->closing);
1144 port->used = 0;
1145
1146 /* mark the card idle when all ports are closed */
1147
1148 for (i = 0; i < sc->numports; i++)
1149 if (sc->ports[i].used)
1150 break;
1151
1152 splx(s);
1153
1154 DPRINT3(DB_CLOSE, "dgm%d: port%d: closed\n", unit, pnum);
1155
1156 wakeup(TSA_CARR_ON(tp));
1157 wakeup(&port->active_out);
1158 port->active_out = 0;
1159
1160 DPRINT3(DB_CLOSE, "dgm%d: port%d: close exit\n", unit, pnum);
1161
1162 return 0;
1163}
1164
1165static void
1166dgmhardclose(struct dgm_p *port)
1167{
1168 volatile struct board_chan *bc = port->brdchan;
1169 struct dgm_softc *sc;
1170 int cs;
1171
1172 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1173 DPRINT2(DB_INFO, "dgm%d: dgmhardclose\n", sc->unit);
1174 cs = splclock();
1175 port->do_timestamp = 0;
1176 setwin(sc, 0);
1177
1178 bc->idata = 0;
1179 bc->iempty = 0;
1180 bc->ilow = 0;
1181 if (port->tty->t_cflag & HUPCL) {
1182 port->omodem &= ~(RTS|DTR);
1183 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1184 }
1185
1186 hidewin(sc);
1187 splx(cs);
1188
1189 timeout(dgm_pause, &port->brdchan, hz/2);
377d4740 1190 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
984263bc
MD
1191}
1192
1193static void
1194dgm_pause(void *chan)
1195{
1196 wakeup((caddr_t)chan);
1197}
1198
1199static void
1200dgmpoll(void *unit_c)
1201{
1202 int unit = (int)unit_c;
1203 int pnum;
1204 struct dgm_p *port;
1205 struct dgm_softc *sc;
1206 int head, tail;
1207 u_char *eventbuf;
1208 int event, mstat, lstat;
1209 volatile struct board_chan *bc;
1210 struct tty *tp;
1211 int rhead, rtail;
1212 int whead, wtail;
1213 int size;
1214 u_char *ptr;
1215 int ocount;
1216 int ibuf_full, obuf_full;
1217 BoardMemWinState ws = bmws_get();
1218
1219 sc = devclass_get_softc(dgmdevclass, unit);
1220 DPRINT2(DB_INFO, "dgm%d: poll\n", sc->unit);
1221 callout_handle_init(&sc->toh);
1222
1223 if (!sc->enabled) {
1224 printf("dgm%d: polling of disabled board stopped\n", unit);
1225 return;
1226 }
1227
1228 setwin(sc, 0);
1229
1230 head = sc->mailbox->ein;
1231 tail = sc->mailbox->eout;
1232
1233 while (head != tail) {
1234 if (head >= FEP_IMAX - FEP_ISTART
1235 || tail >= FEP_IMAX - FEP_ISTART
1236 || (head|tail) & 03 ) {
1237 printf("dgm%d: event queue's head or tail is wrong!"
1238 " hd = %d, tl = %d\n", unit, head, tail);
1239 break;
1240 }
1241
1242 eventbuf = sc->vmem + tail + FEP_ISTART;
1243 pnum = eventbuf[0];
1244 event = eventbuf[1];
1245 mstat = eventbuf[2];
1246 lstat = eventbuf[3];
1247
1248 port = &sc->ports[pnum];
1249 bc = port->brdchan;
1250 tp = &sc->ttys[pnum];
1251
1252 if (pnum >= sc->numports || !port->enabled) {
1253 printf("dgm%d: port%d: got event on nonexisting port\n",
1254 unit, pnum);
1255 } else if (port->used || port->wopeners > 0 ) {
1256
1257 int wrapmask = port->rxbufsize - 1;
1258
1259 if (!(event & ALL_IND))
1260 printf("dgm%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1261 unit, pnum, event, mstat, lstat);
1262
1263 if (event & DATA_IND) {
1264 DPRINT3(DB_DATA, "dgm%d: port%d: DATA_IND\n",
1265 unit, pnum);
1266
1267 rhead = bc->rin & wrapmask;
1268 rtail = bc->rout & wrapmask;
1269
1270 if (!(tp->t_cflag & CREAD) || !port->used ) {
1271 bc->rout = rhead;
1272 goto end_of_data;
1273 }
1274
1275 if (bc->orun) {
1276 printf("dgm%d: port%d: overrun\n", unit, pnum);
1277 bc->orun = 0;
1278 }
1279
1280 if (!(tp->t_state & TS_ISOPEN))
1281 goto end_of_data;
1282
1283 for (ibuf_full = FALSE; rhead != rtail && !ibuf_full;) {
1284 DPRINT5(DB_RXDATA, "dgm%d: port%d:"
1285 " p rx head = %d tail = %d\n", unit,
1286 pnum, rhead, rtail);
1287
1288 if (rhead > rtail)
1289 size = rhead - rtail;
1290 else
1291 size = port->rxbufsize - rtail;
1292
1293 ptr = port->rxptr + rtail;
1294
1295/* Helg: */
1296 if (tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1297 size = DGB_IBUFSIZE - tp->t_rawq.c_cc;
1298 DPRINT1(DB_RXDATA, "*");
1299 ibuf_full = TRUE;
1300 }
1301
1302 if (size) {
1303 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1304 DPRINT1(DB_RXDATA, "!");
1305 towin(sc, port->rxwin);
1306 tk_nin += size;
1307 tk_rawcc += size;
1308 tp->t_rawcc += size;
1309 b_to_q(ptr, size,
1310 &tp->t_rawq);
1311 setwin(sc, 0);
1312 } else {
1313 int i = size;
1314 unsigned char chr;
1315 do {
1316 towin(sc, port->rxwin);
1317 chr = *ptr++;
1318 hidewin(sc);
1319 (*linesw[tp->t_line].l_rint)(chr, tp);
1320 } while (--i > 0 );
1321 setwin(sc, 0);
1322 }
1323 }
1324 rtail= (rtail + size) & wrapmask;
1325 bc->rout = rtail;
1326 rhead = bc->rin & wrapmask;
1327 hidewin(sc);
1328 ttwakeup(tp);
1329 setwin(sc, 0);
1330 }
1331 end_of_data: ;
1332 }
1333
1334 if (event & MODEMCHG_IND) {
1335 DPRINT3(DB_MODEM, "dgm%d: port%d: "
1336 "MODEMCHG_IND\n", unit, pnum);
1337 port->imodem = mstat;
1338 if (mstat & port->dcd) {
1339 hidewin(sc);
1340 linesw[tp->t_line].l_modem(tp, 1);
1341 setwin(sc, 0);
1342 wakeup(TSA_CARR_ON(tp));
1343 } else {
1344 hidewin(sc);
1345 linesw[tp->t_line].l_modem(tp, 0);
1346 setwin(sc, 0);
1347 if (port->draining) {
1348 port->draining = 0;
1349 wakeup(&port->draining);
1350 }
1351 }
1352 }
1353
1354 if (event & BREAK_IND) {
1355 if ((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1356 DPRINT3(DB_BREAK, "dgm%d: port%d:"
1357 " BREAK_IND\n", unit, pnum);
1358 hidewin(sc);
1359 linesw[tp->t_line].l_rint(TTY_BI, tp);
1360 setwin(sc, 0);
1361 }
1362 }
1363
1364/* Helg: with output flow control */
1365
1366 if (event & (LOWTX_IND | EMPTYTX_IND) ) {
1367 DPRINT3(DB_TXDATA, "dgm%d: port%d:"
1368 " LOWTX_IND or EMPTYTX_IND\n", unit, pnum);
1369
1370 if ((event & EMPTYTX_IND ) &&
1371 tp->t_outq.c_cc == 0 && port->draining) {
1372 port->draining = 0;
1373 wakeup(&port->draining);
1374 bc->ilow = 0;
1375 bc->iempty = 0;
1376 } else {
1377
1378 int wrapmask = port->txbufsize - 1;
1379
1380 for (obuf_full = FALSE;
1381 tp->t_outq.c_cc != 0 && !obuf_full;
1382 ) {
1383 int s;
1384 /* add "last-minute" data to write buffer */
1385 if (!(tp->t_state & TS_BUSY)) {
1386 hidewin(sc);
1387#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1388 ttwwakeup(tp);
1389#else
1390 if (tp->t_outq.c_cc <= tp->t_lowat) {
1391 if (tp->t_state & TS_ASLEEP) {
1392 tp->t_state &= ~TS_ASLEEP;
1393 wakeup(TSA_OLOWAT(tp));
1394 }
1395 /* selwakeup(&tp->t_wsel); */
1396 }
1397#endif
1398 setwin(sc, 0);
1399 }
1400 s = spltty();
1401
1402 whead = bc->tin & wrapmask;
1403 wtail = bc->tout & wrapmask;
1404
1405 if (whead < wtail)
1406 size = wtail - whead - 1;
1407 else {
1408 size = port->txbufsize - whead;
1409 if (wtail == 0)
1410 size--;
1411 }
1412
1413 if (size == 0) {
1414 DPRINT5(DB_WR, "dgm: head = %d tail = %d size = %d full = %d\n",
1415 whead, wtail, size, obuf_full);
1416 bc->iempty = 1;
1417 bc->ilow = 1;
1418 obuf_full = TRUE;
1419 splx(s);
1420 break;
1421 }
1422
1423 towin(sc, port->txwin);
1424
1425 ocount = q_to_b(&tp->t_outq, port->txptr + whead, size);
1426 whead += ocount;
1427
1428 setwin(sc, 0);
1429 bc->tin = whead;
1430 bc->tin = whead & wrapmask;
1431 splx(s);
1432 }
1433
1434 if (obuf_full) {
1435 DPRINT1(DB_WR, " +BUSY\n");
1436 tp->t_state |= TS_BUSY;
1437 } else {
1438 DPRINT1(DB_WR, " -BUSY\n");
1439 hidewin(sc);
1440#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1441 /* should clear TS_BUSY before ttwwakeup */
1442 if (tp->t_state & TS_BUSY) {
1443 tp->t_state &= ~TS_BUSY;
1444 linesw[tp->t_line].l_start(tp);
1445 ttwwakeup(tp);
1446 }
1447#else
1448 if (tp->t_state & TS_ASLEEP) {
1449 tp->t_state &= ~TS_ASLEEP;
1450 wakeup(TSA_OLOWAT(tp));
1451 }
1452 tp->t_state &= ~TS_BUSY;
1453#endif
1454 setwin(sc, 0);
1455 }
1456 }
1457 }
1458 bc->idata = 1; /* require event on incoming data */
1459
1460 } else {
1461 bc = port->brdchan;
1462 DPRINT4(DB_EXCEPT, "dgm%d: port%d: got event 0x%x on closed port\n",
1463 unit, pnum, event);
1464 bc->rout = bc->rin;
1465 bc->idata = bc->iempty = bc->ilow = 0;
1466 }
1467
1468 tail = (tail + 4) & (FEP_IMAX - FEP_ISTART - 4);
1469 }
1470
1471 sc->mailbox->eout = tail;
1472 bmws_set(ws);
1473
1474 sc->toh = timeout(dgmpoll, unit_c, hz / POLLSPERSEC);
1475
1476 DPRINT2(DB_INFO, "dgm%d: poll done\n", sc->unit);
1477}
1478
1479static int
dadab5e9 1480dgmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
984263bc
MD
1481{
1482 struct dgm_softc *sc;
1483 int unit, pnum;
1484 struct dgm_p *port;
1485 int mynor;
1486 struct tty *tp;
1487 volatile struct board_chan *bc;
1488 int error;
1489 int s, cs;
1490 int tiocm_xxx;
1491
1492#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1493 u_long oldcmd;
1494 struct termios term;
1495#endif
1496
1497 BoardMemWinState ws = bmws_get();
1498
1499 mynor = minor(dev);
1500 unit = MINOR_TO_UNIT(mynor);
1501 pnum = MINOR_TO_PORT(mynor);
1502
1503 sc = devclass_get_softc(dgmdevclass, unit);
1504 port = &sc->ports[pnum];
1505 tp = &sc->ttys[pnum];
1506 bc = port->brdchan;
1507
1508 if (mynor & CONTROL_MASK) {
1509 struct termios *ct;
1510
1511 switch (mynor & CONTROL_MASK) {
1512 case CONTROL_INIT_STATE:
1513 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1514 break;
1515 case CONTROL_LOCK_STATE:
1516 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1517 break;
1518 default:
1519 return (ENODEV); /* /dev/nodev */
1520 }
1521 switch (cmd) {
1522 case TIOCSETA:
dadab5e9 1523 error = suser(td);
984263bc
MD
1524 if (error != 0)
1525 return (error);
1526 *ct = *(struct termios *)data;
1527 return (0);
1528 case TIOCGETA:
1529 *(struct termios *)data = *ct;
1530 return (0);
1531 case TIOCGETD:
1532 *(int *)data = TTYDISC;
1533 return (0);
1534 case TIOCGWINSZ:
1535 bzero(data, sizeof(struct winsize));
1536 return (0);
1537 default:
1538 return (ENOTTY);
1539 }
1540 }
1541
1542#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1543 term = tp->t_termios;
1544 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1545 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-ISNOW c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, term.c_cflag, term.c_iflag, term.c_lflag);
1546 }
1547 oldcmd = cmd;
1548 error = ttsetcompat(tp, &cmd, data, &term);
1549 if (error != 0)
1550 return (error);
1551 if (cmd != oldcmd)
1552 data = (caddr_t)&term;
1553#endif
1554
1555 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1556 int cc;
1557 struct termios *dt = (struct termios *)data;
1558 struct termios *lt = mynor & CALLOUT_MASK
1559 ? &port->lt_out : &port->lt_in;
1560
1561 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-TOSET c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, dt->c_cflag, dt->c_iflag, dt->c_lflag);
1562 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1563 | (dt->c_iflag & ~lt->c_iflag);
1564 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1565 | (dt->c_oflag & ~lt->c_oflag);
1566 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1567 | (dt->c_cflag & ~lt->c_cflag);
1568 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1569 | (dt->c_lflag & ~lt->c_lflag);
1570 for (cc = 0; cc < NCCS; ++cc)
1571 if (lt->c_cc[cc] != 0)
1572 dt->c_cc[cc] = tp->t_cc[cc];
1573 if (lt->c_ispeed != 0)
1574 dt->c_ispeed = tp->t_ispeed;
1575 if (lt->c_ospeed != 0)
1576 dt->c_ospeed = tp->t_ospeed;
1577 }
1578
1579 if (cmd == TIOCSTOP) {
1580 cs = splclock();
1581 setwin(sc, 0);
1582 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1583 bmws_set(ws);
1584 splx(cs);
1585 return 0;
1586 } else if (cmd == TIOCSTART) {
1587 cs = splclock();
1588 setwin(sc, 0);
1589 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1590 bmws_set(ws);
1591 splx(cs);
1592 return 0;
1593 }
1594
1595 if (cmd == TIOCSETAW || cmd == TIOCSETAF)
1596 port->mustdrain = 1;
1597
7b95be2a 1598 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
984263bc
MD
1599 if (error != ENOIOCTL)
1600 return error;
1601 s = spltty();
1602 error = ttioctl(tp, cmd, data, flag);
1603 disc_optim(tp, &tp->t_termios);
1604 port->mustdrain = 0;
1605 if (error != ENOIOCTL) {
1606 splx(s);
1607 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1608 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmioctl-RES c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, tp->t_cflag, tp->t_iflag, tp->t_lflag);
1609 }
1610 return error;
1611 }
1612
1613 switch (cmd) {
1614 case TIOCSBRK:
1615#if 0
1616 error = dgmdrain(port);
1617
1618 if (error != 0) {
1619 splx(s);
1620 return error;
1621 }
1622#endif
1623
1624 cs = splclock();
1625 setwin(sc, 0);
1626
1627 /* now it sends 400 millisecond break because I don't know */
1628 /* how to send an infinite break */
1629
1630 fepcmd(port, SENDBREAK, 400, 0, 10, 0);
1631 hidewin(sc);
1632 splx(cs);
1633 break;
1634 case TIOCCBRK:
1635 /* now it's empty */
1636 break;
1637 case TIOCSDTR:
1638 DPRINT3(DB_MODEM, "dgm%d: port%d: set DTR\n", unit, pnum);
1639 port->omodem |= DTR;
1640 cs = splclock();
1641 setwin(sc, 0);
1642 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1643
1644 if (!(bc->mstat & DTR))
1645 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is off\n", unit, pnum);
1646
1647 hidewin(sc);
1648 splx(cs);
1649 break;
1650 case TIOCCDTR:
1651 DPRINT3(DB_MODEM, "dgm%d: port%d: reset DTR\n", unit, pnum);
1652 port->omodem &= ~DTR;
1653 cs = splclock();
1654 setwin(sc, 0);
1655 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1656
1657 if (bc->mstat & DTR) {
1658 DPRINT3(DB_MODEM, "dgm%d: port%d: DTR is on\n", unit, pnum);
1659 }
1660
1661 hidewin(sc);
1662 splx(cs);
1663 break;
1664 case TIOCMSET:
1665 if (*(int *)data & TIOCM_DTR)
1666 port->omodem |= DTR;
1667 else
1668 port->omodem &= ~DTR;
1669
1670 if (*(int *)data & TIOCM_RTS)
1671 port->omodem |= RTS;
1672 else
1673 port->omodem &= ~RTS;
1674
1675 cs = splclock();
1676 setwin(sc, 0);
1677 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1678 hidewin(sc);
1679 splx(cs);
1680 break;
1681 case TIOCMBIS:
1682 if (*(int *)data & TIOCM_DTR)
1683 port->omodem |= DTR;
1684
1685 if (*(int *)data & TIOCM_RTS)
1686 port->omodem |= RTS;
1687
1688 cs = splclock();
1689 setwin(sc, 0);
1690 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1691 hidewin(sc);
1692 splx(cs);
1693 break;
1694 case TIOCMBIC:
1695 if (*(int *)data & TIOCM_DTR)
1696 port->omodem &= ~DTR;
1697
1698 if (*(int *)data & TIOCM_RTS)
1699 port->omodem &= ~RTS;
1700
1701 cs = splclock();
1702 setwin(sc, 0);
1703 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1704 hidewin(sc);
1705 splx(cs);
1706 break;
1707 case TIOCMGET:
1708 setwin(sc, 0);
1709 port->imodem = bc->mstat;
1710 hidewin(sc);
1711
1712 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1713
1714 DPRINT3(DB_MODEM, "dgm%d: port%d: modem stat -- ", unit, pnum);
1715
1716 if (port->imodem & DTR) {
1717 DPRINT1(DB_MODEM, "DTR ");
1718 tiocm_xxx |= TIOCM_DTR;
1719 }
1720 if (port->imodem & RTS) {
1721 DPRINT1(DB_MODEM, "RTS ");
1722 tiocm_xxx |= TIOCM_RTS;
1723 }
1724 if (port->imodem & CTS) {
1725 DPRINT1(DB_MODEM, "CTS ");
1726 tiocm_xxx |= TIOCM_CTS;
1727 }
1728 if (port->imodem & port->dcd) {
1729 DPRINT1(DB_MODEM, "DCD ");
1730 tiocm_xxx |= TIOCM_CD;
1731 }
1732 if (port->imodem & port->dsr) {
1733 DPRINT1(DB_MODEM, "DSR ");
1734 tiocm_xxx |= TIOCM_DSR;
1735 }
1736 if (port->imodem & RI) {
1737 DPRINT1(DB_MODEM, "RI ");
1738 tiocm_xxx |= TIOCM_RI;
1739 }
1740 *(int *)data = tiocm_xxx;
1741 DPRINT1(DB_MODEM, "--\n");
1742 break;
1743 case TIOCMSDTRWAIT:
1744 /* must be root since the wait applies to following logins */
dadab5e9 1745 error = suser(td);
984263bc
MD
1746 if (error != 0) {
1747 splx(s);
1748 return (error);
1749 }
1750 port->close_delay = *(int *)data * hz / 100;
1751 break;
1752 case TIOCMGDTRWAIT:
1753 *(int *)data = port->close_delay * 100 / hz;
1754 break;
1755 case TIOCTIMESTAMP:
1756 port->do_timestamp = 1;
1757 *(struct timeval *)data = port->timestamp;
1758 break;
1759 case TIOCDCDTIMESTAMP:
1760 port->do_dcd_timestamp = 1;
1761 *(struct timeval *)data = port->dcd_timestamp;
1762 break;
1763 default:
1764 bmws_set(ws);
1765 splx(s);
1766 return ENOTTY;
1767 }
1768 bmws_set(ws);
1769 splx(s);
1770
1771 return 0;
1772}
1773
1774static void
1775wakeflush(void *p)
1776{
1777 struct dgm_p *port = p;
1778
1779 wakeup(&port->draining);
1780}
1781
1782/* wait for the output to drain */
1783
1784static int
1785dgmdrain(struct dgm_p *port)
1786{
1787 volatile struct board_chan *bc = port->brdchan;
1788 struct dgm_softc *sc;
1789 int error;
1790 int head, tail;
1791 BoardMemWinState ws = bmws_get();
1792
1793 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1794
1795 setwin(sc, 0);
1796
1797 bc->iempty = 1;
1798 tail = bc->tout;
1799 head = bc->tin;
1800
1801 while (tail != head) {
1802 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1803 port->sc->unit, port->pnum, head, tail);
1804
1805 hidewin(sc);
1806 port->draining = 1;
1807 timeout(wakeflush, port, hz);
377d4740 1808 error = tsleep(&port->draining, PCATCH, "dgdrn", 0);
984263bc
MD
1809 port->draining = 0;
1810 setwin(sc, 0);
1811
1812 if (error != 0) {
1813 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgdrn) error = %d\n",
1814 port->sc->unit, port->pnum, error);
1815
1816 bc->iempty = 0;
1817 bmws_set(ws);
1818 return error;
1819 }
1820
1821 tail = bc->tout;
1822 head = bc->tin;
1823 }
1824 DPRINT5(DB_WR, "dgm%d: port%d: drain: head = %d tail = %d\n",
1825 port->sc->unit, port->pnum, head, tail);
1826 bmws_set(ws);
1827 return 0;
1828}
1829
1830/* wait for the output to drain */
1831/* or simply clear the buffer it it's stopped */
1832
1833static void
1834dgm_drain_or_flush(struct dgm_p *port)
1835{
1836 volatile struct board_chan *bc = port->brdchan;
1837 struct tty *tp = port->tty;
1838 struct dgm_softc *sc;
1839 int error;
1840 int lasttail;
1841 int head, tail;
1842
1843 sc = devclass_get_softc(dgmdevclass, port->sc->unit);
1844 setwin(sc, 0);
1845
1846 lasttail = -1;
1847 bc->iempty = 1;
1848 tail = bc->tout;
1849 head = bc->tin;
1850
1851 while (tail != head /* && tail != lasttail */ ) {
1852 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1853 port->sc->unit, port->pnum, head, tail);
1854
1855 /* if there is no carrier simply clean the buffer */
1856 if (!(tp->t_state & TS_CARR_ON)) {
1857 bc->tout = bc->tin = 0;
1858 bc->iempty = 0;
1859 hidewin(sc);
1860 return;
1861 }
1862
1863 hidewin(sc);
1864 port->draining = 1;
1865 timeout(wakeflush, port, hz);
377d4740 1866 error = tsleep(&port->draining, PCATCH, "dgfls", 0);
984263bc
MD
1867 port->draining = 0;
1868 setwin(sc, 0);
1869
1870 if (error != 0) {
1871 DPRINT4(DB_WR, "dgm%d: port%d: tsleep(dgfls)"
1872 " error = %d\n", port->sc->unit, port->pnum, error);
1873
1874 /* silently clean the buffer */
1875
1876 bc->tout = bc->tin = 0;
1877 bc->iempty = 0;
1878 hidewin(sc);
1879 return;
1880 }
1881
1882 lasttail = tail;
1883 tail = bc->tout;
1884 head = bc->tin;
1885 }
1886 hidewin(sc);
1887 DPRINT5(DB_WR, "dgm%d: port%d: flush: head = %d tail = %d\n",
1888 port->sc->unit, port->pnum, head, tail);
1889}
1890
1891static int
1892dgmparam(struct tty *tp, struct termios *t)
1893{
1894 int unit = MINOR_TO_UNIT(minor(tp->t_dev));
1895 int pnum = MINOR_TO_PORT(minor(tp->t_dev));
1896 volatile struct board_chan *bc;
1897 struct dgm_softc *sc;
1898 struct dgm_p *port;
1899 int cflag;
1900 int head;
1901 int mval;
1902 int iflag;
1903 int hflow;
1904 int cs;
1905 BoardMemWinState ws = bmws_get();
1906
1907 sc = devclass_get_softc(dgmdevclass, unit);
1908 port = &sc->ports[pnum];
1909 bc = port->brdchan;
1910
1911 DPRINT6(DB_PARAM, "dgm%d: port%d: dgmparm c = 0x%x i = 0x%x l = 0x%x\n", unit, pnum, t->c_cflag, t->c_iflag, t->c_lflag);
1912
1913 if (port->mustdrain) {
1914 DPRINT3(DB_PARAM, "dgm%d: port%d: must call dgmdrain()\n", unit, pnum);
1915 dgmdrain(port);
1916 }
1917
1918 cflag = ttspeedtab(t->c_ospeed, dgmspeedtab);
1919
1920 if (t->c_ispeed == 0)
1921 t->c_ispeed = t->c_ospeed;
1922
1923 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1924 DPRINT4(DB_PARAM, "dgm%d: port%d: invalid cflag = 0%o\n", unit, pnum, cflag);
1925 return (EINVAL);
1926 }
1927
1928 cs = splclock();
1929 setwin(sc, 0);
1930
1931 if (cflag == 0) { /* hangup */
1932 DPRINT3(DB_PARAM, "dgm%d: port%d: hangup\n", unit, pnum);
1933 head = bc->rin;
1934 bc->rout = head;
1935 head = bc->tin;
1936 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1937 mval= port->omodem & ~(DTR|RTS);
1938 } else {
1939 cflag |= dgmflags(dgm_cflags, t->c_cflag);
1940
1941 if (cflag != port->fepcflag) {
1942 port->fepcflag = cflag;
1943 DPRINT5(DB_PARAM, "dgm%d: port%d: set cflag = 0x%x c = 0x%x\n",
1944 unit, pnum, cflag, t->c_cflag&~CRTSCTS);
1945 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1946 }
1947 mval= port->omodem | (DTR|RTS);
1948 }
1949
1950 iflag = dgmflags(dgm_iflags, t->c_iflag);
1951 if (iflag != port->fepiflag) {
1952 port->fepiflag = iflag;
1953 DPRINT5(DB_PARAM, "dgm%d: port%d: set iflag = 0x%x c = 0x%x\n", unit, pnum, iflag, t->c_iflag);
1954 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1955 }
1956
1957 bc->mint = port->dcd;
1958
1959 hflow = dgmflags(dgm_flow, t->c_cflag);
1960 if (hflow != port->hflow) {
1961 port->hflow = hflow;
1962 DPRINT5(DB_PARAM, "dgm%d: port%d: set hflow = 0x%x f = 0x%x\n", unit, pnum, hflow, t->c_cflag&CRTSCTS);
1963 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1964 }
1965
1966 if (port->omodem != mval) {
1967 DPRINT5(DB_PARAM, "dgm%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1968 unit, pnum, mval, port->omodem);
1969 port->omodem = mval;
1970 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1971 }
1972
1973 if (port->fepstartc != t->c_cc[VSTART] ||
1974 port->fepstopc != t->c_cc[VSTOP]) {
1975 DPRINT5(DB_PARAM, "dgm%d: port%d: set startc = %d, stopc = %d\n", unit, pnum, t->c_cc[VSTART], t->c_cc[VSTOP]);
1976 port->fepstartc = t->c_cc[VSTART];
1977 port->fepstopc = t->c_cc[VSTOP];
1978 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1979 }
1980
1981 bmws_set(ws);
1982 splx(cs);
1983
1984 return 0;
1985
1986}
1987
1988static void
1989dgmstart(struct tty *tp)
1990{
1991 int unit;
1992 int pnum;
1993 struct dgm_p *port;
1994 struct dgm_softc *sc;
1995 volatile struct board_chan *bc;
1996 int head, tail;
1997 int size, ocount;
1998 int s;
1999 int wmask;
2000
2001 BoardMemWinState ws = bmws_get();
2002
2003 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2004 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2005 sc = devclass_get_softc(dgmdevclass, unit);
2006 port = &sc->ports[pnum];
2007 bc = port->brdchan;
2008
2009 wmask = port->txbufsize - 1;
2010
2011 s = spltty();
2012
2013 while (tp->t_outq.c_cc != 0) {
2014 int cs;
2015#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2016 ttwwakeup(tp);
2017#else
2018 if (tp->t_outq.c_cc <= tp->t_lowat) {
2019 if (tp->t_state & TS_ASLEEP) {
2020 tp->t_state &= ~TS_ASLEEP;
2021 wakeup(TSA_OLOWAT(tp));
2022 }
2023 /*selwakeup(&tp->t_wsel);*/
2024 }
2025#endif
2026 cs = splclock();
2027 setwin(sc, 0);
2028
2029 head = bc->tin & wmask;
2030
2031 do { tail = bc->tout; } while (tail != bc->tout);
2032 tail = bc->tout & wmask;
2033
2034 DPRINT5(DB_WR, "dgm%d: port%d: s tx head = %d tail = %d\n", unit, pnum, head, tail);
2035
2036#ifdef LEAVE_FREE_CHARS
2037 if (tail > head) {
2038 size = tail - head - LEAVE_FREE_CHARS;
2039 if (size < 0)
2040 size = 0;
2041 else {
2042 size = port->txbufsize - head;
2043 if (tail + port->txbufsize < head)
2044 size = 0;
2045 }
2046 }
2047#else
2048 if (tail > head)
2049 size = tail - head - 1;
2050 else {
2051 size = port->txbufsize - head;
2052 if (tail == 0)
2053 size--;
2054 }
2055#endif
2056
2057 if (size == 0) {
2058 bc->iempty = 1;
2059 bc->ilow = 1;
2060 splx(cs);
2061 bmws_set(ws);
2062 tp->t_state |= TS_BUSY;
2063 splx(s);
2064 return;
2065 }
2066
2067 towin(sc, port->txwin);
2068
2069 ocount = q_to_b(&tp->t_outq, port->txptr + head, size);
2070 head += ocount;
2071 if (head >= port->txbufsize)
2072 head -= port->txbufsize;
2073
2074 setwin(sc, 0);
2075 bc->tin = head;
2076
2077 DPRINT5(DB_WR, "dgm%d: port%d: tx avail = %d count = %d\n",
2078 unit, pnum, size, ocount);
2079 hidewin(sc);
2080 splx(cs);
2081 }
2082
2083 bmws_set(ws);
2084 splx(s);
2085
2086#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2087 if (tp->t_state & TS_BUSY) {
2088 tp->t_state &= ~TS_BUSY;
2089 linesw[tp->t_line].l_start(tp);
2090 ttwwakeup(tp);
2091 }
2092#else
2093 if (tp->t_state & TS_ASLEEP) {
2094 tp->t_state &= ~TS_ASLEEP;
2095 wakeup(TSA_OLOWAT(tp));
2096 }
2097 tp->t_state& = ~TS_BUSY;
2098#endif
2099}
2100
2101void
2102dgmstop(struct tty *tp, int rw)
2103{
2104 int unit;
2105 int pnum;
2106 struct dgm_p *port;
2107 struct dgm_softc *sc;
2108 volatile struct board_chan *bc;
2109 int s;
2110
2111 BoardMemWinState ws = bmws_get();
2112
2113 unit = MINOR_TO_UNIT(minor(tp->t_dev));
2114 pnum = MINOR_TO_PORT(minor(tp->t_dev));
2115
2116 sc = devclass_get_softc(dgmdevclass, unit);
2117 port = &sc->ports[pnum];
2118 bc = port->brdchan;
2119
2120 DPRINT3(DB_WR, "dgm%d: port%d: stop\n", port->sc->unit, port->pnum);
2121
2122 s = spltty();
2123 setwin(sc, 0);
2124
2125 if (rw & FWRITE) {
2126 /* clear output queue */
2127 bc->tout = bc->tin = 0;
2128 bc->ilow = 0;
2129 bc->iempty = 0;
2130 }
2131 if (rw & FREAD) {
2132 /* clear input queue */
2133 bc->rout = bc->rin;
2134 bc->idata = 1;
2135 }
2136 hidewin(sc);
2137 bmws_set(ws);
2138 splx(s);
2139 dgmstart(tp);
2140}
2141
2142static void
2143fepcmd(struct dgm_p *port,
2144 unsigned cmd,
2145 unsigned op1,
2146 unsigned op2,
2147 unsigned ncmds,
2148 unsigned bytecmd)
2149{
2150 u_char *mem;
2151 unsigned tail, head;
2152 int count, n;
2153
2154 KASSERT(port->sc, ("Couldn't (re)obtain driver softc"));
2155 mem = port->sc->vmem;
2156
2157 if (!port->enabled) {
2158 printf("dgm%d: port%d: FEP command on disabled port\n",
2159 port->sc->unit, port->pnum);
2160 return;
2161 }
2162
2163 /* setwin(port->sc, 0); Require this to be set by caller */
2164 head = port->sc->mailbox->cin;
2165
2166 if (head >= FEP_CMAX - FEP_CSTART || (head & 3)) {
2167 printf("dgm%d: port%d: wrong pointer head of command queue : 0x%x\n",
2168 port->sc->unit, port->pnum, head);
2169 return;
2170 }
2171
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;
2180 }
2181
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]);
2184
2185 head = (head + 4) & (FEP_CMAX - FEP_CSTART - 4);
2186 port->sc->mailbox->cin = head;
2187
2188 count = FEPTIMEOUT;
2189
2190 while (count-- != 0) {
2191 head = port->sc->mailbox->cin;
2192 tail = port->sc->mailbox->cout;
2193
2194 n = (head - tail) & (FEP_CMAX - FEP_CSTART - 4);
2195 if (n <= ncmds * (sizeof(ushort)*4))
2196 return;
2197 }
2198 printf("dgm%d(%d): timeout on FEP cmd = 0x%x\n", port->sc->unit, port->pnum, cmd);
2199}
2200
2201static void
2202disc_optim(struct tty *tp, struct termios *t)
2203{
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;
2213}