Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / gnu / isa / dgb.c
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 $
3  *
4  *  Digiboard driver.
5  *
6  *  Stage 1. "Better than nothing".
7  *  Stage 2. "Gee, it works!".
8  *
9  *  Based on sio driver by Bruce Evans and on Linux driver by Troy 
10  *  De Jongh <troyd@digibd.com> or <troyd@skypoint.com> 
11  *  which is under GNU General Public License version 2 so this driver 
12  *  is forced to be under GPL 2 too.
13  *
14  *  Written by Serge Babkin,
15  *      Joint Stock Commercial Bank "Chelindbank"
16  *      (Chelyabinsk, Russia)
17  *      babkin@hq.icb.chel.su
18  *
19  *  Assorted hacks to make it more functional and working under 3.0-current.
20  *  Fixed broken routines to prevent processes hanging on closed (thanks
21  *  to Bruce for his patience and assistance). Thanks also to Maxim Bolotin
22  *  <max@run.net> for his patches which did most of the work to get this
23  *  running under 2.2/3.0-current.
24  *  Implemented ioctls: TIOCMSDTRWAIT, TIOCMGDTRWAIT, TIOCTIMESTAMP &
25  *  TIOCDCDTIMESTAMP.
26  *  Sysctl debug flag is now a bitflag, to filter noise during debugging.
27  *      David L. Nugent <davidn@blaze.net.au>
28  */
29
30 #include "opt_compat.h"
31 #include "opt_dgb.h"
32
33 #include "dgb.h"
34
35 /* Helg: i.e.25 times per sec board will be polled */
36 #define POLLSPERSEC 25
37 /* How many charactes can we write to input tty rawq */
38 #define DGB_IBUFSIZE (TTYHOG-100)
39
40 /* the overall number of ports controlled by this driver */
41
42 #ifndef NDGBPORTS
43 #       define NDGBPORTS (NDGB*16)
44 #endif
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/tty.h>
49 #include <sys/proc.h>
50 #include <sys/conf.h>
51 #include <sys/dkstat.h>
52 #include <sys/fcntl.h>
53 #include <sys/kernel.h>
54 #include <sys/sysctl.h>
55
56 #include <machine/clock.h>
57
58 #include <vm/vm.h>
59 #include <vm/pmap.h>
60
61 #include <i386/isa/isa_device.h>
62
63 #include <gnu/i386/isa/dgbios.h>
64 #include <gnu/i386/isa/dgfep.h>
65
66 #define DGB_DEBUG               /* Enable debugging info via sysctl */
67 #include <gnu/i386/isa/dgreg.h>
68
69 #define CALLOUT_MASK            0x80
70 #define CONTROL_MASK            0x60
71 #define CONTROL_INIT_STATE      0x20
72 #define CONTROL_LOCK_STATE      0x40
73 #define UNIT_MASK                       0x30000
74 #define PORT_MASK                       0x1F
75 #define DEV_TO_UNIT(dev)        (MINOR_TO_UNIT(minor(dev)))
76 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
77 #define MINOR_TO_UNIT(mynor)    (((mynor) & UNIT_MASK)>>16)
78 #define MINOR_TO_PORT(mynor)    ((mynor) & PORT_MASK)
79
80 /* types.  XXX - should be elsewhere */
81 typedef u_char  bool_t;         /* boolean */
82
83 /* digiboard port structure */
84 struct dgb_p {
85         bool_t  status;
86
87         u_char unit;           /* board unit number */
88         u_char pnum;           /* port number */
89         u_char omodem;         /* FEP output modem status     */
90         u_char imodem;         /* FEP input modem status      */
91         u_char modemfake;      /* Modem values to be forced   */
92         u_char modem;          /* Force values                */
93         u_char hflow;
94         u_char dsr;
95         u_char dcd;
96         u_char stopc;
97         u_char startc;
98         u_char stopca;
99         u_char startca;
100         u_char fepstopc;
101         u_char fepstartc;
102         u_char fepstopca;
103         u_char fepstartca;
104         u_char txwin;
105         u_char rxwin;
106         ushort fepiflag;
107         ushort fepcflag;
108         ushort fepoflag;
109         ushort txbufhead;
110         ushort txbufsize;
111         ushort rxbufhead;
112         ushort rxbufsize;
113         int close_delay;
114         int count;
115         int blocked_open;
116         int event;
117         int asyncflags;
118         u_long statusflags;
119         u_char *txptr;
120         u_char *rxptr;
121         volatile struct board_chan *brdchan;
122         struct tty *tty;
123
124         bool_t  active_out;     /* nonzero if the callout device is open */
125         u_int   wopeners;       /* # processes waiting for DCD in open() */
126
127         /* Initial state. */
128         struct termios  it_in;  /* should be in struct tty */
129         struct termios  it_out;
130
131         /* Lock state. */
132         struct termios  lt_in;  /* should be in struct tty */
133         struct termios  lt_out;
134
135         bool_t  do_timestamp;
136         bool_t  do_dcd_timestamp;
137         struct timeval  timestamp;
138         struct timeval  dcd_timestamp;
139
140         /* flags of state, are used in sleep() too */
141         u_char closing; /* port is being closed now */
142         u_char draining; /* port is being drained now */
143         u_char used;    /* port is being used now */
144         u_char mustdrain; /* data must be waited to drain in dgbparam() */
145 };
146
147 /* Digiboard per-board structure */
148 struct dgb_softc {
149         /* struct board_info */
150         u_char status;  /* status: DISABLED/ENABLED */
151         u_char unit;    /* unit number */
152         u_char type;    /* type of card: PCXE, PCXI, PCXEVE */
153         u_char altpin;  /* do we need alternate pin setting ? */
154         int numports;   /* number of ports on card */
155         int port;       /* I/O port */
156         u_char *vmem; /* virtual memory address */
157         long pmem; /* physical memory address */
158         int mem_seg;  /* internal memory segment */
159         struct dgb_p *ports;    /* pointer to array of port descriptors */
160         struct tty *ttys;       /* pointer to array of TTY structures */
161         volatile struct global_data *mailbox;
162         };
163         
164
165 static struct dgb_softc dgb_softc[NDGB];
166 static struct dgb_p dgb_ports[NDGBPORTS];
167 static struct tty dgb_tty[NDGBPORTS];
168
169 /*
170  * The public functions in the com module ought to be declared in a com-driver
171  * system header.
172  */
173
174 /* Interrupt handling entry points. */
175 static void     dgbpoll         __P((void *unit_c));
176
177 /* Device switch entry points. */
178 #define dgbreset        noreset
179 #define dgbmmap         nommap
180 #define dgbstrategy     nostrategy
181
182 static  int     dgbattach       __P((struct isa_device *dev));
183 static  int     dgbprobe        __P((struct isa_device *dev));
184
185 static void fepcmd(struct dgb_p *port, unsigned cmd, unsigned op1, unsigned op2,
186         unsigned ncmds, unsigned bytecmd);
187
188 static  void    dgbstart        __P((struct tty *tp));
189 static  void    dgbstop         __P((struct tty *tp, int rw));
190 static  int     dgbparam        __P((struct tty *tp, struct termios *t));
191 static  void    dgbhardclose    __P((struct dgb_p *port));
192 static  void    dgb_drain_or_flush      __P((struct dgb_p *port));
193 static  int     dgbdrain        __P((struct dgb_p *port));
194 static  void    dgb_pause       __P((void *chan));
195 static  void    wakeflush       __P((void *p));
196 static  void    disc_optim      __P((struct tty *tp, struct termios *t));
197
198
199 struct isa_driver       dgbdriver = {
200         dgbprobe, dgbattach, "dgb",0
201 };
202
203 static  d_open_t        dgbopen;
204 static  d_close_t       dgbclose;
205 static  d_ioctl_t       dgbioctl;
206
207 #define CDEV_MAJOR      58
208 static struct cdevsw dgb_cdevsw = {
209         /* open */      dgbopen,
210         /* close */     dgbclose,
211         /* read */      ttyread,
212         /* write */     ttywrite,
213         /* ioctl */     dgbioctl,
214         /* poll */      ttypoll,
215         /* mmap */      nommap,
216         /* strategy */  nostrategy,
217         /* name */      "dgb",
218         /* maj */       CDEV_MAJOR,
219         /* dump */      nodump,
220         /* psize */     nopsize,
221         /* flags */     D_TTY | D_KQFILTER,
222         /* bmaj */      -1,
223         /* kqfilter */  ttykqfilter,
224 };
225
226 static  speed_t dgbdefaultrate = TTYDEF_SPEED;
227
228 static  struct speedtab dgbspeedtab[] = {
229         0,      FEP_B0, /* old (sysV-like) Bx codes */
230         50,     FEP_B50,
231         75,     FEP_B75,
232         110,    FEP_B110,
233         134,    FEP_B134,
234         150,    FEP_B150,
235         200,    FEP_B200,
236         300,    FEP_B300,
237         600,    FEP_B600,
238         1200,   FEP_B1200,
239         1800,   FEP_B1800,
240         2400,   FEP_B2400,
241         4800,   FEP_B4800,
242         9600,   FEP_B9600,
243         19200,  FEP_B19200,
244         38400,  FEP_B38400,
245         57600,  (FEP_FASTBAUD|FEP_B50), /* B50 & fast baud table */
246         115200, (FEP_FASTBAUD|FEP_B110), /* B100 & fast baud table */
247         -1,     -1
248 };
249
250 static struct dbgflagtbl
251 {
252   tcflag_t in_mask;
253   tcflag_t in_val;
254   tcflag_t out_val;
255 } dgb_cflags[] =
256 {
257   { PARODD,   PARODD,     FEP_PARODD  },
258   { PARENB,   PARENB,     FEP_PARENB  },
259   { CSTOPB,   CSTOPB,     FEP_CSTOPB  },
260   { CSIZE,    CS5,        FEP_CS6     },
261   { CSIZE,    CS6,        FEP_CS6     },
262   { CSIZE,    CS7,        FEP_CS7     },
263   { CSIZE,    CS8,        FEP_CS8     },
264   { CLOCAL,   CLOCAL,     FEP_CLOCAL  },
265   { (tcflag_t)-1 }
266 }, dgb_iflags[] =
267 {
268   { IGNBRK,   IGNBRK,     FEP_IGNBRK  },
269   { BRKINT,   BRKINT,     FEP_BRKINT  },
270   { IGNPAR,   IGNPAR,     FEP_IGNPAR  },
271   { PARMRK,   PARMRK,     FEP_PARMRK  },
272   { INPCK,    INPCK,      FEP_INPCK   },
273   { ISTRIP,   ISTRIP,     FEP_ISTRIP  },
274   { IXON,     IXON,       FEP_IXON    },
275   { IXOFF,    IXOFF,      FEP_IXOFF   },
276   { IXANY,    IXANY,      FEP_IXANY   },
277   { (tcflag_t)-1 }
278 }, dgb_flow[] =
279 {
280   { CRTSCTS,  CRTSCTS,    CTS|RTS     },
281   { CRTSCTS,  CCTS_OFLOW, CTS         },
282   { CRTSCTS,  CRTS_IFLOW, RTS         },
283   { (tcflag_t)-1 }
284 };
285
286 /* xlat bsd termios flags to dgb sys-v style */
287 static tcflag_t
288 dgbflags(struct dbgflagtbl *tbl, tcflag_t input)
289 {
290   tcflag_t output = 0;
291   int i;
292
293   for (i=0; tbl[i].in_mask != (tcflag_t)-1; i++)
294   {
295     if ((input & tbl[i].in_mask) == tbl[i].in_val)
296       output |= tbl[i].out_val;
297   }
298   return output;
299 }
300
301 #ifdef DGB_DEBUG
302 static int dgbdebug=0;
303 SYSCTL_INT(_debug, OID_AUTO, dgb_debug, CTLFLAG_RW, &dgbdebug, 0, "");
304 #endif
305
306 static __inline int setwin __P((struct dgb_softc *sc, unsigned addr));
307 static __inline int setinitwin __P((struct dgb_softc *sc, unsigned addr));
308 static __inline void hidewin __P((struct dgb_softc *sc));
309 static __inline void towin __P((struct dgb_softc *sc, int win));
310
311 /*Helg: to allow recursive dgb...() calls */
312 typedef struct
313   {                 /* If we were called and don't want to disturb we need: */
314         int port;               /* write to this port */
315         u_char data;            /* this data on exit */
316                           /* or DATA_WINOFF  to close memory window on entry */
317   } BoardMemWinState; /* so several channels and even boards can coexist */
318 #define DATA_WINOFF 0
319 static BoardMemWinState bmws;
320
321 /* return current memory window state and close window */
322 static BoardMemWinState
323 bmws_get(void)
324 {
325         BoardMemWinState bmwsRet=bmws;
326         if(bmws.data!=DATA_WINOFF)
327                 outb(bmws.port, bmws.data=DATA_WINOFF);
328         return bmwsRet;
329 }
330
331 /* restore memory window state */
332 static void
333 bmws_set(BoardMemWinState ws)
334 {
335         if(ws.data != bmws.data || ws.port!=bmws.port ) {
336                 if(bmws.data!=DATA_WINOFF)
337                         outb(bmws.port,DATA_WINOFF);
338                 if(ws.data!=DATA_WINOFF)
339                         outb(ws.port, ws.data);
340                 bmws=ws;
341         }
342 }
343
344 static __inline int 
345 setwin(sc,addr)
346         struct dgb_softc *sc;
347         unsigned int addr;
348 {
349         if(sc->type==PCXEVE) {
350                 outb(bmws.port=sc->port+1, bmws.data=FEPWIN|(addr>>13));
351                 DPRINT3(DB_WIN,"dgb%d: switched to window 0x%x\n",sc->unit,addr>>13);
352                 return (addr & 0x1FFF);
353         } else {
354                 outb(bmws.port=sc->port,bmws.data=FEPMEM);
355                 return addr;
356         }
357 }
358
359 static __inline int 
360 setinitwin(sc,addr)
361         struct dgb_softc *sc;
362         unsigned int addr;
363 {
364         if(sc->type==PCXEVE) {
365                 outb(bmws.port=sc->port+1, bmws.data=FEPWIN|(addr>>13));
366                 DPRINT3(DB_WIN,"dgb%d: switched to window 0x%x\n",sc->unit,addr>>13);
367                 return (addr & 0x1FFF);
368         } else {
369                 outb(bmws.port=sc->port,bmws.data=inb(sc->port)|FEPMEM);
370                 return addr;
371         }
372 }
373
374 static __inline void
375 hidewin(sc)
376         struct dgb_softc *sc;
377 {
378         bmws.data=0;
379         if(sc->type==PCXEVE)
380                 outb(bmws.port=sc->port+1, bmws.data);
381         else
382                 outb(bmws.port=sc->port, bmws.data);
383 }
384
385 static __inline void
386 towin(sc,win)
387         struct dgb_softc *sc;
388         int win;
389 {
390         if(sc->type==PCXEVE) {
391                 outb(bmws.port=sc->port+1, bmws.data=win);
392         } else {
393                 outb(bmws.port=sc->port,bmws.data=FEPMEM);
394         }
395 }
396
397 static int
398 dgbprobe(dev)
399         struct isa_device       *dev;
400 {
401         struct dgb_softc *sc= &dgb_softc[dev->id_unit];
402         int i, v;
403         u_long win_size;  /* size of vizible memory window */
404         int unit=dev->id_unit;
405         static int once;
406
407         if (!once++)
408                 cdevsw_add(&dgb_cdevsw);
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
509 static int
510 dgbattach(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;
523         ushort *pstat;
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 : \
631 0x%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 : \
684 0x%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
727 load_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);
804         pstat=(ushort volatile *)(mem+addr);
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;
897                 make_dev(&dgb_cdevsw, (unit*32)+i,
898                     UID_ROOT, GID_WHEEL, 0600, "ttyD%d%c", unit, suffix);
899
900                 make_dev(&dgb_cdevsw, (unit*32)+i+32,
901                     UID_ROOT, GID_WHEEL, 0600, "ttyiD%d%c", unit, suffix);
902
903                 make_dev(&dgb_cdevsw, (unit*32)+i+64,
904                     UID_ROOT, GID_WHEEL, 0600, "ttylD%d%c", unit, suffix);
905
906                 make_dev(&dgb_cdevsw, (unit*32)+i+128,
907                     UID_UUCP, GID_DIALER, 0660, "cuaD%d%c", unit, suffix);
908
909                 make_dev(&dgb_cdevsw, (unit*32)+i+160,
910                     UID_UUCP, GID_DIALER, 0660, "cuaiD%d%c", unit, suffix);
911
912                 make_dev(&dgb_cdevsw, (unit*32)+i+192,
913                     UID_UUCP, GID_DIALER, 0660, "cualD%d%c", unit, suffix);
914         }
915
916         hidewin(sc);
917
918         /* register the polling function */
919         timeout(dgbpoll, (void *)unit, hz/POLLSPERSEC);
920
921         return 1;
922 }
923
924 /* ARGSUSED */
925 static  int
926 dgbopen(dev, flag, mode, p)
927         dev_t           dev;
928         int             flag;
929         int             mode;
930         struct proc     *p;
931 {
932         struct dgb_softc *sc;
933         struct tty *tp;
934         int unit;
935         int mynor;
936         int pnum;
937         struct dgb_p *port;
938         int s,cs;
939         int error;
940         volatile struct board_chan *bc;
941
942         error=0;
943
944         mynor=minor(dev);
945         unit=MINOR_TO_UNIT(mynor);
946         pnum=MINOR_TO_PORT(mynor);
947
948         if(unit >= NDGB) {
949                 DPRINT2(DB_EXCEPT,"dgb%d: try to open a nonexisting card\n",unit);
950                 return ENXIO;
951         }
952
953         sc=&dgb_softc[unit];
954
955         if(sc->status!=ENABLED) {
956                 DPRINT2(DB_EXCEPT,"dgb%d: try to open a disabled card\n",unit);
957                 return ENXIO;
958         }
959
960         if(pnum>=sc->numports) {
961                 DPRINT3(DB_EXCEPT,"dgb%d: try to open non-existing port %d\n",unit,pnum);
962                 return ENXIO;
963         }
964
965         if(mynor & CONTROL_MASK)
966                 return 0;
967
968         tp=&sc->ttys[pnum];
969         dev->si_tty = tp;
970         port=&sc->ports[pnum];
971         bc=port->brdchan;
972
973 open_top:
974         
975         s=spltty();
976
977         while(port->closing) {
978                 error=tsleep(&port->closing, TTOPRI|PCATCH, "dgocl", 0);
979
980                 if(error) {
981                         DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgocl) error=%d\n",unit,pnum,error);
982                         goto out;
983                 }
984         }
985
986         if (tp->t_state & TS_ISOPEN) {
987                 /*
988                  * The device is open, so everything has been initialized.
989                  * Handle conflicts.
990                  */
991                 if (mynor & CALLOUT_MASK) {
992                         if (!port->active_out) {
993                                 error = EBUSY;
994                                 DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
995                                 goto out;
996                         }
997                 } else {
998                         if (port->active_out) {
999                                 if (flag & O_NONBLOCK) {
1000                                         error = EBUSY;
1001                                         DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
1002                                         goto out;
1003                                 }
1004                                 error = tsleep(&port->active_out,
1005                                                TTIPRI | PCATCH, "dgbi", 0);
1006                                 if (error != 0) {
1007                                         DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgbi) error=%d\n",
1008                                                 unit,pnum,error);
1009                                         goto out;
1010                                 }
1011                                 splx(s);
1012                                 goto open_top;
1013                         }
1014                 }
1015                 if (tp->t_state & TS_XCLUDE &&
1016                     suser(p)) {
1017                         error = EBUSY;
1018                         goto out;
1019                 }
1020         } else {
1021                 /*
1022                  * The device isn't open, so there are no conflicts.
1023                  * Initialize it.  Initialization is done twice in many
1024                  * cases: to preempt sleeping callin opens if we are
1025                  * callout, and to complete a callin open after DCD rises.
1026                  */
1027                 tp->t_oproc=dgbstart;
1028                 tp->t_param=dgbparam;
1029                 tp->t_stop=dgbstop;
1030                 tp->t_dev=dev;
1031                 tp->t_termios= (mynor & CALLOUT_MASK) ?
1032                                                         port->it_out :
1033                                                         port->it_in;
1034
1035                 cs=splclock();
1036                 setwin(sc,0);
1037                 port->imodem=bc->mstat;
1038                 bc->rout=bc->rin; /* clear input queue */
1039                 bc->idata=1;
1040 #ifdef PRINT_BUFSIZE
1041                 printf("dgb buffers tx=%x:%x rx=%x:%x\n",bc->tseg,bc->tmax,bc->rseg,bc->rmax);
1042 #endif
1043
1044                 hidewin(sc);
1045                 splx(cs);
1046
1047                 port->wopeners++;
1048                 error=dgbparam(tp, &tp->t_termios);
1049                 port->wopeners--;
1050
1051                 if(error!=0) {
1052                         DPRINT4(DB_OPEN,"dgb%d: port%d: dgbparam error=%d\n",unit,pnum,error);
1053                         goto out;
1054                 }
1055
1056                 /* handle fake DCD for callout devices */
1057                 /* and initial DCD */
1058
1059                 if( (port->imodem & port->dcd) || mynor & CALLOUT_MASK )
1060                         linesw[tp->t_line].l_modem(tp,1);
1061
1062         }
1063
1064         /*
1065          * Wait for DCD if necessary.
1066          */
1067         if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1068             && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1069                 ++port->wopeners;
1070                 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "dgdcd", 0);
1071                 --port->wopeners;
1072                 if (error != 0) {
1073                         DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgdcd) error=%d\n",unit,pnum,error);
1074                         goto out;
1075                 }
1076                 splx(s);
1077                 goto open_top;
1078         }
1079         error = linesw[tp->t_line].l_open(dev, tp);
1080         disc_optim(tp,&tp->t_termios);
1081         DPRINT4(DB_OPEN,"dgb%d: port%d: l_open error=%d\n",unit,pnum,error);
1082
1083         if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1084                 port->active_out = TRUE;
1085
1086         port->used=1;
1087
1088         /* If any port is open (i.e. the open() call is completed for it) 
1089          * the device is busy
1090          */
1091
1092 out:
1093         disc_optim(tp,&tp->t_termios);
1094         splx(s);
1095
1096         if( !(tp->t_state & TS_ISOPEN) && port->wopeners==0 )
1097                 dgbhardclose(port);
1098
1099         DPRINT4(DB_OPEN,"dgb%d: port%d: open() returns %d\n",unit,pnum,error);
1100
1101         return error;
1102 }
1103
1104 /*ARGSUSED*/
1105 static  int
1106 dgbclose(dev, flag, mode, p)
1107         dev_t           dev;
1108         int             flag;
1109         int             mode;
1110         struct proc     *p;
1111 {
1112         int             mynor;
1113         struct tty      *tp;
1114         int unit, pnum;
1115         struct dgb_softc *sc;
1116         struct dgb_p *port;
1117         int s;
1118         int i;
1119
1120         mynor=minor(dev);
1121         if(mynor & CONTROL_MASK)
1122                 return 0;
1123         unit=MINOR_TO_UNIT(mynor);
1124         pnum=MINOR_TO_PORT(mynor);
1125
1126         sc=&dgb_softc[unit];
1127         tp=&sc->ttys[pnum];
1128         port=sc->ports+pnum;
1129
1130         DPRINT3(DB_CLOSE,"dgb%d: port%d: closing\n",unit,pnum);
1131
1132         DPRINT3(DB_CLOSE,"dgb%d: port%d: draining port\n",unit,pnum);
1133         dgb_drain_or_flush(port);
1134
1135         s=spltty();
1136
1137         port->closing=1;
1138         DPRINT3(DB_CLOSE,"dgb%d: port%d: closing line disc\n",unit,pnum);
1139         linesw[tp->t_line].l_close(tp,flag);
1140         disc_optim(tp,&tp->t_termios);
1141
1142         DPRINT3(DB_CLOSE,"dgb%d: port%d: hard closing\n",unit,pnum);
1143         dgbhardclose(port);
1144         DPRINT3(DB_CLOSE,"dgb%d: port%d: closing tty\n",unit,pnum);
1145         ttyclose(tp);
1146         port->closing=0;
1147         wakeup(&port->closing);
1148         port->used=0;
1149
1150         /* mark the card idle when all ports are closed */
1151
1152         for(i=0; i<sc->numports; i++)
1153                 if(sc->ports[i].used)
1154                         break;
1155
1156         splx(s);
1157
1158         DPRINT3(DB_CLOSE,"dgb%d: port%d: closed\n",unit,pnum);
1159
1160         wakeup(TSA_CARR_ON(tp));
1161         wakeup(&port->active_out);
1162         port->active_out=0;
1163
1164         DPRINT3(DB_CLOSE,"dgb%d: port%d: close exit\n",unit,pnum);
1165
1166         return 0;
1167 }
1168
1169 static void
1170 dgbhardclose(port)
1171         struct dgb_p *port;
1172 {
1173         struct dgb_softc *sc=&dgb_softc[port->unit];
1174         volatile struct board_chan *bc=port->brdchan;
1175         int cs;
1176
1177         cs=splclock();
1178         port->do_timestamp = 0;
1179         setwin(sc,0);
1180
1181         bc->idata=0; bc->iempty=0; bc->ilow=0;
1182         if(port->tty->t_cflag & HUPCL) {
1183                 port->omodem &= ~(RTS|DTR);
1184                 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1185         }
1186
1187         hidewin(sc);
1188         splx(cs);
1189
1190         timeout(dgb_pause, &port->brdchan, hz/2);
1191         tsleep(&port->brdchan, TTIPRI | PCATCH, "dgclo", 0);
1192 }
1193
1194 static void 
1195 dgb_pause(chan)
1196         void *chan;
1197 {
1198         wakeup((caddr_t)chan);
1199 }
1200
1201 static void
1202 dgbpoll(unit_c)
1203         void *unit_c;
1204 {
1205         int unit=(int)unit_c;
1206         int pnum;
1207         struct dgb_p *port;
1208         struct dgb_softc *sc=&dgb_softc[unit];
1209         int head, tail;
1210         u_char *eventbuf;
1211         int event, mstat, lstat;
1212         volatile struct board_chan *bc;
1213         struct tty *tp;
1214         int rhead, rtail;
1215         int whead, wtail;
1216         int size;
1217         u_char *ptr;
1218         int ocount;
1219         int ibuf_full,obuf_full;
1220
1221         BoardMemWinState ws=bmws_get();
1222
1223         if(sc->status==DISABLED) {
1224                 printf("dgb%d: polling of disabled board stopped\n",unit);
1225                 return;
1226         }
1227         
1228         setwin(sc,0);
1229
1230         head=sc->mailbox->ein;
1231         tail=sc->mailbox->eout;
1232
1233         while(head!=tail) {
1234                 if(head >= FEP_IMAX-FEP_ISTART 
1235                 || tail >= FEP_IMAX-FEP_ISTART 
1236                 || (head|tail) & 03 ) {
1237                         printf("dgb%d: event queue's head or tail is wrong! hd=%d,tl=%d\n", unit,head,tail);
1238                         break;
1239                 }
1240
1241                 eventbuf=sc->vmem+tail+FEP_ISTART;
1242                 pnum=eventbuf[0];
1243                 event=eventbuf[1];
1244                 mstat=eventbuf[2];
1245                 lstat=eventbuf[3];
1246
1247                 port=&sc->ports[pnum];
1248                 bc=port->brdchan;
1249                 tp=&sc->ttys[pnum];
1250
1251                 if(pnum>=sc->numports || port->status==DISABLED) {
1252                         printf("dgb%d: port%d: got event on nonexisting port\n",unit,pnum);
1253                 } else if(port->used || port->wopeners>0 ) {
1254
1255                         int wrapmask=port->rxbufsize-1;
1256
1257                         if( !(event & ALL_IND) ) 
1258                                 printf("dgb%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1259                                         unit, pnum, event, mstat, lstat);
1260
1261                         if(event & DATA_IND) {
1262                                 DPRINT3(DB_DATA,"dgb%d: port%d: DATA_IND\n",unit,pnum);
1263
1264                                 rhead=bc->rin & wrapmask; 
1265                                 rtail=bc->rout & wrapmask;
1266
1267                                 if( !(tp->t_cflag & CREAD) || !port->used ) {
1268                                         bc->rout=rhead;
1269                                         goto end_of_data;
1270                                 }
1271
1272                                 if(bc->orun) {
1273                                         printf("dgb%d: port%d: overrun\n", unit, pnum);
1274                                         bc->orun=0;
1275                                 }
1276
1277                                 if(!(tp->t_state & TS_ISOPEN))
1278                                         goto end_of_data;
1279
1280                                 for(ibuf_full=FALSE;rhead!=rtail && !ibuf_full;) {
1281                                         DPRINT5(DB_RXDATA,"dgb%d: port%d: p rx head=%d tail=%d\n",
1282                                                 unit,pnum,rhead,rtail);
1283
1284                                         if(rhead>rtail)
1285                                                 size=rhead-rtail;
1286                                         else
1287                                                 size=port->rxbufsize-rtail;
1288
1289                                         ptr=port->rxptr+rtail;
1290
1291 /* Helg: */
1292                                         if( tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1293                                                 size=DGB_IBUFSIZE-tp->t_rawq.c_cc;
1294                                                 DPRINT1(DB_RXDATA,"*");
1295                                                 ibuf_full=TRUE;
1296                                         }
1297
1298                                         if(size) {
1299                                                 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1300                                                         DPRINT1(DB_RXDATA,"!");
1301                                                         towin(sc,port->rxwin);
1302                                                         tk_nin += size;
1303                                                         tk_rawcc += size;
1304                                                         tp->t_rawcc += size;
1305                                                         b_to_q(ptr,size,&tp->t_rawq);
1306                                                         setwin(sc,0);
1307                                                 } else {
1308                                                         int i=size;
1309                                                         unsigned char chr;
1310                                                         do {
1311                                                                 towin(sc,port->rxwin);
1312                                                                 chr= *ptr++;
1313                                                                 hidewin(sc);
1314                                                                (*linesw[tp->t_line].l_rint)(chr, tp);
1315                                                         } while (--i > 0 );
1316                                                         setwin(sc,0);
1317                                                 }
1318                                         }
1319                                         rtail= (rtail + size) & wrapmask;
1320                                         bc->rout=rtail;
1321                                         rhead=bc->rin & wrapmask;
1322                                         hidewin(sc);
1323                                         ttwakeup(tp);
1324                                         setwin(sc,0);
1325                                 }
1326                         end_of_data: ;
1327                         }
1328
1329                         if(event & MODEMCHG_IND) {
1330                                 DPRINT3(DB_MODEM,"dgb%d: port%d: MODEMCHG_IND\n",unit,pnum);
1331                                 port->imodem=mstat;
1332                                 if(mstat & port->dcd) {
1333                                         hidewin(sc);
1334                                         linesw[tp->t_line].l_modem(tp,1);
1335                                         setwin(sc,0);
1336                                         wakeup(TSA_CARR_ON(tp));
1337                                 } else {
1338                                         hidewin(sc);
1339                                         linesw[tp->t_line].l_modem(tp,0);
1340                                         setwin(sc,0);
1341                                         if( port->draining) {
1342                                                 port->draining=0;
1343                                                 wakeup(&port->draining);
1344                                         }
1345                                 }
1346                         }
1347
1348                         if(event & BREAK_IND) {
1349                                 if((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1350                                         DPRINT3(DB_BREAK,"dgb%d: port%d: BREAK_IND\n",unit,pnum);
1351                                         hidewin(sc);
1352                                         linesw[tp->t_line].l_rint(TTY_BI, tp);
1353                                         setwin(sc,0);
1354                                 }
1355                         }
1356
1357 /* Helg: with output flow control */
1358
1359                         if(event & (LOWTX_IND | EMPTYTX_IND) ) {
1360                                 DPRINT3(DB_TXDATA,"dgb%d: port%d: LOWTX_IND or EMPTYTX_IND\n",unit,pnum);
1361
1362                                 if( (event & EMPTYTX_IND ) && tp->t_outq.c_cc==0
1363                                 && port->draining) {
1364                                         port->draining=0;
1365                                         wakeup(&port->draining);
1366                                         bc->ilow=0; bc->iempty=0;
1367                                 } else {
1368
1369                                         int wrapmask=port->txbufsize-1;
1370
1371                                         for(obuf_full=FALSE; tp->t_outq.c_cc!=0 && !obuf_full; ) {
1372                                                 int s;
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                                                 }
1389                                                 s=spltty();
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;
1407                                                 splx(s);
1408                                                 break;
1409                                         }
1410
1411                                         towin(sc,port->txwin);
1412
1413                                         ocount=q_to_b(&tp->t_outq, port->txptr+whead, size);
1414                                         whead+=ocount;
1415
1416                                         setwin(sc,0);
1417                                         bc->tin=whead;
1418                                         bc->tin=whead & wrapmask;
1419                                         splx(s);
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
1462         timeout(dgbpoll, unit_c, hz/POLLSPERSEC);
1463 }
1464
1465 static  int
1466 dgbioctl(dev, cmd, data, flag, p)
1467         dev_t           dev;
1468         u_long          cmd;
1469         caddr_t         data;
1470         int             flag;
1471         struct proc     *p;
1472 {
1473         struct dgb_softc *sc;
1474         int unit, pnum;
1475         struct dgb_p *port;
1476         int mynor;
1477         struct tty *tp;
1478         volatile struct board_chan *bc;
1479         int error;
1480         int s,cs;
1481         int tiocm_xxx;
1482
1483 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1484         u_long          oldcmd;
1485         struct termios  term;
1486 #endif
1487
1488         BoardMemWinState ws=bmws_get();
1489
1490         mynor=minor(dev);
1491         unit=MINOR_TO_UNIT(mynor);
1492         pnum=MINOR_TO_PORT(mynor);
1493
1494         sc=&dgb_softc[unit];
1495         port=&sc->ports[pnum];
1496         tp=&sc->ttys[pnum];
1497         bc=port->brdchan;
1498
1499         if (mynor & CONTROL_MASK) {
1500                 struct termios *ct;
1501
1502                 switch (mynor & CONTROL_MASK) {
1503                 case CONTROL_INIT_STATE:
1504                         ct = mynor & CALLOUT_MASK ? &port->it_out : &port->it_in;
1505                         break;
1506                 case CONTROL_LOCK_STATE:
1507                         ct = mynor & CALLOUT_MASK ? &port->lt_out : &port->lt_in;
1508                         break;
1509                 default:
1510                         return (ENODEV);        /* /dev/nodev */
1511                 }
1512                 switch (cmd) {
1513                 case TIOCSETA:
1514                         error = suser(p);
1515                         if (error != 0)
1516                                 return (error);
1517                         *ct = *(struct termios *)data;
1518                         return (0);
1519                 case TIOCGETA:
1520                         *(struct termios *)data = *ct;
1521                         return (0);
1522                 case TIOCGETD:
1523                         *(int *)data = TTYDISC;
1524                         return (0);
1525                 case TIOCGWINSZ:
1526                         bzero(data, sizeof(struct winsize));
1527                         return (0);
1528                 default:
1529                         return (ENOTTY);
1530                 }
1531         }
1532
1533 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1534         term = tp->t_termios;
1535         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1536           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);
1537         }
1538         oldcmd = cmd;
1539         error = ttsetcompat(tp, &cmd, data, &term);
1540         if (error != 0)
1541                 return (error);
1542         if (cmd != oldcmd)
1543                 data = (caddr_t)&term;
1544 #endif
1545
1546         if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1547                 int     cc;
1548                 struct termios *dt = (struct termios *)data;
1549                 struct termios *lt = mynor & CALLOUT_MASK
1550                                      ? &port->lt_out : &port->lt_in;
1551
1552                 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);
1553                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1554                               | (dt->c_iflag & ~lt->c_iflag);
1555                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1556                               | (dt->c_oflag & ~lt->c_oflag);
1557                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1558                               | (dt->c_cflag & ~lt->c_cflag);
1559                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1560                               | (dt->c_lflag & ~lt->c_lflag);
1561                 for (cc = 0; cc < NCCS; ++cc)
1562                         if (lt->c_cc[cc] != 0)
1563                                 dt->c_cc[cc] = tp->t_cc[cc];
1564                 if (lt->c_ispeed != 0)
1565                         dt->c_ispeed = tp->t_ispeed;
1566                 if (lt->c_ospeed != 0)
1567                         dt->c_ospeed = tp->t_ospeed;
1568         }
1569
1570         if(cmd==TIOCSTOP) {
1571                 cs=splclock();
1572                 setwin(sc,0);
1573                 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1574                 bmws_set(ws);
1575                 splx(cs);
1576                 return 0;
1577         } else if(cmd==TIOCSTART) {
1578                 cs=splclock();
1579                 setwin(sc,0);
1580                 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1581                 bmws_set(ws);
1582                 splx(cs);
1583                 return 0;
1584         }
1585
1586         if(cmd==TIOCSETAW || cmd==TIOCSETAF)
1587                 port->mustdrain=1;
1588
1589         error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p);
1590         if (error != ENOIOCTL)
1591                 return error;
1592         s = spltty();
1593         error = ttioctl(tp, cmd, data, flag);
1594         disc_optim(tp,&tp->t_termios);
1595         port->mustdrain=0;
1596         if (error != ENOIOCTL) {
1597                 splx(s);
1598                 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1599                         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);
1600                 }
1601                 return error;
1602         }
1603
1604         switch (cmd) {
1605         case TIOCSBRK:
1606 /* Helg: commented */
1607 /*              error=dgbdrain(port);*/
1608
1609                 if(error!=0) {
1610                         splx(s);
1611                         return error;
1612                 }
1613
1614                 cs=splclock();
1615                 setwin(sc,0);
1616         
1617                 /* now it sends 250 millisecond break because I don't know */
1618                 /* how to send an infinite break */
1619
1620                 fepcmd(port, SENDBREAK, 250, 0, 10, 0);
1621                 hidewin(sc);
1622                 splx(cs);
1623                 break;
1624         case TIOCCBRK:
1625                 /* now it's empty */
1626                 break;
1627         case TIOCSDTR:
1628                 DPRINT3(DB_MODEM,"dgb%d: port%d: set DTR\n",unit,pnum);
1629                 port->omodem |= DTR;
1630                 cs=splclock();
1631                 setwin(sc,0);
1632                 fepcmd(port, SETMODEM, port->omodem, RTS, 0, 1);
1633
1634                 if( !(bc->mstat & DTR) ) {
1635                         DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is off\n",unit,pnum);
1636                 }
1637
1638                 hidewin(sc);
1639                 splx(cs);
1640                 break;
1641         case TIOCCDTR:
1642                 DPRINT3(DB_MODEM,"dgb%d: port%d: reset DTR\n",unit,pnum);
1643                 port->omodem &= ~DTR;
1644                 cs=splclock();
1645                 setwin(sc,0);
1646                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1647
1648                 if( bc->mstat & DTR ) {
1649                         DPRINT3(DB_MODEM,"dgb%d: port%d: DTR is on\n",unit,pnum);
1650                 }
1651
1652                 hidewin(sc);
1653                 splx(cs);
1654                 break;
1655         case TIOCMSET:
1656                 if(*(int *)data & TIOCM_DTR)
1657                         port->omodem |=DTR;
1658                 else
1659                         port->omodem &=~DTR;
1660
1661                 if(*(int *)data & TIOCM_RTS)
1662                         port->omodem |=RTS;
1663                 else
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 TIOCMBIS:
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 TIOCMBIC:
1686                 if(*(int *)data & TIOCM_DTR)
1687                         port->omodem &=~DTR;
1688
1689                 if(*(int *)data & TIOCM_RTS)
1690                         port->omodem &=~RTS;
1691
1692                 cs=splclock();
1693                 setwin(sc,0);
1694                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1695                 hidewin(sc);
1696                 splx(cs);
1697                 break;
1698         case TIOCMGET:
1699                 setwin(sc,0);
1700                 port->imodem=bc->mstat;
1701                 hidewin(sc);
1702
1703                 tiocm_xxx = TIOCM_LE;   /* XXX - always enabled while open */
1704
1705                 DPRINT3(DB_MODEM,"dgb%d: port%d: modem stat -- ",unit,pnum);
1706
1707                 if (port->imodem & DTR) {
1708                         DPRINT1(DB_MODEM,"DTR ");
1709                         tiocm_xxx |= TIOCM_DTR;
1710                 }
1711                 if (port->imodem & RTS) {
1712                         DPRINT1(DB_MODEM,"RTS ");
1713                         tiocm_xxx |= TIOCM_RTS;
1714                 }
1715                 if (port->imodem & CTS) {
1716                         DPRINT1(DB_MODEM,"CTS ");
1717                         tiocm_xxx |= TIOCM_CTS;
1718                 }
1719                 if (port->imodem & port->dcd) {
1720                         DPRINT1(DB_MODEM,"DCD ");
1721                         tiocm_xxx |= TIOCM_CD;
1722                 }
1723                 if (port->imodem & port->dsr) {
1724                         DPRINT1(DB_MODEM,"DSR ");
1725                         tiocm_xxx |= TIOCM_DSR;
1726                 }
1727                 if (port->imodem & RI) {
1728                         DPRINT1(DB_MODEM,"RI ");
1729                         tiocm_xxx |= TIOCM_RI;
1730                 }
1731                 *(int *)data = tiocm_xxx;
1732                 DPRINT1(DB_MODEM,"--\n");
1733                 break;
1734         case TIOCMSDTRWAIT:
1735                 /* must be root since the wait applies to following logins */
1736                 error = suser(p);
1737                 if (error != 0) {
1738                         splx(s);
1739                         return (error);
1740                 }
1741                 port->close_delay = *(int *)data * hz / 100;
1742                 break;
1743         case TIOCMGDTRWAIT:
1744                 *(int *)data = port->close_delay * 100 / hz;
1745                 break;
1746         case TIOCTIMESTAMP:
1747                 port->do_timestamp = TRUE;
1748                 *(struct timeval *)data = port->timestamp;
1749                 break;
1750         case TIOCDCDTIMESTAMP:
1751                 port->do_dcd_timestamp = TRUE;
1752                 *(struct timeval *)data = port->dcd_timestamp;
1753                 break;
1754         default:
1755                 bmws_set(ws);
1756                 splx(s);
1757                 return ENOTTY;
1758         }
1759         bmws_set(ws);
1760         splx(s);
1761
1762         return 0;
1763 }
1764
1765 static void 
1766 wakeflush(p)
1767         void *p;
1768 {
1769         struct dgb_p *port=p;
1770
1771         wakeup(&port->draining);
1772 }
1773
1774 /* wait for the output to drain */
1775
1776 static int
1777 dgbdrain(port)
1778         struct dgb_p    *port;
1779 {
1780         struct dgb_softc *sc=&dgb_softc[port->unit];
1781         volatile struct board_chan *bc=port->brdchan;
1782         int error;
1783         int head, tail;
1784
1785         BoardMemWinState ws=bmws_get();
1786
1787         setwin(sc,0);
1788
1789         bc->iempty=1;
1790         tail=bc->tout;
1791         head=bc->tin;
1792
1793         while(tail!=head) {
1794                 DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
1795                         port->unit, port->pnum, head, tail);
1796
1797                 hidewin(sc);
1798                 port->draining=1;
1799                 timeout(wakeflush,port, hz);
1800                 error=tsleep(&port->draining, TTIPRI | PCATCH, "dgdrn", 0);
1801                 port->draining=0;
1802                 setwin(sc,0);
1803
1804                 if (error != 0) {
1805                         DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgdrn) error=%d\n",
1806                                 port->unit,port->pnum,error);
1807
1808                         bc->iempty=0;
1809                         bmws_set(ws);
1810                         return error;
1811                 }
1812
1813                 tail=bc->tout;
1814                 head=bc->tin;
1815         }
1816         DPRINT5(DB_WR,"dgb%d: port%d: drain: head=%d tail=%d\n",
1817                 port->unit, port->pnum, head, tail);
1818         bmws_set(ws);
1819         return 0;
1820 }
1821
1822 /* wait for the output to drain */
1823 /* or simply clear the buffer it it's stopped */
1824
1825 static void
1826 dgb_drain_or_flush(port)
1827         struct dgb_p    *port;
1828 {
1829         struct tty *tp=port->tty;
1830         struct dgb_softc *sc=&dgb_softc[port->unit];
1831         volatile struct board_chan *bc=port->brdchan;
1832         int error;
1833         int lasttail;
1834         int head, tail;
1835
1836         setwin(sc,0);
1837
1838         lasttail=-1;
1839         bc->iempty=1;
1840         tail=bc->tout;
1841         head=bc->tin;
1842
1843         while(tail!=head /* && tail!=lasttail */ ) {
1844                 DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
1845                         port->unit, port->pnum, head, tail);
1846
1847                 /* if there is no carrier simply clean the buffer */
1848                 if( !(tp->t_state & TS_CARR_ON) ) {
1849                         bc->tout=bc->tin=0;
1850                         bc->iempty=0;
1851                         hidewin(sc);
1852                         return;
1853                 }
1854
1855                 hidewin(sc);
1856                 port->draining=1;
1857                 timeout(wakeflush,port, hz);
1858                 error=tsleep(&port->draining, TTIPRI | PCATCH, "dgfls", 0);
1859                 port->draining=0;
1860                 setwin(sc,0);
1861
1862                 if (error != 0) {
1863                         DPRINT4(DB_WR,"dgb%d: port%d: tsleep(dgfls) error=%d\n",
1864                                 port->unit,port->pnum,error);
1865
1866                         /* silently clean the buffer */
1867
1868                         bc->tout=bc->tin=0;
1869                         bc->iempty=0;
1870                         hidewin(sc);
1871                         return;
1872                 }
1873
1874                 lasttail=tail;
1875                 tail=bc->tout;
1876                 head=bc->tin;
1877         }
1878         hidewin(sc);
1879         DPRINT5(DB_WR,"dgb%d: port%d: flush: head=%d tail=%d\n",
1880                         port->unit, port->pnum, head, tail);
1881 }
1882
1883 static int
1884 dgbparam(tp, t)
1885         struct tty      *tp;
1886         struct termios  *t;
1887 {
1888         int unit=MINOR_TO_UNIT(minor(tp->t_dev));
1889         int pnum=MINOR_TO_PORT(minor(tp->t_dev));
1890         struct dgb_softc *sc=&dgb_softc[unit];
1891         struct dgb_p *port=&sc->ports[pnum];
1892         volatile struct board_chan *bc=port->brdchan;
1893         int cflag;
1894         int head;
1895         int mval;
1896         int iflag;
1897         int hflow;
1898         int cs;
1899
1900         BoardMemWinState ws=bmws_get();
1901
1902         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);
1903
1904         if(port->mustdrain) {
1905                 DPRINT3(DB_PARAM,"dgb%d: port%d: must call dgbdrain()\n",unit,pnum);
1906                 dgbdrain(port);
1907         }
1908
1909         cflag=ttspeedtab(t->c_ospeed, dgbspeedtab);
1910
1911         if (t->c_ispeed == 0)
1912                 t->c_ispeed = t->c_ospeed;
1913
1914         if (cflag < 0 /* || cflag > 0 && t->c_ispeed != t->c_ospeed */) {
1915                 DPRINT4(DB_PARAM,"dgb%d: port%d: invalid cflag=0%o\n",unit,pnum,cflag);
1916                 return (EINVAL);
1917         }
1918
1919         cs=splclock();
1920         setwin(sc,0);
1921
1922         if(cflag==0) { /* hangup */
1923                 DPRINT3(DB_PARAM,"dgb%d: port%d: hangup\n",unit,pnum);
1924                 head=bc->rin;
1925                 bc->rout=head;
1926                 head=bc->tin;
1927                 fepcmd(port, STOUT, (unsigned)head, 0, 0, 0);
1928                 mval= port->omodem & ~(DTR|RTS);
1929         } else {
1930                 cflag |= dgbflags(dgb_cflags, t->c_cflag);
1931
1932                 if(cflag!=port->fepcflag) {
1933                         port->fepcflag=cflag;
1934                         DPRINT5(DB_PARAM,"dgb%d: port%d: set cflag=0x%x c=0x%x\n",
1935                                         unit,pnum,cflag,t->c_cflag&~CRTSCTS);
1936                         fepcmd(port, SETCTRLFLAGS, (unsigned)cflag, 0, 0, 0);
1937                 }
1938                 mval= port->omodem | (DTR|RTS);
1939         }
1940
1941         iflag=dgbflags(dgb_iflags, t->c_iflag);
1942         if(iflag!=port->fepiflag) {
1943                 port->fepiflag=iflag;
1944                 DPRINT5(DB_PARAM,"dgb%d: port%d: set iflag=0x%x c=0x%x\n",unit,pnum,iflag,t->c_iflag);
1945                 fepcmd(port, SETIFLAGS, (unsigned)iflag, 0, 0, 0);
1946         }
1947
1948         bc->mint=port->dcd;
1949
1950         hflow=dgbflags(dgb_flow, t->c_cflag);
1951         if(hflow!=port->hflow) {
1952                 port->hflow=hflow;
1953                 DPRINT5(DB_PARAM,"dgb%d: port%d: set hflow=0x%x f=0x%x\n",unit,pnum,hflow,t->c_cflag&CRTSCTS);
1954                 fepcmd(port, SETHFLOW, (unsigned)hflow, 0xff, 0, 1);
1955         }
1956         
1957         if(port->omodem != mval) {
1958                 DPRINT5(DB_PARAM,"dgb%d: port%d: setting modem parameters 0x%x was 0x%x\n",
1959                         unit,pnum,mval,port->omodem);
1960                 port->omodem=mval;
1961                 fepcmd(port, SETMODEM, (unsigned)mval, RTS|DTR, 0, 1);
1962         }
1963
1964         if(port->fepstartc!=t->c_cc[VSTART] || port->fepstopc!=t->c_cc[VSTOP]) {
1965                 DPRINT5(DB_PARAM,"dgb%d: port%d: set startc=%d, stopc=%d\n",unit,pnum,t->c_cc[VSTART],t->c_cc[VSTOP]);
1966                 port->fepstartc=t->c_cc[VSTART];
1967                 port->fepstopc=t->c_cc[VSTOP];
1968                 fepcmd(port, SONOFFC, port->fepstartc, port->fepstopc, 0, 1);
1969         }
1970
1971         bmws_set(ws);
1972         splx(cs);
1973
1974         return 0;
1975
1976 }
1977
1978 static void
1979 dgbstart(tp)
1980         struct tty      *tp;
1981 {
1982         int unit;
1983         int pnum;
1984         struct dgb_p *port;
1985         struct dgb_softc *sc;
1986         volatile struct board_chan *bc;
1987         int head, tail;
1988         int size, ocount;
1989         int s;
1990         int wmask;
1991
1992         BoardMemWinState ws=bmws_get();
1993
1994         unit=MINOR_TO_UNIT(minor(tp->t_dev));
1995         pnum=MINOR_TO_PORT(minor(tp->t_dev));
1996         sc=&dgb_softc[unit];
1997         port=&sc->ports[pnum];
1998         bc=port->brdchan;
1999
2000         wmask=port->txbufsize-1;
2001
2002         s=spltty();
2003
2004         while( tp->t_outq.c_cc!=0 ) {
2005                 int cs;
2006 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2007                 ttwwakeup(tp);
2008 #else
2009                 if(tp->t_outq.c_cc <= tp->t_lowat) {
2010                         if(tp->t_state & TS_ASLEEP) {
2011                                 tp->t_state &= ~TS_ASLEEP;
2012                                 wakeup(TSA_OLOWAT(tp));
2013                         }
2014                         /*selwakeup(&tp->t_wsel);*/
2015                 }
2016 #endif
2017                 cs=splclock();
2018                 setwin(sc,0);
2019
2020                 head=bc->tin & wmask;
2021
2022                 do { tail=bc->tout; } while (tail != bc->tout);
2023                 tail=bc->tout & wmask;
2024
2025                 DPRINT5(DB_WR,"dgb%d: port%d: s tx head=%d tail=%d\n",unit,pnum,head,tail);
2026
2027 #ifdef LEAVE_FREE_CHARS 
2028                 if(tail>head) {
2029                         size=tail-head-LEAVE_FREE_CHARS;
2030                         if (size <0)
2031                                 size=0;
2032                         } else {
2033                                 size=port->txbufsize-head;
2034                                 if(tail+port->txbufsize < head)
2035                                         size=0;
2036                         }
2037                 }
2038 #else
2039                 if(tail>head)
2040                         size=tail-head-1;
2041                 else {
2042                         size=port->txbufsize-head/*-1*/;
2043                         if(tail==0)
2044                                 size--;
2045                 }
2046 #endif
2047
2048                 if(size==0) {
2049                         bc->iempty=1; bc->ilow=1;
2050                         splx(cs);
2051                         bmws_set(ws);
2052                         tp->t_state|=TS_BUSY;
2053                         splx(s);
2054                         return;
2055                 }
2056
2057                 towin(sc,port->txwin);
2058
2059                 ocount=q_to_b(&tp->t_outq, port->txptr+head, size);
2060                 head+=ocount;
2061                 if(head>=port->txbufsize)
2062                         head-=port->txbufsize;
2063
2064                 setwin(sc,0);
2065                 bc->tin=head;
2066
2067                 DPRINT5(DB_WR,"dgb%d: port%d: tx avail=%d count=%d\n",unit,pnum,size,ocount);
2068                 hidewin(sc);
2069                 splx(cs);
2070         }
2071
2072         bmws_set(ws);
2073         splx(s);
2074
2075 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2076         if(tp->t_state & TS_BUSY) {     
2077                 tp->t_state&=~TS_BUSY;
2078                 linesw[tp->t_line].l_start(tp);
2079                 ttwwakeup(tp);
2080         }
2081 #else
2082         if(tp->t_state & TS_ASLEEP) {
2083                 tp->t_state &= ~TS_ASLEEP;
2084                 wakeup(TSA_OLOWAT(tp));
2085         }
2086         tp->t_state&=~TS_BUSY;
2087 #endif
2088 }
2089
2090 void
2091 dgbstop(tp, rw)
2092         struct tty      *tp;
2093         int             rw;
2094 {
2095         int unit;
2096         int pnum;
2097         struct dgb_p *port;
2098         struct dgb_softc *sc;
2099         volatile struct board_chan *bc;
2100         int s;
2101
2102         BoardMemWinState ws=bmws_get();
2103
2104         unit=MINOR_TO_UNIT(minor(tp->t_dev));
2105         pnum=MINOR_TO_PORT(minor(tp->t_dev));
2106
2107         sc=&dgb_softc[unit];
2108         port=&sc->ports[pnum];
2109         bc=port->brdchan;
2110
2111         DPRINT3(DB_WR,"dgb%d: port%d: stop\n",port->unit, port->pnum);
2112
2113         s = spltty();
2114         setwin(sc,0);
2115
2116         if (rw & FWRITE) {
2117                 /* clear output queue */
2118                 bc->tout=bc->tin=0;
2119                 bc->ilow=0;bc->iempty=0;
2120         }
2121         if (rw & FREAD) {
2122                 /* clear input queue */
2123                 bc->rout=bc->rin;
2124                 bc->idata=1;
2125         }
2126         hidewin(sc);
2127         bmws_set(ws);
2128         splx(s);
2129         dgbstart(tp);
2130 }
2131
2132 static void 
2133 fepcmd(port, cmd, op1, op2, ncmds, bytecmd)
2134         struct dgb_p *port;
2135         unsigned cmd, op1, op2, ncmds, bytecmd;
2136 {
2137         struct dgb_softc *sc=&dgb_softc[port->unit];
2138         u_char *mem=sc->vmem;
2139         unsigned tail, head;
2140         int count, n;
2141
2142         if(port->status==DISABLED) {
2143                 printf("dgb%d: port%d: FEP command on disabled port\n", 
2144                         port->unit, port->pnum);
2145                 return;
2146         }
2147
2148         /* setwin(sc,0); Require this to be set by caller */
2149         head=sc->mailbox->cin;
2150
2151         if(head>=(FEP_CMAX-FEP_CSTART) || (head & 3)) {
2152                 printf("dgb%d: port%d: wrong pointer head of command queue : 0x%x\n",
2153                         port->unit, port->pnum, head);
2154                 return;
2155         }
2156
2157         mem[head+FEP_CSTART+0]=cmd;
2158         mem[head+FEP_CSTART+1]=port->pnum;
2159         if(bytecmd) {
2160                 mem[head+FEP_CSTART+2]=op1;
2161                 mem[head+FEP_CSTART+3]=op2;
2162         } else {
2163                 mem[head+FEP_CSTART+2]=op1&0xff;
2164                 mem[head+FEP_CSTART+3]=(op1>>8)&0xff;
2165         }
2166
2167         DPRINT7(DB_FEP,"dgb%d: port%d: %s cmd=0x%x op1=0x%x op2=0x%x\n", port->unit, port->pnum,
2168                         (bytecmd)?"byte":"word", cmd, mem[head+FEP_CSTART+2], mem[head+FEP_CSTART+3]);
2169
2170         head=(head+4) & (FEP_CMAX-FEP_CSTART-4);
2171         sc->mailbox->cin=head;
2172
2173         count=FEPTIMEOUT;
2174
2175         while (count-- != 0) {
2176                 head=sc->mailbox->cin;
2177                 tail=sc->mailbox->cout;
2178
2179                 n = (head-tail) & (FEP_CMAX-FEP_CSTART-4);
2180                 if(n <= ncmds * (sizeof(ushort)*4))
2181                         return;
2182         }
2183         printf("dgb%d(%d): timeout on FEP cmd=0x%x\n", port->unit, port->pnum, cmd);
2184 }
2185
2186 static void 
2187 disc_optim(tp, t)
2188         struct tty      *tp;
2189         struct termios  *t;
2190 {
2191         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2192             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2193             && (!(t->c_iflag & PARMRK)
2194                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2195             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2196             && linesw[tp->t_line].l_rint == ttyinput)
2197                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2198         else
2199                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2200 }