Device layer rollup commit.
[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 $
e4c9c0c8 3 * dgb.c $DragonFly: src/sys/i386/gnu/isa/Attic/dgb.c,v 1.11 2004/05/19 22:52:57 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
1f2de5d4 34#include "use_dgb.h"
984263bc
MD
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
1f2de5d4 62#include <bus/isa/i386/isa_device.h>
984263bc 63
1f2de5d4
MD
64#include "dgbios.h"
65#include "dgfep.h"
984263bc
MD
66
67#define DGB_DEBUG /* Enable debugging info via sysctl */
1f2de5d4 68#include "dgreg.h"
984263bc
MD
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. */
3ae0cd58 176static void dgbpoll (void *unit_c);
984263bc
MD
177
178/* Device switch entry points. */
179#define dgbreset noreset
180#define dgbmmap nommap
181#define dgbstrategy nostrategy
182
3ae0cd58
RG
183static int dgbattach (struct isa_device *dev);
184static int dgbprobe (struct isa_device *dev);
984263bc
MD
185
186static void fepcmd(struct dgb_p *port, unsigned cmd, unsigned op1, unsigned op2,
187 unsigned ncmds, unsigned bytecmd);
188
3ae0cd58
RG
189static void dgbstart (struct tty *tp);
190static void dgbstop (struct tty *tp, int rw);
191static int dgbparam (struct tty *tp, struct termios *t);
192static void dgbhardclose (struct dgb_p *port);
193static void dgb_drain_or_flush (struct dgb_p *port);
194static int dgbdrain (struct dgb_p *port);
195static void dgb_pause (void *chan);
196static void wakeflush (void *p);
197static void disc_optim (struct tty *tp, struct termios *t);
984263bc
MD
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,
455fcd7e 214 /* clone */ NULL,
fabb8ceb 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
3ae0cd58
RG
309static __inline int setwin (struct dgb_softc *sc, unsigned addr);
310static __inline int setinitwin (struct dgb_softc *sc, unsigned addr);
311static __inline void hidewin (struct dgb_softc *sc);
312static __inline void towin (struct dgb_softc *sc, int win);
984263bc
MD
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;
984263bc 408
984263bc
MD
409 sc->unit=dev->id_unit;
410 sc->port=dev->id_iobase;
411
412 if(dev->id_flags & DGBFLAG_ALTPIN)
413 sc->altpin=1;
414 else
415 sc->altpin=0;
416
417 /* left 24 bits only (ISA address) */
418 sc->pmem=((intptr_t)(void *)dev->id_maddr & 0xFFFFFF);
419
420 DPRINT4(DB_INFO,"dgb%d: port 0x%x mem 0x%lx\n",unit,sc->port,sc->pmem);
421
422 outb(sc->port, FEPRST);
423 sc->status=DISABLED;
424
425 for(i=0; i< 1000; i++) {
426 DELAY(1);
427 if( (inb(sc->port) & FEPMASK) == FEPRST ) {
428 sc->status=ENABLED;
429 DPRINT3(DB_EXCEPT,"dgb%d: got reset after %d us\n",unit,i);
430 break;
431 }
432 }
433
434 if(sc->status!=ENABLED) {
435 DPRINT2(DB_EXCEPT,"dgb%d: failed to respond\n",dev->id_unit);
436 return 0;
437 }
438
439 /* check type of card and get internal memory characteristics */
440
441 v=inb(sc->port);
442
443 if( v & 0x1 ) {
444 switch( v&0x30 ) {
445 case 0:
446 sc->mem_seg=0xF000;
447 win_size=0x10000;
448 printf("dgb%d: PC/Xi 64K\n",dev->id_unit);
449 break;
450 case 0x10:
451 sc->mem_seg=0xE000;
452 win_size=0x20000;
453 printf("dgb%d: PC/Xi 128K\n",dev->id_unit);
454 break;
455 case 0x20:
456 sc->mem_seg=0xC000;
457 win_size=0x40000;
458 printf("dgb%d: PC/Xi 256K\n",dev->id_unit);
459 break;
460 default: /* case 0x30: */
461 sc->mem_seg=0x8000;
462 win_size=0x80000;
463 printf("dgb%d: PC/Xi 512K\n",dev->id_unit);
464 break;
465 }
466 sc->type=PCXI;
467 } else {
468 outb(sc->port, 1);
469 v=inb(sc->port);
470
471 if( v & 0x1 ) {
472 printf("dgb%d: PC/Xm isn't supported\n",dev->id_unit);
473 sc->status=DISABLED;
474 return 0;
475 }
476
477 sc->mem_seg=0xF000;
478
479 if(dev->id_flags==DGBFLAG_NOWIN || ( v&0xC0 )==0) {
480 win_size=0x10000;
481 printf("dgb%d: PC/Xe 64K\n",dev->id_unit);
482 sc->type=PCXE;
483 } else {
484 win_size=0x2000;
485 printf("dgb%d: PC/Xe 64/8K (windowed)\n",dev->id_unit);
486 sc->type=PCXEVE;
487 if((u_long)sc->pmem & ~0xFFE000) {
488 printf("dgb%d: warning: address 0x%lx truncated to 0x%lx\n",
489 dev->id_unit, sc->pmem,
490 sc->pmem & 0xFFE000);
491
492 dev->id_maddr= (u_char *)(void *)(intptr_t)( sc->pmem & 0xFFE000 );
493 }
494 }
495 }
496
497 /* save size of vizible memory segment */
498 dev->id_msize=win_size;
499
500 /* map memory */
501 dev->id_maddr=sc->vmem=pmap_mapdev(sc->pmem,dev->id_msize);
502
503 outb(sc->port, FEPCLR); /* drop RESET */
504 hidewin(sc); /* Helg: to set initial bmws state */
505
506 return 4; /* we need I/O space of 4 ports */
507}
508
509static int
510dgbattach(dev)
511 struct isa_device *dev;
512{
513 int unit=dev->id_unit;
514 struct dgb_softc *sc= &dgb_softc[dev->id_unit];
515 int i, t;
516 u_char volatile *mem;
517 u_char volatile *ptr;
518 int addr;
519 struct dgb_p *port;
520 volatile struct board_chan *bc;
521 int shrinkmem;
522 int nfails;
f15db79e 523 const volatile ushort *pstat;
984263bc
MD
524 int lowwater;
525 static int nports=0;
526 char suffix;
527
528 if(sc->status!=ENABLED) {
529 DPRINT2(DB_EXCEPT,"dbg%d: try to attach a disabled card\n",unit);
530 return 0;
531 }
532
533 mem=sc->vmem;
534
535 DPRINT3(DB_INFO,"dgb%d: internal memory segment 0x%x\n",unit,sc->mem_seg);
536
537 outb(sc->port, FEPRST); DELAY(1);
538
539 for(i=0; (inb(sc->port) & FEPMASK) != FEPRST ; i++) {
540 if(i>10000) {
541 printf("dgb%d: 1st reset failed\n",dev->id_unit);
542 sc->status=DISABLED;
543 hidewin(sc);
544 return 0;
545 }
546 DELAY(1);
547 }
548
549 DPRINT3(DB_INFO,"dgb%d: got reset after %d us\n",unit,i);
550
551 /* for PCXEVE set up interrupt and base address */
552
553 if(sc->type==PCXEVE) {
554 t=(((u_long)sc->pmem>>8) & 0xFFE0) | 0x10 /* enable windowing */;
555 /* IRQ isn't used */
556 outb(sc->port+2,t & 0xFF);
557 outb(sc->port+3,t>>8);
558 } else if(sc->type==PCXE) {
559 t=(((u_long)sc->pmem>>8) & 0xFFE0) /* disable windowing */;
560 outb(sc->port+2,t & 0xFF);
561 outb(sc->port+3,t>>8);
562 }
563
564
565 if(sc->type==PCXI || sc->type==PCXE) {
566 outb(sc->port, FEPRST|FEPMEM); DELAY(1);
567
568 for(i=0; (inb(sc->port) & FEPMASK) != (FEPRST|FEPMEM) ; i++) {
569 if(i>10000) {
570 printf("dgb%d: 2nd reset failed\n",dev->id_unit);
571 sc->status=DISABLED;
572 hidewin(sc);
573 return 0;
574 }
575 DELAY(1);
576 }
577
578 DPRINT3(DB_INFO,"dgb%d: got memory after %d us\n",unit,i);
579 }
580
581 mem=sc->vmem;
582
583 /* very short memory test */
584
585 addr=setinitwin(sc,BOTWIN);
586 *(u_long volatile *)(mem+addr) = 0xA55A3CC3;
587 if(*(u_long volatile *)(mem+addr)!=0xA55A3CC3) {
588 printf("dgb%d: 1st memory test failed\n",dev->id_unit);
589 sc->status=DISABLED;
590 hidewin(sc);
591 return 0;
592 }
593
594 addr=setinitwin(sc,TOPWIN);
595 *(u_long volatile *)(mem+addr) = 0x5AA5C33C;
596 if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
597 printf("dgb%d: 2nd memory test failed\n",dev->id_unit);
598 sc->status=DISABLED;
599 hidewin(sc);
600 return 0;
601 }
602
603 addr=setinitwin(sc,BIOSCODE+((0xF000-sc->mem_seg)<<4));
604 *(u_long volatile *)(mem+addr) = 0x5AA5C33C;
605 if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
606 printf("dgb%d: 3rd (BIOS) memory test failed\n",dev->id_unit);
607 }
608
609 addr=setinitwin(sc,MISCGLOBAL);
610 for(i=0; i<16; i++) {
611 mem[addr+i]=0;
612 }
613
614 if(sc->type==PCXI || sc->type==PCXE) {
615
616 addr=BIOSCODE+((0xF000-sc->mem_seg)<<4);
617
618 DPRINT3(DB_INFO,"dgb%d: BIOS local address=0x%x\n",unit,addr);
619
620 ptr= mem+addr;
621
622 for(i=0; i<pcxx_nbios; i++, ptr++)
623 *ptr = pcxx_bios[i];
624
625 ptr= mem+addr;
626
627 nfails=0;
628 for(i=0; i<pcxx_nbios; i++, ptr++)
629 if( *ptr != pcxx_bios[i] ) {
630 DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
6310x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
632
633 if(++nfails>=5) {
634 printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
635 break;
636 }
637 }
638
639 outb(sc->port,FEPMEM);
640
641 for(i=0; (inb(sc->port) & FEPMASK) != FEPMEM ; i++) {
642 if(i>10000) {
643 printf("dgb%d: BIOS start failed\n",dev->id_unit);
644 sc->status=DISABLED;
645 hidewin(sc);
646 return 0;
647 }
648 DELAY(1);
649 }
650
651 DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
652
653 for(i=0; i<200000; i++) {
654 if( *((ushort volatile *)(mem+MISCGLOBAL)) == *((ushort *)"GD") )
655 goto load_fep;
656 DELAY(1);
657 }
658 printf("dgb%d: BIOS download failed\n",dev->id_unit);
659 DPRINT4(DB_EXCEPT,"dgb%d: code=0x%x must be 0x%x\n",
660 dev->id_unit,
661 *((ushort volatile *)(mem+MISCGLOBAL)),
662 *((ushort *)"GD"));
663
664 sc->status=DISABLED;
665 hidewin(sc);
666 return 0;
667 }
668
669 if(sc->type==PCXEVE) {
670 /* set window 7 */
671 outb(sc->port+1,0xFF);
672
673 ptr= mem+(BIOSCODE & 0x1FFF);
674
675 for(i=0; i<pcxx_nbios; i++)
676 *ptr++ = pcxx_bios[i];
677
678 ptr= mem+(BIOSCODE & 0x1FFF);
679
680 nfails=0;
681 for(i=0; i<pcxx_nbios; i++, ptr++)
682 if( *ptr != pcxx_bios[i] ) {
683 DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
6840x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
685
686 if(++nfails>=5) {
687 printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
688 break;
689 }
690 }
691
692 outb(sc->port,FEPCLR);
693
694 setwin(sc,0);
695
696 for(i=0; (inb(sc->port) & FEPMASK) != FEPCLR ; i++) {
697 if(i>10000) {
698 printf("dgb%d: BIOS start failed\n",dev->id_unit);
699 sc->status=DISABLED;
700 hidewin(sc);
701 return 0;
702 }
703 DELAY(1);
704 }
705
706 DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
707
708 addr=setwin(sc,MISCGLOBAL);
709
710 for(i=0; i<200000; i++) {
711 if(*(ushort volatile *)(mem+addr)== *(ushort *)"GD")
712 goto load_fep;
713 DELAY(1);
714 }
715 printf("dgb%d: BIOS download failed\n",dev->id_unit);
716 DPRINT5(DB_EXCEPT,"dgb%d: Error#(0x%x,0x%x) code=0x%x\n",
717 dev->id_unit,
718 *(ushort volatile *)(mem+0xC12),
719 *(ushort volatile *)(mem+0xC14),
720 *(ushort volatile *)(mem+MISCGLOBAL));
721
722 sc->status=DISABLED;
723 hidewin(sc);
724 return 0;
725 }
726
727load_fep:
728 DPRINT2(DB_INFO,"dgb%d: BIOS loaded\n",dev->id_unit);
729
730 addr=setwin(sc,FEPCODE);
731
732 ptr= mem+addr;
733
734 for(i=0; i<pcxx_ncook; i++)
735 *ptr++ = pcxx_cook[i];
736
737 addr=setwin(sc,MBOX);
738 *(ushort volatile *)(mem+addr+ 0)=2;
739 *(ushort volatile *)(mem+addr+ 2)=sc->mem_seg+FEPCODESEG;
740 *(ushort volatile *)(mem+addr+ 4)=0;
741 *(ushort volatile *)(mem+addr+ 6)=FEPCODESEG;
742 *(ushort volatile *)(mem+addr+ 8)=0;
743 *(ushort volatile *)(mem+addr+10)=pcxx_ncook;
744
745 outb(sc->port,FEPMEM|FEPINT); /* send interrupt to BIOS */
746 outb(sc->port,FEPMEM);
747
748 for(i=0; *(ushort volatile *)(mem+addr)!=0; i++) {
749 if(i>200000) {
750 printf("dgb%d: FEP code download failed\n",unit);
751 DPRINT3(DB_EXCEPT,"dgb%d: code=0x%x must be 0\n", unit,
752 *(ushort volatile *)(mem+addr));
753 sc->status=DISABLED;
754 hidewin(sc);
755 return 0;
756 }
757 }
758
759 DPRINT2(DB_INFO,"dgb%d: FEP code loaded\n",unit);
760
761 *(ushort volatile *)(mem+setwin(sc,FEPSTAT))=0;
762 addr=setwin(sc,MBOX);
763 *(ushort volatile *)(mem+addr+0)=1;
764 *(ushort volatile *)(mem+addr+2)=FEPCODESEG;
765 *(ushort volatile *)(mem+addr+4)=0x4;
766
767 outb(sc->port,FEPINT); /* send interrupt to BIOS */
768 outb(sc->port,FEPCLR);
769
770 addr=setwin(sc,FEPSTAT);
771 for(i=0; *(ushort volatile *)(mem+addr)!= *(ushort *)"OS"; i++) {
772 if(i>200000) {
773 printf("dgb%d: FEP/OS start failed\n",dev->id_unit);
774 sc->status=DISABLED;
775 hidewin(sc);
776 return 0;
777 }
778 }
779
780 DPRINT2(DB_INFO,"dgb%d: FEP/OS started\n",dev->id_unit);
781
782 sc->numports= *(ushort volatile *)(mem+setwin(sc,NPORT));
783
784 printf("dgb%d: %d ports\n",unit,sc->numports);
785
786 if(sc->numports > MAX_DGB_PORTS) {
787 printf("dgb%d: too many ports\n",unit);
788 sc->status=DISABLED;
789 hidewin(sc);
790 return 0;
791 }
792
793 if(nports+sc->numports>NDGBPORTS) {
794 printf("dgb%d: only %d ports are usable\n", unit, NDGBPORTS-nports);
795 sc->numports=NDGBPORTS-nports;
796 }
797
798 /* allocate port and tty structures */
799 sc->ports=&dgb_ports[nports];
800 sc->ttys=&dgb_tty[nports];
801 nports+=sc->numports;
802
803 addr=setwin(sc,PORTBASE);
f15db79e 804 pstat=(const ushort volatile *)(mem+addr);
984263bc
MD
805
806 for(i=0; i<sc->numports && pstat[i]; i++)
807 if(pstat[i])
808 sc->ports[i].status=ENABLED;
809 else {
810 sc->ports[i].status=DISABLED;
811 printf("dgb%d: port%d is broken\n", unit, i);
812 }
813
814 /* We should now init per-port structures */
815 bc=(volatile struct board_chan *)(mem + CHANSTRUCT);
816 sc->mailbox=(volatile struct global_data *)(mem + FEP_GLOBAL);
817
818 if(sc->numports<3)
819 shrinkmem=1;
820 else
821 shrinkmem=0;
822
823 for(i=0; i<sc->numports; i++, bc++) {
824 port= &sc->ports[i];
825
826 port->tty=&sc->ttys[i];
827 port->unit=unit;
828
829 port->brdchan=bc;
830
831 if(sc->altpin) {
832 port->dsr=CD;
833 port->dcd=DSR;
834 } else {
835 port->dcd=CD;
836 port->dsr=DSR;
837 }
838
839 port->pnum=i;
840
841 if(shrinkmem) {
842 DPRINT2(DB_INFO,"dgb%d: shrinking memory\n",unit);
843 fepcmd(port, SETBUFFER, 32, 0, 0, 0);
844 shrinkmem=0;
845 }
846
847 if(sc->type!=PCXEVE) {
848 port->txptr=mem+((bc->tseg-sc->mem_seg)<<4);
849 port->rxptr=mem+((bc->rseg-sc->mem_seg)<<4);
850 port->txwin=port->rxwin=0;
851 } else {
852 port->txptr=mem+( ((bc->tseg-sc->mem_seg)<<4) & 0x1FFF );
853 port->rxptr=mem+( ((bc->rseg-sc->mem_seg)<<4) & 0x1FFF );
854 port->txwin=FEPWIN | ((bc->tseg-sc->mem_seg)>>9);
855 port->rxwin=FEPWIN | ((bc->rseg-sc->mem_seg)>>9);
856 }
857
858 port->txbufhead=0;
859 port->rxbufhead=0;
860 port->txbufsize=bc->tmax+1;
861 port->rxbufsize=bc->rmax+1;
862
863 lowwater= (port->txbufsize>=2000) ? 1024 : (port->txbufsize/2);
864 setwin(sc,0);
865 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
866 fepcmd(port, SRXLWATER, port->rxbufsize/4, 0, 10, 0);
867 fepcmd(port, SRXHWATER, 3*port->rxbufsize/4, 0, 10, 0);
868
869 bc->edelay=100;
870 bc->idata=1;
871
872 port->startc=bc->startc;
873 port->startca=bc->startca;
874 port->stopc=bc->stopc;
875 port->stopca=bc->stopca;
876
877 /*port->close_delay=50;*/
878 port->close_delay=3 * hz;
879 port->do_timestamp=0;
880 port->do_dcd_timestamp=0;
881
882 /*
883 * We don't use all the flags from <sys/ttydefaults.h> since they
884 * are only relevant for logins. It's important to have echo off
885 * initially so that the line doesn't start blathering before the
886 * echo flag can be turned off.
887 */
888 port->it_in.c_iflag = TTYDEF_IFLAG;
889 port->it_in.c_oflag = TTYDEF_OFLAG;
890 port->it_in.c_cflag = TTYDEF_CFLAG;
891 port->it_in.c_lflag = TTYDEF_LFLAG;
892 termioschars(&port->it_in);
893 port->it_in.c_ispeed = port->it_in.c_ospeed = dgbdefaultrate;
894 port->it_out = port->it_in;
895 /* MAX_DGB_PORTS is 32 => [0-9a-v] */
896 suffix = i < 10 ? '0' + i : 'a' + i - 10;
e4c9c0c8
MD
897 cdevsw_add(&dgb_cdevsw, 0xffff0000, unit << 16);
898 make_dev(&dgb_cdevsw, (unit<<16)+i,
984263bc
MD
899 UID_ROOT, GID_WHEEL, 0600, "ttyD%d%c", unit, suffix);
900
e4c9c0c8 901 make_dev(&dgb_cdevsw, (unit<<16)+i+32,
984263bc
MD
902 UID_ROOT, GID_WHEEL, 0600, "ttyiD%d%c", unit, suffix);
903
e4c9c0c8 904 make_dev(&dgb_cdevsw, (unit<<16)+i+64,
984263bc
MD
905 UID_ROOT, GID_WHEEL, 0600, "ttylD%d%c", unit, suffix);
906
e4c9c0c8 907 make_dev(&dgb_cdevsw, (unit<<16)+i+128,
984263bc
MD
908 UID_UUCP, GID_DIALER, 0660, "cuaD%d%c", unit, suffix);
909
e4c9c0c8 910 make_dev(&dgb_cdevsw, (unit<<16)+i+160,
984263bc
MD
911 UID_UUCP, GID_DIALER, 0660, "cuaiD%d%c", unit, suffix);
912
e4c9c0c8 913 make_dev(&dgb_cdevsw, (unit<<16)+i+192,
984263bc
MD
914 UID_UUCP, GID_DIALER, 0660, "cualD%d%c", unit, suffix);
915 }
916
917 hidewin(sc);
918
919 /* register the polling function */
920 timeout(dgbpoll, (void *)unit, hz/POLLSPERSEC);
921
922 return 1;
923}
924
925/* ARGSUSED */
926static int
dadab5e9 927dgbopen(dev_t dev, int flag, int mode, struct thread *td)
984263bc
MD
928{
929 struct dgb_softc *sc;
930 struct tty *tp;
931 int unit;
932 int mynor;
933 int pnum;
934 struct dgb_p *port;
935 int s,cs;
936 int error;
937 volatile struct board_chan *bc;
938
939 error=0;
940
941 mynor=minor(dev);
942 unit=MINOR_TO_UNIT(mynor);
943 pnum=MINOR_TO_PORT(mynor);
944
945 if(unit >= NDGB) {
946 DPRINT2(DB_EXCEPT,"dgb%d: try to open a nonexisting card\n",unit);
947 return ENXIO;
948 }
949
950 sc=&dgb_softc[unit];
951
952 if(sc->status!=ENABLED) {
953 DPRINT2(DB_EXCEPT,"dgb%d: try to open a disabled card\n",unit);
954 return ENXIO;
955 }
956
957 if(pnum>=sc->numports) {
958 DPRINT3(DB_EXCEPT,"dgb%d: try to open non-existing port %d\n",unit,pnum);
959 return ENXIO;
960 }
961
962 if(mynor & CONTROL_MASK)
963 return 0;
964
965 tp=&sc->ttys[pnum];
966 dev->si_tty = tp;
967 port=&sc->ports[pnum];
968 bc=port->brdchan;
969
970open_top:
971
972 s=spltty();
973
974 while(port->closing) {
377d4740 975 error=tsleep(&port->closing, PCATCH, "dgocl", 0);
984263bc
MD
976
977 if(error) {
978 DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgocl) error=%d\n",unit,pnum,error);
979 goto out;
980 }
981 }
982
983 if (tp->t_state & TS_ISOPEN) {
984 /*
985 * The device is open, so everything has been initialized.
986 * Handle conflicts.
987 */
988 if (mynor & CALLOUT_MASK) {
989 if (!port->active_out) {
990 error = EBUSY;
991 DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
992 goto out;
993 }
994 } else {
995 if (port->active_out) {
996 if (flag & O_NONBLOCK) {
997 error = EBUSY;
998 DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
999 goto out;
1000 }
1001 error = tsleep(&port->active_out,
377d4740 1002 PCATCH, "dgbi", 0);
984263bc
MD
1003 if (error != 0) {
1004 DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgbi) error=%d\n",
1005 unit,pnum,error);
1006 goto out;
1007 }
1008 splx(s);
1009 goto open_top;
1010 }
1011 }
dadab5e9 1012 if (tp->t_state & TS_XCLUDE && suser(td)) {
984263bc
MD
1013 error = EBUSY;
1014 goto out;
1015 }
1016 } else {
1017 /*
1018 * The device isn't open, so there are no conflicts.
1019 * Initialize it. Initialization is done twice in many
1020 * cases: to preempt sleeping callin opens if we are
1021 * callout, and to complete a callin open after DCD rises.
1022 */
1023 tp->t_oproc=dgbstart;
1024 tp->t_param=dgbparam;
1025 tp->t_stop=dgbstop;
1026 tp->t_dev=dev;
1027 tp->t_termios= (mynor & CALLOUT_MASK) ?
1028 port->it_out :
1029 port->it_in;
1030
1031 cs=splclock();
1032 setwin(sc,0);
1033 port->imodem=bc->mstat;
1034 bc->rout=bc->rin; /* clear input queue */
1035 bc->idata=1;
1036#ifdef PRINT_BUFSIZE
1037 printf("dgb buffers tx=%x:%x rx=%x:%x\n",bc->tseg,bc->tmax,bc->rseg,bc->rmax);
1038#endif
1039
1040 hidewin(sc);
1041 splx(cs);
1042
1043 port->wopeners++;
1044 error=dgbparam(tp, &tp->t_termios);
1045 port->wopeners--;
1046
1047 if(error!=0) {
1048 DPRINT4(DB_OPEN,"dgb%d: port%d: dgbparam error=%d\n",unit,pnum,error);
1049 goto out;
1050 }
1051
1052 /* handle fake DCD for callout devices */
1053 /* and initial DCD */
1054
1055 if( (port->imodem & port->dcd) || mynor & CALLOUT_MASK )
1056 linesw[tp->t_line].l_modem(tp,1);
1057
1058 }
1059
1060 /*
1061 * Wait for DCD if necessary.
1062 */
1063 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1064 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1065 ++port->wopeners;
377d4740 1066 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
984263bc
MD
1067 --port->wopeners;
1068 if (error != 0) {
1069 DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgdcd) error=%d\n",unit,pnum,error);
1070 goto out;
1071 }
1072 splx(s);
1073 goto open_top;
1074 }
1075 error = linesw[tp->t_line].l_open(dev, tp);
1076 disc_optim(tp,&tp->t_termios);
1077 DPRINT4(DB_OPEN,"dgb%d: port%d: l_open error=%d\n",unit,pnum,error);
1078
1079 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1080 port->active_out = TRUE;
1081
1082 port->used=1;
1083
1084 /* If any port is open (i.e. the open() call is completed for it)
1085 * the device is busy
1086 */
1087
1088out:
1089 disc_optim(tp,&tp->t_termios);
1090 splx(s);
1091
1092 if( !(tp->t_state & TS_ISOPEN) && port->wopeners==0 )
1093 dgbhardclose(port);
1094
1095 DPRINT4(DB_OPEN,"dgb%d: port%d: open() returns %d\n",unit,pnum,error);
1096
1097 return error;
1098}
1099
1100/*ARGSUSED*/
1101static int
dadab5e9 1102dgbclose(dev_t dev, int flag, int mode, struct thread *td)
984263bc 1103{
dadab5e9 1104 struct tty *tp;
984263bc
MD
1105 int unit, pnum;
1106 struct dgb_softc *sc;
1107 struct dgb_p *port;
dadab5e9 1108 int mynor;
984263bc
MD
1109 int s;
1110 int i;
1111
1112 mynor=minor(dev);
1113 if(mynor & CONTROL_MASK)
1114 return 0;
1115 unit=MINOR_TO_UNIT(mynor);
1116 pnum=MINOR_TO_PORT(mynor);
1117
1118 sc=&dgb_softc[unit];
1119 tp=&sc->ttys[pnum];
1120 port=sc->ports+pnum;
1121
1122 DPRINT3(DB_CLOSE,"dgb%d: port%d: closing\n",unit,pnum);
1123
1124 DPRINT3(DB_CLOSE,"dgb%d: port%d: draining port\n",unit,pnum);
1125 dgb_drain_or_flush(port);
1126
1127 s=spltty();
1128
1129 port->closing=1;
1130 DPRINT3(DB_CLOSE,"dgb%d: port%d: closing line disc\n",unit,pnum);
1131 linesw[tp->t_line].l_close(tp,flag);
1132 disc_optim(tp,&tp->t_termios);
1133
1134 DPRINT3(DB_CLOSE,"dgb%d: port%d: hard closing\n",unit,pnum);
1135 dgbhardclose(port);
1136 DPRINT3(DB_CLOSE,"dgb%d: port%d: closing tty\n",unit,pnum);
1137 ttyclose(tp);
1138 port->closing=0;
1139 wakeup(&port->closing);
1140 port->used=0;
1141
1142 /* mark the card idle when all ports are closed */
1143
1144 for(i=0; i<sc->numports; i++)
1145 if(sc->ports[i].used)
1146 break;
1147
1148 splx(s);
1149
1150 DPRINT3(DB_CLOSE,"dgb%d: port%d: closed\n",unit,pnum);
1151
1152 wakeup(TSA_CARR_ON(tp));
1153 wakeup(&port->active_out);
1154 port->active_out=0;
1155
1156 DPRINT3(DB_CLOSE,"dgb%d: port%d: close exit\n",unit,pnum);
1157
1158 return 0;
1159}
1160
1161static void
1162dgbhardclose(port)
1163 struct dgb_p *port;
1164{
1165 struct dgb_softc *sc=&dgb_softc[port->unit];
1166 volatile struct board_chan *bc=port->brdchan;
1167 int cs;
1168
1169 cs=splclock();
1170 port->do_timestamp = 0;
1171 setwin(sc,0);
1172
1173 bc->idata=0; bc->iempty=0; bc->ilow=0;
1174 if(port->tty->t_cflag & HUPCL) {
1175 port->omodem &= ~(RTS|DTR);
1176 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1177 }
1178
1179 hidewin(sc);
1180 splx(cs);
1181
1182 timeout(dgb_pause, &port->brdchan, hz/2);
377d4740 1183 tsleep(&port->brdchan, PCATCH, "dgclo", 0);
984263bc
MD
1184}
1185
1186static void
1187dgb_pause(chan)
1188 void *chan;
1189{
1190 wakeup((caddr_t)chan);
1191}
1192
1193static void
1194dgbpoll(unit_c)
1195 void *unit_c;
1196{
1197 int unit=(int)unit_c;
1198 int pnum;
1199 struct dgb_p *port;
1200 struct dgb_softc *sc=&dgb_softc[unit];
1201 int head, tail;
1202 u_char *eventbuf;
1203 int event, mstat, lstat;
1204 volatile struct board_chan *bc;
1205 struct tty *tp;
1206 int rhead, rtail;
1207 int whead, wtail;
1208 int size;
1209 u_char *ptr;
1210 int ocount;
1211 int ibuf_full,obuf_full;
1212
1213 BoardMemWinState ws=bmws_get();
1214
1215 if(sc->status==DISABLED) {
1216 printf("dgb%d: polling of disabled board stopped\n",unit);
1217 return;
1218 }
1219
1220 setwin(sc,0);
1221
1222 head=sc->mailbox->ein;
1223 tail=sc->mailbox->eout;
1224
1225 while(head!=tail) {
1226 if(head >= FEP_IMAX-FEP_ISTART
1227 || tail >= FEP_IMAX-FEP_ISTART
1228 || (head|tail) & 03 ) {
1229 printf("dgb%d: event queue's head or tail is wrong! hd=%d,tl=%d\n", unit,head,tail);
1230 break;
1231 }
1232
1233 eventbuf=sc->vmem+tail+FEP_ISTART;
1234 pnum=eventbuf[0];
1235 event=eventbuf[1];
1236 mstat=eventbuf[2];
1237 lstat=eventbuf[3];
1238
1239 port=&sc->ports[pnum];
1240 bc=port->brdchan;
1241 tp=&sc->ttys[pnum];
1242
1243 if(pnum>=sc->numports || port->status==DISABLED) {
1244 printf("dgb%d: port%d: got event on nonexisting port\n",unit,pnum);
1245 } else if(port->used || port->wopeners>0 ) {
1246
1247 int wrapmask=port->rxbufsize-1;
1248
1249 if( !(event & ALL_IND) )
1250 printf("dgb%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1251 unit, pnum, event, mstat, lstat);
1252
1253 if(event & DATA_IND) {
1254 DPRINT3(DB_DATA,"dgb%d: port%d: DATA_IND\n",unit,pnum);
1255
1256 rhead=bc->rin & wrapmask;
1257 rtail=bc->rout & wrapmask;
1258
1259 if( !(tp->t_cflag & CREAD) || !port->used ) {
1260 bc->rout=rhead;
1261 goto end_of_data;
1262 }
1263
1264 if(bc->orun) {
1265 printf("dgb%d: port%d: overrun\n", unit, pnum);
1266 bc->orun=0;
1267 }
1268
1269 if(!(tp->t_state & TS_ISOPEN))
1270 goto end_of_data;
1271
1272 for(ibuf_full=FALSE;rhead!=rtail && !ibuf_full;) {
1273 DPRINT5(DB_RXDATA,"dgb%d: port%d: p rx head=%d tail=%d\n",
1274 unit,pnum,rhead,rtail);
1275
1276 if(rhead>rtail)
1277 size=rhead-rtail;
1278 else
1279 size=port->rxbufsize-rtail;
1280
1281 ptr=port->rxptr+rtail;
1282
1283/* Helg: */
1284 if( tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1285 size=DGB_IBUFSIZE-tp->t_rawq.c_cc;
1286 DPRINT1(DB_RXDATA,"*");
1287 ibuf_full=TRUE;
1288 }
1289
1290 if(size) {
1291 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1292 DPRINT1(DB_RXDATA,"!");
1293 towin(sc,port->rxwin);
1294 tk_nin += size;
1295 tk_rawcc += size;
1296 tp->t_rawcc += size;
1297 b_to_q(ptr,size,&tp->t_rawq);
1298 setwin(sc,0);
1299 } else {
1300 int i=size;
1301 unsigned char chr;
1302 do {
1303 towin(sc,port->rxwin);
1304 chr= *ptr++;
1305 hidewin(sc);
1306 (*linesw[tp->t_line].l_rint)(chr, tp);
1307 } while (--i > 0 );
1308 setwin(sc,0);
1309 }
1310 }
1311 rtail= (rtail + size) & wrapmask;
1312 bc->rout=rtail;
1313 rhead=bc->rin & wrapmask;
1314 hidewin(sc);
1315 ttwakeup(tp);
1316 setwin(sc,0);
1317 }
1318 end_of_data: ;
1319 }
1320
1321 if(event & MODEMCHG_IND) {
1322 DPRINT3(DB_MODEM,"dgb%d: port%d: MODEMCHG_IND\n",unit,pnum);
1323 port->imodem=mstat;
1324 if(mstat & port->dcd) {
1325 hidewin(sc);
1326 linesw[tp->t_line].l_modem(tp,1);
1327 setwin(sc,0);
1328 wakeup(TSA_CARR_ON(tp));
1329 } else {
1330 hidewin(sc);
1331 linesw[tp->t_line].l_modem(tp,0);
1332 setwin(sc,0);
1333 if( port->draining) {
1334 port->draining=0;
1335 wakeup(&port->draining);
1336 }
1337 }
1338 }
1339
1340 if(event & BREAK_IND) {
1341 if((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1342 DPRINT3(DB_BREAK,"dgb%d: port%d: BREAK_IND\n",unit,pnum);
1343 hidewin(sc);
1344 linesw[tp->t_line].l_rint(TTY_BI, tp);
1345 setwin(sc,0);
1346 }
1347 }
1348
1349/* Helg: with output flow control */
1350
1351 if(event & (LOWTX_IND | EMPTYTX_IND) ) {
1352 DPRINT3(DB_TXDATA,"dgb%d: port%d: LOWTX_IND or EMPTYTX_IND\n",unit,pnum);
1353
1354 if( (event & EMPTYTX_IND ) && tp->t_outq.c_cc==0
1355 && port->draining) {
1356 port->draining=0;
1357 wakeup(&port->draining);
1358 bc->ilow=0; bc->iempty=0;
1359 } else {
1360
1361 int wrapmask=port->txbufsize-1;
1362
1363 for(obuf_full=FALSE; tp->t_outq.c_cc!=0 && !obuf_full; ) {
1364 int s;
1365 /* add "last-minute" data to write buffer */
1366 if(!(tp->t_state & TS_BUSY)) {
1367 hidewin(sc);
1368#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1369 ttwwakeup(tp);
1370#else
1371 if(tp->t_outq.c_cc <= tp->t_lowat) {
1372 if(tp->t_state & TS_ASLEEP) {
1373 tp->t_state &= ~TS_ASLEEP;
1374 wakeup(TSA_OLOWAT(tp));
1375 }
1376 /* selwakeup(&tp->t_wsel); */
1377 }
1378#endif
1379 setwin(sc,0);
1380 }
1381 s=spltty();
1382
1383 whead=bc->tin & wrapmask;
1384 wtail=bc->tout & wrapmask;
1385
1386 if(whead<wtail)
1387 size=wtail-whead-1;
1388 else {
1389 size=port->txbufsize-whead;
1390 if(wtail==0)
1391 size--;
1392 }
1393
1394 if(size==0) {
1395 DPRINT5(DB_WR,"dgb: head=%d tail=%d size=%d full=%d\n",
1396 whead,wtail,size,obuf_full);
1397 bc->iempty=1; bc->ilow=1;
1398 obuf_full=TRUE;
1399 splx(s);
1400 break;
1401 }
1402
1403 towin(sc,port->txwin);
1404
1405 ocount=q_to_b(&tp->t_outq, port->txptr+whead, size);
1406 whead+=ocount;
1407
1408 setwin(sc,0);
1409 bc->tin=whead;
1410 bc->tin=whead & wrapmask;
1411 splx(s);
1412 }
1413
1414 if(obuf_full) {
1415 DPRINT1(DB_WR," +BUSY\n");
1416 tp->t_state|=TS_BUSY;
1417 } else {
1418 DPRINT1(DB_WR," -BUSY\n");
1419 hidewin(sc);
1420#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1421 /* should clear TS_BUSY before ttwwakeup */
1422 if(tp->t_state & TS_BUSY) {
1423 tp->t_state &= ~TS_BUSY;
1424 linesw[tp->t_line].l_start(tp);
1425 ttwwakeup(tp);
1426 }
1427#else
1428 if(tp->t_state & TS_ASLEEP) {
1429 tp->t_state &= ~TS_ASLEEP;
1430 wakeup(TSA_OLOWAT(tp));
1431 }
1432 tp->t_state &= ~TS_BUSY;
1433#endif
1434 setwin(sc,0);
1435 }
1436 }
1437 }
1438 bc->idata=1; /* require event on incoming data */
1439
1440 } else {
1441 bc=port->brdchan;
1442 DPRINT4(DB_EXCEPT,"dgb%d: port%d: got event 0x%x on closed port\n",
1443 unit,pnum,event);
1444 bc->rout=bc->rin;
1445 bc->idata=bc->iempty=bc->ilow=0;
1446 }
1447
1448 tail= (tail+4) & (FEP_IMAX-FEP_ISTART-4);
1449 }
1450
1451 sc->mailbox->eout=tail;
1452 bmws_set(ws);
1453
1454 timeout(dgbpoll, unit_c, hz/POLLSPERSEC);
1455}
1456
1457static int
dadab5e9 1458dgbioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
984263bc
MD
1459{
1460 struct dgb_softc *sc;
1461 int unit, pnum;
1462 struct dgb_p *port;
1463 int mynor;
1464 struct tty *tp;
1465 volatile struct board_chan *bc;
1466 int error;
1467 int s,cs;
1468 int tiocm_xxx;
1469
1470#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1471 u_long oldcmd;
1472 struct termios term;
1473#endif
1474
1475 BoardMemWinState ws=bmws_get();
1476
1477 mynor=minor(dev);
1478 unit=MINOR_TO_UNIT(mynor);
1479 pnum=MINOR_TO_PORT(mynor);
1480
1481 sc=&dgb_softc[unit];
1482 port=&sc->ports[pnum];
1483 tp=&sc->ttys[pnum];
1484 bc=port->brdchan;
1485
1486 if (mynor & CONTROL_MASK) {
1487 struct termios *ct;
1488
1489 switch (mynor & CONTROL_MASK) {
1490 case CONTROL_INIT_STATE:
1491 ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1492 break;
1493 case CONTROL_LOCK_STATE:
1494 ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1495 break;
1496 default:
1497 return (ENODEV); /* /dev/nodev */
1498 }
1499 switch (cmd) {
1500 case TIOCSETA:
dadab5e9 1501 error = suser(td);
984263bc
MD
1502 if (error != 0)
1503 return (error);
1504 *ct = *(struct termios *)data;
1505 return (0);
1506 case TIOCGETA:
1507 *(struct termios *)data = *ct;
1508 return (0);
1509 case TIOCGETD:
1510 *(int *)data = TTYDISC;
1511 return (0);
1512 case TIOCGWINSZ:
1513 bzero(data, sizeof(struct winsize));
1514 return (0);
1515 default:
1516 return (ENOTTY);
1517 }
1518 }
1519
1520#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1521 term = tp->t_termios;
1522 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1523 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);
1524 }
1525 oldcmd = cmd;
1526 error = ttsetcompat(tp, &cmd, data, &term);
1527 if (error != 0)
1528 return (error);
1529 if (cmd != oldcmd)
1530 data = (caddr_t)&term;
1531#endif
1532
1533 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1534 int cc;
1535 struct termios *dt = (struct termios *)data;
1536 struct termios *lt = mynor & CALLOUT_MASK
1537 ? &port->lt_out : &port->lt_in;
1538
1539 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);
1540 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1541 | (dt->c_iflag & ~lt->c_iflag);
1542 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1543 | (dt->c_oflag & ~lt->c_oflag);
1544 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1545 | (dt->c_cflag & ~lt->c_cflag);
1546 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1547 | (dt->c_lflag & ~lt->c_lflag);
1548 for (cc = 0; cc < NCCS; ++cc)
1549 if (lt->c_cc[cc] != 0)
1550 dt->c_cc[cc] = tp->t_cc[cc];
1551 if (lt->c_ispeed != 0)
1552 dt->c_ispeed = tp->t_ispeed;
1553 if (lt->c_ospeed != 0)
1554 dt->c_ospeed = tp->t_ospeed;
1555 }
1556
1557 if(cmd==TIOCSTOP) {
1558 cs=splclock();
1559 setwin(sc,0);
1560 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1561 bmws_set(ws);
1562 splx(cs);
1563 return 0;
1564 } else if(cmd==TIOCSTART) {
1565 cs=splclock();
1566 setwin(sc,0);
1567 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1568 bmws_set(ws);
1569 splx(cs);
1570 return 0;
1571 }
1572
1573 if(cmd==TIOCSETAW || cmd==TIOCSETAF)
1574 port->mustdrain=1;
1575
7b95be2a 1576 error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, td);
984263bc
MD
1577 if (error != ENOIOCTL)
1578 return error;
1579 s = spltty();
1580 error = ttioctl(tp, cmd, data, flag);
1581 disc_optim(tp,&tp->t_termios);
1582 port->mustdrain=0;
1583 if (error != ENOIOCTL) {
1584 splx(s);
1585 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1586 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);
1587 }
1588 return error;
1589 }
1590
1591 switch (cmd) {
1592 case TIOCSBRK:
1593/* Helg: commented */
1594/* error=dgbdrain(port);*/
1595
1596 if(error!=0) {
1597 splx(s);
1598 return error;
1599 }
1600
1601 cs=splclock();
1602 setwin(sc,0);
1603
1604 /* now it sends 250 millisecond break because I don't know */
1605 /* how to send an infinite break */
1606
1607 fepcmd(port, SENDBREAK, 250, 0, 10, 0);
1608 hidewin(sc);
1609 splx(cs);
1610 break;
1611 case TIOCCBRK:
1612 /* now it's empty */
1613 break;
1614 case TIOCSDTR:
1615 DPRINT3(DB_MODEM,"dgb%d: port%d: set DTR\n",unit,pnum);
1616 port->omodem |= DTR;
1617 cs=splclock();
1618 setwin(sc,0);
1619 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1620
1621 if( !(bc->mstat & DTR) ) {
1622 DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is off\n",unit,pnum);
1623 }
1624
1625 hidewin(sc);
1626 splx(cs);
1627 break;
1628 case TIOCCDTR:
1629 DPRINT3(DB_MODEM,"dgb%d: port%d: reset DTR\n",unit,pnum);
1630 port->omodem &= ~DTR;
1631 cs=splclock();
1632 setwin(sc,0);
1633 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1634
1635 if( bc->mstat & DTR ) {
1636 DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is on\n",unit,pnum);
1637 }
1638
1639 hidewin(sc);
1640 splx(cs);
1641 break;
1642 case TIOCMSET:
1643 if(*(int *)data & TIOCM_DTR)
1644 port->omodem |=DTR;
1645 else
1646 port->omodem &=~DTR;
1647
1648 if(*(int *)data & TIOCM_RTS)
1649 port->omodem |=RTS;
1650 else
1651 port->omodem &=~RTS;
1652
1653 cs=splclock();
1654 setwin(sc,0);
1655 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1656 hidewin(sc);
1657 splx(cs);
1658 break;
1659 case TIOCMBIS:
1660 if(*(int *)data & TIOCM_DTR)
1661 port->omodem |=DTR;
1662
1663 if(*(int *)data & TIOCM_RTS)
1664 port->omodem |=RTS;
1665
1666 cs=splclock();
1667 setwin(sc,0);
1668 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1669 hidewin(sc);
1670 splx(cs);
1671 break;
1672 case TIOCMBIC:
1673 if(*(int *)data & TIOCM_DTR)
1674 port->omodem &=~DTR;
1675
1676 if(*(int *)data & TIOCM_RTS)
1677 port->omodem &=~RTS;
1678
1679 cs=splclock();
1680 setwin(sc,0);
1681 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1682 hidewin(sc);
1683 splx(cs);
1684 break;
1685 case TIOCMGET:
1686 setwin(sc,0);
1687 port->imodem=bc->mstat;
1688 hidewin(sc);
1689
1690 tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
1691
1692 DPRINT3(DB_MODEM,"dgb%d: port%d: modem stat -- ",unit,pnum);
1693
1694 if (port->imodem & DTR) {
1695 DPRINT1(DB_MODEM,"DTR ");
1696 tiocm_xxx |= TIOCM_DTR;
1697 }
1698 if (port->imodem & RTS) {
1699 DPRINT1(DB_MODEM,"RTS ");
1700 tiocm_xxx |= TIOCM_RTS;
1701 }
1702 if (port->imodem & CTS) {
1703 DPRINT1(DB_MODEM,"CTS ");
1704 tiocm_xxx |= TIOCM_CTS;
1705 }
1706 if (port->imodem & port->dcd) {
1707 DPRINT1(DB_MODEM,"DCD ");
1708 tiocm_xxx |= TIOCM_CD;
1709 }
1710 if (port->imodem & port->dsr) {
1711 DPRINT1(DB_MODEM,"DSR ");
1712 tiocm_xxx |= TIOCM_DSR;
1713 }
1714 if (port->imodem & RI) {
1715 DPRINT1(DB_MODEM,"RI ");
1716 tiocm_xxx |= TIOCM_RI;
1717 }
1718 *(int *)data = tiocm_xxx;
1719 DPRINT1(DB_MODEM,"--\n");
1720 break;
1721 case TIOCMSDTRWAIT:
1722 /* must be root since the wait applies to following logins */
dadab5e9 1723 error = suser(td);
984263bc
MD
1724 if (error != 0) {
1725 splx(s);
1726 return (error);
1727 }
1728 port->close_delay = *(int *)data * hz / 100;
1729 break;
1730 case TIOCMGDTRWAIT:
1731 *(int *)data = port->close_delay * 100 / hz;
1732 break;
1733 case TIOCTIMESTAMP:
1734 port->do_timestamp = TRUE;
1735 *(struct timeval *)data = port->timestamp;
1736 break;
1737 case TIOCDCDTIMESTAMP:
1738 port->do_dcd_timestamp = TRUE;
1739 *(struct timeval *)data = port->dcd_timestamp;
1740 break;
1741 default:
1742 bmws_set(ws);
1743 splx(s);
1744 return ENOTTY;
1745 }
1746 bmws_set(ws);
1747 splx(s);
1748
1749 return 0;
1750}
1751
1752static void
1753wakeflush(p)
1754 void *p;
1755{
1756 struct dgb_p *port=p;
1757
1758 wakeup(&port->draining);
1759}
1760
1761/* wait for the output to drain */
1762
1763static int
1764dgbdrain(port)
1765 struct dgb_p *port;
1766{
1767 struct dgb_softc *sc=&dgb_softc[port->unit];
1768 volatile struct board_chan *bc=port->brdchan;
1769 int error;
1770 int head, tail;
1771
1772 BoardMemWinState ws=bmws_get();
1773
1774 setwin(sc,0);
1775
1776 bc->iempty=1;
1777 tail=bc->tout;
1778 head=bc->tin;
1779
1780 while(tail!=head) {
1781 DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
1782 port->unit, port->pnum, head, tail);
1783
1784 hidewin(sc);
1785 port->draining=1;
1786 timeout(wakeflush,port, hz);
377d4740 1787 error=tsleep(&port->draining, PCATCH, "dgdrn", 0);
984263bc
MD
1788 port->draining=0;
1789 setwin(sc,0);
1790
1791 if (error != 0) {
1792 DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgdrn) error=%d\n",
1793 port->unit,port->pnum,error);
1794
1795 bc->iempty=0;
1796 bmws_set(ws);
1797 return error;
1798 }
1799
1800 tail=bc->tout;
1801 head=bc->tin;
1802 }
1803 DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
1804 port->unit, port->pnum, head, tail);
1805 bmws_set(ws);
1806 return 0;
1807}
1808
1809/* wait for the output to drain */
1810/* or simply clear the buffer it it's stopped */
1811
1812static void
1813dgb_drain_or_flush(port)
1814 struct dgb_p *port;
1815{
1816 struct tty *tp=port->tty;
1817 struct dgb_softc *sc=&dgb_softc[port->unit];
1818 volatile struct board_chan *bc=port->brdchan;
1819 int error;
1820 int lasttail;
1821 int head, tail;
1822
1823 setwin(sc,0);
1824
1825 lasttail=-1;
1826 bc->iempty=1;
1827 tail=bc->tout;
1828 head=bc->tin;
1829
1830 while(tail!=head /* && tail!=lasttail */ ) {
1831 DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
1832 port->unit, port->pnum, head, tail);
1833
1834 /* if there is no carrier simply clean the buffer */
1835 if( !(tp->t_state & TS_CARR_ON) ) {
1836 bc->tout=bc->tin=0;
1837 bc->iempty=0;
1838 hidewin(sc);
1839 return;
1840 }
1841
1842 hidewin(sc);
1843 port->draining=1;
1844 timeout(wakeflush,port, hz);
377d4740 1845 error=tsleep(&port->draining, PCATCH, "dgfls", 0);
984263bc
MD
1846 port->draining=0;
1847 setwin(sc,0);
1848
1849 if (error != 0) {
1850 DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgfls) error=%d\n",
1851 port->unit,port->pnum,error);
1852
1853 /* silently clean the buffer */
1854
1855 bc->tout=bc->tin=0;
1856 bc->iempty=0;
1857 hidewin(sc);
1858 return;
1859 }
1860
1861 lasttail=tail;
1862 tail=bc->tout;
1863 head=bc->tin;
1864 }
1865 hidewin(sc);
1866 DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
1867 port->unit, port->pnum, head, tail);
1868}
1869
1870static int
1871dgbparam(tp, t)
1872 struct tty *tp;
1873 struct termios *t;
1874{
1875 int unit=MINOR_TO_UNIT(minor(tp->t_dev));
1876 int pnum=MINOR_TO_PORT(minor(tp->t_dev));
1877 struct dgb_softc *sc=&dgb_softc[unit];
1878 struct dgb_p *port=&sc->ports[pnum];
1879 volatile struct board_chan *bc=port->brdchan;
1880 int cflag;
1881 int head;
1882 int mval;
1883 int iflag;
1884 int hflow;
1885 int cs;
1886
1887 BoardMemWinState ws=bmws_get();
1888
1889 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);
1890
1891 if(port->mustdrain) {
1892 DPRINT3(DB_PARAM,"dgb%d: port%d: must call dgbdrain()\n",unit,pnum);
1893 dgbdrain(port);
1894 }
1895
1896 cflag=ttspeedtab(t->c_ospeed, dgbspeedtab);
1897
1898 if (t->c_ispeed == 0)
1899 t->c_ispeed = t->c_ospeed;
1900
1901 if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1902 DPRINT4(DB_PARAM,"dgb%d: port%d: invalid cflag=0%o\n",unit,pnum,cflag);
1903 return (EINVAL);
1904 }
1905
1906 cs=splclock();
1907 setwin(sc,0);
1908
1909 if(cflag==0) { /* hangup */
1910 DPRINT3(DB_PARAM,"dgb%d: port%d: hangup\n",unit,pnum);
1911 head=bc->rin;
1912 bc->rout=head;
1913 head=bc->tin;
1914 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1915 mval= port->omodem & ~(DTR|RTS);
1916 } else {
1917 cflag |= dgbflags(dgb_cflags, t->c_cflag);
1918
1919 if(cflag!=port->fepcflag) {
1920 port->fepcflag=cflag;
1921 DPRINT5(DB_PARAM,"dgb%d: port%d: set cflag=0x%x c=0x%x\n",
1922 unit,pnum,cflag,t->c_cflag&~CRTSCTS);
1923 fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1924 }
1925 mval= port->omodem | (DTR|RTS);
1926 }
1927
1928 iflag=dgbflags(dgb_iflags, t->c_iflag);
1929 if(iflag!=port->fepiflag) {
1930 port->fepiflag=iflag;
1931 DPRINT5(DB_PARAM,"dgb%d: port%d: set iflag=0x%x c=0x%x\n",unit,pnum,iflag,t->c_iflag);
1932 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1933 }
1934
1935 bc->mint=port->dcd;
1936
1937 hflow=dgbflags(dgb_flow, t->c_cflag);
1938 if(hflow!=port->hflow) {
1939 port->hflow=hflow;
1940 DPRINT5(DB_PARAM,"dgb%d: port%d: set hflow=0x%x f=0x%x\n",unit,pnum,hflow,t->c_cflag&CRTSCTS);
1941 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1942 }
1943
1944 if(port->omodem != mval) {
1945 DPRINT5(DB_PARAM,"dgb%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1946 unit,pnum,mval,port->omodem);
1947 port->omodem=mval;
1948 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1949 }
1950
1951 if(port->fepstartc!=t->c_cc[VSTART] || port->fepstopc!=t->c_cc[VSTOP]) {
1952 DPRINT5(DB_PARAM,"dgb%d: port%d: set startc=%d, stopc=%d\n",unit,pnum,t->c_cc[VSTART],t->c_cc[VSTOP]);
1953 port->fepstartc=t->c_cc[VSTART];
1954 port->fepstopc=t->c_cc[VSTOP];
1955 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1956 }
1957
1958 bmws_set(ws);
1959 splx(cs);
1960
1961 return 0;
1962
1963}
1964
1965static void
1966dgbstart(tp)
1967 struct tty *tp;
1968{
1969 int unit;
1970 int pnum;
1971 struct dgb_p *port;
1972 struct dgb_softc *sc;
1973 volatile struct board_chan *bc;
1974 int head, tail;
1975 int size, ocount;
1976 int s;
1977 int wmask;
1978
1979 BoardMemWinState ws=bmws_get();
1980
1981 unit=MINOR_TO_UNIT(minor(tp->t_dev));
1982 pnum=MINOR_TO_PORT(minor(tp->t_dev));
1983 sc=&dgb_softc[unit];
1984 port=&sc->ports[pnum];
1985 bc=port->brdchan;
1986
1987 wmask=port->txbufsize-1;
1988
1989 s=spltty();
1990
1991 while( tp->t_outq.c_cc!=0 ) {
1992 int cs;
1993#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
1994 ttwwakeup(tp);
1995#else
1996 if(tp->t_outq.c_cc <= tp->t_lowat) {
1997 if(tp->t_state & TS_ASLEEP) {
1998 tp->t_state &= ~TS_ASLEEP;
1999 wakeup(TSA_OLOWAT(tp));
2000 }
2001 /*selwakeup(&tp->t_wsel);*/
2002 }
2003#endif
2004 cs=splclock();
2005 setwin(sc,0);
2006
2007 head=bc->tin & wmask;
2008
2009 do { tail=bc->tout; } while (tail != bc->tout);
2010 tail=bc->tout & wmask;
2011
2012 DPRINT5(DB_WR,"dgb%d: port%d: s tx head=%d tail=%d\n",unit,pnum,head,tail);
2013
2014#ifdef LEAVE_FREE_CHARS
2015 if(tail>head) {
2016 size=tail-head-LEAVE_FREE_CHARS;
2017 if (size <0)
2018 size=0;
2019 } else {
2020 size=port->txbufsize-head;
2021 if(tail+port->txbufsize < head)
2022 size=0;
2023 }
2024 }
2025#else
2026 if(tail>head)
2027 size=tail-head-1;
2028 else {
2029 size=port->txbufsize-head/*-1*/;
2030 if(tail==0)
2031 size--;
2032 }
2033#endif
2034
2035 if(size==0) {
2036 bc->iempty=1; bc->ilow=1;
2037 splx(cs);
2038 bmws_set(ws);
2039 tp->t_state|=TS_BUSY;
2040 splx(s);
2041 return;
2042 }
2043
2044 towin(sc,port->txwin);
2045
2046 ocount=q_to_b(&tp->t_outq, port->txptr+head, size);
2047 head+=ocount;
2048 if(head>=port->txbufsize)
2049 head-=port->txbufsize;
2050
2051 setwin(sc,0);
2052 bc->tin=head;
2053
2054 DPRINT5(DB_WR,"dgb%d: port%d: tx avail=%d count=%d\n",unit,pnum,size,ocount);
2055 hidewin(sc);
2056 splx(cs);
2057 }
2058
2059 bmws_set(ws);
2060 splx(s);
2061
2062#ifndef TS_ASLEEP /* post 2.0.5 FreeBSD */
2063 if(tp->t_state & TS_BUSY) {
2064 tp->t_state&=~TS_BUSY;
2065 linesw[tp->t_line].l_start(tp);
2066 ttwwakeup(tp);
2067 }
2068#else
2069 if(tp->t_state & TS_ASLEEP) {
2070 tp->t_state &= ~TS_ASLEEP;
2071 wakeup(TSA_OLOWAT(tp));
2072 }
2073 tp->t_state&=~TS_BUSY;
2074#endif
2075}
2076
2077void
2078dgbstop(tp, rw)
2079 struct tty *tp;
2080 int rw;
2081{
2082 int unit;
2083 int pnum;
2084 struct dgb_p *port;
2085 struct dgb_softc *sc;
2086 volatile struct board_chan *bc;
2087 int s;
2088
2089 BoardMemWinState ws=bmws_get();
2090
2091 unit=MINOR_TO_UNIT(minor(tp->t_dev));
2092 pnum=MINOR_TO_PORT(minor(tp->t_dev));
2093
2094 sc=&dgb_softc[unit];
2095 port=&sc->ports[pnum];
2096 bc=port->brdchan;
2097
2098 DPRINT3(DB_WR,"dgb%d: port%d: stop\n",port->unit, port->pnum);
2099
2100 s = spltty();
2101 setwin(sc,0);
2102
2103 if (rw & FWRITE) {
2104 /* clear output queue */
2105 bc->tout=bc->tin=0;
2106 bc->ilow=0;bc->iempty=0;
2107 }
2108 if (rw & FREAD) {
2109 /* clear input queue */
2110 bc->rout=bc->rin;
2111 bc->idata=1;
2112 }
2113 hidewin(sc);
2114 bmws_set(ws);
2115 splx(s);
2116 dgbstart(tp);
2117}
2118
2119static void
2120fepcmd(port, cmd, op1, op2, ncmds, bytecmd)
2121 struct dgb_p *port;
2122 unsigned cmd, op1, op2, ncmds, bytecmd;
2123{
2124 struct dgb_softc *sc=&dgb_softc[port->unit];
2125 u_char *mem=sc->vmem;
2126 unsigned tail, head;
2127 int count, n;
2128
2129 if(port->status==DISABLED) {
2130 printf("dgb%d: port%d: FEP command on disabled port\n",
2131 port->unit, port->pnum);
2132 return;
2133 }
2134
2135 /* setwin(sc,0); Require this to be set by caller */
2136 head=sc->mailbox->cin;
2137
2138 if(head>=(FEP_CMAX-FEP_CSTART) || (head & 3)) {
2139 printf("dgb%d: port%d: wrong pointer head of command queue : 0x%x\n",
2140 port->unit, port->pnum, head);
2141 return;
2142 }
2143
2144 mem[head+FEP_CSTART+0]=cmd;
2145 mem[head+FEP_CSTART+1]=port->pnum;
2146 if(bytecmd) {
2147 mem[head+FEP_CSTART+2]=op1;
2148 mem[head+FEP_CSTART+3]=op2;
2149 } else {
2150 mem[head+FEP_CSTART+2]=op1&0xff;
2151 mem[head+FEP_CSTART+3]=(op1>>8)&0xff;
2152 }
2153
2154 DPRINT7(DB_FEP,"dgb%d: port%d: %s cmd=0x%x op1=0x%x op2=0x%x\n", port->unit, port->pnum,
2155 (bytecmd)?"byte":"word", cmd, mem[head+FEP_CSTART+2], mem[head+FEP_CSTART+3]);
2156
2157 head=(head+4) & (FEP_CMAX-FEP_CSTART-4);
2158 sc->mailbox->cin=head;
2159
2160 count=FEPTIMEOUT;
2161
2162 while (count-- != 0) {
2163 head=sc->mailbox->cin;
2164 tail=sc->mailbox->cout;
2165
2166 n = (head-tail) & (FEP_CMAX-FEP_CSTART-4);
2167 if(n <= ncmds * (sizeof(ushort)*4))
2168 return;
2169 }
2170 printf("dgb%d(%d): timeout on FEP cmd=0x%x\n", port->unit, port->pnum, cmd);
2171}
2172
2173static void
2174disc_optim(tp, t)
2175 struct tty *tp;
2176 struct termios *t;
2177{
2178 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2179 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2180 && (!(t->c_iflag & PARMRK)
2181 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2182 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2183 && linesw[tp->t_line].l_rint == ttyinput)
2184 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2185 else
2186 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2187}