cxddk.c revision 315221
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: stable/11/sys/dev/cx/cxddk.c 315221 2017-03-14 02:06:03Z pfg $");
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 */
31static 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 */
39static 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 */
58int 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 */
71int 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 */
97void 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 */
110void 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 */
195void 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 */
220void 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 */
236int 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
242int 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
248unsigned long cx_get_baud (cx_chan_t *c)
249{
250	return (c->opt.tcor.clk == CLK_EXT) ? 0 : c->txbaud;
251}
252
253int cx_get_loop (cx_chan_t *c)
254{
255	return c->opt.tcor.llm ? 1 : 0;
256}
257
258int cx_get_nrzi (cx_chan_t *c)
259{
260	return c->opt.rcor.encod == ENCOD_NRZI;
261}
262
263int cx_get_dpll (cx_chan_t *c)
264{
265	return c->opt.rcor.dpll ? 1 : 0;
266}
267
268void 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
317void 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
326void 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
335void 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
342static 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 */
404int 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 */
413int 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
430static 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
548static 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
586void 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 */
625void 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
631void 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
637void cx_register_modem (cx_chan_t *c, void (*func) (cx_chan_t *c))
638{
639	c->call_on_msig = func;
640}
641
642void 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 */
654void 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 */
663void 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 */
672void 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 */
681void 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 */
712void 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 */
788int 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 */
827void 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 */
862int 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
888void 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
895void 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
902int cx_checkintr (cx_board_t *b)
903{
904	return (!(inw (BSR(b->port)) & BSR_NOINTR));
905}
906