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