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