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