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