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