The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/gnu/i386/isa/dgb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: c8e53bf830ea928b1b001e5200732382


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.