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