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