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