1139749Simp/*- 2123120Simp * Cronyx-Sigma Driver Development Kit. 3123120Simp * 4123120Simp * Copyright (C) 1998 Cronyx Engineering. 5123120Simp * Author: Pavel Novikov, <pavel@inr.net.kiae.su> 6123120Simp * 7123120Simp * Copyright (C) 1998-2003 Cronyx Engineering. 8123120Simp * Author: Roman Kurakin, <rik@cronyx.ru> 9123120Simp * 10123120Simp * This software is distributed with NO WARRANTIES, not even the implied 11123120Simp * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12123120Simp * 13123120Simp * Authors grant any other persons or organisations permission to use 14123120Simp * or modify this software as long as this message is kept with the software, 15123120Simp * all derivative works or modified versions. 16123120Simp * 17123120Simp * Cronyx Id: cxddk.c,v 1.1.2.2 2003/11/27 14:24:50 rik Exp $ 18123120Simp */ 19123120Simp#include <sys/cdefs.h> 20123120Simp__FBSDID("$FreeBSD: stable/11/sys/dev/cx/cxddk.c 315221 2017-03-14 02:06:03Z pfg $"); 21123120Simp 22123120Simp#include <dev/cx/machdep.h> 23123120Simp#include <dev/cx/cxddk.h> 24123120Simp#include <dev/cx/cxreg.h> 25123120Simp#include <dev/cx/cronyxfw.h> 26123120Simp#include <dev/cx/csigmafw.h> 27123120Simp 28123120Simp#define BYTE *(unsigned char*)& 29123120Simp 30123120Simp/* standard base port set */ 31123120Simpstatic short porttab [] = { 32123120Simp 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 33123120Simp 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0 34123120Simp}; 35123120Simp 36123120Simp/* 37123120Simp * Compute the optimal size of the receive buffer. 38123120Simp */ 39123120Simpstatic int cx_compute_buf_len (cx_chan_t *c) 40123120Simp{ 41123120Simp int rbsz; 42123120Simp if (c->mode == M_ASYNC) { 43123120Simp rbsz = (c->rxbaud + 800 - 1) / 800 * 2; 44123120Simp if (rbsz < 4) 45123120Simp rbsz = 4; 46123120Simp else if (rbsz > DMABUFSZ) 47123120Simp rbsz = DMABUFSZ; 48123120Simp } 49123120Simp else 50123120Simp rbsz = DMABUFSZ; 51123120Simp 52123120Simp return rbsz; 53123120Simp} 54123120Simp 55123120Simp/* 56123120Simp * Auto-detect the installed adapters. 57123120Simp */ 58123120Simpint cx_find (port_t *board_ports) 59123120Simp{ 60123120Simp int i, n; 61123120Simp 62123120Simp for (i=0, n=0; porttab[i] && n<NBRD; i++) 63123120Simp if (cx_probe_board (porttab[i], -1, -1)) 64123120Simp board_ports[n++] = porttab[i]; 65123120Simp return n; 66123120Simp} 67123120Simp 68123120Simp/* 69123120Simp * Initialize the adapter. 70123120Simp */ 71123120Simpint cx_open_board (cx_board_t *b, int num, port_t port, int irq, int dma) 72123120Simp{ 73123120Simp cx_chan_t *c; 74123120Simp 75123120Simp if (num >= NBRD || ! cx_probe_board (port, irq, dma)) 76123120Simp return 0; 77123120Simp 78123120Simp /* init callback pointers */ 79123120Simp for (c=b->chan; c<b->chan+NCHAN; ++c) { 80123120Simp c->call_on_tx = 0; 81123120Simp c->call_on_rx = 0; 82123120Simp c->call_on_msig = 0; 83123120Simp c->call_on_err = 0; 84123120Simp } 85123120Simp 86123120Simp cx_init (b, num, port, irq, dma); 87123120Simp 88123120Simp /* Loading firmware */ 89123120Simp if (! cx_setup_board (b, csigma_fw_data, csigma_fw_len, csigma_fw_tvec)) 90123120Simp return 0; 91123120Simp return 1; 92123120Simp} 93123120Simp 94123120Simp/* 95123120Simp * Shutdown the adapter. 96123120Simp */ 97123120Simpvoid cx_close_board (cx_board_t *b) 98123120Simp{ 99123120Simp cx_setup_board (b, 0, 0, 0); 100123120Simp 101123120Simp /* Reset the controller. */ 102123120Simp outb (BCR0(b->port), 0); 103123120Simp if (b->chan[8].type || b->chan[12].type) 104123120Simp outb (BCR0(b->port+0x10), 0); 105123120Simp} 106123120Simp 107123120Simp/* 108123120Simp * Start the channel. 109123120Simp */ 110123120Simpvoid cx_start_chan (cx_chan_t *c, cx_buf_t *cb, unsigned long phys) 111123120Simp{ 112123120Simp int command = 0; 113123120Simp int mode = 0; 114123120Simp int ier = 0; 115123120Simp int rbsz; 116123120Simp 117123120Simp c->overflow = 0; 118123120Simp 119123120Simp /* Setting up buffers */ 120123120Simp if (cb) { 121123120Simp c->arbuf = cb->rbuffer[0]; 122123120Simp c->brbuf = cb->rbuffer[1]; 123123120Simp c->atbuf = cb->tbuffer[0]; 124123120Simp c->btbuf = cb->tbuffer[1]; 125123120Simp c->arphys = phys + ((char*)c->arbuf - (char*)cb); 126123120Simp c->brphys = phys + ((char*)c->brbuf - (char*)cb); 127123120Simp c->atphys = phys + ((char*)c->atbuf - (char*)cb); 128123120Simp c->btphys = phys + ((char*)c->btbuf - (char*)cb); 129123120Simp } 130123120Simp 131123120Simp /* Set current channel number */ 132123120Simp outb (CAR(c->port), c->num & 3); 133123120Simp 134123120Simp /* set receiver A buffer physical address */ 135123120Simp outw (ARBADRU(c->port), (unsigned short) (c->arphys>>16)); 136123120Simp outw (ARBADRL(c->port), (unsigned short) c->arphys); 137123120Simp 138123120Simp /* set receiver B buffer physical address */ 139123120Simp outw (BRBADRU(c->port), (unsigned short) (c->brphys>>16)); 140123120Simp outw (BRBADRL(c->port), (unsigned short) c->brphys); 141123120Simp 142123120Simp /* set transmitter A buffer physical address */ 143123120Simp outw (ATBADRU(c->port), (unsigned short) (c->atphys>>16)); 144123120Simp outw (ATBADRL(c->port), (unsigned short) c->atphys); 145123120Simp 146123120Simp /* set transmitter B buffer physical address */ 147123120Simp outw (BTBADRU(c->port), (unsigned short) (c->btphys>>16)); 148123120Simp outw (BTBADRL(c->port), (unsigned short) c->btphys); 149123120Simp 150123120Simp /* rx */ 151123120Simp command |= CCR_ENRX; 152123120Simp ier |= IER_RXD; 153123120Simp if (c->board->dma) { 154123120Simp mode |= CMR_RXDMA; 155123120Simp if (c->mode == M_ASYNC) 156123120Simp ier |= IER_RET; 157123120Simp } 158123120Simp 159123120Simp /* tx */ 160123120Simp command |= CCR_ENTX; 161123120Simp ier |= (c->mode == M_ASYNC) ? IER_TXD : (IER_TXD | IER_TXMPTY); 162123120Simp if (c->board->dma) 163123120Simp mode |= CMR_TXDMA; 164123120Simp 165123120Simp /* Set mode */ 166123120Simp outb (CMR(c->port), mode | (c->mode == M_ASYNC ? CMR_ASYNC : CMR_HDLC)); 167123120Simp 168123120Simp /* Clear and initialize channel */ 169123120Simp cx_cmd (c->port, CCR_CLRCH); 170123120Simp cx_cmd (c->port, CCR_INITCH | command); 171123120Simp if (c->mode == M_ASYNC) 172123120Simp cx_cmd (c->port, CCR_ENTX); 173123120Simp 174123120Simp /* Start receiver */ 175123120Simp rbsz = cx_compute_buf_len(c); 176123120Simp outw (ARBCNT(c->port), rbsz); 177123120Simp outw (BRBCNT(c->port), rbsz); 178123120Simp outw (ARBSTS(c->port), BSTS_OWN24); 179123120Simp outw (BRBSTS(c->port), BSTS_OWN24); 180123120Simp 181123120Simp if (c->mode == M_ASYNC) 182123120Simp ier |= IER_MDM; 183123120Simp 184123120Simp /* Enable interrupts */ 185123120Simp outb (IER(c->port), ier); 186123120Simp 187123120Simp /* Clear DTR and RTS */ 188123120Simp cx_set_dtr (c, 0); 189123120Simp cx_set_rts (c, 0); 190123120Simp} 191123120Simp 192123120Simp/* 193123120Simp * Turn the receiver on/off. 194123120Simp */ 195123120Simpvoid cx_enable_receive (cx_chan_t *c, int on) 196123120Simp{ 197123120Simp unsigned char ier; 198123120Simp 199123120Simp if (cx_receive_enabled(c) && ! on) { 200123120Simp outb (CAR(c->port), c->num & 3); 201123120Simp if (c->mode == M_ASYNC) { 202123120Simp ier = inb (IER(c->port)); 203123120Simp outb (IER(c->port), ier & ~ (IER_RXD | IER_RET)); 204123120Simp } 205123120Simp cx_cmd (c->port, CCR_DISRX); 206123120Simp } else if (! cx_receive_enabled(c) && on) { 207123120Simp outb (CAR(c->port), c->num & 3); 208123120Simp ier = inb (IER(c->port)); 209123120Simp if (c->mode == M_ASYNC) 210123120Simp outb (IER(c->port), ier | (IER_RXD | IER_RET)); 211123120Simp else 212123120Simp outb (IER(c->port), ier | IER_RXD); 213123120Simp cx_cmd (c->port, CCR_ENRX); 214123120Simp } 215123120Simp} 216123120Simp 217123120Simp/* 218123120Simp * Turn the transmiter on/off. 219123120Simp */ 220123120Simpvoid cx_enable_transmit (cx_chan_t *c, int on) 221123120Simp{ 222123120Simp if (cx_transmit_enabled(c) && ! on) { 223123120Simp outb (CAR(c->port), c->num & 3); 224123120Simp if (c->mode != M_ASYNC) 225123120Simp outb (STCR(c->port), STC_ABORTTX | STC_SNDSPC); 226123120Simp cx_cmd (c->port, CCR_DISTX); 227123120Simp } else if (! cx_transmit_enabled(c) && on) { 228123120Simp outb (CAR(c->port), c->num & 3); 229123120Simp cx_cmd (c->port, CCR_ENTX); 230123120Simp } 231123120Simp} 232123120Simp 233123120Simp/* 234123120Simp * Get channel status. 235123120Simp */ 236123120Simpint cx_receive_enabled (cx_chan_t *c) 237123120Simp{ 238123120Simp outb (CAR(c->port), c->num & 3); 239123120Simp return (inb (CSR(c->port)) & CSRA_RXEN) != 0; 240123120Simp} 241123120Simp 242123120Simpint cx_transmit_enabled (cx_chan_t *c) 243123120Simp{ 244123120Simp outb (CAR(c->port), c->num & 3); 245123120Simp return (inb (CSR(c->port)) & CSRA_TXEN) != 0; 246123120Simp} 247123120Simp 248123120Simpunsigned long cx_get_baud (cx_chan_t *c) 249123120Simp{ 250123120Simp return (c->opt.tcor.clk == CLK_EXT) ? 0 : c->txbaud; 251123120Simp} 252123120Simp 253123120Simpint cx_get_loop (cx_chan_t *c) 254123120Simp{ 255123120Simp return c->opt.tcor.llm ? 1 : 0; 256123120Simp} 257123120Simp 258123120Simpint cx_get_nrzi (cx_chan_t *c) 259123120Simp{ 260123120Simp return c->opt.rcor.encod == ENCOD_NRZI; 261123120Simp} 262123120Simp 263123120Simpint cx_get_dpll (cx_chan_t *c) 264123120Simp{ 265123120Simp return c->opt.rcor.dpll ? 1 : 0; 266123120Simp} 267123120Simp 268123120Simpvoid cx_set_baud (cx_chan_t *c, unsigned long bps) 269123120Simp{ 270123120Simp int clock, period; 271123120Simp 272123120Simp c->txbaud = c->rxbaud = bps; 273123120Simp 274123120Simp /* Set current channel number */ 275123120Simp outb (CAR(c->port), c->num & 3); 276123120Simp if (bps) { 277123120Simp if (c->mode == M_ASYNC || c->opt.rcor.dpll || c->opt.tcor.llm) { 278123120Simp /* Receive baud - internal */ 279123120Simp cx_clock (c->oscfreq, c->rxbaud, &clock, &period); 280123120Simp c->opt.rcor.clk = clock; 281123120Simp outb (RCOR(c->port), BYTE c->opt.rcor); 282123120Simp outb (RBPR(c->port), period); 283123120Simp } else { 284123120Simp /* Receive baud - external */ 285123120Simp c->opt.rcor.clk = CLK_EXT; 286123120Simp outb (RCOR(c->port), BYTE c->opt.rcor); 287123120Simp outb (RBPR(c->port), 1); 288123120Simp } 289123120Simp 290123120Simp /* Transmit baud - internal */ 291123120Simp cx_clock (c->oscfreq, c->txbaud, &clock, &period); 292123120Simp c->opt.tcor.clk = clock; 293123120Simp c->opt.tcor.ext1x = 0; 294123120Simp outb (TBPR(c->port), period); 295123120Simp } else if (c->mode != M_ASYNC) { 296123120Simp /* External clock - disable local loopback and DPLL */ 297123120Simp c->opt.tcor.llm = 0; 298123120Simp c->opt.rcor.dpll = 0; 299123120Simp 300123120Simp /* Transmit baud - external */ 301123120Simp c->opt.tcor.ext1x = 1; 302123120Simp c->opt.tcor.clk = CLK_EXT; 303123120Simp outb (TBPR(c->port), 1); 304123120Simp 305123120Simp /* Receive baud - external */ 306123120Simp c->opt.rcor.clk = CLK_EXT; 307123120Simp outb (RCOR(c->port), BYTE c->opt.rcor); 308123120Simp outb (RBPR(c->port), 1); 309123120Simp } 310123120Simp if (c->opt.tcor.llm) 311123120Simp outb (COR2(c->port), (BYTE c->hopt.cor2) & ~3); 312123120Simp else 313123120Simp outb (COR2(c->port), BYTE c->hopt.cor2); 314123120Simp outb (TCOR(c->port), BYTE c->opt.tcor); 315123120Simp} 316123120Simp 317123120Simpvoid cx_set_loop (cx_chan_t *c, int on) 318123120Simp{ 319123120Simp if (! c->txbaud) 320123120Simp return; 321123120Simp 322123120Simp c->opt.tcor.llm = on ? 1 : 0; 323123120Simp cx_set_baud (c, c->txbaud); 324123120Simp} 325123120Simp 326123120Simpvoid cx_set_dpll (cx_chan_t *c, int on) 327123120Simp{ 328123120Simp if (! c->txbaud) 329123120Simp return; 330123120Simp 331123120Simp c->opt.rcor.dpll = on ? 1 : 0; 332123120Simp cx_set_baud (c, c->txbaud); 333123120Simp} 334123120Simp 335123120Simpvoid cx_set_nrzi (cx_chan_t *c, int nrzi) 336123120Simp{ 337123120Simp c->opt.rcor.encod = (nrzi ? ENCOD_NRZI : ENCOD_NRZ); 338123120Simp outb (CAR(c->port), c->num & 3); 339123120Simp outb (RCOR(c->port), BYTE c->opt.rcor); 340123120Simp} 341123120Simp 342123120Simpstatic int cx_send (cx_chan_t *c, char *data, int len, 343123120Simp void *attachment) 344123120Simp{ 345123120Simp unsigned char *buf; 346123120Simp port_t cnt_port, sts_port; 347123120Simp void **attp; 348123120Simp 349123120Simp /* Set the current channel number. */ 350123120Simp outb (CAR(c->port), c->num & 3); 351123120Simp 352123120Simp /* Determine the buffer order. */ 353123120Simp if (inb (DMABSTS(c->port)) & DMABSTS_NTBUF) { 354123120Simp if (inb (BTBSTS(c->port)) & BSTS_OWN24) { 355123120Simp buf = c->atbuf; 356123120Simp cnt_port = ATBCNT(c->port); 357123120Simp sts_port = ATBSTS(c->port); 358123120Simp attp = &c->attach[0]; 359123120Simp } else { 360123120Simp buf = c->btbuf; 361123120Simp cnt_port = BTBCNT(c->port); 362123120Simp sts_port = BTBSTS(c->port); 363123120Simp attp = &c->attach[1]; 364123120Simp } 365123120Simp } else { 366123120Simp if (inb (ATBSTS(c->port)) & BSTS_OWN24) { 367123120Simp buf = c->btbuf; 368123120Simp cnt_port = BTBCNT(c->port); 369123120Simp sts_port = BTBSTS(c->port); 370123120Simp attp = &c->attach[1]; 371123120Simp } else { 372123120Simp buf = c->atbuf; 373123120Simp cnt_port = ATBCNT(c->port); 374123120Simp sts_port = ATBSTS(c->port); 375123120Simp attp = &c->attach[0]; 376123120Simp } 377123120Simp } 378123120Simp /* Is it busy? */ 379123120Simp if (inb (sts_port) & BSTS_OWN24) 380123120Simp return -1; 381123120Simp 382123120Simp memcpy (buf, data, len); 383123120Simp *attp = attachment; 384123120Simp 385123120Simp /* Start transmitter. */ 386123120Simp outw (cnt_port, len); 387123120Simp outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24); 388123120Simp 389123120Simp /* Enable TXMPTY interrupt, 390123120Simp * to catch the case when the second buffer is empty. */ 391123120Simp if (c->mode != M_ASYNC) { 392123120Simp if ((inb(ATBSTS(c->port)) & BSTS_OWN24) && 393123120Simp (inb(BTBSTS(c->port)) & BSTS_OWN24)) { 394123120Simp outb (IER(c->port), IER_RXD | IER_TXD | IER_TXMPTY); 395123120Simp } else 396123120Simp outb (IER(c->port), IER_RXD | IER_TXD); 397123120Simp } 398123120Simp return 0; 399123120Simp} 400123120Simp 401123120Simp/* 402123120Simp * Number of free buffs 403123120Simp */ 404123120Simpint cx_buf_free (cx_chan_t *c) 405123120Simp{ 406123120Simp return ! (inb (ATBSTS(c->port)) & BSTS_OWN24) + 407123120Simp ! (inb (BTBSTS(c->port)) & BSTS_OWN24); 408123120Simp} 409123120Simp 410123120Simp/* 411123120Simp * Send the data packet. 412123120Simp */ 413123120Simpint cx_send_packet (cx_chan_t *c, char *data, int len, void *attachment) 414123120Simp{ 415123120Simp if (len >= DMABUFSZ) 416123120Simp return -2; 417123120Simp if (c->mode == M_ASYNC) { 418123120Simp static char buf [DMABUFSZ]; 419123120Simp char *p, *t = buf; 420123120Simp 421123120Simp /* Async -- double all nulls. */ 422123120Simp for (p=data; p < data+len && t < buf+DMABUFSZ-1; ++p) 423123120Simp if ((*t++ = *p) == 0) 424123120Simp *t++ = 0; 425123120Simp return cx_send (c, buf, t-buf, attachment); 426123120Simp } 427123120Simp return cx_send (c, data, len, attachment); 428123120Simp} 429123120Simp 430123120Simpstatic int cx_receive_interrupt (cx_chan_t *c) 431123120Simp{ 432123120Simp unsigned short risr; 433123120Simp int len = 0, rbsz; 434123120Simp 435123120Simp ++c->rintr; 436123120Simp risr = inw (RISR(c->port)); 437123120Simp 438123120Simp /* Compute optimal receiver buffer length */ 439123120Simp rbsz = cx_compute_buf_len(c); 440123120Simp if (c->mode == M_ASYNC && (risr & RISA_TIMEOUT)) { 441123120Simp unsigned long rcbadr = (unsigned short) inw (RCBADRL(c->port)) | 442123120Simp (long) inw (RCBADRU(c->port)) << 16; 443315221Spfg unsigned char *buf = NULL; 444123120Simp port_t cnt_port = 0, sts_port = 0; 445123120Simp 446123120Simp if (rcbadr >= c->brphys && rcbadr < c->brphys+DMABUFSZ) { 447123120Simp buf = c->brbuf; 448123120Simp len = rcbadr - c->brphys; 449123120Simp cnt_port = BRBCNT(c->port); 450123120Simp sts_port = BRBSTS(c->port); 451123120Simp } else if (rcbadr >= c->arphys && rcbadr < c->arphys+DMABUFSZ) { 452123120Simp buf = c->arbuf; 453123120Simp len = rcbadr - c->arphys; 454123120Simp cnt_port = ARBCNT(c->port); 455123120Simp sts_port = ARBSTS(c->port); 456123120Simp } 457123120Simp 458123120Simp if (len) { 459123120Simp c->ibytes += len; 460123120Simp c->received_data = buf; 461123120Simp c->received_len = len; 462123120Simp 463123120Simp /* Restart receiver. */ 464123120Simp outw (cnt_port, rbsz); 465123120Simp outb (sts_port, BSTS_OWN24); 466123120Simp } 467123120Simp return (REOI_TERMBUFF); 468123120Simp } 469123120Simp 470123120Simp /* Receive errors. */ 471123120Simp if (risr & RIS_OVERRUN) { 472123120Simp ++c->ierrs; 473123120Simp if (c->call_on_err) 474123120Simp c->call_on_err (c, CX_OVERRUN); 475123120Simp } else if (c->mode != M_ASYNC && (risr & RISH_CRCERR)) { 476123120Simp ++c->ierrs; 477123120Simp if (c->call_on_err) 478123120Simp c->call_on_err (c, CX_CRC); 479123120Simp } else if (c->mode != M_ASYNC && (risr & (RISH_RXABORT | RISH_RESIND))) { 480123120Simp ++c->ierrs; 481123120Simp if (c->call_on_err) 482123120Simp c->call_on_err (c, CX_FRAME); 483123120Simp } else if (c->mode == M_ASYNC && (risr & RISA_PARERR)) { 484123120Simp ++c->ierrs; 485123120Simp if (c->call_on_err) 486123120Simp c->call_on_err (c, CX_CRC); 487123120Simp } else if (c->mode == M_ASYNC && (risr & RISA_FRERR)) { 488123120Simp ++c->ierrs; 489123120Simp if (c->call_on_err) 490123120Simp c->call_on_err (c, CX_FRAME); 491123120Simp } else if (c->mode == M_ASYNC && (risr & RISA_BREAK)) { 492123120Simp if (c->call_on_err) 493123120Simp c->call_on_err (c, CX_BREAK); 494123120Simp } else if (! (risr & RIS_EOBUF)) { 495123120Simp ++c->ierrs; 496123120Simp } else { 497123120Simp /* Handle received data. */ 498123120Simp len = (risr & RIS_BB) ? inw(BRBCNT(c->port)) : inw(ARBCNT(c->port)); 499123120Simp 500123120Simp if (len > DMABUFSZ) { 501123120Simp /* Fatal error: actual DMA transfer size 502123120Simp * exceeds our buffer size. It could be caused 503123120Simp * by incorrectly programmed DMA register or 504123120Simp * hardware fault. Possibly, should panic here. */ 505123120Simp len = DMABUFSZ; 506123120Simp } else if (c->mode != M_ASYNC && ! (risr & RIS_EOFR)) { 507123120Simp /* The received frame does not fit in the DMA buffer. 508123120Simp * It could be caused by serial lie noise, 509123120Simp * or if the peer has too big MTU. */ 510123120Simp if (! c->overflow) { 511123120Simp if (c->call_on_err) 512123120Simp c->call_on_err (c, CX_OVERFLOW); 513123120Simp c->overflow = 1; 514123120Simp ++c->ierrs; 515123120Simp } 516123120Simp } else if (! c->overflow) { 517123120Simp if (risr & RIS_BB) { 518123120Simp c->received_data = c->brbuf; 519123120Simp c->received_len = len; 520123120Simp } else { 521123120Simp c->received_data = c->arbuf; 522123120Simp c->received_len = len; 523123120Simp } 524123120Simp if (c->mode != M_ASYNC) 525123120Simp ++c->ipkts; 526123120Simp c->ibytes += len; 527123120Simp } else 528123120Simp c->overflow = 0; 529123120Simp } 530123120Simp 531123120Simp /* Restart receiver. */ 532123120Simp if (! (inb (ARBSTS(c->port)) & BSTS_OWN24)) { 533123120Simp outw (ARBCNT(c->port), rbsz); 534123120Simp outb (ARBSTS(c->port), BSTS_OWN24); 535123120Simp } 536123120Simp if (! (inb (BRBSTS(c->port)) & BSTS_OWN24)) { 537123120Simp outw (BRBCNT(c->port), rbsz); 538123120Simp outb (BRBSTS(c->port), BSTS_OWN24); 539123120Simp } 540123120Simp 541123120Simp /* Discard exception characters. */ 542123120Simp if ((risr & RISA_SCMASK) && c->aopt.cor2.ixon) 543123120Simp return (REOI_DISCEXC); 544123120Simp else 545123120Simp return (0); 546123120Simp} 547123120Simp 548123120Simpstatic void cx_transmit_interrupt (cx_chan_t *c) 549123120Simp{ 550123120Simp unsigned char tisr; 551123120Simp int len = 0; 552123120Simp 553123120Simp ++c->tintr; 554123120Simp tisr = inb (TISR(c->port)); 555123120Simp if (tisr & TIS_UNDERRUN) { /* Transmit underrun error */ 556123120Simp if (c->call_on_err) 557123120Simp c->call_on_err (c, CX_UNDERRUN); 558123120Simp ++c->oerrs; 559123120Simp } else if (tisr & (TIS_EOBUF | TIS_TXEMPTY | TIS_TXDATA)) { 560123120Simp /* Call processing function */ 561123120Simp if (tisr & TIS_BB) { 562123120Simp len = inw(BTBCNT(c->port)); 563123120Simp if (c->call_on_tx) 564123120Simp c->call_on_tx (c, c->attach[1], len); 565123120Simp } else { 566123120Simp len = inw(ATBCNT(c->port)); 567123120Simp if (c->call_on_tx) 568123120Simp c->call_on_tx (c, c->attach[0], len); 569123120Simp } 570123120Simp if (c->mode != M_ASYNC && len != 0) 571123120Simp ++c->opkts; 572123120Simp c->obytes += len; 573123120Simp } 574123120Simp 575123120Simp /* Enable TXMPTY interrupt, 576123120Simp * to catch the case when the second buffer is empty. */ 577123120Simp if (c->mode != M_ASYNC) { 578123120Simp if ((inb (ATBSTS(c->port)) & BSTS_OWN24) && 579123120Simp (inb (BTBSTS(c->port)) & BSTS_OWN24)) { 580123120Simp outb (IER(c->port), IER_RXD | IER_TXD | IER_TXMPTY); 581123120Simp } else 582123120Simp outb (IER(c->port), IER_RXD | IER_TXD); 583123120Simp } 584123120Simp} 585123120Simp 586123120Simpvoid cx_int_handler (cx_board_t *b) 587123120Simp{ 588123120Simp unsigned char livr; 589123120Simp cx_chan_t *c; 590123120Simp 591123120Simp while (! (inw (BSR(b->port)) & BSR_NOINTR)) { 592123120Simp /* Enter the interrupt context, using IACK bus cycle. 593123120Simp Read the local interrupt vector register. */ 594123120Simp livr = inb (IACK(b->port, BRD_INTR_LEVEL)); 595123120Simp c = b->chan + (livr>>2 & 0xf); 596123120Simp if (c->type == T_NONE) 597123120Simp continue; 598123120Simp switch (livr & 3) { 599123120Simp case LIV_MODEM: /* modem interrupt */ 600123120Simp ++c->mintr; 601123120Simp if (c->call_on_msig) 602123120Simp c->call_on_msig (c); 603123120Simp outb (MEOIR(c->port), 0); 604123120Simp break; 605123120Simp case LIV_EXCEP: /* receive exception */ 606123120Simp case LIV_RXDATA: /* receive interrupt */ 607123120Simp outb (REOIR(c->port), cx_receive_interrupt (c)); 608123120Simp if (c->call_on_rx && c->received_data) { 609123120Simp c->call_on_rx (c, c->received_data, 610123120Simp c->received_len); 611123120Simp c->received_data = 0; 612123120Simp } 613123120Simp break; 614123120Simp case LIV_TXDATA: /* transmit interrupt */ 615123120Simp cx_transmit_interrupt (c); 616123120Simp outb (TEOIR(c->port), 0); 617123120Simp break; 618123120Simp } 619123120Simp } 620123120Simp} 621123120Simp 622123120Simp/* 623123120Simp * Register event processing functions 624123120Simp */ 625123120Simpvoid cx_register_transmit (cx_chan_t *c, 626123120Simp void (*func) (cx_chan_t *c, void *attachment, int len)) 627123120Simp{ 628123120Simp c->call_on_tx = func; 629123120Simp} 630123120Simp 631123120Simpvoid cx_register_receive (cx_chan_t *c, 632123120Simp void (*func) (cx_chan_t *c, char *data, int len)) 633123120Simp{ 634123120Simp c->call_on_rx = func; 635123120Simp} 636123120Simp 637123120Simpvoid cx_register_modem (cx_chan_t *c, void (*func) (cx_chan_t *c)) 638123120Simp{ 639123120Simp c->call_on_msig = func; 640123120Simp} 641123120Simp 642123120Simpvoid cx_register_error (cx_chan_t *c, void (*func) (cx_chan_t *c, int data)) 643123120Simp{ 644123120Simp c->call_on_err = func; 645123120Simp} 646123120Simp 647123120Simp/* 648123120Simp * Async protocol functions. 649123120Simp */ 650123120Simp 651123120Simp/* 652123120Simp * Enable/disable transmitter. 653123120Simp */ 654123120Simpvoid cx_transmitter_ctl (cx_chan_t *c,int start) 655123120Simp{ 656123120Simp outb (CAR(c->port), c->num & 3); 657123120Simp cx_cmd (c->port, start ? CCR_ENTX : CCR_DISTX); 658123120Simp} 659123120Simp 660123120Simp/* 661123120Simp * Discard all data queued in transmitter. 662123120Simp */ 663123120Simpvoid cx_flush_transmit (cx_chan_t *c) 664123120Simp{ 665123120Simp outb (CAR(c->port), c->num & 3); 666123120Simp cx_cmd (c->port, CCR_CLRTX); 667123120Simp} 668123120Simp 669123120Simp/* 670123120Simp * Send the XON/XOFF flow control symbol. 671123120Simp */ 672123120Simpvoid cx_xflow_ctl (cx_chan_t *c, int on) 673123120Simp{ 674123120Simp outb (CAR(c->port), c->num & 3); 675123120Simp outb (STCR(c->port), STC_SNDSPC | (on ? STC_SSPC_1 : STC_SSPC_2)); 676123120Simp} 677123120Simp 678123120Simp/* 679123120Simp * Send the break signal for a given number of milliseconds. 680123120Simp */ 681123120Simpvoid cx_send_break (cx_chan_t *c, int msec) 682123120Simp{ 683123120Simp static unsigned char buf [128]; 684123120Simp unsigned char *p; 685123120Simp 686123120Simp p = buf; 687123120Simp *p++ = 0; /* extended transmit command */ 688123120Simp *p++ = 0x81; /* send break */ 689123120Simp 690123120Simp if (msec > 10000) /* max 10 seconds */ 691123120Simp msec = 10000; 692123120Simp if (msec < 10) /* min 10 msec */ 693123120Simp msec = 10; 694123120Simp while (msec > 0) { 695123120Simp int ms = 250; /* 250 msec */ 696123120Simp if (ms > msec) 697123120Simp ms = msec; 698123120Simp msec -= ms; 699123120Simp *p++ = 0; /* extended transmit command */ 700123120Simp *p++ = 0x82; /* insert delay */ 701123120Simp *p++ = ms; 702123120Simp } 703123120Simp *p++ = 0; /* extended transmit command */ 704123120Simp *p++ = 0x83; /* stop break */ 705123120Simp 706123120Simp cx_send (c, buf, p-buf, 0); 707123120Simp} 708123120Simp 709123120Simp/* 710123120Simp * Set async parameters. 711123120Simp */ 712123120Simpvoid cx_set_async_param (cx_chan_t *c, int baud, int bits, int parity, 713123120Simp int stop2, int ignpar, int rtscts, 714123120Simp int ixon, int ixany, int symstart, int symstop) 715123120Simp{ 716123120Simp int clock, period; 717123120Simp cx_cor1_async_t cor1; 718123120Simp 719123120Simp /* Set character length and parity mode. */ 720123120Simp BYTE cor1 = 0; 721123120Simp cor1.charlen = bits - 1; 722123120Simp cor1.parmode = parity ? PARM_NORMAL : PARM_NOPAR; 723123120Simp cor1.parity = parity==1 ? PAR_ODD : PAR_EVEN; 724123120Simp cor1.ignpar = ignpar ? 1 : 0; 725123120Simp 726123120Simp /* Enable/disable hardware CTS. */ 727123120Simp c->aopt.cor2.ctsae = rtscts ? 1 : 0; 728123120Simp 729123120Simp /* Enable extended transmit command mode. 730123120Simp * Unfortunately, there is no other method for sending break. */ 731123120Simp c->aopt.cor2.etc = 1; 732123120Simp 733123120Simp /* Enable/disable hardware XON/XOFF. */ 734123120Simp c->aopt.cor2.ixon = ixon ? 1 : 0; 735123120Simp c->aopt.cor2.ixany = ixany ? 1 : 0; 736123120Simp 737123120Simp /* Set the number of stop bits. */ 738123120Simp if (stop2) 739123120Simp c->aopt.cor3.stopb = STOPB_2; 740123120Simp else 741123120Simp c->aopt.cor3.stopb = STOPB_1; 742123120Simp 743123120Simp /* Disable/enable passing XON/XOFF chars to the host. */ 744123120Simp c->aopt.cor3.scde = ixon ? 1 : 0; 745123120Simp c->aopt.cor3.flowct = ixon ? FLOWCC_NOTPASS : FLOWCC_PASS; 746123120Simp 747123120Simp c->aopt.schr1 = symstart; /* XON */ 748123120Simp c->aopt.schr2 = symstop; /* XOFF */ 749123120Simp 750123120Simp /* Set current channel number. */ 751123120Simp outb (CAR(c->port), c->num & 3); 752123120Simp 753123120Simp /* Set up clock values. */ 754123120Simp if (baud) { 755123120Simp c->rxbaud = c->txbaud = baud; 756123120Simp 757123120Simp /* Receiver. */ 758123120Simp cx_clock (c->oscfreq, c->rxbaud, &clock, &period); 759123120Simp c->opt.rcor.clk = clock; 760123120Simp outb (RCOR(c->port), BYTE c->opt.rcor); 761123120Simp outb (RBPR(c->port), period); 762123120Simp 763123120Simp /* Transmitter. */ 764123120Simp cx_clock (c->oscfreq, c->txbaud, &clock, &period); 765123120Simp c->opt.tcor.clk = clock; 766123120Simp c->opt.tcor.ext1x = 0; 767123120Simp outb (TCOR(c->port), BYTE c->opt.tcor); 768123120Simp outb (TBPR(c->port), period); 769123120Simp } 770123120Simp outb (COR2(c->port), BYTE c->aopt.cor2); 771123120Simp outb (COR3(c->port), BYTE c->aopt.cor3); 772123120Simp outb (SCHR1(c->port), c->aopt.schr1); 773123120Simp outb (SCHR2(c->port), c->aopt.schr2); 774123120Simp 775123120Simp if (BYTE c->aopt.cor1 != BYTE cor1) { 776123120Simp BYTE c->aopt.cor1 = BYTE cor1; 777123120Simp outb (COR1(c->port), BYTE c->aopt.cor1); 778123120Simp /* Any change to COR1 require reinitialization. */ 779123120Simp /* Unfortunately, it may cause transmitter glitches... */ 780123120Simp cx_cmd (c->port, CCR_INITCH); 781123120Simp } 782123120Simp} 783123120Simp 784123120Simp/* 785123120Simp * Set mode: M_ASYNC or M_HDLC. 786123120Simp * Both receiver and transmitter are disabled. 787123120Simp */ 788123120Simpint cx_set_mode (cx_chan_t *c, int mode) 789123120Simp{ 790123120Simp if (mode == M_HDLC) { 791123120Simp if (c->type == T_ASYNC) 792123120Simp return -1; 793123120Simp 794123120Simp if (c->mode == M_HDLC) 795123120Simp return 0; 796123120Simp 797123120Simp c->mode = M_HDLC; 798123120Simp } else if (mode == M_ASYNC) { 799123120Simp if (c->type == T_SYNC_RS232 || 800123120Simp c->type == T_SYNC_V35 || 801123120Simp c->type == T_SYNC_RS449) 802123120Simp return -1; 803123120Simp 804123120Simp if (c->mode == M_ASYNC) 805123120Simp return 0; 806123120Simp 807123120Simp c->mode = M_ASYNC; 808123120Simp c->opt.tcor.ext1x = 0; 809123120Simp c->opt.tcor.llm = 0; 810123120Simp c->opt.rcor.dpll = 0; 811123120Simp c->opt.rcor.encod = ENCOD_NRZ; 812123120Simp if (! c->txbaud || ! c->rxbaud) 813123120Simp c->txbaud = c->rxbaud = 9600; 814123120Simp } else 815123120Simp return -1; 816123120Simp 817123120Simp cx_setup_chan (c); 818123120Simp cx_start_chan (c, 0, 0); 819123120Simp cx_enable_receive (c, 0); 820123120Simp cx_enable_transmit (c, 0); 821123120Simp return 0; 822123120Simp} 823123120Simp 824123120Simp/* 825123120Simp * Set port type for old models of Sigma 826123120Simp */ 827123120Simpvoid cx_set_port (cx_chan_t *c, int iftype) 828123120Simp{ 829123120Simp if (c->board->type == B_SIGMA_XXX) { 830123120Simp switch (c->num) { 831123120Simp case 0: 832123120Simp if ((c->board->if0type != 0) == (iftype != 0)) 833123120Simp return; 834123120Simp c->board->if0type = iftype; 835123120Simp c->board->bcr0 &= ~BCR0_UMASK; 836123120Simp if (c->board->if0type && 837123120Simp (c->type==T_UNIV_RS449 || c->type==T_UNIV_V35)) 838123120Simp c->board->bcr0 |= BCR0_UI_RS449; 839123120Simp outb (BCR0(c->board->port), c->board->bcr0); 840123120Simp break; 841123120Simp case 8: 842123120Simp if ((c->board->if8type != 0) == (iftype != 0)) 843123120Simp return; 844123120Simp c->board->if8type = iftype; 845123120Simp c->board->bcr0b &= ~BCR0_UMASK; 846123120Simp if (c->board->if8type && 847123120Simp (c->type==T_UNIV_RS449 || c->type==T_UNIV_V35)) 848123120Simp c->board->bcr0b |= BCR0_UI_RS449; 849123120Simp outb (BCR0(c->board->port+0x10), c->board->bcr0b); 850123120Simp break; 851123120Simp } 852123120Simp } 853123120Simp} 854123120Simp 855123120Simp/* 856123120Simp * Get port type for old models of Sigma 857123120Simp * -1 Fixed port type or auto detect 858123120Simp * 0 RS232 859123120Simp * 1 V35 860123120Simp * 2 RS449 861123120Simp */ 862123120Simpint cx_get_port (cx_chan_t *c) 863123120Simp{ 864123120Simp int iftype; 865123120Simp 866123120Simp if (c->board->type == B_SIGMA_XXX) { 867123120Simp switch (c->num) { 868123120Simp case 0: 869123120Simp iftype = c->board->if0type; break; 870123120Simp case 8: 871123120Simp iftype = c->board->if8type; break; 872123120Simp default: 873123120Simp return -1; 874123120Simp } 875123120Simp 876123120Simp if (iftype) 877123120Simp switch (c->type) { 878277565Skevlo case T_UNIV_V35: return 1; 879277565Skevlo case T_UNIV_RS449: return 2; 880277565Skevlo default: return -1; 881123120Simp } 882123120Simp else 883123120Simp return 0; 884123120Simp } else 885123120Simp return -1; 886123120Simp} 887123120Simp 888123120Simpvoid cx_intr_off (cx_board_t *b) 889123120Simp{ 890123120Simp outb (BCR0(b->port), b->bcr0 & ~BCR0_IRQ_MASK); 891123120Simp if (b->chan[8].port || b->chan[12].port) 892123120Simp outb (BCR0(b->port+0x10), b->bcr0b & ~BCR0_IRQ_MASK); 893123120Simp} 894123120Simp 895123120Simpvoid cx_intr_on (cx_board_t *b) 896123120Simp{ 897123120Simp outb (BCR0(b->port), b->bcr0); 898123120Simp if (b->chan[8].port || b->chan[12].port) 899123120Simp outb (BCR0(b->port+0x10), b->bcr0b); 900123120Simp} 901123120Simp 902123120Simpint cx_checkintr (cx_board_t *b) 903123120Simp{ 904123120Simp return (!(inw (BSR(b->port)) & BSR_NOINTR)); 905123120Simp} 906