xref: /freebsd-12.1/sys/dev/cx/cxddk.c (revision ab9ed8a1)
1 /*-
2  * Cronyx-Sigma Driver Development Kit.
3  *
4  * Copyright (C) 1998 Cronyx Engineering.
5  * Author: Pavel Novikov, <[email protected]>
6  *
7  * Copyright (C) 1998-2003 Cronyx Engineering.
8  * Author: Roman Kurakin, <[email protected]>
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  */
cx_compute_buf_len(cx_chan_t * c)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  */
cx_find(port_t * board_ports)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  */
cx_open_board(cx_board_t * b,int num,port_t port,int irq,int dma)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  */
cx_close_board(cx_board_t * b)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  */
cx_start_chan(cx_chan_t * c,cx_buf_t * cb,unsigned long phys)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  */
cx_enable_receive(cx_chan_t * c,int on)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  */
cx_enable_transmit(cx_chan_t * c,int on)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  */
cx_receive_enabled(cx_chan_t * c)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 
cx_transmit_enabled(cx_chan_t * c)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 
cx_get_baud(cx_chan_t * c)248 unsigned long cx_get_baud (cx_chan_t *c)
249 {
250 	return (c->opt.tcor.clk == CLK_EXT) ? 0 : c->txbaud;
251 }
252 
cx_get_loop(cx_chan_t * c)253 int cx_get_loop (cx_chan_t *c)
254 {
255 	return c->opt.tcor.llm ? 1 : 0;
256 }
257 
cx_get_nrzi(cx_chan_t * c)258 int cx_get_nrzi (cx_chan_t *c)
259 {
260 	return c->opt.rcor.encod == ENCOD_NRZI;
261 }
262 
cx_get_dpll(cx_chan_t * c)263 int cx_get_dpll (cx_chan_t *c)
264 {
265 	return c->opt.rcor.dpll ? 1 : 0;
266 }
267 
cx_set_baud(cx_chan_t * c,unsigned long bps)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 
cx_set_loop(cx_chan_t * c,int on)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 
cx_set_dpll(cx_chan_t * c,int on)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 
cx_set_nrzi(cx_chan_t * c,int nrzi)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 
cx_send(cx_chan_t * c,char * data,int len,void * attachment)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  */
cx_buf_free(cx_chan_t * c)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  */
cx_send_packet(cx_chan_t * c,char * data,int len,void * attachment)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 
cx_receive_interrupt(cx_chan_t * c)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 
cx_transmit_interrupt(cx_chan_t * c)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 
cx_int_handler(cx_board_t * b)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  */
cx_register_transmit(cx_chan_t * c,void (* func)(cx_chan_t * c,void * attachment,int len))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 
cx_register_receive(cx_chan_t * c,void (* func)(cx_chan_t * c,char * data,int len))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 
cx_register_modem(cx_chan_t * c,void (* func)(cx_chan_t * c))637 void cx_register_modem (cx_chan_t *c, void (*func) (cx_chan_t *c))
638 {
639 	c->call_on_msig = func;
640 }
641 
cx_register_error(cx_chan_t * c,void (* func)(cx_chan_t * c,int data))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  */
cx_transmitter_ctl(cx_chan_t * c,int start)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  */
cx_flush_transmit(cx_chan_t * c)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  */
cx_xflow_ctl(cx_chan_t * c,int on)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  */
cx_send_break(cx_chan_t * c,int msec)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  */
cx_set_async_param(cx_chan_t * c,int baud,int bits,int parity,int stop2,int ignpar,int rtscts,int ixon,int ixany,int symstart,int symstop)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  */
cx_set_mode(cx_chan_t * c,int mode)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  */
cx_set_port(cx_chan_t * c,int iftype)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  */
cx_get_port(cx_chan_t * c)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 
cx_intr_off(cx_board_t * b)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 
cx_intr_on(cx_board_t * b)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 
cx_checkintr(cx_board_t * b)902 int cx_checkintr (cx_board_t *b)
903 {
904 	return (!(inw (BSR(b->port)) & BSR_NOINTR));
905 }
906