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