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