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