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/cx/cxddk.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  * Cronyx-Sigma Driver Development Kit.
    3  *
    4  * Copyright (C) 1998 Cronyx Engineering.
    5  * Author: Pavel Novikov, <pavel@inr.net.kiae.su>
    6  *
    7  * Copyright (C) 1998-2003 Cronyx Engineering.
    8  * Author: Roman Kurakin, <rik@cronyx.ru>
    9  *
   10  * This software is distributed with NO WARRANTIES, not even the implied
   11  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   12  *
   13  * Authors grant any other persons or organisations permission to use
   14  * or modify this software as long as this message is kept with the software,
   15  * all derivative works or modified versions.
   16  *
   17  * Cronyx Id: cxddk.c,v 1.1.2.2 2003/11/27 14:24:50 rik Exp $
   18  */
   19 #include <sys/cdefs.h>
   20 __FBSDID("$FreeBSD$");
   21 
   22 #include <dev/cx/machdep.h>
   23 #include <dev/cx/cxddk.h>
   24 #include <dev/cx/cxreg.h>
   25 #include <dev/cx/cronyxfw.h>
   26 #include <dev/cx/csigmafw.h>
   27 
   28 #define BYTE *(unsigned char*)&
   29 
   30 /* standard base port set */
   31 static short porttab [] = {
   32         0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
   33         0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
   34 };
   35 
   36 /*
   37  * Compute the optimal size of the receive buffer.
   38  */
   39 static int cx_compute_buf_len (cx_chan_t *c)
   40 {
   41         int rbsz;
   42         if (c->mode == M_ASYNC) {
   43                 rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
   44                 if (rbsz < 4)
   45                         rbsz = 4;
   46                 else if (rbsz  > DMABUFSZ)
   47                         rbsz = DMABUFSZ;
   48         }
   49         else
   50                 rbsz = DMABUFSZ;
   51 
   52         return rbsz;
   53 }
   54 
   55 /*
   56  * Auto-detect the installed adapters.
   57  */
   58 int cx_find (port_t *board_ports)
   59 {
   60         int i, n;
   61 
   62         for (i=0, n=0; porttab[i] && n<NBRD; i++)
   63                 if (cx_probe_board (porttab[i], -1, -1))
   64                         board_ports[n++] = porttab[i];
   65         return n;
   66 }
   67 
   68 /*
   69  * Initialize the adapter.
   70  */
   71 int cx_open_board (cx_board_t *b, int num, port_t port, int irq, int dma)
   72 {
   73         cx_chan_t *c;
   74 
   75         if (num >= NBRD || ! cx_probe_board (port, irq, dma))
   76                 return 0;
   77 
   78         /* init callback pointers */
   79         for (c=b->chan; c<b->chan+NCHAN; ++c) {
   80                 c->call_on_tx = 0;
   81                 c->call_on_rx = 0;
   82                 c->call_on_msig = 0;
   83                 c->call_on_err = 0;
   84         }
   85 
   86         cx_init (b, num, port, irq, dma);
   87 
   88         /* Loading firmware */
   89         if (! cx_setup_board (b, csigma_fw_data, csigma_fw_len, csigma_fw_tvec))
   90                 return 0;
   91         return 1;
   92 }
   93 
   94 /*
   95  * Shutdown the adapter.
   96  */
   97 void cx_close_board (cx_board_t *b)
   98 {
   99         cx_setup_board (b, 0, 0, 0);
  100 
  101         /* Reset the controller. */
  102         outb (BCR0(b->port), 0);
  103         if (b->chan[8].type || b->chan[12].type)
  104                 outb (BCR0(b->port+0x10), 0);
  105 }
  106 
  107 /*
  108  * Start the channel.
  109  */
  110 void cx_start_chan (cx_chan_t *c, cx_buf_t *cb, unsigned long phys)
  111 {
  112         int command = 0;
  113         int mode = 0;
  114         int ier = 0;
  115         int rbsz;
  116 
  117         c->overflow = 0;
  118 
  119         /* Setting up buffers */
  120         if (cb) {
  121                 c->arbuf = cb->rbuffer[0];
  122                 c->brbuf = cb->rbuffer[1];
  123                 c->atbuf = cb->tbuffer[0];
  124                 c->btbuf = cb->tbuffer[1];
  125                 c->arphys = phys + ((char*)c->arbuf - (char*)cb);
  126                 c->brphys = phys + ((char*)c->brbuf - (char*)cb);
  127                 c->atphys = phys + ((char*)c->atbuf - (char*)cb);
  128                 c->btphys = phys + ((char*)c->btbuf - (char*)cb);
  129         }
  130 
  131         /* Set current channel number */
  132         outb (CAR(c->port), c->num & 3);
  133 
  134         /* set receiver A buffer physical address */
  135         outw (ARBADRU(c->port), (unsigned short) (c->arphys>>16));
  136         outw (ARBADRL(c->port), (unsigned short) c->arphys);
  137 
  138         /* set receiver B buffer physical address */
  139         outw (BRBADRU(c->port), (unsigned short) (c->brphys>>16));
  140         outw (BRBADRL(c->port), (unsigned short) c->brphys);
  141 
  142         /* set transmitter A buffer physical address */
  143         outw (ATBADRU(c->port), (unsigned short) (c->atphys>>16));
  144         outw (ATBADRL(c->port), (unsigned short) c->atphys);
  145 
  146         /* set transmitter B buffer physical address */
  147         outw (BTBADRU(c->port), (unsigned short) (c->btphys>>16));
  148         outw (BTBADRL(c->port), (unsigned short) c->btphys);
  149 
  150         /* rx */
  151         command |= CCR_ENRX;
  152         ier |= IER_RXD;
  153         if (c->board->dma) {
  154                 mode |= CMR_RXDMA;
  155                 if (c->mode == M_ASYNC)
  156                         ier |= IER_RET;
  157         }
  158 
  159         /* tx */
  160         command |= CCR_ENTX;
  161         ier |= (c->mode == M_ASYNC) ? IER_TXD : (IER_TXD | IER_TXMPTY);
  162         if (c->board->dma)
  163                 mode |= CMR_TXDMA;
  164 
  165         /* Set mode */
  166         outb (CMR(c->port), mode | (c->mode == M_ASYNC ? CMR_ASYNC : CMR_HDLC));
  167 
  168         /* Clear and initialize channel */
  169         cx_cmd (c->port, CCR_CLRCH);
  170         cx_cmd (c->port, CCR_INITCH | command);
  171         if (c->mode == M_ASYNC)
  172                 cx_cmd (c->port, CCR_ENTX);
  173 
  174         /* Start receiver */
  175         rbsz = cx_compute_buf_len(c);
  176         outw (ARBCNT(c->port), rbsz);
  177         outw (BRBCNT(c->port), rbsz);
  178         outw (ARBSTS(c->port), BSTS_OWN24);
  179         outw (BRBSTS(c->port), BSTS_OWN24);
  180 
  181         if (c->mode == M_ASYNC)
  182                 ier |= IER_MDM;
  183 
  184         /* Enable interrupts */
  185         outb (IER(c->port), ier);
  186 
  187         /* Clear DTR and RTS */
  188         cx_set_dtr (c, 0);
  189         cx_set_rts (c, 0);
  190 }
  191 
  192 /*
  193  * Turn the receiver on/off.
  194  */
  195 void cx_enable_receive (cx_chan_t *c, int on)
  196 {
  197         unsigned char ier;
  198 
  199         if (cx_receive_enabled(c) && ! on) {
  200                 outb (CAR(c->port), c->num & 3);
  201                 if (c->mode == M_ASYNC) {
  202                         ier = inb (IER(c->port));
  203                         outb (IER(c->port), ier & ~ (IER_RXD | IER_RET));
  204                 }
  205                 cx_cmd (c->port, CCR_DISRX);
  206         } else if (! cx_receive_enabled(c) && on) {
  207                 outb (CAR(c->port), c->num & 3);
  208                 ier = inb (IER(c->port));
  209                 if (c->mode == M_ASYNC)
  210                         outb (IER(c->port), ier | (IER_RXD | IER_RET));
  211                 else
  212                         outb (IER(c->port), ier | IER_RXD);
  213                 cx_cmd (c->port, CCR_ENRX);
  214         }
  215 }
  216 
  217 /*
  218  * Turn the transmitter on/off.
  219  */
  220 void cx_enable_transmit (cx_chan_t *c, int on)
  221 {
  222         if (cx_transmit_enabled(c) && ! on) {
  223                 outb (CAR(c->port), c->num & 3);
  224                 if (c->mode != M_ASYNC)
  225                         outb (STCR(c->port), STC_ABORTTX | STC_SNDSPC);
  226                 cx_cmd (c->port, CCR_DISTX);
  227         } else if (! cx_transmit_enabled(c) && on) {
  228                 outb (CAR(c->port), c->num & 3);
  229                 cx_cmd (c->port, CCR_ENTX);
  230         }
  231 }
  232 
  233 /*
  234  * Get channel status.
  235  */
  236 int cx_receive_enabled (cx_chan_t *c)
  237 {
  238         outb (CAR(c->port), c->num & 3);
  239         return (inb (CSR(c->port)) & CSRA_RXEN) != 0;
  240 }
  241 
  242 int cx_transmit_enabled (cx_chan_t *c)
  243 {
  244         outb (CAR(c->port), c->num & 3);
  245         return (inb (CSR(c->port)) & CSRA_TXEN) != 0;
  246 }
  247 
  248 unsigned long cx_get_baud (cx_chan_t *c)
  249 {
  250         return (c->opt.tcor.clk == CLK_EXT) ? 0 : c->txbaud;
  251 }
  252 
  253 int cx_get_loop (cx_chan_t *c)
  254 {
  255         return c->opt.tcor.llm ? 1 : 0;
  256 }
  257 
  258 int cx_get_nrzi (cx_chan_t *c)
  259 {
  260         return c->opt.rcor.encod == ENCOD_NRZI;
  261 }
  262 
  263 int cx_get_dpll (cx_chan_t *c)
  264 {
  265         return c->opt.rcor.dpll ? 1 : 0;
  266 }
  267 
  268 void cx_set_baud (cx_chan_t *c, unsigned long bps)
  269 {
  270         int clock, period;
  271 
  272         c->txbaud = c->rxbaud = bps;
  273 
  274         /* Set current channel number */
  275         outb (CAR(c->port), c->num & 3);
  276         if (bps) {
  277                 if (c->mode == M_ASYNC || c->opt.rcor.dpll || c->opt.tcor.llm) {
  278                         /* Receive baud - internal */
  279                         cx_clock (c->oscfreq, c->rxbaud, &clock, &period);
  280                         c->opt.rcor.clk = clock;
  281                         outb (RCOR(c->port), BYTE c->opt.rcor);
  282                         outb (RBPR(c->port), period);
  283                 } else {
  284                         /* Receive baud - external */
  285                         c->opt.rcor.clk = CLK_EXT;
  286                         outb (RCOR(c->port), BYTE c->opt.rcor);
  287                         outb (RBPR(c->port), 1);
  288                 }
  289 
  290                 /* Transmit baud - internal */
  291                 cx_clock (c->oscfreq, c->txbaud, &clock, &period);
  292                 c->opt.tcor.clk = clock;
  293                 c->opt.tcor.ext1x = 0;
  294                 outb (TBPR(c->port), period);
  295         } else if (c->mode != M_ASYNC) {
  296                 /* External clock - disable local loopback and DPLL */
  297                 c->opt.tcor.llm = 0;
  298                 c->opt.rcor.dpll = 0;
  299 
  300                 /* Transmit baud - external */
  301                 c->opt.tcor.ext1x = 1;
  302                 c->opt.tcor.clk = CLK_EXT;
  303                 outb (TBPR(c->port), 1);
  304 
  305                 /* Receive baud - external */
  306                 c->opt.rcor.clk = CLK_EXT;
  307                 outb (RCOR(c->port), BYTE c->opt.rcor);
  308                 outb (RBPR(c->port), 1);
  309         }
  310         if (c->opt.tcor.llm)
  311                 outb (COR2(c->port), (BYTE c->hopt.cor2) & ~3);
  312         else
  313                 outb (COR2(c->port), BYTE c->hopt.cor2);
  314         outb (TCOR(c->port), BYTE c->opt.tcor);
  315 }
  316 
  317 void cx_set_loop (cx_chan_t *c, int on)
  318 {
  319         if (! c->txbaud)
  320                 return;
  321 
  322         c->opt.tcor.llm = on ? 1 : 0;
  323         cx_set_baud (c, c->txbaud);
  324 }
  325 
  326 void cx_set_dpll (cx_chan_t *c, int on)
  327 {
  328         if (! c->txbaud)
  329                 return;
  330 
  331         c->opt.rcor.dpll = on ? 1 : 0;
  332         cx_set_baud (c, c->txbaud);
  333 }
  334 
  335 void cx_set_nrzi (cx_chan_t *c, int nrzi)
  336 {
  337         c->opt.rcor.encod = (nrzi ? ENCOD_NRZI : ENCOD_NRZ);
  338         outb (CAR(c->port), c->num & 3);
  339         outb (RCOR(c->port), BYTE c->opt.rcor);
  340 }
  341 
  342 static int cx_send (cx_chan_t *c, char *data, int len,
  343         void *attachment)
  344 {
  345         unsigned char *buf;
  346         port_t cnt_port, sts_port;
  347         void **attp;
  348 
  349         /* Set the current channel number. */
  350         outb (CAR(c->port), c->num & 3);
  351 
  352         /* Determine the buffer order. */
  353         if (inb (DMABSTS(c->port)) & DMABSTS_NTBUF) {
  354                 if (inb (BTBSTS(c->port)) & BSTS_OWN24) {
  355                         buf      = c->atbuf;
  356                         cnt_port = ATBCNT(c->port);
  357                         sts_port = ATBSTS(c->port);
  358                         attp     = &c->attach[0];
  359                 } else {
  360                         buf      = c->btbuf;
  361                         cnt_port = BTBCNT(c->port);
  362                         sts_port = BTBSTS(c->port);
  363                         attp     = &c->attach[1];
  364                 }
  365         } else {
  366                 if (inb (ATBSTS(c->port)) & BSTS_OWN24) {
  367                         buf      = c->btbuf;
  368                         cnt_port = BTBCNT(c->port);
  369                         sts_port = BTBSTS(c->port);
  370                         attp     = &c->attach[1];
  371                 } else {
  372                         buf      = c->atbuf;
  373                         cnt_port = ATBCNT(c->port);
  374                         sts_port = ATBSTS(c->port);
  375                         attp     = &c->attach[0];
  376                 }
  377         }
  378         /* Is it busy? */
  379         if (inb (sts_port) & BSTS_OWN24)
  380                 return -1;
  381 
  382         memcpy (buf, data, len);
  383         *attp = attachment;
  384 
  385         /* Start transmitter. */
  386         outw (cnt_port, len);
  387         outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24);
  388 
  389         /* Enable TXMPTY interrupt,
  390          * to catch the case when the second buffer is empty. */
  391         if (c->mode != M_ASYNC) {
  392                 if ((inb(ATBSTS(c->port)) & BSTS_OWN24) &&
  393                     (inb(BTBSTS(c->port)) & BSTS_OWN24)) {
  394                         outb (IER(c->port), IER_RXD | IER_TXD | IER_TXMPTY);
  395                 } else
  396                         outb (IER(c->port), IER_RXD | IER_TXD);
  397         }
  398         return 0;
  399 }
  400 
  401 /*
  402  * Number of free buffs
  403  */
  404 int cx_buf_free (cx_chan_t *c)
  405 {
  406         return ! (inb (ATBSTS(c->port)) & BSTS_OWN24) +
  407                 ! (inb (BTBSTS(c->port)) & BSTS_OWN24);
  408 }
  409 
  410 /*
  411  * Send the data packet.
  412  */
  413 int cx_send_packet (cx_chan_t *c, char *data, int len, void *attachment)
  414 {
  415         if (len >= DMABUFSZ)
  416                 return -2;
  417         if (c->mode == M_ASYNC) {
  418                 static char buf [DMABUFSZ];
  419                 char *p, *t = buf;
  420 
  421                 /* Async -- double all nulls. */
  422                 for (p=data; p < data+len && t < buf+DMABUFSZ-1; ++p)
  423                         if ((*t++ = *p) == 0)
  424                                 *t++ = 0;
  425                 return cx_send (c, buf, t-buf, attachment);
  426         }
  427         return cx_send (c, data, len, attachment);
  428 }
  429 
  430 static int cx_receive_interrupt (cx_chan_t *c)
  431 {
  432         unsigned short risr;
  433         int len = 0, rbsz;
  434 
  435         ++c->rintr;
  436         risr = inw (RISR(c->port));
  437 
  438         /* Compute optimal receiver buffer length */
  439         rbsz = cx_compute_buf_len(c);
  440         if (c->mode == M_ASYNC && (risr & RISA_TIMEOUT)) {
  441                 unsigned long rcbadr = (unsigned short) inw (RCBADRL(c->port)) |
  442                         (long) inw (RCBADRU(c->port)) << 16;
  443                 unsigned char *buf = NULL;
  444                 port_t cnt_port = 0, sts_port = 0;
  445 
  446                 if (rcbadr >= c->brphys && rcbadr < c->brphys+DMABUFSZ) {
  447                         buf = c->brbuf;
  448                         len = rcbadr - c->brphys;
  449                         cnt_port = BRBCNT(c->port);
  450                         sts_port = BRBSTS(c->port);
  451                 } else if (rcbadr >= c->arphys && rcbadr < c->arphys+DMABUFSZ) {
  452                         buf = c->arbuf;
  453                         len = rcbadr - c->arphys;
  454                         cnt_port = ARBCNT(c->port);
  455                         sts_port = ARBSTS(c->port);
  456                 }
  457 
  458                 if (len) {
  459                         c->ibytes += len;
  460                         c->received_data = buf;
  461                         c->received_len = len;
  462 
  463                         /* Restart receiver. */
  464                         outw (cnt_port, rbsz);
  465                         outb (sts_port, BSTS_OWN24);
  466                 }
  467                 return (REOI_TERMBUFF);
  468         }
  469 
  470         /* Receive errors. */
  471         if (risr & RIS_OVERRUN) {
  472                 ++c->ierrs;
  473                 if (c->call_on_err)
  474                         c->call_on_err (c, CX_OVERRUN);
  475         } else if (c->mode != M_ASYNC && (risr & RISH_CRCERR)) {
  476                 ++c->ierrs;
  477                 if (c->call_on_err)
  478                         c->call_on_err (c, CX_CRC);
  479         } else if (c->mode != M_ASYNC && (risr & (RISH_RXABORT | RISH_RESIND))) {
  480                 ++c->ierrs;
  481                 if (c->call_on_err)
  482                         c->call_on_err (c, CX_FRAME);
  483         } else if (c->mode == M_ASYNC && (risr & RISA_PARERR)) {
  484                 ++c->ierrs;
  485                 if (c->call_on_err)
  486                         c->call_on_err (c, CX_CRC);
  487         } else if (c->mode == M_ASYNC && (risr & RISA_FRERR)) {
  488                 ++c->ierrs;
  489                 if (c->call_on_err)
  490                         c->call_on_err (c, CX_FRAME);
  491         } else if (c->mode == M_ASYNC && (risr & RISA_BREAK)) {
  492                 if (c->call_on_err)
  493                         c->call_on_err (c, CX_BREAK);
  494         } else if (! (risr & RIS_EOBUF)) {
  495                 ++c->ierrs;
  496         } else {
  497                 /* Handle received data. */
  498                 len = (risr & RIS_BB) ? inw(BRBCNT(c->port)) : inw(ARBCNT(c->port));
  499 
  500                 if (len > DMABUFSZ) {
  501                         /* Fatal error: actual DMA transfer size
  502                          * exceeds our buffer size.  It could be caused
  503                          * by incorrectly programmed DMA register or
  504                          * hardware fault.  Possibly, should panic here. */
  505                         len = DMABUFSZ;
  506                 } else if (c->mode != M_ASYNC && ! (risr & RIS_EOFR)) {
  507                         /* The received frame does not fit in the DMA buffer.
  508                          * It could be caused by serial lie noise,
  509                          * or if the peer has too big MTU. */
  510                         if (! c->overflow) {
  511                                 if (c->call_on_err)
  512                                         c->call_on_err (c, CX_OVERFLOW);
  513                                 c->overflow = 1;
  514                                 ++c->ierrs;
  515                         }
  516                 } else if (! c->overflow) {
  517                         if (risr & RIS_BB) {
  518                                 c->received_data = c->brbuf;
  519                                 c->received_len = len;
  520                         } else {
  521                                 c->received_data = c->arbuf;
  522                                 c->received_len = len;
  523                         }
  524                         if (c->mode != M_ASYNC)
  525                                 ++c->ipkts;
  526                         c->ibytes += len;
  527                 } else
  528                         c->overflow = 0;
  529         }
  530 
  531         /* Restart receiver. */
  532         if (! (inb (ARBSTS(c->port)) & BSTS_OWN24)) {
  533                 outw (ARBCNT(c->port), rbsz);
  534                 outb (ARBSTS(c->port), BSTS_OWN24);
  535         }
  536         if (! (inb (BRBSTS(c->port)) & BSTS_OWN24)) {
  537                 outw (BRBCNT(c->port), rbsz);
  538                 outb (BRBSTS(c->port), BSTS_OWN24);
  539         }
  540 
  541         /* Discard exception characters. */
  542         if ((risr & RISA_SCMASK) && c->aopt.cor2.ixon)
  543                 return (REOI_DISCEXC);
  544         else
  545                 return (0);
  546 }
  547 
  548 static void cx_transmit_interrupt (cx_chan_t *c)
  549 {
  550         unsigned char tisr;
  551         int len = 0;
  552 
  553         ++c->tintr;
  554         tisr = inb (TISR(c->port));
  555         if (tisr & TIS_UNDERRUN) {      /* Transmit underrun error */
  556                 if (c->call_on_err)
  557                         c->call_on_err (c, CX_UNDERRUN);
  558                 ++c->oerrs;
  559         } else if (tisr & (TIS_EOBUF | TIS_TXEMPTY | TIS_TXDATA)) {
  560                 /* Call processing function */
  561                 if (tisr & TIS_BB) {
  562                         len = inw(BTBCNT(c->port));
  563                         if (c->call_on_tx)
  564                                 c->call_on_tx (c, c->attach[1], len);
  565                 } else {
  566                         len = inw(ATBCNT(c->port));
  567                         if (c->call_on_tx)
  568                                 c->call_on_tx (c, c->attach[0], len);
  569                 }
  570                 if (c->mode != M_ASYNC && len != 0)
  571                         ++c->opkts;
  572                 c->obytes += len;
  573         }
  574 
  575         /* Enable TXMPTY interrupt,
  576          * to catch the case when the second buffer is empty. */
  577         if (c->mode != M_ASYNC) {
  578                 if ((inb (ATBSTS(c->port)) & BSTS_OWN24) &&
  579                    (inb (BTBSTS(c->port)) & BSTS_OWN24)) {
  580                         outb (IER(c->port), IER_RXD | IER_TXD | IER_TXMPTY);
  581                 } else
  582                         outb (IER(c->port), IER_RXD | IER_TXD);
  583         }
  584 }
  585 
  586 void cx_int_handler (cx_board_t *b)
  587 {
  588         unsigned char livr;
  589         cx_chan_t *c;
  590 
  591         while (! (inw (BSR(b->port)) & BSR_NOINTR)) {
  592                 /* Enter the interrupt context, using IACK bus cycle.
  593                    Read the local interrupt vector register. */
  594                 livr = inb (IACK(b->port, BRD_INTR_LEVEL));
  595                 c = b->chan + (livr>>2 & 0xf);
  596                 if (c->type == T_NONE)
  597                         continue;
  598                 switch (livr & 3) {
  599                 case LIV_MODEM:                 /* modem interrupt */
  600                         ++c->mintr;
  601                         if (c->call_on_msig)
  602                                 c->call_on_msig (c);
  603                         outb (MEOIR(c->port), 0);
  604                         break;
  605                 case LIV_EXCEP:                 /* receive exception */
  606                 case LIV_RXDATA:                /* receive interrupt */
  607                         outb (REOIR(c->port), cx_receive_interrupt (c));
  608                         if (c->call_on_rx && c->received_data) {
  609                                 c->call_on_rx (c, c->received_data,
  610                                         c->received_len);
  611                                 c->received_data = 0;
  612                         }
  613                         break;
  614                 case LIV_TXDATA:                /* transmit interrupt */
  615                         cx_transmit_interrupt (c);
  616                         outb (TEOIR(c->port), 0);
  617                         break;
  618                 }
  619         }
  620 }
  621 
  622 /*
  623  * Register event processing functions
  624  */
  625 void cx_register_transmit (cx_chan_t *c,
  626         void (*func) (cx_chan_t *c, void *attachment, int len))
  627 {
  628         c->call_on_tx = func;
  629 }
  630 
  631 void cx_register_receive (cx_chan_t *c,
  632         void (*func) (cx_chan_t *c, char *data, int len))
  633 {
  634         c->call_on_rx = func;
  635 }
  636 
  637 void cx_register_modem (cx_chan_t *c, void (*func) (cx_chan_t *c))
  638 {
  639         c->call_on_msig = func;
  640 }
  641 
  642 void cx_register_error (cx_chan_t *c, void (*func) (cx_chan_t *c, int data))
  643 {
  644         c->call_on_err = func;
  645 }
  646 
  647 /*
  648  * Async protocol functions.
  649  */
  650 
  651 /*
  652  * Enable/disable transmitter.
  653  */
  654 void cx_transmitter_ctl (cx_chan_t *c,int start)
  655 {
  656         outb (CAR(c->port), c->num & 3);
  657         cx_cmd (c->port, start ? CCR_ENTX : CCR_DISTX);
  658 }
  659 
  660 /*
  661  * Discard all data queued in transmitter.
  662  */
  663 void cx_flush_transmit (cx_chan_t *c)
  664 {
  665         outb (CAR(c->port), c->num & 3);
  666         cx_cmd (c->port, CCR_CLRTX);
  667 }
  668 
  669 /*
  670  * Send the XON/XOFF flow control symbol.
  671  */
  672 void cx_xflow_ctl (cx_chan_t *c, int on)
  673 {
  674         outb (CAR(c->port), c->num & 3);
  675         outb (STCR(c->port), STC_SNDSPC | (on ? STC_SSPC_1 : STC_SSPC_2));
  676 }
  677 
  678 /*
  679  * Send the break signal for a given number of milliseconds.
  680  */
  681 void cx_send_break (cx_chan_t *c, int msec)
  682 {
  683         static unsigned char buf [128];
  684         unsigned char *p;
  685 
  686         p = buf;
  687         *p++ = 0;               /* extended transmit command */
  688         *p++ = 0x81;            /* send break */
  689 
  690         if (msec > 10000)       /* max 10 seconds */
  691                 msec = 10000;
  692         if (msec < 10)          /* min 10 msec */
  693                 msec = 10;
  694         while (msec > 0) {
  695                 int ms = 250;   /* 250 msec */
  696                 if (ms > msec)
  697                         ms = msec;
  698                 msec -= ms;
  699                 *p++ = 0;       /* extended transmit command */
  700                 *p++ = 0x82;    /* insert delay */
  701                 *p++ = ms;
  702         }
  703         *p++ = 0;               /* extended transmit command */
  704         *p++ = 0x83;            /* stop break */
  705 
  706         cx_send (c, buf, p-buf, 0);
  707 }
  708 
  709 /*
  710  * Set async parameters.
  711  */
  712 void cx_set_async_param (cx_chan_t *c, int baud, int bits, int parity,
  713         int stop2, int ignpar, int rtscts,
  714         int ixon, int ixany, int symstart, int symstop)
  715 {
  716         int clock, period;
  717         cx_cor1_async_t cor1;
  718 
  719         /* Set character length and parity mode. */
  720         BYTE cor1 = 0;
  721         cor1.charlen = bits - 1;
  722         cor1.parmode = parity ? PARM_NORMAL : PARM_NOPAR;
  723         cor1.parity = parity==1 ? PAR_ODD : PAR_EVEN;
  724         cor1.ignpar = ignpar ? 1 : 0;
  725 
  726         /* Enable/disable hardware CTS. */
  727         c->aopt.cor2.ctsae = rtscts ? 1 : 0;
  728 
  729         /* Enable extended transmit command mode.
  730          * Unfortunately, there is no other method for sending break. */
  731         c->aopt.cor2.etc = 1;
  732 
  733         /* Enable/disable hardware XON/XOFF. */
  734         c->aopt.cor2.ixon = ixon ? 1 : 0;
  735         c->aopt.cor2.ixany = ixany ? 1 : 0;
  736 
  737         /* Set the number of stop bits. */
  738         if (stop2)
  739                 c->aopt.cor3.stopb = STOPB_2;
  740         else
  741                 c->aopt.cor3.stopb = STOPB_1;
  742 
  743         /* Disable/enable passing XON/XOFF chars to the host. */
  744         c->aopt.cor3.scde = ixon ? 1 : 0;
  745         c->aopt.cor3.flowct = ixon ? FLOWCC_NOTPASS : FLOWCC_PASS;
  746 
  747         c->aopt.schr1 = symstart;       /* XON */
  748         c->aopt.schr2 = symstop;        /* XOFF */
  749 
  750         /* Set current channel number. */
  751         outb (CAR(c->port), c->num & 3);
  752 
  753         /* Set up clock values. */
  754         if (baud) {
  755                 c->rxbaud = c->txbaud = baud;
  756 
  757                 /* Receiver. */
  758                 cx_clock (c->oscfreq, c->rxbaud, &clock, &period);
  759                 c->opt.rcor.clk = clock;
  760                 outb (RCOR(c->port), BYTE c->opt.rcor);
  761                 outb (RBPR(c->port), period);
  762 
  763                 /* Transmitter. */
  764                 cx_clock (c->oscfreq, c->txbaud, &clock, &period);
  765                 c->opt.tcor.clk = clock;
  766                 c->opt.tcor.ext1x = 0;
  767                 outb (TCOR(c->port), BYTE c->opt.tcor);
  768                 outb (TBPR(c->port), period);
  769         }
  770         outb (COR2(c->port), BYTE c->aopt.cor2);
  771         outb (COR3(c->port), BYTE c->aopt.cor3);
  772         outb (SCHR1(c->port), c->aopt.schr1);
  773         outb (SCHR2(c->port), c->aopt.schr2);
  774 
  775         if (BYTE c->aopt.cor1 != BYTE cor1) {
  776                 BYTE c->aopt.cor1 = BYTE cor1;
  777                 outb (COR1(c->port), BYTE c->aopt.cor1);
  778                 /* Any change to COR1 require reinitialization. */
  779                 /* Unfortunately, it may cause transmitter glitches... */
  780                 cx_cmd (c->port, CCR_INITCH);
  781         }
  782 }
  783 
  784 /*
  785  * Set mode: M_ASYNC or M_HDLC.
  786  * Both receiver and transmitter are disabled.
  787  */
  788 int cx_set_mode (cx_chan_t *c, int mode)
  789 {
  790         if (mode == M_HDLC) {
  791                 if (c->type == T_ASYNC)
  792                         return -1;
  793 
  794                 if (c->mode == M_HDLC)
  795                         return 0;
  796 
  797                 c->mode = M_HDLC;
  798         } else if (mode == M_ASYNC) {
  799                 if (c->type == T_SYNC_RS232 ||
  800                     c->type == T_SYNC_V35   ||
  801                     c->type == T_SYNC_RS449)
  802                         return -1;
  803 
  804                 if (c->mode == M_ASYNC)
  805                         return 0;
  806 
  807                 c->mode = M_ASYNC;
  808                 c->opt.tcor.ext1x = 0;
  809                 c->opt.tcor.llm = 0;
  810                 c->opt.rcor.dpll = 0;
  811                 c->opt.rcor.encod = ENCOD_NRZ;
  812                 if (! c->txbaud || ! c->rxbaud)
  813                         c->txbaud = c->rxbaud = 9600;
  814         } else
  815                 return -1;
  816 
  817         cx_setup_chan (c);
  818         cx_start_chan (c, 0, 0);
  819         cx_enable_receive (c, 0);
  820         cx_enable_transmit (c, 0);
  821         return 0;
  822 }
  823 
  824 /*
  825  * Set port type for old models of Sigma
  826  */
  827 void cx_set_port (cx_chan_t *c, int iftype)
  828 {
  829         if (c->board->type == B_SIGMA_XXX) {
  830                 switch (c->num) {
  831                 case 0:
  832                         if ((c->board->if0type != 0) == (iftype != 0))
  833                                 return;
  834                         c->board->if0type = iftype;
  835                         c->board->bcr0 &= ~BCR0_UMASK;
  836                         if (c->board->if0type &&
  837                             (c->type==T_UNIV_RS449 || c->type==T_UNIV_V35))
  838                                 c->board->bcr0 |= BCR0_UI_RS449;
  839                         outb (BCR0(c->board->port), c->board->bcr0);
  840                         break;
  841                 case 8:
  842                         if ((c->board->if8type != 0) == (iftype != 0))
  843                                 return;
  844                         c->board->if8type = iftype;
  845                         c->board->bcr0b &= ~BCR0_UMASK;
  846                         if (c->board->if8type &&
  847                             (c->type==T_UNIV_RS449 || c->type==T_UNIV_V35))
  848                                 c->board->bcr0b |= BCR0_UI_RS449;
  849                         outb (BCR0(c->board->port+0x10), c->board->bcr0b);
  850                         break;
  851                 }
  852         }
  853 }
  854 
  855 /*
  856  * Get port type for old models of Sigma
  857  * -1 Fixed port type or auto detect
  858  *  0 RS232
  859  *  1 V35
  860  *  2 RS449
  861  */
  862 int cx_get_port (cx_chan_t *c)
  863 {
  864         int iftype;
  865 
  866         if (c->board->type == B_SIGMA_XXX) {
  867                 switch (c->num) {
  868                 case 0:
  869                         iftype = c->board->if0type; break;
  870                 case 8:
  871                         iftype = c->board->if8type; break;
  872                 default:
  873                         return -1;
  874                 }
  875 
  876                 if (iftype)
  877                         switch (c->type) {
  878                         case T_UNIV_V35:   return 1;
  879                         case T_UNIV_RS449: return 2;
  880                         default:           return -1;
  881                         }
  882                 else
  883                         return 0;
  884         } else
  885                 return -1;
  886 }
  887 
  888 void cx_intr_off (cx_board_t *b)
  889 {
  890         outb (BCR0(b->port), b->bcr0 & ~BCR0_IRQ_MASK);
  891         if (b->chan[8].port || b->chan[12].port)
  892                 outb (BCR0(b->port+0x10), b->bcr0b & ~BCR0_IRQ_MASK);
  893 }
  894 
  895 void cx_intr_on (cx_board_t *b)
  896 {
  897         outb (BCR0(b->port), b->bcr0);
  898         if (b->chan[8].port || b->chan[12].port)
  899                 outb (BCR0(b->port+0x10), b->bcr0b);
  900 }
  901 
  902 int cx_checkintr (cx_board_t *b)
  903 {
  904         return (!(inw (BSR(b->port)) & BSR_NOINTR));
  905 }

Cache object: 3aa4ee1d2f2b8f683beca7662f5665b2


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