FreeBSD/Linux Kernel Cross Reference
sys/dev/cx/cxddk.c
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
|