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/dev/digi/digi.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  * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
    3  *   based on work by Slawa Olhovchenkov
    4  *                    John Prince <johnp@knight-trosoft.com>
    5  *                    Eric Hernes
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD: releng/8.4/sys/dev/digi/digi.c 162711 2006-09-27 19:57:02Z ru $
   30  */
   31 
   32 /*-
   33  * TODO:
   34  *      Figure out what the con bios stuff is supposed to do
   35  *      Test with *LOTS* more cards - I only have a PCI8r and an ISA Xem.
   36  */
   37 
   38 #include "opt_compat.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/proc.h>
   43 #include <sys/conf.h>
   44 #include <sys/linker.h>
   45 #include <sys/kernel.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/malloc.h>
   48 #include <sys/module.h>
   49 #include <sys/tty.h>
   50 #include <sys/syslog.h>
   51 #include <sys/fcntl.h>
   52 #include <sys/serial.h>
   53 #include <sys/bus.h>
   54 #include <machine/resource.h>
   55 
   56 #include <sys/digiio.h>
   57 #include <dev/digi/digireg.h>
   58 #include <dev/digi/digi.h>
   59 #include <dev/digi/digi_mod.h>
   60 #include <dev/digi/digi_pci.h>
   61 
   62 static t_open_t         digiopen;
   63 static d_open_t         digicopen;
   64 static d_close_t        digicclose;
   65 static t_ioctl_t        digiioctl;
   66 static d_ioctl_t        digisioctl;
   67 static d_ioctl_t        digicioctl;
   68 
   69 static void     digistop(struct tty *tp, int rw);
   70 static void     digibreak(struct tty *tp, int brk);
   71 static int      digimodem(struct tty *tp, int sigon, int sigoff);
   72 static void     digi_poll(void *ptr);
   73 static void     digi_freemoduledata(struct digi_softc *);
   74 static void     fepcmd(struct digi_p *port, int cmd, int op, int ncmds);
   75 static void     digistart(struct tty *tp);
   76 static int      digiparam(struct tty *tp, struct termios *t);
   77 static void     digiclose(struct tty *tp);
   78 static void     digi_intr(void *);
   79 static int      digi_init(struct digi_softc *_sc);
   80 static int      digi_loadmoduledata(struct digi_softc *);
   81 static int      digi_inuse(struct digi_softc *);
   82 static void     digi_free_state(struct digi_softc *);
   83 
   84 #define fepcmd_b(port, cmd, op1, op2, ncmds) \
   85         fepcmd(port, cmd, (op2 << 8) | op1, ncmds)
   86 #define fepcmd_w        fepcmd
   87 
   88 struct con_bios {
   89         struct con_bios *next;
   90         u_char *bios;
   91         size_t size;
   92 };
   93 
   94 static struct con_bios *con_bios_list;
   95 devclass_t       digi_devclass;
   96 static char      driver_name[] = "digi";
   97 unsigned         digi_debug = 0;
   98 
   99 static struct speedtab digispeedtab[] = {
  100         { 0,            0},                     /* old (sysV-like) Bx codes */
  101         { 50,           1},
  102         { 75,           2},
  103         { 110,          3},
  104         { 134,          4},
  105         { 150,          5},
  106         { 200,          6},
  107         { 300,          7},
  108         { 600,          8},
  109         { 1200,         9},
  110         { 1800,         10},
  111         { 2400,         11},
  112         { 4800,         12},
  113         { 9600,         13},
  114         { 19200,        14},
  115         { 38400,        15},
  116         { 57600,        (02000 | 1)},
  117         { 76800,        (02000 | 2)},
  118         { 115200,       (02000 | 3)},
  119         { 230400,       (02000 | 6)},
  120         { -1,           -1}
  121 };
  122 
  123 const struct digi_control_signals digi_xixe_signals = {
  124         0x02, 0x08, 0x10, 0x20, 0x40, 0x80
  125 };
  126 
  127 const struct digi_control_signals digi_normal_signals = {
  128         0x02, 0x80, 0x20, 0x10, 0x40, 0x01
  129 };
  130 
  131 static struct cdevsw digi_csw = {
  132         .d_version =    D_VERSION,
  133         .d_open =       digicopen,
  134         .d_close =      digicclose,
  135         .d_ioctl =      digicioctl,
  136         .d_name =       driver_name,
  137         .d_flags =      D_TTY | D_NEEDGIANT,
  138 };
  139 
  140 static void
  141 digi_poll(void *ptr)
  142 {
  143         struct digi_softc *sc;
  144 
  145         sc = (struct digi_softc *)ptr;
  146         callout_handle_init(&sc->callout);
  147         digi_intr(sc);
  148         sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1);
  149 }
  150 
  151 static void
  152 digi_int_test(void *v)
  153 {
  154         struct digi_softc *sc = v;
  155 
  156         callout_handle_init(&sc->inttest);
  157 #ifdef DIGI_INTERRUPT
  158         if (sc->intr_timestamp.tv_sec || sc->intr_timestamp.tv_usec) {
  159                 /* interrupt OK! */
  160                 return;
  161         }
  162         log(LOG_ERR, "digi%d: Interrupt didn't work, use polled mode\n", unit);
  163 #endif
  164         sc->callout = timeout(digi_poll, sc, (hz >= 200) ? hz / 100 : 1);
  165 }
  166 
  167 static void
  168 digi_freemoduledata(struct digi_softc *sc)
  169 {
  170         if (sc->fep.data != NULL) {
  171                 free(sc->fep.data, M_TTYS);
  172                 sc->fep.data = NULL;
  173         }
  174         if (sc->link.data != NULL) {
  175                 free(sc->link.data, M_TTYS);
  176                 sc->link.data = NULL;
  177         }
  178         if (sc->bios.data != NULL) {
  179                 free(sc->bios.data, M_TTYS);
  180                 sc->bios.data = NULL;
  181         }
  182 }
  183 
  184 static int
  185 digi_bcopy(const void *vfrom, void *vto, size_t sz)
  186 {
  187         volatile const char *from = (volatile const char *)vfrom;
  188         volatile char *to = (volatile char *)vto;
  189         size_t i;
  190 
  191         for (i = 0; i < sz; i++)
  192                 *to++ = *from++;
  193 
  194         from = (const volatile char *)vfrom;
  195         to = (volatile char *)vto;
  196         for (i = 0; i < sz; i++)
  197                 if (*to++ != *from++)
  198                         return (0);
  199         return (1);
  200 }
  201 
  202 void
  203 digi_delay(struct digi_softc *sc, const char *txt, u_long timo)
  204 {
  205         if (cold)
  206                 DELAY(timo * 1000000 / hz);
  207         else
  208                 tsleep(sc, PUSER | PCATCH, txt, timo);
  209 }
  210 
  211 static int
  212 digi_init(struct digi_softc *sc)
  213 {
  214         int i, cnt, resp;
  215         u_char *ptr;
  216         int lowwater;
  217         struct digi_p *port;
  218         volatile struct board_chan *bc;
  219         struct tty *tp;
  220 
  221         ptr = NULL;
  222 
  223         if (sc->status == DIGI_STATUS_DISABLED) {
  224                 log(LOG_ERR, "digi%d: Cannot init a disabled card\n",
  225                     sc->res.unit);
  226                 return (EIO);
  227         }
  228         if (sc->bios.data == NULL) {
  229                 log(LOG_ERR, "digi%d: Cannot init without BIOS\n",
  230                     sc->res.unit);
  231                 return (EIO);
  232         }
  233 #if 0
  234         if (sc->link.data == NULL && sc->model >= PCCX) {
  235                 log(LOG_ERR, "digi%d: Cannot init without link info\n",
  236                     sc->res.unit);
  237                 return (EIO);
  238         }
  239 #endif
  240         if (sc->fep.data == NULL) {
  241                 log(LOG_ERR, "digi%d: Cannot init without fep code\n",
  242                     sc->res.unit);
  243                 return (EIO);
  244         }
  245         sc->status = DIGI_STATUS_NOTINIT;
  246 
  247         if (sc->numports) {
  248                 /*
  249                  * We're re-initialising - maybe because someone's attached
  250                  * another port module.  For now, we just re-initialise
  251                  * everything.
  252                  */
  253                 if (digi_inuse(sc))
  254                         return (EBUSY);
  255 
  256                 digi_free_state(sc);
  257         }
  258 
  259         ptr = sc->setwin(sc, MISCGLOBAL);
  260         for (i = 0; i < 16; i += 2)
  261                 vW(ptr + i) = 0;
  262 
  263         switch (sc->model) {
  264         case PCXEVE:
  265                 outb(sc->wport, 0xff);          /* window 7 */
  266                 ptr = sc->vmem + (BIOSCODE & 0x1fff);
  267 
  268                 if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) {
  269                         device_printf(sc->dev, "BIOS upload failed\n");
  270                         return (EIO);
  271                 }
  272 
  273                 outb(sc->port, FEPCLR);
  274                 break;
  275 
  276         case PCXE:
  277         case PCXI:
  278         case PCCX:
  279                 ptr = sc->setwin(sc, BIOSCODE + ((0xf000 - sc->mem_seg) << 4));
  280                 if (!digi_bcopy(sc->bios.data, ptr, sc->bios.size)) {
  281                         device_printf(sc->dev, "BIOS upload failed\n");
  282                         return (EIO);
  283                 }
  284                 break;
  285 
  286         case PCXEM:
  287         case PCIEPCX:
  288         case PCIXR:
  289                 if (sc->pcibus)
  290                         PCIPORT = FEPRST;
  291                 else
  292                         outb(sc->port, FEPRST | FEPMEM);
  293 
  294                 for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) &
  295                     FEPMASK) != FEPRST; i++) {
  296                         if (i > hz) {
  297                                 log(LOG_ERR, "digi%d: %s init reset failed\n",
  298                                     sc->res.unit, sc->name);
  299                                 return (EIO);
  300                         }
  301                         digi_delay(sc, "digiinit0", 5);
  302                 }
  303                 DLOG(DIGIDB_INIT, (sc->dev, "Got init reset after %d us\n", i));
  304 
  305                 /* Now upload the BIOS */
  306                 cnt = (sc->bios.size < sc->win_size - BIOSOFFSET) ?
  307                     sc->bios.size : sc->win_size - BIOSOFFSET;
  308 
  309                 ptr = sc->setwin(sc, BIOSOFFSET);
  310                 if (!digi_bcopy(sc->bios.data, ptr, cnt)) {
  311                         device_printf(sc->dev, "BIOS upload (1) failed\n");
  312                         return (EIO);
  313                 }
  314 
  315                 if (cnt != sc->bios.size) {
  316                         /* and the second part */
  317                         ptr = sc->setwin(sc, sc->win_size);
  318                         if (!digi_bcopy(sc->bios.data + cnt, ptr,
  319                             sc->bios.size - cnt)) {
  320                                 device_printf(sc->dev, "BIOS upload failed\n");
  321                                 return (EIO);
  322                         }
  323                 }
  324 
  325                 ptr = sc->setwin(sc, 0);
  326                 vW(ptr + 0) = 0x0401;
  327                 vW(ptr + 2) = 0x0bf0;
  328                 vW(ptr + 4) = 0x0000;
  329                 vW(ptr + 6) = 0x0000;
  330 
  331                 break;
  332         }
  333 
  334         DLOG(DIGIDB_INIT, (sc->dev, "BIOS uploaded\n"));
  335 
  336         ptr = sc->setwin(sc, MISCGLOBAL);
  337         W(ptr) = 0;
  338 
  339         if (sc->pcibus) {
  340                 PCIPORT = FEPCLR;
  341                 resp = FEPRST;
  342         } else if (sc->model == PCXEVE) {
  343                 outb(sc->port, FEPCLR);
  344                 resp = FEPRST;
  345         } else {
  346                 outb(sc->port, FEPCLR | FEPMEM);
  347                 resp = FEPRST | FEPMEM;
  348         }
  349 
  350         for (i = 0; ((sc->pcibus ? PCIPORT : inb(sc->port)) & FEPMASK)
  351             == resp; i++) {
  352                 if (i > hz) {
  353                         log(LOG_ERR, "digi%d: BIOS start failed\n",
  354                             sc->res.unit);
  355                         return (EIO);
  356                 }
  357                 digi_delay(sc, "digibios0", 5);
  358         }
  359 
  360         DLOG(DIGIDB_INIT, (sc->dev, "BIOS started after %d us\n", i));
  361 
  362         for (i = 0; vW(ptr) != *(u_short *)"GD"; i++) {
  363                 if (i > 5*hz) {
  364                         log(LOG_ERR, "digi%d: BIOS boot failed "
  365                             "(0x%02x != 0x%02x)\n",
  366                             sc->res.unit, vW(ptr), *(u_short *)"GD");
  367                         return (EIO);
  368                 }
  369                 digi_delay(sc, "digibios1", 5);
  370         }
  371 
  372         DLOG(DIGIDB_INIT, (sc->dev, "BIOS booted after %d iterations\n", i));
  373 
  374         if (sc->link.data != NULL) {
  375                 DLOG(DIGIDB_INIT, (sc->dev, "Loading link data\n"));
  376                 ptr = sc->setwin(sc, 0xcd0);
  377                 digi_bcopy(sc->link.data, ptr, 21);     /* XXX 21 ? */
  378         }
  379 
  380         /* load FEP/OS */
  381 
  382         switch (sc->model) {
  383         case PCXE:
  384         case PCXEVE:
  385         case PCXI:
  386                 ptr = sc->setwin(sc, sc->model == PCXI ? 0x2000 : 0x0);
  387                 digi_bcopy(sc->fep.data, ptr, sc->fep.size);
  388 
  389                 /* A BIOS request to move our data to 0x2000 */
  390                 ptr = sc->setwin(sc, MBOX);
  391                 vW(ptr + 0) = 2;
  392                 vW(ptr + 2) = sc->mem_seg + FEPCODESEG;
  393                 vW(ptr + 4) = 0;
  394                 vW(ptr + 6) = FEPCODESEG;
  395                 vW(ptr + 8) = 0;
  396                 vW(ptr + 10) = sc->fep.size;
  397 
  398                 /* Run the BIOS request */
  399                 outb(sc->port, FEPREQ | FEPMEM);
  400                 outb(sc->port, FEPCLR | FEPMEM);
  401 
  402                 for (i = 0; W(ptr); i++) {
  403                         if (i > hz) {
  404                                 log(LOG_ERR, "digi%d: FEP/OS move failed\n",
  405                                     sc->res.unit);
  406                                 sc->hidewin(sc);
  407                                 return (EIO);
  408                         }
  409                         digi_delay(sc, "digifep0", 5);
  410                 }
  411                 DLOG(DIGIDB_INIT,
  412                     (sc->dev, "FEP/OS moved after %d iterations\n", i));
  413 
  414                 /* Clear the confirm word */
  415                 ptr = sc->setwin(sc, FEPSTAT);
  416                 vW(ptr + 0) = 0;
  417 
  418                 /* A BIOS request to execute the FEP/OS */
  419                 ptr = sc->setwin(sc, MBOX);
  420                 vW(ptr + 0) = 0x01;
  421                 vW(ptr + 2) = FEPCODESEG;
  422                 vW(ptr + 4) = 0x04;
  423 
  424                 /* Run the BIOS request */
  425                 outb(sc->port, FEPREQ);
  426                 outb(sc->port, FEPCLR);
  427 
  428                 ptr = sc->setwin(sc, FEPSTAT);
  429 
  430                 break;
  431 
  432         case PCXEM:
  433         case PCIEPCX:
  434         case PCIXR:
  435                 DLOG(DIGIDB_INIT, (sc->dev, "Loading FEP/OS\n"));
  436 
  437                 cnt = (sc->fep.size < sc->win_size - BIOSOFFSET) ?
  438                     sc->fep.size : sc->win_size - BIOSOFFSET;
  439 
  440                 ptr = sc->setwin(sc, BIOSOFFSET);
  441                 digi_bcopy(sc->fep.data, ptr, cnt);
  442 
  443                 if (cnt != sc->fep.size) {
  444                         ptr = sc->setwin(sc, BIOSOFFSET + cnt);
  445                         digi_bcopy(sc->fep.data + cnt, ptr,
  446                             sc->fep.size - cnt);
  447                 }
  448 
  449                 DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS loaded\n"));
  450 
  451                 ptr = sc->setwin(sc, 0xc30);
  452                 W(ptr + 4) = 0x1004;
  453                 W(ptr + 6) = 0xbfc0;
  454                 W(ptr + 0) = 0x03;
  455                 W(ptr + 2) = 0x00;
  456 
  457                 /* Clear the confirm word */
  458                 ptr = sc->setwin(sc, FEPSTAT);
  459                 W(ptr + 0) = 0;
  460 
  461                 if (sc->port)
  462                         outb(sc->port, 0);              /* XXX necessary ? */
  463 
  464                 break;
  465 
  466         case PCCX:
  467                 ptr = sc->setwin(sc, 0xd000);
  468                 digi_bcopy(sc->fep.data, ptr, sc->fep.size);
  469 
  470                 /* A BIOS request to execute the FEP/OS */
  471                 ptr = sc->setwin(sc, 0xc40);
  472                 W(ptr + 0) = 1;
  473                 W(ptr + 2) = FEPCODE >> 4;
  474                 W(ptr + 4) = 4;
  475 
  476                 /* Clear the confirm word */
  477                 ptr = sc->setwin(sc, FEPSTAT);
  478                 W(ptr + 0) = 0;
  479 
  480                 /* Run the BIOS request */
  481                 outb(sc->port, FEPREQ | FEPMEM); /* send interrupt to BIOS */
  482                 outb(sc->port, FEPCLR | FEPMEM);
  483                 break;
  484         }
  485 
  486         /* Now wait 'till the FEP/OS has booted */
  487         for (i = 0; vW(ptr) != *(u_short *)"OS"; i++) {
  488                 if (i > 2*hz) {
  489                         log(LOG_ERR, "digi%d: FEP/OS start failed "
  490                             "(0x%02x != 0x%02x)\n",
  491                             sc->res.unit, vW(ptr), *(u_short *)"OS");
  492                         sc->hidewin(sc);
  493                         return (EIO);
  494                 }
  495                 digi_delay(sc, "digifep1", 5);
  496         }
  497 
  498         DLOG(DIGIDB_INIT, (sc->dev, "FEP/OS started after %d iterations\n", i));
  499 
  500         if (sc->model >= PCXEM) {
  501                 ptr = sc->setwin(sc, 0xe04);
  502                 vW(ptr) = 2;
  503                 ptr = sc->setwin(sc, 0xc02);
  504                 sc->numports = vW(ptr);
  505         } else {
  506                 ptr = sc->setwin(sc, 0xc22);
  507                 sc->numports = vW(ptr);
  508         }
  509 
  510         if (sc->numports == 0) {
  511                 device_printf(sc->dev, "%s, 0 ports found\n", sc->name);
  512                 sc->hidewin(sc);
  513                 return (0);
  514         }
  515 
  516         device_printf(sc->dev, "%s, %d ports found\n", sc->name, sc->numports);
  517 
  518         if (sc->ports)
  519                 free(sc->ports, M_TTYS);
  520         sc->ports = malloc(sizeof(struct digi_p) * sc->numports,
  521             M_TTYS, M_WAITOK | M_ZERO);
  522 
  523         /*
  524          * XXX Should read port 0xc90 for an array of 2byte values, 1 per
  525          * port.  If the value is 0, the port is broken....
  526          */
  527 
  528         ptr = sc->setwin(sc, 0);
  529 
  530         /* We should now init per-port structures */
  531         bc = (volatile struct board_chan *)(ptr + CHANSTRUCT);
  532         sc->gdata = (volatile struct global_data *)(ptr + FEP_GLOBAL);
  533 
  534         sc->memcmd = ptr + sc->gdata->cstart;
  535         sc->memevent = ptr + sc->gdata->istart;
  536 
  537         for (i = 0; i < sc->numports; i++, bc++) {
  538                 port = sc->ports + i;
  539                 port->pnum = i;
  540                 port->sc = sc;
  541                 port->status = ENABLED;
  542                 port->bc = bc;
  543                 tp = port->tp = ttyalloc();
  544                 tp->t_oproc = digistart;
  545                 tp->t_param = digiparam;
  546                 tp->t_modem = digimodem;
  547                 tp->t_break = digibreak;
  548                 tp->t_stop = digistop;
  549                 tp->t_cioctl = digisioctl;
  550                 tp->t_ioctl = digiioctl;
  551                 tp->t_open = digiopen;
  552                 tp->t_close = digiclose;
  553                 tp->t_sc = port;
  554 
  555                 if (sc->model == PCXEVE) {
  556                         port->txbuf = ptr +
  557                             (((bc->tseg - sc->mem_seg) << 4) & 0x1fff);
  558                         port->rxbuf = ptr +
  559                             (((bc->rseg - sc->mem_seg) << 4) & 0x1fff);
  560                         port->txwin = FEPWIN | ((bc->tseg - sc->mem_seg) >> 9);
  561                         port->rxwin = FEPWIN | ((bc->rseg - sc->mem_seg) >> 9);
  562                 } else if (sc->model == PCXI || sc->model == PCXE) {
  563                         port->txbuf = ptr + ((bc->tseg - sc->mem_seg) << 4);
  564                         port->rxbuf = ptr + ((bc->rseg - sc->mem_seg) << 4);
  565                         port->txwin = port->rxwin = 0;
  566                 } else {
  567                         port->txbuf = ptr +
  568                             (((bc->tseg - sc->mem_seg) << 4) % sc->win_size);
  569                         port->rxbuf = ptr +
  570                             (((bc->rseg - sc->mem_seg) << 4) % sc->win_size);
  571                         port->txwin = FEPWIN |
  572                             (((bc->tseg - sc->mem_seg) << 4) / sc->win_size);
  573                         port->rxwin = FEPWIN |
  574                             (((bc->rseg - sc->mem_seg) << 4) / sc->win_size);
  575                 }
  576                 port->txbufsize = bc->tmax + 1;
  577                 port->rxbufsize = bc->rmax + 1;
  578 
  579                 lowwater = port->txbufsize >> 2;
  580                 if (lowwater > 1024)
  581                         lowwater = 1024;
  582                 sc->setwin(sc, 0);
  583                 fepcmd_w(port, STXLWATER, lowwater, 10);
  584                 fepcmd_w(port, SRXLWATER, port->rxbufsize >> 2, 10);
  585                 fepcmd_w(port, SRXHWATER, (3 * port->rxbufsize) >> 2, 10);
  586 
  587                 bc->edelay = 100;
  588 
  589                 ttyinitmode(tp, 0, 0);
  590                 port->send_ring = 1;    /* Default action on signal RI */
  591                 ttycreate(tp, TS_CALLOUT, "D%r%r", sc->res.unit, i);
  592         }
  593 
  594         sc->hidewin(sc);
  595         sc->inttest = timeout(digi_int_test, sc, hz);
  596         /* fepcmd_w(&sc->ports[0], 0xff, 0, 0); */
  597         sc->status = DIGI_STATUS_ENABLED;
  598 
  599         return (0);
  600 }
  601 
  602 static int
  603 digimodem(struct tty *tp, int sigon, int sigoff)
  604 {
  605         struct digi_softc *sc;
  606         struct digi_p *port;
  607         int bitand, bitor, mstat;
  608 
  609         port = tp->t_sc;
  610         sc = port->sc;
  611 
  612         if (sigon == 0 && sigoff == 0) {
  613                 port->sc->setwin(port->sc, 0);
  614                 mstat = port->bc->mstat;
  615                 port->sc->hidewin(port->sc);
  616                 if (mstat & port->sc->csigs->rts)
  617                         sigon |= SER_RTS;
  618                 if (mstat & port->cd)
  619                         sigon |= SER_DCD;
  620                 if (mstat & port->dsr)
  621                         sigon |= SER_DSR;
  622                 if (mstat & port->sc->csigs->cts)
  623                         sigon |= SER_CTS;
  624                 if (mstat & port->sc->csigs->ri)
  625                         sigon |= SER_RI;
  626                 if (mstat & port->sc->csigs->dtr)
  627                         sigon |= SER_DTR;
  628                 return (sigon);
  629         }
  630 
  631         bitand = 0;
  632         bitor = 0;
  633 
  634         if (sigoff & SER_DTR)
  635                 bitand |= port->sc->csigs->dtr;
  636         if (sigoff & SER_RTS)
  637                 bitand |= port->sc->csigs->rts;
  638         if (sigon & SER_DTR)
  639                 bitor |= port->sc->csigs->dtr;
  640         if (sigon & SER_RTS)
  641                 bitor |= port->sc->csigs->rts;
  642         fepcmd_b(port, SETMODEM, bitor, ~bitand, 0);
  643         return (0);
  644 }
  645 
  646 static int
  647 digicopen(struct cdev *dev, int flag, int mode, struct thread *td)
  648 {
  649         struct digi_softc *sc;
  650 
  651         sc = dev->si_drv1;
  652         if (sc->status != DIGI_STATUS_ENABLED) {
  653                 DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n"));
  654                 return (ENXIO);
  655         }
  656         sc->opencnt++;
  657         return (0);
  658 }
  659 
  660 static int
  661 digiopen(struct tty *tp, struct cdev *dev)
  662 {
  663         int error;
  664         struct digi_softc *sc;
  665         struct digi_p *port;
  666         volatile struct board_chan *bc;
  667 
  668         port = tp->t_sc;
  669         sc = port->sc;
  670 
  671         if (sc->status != DIGI_STATUS_ENABLED) {
  672                 DLOG(DIGIDB_OPEN, (sc->dev, "Cannot open a disabled card\n"));
  673                 return (ENXIO);
  674         }
  675         bc = port->bc;
  676 
  677         /*
  678          * The device isn't open, so there are no conflicts.
  679          * Initialize it.  Initialization is done twice in many
  680          * cases: to preempt sleeping callin opens if we are callout,
  681          * and to complete a callin open after DCD rises.
  682          */
  683         sc->setwin(sc, 0);
  684 
  685         bc->rout = bc->rin;     /* clear input queue */
  686         bc->idata = 1;
  687         bc->iempty = 1;
  688         bc->ilow = 1;
  689         bc->mint = port->cd | port->sc->csigs->ri;
  690         bc->tin = bc->tout;
  691         if (port->ialtpin) {
  692                 port->cd = sc->csigs->dsr;
  693                 port->dsr = sc->csigs->cd;
  694         } else {
  695                 port->cd = sc->csigs->cd;
  696                 port->dsr = sc->csigs->dsr;
  697         }
  698         tp->t_wopeners++;                       /* XXX required ? */
  699         error = digiparam(tp, &tp->t_termios);
  700         tp->t_wopeners--;
  701 
  702         return (error);
  703 }
  704 
  705 static int
  706 digicclose(struct cdev *dev, int flag, int mode, struct thread *td)
  707 {
  708         struct digi_softc *sc;
  709 
  710         sc = dev->si_drv1;
  711         sc->opencnt--;
  712         return (0);
  713 }
  714 
  715 static void
  716 digidtrwakeup(void *chan)
  717 {
  718         struct digi_p *port = chan;
  719 
  720         port->status &= ~DIGI_DTR_OFF;
  721         wakeup(&port->tp->t_dtr_wait);
  722         port->tp->t_wopeners--;
  723 }
  724 
  725 static void
  726 digiclose(struct tty *tp)
  727 {
  728         volatile struct board_chan *bc;
  729         struct digi_p *port;
  730         int s;
  731 
  732         port = tp->t_sc;
  733         bc = port->bc;
  734 
  735         s = spltty();
  736         port->sc->setwin(port->sc, 0);
  737         bc->idata = 0;
  738         bc->iempty = 0;
  739         bc->ilow = 0;
  740         bc->mint = 0;
  741         if ((tp->t_cflag & HUPCL) ||
  742             (!tp->t_actout && !(bc->mstat & port->cd) &&
  743             !(tp->t_init_in.c_cflag & CLOCAL)) ||
  744             !(tp->t_state & TS_ISOPEN)) {
  745                 digimodem(tp, 0, SER_DTR | SER_RTS);
  746                 if (tp->t_dtr_wait != 0) {
  747                         /* Schedule a wakeup of any callin devices */
  748                         tp->t_wopeners++;
  749                         timeout(&digidtrwakeup, port, tp->t_dtr_wait);
  750                         port->status |= DIGI_DTR_OFF;
  751                 }
  752         }
  753         tp->t_actout = FALSE;
  754         wakeup(&tp->t_actout);
  755         wakeup(TSA_CARR_ON(tp));
  756         splx(s);
  757 }
  758 
  759 /*
  760  * Load module "digi_<mod>.ko" and look for a symbol called digi_mod_<mod>.
  761  *
  762  * Populate sc->bios, sc->fep, and sc->link from this data.
  763  *
  764  * sc->fep.data, sc->bios.data and sc->link.data are malloc()d according
  765  * to their respective sizes.
  766  *
  767  * The module is unloaded when we're done.
  768  */
  769 static int
  770 digi_loadmoduledata(struct digi_softc *sc)
  771 {
  772         struct digi_mod *digi_mod;
  773         linker_file_t lf;
  774         char *modfile, *sym;
  775         caddr_t symptr;
  776         int modlen, res;
  777 
  778         KASSERT(sc->bios.data == NULL, ("Uninitialised BIOS variable"));
  779         KASSERT(sc->fep.data == NULL, ("Uninitialised FEP variable"));
  780         KASSERT(sc->link.data == NULL, ("Uninitialised LINK variable"));
  781         KASSERT(sc->module != NULL, ("Uninitialised module name"));
  782 
  783         modlen = strlen(sc->module);
  784         modfile = malloc(modlen + 6, M_TEMP, M_WAITOK);
  785         snprintf(modfile, modlen + 6, "digi_%s", sc->module);
  786         if ((res = linker_reference_module(modfile, NULL, &lf)) != 0)
  787                 printf("%s: Failed %d to autoload module\n", modfile, res);
  788         free(modfile, M_TEMP);
  789         if (res != 0)
  790                 return (res);
  791 
  792         sym = malloc(modlen + 10, M_TEMP, M_WAITOK);
  793         snprintf(sym, modlen + 10, "digi_mod_%s", sc->module);
  794         symptr = linker_file_lookup_symbol(lf, sym, 0);
  795         free(sym, M_TEMP);
  796         if (symptr == NULL) {
  797                 printf("digi_%s.ko: Symbol `%s' not found\n", sc->module, sym);
  798                 linker_release_module(NULL, NULL, lf);
  799                 return (EINVAL);
  800         }
  801 
  802         digi_mod = (struct digi_mod *)symptr;
  803         if (digi_mod->dm_version != DIGI_MOD_VERSION) {
  804                 printf("digi_%s.ko: Invalid version %d (need %d)\n",
  805                     sc->module, digi_mod->dm_version, DIGI_MOD_VERSION);
  806                 linker_release_module(NULL, NULL, lf);
  807                 return (EINVAL);
  808         }
  809 
  810         sc->bios.size = digi_mod->dm_bios.size;
  811         if (sc->bios.size != 0 && digi_mod->dm_bios.data != NULL) {
  812                 sc->bios.data = malloc(sc->bios.size, M_TTYS, M_WAITOK);
  813                 bcopy(digi_mod->dm_bios.data, sc->bios.data, sc->bios.size);
  814         }
  815 
  816         sc->fep.size = digi_mod->dm_fep.size;
  817         if (sc->fep.size != 0 && digi_mod->dm_fep.data != NULL) {
  818                 sc->fep.data = malloc(sc->fep.size, M_TTYS, M_WAITOK);
  819                 bcopy(digi_mod->dm_fep.data, sc->fep.data, sc->fep.size);
  820         }
  821 
  822         sc->link.size = digi_mod->dm_link.size;
  823         if (sc->link.size != 0 && digi_mod->dm_link.data != NULL) {
  824                 sc->link.data = malloc(sc->link.size, M_TTYS, M_WAITOK);
  825                 bcopy(digi_mod->dm_link.data, sc->link.data, sc->link.size);
  826         }
  827 
  828         linker_release_module(NULL, NULL, lf);
  829 
  830         return (0);
  831 }
  832 
  833 static int
  834 digisioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  835 {
  836         struct digi_p *port;
  837         struct digi_softc *sc;
  838 
  839         port = dev->si_drv1;
  840         sc = port->sc;
  841 
  842         switch (cmd) {
  843         case DIGIIO_GETALTPIN:
  844                 if (ISINIT(dev))
  845                         *(int *)data = port->ialtpin;
  846                 else if (ISLOCK(dev))
  847                         *(int *)data = port->laltpin;
  848                 else
  849                         return (ENOTTY);
  850                 break;
  851         case DIGIIO_SETALTPIN:
  852                 if (ISINIT(dev)) {
  853                         if (!port->laltpin) {
  854                                 port->ialtpin = !!*(int *)data;
  855                                 DLOG(DIGIDB_SET, (sc->dev,
  856                                     "port%d: initial ALTPIN %s\n", port->pnum,
  857                                     port->ialtpin ? "set" : "cleared"));
  858                         }
  859                 } else if (ISLOCK(dev)) {
  860                         port->laltpin = !!*(int *)data;
  861                         DLOG(DIGIDB_SET, (sc->dev,
  862                             "port%d: ALTPIN %slocked\n",
  863                             port->pnum, port->laltpin ? "" : "un"));
  864                 } else
  865                         return (ENOTTY);
  866                 break;
  867         default:
  868                 return (ENOTTY);
  869         }
  870         return (0);
  871 }
  872 
  873 static int
  874 digicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  875 {
  876         int error;
  877         struct digi_softc *sc;
  878 
  879         sc = dev->si_drv1;
  880 
  881         if (sc->status == DIGI_STATUS_DISABLED)
  882                 return (ENXIO);
  883 
  884         switch (cmd) {
  885         case DIGIIO_DEBUG:
  886 #ifdef DEBUG
  887                 digi_debug = *(int *)data;
  888                 return (0);
  889 #else
  890                 device_printf(sc->dev, "DEBUG not defined\n");
  891                 return (ENXIO);
  892 #endif
  893         case DIGIIO_REINIT:
  894                 digi_loadmoduledata(sc);
  895                 error = digi_init(sc);
  896                 digi_freemoduledata(sc);
  897                 return (error);
  898 
  899         case DIGIIO_MODEL:
  900                 *(enum digi_model *)data = sc->model;
  901                 return (0);
  902 
  903         case DIGIIO_IDENT:
  904                 return (copyout(sc->name, *(char **)data,
  905                     strlen(sc->name) + 1));
  906         default:
  907                 return (ENOIOCTL);
  908         }
  909 }
  910 
  911 static int
  912 digiioctl(struct tty *tp, u_long cmd, void *data, int flag, struct thread *td)
  913 {
  914         struct digi_softc *sc;
  915         struct digi_p *port;
  916 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
  917     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
  918         int ival;
  919 #endif
  920 
  921         port = tp->t_sc;
  922         sc = port->sc;
  923         if (sc->status == DIGI_STATUS_DISABLED)
  924                 return (ENXIO);
  925 
  926         if (!(port->status & ENABLED))
  927                 return (ENXIO);
  928 
  929         switch (cmd) {
  930         case DIGIIO_GETALTPIN:
  931                 *(int *)data = !!(port->dsr == sc->csigs->cd);
  932                 return (0);
  933 
  934         case DIGIIO_SETALTPIN:
  935                 if (!port->laltpin) {
  936                         if (*(int *)data) {
  937                                 DLOG(DIGIDB_SET, (sc->dev,
  938                                     "port%d: ALTPIN set\n", port->pnum));
  939                                 port->cd = sc->csigs->dsr;
  940                                 port->dsr = sc->csigs->cd;
  941                         } else {
  942                                 DLOG(DIGIDB_SET, (sc->dev,
  943                                     "port%d: ALTPIN cleared\n", port->pnum));
  944                                 port->cd = sc->csigs->cd;
  945                                 port->dsr = sc->csigs->dsr;
  946                         }
  947                 }
  948                 return (0);
  949 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
  950     defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
  951         case _IO('e', 'C'):
  952                 ival = IOCPARM_IVAL(data);
  953                 data = &ival;
  954                 /* FALLTHROUGH */
  955 #endif
  956         case DIGIIO_RING:
  957                 port->send_ring = (u_char)*(int *)data;
  958                 break;
  959         default:
  960                 return (ENOTTY);
  961         }
  962         return (0);
  963 }
  964 
  965 static void
  966 digibreak(struct tty *tp, int brk)
  967 {
  968         struct digi_p *port;
  969 
  970         port = tp->t_sc;
  971 
  972         /*
  973          * now it sends 400 millisecond break because I don't know
  974          * how to send an infinite break
  975          */
  976         if (brk)
  977                 fepcmd_w(port, SENDBREAK, 400, 10);
  978 }
  979 
  980 static int
  981 digiparam(struct tty *tp, struct termios *t)
  982 {
  983         struct digi_softc *sc;
  984         struct digi_p *port;
  985         int cflag;
  986         int iflag;
  987         int hflow;
  988         int s;
  989         int window;
  990 
  991         port = tp->t_sc;
  992         sc = port->sc;
  993         DLOG(DIGIDB_SET, (sc->dev, "port%d: setting parameters\n", port->pnum));
  994 
  995         if (t->c_ispeed == 0)
  996                 t->c_ispeed = t->c_ospeed;
  997 
  998         cflag = ttspeedtab(t->c_ospeed, digispeedtab);
  999 
 1000         if (cflag < 0 || (cflag > 0 && t->c_ispeed != t->c_ospeed))
 1001                 return (EINVAL);
 1002 
 1003         s = splclock();
 1004 
 1005         window = sc->window;
 1006         sc->setwin(sc, 0);
 1007 
 1008         if (cflag == 0) {                               /* hangup */
 1009                 DLOG(DIGIDB_SET, (sc->dev, "port%d: hangup\n", port->pnum));
 1010                 digimodem(port->tp, 0, SER_DTR | SER_RTS);
 1011         } else {
 1012                 digimodem(port->tp, SER_DTR | SER_RTS, 0);
 1013 
 1014                 DLOG(DIGIDB_SET, (sc->dev, "port%d: CBAUD = %d\n", port->pnum,
 1015                     cflag));
 1016 
 1017 #if 0
 1018                 /* convert flags to sysV-style values */
 1019                 if (t->c_cflag & PARODD)
 1020                         cflag |= 0x0200;
 1021                 if (t->c_cflag & PARENB)
 1022                         cflag |= 0x0100;
 1023                 if (t->c_cflag & CSTOPB)
 1024                         cflag |= 0x0080;
 1025 #else
 1026                 /* convert flags to sysV-style values */
 1027                 if (t->c_cflag & PARODD)
 1028                         cflag |= FEP_PARODD;
 1029                 if (t->c_cflag & PARENB)
 1030                         cflag |= FEP_PARENB;
 1031                 if (t->c_cflag & CSTOPB)
 1032                         cflag |= FEP_CSTOPB;
 1033                 if (t->c_cflag & CLOCAL)
 1034                         cflag |= FEP_CLOCAL;
 1035 #endif
 1036 
 1037                 cflag |= (t->c_cflag & CSIZE) >> 4;
 1038                 DLOG(DIGIDB_SET, (sc->dev, "port%d: CFLAG = 0x%x\n", port->pnum,
 1039                     cflag));
 1040                 fepcmd_w(port, SETCFLAGS, (unsigned)cflag, 0);
 1041         }
 1042 
 1043         iflag =
 1044             t->c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP);
 1045         if (port->c_iflag & IXON)
 1046                 iflag |= 0x400;
 1047         if (port->c_iflag & IXANY)
 1048                 iflag |= 0x800;
 1049         if (port->c_iflag & IXOFF)
 1050                 iflag |= 0x1000;
 1051 
 1052         DLOG(DIGIDB_SET, (sc->dev, "port%d: set iflag = 0x%x\n", port->pnum, iflag));
 1053         fepcmd_w(port, SETIFLAGS, (unsigned)iflag, 0);
 1054 
 1055         hflow = 0;
 1056         if (t->c_cflag & CDTR_IFLOW)
 1057                 hflow |= sc->csigs->dtr;
 1058         if (t->c_cflag & CRTS_IFLOW)
 1059                 hflow |= sc->csigs->rts;
 1060         if (t->c_cflag & CCTS_OFLOW)
 1061                 hflow |= sc->csigs->cts;
 1062         if (t->c_cflag & CDSR_OFLOW)
 1063                 hflow |= port->dsr;
 1064         if (t->c_cflag & CCAR_OFLOW)
 1065                 hflow |= port->cd;
 1066 
 1067         DLOG(DIGIDB_SET, (sc->dev, "port%d: set hflow = 0x%x\n", port->pnum, hflow));
 1068         fepcmd_w(port, SETHFLOW, 0xff00 | (unsigned)hflow, 0);
 1069 
 1070         DLOG(DIGIDB_SET, (sc->dev, "port%d: set startc(0x%x), stopc(0x%x)\n",
 1071             port->pnum, t->c_cc[VSTART], t->c_cc[VSTOP]));
 1072         fepcmd_b(port, SONOFFC, t->c_cc[VSTART], t->c_cc[VSTOP], 0);
 1073 
 1074         if (sc->window != 0)
 1075                 sc->towin(sc, 0);
 1076         if (window != 0)
 1077                 sc->towin(sc, window);
 1078         splx(s);
 1079 
 1080         return (0);
 1081 }
 1082 
 1083 static void
 1084 digi_intr(void *vp)
 1085 {
 1086         struct digi_p *port;
 1087         char *cxcon;
 1088         struct digi_softc *sc;
 1089         int ehead, etail;
 1090         volatile struct board_chan *bc;
 1091         struct tty *tp;
 1092         int head, tail;
 1093         int wrapmask;
 1094         int size, window;
 1095         struct event {
 1096                 u_char pnum;
 1097                 u_char event;
 1098                 u_char mstat;
 1099                 u_char lstat;
 1100         } event;
 1101 
 1102         sc = vp;
 1103 
 1104         if (sc->status != DIGI_STATUS_ENABLED) {
 1105                 DLOG(DIGIDB_IRQ, (sc->dev, "interrupt on disabled board !\n"));
 1106                 return;
 1107         }
 1108 
 1109 #ifdef DIGI_INTERRUPT
 1110         microtime(&sc->intr_timestamp);
 1111 #endif
 1112 
 1113         window = sc->window;
 1114         sc->setwin(sc, 0);
 1115 
 1116         if (sc->model >= PCXEM && W(sc->vmem + 0xd00)) {
 1117                 struct con_bios *con = con_bios_list;
 1118                 register u_char *ptr;
 1119 
 1120                 ptr = sc->vmem + W(sc->vmem + 0xd00);
 1121                 while (con) {
 1122                         if (ptr[1] && W(ptr + 2) == W(con->bios + 2))
 1123                                 /* Not first block -- exact match */
 1124                                 break;
 1125 
 1126                         if (W(ptr + 4) >= W(con->bios + 4) &&
 1127                             W(ptr + 4) <= W(con->bios + 6))
 1128                                 /* Initial search concetrator BIOS */
 1129                                 break;
 1130                 }
 1131 
 1132                 if (con == NULL) {
 1133                         log(LOG_ERR, "digi%d: wanted bios LREV = 0x%04x"
 1134                             " not found!\n", sc->res.unit, W(ptr + 4));
 1135                         W(ptr + 10) = 0;
 1136                         W(sc->vmem + 0xd00) = 0;
 1137                         goto eoi;
 1138                 }
 1139                 cxcon = con->bios;
 1140                 W(ptr + 4) = W(cxcon + 4);
 1141                 W(ptr + 6) = W(cxcon + 6);
 1142                 if (ptr[1] == 0)
 1143                         W(ptr + 2) = W(cxcon + 2);
 1144                 W(ptr + 8) = (ptr[1] << 6) + W(cxcon + 8);
 1145                 size = W(cxcon + 10) - (ptr[1] << 10);
 1146                 if (size <= 0) {
 1147                         W(ptr + 8) = W(cxcon + 8);
 1148                         W(ptr + 10) = 0;
 1149                 } else {
 1150                         if (size > 1024)
 1151                                 size = 1024;
 1152                         W(ptr + 10) = size;
 1153                         bcopy(cxcon + (ptr[1] << 10), ptr + 12, size);
 1154                 }
 1155                 W(sc->vmem + 0xd00) = 0;
 1156                 goto eoi;
 1157         }
 1158 
 1159         ehead = sc->gdata->ein;
 1160         etail = sc->gdata->eout;
 1161         if (ehead == etail) {
 1162 #ifdef DEBUG
 1163                 sc->intr_count++;
 1164                 if (sc->intr_count % 6000 == 0) {
 1165                         DLOG(DIGIDB_IRQ, (sc->dev,
 1166                             "6000 useless polls %x %x\n", ehead, etail));
 1167                         sc->intr_count = 0;
 1168                 }
 1169 #endif
 1170                 goto eoi;
 1171         }
 1172         while (ehead != etail) {
 1173                 event = *(volatile struct event *)(sc->memevent + etail);
 1174 
 1175                 etail = (etail + 4) & sc->gdata->imax;
 1176 
 1177                 if (event.pnum >= sc->numports) {
 1178                         log(LOG_ERR, "digi%d: port %d: got event"
 1179                             " on nonexisting port\n", sc->res.unit,
 1180                             event.pnum);
 1181                         continue;
 1182                 }
 1183                 port = &sc->ports[event.pnum];
 1184                 bc = port->bc;
 1185                 tp = port->tp;
 1186 
 1187                 if (!(tp->t_state & TS_ISOPEN) && !tp->t_wopeners) {
 1188                         DLOG(DIGIDB_IRQ, (sc->dev,
 1189                             "port %d: event 0x%x on closed port\n",
 1190                             event.pnum, event.event));
 1191                         bc->rout = bc->rin;
 1192                         bc->idata = 0;
 1193                         bc->iempty = 0;
 1194                         bc->ilow = 0;
 1195                         bc->mint = 0;
 1196                         continue;
 1197                 }
 1198                 if (event.event & ~ALL_IND)
 1199                         log(LOG_ERR, "digi%d: port%d: ? event 0x%x mstat 0x%x"
 1200                             " lstat 0x%x\n", sc->res.unit, event.pnum,
 1201                             event.event, event.mstat, event.lstat);
 1202 
 1203                 if (event.event & DATA_IND) {
 1204                         DLOG(DIGIDB_IRQ, (sc->dev, "port %d: DATA_IND\n",
 1205                             event.pnum));
 1206                         wrapmask = port->rxbufsize - 1;
 1207                         head = bc->rin;
 1208                         tail = bc->rout;
 1209 
 1210                         size = 0;
 1211                         if (!(tp->t_state & TS_ISOPEN)) {
 1212                                 bc->rout = head;
 1213                                 goto end_of_data;
 1214                         }
 1215                         while (head != tail) {
 1216                                 int top;
 1217 
 1218                                 DLOG(DIGIDB_INT, (sc->dev,
 1219                                     "port %d: p rx head = %d tail = %d\n",
 1220                                     event.pnum, head, tail));
 1221                                 top = (head > tail) ? head : wrapmask + 1;
 1222                                 sc->towin(sc, port->rxwin);
 1223                                 size = top - tail;
 1224                                 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
 1225                                         size = b_to_q((char *)port->rxbuf +
 1226                                             tail, size, &tp->t_rawq);
 1227                                         tail = top - size;
 1228                                         ttwakeup(tp);
 1229                                 } else for (; tail < top;) {
 1230                                         ttyld_rint(tp, port->rxbuf[tail]);
 1231                                         sc->towin(sc, port->rxwin);
 1232                                         size--;
 1233                                         tail++;
 1234                                         if (tp->t_state & TS_TBLOCK)
 1235                                                 break;
 1236                                 }
 1237                                 tail &= wrapmask;
 1238                                 sc->setwin(sc, 0);
 1239                                 bc->rout = tail;
 1240                                 head = bc->rin;
 1241                                 if (size)
 1242                                         break;
 1243                         }
 1244 
 1245                         if (bc->orun) {
 1246                                 CE_RECORD(port, CE_OVERRUN);
 1247                                 log(LOG_ERR, "digi%d: port%d: %s\n",
 1248                                     sc->res.unit, event.pnum,
 1249                                     digi_errortxt(CE_OVERRUN));
 1250                                 bc->orun = 0;
 1251                         }
 1252 end_of_data:
 1253                         if (size) {
 1254                                 tp->t_state |= TS_TBLOCK;
 1255                                 port->status |= PAUSE_RX;
 1256                                 DLOG(DIGIDB_RX, (sc->dev, "port %d: pause RX\n",
 1257                                     event.pnum));
 1258                         } else {
 1259                                 bc->idata = 1;
 1260                         }
 1261                 }
 1262 
 1263                 if (event.event & MODEMCHG_IND) {
 1264                         DLOG(DIGIDB_MODEM, (sc->dev, "port %d: MODEMCHG_IND\n",
 1265                             event.pnum));
 1266 
 1267                         if ((event.mstat ^ event.lstat) & port->cd) {
 1268                                 sc->hidewin(sc);
 1269                                 ttyld_modem(tp, event.mstat & port->cd);
 1270                                 sc->setwin(sc, 0);
 1271                                 wakeup(TSA_CARR_ON(tp));
 1272                         }
 1273 
 1274                         if (event.mstat & sc->csigs->ri) {
 1275                                 DLOG(DIGIDB_RI, (sc->dev, "port %d: RING\n",
 1276                                     event.pnum));
 1277                                 if (port->send_ring) {
 1278                                         ttyld_rint(tp, 'R');
 1279                                         ttyld_rint(tp, 'I');
 1280                                         ttyld_rint(tp, 'N');
 1281                                         ttyld_rint(tp, 'G');
 1282                                         ttyld_rint(tp, '\r');
 1283                                         ttyld_rint(tp, '\n');
 1284                                 }
 1285                         }
 1286                 }
 1287                 if (event.event & BREAK_IND) {
 1288                         DLOG(DIGIDB_MODEM, (sc->dev, "port %d: BREAK_IND\n",
 1289                             event.pnum));
 1290                         ttyld_rint(tp, TTY_BI);
 1291                 }
 1292                 if (event.event & (LOWTX_IND | EMPTYTX_IND)) {
 1293                         DLOG(DIGIDB_IRQ, (sc->dev, "port %d:%s%s\n",
 1294                             event.pnum,
 1295                             event.event & LOWTX_IND ? " LOWTX" : "",
 1296                             event.event & EMPTYTX_IND ?  " EMPTYTX" : ""));
 1297                         ttyld_start(tp);
 1298                 }
 1299         }
 1300         sc->gdata->eout = etail;
 1301 eoi:
 1302         if (sc->window != 0)
 1303                 sc->towin(sc, 0);
 1304         if (window != 0)
 1305                 sc->towin(sc, window);
 1306 }
 1307 
 1308 static void
 1309 digistart(struct tty *tp)
 1310 {
 1311         struct digi_p *port;
 1312         struct digi_softc *sc;
 1313         volatile struct board_chan *bc;
 1314         int head, tail;
 1315         int size, ocount, totcnt = 0;
 1316         int s;
 1317         int wmask;
 1318 
 1319         port = tp->t_sc;
 1320         sc = port->sc;
 1321         bc = port->bc;
 1322 
 1323         wmask = port->txbufsize - 1;
 1324 
 1325         s = spltty();
 1326         port->lcc = tp->t_outq.c_cc;
 1327         sc->setwin(sc, 0);
 1328         if (!(tp->t_state & TS_TBLOCK)) {
 1329                 if (port->status & PAUSE_RX) {
 1330                         DLOG(DIGIDB_RX, (sc->dev, "port %d: resume RX\n",
 1331                             port->pnum));
 1332                         /*
 1333                          * CAREFUL - braces are needed here if the DLOG is
 1334                          * optimised out!
 1335                          */
 1336                 }
 1337                 port->status &= ~PAUSE_RX;
 1338                 bc->idata = 1;
 1339         }
 1340         if (!(tp->t_state & TS_TTSTOP) && port->status & PAUSE_TX) {
 1341                 DLOG(DIGIDB_TX, (sc->dev, "port %d: resume TX\n", port->pnum));
 1342                 port->status &= ~PAUSE_TX;
 1343                 fepcmd_w(port, RESUMETX, 0, 10);
 1344         }
 1345         if (tp->t_outq.c_cc == 0)
 1346                 tp->t_state &= ~TS_BUSY;
 1347         else
 1348                 tp->t_state |= TS_BUSY;
 1349 
 1350         head = bc->tin;
 1351         while (tp->t_outq.c_cc != 0) {
 1352                 tail = bc->tout;
 1353                 DLOG(DIGIDB_INT, (sc->dev, "port%d: s tx head = %d tail = %d\n",
 1354                     port->pnum, head, tail));
 1355 
 1356                 if (head < tail)
 1357                         size = tail - head - 1;
 1358                 else {
 1359                         size = port->txbufsize - head;
 1360                         if (tail == 0)
 1361                                 size--;
 1362                 }
 1363 
 1364                 if (size == 0)
 1365                         break;
 1366                 sc->towin(sc, port->txwin);
 1367                 ocount = q_to_b(&tp->t_outq, port->txbuf + head, size);
 1368                 totcnt += ocount;
 1369                 head += ocount;
 1370                 head &= wmask;
 1371                 sc->setwin(sc, 0);
 1372                 bc->tin = head;
 1373                 bc->iempty = 1;
 1374                 bc->ilow = 1;
 1375         }
 1376         port->lostcc = tp->t_outq.c_cc;
 1377         tail = bc->tout;
 1378         if (head < tail)
 1379                 size = port->txbufsize - tail + head;
 1380         else
 1381                 size = head - tail;
 1382 
 1383         port->lbuf = size;
 1384         DLOG(DIGIDB_INT, (sc->dev, "port%d: s total cnt = %d\n", port->pnum, totcnt));
 1385         ttwwakeup(tp);
 1386         splx(s);
 1387 }
 1388 
 1389 static void
 1390 digistop(struct tty *tp, int rw)
 1391 {
 1392         struct digi_softc *sc;
 1393         struct digi_p *port;
 1394 
 1395         port = tp->t_sc;
 1396         sc = port->sc;
 1397 
 1398         DLOG(DIGIDB_TX, (sc->dev, "port %d: pause TX\n", port->pnum));
 1399         port->status |= PAUSE_TX;
 1400         fepcmd_w(port, PAUSETX, 0, 10);
 1401 }
 1402 
 1403 static void
 1404 fepcmd(struct digi_p *port, int cmd, int op1, int ncmds)
 1405 {
 1406         u_char *mem;
 1407         unsigned tail, head;
 1408         int count, n;
 1409 
 1410         mem = port->sc->memcmd;
 1411 
 1412         port->sc->setwin(port->sc, 0);
 1413 
 1414         head = port->sc->gdata->cin;
 1415         mem[head + 0] = cmd;
 1416         mem[head + 1] = port->pnum;
 1417         *(u_short *)(mem + head + 2) = op1;
 1418 
 1419         head = (head + 4) & port->sc->gdata->cmax;
 1420         port->sc->gdata->cin = head;
 1421 
 1422         for (count = FEPTIMEOUT; count > 0; count--) {
 1423                 head = port->sc->gdata->cin;
 1424                 tail = port->sc->gdata->cout;
 1425                 n = (head - tail) & port->sc->gdata->cmax;
 1426 
 1427                 if (n <= ncmds * sizeof(short) * 4)
 1428                         break;
 1429         }
 1430         if (count == 0)
 1431                 log(LOG_ERR, "digi%d: port%d: timeout on FEP command\n",
 1432                     port->sc->res.unit, port->pnum);
 1433 }
 1434 
 1435 const char *
 1436 digi_errortxt(int id)
 1437 {
 1438         static const char *error_desc[] = {
 1439                 "silo overflow",
 1440                 "interrupt-level buffer overflow",
 1441                 "tty-level buffer overflow",
 1442         };
 1443 
 1444         KASSERT(id >= 0 && id < sizeof(error_desc) / sizeof(error_desc[0]),
 1445             ("Unexpected digi error id %d\n", id));
 1446 
 1447         return (error_desc[id]);
 1448 }
 1449 
 1450 int
 1451 digi_attach(struct digi_softc *sc)
 1452 {
 1453         sc->res.ctldev = make_dev(&digi_csw,
 1454             sc->res.unit << 16, UID_ROOT, GID_WHEEL,
 1455             0600, "digi%r.ctl", sc->res.unit);
 1456         sc->res.ctldev->si_drv1 = sc;
 1457 
 1458         digi_loadmoduledata(sc);
 1459         digi_init(sc);
 1460         digi_freemoduledata(sc);
 1461 
 1462         return (0);
 1463 }
 1464 
 1465 static int
 1466 digi_inuse(struct digi_softc *sc)
 1467 {
 1468         int i;
 1469         struct digi_p *port;
 1470 
 1471         port = &sc->ports[0];
 1472         for (i = 0; i < sc->numports; i++, port++)
 1473                 if (port->tp->t_state & TS_ISOPEN) {
 1474                         DLOG(DIGIDB_INIT, (sc->dev, "port%d: busy\n", i));
 1475                         return (1);
 1476                 } else if (port->tp->t_wopeners || port->opencnt) {
 1477                         DLOG(DIGIDB_INIT, (sc->dev, "port%d: blocked in open\n",
 1478                             i));
 1479                         return (1);
 1480                 }
 1481         return (0);
 1482 }
 1483 
 1484 static void
 1485 digi_free_state(struct digi_softc *sc)
 1486 {
 1487         int i;
 1488 
 1489         /* Blow it all away */
 1490 
 1491         for (i = 0; i < sc->numports; i++)
 1492                 ttygone(sc->ports[i].tp);
 1493 
 1494         /* XXX: this might be better done as a ttypurge method */
 1495         untimeout(digi_poll, sc, sc->callout);
 1496         callout_handle_init(&sc->callout);
 1497         untimeout(digi_int_test, sc, sc->inttest);
 1498         callout_handle_init(&sc->inttest);
 1499 
 1500         for (i = 0; i < sc->numports; i++)
 1501                 ttyfree(sc->ports[i].tp);
 1502 
 1503         bus_teardown_intr(sc->dev, sc->res.irq, sc->res.irqHandler);
 1504 #ifdef DIGI_INTERRUPT
 1505         if (sc->res.irq != NULL) {
 1506                 bus_release_resource(dev, SYS_RES_IRQ, sc->res.irqrid,
 1507                     sc->res.irq);
 1508                 sc->res.irq = NULL;
 1509         }
 1510 #endif
 1511         if (sc->numports) {
 1512                 KASSERT(sc->ports, ("digi%d: Lost my ports ?", sc->res.unit));
 1513                 free(sc->ports, M_TTYS);
 1514                 sc->ports = NULL;
 1515                 sc->numports = 0;
 1516         }
 1517 
 1518         sc->status = DIGI_STATUS_NOTINIT;
 1519 }
 1520 
 1521 int
 1522 digi_detach(device_t dev)
 1523 {
 1524         struct digi_softc *sc = device_get_softc(dev);
 1525 
 1526         DLOG(DIGIDB_INIT, (sc->dev, "detaching\n"));
 1527 
 1528         /* If we're INIT'd, numports must be 0 */
 1529         KASSERT(sc->numports == 0 || sc->status != DIGI_STATUS_NOTINIT,
 1530             ("digi%d: numports(%d) & status(%d) are out of sync",
 1531             sc->res.unit, sc->numports, (int)sc->status));
 1532 
 1533         if (digi_inuse(sc))
 1534                 return (EBUSY);
 1535 
 1536         digi_free_state(sc);
 1537 
 1538         destroy_dev(sc->res.ctldev);
 1539 
 1540         if (sc->res.mem != NULL) {
 1541                 bus_release_resource(dev, SYS_RES_MEMORY, sc->res.mrid,
 1542                     sc->res.mem);
 1543                 sc->res.mem = NULL;
 1544         }
 1545         if (sc->res.io != NULL) {
 1546                 bus_release_resource(dev, SYS_RES_IOPORT, sc->res.iorid,
 1547                     sc->res.io);
 1548                 sc->res.io = NULL;
 1549         }
 1550 
 1551         return (0);
 1552 }
 1553 
 1554 int
 1555 digi_shutdown(device_t dev)
 1556 {
 1557         return (0);
 1558 }
 1559 
 1560 MODULE_VERSION(digi, 1);

Cache object: a4b12d31c7c7b2bde16e59e87a6b2fb7


[ 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.