timeout/untimeout ==> callout_*
[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.13 2004/09/17 00:28:44 joerg Exp $
4  *
5  *  Digiboard driver.
6  *
7  *  Stage 1. "Better than nothing".
8  *  Stage 2. "Gee, it works!".
9  *
10  *  Based on sio driver by Bruce Evans and on Linux driver by Troy 
11  *  De Jongh <troyd@digibd.com> or <troyd@skypoint.com> 
12  *  which is under GNU General Public License version 2 so this driver 
13  *  is forced to be under GPL 2 too.
14  *
15  *  Written by Serge Babkin,
16  *      Joint Stock Commercial Bank "Chelindbank"
17  *      (Chelyabinsk, Russia)
18  *      babkin@hq.icb.chel.su
19  *
20  *  Assorted hacks to make it more functional and working under 3.0-current.
21  *  Fixed broken routines to prevent processes hanging on closed (thanks
22  *  to Bruce for his patience and assistance). Thanks also to Maxim Bolotin
23  *  <max@run.net> for his patches which did most of the work to get this
24  *  running under 2.2/3.0-current.
25  *  Implemented ioctls: TIOCMSDTRWAIT, TIOCMGDTRWAIT, TIOCTIMESTAMP &
26  *  TIOCDCDTIMESTAMP.
27  *  Sysctl debug flag is now a bitflag, to filter noise during debugging.
28  *      David L. Nugent <davidn@blaze.net.au>
29  */
30
31 #include "opt_compat.h"
32 #include "opt_dgb.h"
33
34 #include "use_dgb.h"
35
36 /* Helg: i.e.25 times per sec board will be polled */
37 #define POLLSPERSEC 25
38 /* How many charactes can we write to input tty rawq */
39 #define DGB_IBUFSIZE (TTYHOG-100)
40
41 /* the overall number of ports controlled by this driver */
42
43 #ifndef NDGBPORTS
44 #       define NDGBPORTS (NDGB*16)
45 #endif
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/tty.h>
50 #include <sys/proc.h>
51 #include <sys/conf.h>
52 #include <sys/dkstat.h>
53 #include <sys/fcntl.h>
54 #include <sys/kernel.h>
55 #include <sys/sysctl.h>
56
57 #include <machine/clock.h>
58
59 #include <vm/vm.h>
60 #include <vm/pmap.h>
61
62 #include <bus/isa/i386/isa_device.h>
63
64 #include "dgbios.h"
65 #include "dgfep.h"
66
67 #define DGB_DEBUG               /* Enable debugging info via sysctl */
68 #include "dgreg.h"
69
70 #define CALLOUT_MASK            0x80
71 #define CONTROL_MASK            0x60
72 #define CONTROL_INIT_STATE      0x20
73 #define CONTROL_LOCK_STATE      0x40
74 #define UNIT_MASK                       0x30000
75 #define PORT_MASK                       0x1F
76 #define DEV_TO_UNIT(dev)        (MINOR_TO_UNIT(minor(dev)))
77 #define MINOR_MAGIC_MASK        (CALLOUT_MASK | CONTROL_MASK)
78 #define MINOR_TO_UNIT(mynor)    (((mynor) & UNIT_MASK)>>16)
79 #define MINOR_TO_PORT(mynor)    ((mynor) & PORT_MASK)
80
81 /* types.  XXX - should be elsewhere */
82 typedef u_char  bool_t;         /* boolean */
83
84 /* digiboard port structure */
85 struct dgb_p {
86         bool_t  status;
87
88         u_char unit;           /* board unit number */
89         u_char pnum;           /* port number */
90         u_char omodem;         /* FEP output modem status     */
91         u_char imodem;         /* FEP input modem status      */
92         u_char modemfake;      /* Modem values to be forced   */
93         u_char modem;          /* Force values                */
94         u_char hflow;
95         u_char dsr;
96         u_char dcd;
97         u_char stopc;
98         u_char startc;
99         u_char stopca;
100         u_char startca;
101         u_char fepstopc;
102         u_char fepstartc;
103         u_char fepstopca;
104         u_char fepstartca;
105         u_char txwin;
106         u_char rxwin;
107         ushort fepiflag;
108         ushort fepcflag;
109         ushort fepoflag;
110         ushort txbufhead;
111         ushort txbufsize;
112         ushort rxbufhead;
113         ushort rxbufsize;
114         int close_delay;
115         int count;
116         int blocked_open;
117         int event;
118         int asyncflags;
119         u_long statusflags;
120         volatile u_char *txptr;
121         volatile u_char *rxptr;
122         volatile struct board_chan *brdchan;
123         struct tty *tty;
124
125         bool_t  active_out;     /* nonzero if the callout device is open */
126         u_int   wopeners;       /* # processes waiting for DCD in open() */
127
128         /* Initial state. */
129         struct termios  it_in;  /* should be in struct tty */
130         struct termios  it_out;
131
132         /* Lock state. */
133         struct termios  lt_in;  /* should be in struct tty */
134         struct termios  lt_out;
135
136         bool_t  do_timestamp;
137         bool_t  do_dcd_timestamp;
138         struct timeval  timestamp;
139         struct timeval  dcd_timestamp;
140
141         /* flags of state, are used in sleep() too */
142         u_char closing; /* port is being closed now */
143         u_char draining; /* port is being drained now */
144         u_char used;    /* port is being used now */
145         u_char mustdrain; /* data must be waited to drain in dgbparam() */
146 };
147
148 /* Digiboard per-board structure */
149 struct dgb_softc {
150         /* struct board_info */
151         u_char status;  /* status: DISABLED/ENABLED */
152         u_char unit;    /* unit number */
153         u_char type;    /* type of card: PCXE, PCXI, PCXEVE */
154         u_char altpin;  /* do we need alternate pin setting ? */
155         int numports;   /* number of ports on card */
156         int port;       /* I/O port */
157         u_char *vmem; /* virtual memory address */
158         long pmem; /* physical memory address */
159         int mem_seg;  /* internal memory segment */
160         struct dgb_p *ports;    /* pointer to array of port descriptors */
161         struct tty *ttys;       /* pointer to array of TTY structures */
162         volatile struct global_data *mailbox;
163         struct callout dgb_pause;
164         struct callout dgbpoll;
165         struct callout wakeflush;
166         };
167         
168
169 static struct dgb_softc dgb_softc[NDGB];
170 static struct dgb_p dgb_ports[NDGBPORTS];
171 static struct tty dgb_tty[NDGBPORTS];
172
173 /*
174  * The public functions in the com module ought to be declared in a com-driver
175  * system header.
176  */
177
178 /* Interrupt handling entry points. */
179 static void     dgbpoll         (void *unit_c);
180
181 /* Device switch entry points. */
182 #define dgbreset        noreset
183 #define dgbmmap         nommap
184 #define dgbstrategy     nostrategy
185
186 static  int     dgbattach       (struct isa_device *dev);
187 static  int     dgbprobe        (struct isa_device *dev);
188
189 static void fepcmd(struct dgb_p *port, unsigned cmd, unsigned op1, unsigned op2,
190         unsigned ncmds, unsigned bytecmd);
191
192 static  void    dgbstart        (struct tty *tp);
193 static  void    dgbstop         (struct tty *tp, int rw);
194 static  int     dgbparam        (struct tty *tp, struct termios *t);
195 static  void    dgbhardclose    (struct dgb_p *port);
196 static  void    dgb_drain_or_flush      (struct dgb_p *port);
197 static  int     dgbdrain        (struct dgb_p *port);
198 static  void    dgb_pause       (void *chan);
199 static  void    wakeflush       (void *p);
200 static  void    disc_optim      (struct tty     *tp, struct termios *t);
201
202
203 struct isa_driver       dgbdriver = {
204         dgbprobe, dgbattach, "dgb",0
205 };
206
207 static  d_open_t        dgbopen;
208 static  d_close_t       dgbclose;
209 static  d_ioctl_t       dgbioctl;
210
211 #define CDEV_MAJOR      58
212 static struct cdevsw dgb_cdevsw = {
213         /* name */      "dgb",
214         /* maj */       CDEV_MAJOR,
215         /* flags */     D_TTY | D_KQFILTER,
216         /* port */      NULL,
217         /* clone */     NULL,
218
219         /* open */      dgbopen,
220         /* close */     dgbclose,
221         /* read */      ttyread,
222         /* write */     ttywrite,
223         /* ioctl */     dgbioctl,
224         /* poll */      ttypoll,
225         /* mmap */      nommap,
226         /* strategy */  nostrategy,
227         /* dump */      nodump,
228         /* psize */     nopsize,
229         /* kqfilter */  ttykqfilter
230 };
231
232 static  speed_t dgbdefaultrate = TTYDEF_SPEED;
233
234 static  struct speedtab dgbspeedtab[] = {
235         { 0,            FEP_B0 }, /* old (sysV-like) Bx codes */
236         { 50,           FEP_B50 },
237         { 75,           FEP_B75 },
238         { 110,          FEP_B110 },
239         { 134,          FEP_B134 },
240         { 150,          FEP_B150 },
241         { 200,          FEP_B200 },
242         { 300,          FEP_B300 },
243         { 600,          FEP_B600 },
244         { 1200,         FEP_B1200 },
245         { 1800,         FEP_B1800 },
246         { 2400,         FEP_B2400 },
247         { 4800,         FEP_B4800 },
248         { 9600,         FEP_B9600 },
249         { 19200,        FEP_B19200 },
250         { 38400,        FEP_B38400 },
251         { 57600,        (FEP_FASTBAUD|FEP_B50) }, /* B50 & fast baud table */
252         { 115200, (FEP_FASTBAUD|FEP_B110) }, /* B100 & fast baud table */
253         { -1,   -1 }
254 };
255
256 static struct dbgflagtbl
257 {
258   tcflag_t in_mask;
259   tcflag_t in_val;
260   tcflag_t out_val;
261 } dgb_cflags[] =
262 {
263   { PARODD,   PARODD,     FEP_PARODD  },
264   { PARENB,   PARENB,     FEP_PARENB  },
265   { CSTOPB,   CSTOPB,     FEP_CSTOPB  },
266   { CSIZE,    CS5,        FEP_CS6     },
267   { CSIZE,    CS6,        FEP_CS6     },
268   { CSIZE,    CS7,        FEP_CS7     },
269   { CSIZE,    CS8,        FEP_CS8     },
270   { CLOCAL,   CLOCAL,     FEP_CLOCAL  },
271   { (tcflag_t)-1 }
272 }, dgb_iflags[] =
273 {
274   { IGNBRK,   IGNBRK,     FEP_IGNBRK  },
275   { BRKINT,   BRKINT,     FEP_BRKINT  },
276   { IGNPAR,   IGNPAR,     FEP_IGNPAR  },
277   { PARMRK,   PARMRK,     FEP_PARMRK  },
278   { INPCK,    INPCK,      FEP_INPCK   },
279   { ISTRIP,   ISTRIP,     FEP_ISTRIP  },
280   { IXON,     IXON,       FEP_IXON    },
281   { IXOFF,    IXOFF,      FEP_IXOFF   },
282   { IXANY,    IXANY,      FEP_IXANY   },
283   { (tcflag_t)-1 }
284 }, dgb_flow[] =
285 {
286   { CRTSCTS,  CRTSCTS,    CTS|RTS     },
287   { CRTSCTS,  CCTS_OFLOW, CTS         },
288   { CRTSCTS,  CRTS_IFLOW, RTS         },
289   { (tcflag_t)-1 }
290 };
291
292 /* xlat bsd termios flags to dgb sys-v style */
293 static tcflag_t
294 dgbflags(struct dbgflagtbl *tbl, tcflag_t input)
295 {
296   tcflag_t output = 0;
297   int i;
298
299   for (i=0; tbl[i].in_mask != (tcflag_t)-1; i++)
300   {
301     if ((input & tbl[i].in_mask) == tbl[i].in_val)
302       output |= tbl[i].out_val;
303   }
304   return output;
305 }
306
307 #ifdef DGB_DEBUG
308 static int dgbdebug=0;
309 SYSCTL_INT(_debug, OID_AUTO, dgb_debug, CTLFLAG_RW, &dgbdebug, 0, "");
310 #endif
311
312 static __inline int setwin (struct dgb_softc *sc, unsigned addr);
313 static __inline int setinitwin (struct dgb_softc *sc, unsigned addr);
314 static __inline void hidewin (struct dgb_softc *sc);
315 static __inline void towin (struct dgb_softc *sc, int win);
316
317 /*Helg: to allow recursive dgb...() calls */
318 typedef struct
319   {                 /* If we were called and don't want to disturb we need: */
320         int port;               /* write to this port */
321         u_char data;            /* this data on exit */
322                           /* or DATA_WINOFF  to close memory window on entry */
323   } BoardMemWinState; /* so several channels and even boards can coexist */
324 #define DATA_WINOFF 0
325 static BoardMemWinState bmws;
326
327 /* return current memory window state and close window */
328 static BoardMemWinState
329 bmws_get(void)
330 {
331         BoardMemWinState bmwsRet=bmws;
332         if(bmws.data!=DATA_WINOFF)
333                 outb(bmws.port, bmws.data=DATA_WINOFF);
334         return bmwsRet;
335 }
336
337 /* restore memory window state */
338 static void
339 bmws_set(BoardMemWinState ws)
340 {
341         if(ws.data != bmws.data || ws.port!=bmws.port ) {
342                 if(bmws.data!=DATA_WINOFF)
343                         outb(bmws.port,DATA_WINOFF);
344                 if(ws.data!=DATA_WINOFF)
345                         outb(ws.port, ws.data);
346                 bmws=ws;
347         }
348 }
349
350 static __inline int 
351 setwin(sc,addr)
352         struct dgb_softc *sc;
353         unsigned int addr;
354 {
355         if(sc->type==PCXEVE) {
356                 outb(bmws.port=sc->port+1, bmws.data=FEPWIN|(addr>>13));
357                 DPRINT3(DB_WIN,"dgb%d: switched to window 0x%x\n",sc->unit,addr>>13);
358                 return (addr & 0x1FFF);
359         } else {
360                 outb(bmws.port=sc->port,bmws.data=FEPMEM);
361                 return addr;
362         }
363 }
364
365 static __inline int 
366 setinitwin(sc,addr)
367         struct dgb_softc *sc;
368         unsigned int addr;
369 {
370         if(sc->type==PCXEVE) {
371                 outb(bmws.port=sc->port+1, bmws.data=FEPWIN|(addr>>13));
372                 DPRINT3(DB_WIN,"dgb%d: switched to window 0x%x\n",sc->unit,addr>>13);
373                 return (addr & 0x1FFF);
374         } else {
375                 outb(bmws.port=sc->port,bmws.data=inb(sc->port)|FEPMEM);
376                 return addr;
377         }
378 }
379
380 static __inline void
381 hidewin(sc)
382         struct dgb_softc *sc;
383 {
384         bmws.data=0;
385         if(sc->type==PCXEVE)
386                 outb(bmws.port=sc->port+1, bmws.data);
387         else
388                 outb(bmws.port=sc->port, bmws.data);
389 }
390
391 static __inline void
392 towin(sc,win)
393         struct dgb_softc *sc;
394         int win;
395 {
396         if(sc->type==PCXEVE) {
397                 outb(bmws.port=sc->port+1, bmws.data=win);
398         } else {
399                 outb(bmws.port=sc->port,bmws.data=FEPMEM);
400         }
401 }
402
403 static int
404 dgbprobe(dev)
405         struct isa_device       *dev;
406 {
407         struct dgb_softc *sc= &dgb_softc[dev->id_unit];
408         int i, v;
409         u_long win_size;  /* size of vizible memory window */
410         int unit=dev->id_unit;
411
412         sc->unit=dev->id_unit;
413         sc->port=dev->id_iobase;
414
415         if(dev->id_flags & DGBFLAG_ALTPIN)
416                 sc->altpin=1;
417         else
418                 sc->altpin=0;
419
420         /* left 24 bits only (ISA address) */
421         sc->pmem=((intptr_t)(void *)dev->id_maddr & 0xFFFFFF); 
422         
423         DPRINT4(DB_INFO,"dgb%d: port 0x%x mem 0x%lx\n",unit,sc->port,sc->pmem);
424
425         outb(sc->port, FEPRST);
426         sc->status=DISABLED;
427
428         for(i=0; i< 1000; i++) {
429                 DELAY(1);
430                 if( (inb(sc->port) & FEPMASK) == FEPRST ) {
431                         sc->status=ENABLED;
432                         DPRINT3(DB_EXCEPT,"dgb%d: got reset after %d us\n",unit,i);
433                         break;
434                 }
435         }
436
437         if(sc->status!=ENABLED) {
438                 DPRINT2(DB_EXCEPT,"dgb%d: failed to respond\n",dev->id_unit);
439                 return 0;
440         }
441
442         /* check type of card and get internal memory characteristics */
443
444         v=inb(sc->port);
445
446         if( v & 0x1 ) {
447                 switch( v&0x30 ) {
448                 case 0:
449                         sc->mem_seg=0xF000;
450                         win_size=0x10000;
451                         printf("dgb%d: PC/Xi 64K\n",dev->id_unit);
452                         break;
453                 case 0x10:
454                         sc->mem_seg=0xE000;
455                         win_size=0x20000;
456                         printf("dgb%d: PC/Xi 128K\n",dev->id_unit);
457                         break;
458                 case 0x20:
459                         sc->mem_seg=0xC000;
460                         win_size=0x40000;
461                         printf("dgb%d: PC/Xi 256K\n",dev->id_unit);
462                         break;
463                 default: /* case 0x30: */
464                         sc->mem_seg=0x8000;
465                         win_size=0x80000;
466                         printf("dgb%d: PC/Xi 512K\n",dev->id_unit);
467                         break;
468                 }
469                 sc->type=PCXI;
470         } else {
471                 outb(sc->port, 1);
472                 v=inb(sc->port);
473
474                 if( v & 0x1 ) {
475                         printf("dgb%d: PC/Xm isn't supported\n",dev->id_unit);
476                         sc->status=DISABLED;
477                         return 0;
478                         }
479
480                 sc->mem_seg=0xF000;
481
482                 if(dev->id_flags==DGBFLAG_NOWIN || ( v&0xC0 )==0) {
483                         win_size=0x10000;
484                         printf("dgb%d: PC/Xe 64K\n",dev->id_unit);
485                         sc->type=PCXE;
486                 } else {
487                         win_size=0x2000;
488                         printf("dgb%d: PC/Xe 64/8K (windowed)\n",dev->id_unit);
489                         sc->type=PCXEVE;
490                         if((u_long)sc->pmem & ~0xFFE000) {
491                                 printf("dgb%d: warning: address 0x%lx truncated to 0x%lx\n",
492                                         dev->id_unit, sc->pmem,
493                                         sc->pmem & 0xFFE000);
494
495                                 dev->id_maddr= (u_char *)(void *)(intptr_t)( sc->pmem & 0xFFE000 );
496                         }
497                 }
498         }
499
500         /* save size of vizible memory segment */
501         dev->id_msize=win_size;
502
503         /* map memory */
504         dev->id_maddr=sc->vmem=pmap_mapdev(sc->pmem,dev->id_msize);
505
506         outb(sc->port, FEPCLR); /* drop RESET */
507         hidewin(sc); /* Helg: to set initial bmws state */
508
509         return 4; /* we need I/O space of 4 ports */
510 }
511
512 static int
513 dgbattach(dev)
514         struct isa_device       *dev;
515 {
516         int unit=dev->id_unit;
517         struct dgb_softc *sc= &dgb_softc[dev->id_unit];
518         int i, t;
519         u_char volatile *mem;
520         u_char volatile *ptr;
521         int addr;
522         struct dgb_p *port;
523         volatile struct board_chan *bc;
524         int shrinkmem;
525         int nfails;
526         const volatile ushort *pstat;
527         int lowwater;
528         static int nports=0;
529         char suffix;
530
531         if(sc->status!=ENABLED) {
532                 DPRINT2(DB_EXCEPT,"dbg%d: try to attach a disabled card\n",unit);
533                 return 0;
534                 }
535
536         callout_init(&sc->dgb_pause);
537         callout_init(&sc->dgbpoll);
538         callout_init(&sc->wakeflush);
539
540         mem=sc->vmem;
541
542         DPRINT3(DB_INFO,"dgb%d: internal memory segment 0x%x\n",unit,sc->mem_seg);
543
544         outb(sc->port, FEPRST); DELAY(1);
545
546         for(i=0; (inb(sc->port) & FEPMASK) != FEPRST ; i++) {
547                 if(i>10000) {
548                         printf("dgb%d: 1st reset failed\n",dev->id_unit);
549                         sc->status=DISABLED;
550                         hidewin(sc);
551                         return 0;
552                 }
553                 DELAY(1);
554         }
555
556         DPRINT3(DB_INFO,"dgb%d: got reset after %d us\n",unit,i);
557
558         /* for PCXEVE set up interrupt and base address */
559
560         if(sc->type==PCXEVE) {
561                 t=(((u_long)sc->pmem>>8) & 0xFFE0) | 0x10 /* enable windowing */;
562                 /* IRQ isn't used */
563                 outb(sc->port+2,t & 0xFF);
564                 outb(sc->port+3,t>>8);
565         } else if(sc->type==PCXE) {
566                 t=(((u_long)sc->pmem>>8) & 0xFFE0) /* disable windowing */;
567                 outb(sc->port+2,t & 0xFF);
568                 outb(sc->port+3,t>>8);
569         }
570
571
572         if(sc->type==PCXI || sc->type==PCXE) {
573                 outb(sc->port, FEPRST|FEPMEM); DELAY(1);
574
575                 for(i=0; (inb(sc->port) & FEPMASK) != (FEPRST|FEPMEM) ; i++) {
576                         if(i>10000) {
577                                 printf("dgb%d: 2nd reset failed\n",dev->id_unit);
578                                 sc->status=DISABLED;
579                                 hidewin(sc);
580                                 return 0;
581                         }
582                         DELAY(1);
583                 }
584
585                 DPRINT3(DB_INFO,"dgb%d: got memory after %d us\n",unit,i);
586         }
587
588         mem=sc->vmem;
589
590         /* very short memory test */
591
592         addr=setinitwin(sc,BOTWIN);
593         *(u_long volatile *)(mem+addr) = 0xA55A3CC3;
594         if(*(u_long volatile *)(mem+addr)!=0xA55A3CC3) {
595                 printf("dgb%d: 1st memory test failed\n",dev->id_unit);
596                 sc->status=DISABLED;
597                 hidewin(sc);
598                 return 0;
599         }
600                 
601         addr=setinitwin(sc,TOPWIN);
602         *(u_long volatile *)(mem+addr) = 0x5AA5C33C;
603         if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
604                 printf("dgb%d: 2nd memory test failed\n",dev->id_unit);
605                 sc->status=DISABLED;
606                 hidewin(sc);
607                 return 0;
608         }
609                 
610         addr=setinitwin(sc,BIOSCODE+((0xF000-sc->mem_seg)<<4));
611         *(u_long volatile *)(mem+addr) = 0x5AA5C33C;
612         if(*(u_long volatile *)(mem+addr)!=0x5AA5C33C) {
613                 printf("dgb%d: 3rd (BIOS) memory test failed\n",dev->id_unit);
614         }
615                 
616         addr=setinitwin(sc,MISCGLOBAL);
617         for(i=0; i<16; i++) {
618                 mem[addr+i]=0;
619         }
620
621         if(sc->type==PCXI || sc->type==PCXE) {
622
623                 addr=BIOSCODE+((0xF000-sc->mem_seg)<<4);
624
625                 DPRINT3(DB_INFO,"dgb%d: BIOS local address=0x%x\n",unit,addr);
626
627                 ptr= mem+addr;
628
629                 for(i=0; i<pcxx_nbios; i++, ptr++)
630                         *ptr = pcxx_bios[i];
631
632                 ptr= mem+addr;
633
634                 nfails=0;
635                 for(i=0; i<pcxx_nbios; i++, ptr++)
636                         if( *ptr != pcxx_bios[i] ) {
637                                 DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
638 0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
639
640                                 if(++nfails>=5) {
641                                         printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
642                                         break;
643                                         }
644                                 }
645
646                 outb(sc->port,FEPMEM);
647
648                 for(i=0; (inb(sc->port) & FEPMASK) != FEPMEM ; i++) {
649                         if(i>10000) {
650                                 printf("dgb%d: BIOS start failed\n",dev->id_unit);
651                                 sc->status=DISABLED;
652                                 hidewin(sc);
653                                 return 0;
654                         }
655                         DELAY(1);
656                 }
657
658                 DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
659
660                 for(i=0; i<200000; i++) {
661                         if( *((ushort volatile *)(mem+MISCGLOBAL)) == *((ushort *)"GD") )
662                                 goto load_fep;
663                         DELAY(1);
664                 }
665                 printf("dgb%d: BIOS download failed\n",dev->id_unit);
666                 DPRINT4(DB_EXCEPT,"dgb%d: code=0x%x must be 0x%x\n",
667                         dev->id_unit,
668                         *((ushort volatile *)(mem+MISCGLOBAL)),
669                         *((ushort *)"GD"));
670
671                 sc->status=DISABLED;
672                 hidewin(sc);
673                 return 0;
674         }
675
676         if(sc->type==PCXEVE) {
677                 /* set window 7 */
678                 outb(sc->port+1,0xFF);
679
680                 ptr= mem+(BIOSCODE & 0x1FFF);
681
682                 for(i=0; i<pcxx_nbios; i++)
683                         *ptr++ = pcxx_bios[i];
684
685                 ptr= mem+(BIOSCODE & 0x1FFF);
686
687                 nfails=0;
688                 for(i=0; i<pcxx_nbios; i++, ptr++)
689                         if( *ptr != pcxx_bios[i] ) {
690                                 DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \
691 0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] );
692
693                                 if(++nfails>=5) {
694                                         printf("dgb%d: 4th memory test (BIOS load) fails\n",unit);
695                                         break;
696                                         }
697                                 }
698
699                 outb(sc->port,FEPCLR);
700
701                 setwin(sc,0);
702
703                 for(i=0; (inb(sc->port) & FEPMASK) != FEPCLR ; i++) {
704                         if(i>10000) {
705                                 printf("dgb%d: BIOS start failed\n",dev->id_unit);
706                                 sc->status=DISABLED;
707                                 hidewin(sc);
708                                 return 0;
709                         }
710                         DELAY(1);
711                 }
712
713                 DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i);
714
715                 addr=setwin(sc,MISCGLOBAL);
716
717                 for(i=0; i<200000; i++) {
718                         if(*(ushort volatile *)(mem+addr)== *(ushort *)"GD")
719                                 goto load_fep;
720                         DELAY(1);
721                 }
722                 printf("dgb%d: BIOS download failed\n",dev->id_unit);
723                 DPRINT5(DB_EXCEPT,"dgb%d: Error#(0x%x,0x%x) code=0x%x\n",
724                         dev->id_unit,
725                         *(ushort volatile *)(mem+0xC12),
726                         *(ushort volatile *)(mem+0xC14),
727                         *(ushort volatile *)(mem+MISCGLOBAL));
728
729                 sc->status=DISABLED;
730                 hidewin(sc);
731                 return 0;
732         }
733
734 load_fep:
735         DPRINT2(DB_INFO,"dgb%d: BIOS loaded\n",dev->id_unit);
736
737         addr=setwin(sc,FEPCODE);
738
739         ptr= mem+addr;
740
741         for(i=0; i<pcxx_ncook; i++)
742                 *ptr++ = pcxx_cook[i];
743
744         addr=setwin(sc,MBOX);
745         *(ushort volatile *)(mem+addr+ 0)=2;
746         *(ushort volatile *)(mem+addr+ 2)=sc->mem_seg+FEPCODESEG;
747         *(ushort volatile *)(mem+addr+ 4)=0;
748         *(ushort volatile *)(mem+addr+ 6)=FEPCODESEG;
749         *(ushort volatile *)(mem+addr+ 8)=0;
750         *(ushort volatile *)(mem+addr+10)=pcxx_ncook;
751
752         outb(sc->port,FEPMEM|FEPINT); /* send interrupt to BIOS */
753         outb(sc->port,FEPMEM);
754
755         for(i=0; *(ushort volatile *)(mem+addr)!=0; i++) {
756                 if(i>200000) {
757                         printf("dgb%d: FEP code download failed\n",unit);
758                         DPRINT3(DB_EXCEPT,"dgb%d: code=0x%x must be 0\n", unit,
759                                 *(ushort volatile *)(mem+addr));
760                         sc->status=DISABLED;
761                         hidewin(sc);
762                         return 0;
763                 }
764         }
765
766         DPRINT2(DB_INFO,"dgb%d: FEP code loaded\n",unit);
767
768         *(ushort volatile *)(mem+setwin(sc,FEPSTAT))=0;
769         addr=setwin(sc,MBOX);
770         *(ushort volatile *)(mem+addr+0)=1;
771         *(ushort volatile *)(mem+addr+2)=FEPCODESEG;
772         *(ushort volatile *)(mem+addr+4)=0x4;
773
774         outb(sc->port,FEPINT); /* send interrupt to BIOS */
775         outb(sc->port,FEPCLR);
776
777         addr=setwin(sc,FEPSTAT);
778         for(i=0; *(ushort volatile *)(mem+addr)!= *(ushort *)"OS"; i++) {
779                 if(i>200000) {
780                         printf("dgb%d: FEP/OS start failed\n",dev->id_unit);
781                         sc->status=DISABLED;
782                         hidewin(sc);
783                         return 0;
784                 }
785         }
786
787         DPRINT2(DB_INFO,"dgb%d: FEP/OS started\n",dev->id_unit);
788
789         sc->numports= *(ushort volatile *)(mem+setwin(sc,NPORT));
790
791         printf("dgb%d: %d ports\n",unit,sc->numports);
792
793         if(sc->numports > MAX_DGB_PORTS) {
794                 printf("dgb%d: too many ports\n",unit);
795                 sc->status=DISABLED;
796                 hidewin(sc);
797                 return 0;
798         }
799
800         if(nports+sc->numports>NDGBPORTS) {
801                 printf("dgb%d: only %d ports are usable\n", unit, NDGBPORTS-nports);
802                 sc->numports=NDGBPORTS-nports;
803         }
804
805         /* allocate port and tty structures */
806         sc->ports=&dgb_ports[nports];
807         sc->ttys=&dgb_tty[nports];
808         nports+=sc->numports;
809
810         addr=setwin(sc,PORTBASE);
811         pstat=(const ushort volatile *)(mem+addr);
812
813         for(i=0; i<sc->numports && pstat[i]; i++)
814                 if(pstat[i])
815                         sc->ports[i].status=ENABLED;
816                 else {
817                         sc->ports[i].status=DISABLED;
818                         printf("dgb%d: port%d is broken\n", unit, i);
819                 }
820
821         /* We should now init per-port structures */
822         bc=(volatile struct board_chan *)(mem + CHANSTRUCT);
823         sc->mailbox=(volatile struct global_data *)(mem + FEP_GLOBAL);
824
825         if(sc->numports<3)
826                 shrinkmem=1;
827         else
828                 shrinkmem=0;
829
830         for(i=0; i<sc->numports; i++, bc++) {
831                 port= &sc->ports[i];
832
833                 port->tty=&sc->ttys[i];
834                 port->unit=unit;
835
836                 port->brdchan=bc;
837
838                 if(sc->altpin) {
839                         port->dsr=CD;
840                         port->dcd=DSR;
841                 } else {
842                         port->dcd=CD;
843                         port->dsr=DSR;
844                 }
845
846                 port->pnum=i;
847
848                 if(shrinkmem) {
849                         DPRINT2(DB_INFO,"dgb%d: shrinking memory\n",unit);
850                         fepcmd(port, SETBUFFER, 32, 0, 0, 0);
851                         shrinkmem=0;
852                         }
853
854                 if(sc->type!=PCXEVE) {
855                         port->txptr=mem+((bc->tseg-sc->mem_seg)<<4);
856                         port->rxptr=mem+((bc->rseg-sc->mem_seg)<<4);
857                         port->txwin=port->rxwin=0;
858                 } else {
859                         port->txptr=mem+( ((bc->tseg-sc->mem_seg)<<4) & 0x1FFF );
860                         port->rxptr=mem+( ((bc->rseg-sc->mem_seg)<<4) & 0x1FFF );
861                         port->txwin=FEPWIN | ((bc->tseg-sc->mem_seg)>>9);
862                         port->rxwin=FEPWIN | ((bc->rseg-sc->mem_seg)>>9);
863                 }
864
865                 port->txbufhead=0;
866                 port->rxbufhead=0;
867                 port->txbufsize=bc->tmax+1;
868                 port->rxbufsize=bc->rmax+1;
869
870                 lowwater= (port->txbufsize>=2000) ? 1024 : (port->txbufsize/2);
871                 setwin(sc,0);
872                 fepcmd(port, STXLWATER, lowwater, 0, 10, 0);
873                 fepcmd(port, SRXLWATER, port->rxbufsize/4, 0, 10, 0);
874                 fepcmd(port, SRXHWATER, 3*port->rxbufsize/4, 0, 10, 0);
875
876                 bc->edelay=100;
877                 bc->idata=1;
878
879                 port->startc=bc->startc;
880                 port->startca=bc->startca;
881                 port->stopc=bc->stopc;
882                 port->stopca=bc->stopca;
883                         
884                 /*port->close_delay=50;*/
885                 port->close_delay=3 * hz;
886                 port->do_timestamp=0;
887                 port->do_dcd_timestamp=0;
888
889                 /*
890                  * We don't use all the flags from <sys/ttydefaults.h> since they
891                  * are only relevant for logins.  It's important to have echo off
892                  * initially so that the line doesn't start blathering before the
893                  * echo flag can be turned off.
894                  */
895                 port->it_in.c_iflag = TTYDEF_IFLAG;
896                 port->it_in.c_oflag = TTYDEF_OFLAG;
897                 port->it_in.c_cflag = TTYDEF_CFLAG;
898                 port->it_in.c_lflag = TTYDEF_LFLAG;
899                 termioschars(&port->it_in);
900                 port->it_in.c_ispeed = port->it_in.c_ospeed = dgbdefaultrate;
901                 port->it_out = port->it_in;
902                 /* MAX_DGB_PORTS is 32 => [0-9a-v] */
903                 suffix = i < 10 ? '0' + i : 'a' + i - 10;
904                 cdevsw_add(&dgb_cdevsw, 0xffff0000, unit << 16);
905                 make_dev(&dgb_cdevsw, (unit<<16)+i,
906                     UID_ROOT, GID_WHEEL, 0600, "ttyD%d%c", unit, suffix);
907
908                 make_dev(&dgb_cdevsw, (unit<<16)+i+32,
909                     UID_ROOT, GID_WHEEL, 0600, "ttyiD%d%c", unit, suffix);
910
911                 make_dev(&dgb_cdevsw, (unit<<16)+i+64,
912                     UID_ROOT, GID_WHEEL, 0600, "ttylD%d%c", unit, suffix);
913
914                 make_dev(&dgb_cdevsw, (unit<<16)+i+128,
915                     UID_UUCP, GID_DIALER, 0660, "cuaD%d%c", unit, suffix);
916
917                 make_dev(&dgb_cdevsw, (unit<<16)+i+160,
918                     UID_UUCP, GID_DIALER, 0660, "cuaiD%d%c", unit, suffix);
919
920                 make_dev(&dgb_cdevsw, (unit<<16)+i+192,
921                     UID_UUCP, GID_DIALER, 0660, "cualD%d%c", unit, suffix);
922         }
923
924         hidewin(sc);
925
926         /* register the polling function */
927         callout_reset(&sc->dgbpoll, hz / POLLSPERSEC, dgbpoll, (void *)unit);
928
929         return 1;
930 }
931
932 /* ARGSUSED */
933 static  int
934 dgbopen(dev_t dev, int flag, int mode, struct thread *td)
935 {
936         struct dgb_softc *sc;
937         struct tty *tp;
938         int unit;
939         int mynor;
940         int pnum;
941         struct dgb_p *port;
942         int s,cs;
943         int error;
944         volatile struct board_chan *bc;
945
946         error=0;
947
948         mynor=minor(dev);
949         unit=MINOR_TO_UNIT(mynor);
950         pnum=MINOR_TO_PORT(mynor);
951
952         if(unit >= NDGB) {
953                 DPRINT2(DB_EXCEPT,"dgb%d: try to open a nonexisting card\n",unit);
954                 return ENXIO;
955         }
956
957         sc=&dgb_softc[unit];
958
959         if(sc->status!=ENABLED) {
960                 DPRINT2(DB_EXCEPT,"dgb%d: try to open a disabled card\n",unit);
961                 return ENXIO;
962         }
963
964         if(pnum>=sc->numports) {
965                 DPRINT3(DB_EXCEPT,"dgb%d: try to open non-existing port %d\n",unit,pnum);
966                 return ENXIO;
967         }
968
969         if(mynor & CONTROL_MASK)
970                 return 0;
971
972         tp=&sc->ttys[pnum];
973         dev->si_tty = tp;
974         port=&sc->ports[pnum];
975         bc=port->brdchan;
976
977 open_top:
978         
979         s=spltty();
980
981         while(port->closing) {
982                 error=tsleep(&port->closing, PCATCH, "dgocl", 0);
983
984                 if(error) {
985                         DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgocl) error=%d\n",unit,pnum,error);
986                         goto out;
987                 }
988         }
989
990         if (tp->t_state & TS_ISOPEN) {
991                 /*
992                  * The device is open, so everything has been initialized.
993                  * Handle conflicts.
994                  */
995                 if (mynor & CALLOUT_MASK) {
996                         if (!port->active_out) {
997                                 error = EBUSY;
998                                 DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
999                                 goto out;
1000                         }
1001                 } else {
1002                         if (port->active_out) {
1003                                 if (flag & O_NONBLOCK) {
1004                                         error = EBUSY;
1005                                         DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error);
1006                                         goto out;
1007                                 }
1008                                 error = tsleep(&port->active_out,
1009                                                PCATCH, "dgbi", 0);
1010                                 if (error != 0) {
1011                                         DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgbi) error=%d\n",
1012                                                 unit,pnum,error);
1013                                         goto out;
1014                                 }
1015                                 splx(s);
1016                                 goto open_top;
1017                         }
1018                 }
1019                 if (tp->t_state & TS_XCLUDE && suser(td)) {
1020                         error = EBUSY;
1021                         goto out;
1022                 }
1023         } else {
1024                 /*
1025                  * The device isn't open, so there are no conflicts.
1026                  * Initialize it.  Initialization is done twice in many
1027                  * cases: to preempt sleeping callin opens if we are
1028                  * callout, and to complete a callin open after DCD rises.
1029                  */
1030                 tp->t_oproc=dgbstart;
1031                 tp->t_param=dgbparam;
1032                 tp->t_stop=dgbstop;
1033                 tp->t_dev=dev;
1034                 tp->t_termios= (mynor & CALLOUT_MASK) ?
1035                                                         port->it_out :
1036                                                         port->it_in;
1037
1038                 cs=splclock();
1039                 setwin(sc,0);
1040                 port->imodem=bc->mstat;
1041                 bc->rout=bc->rin; /* clear input queue */
1042                 bc->idata=1;
1043 #ifdef PRINT_BUFSIZE
1044                 printf("dgb buffers tx=%x:%x rx=%x:%x\n",bc->tseg,bc->tmax,bc->rseg,bc->rmax);
1045 #endif
1046
1047                 hidewin(sc);
1048                 splx(cs);
1049
1050                 port->wopeners++;
1051                 error=dgbparam(tp, &tp->t_termios);
1052                 port->wopeners--;
1053
1054                 if(error!=0) {
1055                         DPRINT4(DB_OPEN,"dgb%d: port%d: dgbparam error=%d\n",unit,pnum,error);
1056                         goto out;
1057                 }
1058
1059                 /* handle fake DCD for callout devices */
1060                 /* and initial DCD */
1061
1062                 if( (port->imodem & port->dcd) || mynor & CALLOUT_MASK )
1063                         linesw[tp->t_line].l_modem(tp,1);
1064
1065         }
1066
1067         /*
1068          * Wait for DCD if necessary.
1069          */
1070         if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1071             && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1072                 ++port->wopeners;
1073                 error = tsleep(TSA_CARR_ON(tp), PCATCH, "dgdcd", 0);
1074                 --port->wopeners;
1075                 if (error != 0) {
1076                         DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgdcd) error=%d\n",unit,pnum,error);
1077                         goto out;
1078                 }
1079                 splx(s);
1080                 goto open_top;
1081         }
1082         error = linesw[tp->t_line].l_open(dev, tp);
1083         disc_optim(tp,&tp->t_termios);
1084         DPRINT4(DB_OPEN,"dgb%d: port%d: l_open error=%d\n",unit,pnum,error);
1085
1086         if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1087                 port->active_out = TRUE;
1088
1089         port->used=1;
1090
1091         /* If any port is open (i.e. the open() call is completed for it) 
1092          * the device is busy
1093          */
1094
1095 out:
1096         disc_optim(tp,&tp->t_termios);
1097         splx(s);
1098
1099         if( !(tp->t_state & TS_ISOPEN) && port->wopeners==0 )
1100                 dgbhardclose(port);
1101
1102         DPRINT4(DB_OPEN,"dgb%d: port%d: open() returns %d\n",unit,pnum,error);
1103
1104         return error;
1105 }
1106
1107 /*ARGSUSED*/
1108 static  int
1109 dgbclose(dev_t dev, int flag, int mode, struct thread *td)
1110 {
1111         struct tty *tp;
1112         int unit, pnum;
1113         struct dgb_softc *sc;
1114         struct dgb_p *port;
1115         int mynor;
1116         int s;
1117         int i;
1118
1119         mynor=minor(dev);
1120         if(mynor & CONTROL_MASK)
1121                 return 0;
1122         unit=MINOR_TO_UNIT(mynor);
1123         pnum=MINOR_TO_PORT(mynor);
1124
1125         sc=&dgb_softc[unit];
1126         tp=&sc->ttys[pnum];
1127         port=sc->ports+pnum;
1128
1129         DPRINT3(DB_CLOSE,"dgb%d: port%d: closing\n",unit,pnum);
1130
1131         DPRINT3(DB_CLOSE,"dgb%d: port%d: draining port\n",unit,pnum);
1132         dgb_drain_or_flush(port);
1133
1134         s=spltty();
1135
1136         port->closing=1;
1137         DPRINT3(DB_CLOSE,"dgb%d: port%d: closing line disc\n",unit,pnum);
1138         linesw[tp->t_line].l_close(tp,flag);
1139         disc_optim(tp,&tp->t_termios);
1140
1141         DPRINT3(DB_CLOSE,"dgb%d: port%d: hard closing\n",unit,pnum);
1142         dgbhardclose(port);
1143         DPRINT3(DB_CLOSE,"dgb%d: port%d: closing tty\n",unit,pnum);
1144         ttyclose(tp);
1145         port->closing=0;
1146         wakeup(&port->closing);
1147         port->used=0;
1148
1149         /* mark the card idle when all ports are closed */
1150
1151         for(i=0; i<sc->numports; i++)
1152                 if(sc->ports[i].used)
1153                         break;
1154
1155         splx(s);
1156
1157         DPRINT3(DB_CLOSE,"dgb%d: port%d: closed\n",unit,pnum);
1158
1159         wakeup(TSA_CARR_ON(tp));
1160         wakeup(&port->active_out);
1161         port->active_out=0;
1162
1163         DPRINT3(DB_CLOSE,"dgb%d: port%d: close exit\n",unit,pnum);
1164
1165         return 0;
1166 }
1167
1168 static void
1169 dgbhardclose(port)
1170         struct dgb_p *port;
1171 {
1172         struct dgb_softc *sc=&dgb_softc[port->unit];
1173         volatile struct board_chan *bc=port->brdchan;
1174         int cs;
1175
1176         cs=splclock();
1177         port->do_timestamp = 0;
1178         setwin(sc,0);
1179
1180         bc->idata=0; bc->iempty=0; bc->ilow=0;
1181         if(port->tty->t_cflag & HUPCL) {
1182                 port->omodem &= ~(RTS|DTR);
1183                 fepcmd(port, SETMODEM, 0, DTR|RTS, 0, 1);
1184         }
1185
1186         hidewin(sc);
1187         splx(cs);
1188
1189         callout_reset(&sc->dgb_pause, hz / 2, dgb_pause, &port->brdchan);
1190         tsleep(&port->brdchan, PCATCH, "dgclo", 0);
1191 }
1192
1193 static void 
1194 dgb_pause(chan)
1195         void *chan;
1196 {
1197         wakeup((caddr_t)chan);
1198 }
1199
1200 static void
1201 dgbpoll(unit_c)
1202         void *unit_c;
1203 {
1204         int unit=(int)unit_c;
1205         int pnum;
1206         struct dgb_p *port;
1207         struct dgb_softc *sc=&dgb_softc[unit];
1208         int head, tail;
1209         u_char *eventbuf;
1210         int event, mstat, lstat;
1211         volatile struct board_chan *bc;
1212         struct tty *tp;
1213         int rhead, rtail;
1214         int whead, wtail;
1215         int size;
1216         u_char *ptr;
1217         int ocount;
1218         int ibuf_full,obuf_full;
1219
1220         BoardMemWinState ws=bmws_get();
1221
1222         if(sc->status==DISABLED) {
1223                 printf("dgb%d: polling of disabled board stopped\n",unit);
1224                 return;
1225         }
1226         
1227         setwin(sc,0);
1228
1229         head=sc->mailbox->ein;
1230         tail=sc->mailbox->eout;
1231
1232         while(head!=tail) {
1233                 if(head >= FEP_IMAX-FEP_ISTART 
1234                 || tail >= FEP_IMAX-FEP_ISTART 
1235                 || (head|tail) & 03 ) {
1236                         printf("dgb%d: event queue's head or tail is wrong! hd=%d,tl=%d\n", unit,head,tail);
1237                         break;
1238                 }
1239
1240                 eventbuf=sc->vmem+tail+FEP_ISTART;
1241                 pnum=eventbuf[0];
1242                 event=eventbuf[1];
1243                 mstat=eventbuf[2];
1244                 lstat=eventbuf[3];
1245
1246                 port=&sc->ports[pnum];
1247                 bc=port->brdchan;
1248                 tp=&sc->ttys[pnum];
1249
1250                 if(pnum>=sc->numports || port->status==DISABLED) {
1251                         printf("dgb%d: port%d: got event on nonexisting port\n",unit,pnum);
1252                 } else if(port->used || port->wopeners>0 ) {
1253
1254                         int wrapmask=port->rxbufsize-1;
1255
1256                         if( !(event & ALL_IND) ) 
1257                                 printf("dgb%d: port%d: ? event 0x%x mstat 0x%x lstat 0x%x\n",
1258                                         unit, pnum, event, mstat, lstat);
1259
1260                         if(event & DATA_IND) {
1261                                 DPRINT3(DB_DATA,"dgb%d: port%d: DATA_IND\n",unit,pnum);
1262
1263                                 rhead=bc->rin & wrapmask; 
1264                                 rtail=bc->rout & wrapmask;
1265
1266                                 if( !(tp->t_cflag & CREAD) || !port->used ) {
1267                                         bc->rout=rhead;
1268                                         goto end_of_data;
1269                                 }
1270
1271                                 if(bc->orun) {
1272                                         printf("dgb%d: port%d: overrun\n", unit, pnum);
1273                                         bc->orun=0;
1274                                 }
1275
1276                                 if(!(tp->t_state & TS_ISOPEN))
1277                                         goto end_of_data;
1278
1279                                 for(ibuf_full=FALSE;rhead!=rtail && !ibuf_full;) {
1280                                         DPRINT5(DB_RXDATA,"dgb%d: port%d: p rx head=%d tail=%d\n",
1281                                                 unit,pnum,rhead,rtail);
1282
1283                                         if(rhead>rtail)
1284                                                 size=rhead-rtail;
1285                                         else
1286                                                 size=port->rxbufsize-rtail;
1287
1288                                         ptr=__DEVOLATILE(u_char *, port->rxptr+rtail);
1289
1290 /* Helg: */
1291                                         if( tp->t_rawq.c_cc + size > DGB_IBUFSIZE ) {
1292                                                 size=DGB_IBUFSIZE-tp->t_rawq.c_cc;
1293                                                 DPRINT1(DB_RXDATA,"*");
1294                                                 ibuf_full=TRUE;
1295                                         }
1296
1297                                         if(size) {
1298                                                 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1299                                                         DPRINT1(DB_RXDATA,"!");
1300                                                         towin(sc,port->rxwin);
1301                                                         tk_nin += size;
1302                                                         tk_rawcc += size;
1303                                                         tp->t_rawcc += size;
1304                                                         b_to_q(ptr,size,&tp->t_rawq);
1305                                                         setwin(sc,0);
1306                                                 } else {
1307                                                         int i=size;
1308                                                         unsigned char chr;
1309                                                         do {
1310                                                                 towin(sc,port->rxwin);
1311                                                                 chr= *ptr++;
1312                                                                 hidewin(sc);
1313                                                                (*linesw[tp->t_line].l_rint)(chr, tp);
1314                                                         } while (--i > 0 );
1315                                                         setwin(sc,0);
1316                                                 }
1317                                         }
1318                                         rtail= (rtail + size) & wrapmask;
1319                                         bc->rout=rtail;
1320                                         rhead=bc->rin & wrapmask;
1321                                         hidewin(sc);
1322                                         ttwakeup(tp);
1323                                         setwin(sc,0);
1324                                 }
1325                         end_of_data: ;
1326                         }
1327
1328                         if(event & MODEMCHG_IND) {
1329                                 DPRINT3(DB_MODEM,"dgb%d: port%d: MODEMCHG_IND\n",unit,pnum);
1330                                 port->imodem=mstat;
1331                                 if(mstat & port->dcd) {
1332                                         hidewin(sc);
1333                                         linesw[tp->t_line].l_modem(tp,1);
1334                                         setwin(sc,0);
1335                                         wakeup(TSA_CARR_ON(tp));
1336                                 } else {
1337                                         hidewin(sc);
1338                                         linesw[tp->t_line].l_modem(tp,0);
1339                                         setwin(sc,0);
1340                                         if( port->draining) {
1341                                                 port->draining=0;
1342                                                 wakeup(&port->draining);
1343                                         }
1344                                 }
1345                         }
1346
1347                         if(event & BREAK_IND) {
1348                                 if((tp->t_state & TS_ISOPEN) && (tp->t_iflag & IGNBRK)) {
1349                                         DPRINT3(DB_BREAK,"dgb%d: port%d: BREAK_IND\n",unit,pnum);
1350                                         hidewin(sc);
1351                                         linesw[tp->t_line].l_rint(TTY_BI, tp);
1352                                         setwin(sc,0);
1353                                 }
1354                         }
1355
1356 /* Helg: with output flow control */
1357
1358                         if(event & (LOWTX_IND | EMPTYTX_IND) ) {
1359                                 DPRINT3(DB_TXDATA,"dgb%d: port%d: LOWTX_IND or EMPTYTX_IND\n",unit,pnum);
1360
1361                                 if( (event & EMPTYTX_IND ) && tp->t_outq.c_cc==0
1362                                 && port->draining) {
1363                                         port->draining=0;
1364                                         wakeup(&port->draining);
1365                                         bc->ilow=0; bc->iempty=0;
1366                                 } else {
1367
1368                                         int wrapmask=port->txbufsize-1;
1369
1370                                         for(obuf_full=FALSE; tp->t_outq.c_cc!=0 && !obuf_full; ) {
1371                                                 int s;
1372                                                 /* add "last-minute" data to write buffer */
1373                                                 if(!(tp->t_state & TS_BUSY)) {
1374                                                         hidewin(sc);
1375 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
1376                                                         ttwwakeup(tp);
1377 #else
1378                                                         if(tp->t_outq.c_cc <= tp->t_lowat) {
1379                                                                 if(tp->t_state & TS_ASLEEP) {
1380                                                                         tp->t_state &= ~TS_ASLEEP;
1381                                                                         wakeup(TSA_OLOWAT(tp));
1382                                                                 }
1383                                                                 /* selwakeup(&tp->t_wsel); */
1384                                                         }
1385 #endif
1386                                                         setwin(sc,0);
1387                                                 }
1388                                                 s=spltty();
1389
1390                                         whead=bc->tin & wrapmask;
1391                                         wtail=bc->tout & wrapmask;
1392
1393                                         if(whead<wtail)
1394                                                 size=wtail-whead-1;
1395                                         else {
1396                                                 size=port->txbufsize-whead;
1397                                                 if(wtail==0)
1398                                                         size--;
1399                                         }
1400
1401                                         if(size==0) {
1402                                                 DPRINT5(DB_WR,"dgb: head=%d tail=%d size=%d full=%d\n",
1403                                                         whead,wtail,size,obuf_full);
1404                                                 bc->iempty=1; bc->ilow=1;
1405                                                 obuf_full=TRUE;
1406                                                 splx(s);
1407                                                 break;
1408                                         }
1409
1410                                         towin(sc,port->txwin);
1411
1412                                         ocount=q_to_b(&tp->t_outq, __DEVOLATILE(u_char *, port->txptr+whead), size);
1413                                         whead+=ocount;
1414
1415                                         setwin(sc,0);
1416                                         bc->tin=whead;
1417                                         bc->tin=whead & wrapmask;
1418                                         splx(s);
1419                                 }
1420
1421                                 if(obuf_full) {
1422                                         DPRINT1(DB_WR," +BUSY\n");
1423                                         tp->t_state|=TS_BUSY;
1424                                 } else {
1425                                         DPRINT1(DB_WR," -BUSY\n");
1426                                         hidewin(sc);
1427 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
1428                                         /* should clear TS_BUSY before ttwwakeup */
1429                                         if(tp->t_state & TS_BUSY)       {
1430                                                 tp->t_state &= ~TS_BUSY;
1431                                                 linesw[tp->t_line].l_start(tp);
1432                                                 ttwwakeup(tp);
1433                                         }
1434 #else
1435                                 if(tp->t_state & TS_ASLEEP) {
1436                                         tp->t_state &= ~TS_ASLEEP;
1437                                         wakeup(TSA_OLOWAT(tp));
1438                                 }
1439                                 tp->t_state &= ~TS_BUSY;
1440 #endif
1441                                         setwin(sc,0);
1442                                         }
1443                                 }
1444                         }
1445                         bc->idata=1;   /* require event on incoming data */ 
1446
1447                 } else {
1448                         bc=port->brdchan;
1449                         DPRINT4(DB_EXCEPT,"dgb%d: port%d: got event 0x%x on closed port\n",
1450                                 unit,pnum,event);
1451                         bc->rout=bc->rin;
1452                         bc->idata=bc->iempty=bc->ilow=0;
1453                 }
1454
1455                 tail= (tail+4) & (FEP_IMAX-FEP_ISTART-4);
1456         }
1457
1458         sc->mailbox->eout=tail;
1459         bmws_set(ws);
1460
1461         callout_reset(&sc->dgbpoll, hz / POLLSPERSEC, dgbpoll, unit_c);
1462 }
1463
1464 static  int
1465 dgbioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1466 {
1467         struct dgb_softc *sc;
1468         int unit, pnum;
1469         struct dgb_p *port;
1470         int mynor;
1471         struct tty *tp;
1472         volatile struct board_chan *bc;
1473         int error;
1474         int s,cs;
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 = suser(td);
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                 cs=splclock();
1566                 setwin(sc,0);
1567                 fepcmd(port, PAUSETX, 0, 0, 0, 0);
1568                 bmws_set(ws);
1569                 splx(cs);
1570                 return 0;
1571         } else if(cmd==TIOCSTART) {
1572                 cs=splclock();
1573                 setwin(sc,0);
1574                 fepcmd(port, RESUMETX, 0, 0, 0, 0);
1575                 bmws_set(ws);
1576                 splx(cs);
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         s = spltty();
1587         error = ttioctl(tp, cmd, data, flag);
1588         disc_optim(tp,&tp->t_termios);
1589         port->mustdrain=0;
1590         if (error != ENOIOCTL) {
1591                 splx(s);
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                         splx(s);
1605                         return error;
1606                 }
1607
1608                 cs=splclock();
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                 splx(cs);
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                 cs=splclock();
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                 splx(cs);
1634                 break;
1635         case TIOCCDTR:
1636                 DPRINT3(DB_MODEM,"dgb%d: port%d: reset DTR\n",unit,pnum);
1637                 port->omodem &= ~DTR;
1638                 cs=splclock();
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                 splx(cs);
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                 cs=splclock();
1661                 setwin(sc,0);
1662                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1663                 hidewin(sc);
1664                 splx(cs);
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                 cs=splclock();
1674                 setwin(sc,0);
1675                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1676                 hidewin(sc);
1677                 splx(cs);
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                 cs=splclock();
1687                 setwin(sc,0);
1688                 fepcmd(port, SETMODEM, port->omodem, RTS|DTR, 0, 1);
1689                 hidewin(sc);
1690                 splx(cs);
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 = suser(td);
1731                 if (error != 0) {
1732                         splx(s);
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                 splx(s);
1751                 return ENOTTY;
1752         }
1753         bmws_set(ws);
1754         splx(s);
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         int cs;
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         cs=splclock();
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         splx(cs);
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 s;
1984         int wmask;
1985
1986         BoardMemWinState ws=bmws_get();
1987
1988         unit=MINOR_TO_UNIT(minor(tp->t_dev));
1989         pnum=MINOR_TO_PORT(minor(tp->t_dev));
1990         sc=&dgb_softc[unit];
1991         port=&sc->ports[pnum];
1992         bc=port->brdchan;
1993
1994         wmask=port->txbufsize-1;
1995
1996         s=spltty();
1997
1998         while( tp->t_outq.c_cc!=0 ) {
1999                 int cs;
2000 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2001                 ttwwakeup(tp);
2002 #else
2003                 if(tp->t_outq.c_cc <= tp->t_lowat) {
2004                         if(tp->t_state & TS_ASLEEP) {
2005                                 tp->t_state &= ~TS_ASLEEP;
2006                                 wakeup(TSA_OLOWAT(tp));
2007                         }
2008                         /*selwakeup(&tp->t_wsel);*/
2009                 }
2010 #endif
2011                 cs=splclock();
2012                 setwin(sc,0);
2013
2014                 head=bc->tin & wmask;
2015
2016                 do { tail=bc->tout; } while (tail != bc->tout);
2017                 tail=bc->tout & wmask;
2018
2019                 DPRINT5(DB_WR,"dgb%d: port%d: s tx head=%d tail=%d\n",unit,pnum,head,tail);
2020
2021 #ifdef LEAVE_FREE_CHARS 
2022                 if(tail>head) {
2023                         size=tail-head-LEAVE_FREE_CHARS;
2024                         if (size <0)
2025                                 size=0;
2026                         } else {
2027                                 size=port->txbufsize-head;
2028                                 if(tail+port->txbufsize < head)
2029                                         size=0;
2030                         }
2031                 }
2032 #else
2033                 if(tail>head)
2034                         size=tail-head-1;
2035                 else {
2036                         size=port->txbufsize-head/*-1*/;
2037                         if(tail==0)
2038                                 size--;
2039                 }
2040 #endif
2041
2042                 if(size==0) {
2043                         bc->iempty=1; bc->ilow=1;
2044                         splx(cs);
2045                         bmws_set(ws);
2046                         tp->t_state|=TS_BUSY;
2047                         splx(s);
2048                         return;
2049                 }
2050
2051                 towin(sc,port->txwin);
2052
2053                 ocount=q_to_b(&tp->t_outq, __DEVOLATILE(u_char *, port->txptr+head), size);
2054                 head+=ocount;
2055                 if(head>=port->txbufsize)
2056                         head-=port->txbufsize;
2057
2058                 setwin(sc,0);
2059                 bc->tin=head;
2060
2061                 DPRINT5(DB_WR,"dgb%d: port%d: tx avail=%d count=%d\n",unit,pnum,size,ocount);
2062                 hidewin(sc);
2063                 splx(cs);
2064         }
2065
2066         bmws_set(ws);
2067         splx(s);
2068
2069 #ifndef TS_ASLEEP       /* post 2.0.5 FreeBSD */
2070         if(tp->t_state & TS_BUSY) {     
2071                 tp->t_state&=~TS_BUSY;
2072                 linesw[tp->t_line].l_start(tp);
2073                 ttwwakeup(tp);
2074         }
2075 #else
2076         if(tp->t_state & TS_ASLEEP) {
2077                 tp->t_state &= ~TS_ASLEEP;
2078                 wakeup(TSA_OLOWAT(tp));
2079         }
2080         tp->t_state&=~TS_BUSY;
2081 #endif
2082 }
2083
2084 void
2085 dgbstop(tp, rw)
2086         struct tty      *tp;
2087         int             rw;
2088 {
2089         int unit;
2090         int pnum;
2091         struct dgb_p *port;
2092         struct dgb_softc *sc;
2093         volatile struct board_chan *bc;
2094         int s;
2095
2096         BoardMemWinState ws=bmws_get();
2097
2098         unit=MINOR_TO_UNIT(minor(tp->t_dev));
2099         pnum=MINOR_TO_PORT(minor(tp->t_dev));
2100
2101         sc=&dgb_softc[unit];
2102         port=&sc->ports[pnum];
2103         bc=port->brdchan;
2104
2105         DPRINT3(DB_WR,"dgb%d: port%d: stop\n",port->unit, port->pnum);
2106
2107         s = spltty();
2108         setwin(sc,0);
2109
2110         if (rw & FWRITE) {
2111                 /* clear output queue */
2112                 bc->tout=bc->tin=0;
2113                 bc->ilow=0;bc->iempty=0;
2114         }
2115         if (rw & FREAD) {
2116                 /* clear input queue */
2117                 bc->rout=bc->rin;
2118                 bc->idata=1;
2119         }
2120         hidewin(sc);
2121         bmws_set(ws);
2122         splx(s);
2123         dgbstart(tp);
2124 }
2125
2126 static void 
2127 fepcmd(port, cmd, op1, op2, ncmds, bytecmd)
2128         struct dgb_p *port;
2129         unsigned cmd, op1, op2, ncmds, bytecmd;
2130 {
2131         struct dgb_softc *sc=&dgb_softc[port->unit];
2132         u_char *mem=sc->vmem;
2133         unsigned tail, head;
2134         int count, n;
2135
2136         if(port->status==DISABLED) {
2137                 printf("dgb%d: port%d: FEP command on disabled port\n", 
2138                         port->unit, port->pnum);
2139                 return;
2140         }
2141
2142         /* setwin(sc,0); Require this to be set by caller */
2143         head=sc->mailbox->cin;
2144
2145         if(head>=(FEP_CMAX-FEP_CSTART) || (head & 3)) {
2146                 printf("dgb%d: port%d: wrong pointer head of command queue : 0x%x\n",
2147                         port->unit, port->pnum, head);
2148                 return;
2149         }
2150
2151         mem[head+FEP_CSTART+0]=cmd;
2152         mem[head+FEP_CSTART+1]=port->pnum;
2153         if(bytecmd) {
2154                 mem[head+FEP_CSTART+2]=op1;
2155                 mem[head+FEP_CSTART+3]=op2;
2156         } else {
2157                 mem[head+FEP_CSTART+2]=op1&0xff;
2158                 mem[head+FEP_CSTART+3]=(op1>>8)&0xff;
2159         }
2160
2161         DPRINT7(DB_FEP,"dgb%d: port%d: %s cmd=0x%x op1=0x%x op2=0x%x\n", port->unit, port->pnum,
2162                         (bytecmd)?"byte":"word", cmd, mem[head+FEP_CSTART+2], mem[head+FEP_CSTART+3]);
2163
2164         head=(head+4) & (FEP_CMAX-FEP_CSTART-4);
2165         sc->mailbox->cin=head;
2166
2167         count=FEPTIMEOUT;
2168
2169         while (count-- != 0) {
2170                 head=sc->mailbox->cin;
2171                 tail=sc->mailbox->cout;
2172
2173                 n = (head-tail) & (FEP_CMAX-FEP_CSTART-4);
2174                 if(n <= ncmds * (sizeof(ushort)*4))
2175                         return;
2176         }
2177         printf("dgb%d(%d): timeout on FEP cmd=0x%x\n", port->unit, port->pnum, cmd);
2178 }
2179
2180 static void 
2181 disc_optim(tp, t)
2182         struct tty      *tp;
2183         struct termios  *t;
2184 {
2185         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2186             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2187             && (!(t->c_iflag & PARMRK)
2188                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2189             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2190             && linesw[tp->t_line].l_rint == ttyinput)
2191                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2192         else
2193                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2194 }