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