]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/cx/cxddk.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / 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 transmiter 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 = 0;
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; break;
879                         case T_UNIV_RS449: return 2; break;
880                         default:           return -1; break;
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 }