1139749Simp/*-
2126177Srik * DDK library for Cronyx-Tau adapters.
3126177Srik *
4126177Srik * Copyright (C) 1998-1999 Cronyx Engineering.
5126177Srik * Author: Alexander Kvitchenko, <aak@cronyx.ru>
6126177Srik *
7126177Srik * Copyright (C) 1999-2003 Cronyx Engineering.
8126177Srik * Author: Roman Kurakin, <rik@cronyx.ru>
9126177Srik *
10126177Srik * This source is derived from
11126177Srik * Diagnose utility for Cronyx-Tau adapter:
12126177Srik * by Serge Vakulenko, <vak@cronyx.ru>
13126177Srik *
14126177Srik * This software is distributed with NO WARRANTIES, not even the implied
15126177Srik * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16126177Srik *
17126177Srik * Authors grant any other persons or organisations permission to use
18126177Srik * or modify this software as long as this message is kept with the software,
19126177Srik * all derivative works or modified versions.
20126177Srik *
21126177Srik * Cronyx Id: ctddk.c,v 1.1.2.3 2003/11/14 16:55:36 rik Exp $
22126177Srik */
23126177Srik#include <sys/cdefs.h>
24126177Srik__FBSDID("$FreeBSD$");
25126177Srik
26126177Srik#include <dev/cx/machdep.h>
27126177Srik#include <dev/ctau/ctddk.h>
28126177Srik#include <dev/ctau/ctaureg.h>
29126177Srik#include <dev/ctau/hdc64570.h>
30126177Srik#include <dev/ctau/ds2153.h>
31126177Srik#include <dev/ctau/am8530.h>
32126177Srik#include <dev/ctau/lxt318.h>
33126177Srik#include <dev/cx/cronyxfw.h>
34126177Srik#include <dev/ctau/ctaufw.h>
35126177Srik#include <dev/ctau/ctau2fw.h>
36126177Srik
37126177Srik#ifndef CT_DDK_NO_G703
38126177Srik#include <dev/ctau/ctaug7fw.h>
39126177Srik#endif
40126177Srik
41126177Srik#ifndef CT_DDK_NO_E1
42126177Srik#include <dev/ctau/ctaue1fw.h>
43126177Srik#endif
44126177Srik
45126177Srikstatic void ct_hdlc_interrupt (ct_chan_t *c, int imvr);
46126177Srikstatic void ct_e1_interrupt (ct_board_t *b);
47126177Srikstatic void ct_scc_interrupt (ct_board_t *b);
48126177Srikstatic void ct_e1timer_interrupt (ct_chan_t *c);
49126177Srik
50126177Srikstatic short porttab [] = {	       /* standard base port set */
51126177Srik	0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
52126177Srik	0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
53126177Srik};
54126177Srik
55126177Srikint ct_find (port_t *board_ports)
56126177Srik{
57126177Srik	int i, n;
58126177Srik
59126177Srik	for (i=0, n=0; porttab[i] && n<NBRD; i++)
60126177Srik		if (ct_probe_board (porttab[i], -1, -1))
61126177Srik			board_ports[n++] = porttab[i];
62126177Srik	return n;
63126177Srik}
64126177Srik
65126177Srikint ct_open_board (ct_board_t *b, int num, port_t port, int irq, int dma)
66126177Srik{
67126177Srik	ct_chan_t *c;
68126177Srik	const unsigned char *fw;
69126177Srik	const cr_dat_tst_t *ft;
70126177Srik	long flen;
71126177Srik
72126177Srik	if (num >= NBRD || ! ct_probe_board (port, irq, dma))
73126177Srik		return 0;
74126177Srik
75126177Srik	/* init callback pointers */
76126177Srik	for (c=b->chan; c<b->chan+NCHAN; ++c) {
77126177Srik		c->call_on_tx = 0;
78126177Srik		c->call_on_rx = 0;
79126177Srik		c->call_on_msig = 0;
80126177Srik		c->call_on_scc = 0;
81126177Srik		c->call_on_err = 0;
82126177Srik	}
83126177Srik
84126177Srik	/* init DDK channel variables */
85126177Srik	for (c=b->chan; c<b->chan+NCHAN; ++c) {
86126177Srik		c->sccrx_empty = c->scctx_empty = 1;
87126177Srik		c->sccrx_b = c->sccrx_e = 0;
88126177Srik		c->scctx_b = c->scctx_e = 0;
89126177Srik		c->e1_first_int = 1;
90126177Srik	}
91126177Srik
92126177Srik	/* init board structure */
93126177Srik	ct_init (b, num, port, irq, dma, ctau_fw_data,
94126177Srik		ctau_fw_len, ctau_fw_tvec, ctau2_fw_data);
95126177Srik
96126177Srik	/* determine which firmware should be loaded */
97126177Srik	fw = ctau_fw_data;
98126177Srik	flen = ctau_fw_len;
99126177Srik	ft = ctau_fw_tvec;
100126177Srik	switch (b->type) {
101126177Srik	case B_TAU2:
102126177Srik	case B_TAU2_G703:
103126177Srik	case B_TAU2_E1:
104126177Srik	case B_TAU2_E1D:
105126177Srik		fw = ctau2_fw_data;
106126177Srik		flen = 0;
107126177Srik		ft = 0;
108126177Srik		break;
109126177Srik#ifndef CT_DDK_NO_G703
110126177Srik	case B_TAU_G703:
111126177Srik		fw = ctaug703_fw_data;
112126177Srik		flen = ctaug703_fw_len;
113126177Srik		ft = ctaug703_fw_tvec;
114126177Srik		break;
115126177Srik#endif
116126177Srik#ifndef CT_DDK_NO_E1
117126177Srik	case B_TAU_E1:
118126177Srik		fw = ctaue1_fw_data;
119126177Srik		flen = ctaue1_fw_len;
120126177Srik		ft = ctaue1_fw_tvec;
121126177Srik		break;
122126177Srik#endif
123126177Srik	}
124126177Srik	/* Load firmware and set up board */
125126177Srik	return ct_setup_board (b, fw, flen, ft);
126126177Srik}
127126177Srik
128126177Srik/*
129126177Srik * must be called on the exit
130126177Srik */
131126177Srikvoid ct_close_board (ct_board_t *b)
132126177Srik{
133126177Srik	ct_setup_board (b, 0, 0, 0);
134126177Srik
135126177Srik	/* Reset the controller. */
136126177Srik	outb (BCR0(b->port), 0);
137126177Srik
138126177Srik	/* Disable DMA channel. */
139126177Srik	ct_disable_dma (b);
140126177Srik
141126177Srik	ct_led (b, 0);
142126177Srik}
143126177Srik
144126177Srikstatic void ct_g703_rate (ct_chan_t *c, unsigned long rate)
145126177Srik{
146126177Srik	c->gopt.rate = rate;
147126177Srik	ct_setup_g703 (c->board);
148126177Srik}
149126177Srik
150126177Srik/*
151126177Srik * Set up baud rate.
152126177Srik */
153126177Srikstatic void ct_chan_baud (ct_chan_t *c, unsigned long baud)
154126177Srik{
155126177Srik	c->baud = baud;
156126177Srik	if (baud) {
157126177Srik		c->hopt.txs = CLK_INT;
158126177Srik	} else {
159126177Srik		ct_set_dpll (c, 0);
160126177Srik		c->hopt.txs = CLK_LINE;
161126177Srik	}
162126177Srik	ct_update_chan (c);
163126177Srik}
164126177Srik
165126177Srikvoid ct_set_baud (ct_chan_t *c, unsigned long baud)
166126177Srik{
167126177Srik	unsigned long r;
168126177Srik
169126177Srik	if (c->mode == M_E1)
170126177Srik		return;
171126177Srik	if (c->mode == M_G703) {
172126177Srik		if	(baud >= 2048000)  r = 2048;
173126177Srik		else if (baud >= 1024000)  r = 1024;
174126177Srik		else if (baud >= 512000)   r = 512;
175126177Srik		else if (baud >= 256000)   r = 256;
176126177Srik		else if (baud >= 128000)   r = 128;
177126177Srik		else			   r = 64;
178126177Srik		ct_g703_rate (c, r);
179126177Srik	} else
180126177Srik		ct_chan_baud (c, baud);
181126177Srik}
182126177Srik
183126177Srik/*
184126177Srik * Configure Tau/E1 board.
185126177Srik */
186126177Srikstatic void ct_e1_config (ct_board_t *b, unsigned char cfg)
187126177Srik{
188126177Srik	if (cfg == b->opt.cfg)
189126177Srik		return;
190126177Srik
191126177Srik	if (cfg == CFG_B)
192126177Srik		b->chan[1].mode = M_HDLC;
193126177Srik	else
194126177Srik		b->chan[1].mode = M_E1;
195126177Srik
196126177Srik	/* Recovering synchronization */
197126177Srik	if (b->opt.cfg == CFG_B) {
198126177Srik		ct_chan_baud (b->chan+1, 0);
199126177Srik		ct_set_invtxc (b->chan+1, 0);
200126177Srik		ct_set_invrxc (b->chan+1, 0);
201126177Srik		ct_set_nrzi (b->chan+1, 0);
202126177Srik	}
203126177Srik	b->opt.cfg = cfg;
204126177Srik	ct_setup_e1 (b);
205126177Srik}
206126177Srik
207126177Srik/*
208126177Srik * Config Tau/G.703 board
209126177Srik */
210126177Srikstatic void ct_g703_config (ct_board_t *b, unsigned char cfg)
211126177Srik{
212126177Srik	if (cfg == b->opt.cfg)
213126177Srik		return;
214126177Srik
215126177Srik	if (cfg == CFG_B)
216126177Srik		b->chan[1].mode = M_HDLC;
217126177Srik	else
218126177Srik		b->chan[1].mode = M_G703;
219126177Srik
220126177Srik	/* Recovering synchronization */
221126177Srik	if (b->opt.cfg == CFG_B) {
222126177Srik		ct_chan_baud (b->chan+1, 0);
223126177Srik		ct_set_invtxc (b->chan+1, 0);
224126177Srik		ct_set_invrxc (b->chan+1, 0);
225126177Srik		ct_set_nrzi (b->chan+1, 0);
226126177Srik	}
227126177Srik	b->opt.cfg = cfg;
228126177Srik	ct_setup_g703 (b);
229126177Srik}
230126177Srik
231126177Srikint ct_set_clk (ct_chan_t *c, int clk)
232126177Srik{
233126177Srik	if (c->num)
234126177Srik		c->board->opt.clk1 = clk;
235126177Srik	else
236126177Srik		c->board->opt.clk0 = clk;
237126177Srik	if (c->mode == M_E1) {
238126177Srik		ct_setup_e1 (c->board);
239126177Srik		return 0;
240126177Srik	} if (c->mode == M_G703) {
241126177Srik		ct_setup_g703 (c->board);
242126177Srik		return 0;
243126177Srik	} else
244126177Srik		return -1;
245126177Srik}
246126177Srik
247126177Srikint ct_get_clk (ct_chan_t *c)
248126177Srik{
249126177Srik	return c->num ? c->board->opt.clk1 : c->board->opt.clk0;
250126177Srik}
251126177Srik
252126177Srikint ct_set_ts (ct_chan_t *c, unsigned long ts)
253126177Srik{
254126177Srik	if (! (c->mode == M_E1))
255126177Srik		return -1;
256126177Srik	if (c->num)
257126177Srik		c->board->opt.s1 = ts;
258126177Srik	else
259126177Srik		c->board->opt.s0 = ts;
260126177Srik	ct_setup_e1 (c->board);
261126177Srik	return 0;
262126177Srik}
263126177Srik
264126177Srikint ct_set_subchan (ct_board_t *b, unsigned long ts)
265126177Srik{
266126177Srik	if (b->chan[0].mode != M_E1)
267126177Srik		return -1;
268126177Srik	b->opt.s2 = ts;
269126177Srik	ct_setup_e1 (b);
270126177Srik	return 0;
271126177Srik}
272126177Srik
273126177Srikint ct_set_higain (ct_chan_t *c, int on)
274126177Srik{
275126177Srik	if (! (c->mode == M_E1))
276126177Srik		return -1;
277126177Srik	c->gopt.higain = on ? 1 : 0;
278126177Srik	ct_setup_e1 (c->board);
279126177Srik	return 0;
280126177Srik}
281126177Srik
282126177Srik/*
283126177Srik * Start service channel.
284126177Srik */
285126177Srikvoid ct_start_scc (ct_chan_t *c, char *rxbuf, char *txbuf)
286126177Srik{
287126177Srik	c->sccrx = rxbuf;
288126177Srik	c->scctx = txbuf;
289126177Srik
290126177Srik	/* Enable interrupts from service channel. */
291126177Srik	if (c->board->type != B_TAU_E1 && c->board->type != B_TAU_E1C &&
292126177Srik	    c->board->type != B_TAU2_E1)
293126177Srik		return;
294126177Srik
295126177Srik	cte_out2 (c->board->port, c->num ? AM_IMR : AM_IMR | AM_A,
296126177Srik		 IMR_TX | IMR_RX_ALL);
297126177Srik	cte_out2 (c->board->port, AM_MICR, MICR_MIE);
298126177Srik}
299126177Srik
300126177Srik/*
301126177Srik * Start HDLC channel.
302126177Srik */
303126177Srikvoid ct_start_chan (ct_chan_t *c, ct_buf_t *cb, unsigned long phys)
304126177Srik{
305126177Srik	int i, ier0;
306126177Srik	unsigned long bound;
307126177Srik
308126177Srik	if (cb) {
309126177Srik		/* Set up descriptors, align to 64k boundary.
310126177Srik		 * If 64k boundary is inside buffers
311126177Srik		 * buffers will begin on this boundary
312126177Srik		 * (there were allocated additional space for this) */
313126177Srik		c->tdesc = cb->descbuf;
314126177Srik		c->tdphys[0] = phys + ((char*)c->tdesc - (char*)cb);
315126177Srik		bound = ((c->tdphys[0] + 0xffff) & ~(0xffffUL));
316126177Srik		if (bound < c->tdphys[0] + 2*NBUF*sizeof(ct_desc_t)) {
317126177Srik			c->tdesc = (ct_desc_t*) ((char*) c->tdesc +
318126177Srik				(bound - c->tdphys[0]));
319126177Srik			c->tdphys[0] = bound;
320126177Srik		}
321126177Srik		c->rdesc = c->tdesc + NBUF;
322126177Srik
323126177Srik		/* Set buffers. */
324126177Srik		for (i=0; i<NBUF; ++i) {
325126177Srik			c->rbuf[i] = cb->rbuffer[i];
326126177Srik			c->tbuf[i] = cb->tbuffer[i];
327126177Srik		}
328126177Srik
329126177Srik		/* Set buffer physical addresses */
330126177Srik		for (i=0; i<NBUF; ++i) {
331126177Srik			c->rphys[i] = phys + ((char*)c->rbuf[i] - (char*)cb);
332126177Srik			c->tphys[i] = phys + ((char*)c->tbuf[i] - (char*)cb);
333126177Srik			c->rdphys[i] = phys + ((char*)(c->rdesc+i) - (char*)cb);
334126177Srik			c->tdphys[i] = phys + ((char*)(c->tdesc+i) - (char*)cb);
335126177Srik		}
336126177Srik	}
337126177Srik	/* Set up block chains. */
338126177Srik	/* receive buffers */
339126177Srik	for (i=0; i<NBUF; ++i) {
340126177Srik		B_NEXT (c->rdesc[i]) = c->rdphys[(i+1) % NBUF] & 0xffff;
341126177Srik		B_PTR (c->rdesc[i]) = c->rphys[i];
342126177Srik		B_LEN (c->rdesc[i]) = DMABUFSZ;
343126177Srik		B_STATUS (c->rdesc[i]) = 0;
344126177Srik	}
345126177Srik	/* transmit buffers */
346126177Srik	for (i=0; i<NBUF; ++i) {
347126177Srik		B_NEXT (c->tdesc[i]) = c->tdphys[(i+1) % NBUF] & 0xffff;
348126177Srik		B_PTR (c->tdesc[i]) = c->tphys[i];
349126177Srik		B_LEN (c->tdesc[i]) = DMABUFSZ;
350126177Srik		B_STATUS (c->tdesc[i]) = FST_EOM;
351126177Srik		c->attach[i] = 0;
352126177Srik	}
353126177Srik
354126177Srik	if (c->type & T_E1) {
355126177Srik		c->mode = M_E1;
356126177Srik		if (c->num && c->board->opt.cfg == CFG_B)
357126177Srik			c->mode = M_HDLC;
358126177Srik	}
359126177Srik	if (c->type & T_G703) {
360126177Srik		c->mode = M_G703;
361126177Srik		if (c->num && c->board->opt.cfg == CFG_B)
362126177Srik			c->mode = M_HDLC;
363126177Srik	}
364126177Srik	ct_update_chan (c);
365126177Srik
366126177Srik	/* enable receiver */
367126177Srik	c->rn = 0;
368126177Srik	ct_start_receiver (c, 1 , c->rphys[0], DMABUFSZ, c->rdphys[0],
369126177Srik		c->rdphys[NBUF-1]);
370126177Srik	outb (c->IE1, inb (c->IE1) | IE1_CDCDE);
371126177Srik	outb (c->IE0, inb (c->IE0) | IE0_RX_INTE);
372126177Srik	ier0 = inb (IER0(c->board->port));
373126177Srik	ier0 |= c->num ? IER0_RX_INTE_1 : IER0_RX_INTE_0;
374126177Srik	outb (IER0(c->board->port), ier0);
375126177Srik
376126177Srik	/* Enable transmitter */
377126177Srik	c->tn = 0;
378126177Srik	c->te = 0;
379126177Srik	ct_start_transmitter (c, 1 , c->tphys[0], DMABUFSZ, c->tdphys[0],
380126177Srik		c->tdphys[0]);
381126177Srik	outb (c->TX.DIR, DIR_CHAIN_EOME | DIR_CHAIN_BOFE | DIR_CHAIN_COFE);
382126177Srik
383126177Srik	/* Clear DTR and RTS */
384126177Srik	ct_set_dtr (c, 0);
385126177Srik	ct_set_rts (c, 0);
386126177Srik}
387126177Srik
388126177Srik/*
389126177Srik * Turn receiver on/off
390126177Srik */
391126177Srikvoid ct_enable_receive (ct_chan_t *c, int on)
392126177Srik{
393126177Srik	unsigned char st3, ier0, ier1;
394126177Srik
395126177Srik	st3 = inb (c->ST3);
396126177Srik	/* enable or disable receiver */
397126177Srik	if (on && ! (st3 & ST3_RX_ENABLED)) {
398126177Srik		c->rn = 0;
399126177Srik		ct_start_receiver (c, 1 , c->rphys[0], DMABUFSZ, c->rdphys[0],
400126177Srik			c->rdphys[NBUF-1]);
401126177Srik		/* enable status interrupt */
402126177Srik		outb (c->IE1, inb (c->IE1) | IE1_CDCDE);
403126177Srik		outb (c->IE0, inb (c->IE0) | IE0_RX_INTE);
404126177Srik		ier0 = inb (IER0(c->board->port));
405126177Srik		ier0 |= c->num ? IER0_RX_INTE_1 : IER0_RX_INTE_0;
406126177Srik		outb (IER0(c->board->port), ier0);
407126177Srik		ct_set_rts (c, 1);
408126177Srik	} else if (! on && (st3 & ST3_RX_ENABLED)) {
409126177Srik		ct_set_rts (c, 0);
410126177Srik		outb (c->CMD, CMD_RX_DISABLE);
411126177Srik
412126177Srik		ier0 = inb (IER0(c->board->port));
413126177Srik		ier0 &= c->num ? ~(IER0_RX_INTE_1 | IER0_RX_RDYE_1) :
414126177Srik			~(IER0_RX_INTE_0 | IER0_RX_RDYE_0);
415126177Srik		outb (IER0(c->board->port), ier0);
416126177Srik
417126177Srik		ier1 = inb (IER1(c->board->port));
418126177Srik		ier1 &= c->num ? ~(IER1_RX_DMERE_1 | IER1_RX_DME_1) :
419126177Srik			~(IER1_RX_DMERE_0 | IER1_RX_DME_0);
420126177Srik		outb (IER1(c->board->port), ier1);
421126177Srik	}
422126177Srik
423126177Srik}
424126177Srik
425126177Srik/*
426126177Srik * Turn transmitter on/off
427126177Srik */
428126177Srikvoid ct_enable_transmit (ct_chan_t *c, int on)
429126177Srik{
430126177Srik	unsigned char st3, ier0, ier1;
431126177Srik
432126177Srik	st3 = inb (c->ST3);
433126177Srik	/* enable or disable receiver */
434126177Srik	if (on && ! (st3 & ST3_TX_ENABLED)) {
435126177Srik		c->tn = 0;
436126177Srik		c->te = 0;
437126177Srik		ct_start_transmitter (c, 1 , c->tphys[0], DMABUFSZ,
438126177Srik			c->tdphys[0], c->tdphys[0]);
439126177Srik		outb (c->TX.DIR,
440126177Srik			DIR_CHAIN_EOME | DIR_CHAIN_BOFE | DIR_CHAIN_COFE);
441126177Srik	} else if (! on && (st3 & ST3_TX_ENABLED)) {
442126177Srik		outb (c->CMD, CMD_TX_DISABLE);
443126177Srik
444126177Srik		ier0 = inb (IER0(c->board->port));
445126177Srik		ier0 &= c->num ? ~(IER0_TX_INTE_1 | IER0_TX_RDYE_1) :
446126177Srik			~(IER0_TX_INTE_0 | IER0_TX_RDYE_0);
447126177Srik		outb (IER0(c->board->port), ier0);
448126177Srik
449126177Srik		ier1 = inb (IER1(c->board->port));
450126177Srik		ier1 &= c->num ? ~(IER1_TX_DMERE_1 | IER1_TX_DME_1) :
451126177Srik			~(IER1_TX_DMERE_0 | IER1_TX_DME_0);
452126177Srik		outb (IER1(c->board->port), ier1);
453126177Srik	}
454126177Srik
455126177Srik}
456126177Srik
457126177Srikint ct_set_config (ct_board_t *b, int cfg)
458126177Srik{
459126177Srik	if (b->opt.cfg == cfg)
460126177Srik		return 0;
461126177Srik	switch (b->type) {
462126177Srik	case B_TAU_G703:
463126177Srik	case B_TAU_G703C:
464126177Srik	case B_TAU2_G703:
465126177Srik		if (cfg == CFG_C)
466126177Srik			return -1;
467126177Srik		ct_g703_config (b, cfg);
468126177Srik		return 0;
469126177Srik	case B_TAU_E1:
470126177Srik	case B_TAU_E1C:
471126177Srik	case B_TAU_E1D:
472126177Srik	case B_TAU2_E1:
473126177Srik	case B_TAU2_E1D:
474126177Srik		ct_e1_config (b, cfg);
475126177Srik		return 0;
476126177Srik	default:
477126177Srik		return cfg == CFG_A ? 0 : -1;
478126177Srik	}
479126177Srik}
480126177Srik
481126177Srikint ct_get_dpll (ct_chan_t *c)
482126177Srik{
483126177Srik	return (c->hopt.rxs == CLK_RXS_DPLL_INT);
484126177Srik}
485126177Srik
486126177Srikvoid ct_set_dpll (ct_chan_t *c, int on)
487126177Srik{
488126177Srik	if (on && ct_get_baud (c))
489126177Srik		c->hopt.rxs = CLK_RXS_DPLL_INT;
490126177Srik	else
491126177Srik		c->hopt.rxs = CLK_LINE;
492126177Srik	ct_update_chan (c);
493126177Srik}
494126177Srik
495126177Srikint ct_get_nrzi (ct_chan_t *c)
496126177Srik{
497126177Srik	return (c->opt.md2.encod == MD2_ENCOD_NRZI);
498126177Srik}
499126177Srik
500126177Srik/*
501126177Srik * Change line encoding to NRZI, default is NRZ
502126177Srik */
503126177Srikvoid ct_set_nrzi (ct_chan_t *c, int on)
504126177Srik{
505126177Srik	c->opt.md2.encod = on ? MD2_ENCOD_NRZI : MD2_ENCOD_NRZ;
506126177Srik	outb (c->MD2, *(unsigned char*)&c->opt.md2);
507126177Srik}
508126177Srik
509126177Srik/*
510126177Srik * Transmit clock inversion
511126177Srik */
512126177Srikvoid ct_set_invtxc (ct_chan_t *c, int on)
513126177Srik{
514126177Srik	if (on) c->board->bcr2 |=  (c->num ? BCR2_INVTXC1 : BCR2_INVTXC0);
515126177Srik	else	c->board->bcr2 &= ~(c->num ? BCR2_INVTXC1 : BCR2_INVTXC0);
516126177Srik	outb (BCR2(c->board->port), c->board->bcr2);
517126177Srik}
518126177Srik
519126177Srikint ct_get_invtxc (ct_chan_t *c)
520126177Srik{
521126177Srik	return (c->board->bcr2 & (c->num ? BCR2_INVTXC1 : BCR2_INVTXC0)) != 0;
522126177Srik}
523126177Srik
524126177Srik/*
525126177Srik * Receive clock inversion
526126177Srik */
527126177Srikvoid ct_set_invrxc (ct_chan_t *c, int on)
528126177Srik{
529126177Srik	if (on) c->board->bcr2 |=  (c->num ? BCR2_INVRXC1 : BCR2_INVRXC0);
530126177Srik	else	c->board->bcr2 &= ~(c->num ? BCR2_INVRXC1 : BCR2_INVRXC0);
531126177Srik	outb (BCR2(c->board->port), c->board->bcr2);
532126177Srik}
533126177Srik
534126177Srikint ct_get_invrxc (ct_chan_t *c)
535126177Srik{
536126177Srik	return (c->board->bcr2 & (c->num ? BCR2_INVRXC1 : BCR2_INVRXC0)) != 0;
537126177Srik}
538126177Srik
539126177Srik/*
540126177Srik * Main interrupt handler
541126177Srik */
542126177Srikvoid ct_int_handler (ct_board_t *b)
543126177Srik{
544126177Srik	unsigned char bsr0, imvr;
545126177Srik	ct_chan_t *c;
546126177Srik
547126177Srik	while ((bsr0 = inb (BSR0(b->port))) & BSR0_INTR) {
548126177Srik		if (bsr0 & BSR0_RDYERR) {
549126177Srik			outb (BCR1(b->port), b->bcr1);
550126177Srik		} else if (bsr0 & BSR0_GINT) {
551126177Srik			if (b->type == B_TAU_E1 || b->type == B_TAU_E1C ||
552126177Srik			    b->type == B_TAU_E1D || b->type == B_TAU2_E1 ||
553126177Srik			    b->type == B_TAU2_E1D)
554126177Srik				ct_e1_interrupt (b);
555126177Srik		} else if (bsr0 & BSR0_HDINT) {
556126177Srik			/* Read the interrupt modified vector register. */
557126177Srik			imvr = inb (IACK(b->port));
558126177Srik			c = b->chan + (imvr & IMVR_CHAN1 ? 1 : 0);
559126177Srik			ct_hdlc_interrupt (c, imvr);
560126177Srik		}
561126177Srik	}
562126177Srik}
563126177Srik
564126177Srikstatic void ct_e1_interrupt (ct_board_t *b)
565126177Srik{
566126177Srik	unsigned char sr;
567126177Srik
568126177Srik	sr = inb (E1SR(b->port));
569126177Srik
570126177Srik	if (sr & E1SR_SCC_IRQ) ct_scc_interrupt (b);
571126177Srik	if (sr & E1SR_E0_IRQ1) ct_e1timer_interrupt (b->chan + 0);
572126177Srik	if (sr & E1SR_E1_IRQ1) ct_e1timer_interrupt (b->chan + 1);
573126177Srik}
574126177Srik
575126177Srikstatic void ct_scc_interrupt (ct_board_t *b)
576126177Srik{
577126177Srik	unsigned char rsr;
578126177Srik	unsigned char ivr, a = AM_A;		/* assume channel A */
579126177Srik	ct_chan_t *c = b->chan;
580126177Srik
581126177Srik	ivr = cte_in2 (b->port, AM_IVR);
582126177Srik	if (! (ivr & IVR_A))
583126177Srik		++c, a = 0;			/* really channel B */
584126177Srik
585126177Srik	switch (ivr & IVR_REASON) {
586126177Srik	case IVR_TXRDY: 			/* transmitter empty */
587126177Srik		c->scctx_b = (c->scctx_b + 1) % SCCBUFSZ;
588126177Srik		if (c->scctx_b == c->scctx_e) {
589126177Srik			c->scctx_empty = 1;
590126177Srik			cte_out2c (c, AM_CR | CR_RST_TXINT);
591126177Srik		} else
592126177Srik			cte_out2d (c, c->scctx[c->scctx_b]);
593126177Srik		break;
594126177Srik
595126177Srik	case IVR_RXERR: 		/* receive error */
596126177Srik	case IVR_RX:			/* receive character available */
597126177Srik		rsr = cte_in2 (b->port, a|AM_RSR);
598126177Srik
599126177Srik		if (rsr & RSR_RXOVRN) { 	/* rx overrun */
600126177Srik			if (c->call_on_err)
601126177Srik				c->call_on_err (c, CT_SCC_OVERRUN);
602126177Srik		} else if (rsr & RSR_FRME) {	/* frame error */
603126177Srik			if (c->call_on_err)
604126177Srik				c->call_on_err (c, CT_SCC_FRAME);
605126177Srik		} else {
606126177Srik			c->sccrx[c->sccrx_e] = cte_in2d (c);
607126177Srik			c->sccrx_e = (c->sccrx_e + 1) % SCCBUFSZ;
608126177Srik			c->sccrx_empty &= 0;
609126177Srik			if (c->call_on_scc)
610126177Srik				c->call_on_scc (c);
611126177Srik			if (c->sccrx_e == c->sccrx_b && ! c->sccrx_empty)
612126177Srik				if (c->call_on_err)
613126177Srik					c->call_on_err (c, CT_SCC_OVERFLOW);
614126177Srik		}
615126177Srik		if (rsr)
616126177Srik			cte_out2c (c, CR_RST_ERROR);
617126177Srik		break;
618126177Srik
619126177Srik	case IVR_STATUS:		/* external status interrupt */
620126177Srik		/* Unexpected SCC status interrupt. */
621126177Srik		cte_out2c (c, CR_RST_EXTINT);
622126177Srik		break;
623126177Srik	}
624126177Srik}
625126177Srik
626126177Srik/*
627126177Srik * G.703 mode channel: process 1-second timer interrupts.
628126177Srik * Read error and request registers, and fill the status field.
629126177Srik */
630126177Srikvoid ct_g703_timer (ct_chan_t *c)
631126177Srik{
632126177Srik	int bpv, cd, tsterr, tstreq;
633126177Srik
634126177Srik	/* Count seconds.
635126177Srik	 * During the first second after the channel startup
636126177Srik	 * the status registers are not stable yet,
637126177Srik	 * we will so skip the first second. */
638126177Srik	++c->cursec;
639126177Srik	if (c->mode != M_G703)
640126177Srik		return;
641126177Srik	if (c->totsec + c->cursec <= 1)
642126177Srik		return;
643126177Srik	c->status = 0;
644126177Srik
645126177Srik	cd = ct_get_cd (c);
646126177Srik
647126177Srik	bpv = inb (GERR (c->board->port)) & (c->num ? GERR_BPV1 : GERR_BPV0);
648126177Srik	outb (GERR (c->board->port), bpv);
649126177Srik
650126177Srik	tsterr = inb (GERR (c->board->port)) & (c->num ? GERR_ERR1 : GERR_ERR0);
651126177Srik	outb (GERR (c->board->port), tsterr);
652126177Srik
653126177Srik	tstreq = inb (GLDR (c->board->port)) &
654126177Srik		(c->num ? GLDR_LREQ1 : GLDR_LREQ0);
655126177Srik	outb (GLDR (c->board->port), tstreq);
656126177Srik
657126177Srik	/* Compute the SNMP-compatible channel status. */
658126177Srik	if (bpv)
659126177Srik		++c->currnt.bpv;	  /* bipolar violation */
660126177Srik	if (! cd)
661126177Srik		c->status |= ESTS_LOS;	  /* loss of signal */
662126177Srik	if (tsterr)
663126177Srik		c->status |= ESTS_TSTERR; /* test error */
664126177Srik	if (tstreq)
665126177Srik		c->status |= ESTS_TSTREQ; /* test code detected */
666126177Srik
667126177Srik	if (! c->status)
668126177Srik		c->status = ESTS_NOALARM;
669126177Srik
670126177Srik	/* Unavaiable second -- loss of carrier, or receiving test code. */
671126177Srik	if ((! cd) || tstreq)
672126177Srik		/* Unavailable second -- no other counters. */
673126177Srik		++c->currnt.uas;
674126177Srik	else {
675126177Srik		/* Line errored second -- any BPV. */
676126177Srik		if (bpv)
677126177Srik			++c->currnt.les;
678126177Srik
679126177Srik		/* Collect data for computing
680126177Srik		 * degraded minutes. */
681126177Srik		++c->degsec;
682126177Srik		if (cd && bpv)
683126177Srik			++c->degerr;
684126177Srik	}
685126177Srik
686126177Srik	/* Degraded minutes -- having more than 50% error intervals. */
687126177Srik	if (c->cursec / 60 == 0) {
688126177Srik		if (c->degerr*2 > c->degsec)
689126177Srik			++c->currnt.dm;
690126177Srik		c->degsec = 0;
691126177Srik		c->degerr = 0;
692126177Srik	}
693126177Srik
694126177Srik	/* Rotate statistics every 15 minutes. */
695126177Srik	if (c->cursec > 15*60) {
696126177Srik		int i;
697126177Srik
698126177Srik		for (i=47; i>0; --i)
699126177Srik			c->interval[i] = c->interval[i-1];
700126177Srik		c->interval[0] = c->currnt;
701126177Srik
702126177Srik		/* Accumulate total statistics. */
703126177Srik		c->total.bpv   += c->currnt.bpv;
704126177Srik		c->total.fse   += c->currnt.fse;
705126177Srik		c->total.crce  += c->currnt.crce;
706126177Srik		c->total.rcrce += c->currnt.rcrce;
707126177Srik		c->total.uas   += c->currnt.uas;
708126177Srik		c->total.les   += c->currnt.les;
709126177Srik		c->total.es    += c->currnt.es;
710126177Srik		c->total.bes   += c->currnt.bes;
711126177Srik		c->total.ses   += c->currnt.ses;
712126177Srik		c->total.oofs  += c->currnt.oofs;
713126177Srik		c->total.css   += c->currnt.css;
714126177Srik		c->total.dm    += c->currnt.dm;
715126177Srik		memset (&c->currnt, 0, sizeof (c->currnt));
716126177Srik
717126177Srik		c->totsec += c->cursec;
718126177Srik		c->cursec = 0;
719126177Srik	}
720126177Srik}
721126177Srik
722126177Srikstatic void ct_e1timer_interrupt (ct_chan_t *c)
723126177Srik{
724126177Srik	unsigned short port;
725126177Srik	unsigned char sr1, sr2, ssr;
726126177Srik	unsigned long bpv, fas, crc4, ebit, pcv, oof;
727126177Srik
728126177Srik	port = c->num ? E1CS1(c->board->port) : E1CS0(c->board->port);
729126177Srik
730126177Srik	sr2 = cte_ins (port, DS_SR2, 0xff);
731126177Srik	/* is it timer interrupt ? */
732126177Srik	if (! (sr2 & SR2_SEC))
733126177Srik		return;
734126177Srik
735126177Srik	/* first interrupts should be ignored */
736126177Srik	if (c->e1_first_int > 0) {
737126177Srik		c->e1_first_int --;
738126177Srik		return;
739126177Srik	}
740126177Srik
741126177Srik	++c->cursec;
742126177Srik	c->status = 0;
743126177Srik
744126177Srik	/* Compute the SNMP-compatible channel status. */
745126177Srik	sr1 = cte_ins (port, DS_SR1, 0xff);
746126177Srik	ssr = cte_in (port, DS_SSR);
747126177Srik	oof = 0;
748126177Srik
749126177Srik	if (sr1 & (SR1_RCL | SR1_RLOS))
750126177Srik		c->status |= ESTS_LOS;		/* loss of signal */
751126177Srik	if (sr1 & SR1_RUA1)
752126177Srik		c->status |= ESTS_AIS;		/* receiving all ones */
753126177Srik	if (c->gopt.cas && (sr1 & SR1_RSA1))
754126177Srik		c->status |= ESTS_AIS16;	/* signaling all ones */
755126177Srik	if (c->gopt.cas && (sr1 & SR1_RDMA))
756126177Srik		c->status |= ESTS_FARLOMF;	/* alarm in timeslot 16 */
757126177Srik	if (sr1 & SR1_RRA)
758126177Srik		c->status |= ESTS_FARLOF;	/* far loss of framing */
759126177Srik
760126177Srik	/* Controlled slip second -- any slip event. */
761126177Srik	if (sr1 & SR1_RSLIP) {
762126177Srik		++c->currnt.css;
763126177Srik	}
764126177Srik
765126177Srik	if (ssr & SSR_SYNC) {
766126177Srik		c->status |= ESTS_LOF;		/* loss of framing */
767126177Srik		++oof;				/* out of framing */
768126177Srik	}
769126177Srik	if ((c->gopt.cas && (ssr & SSR_SYNC_CAS)) ||
770126177Srik	    (c->gopt.crc4 && (ssr & SSR_SYNC_CRC4))) {
771126177Srik		c->status |= ESTS_LOMF; 	/* loss of multiframing */
772126177Srik		++oof;				/* out of framing */
773126177Srik	}
774126177Srik
775126177Srik	if (! c->status)
776126177Srik		c->status = ESTS_NOALARM;
777126177Srik
778126177Srik	/* Get error counters. */
779126177Srik	bpv = VCR (cte_in (port, DS_VCR1), cte_in (port, DS_VCR2));
780126177Srik	fas = FASCR (cte_in (port, DS_FASCR1), cte_in (port, DS_FASCR2));
781126177Srik	crc4 = CRCCR (cte_in (port, DS_CRCCR1), cte_in (port, DS_CRCCR2));
782126177Srik	ebit = EBCR (cte_in (port, DS_EBCR1), cte_in (port, DS_EBCR2));
783126177Srik
784126177Srik	c->currnt.bpv += bpv;
785126177Srik	c->currnt.fse += fas;
786126177Srik	if (c->gopt.crc4) {
787126177Srik		c->currnt.crce += crc4;
788126177Srik		c->currnt.rcrce += ebit;
789126177Srik	}
790126177Srik
791126177Srik	/* Path code violation is frame sync error if CRC4 disabled,
792126177Srik	 * or CRC error if CRC4 enabled. */
793126177Srik	pcv = fas;
794126177Srik	if (c->gopt.crc4)
795126177Srik		pcv += crc4;
796126177Srik
797126177Srik	/* Unavaiable second -- receiving all ones, or
798126177Srik	 * loss of carrier, or loss of signal. */
799126177Srik	if (sr1 & (SR1_RUA1 | SR1_RCL | SR1_RLOS))
800126177Srik		/* Unavailable second -- no other counters. */
801126177Srik		++c->currnt.uas;
802126177Srik	else {
803126177Srik		/* Line errored second -- any BPV. */
804126177Srik		if (bpv)
805126177Srik			++c->currnt.les;
806126177Srik
807126177Srik		/* Errored second -- any PCV, or out of frame sync,
808126177Srik		 * or any slip events. */
809126177Srik		if (pcv || oof || (sr1 & SR1_RSLIP))
810126177Srik			++c->currnt.es;
811126177Srik
812126177Srik		/* Severely errored framing second -- out of frame sync. */
813126177Srik		if (oof)
814126177Srik			++c->currnt.oofs;
815126177Srik
816126177Srik		/* Severely errored seconds --
817126177Srik		 * 832 or more PCVs, or 2048 or more BPVs. */
818126177Srik		if (bpv >= 2048 || pcv >= 832)
819126177Srik			++c->currnt.ses;
820126177Srik		else {
821126177Srik			/* Bursty errored seconds --
822126177Srik			 * no SES and more than 1 PCV. */
823126177Srik			if (pcv > 1)
824126177Srik				++c->currnt.bes;
825126177Srik
826126177Srik			/* Collect data for computing
827126177Srik			 * degraded minutes. */
828126177Srik			++c->degsec;
829126177Srik			c->degerr += bpv + pcv;
830126177Srik		}
831126177Srik	}
832126177Srik
833126177Srik	/* Degraded minutes -- having error rate more than 10e-6,
834126177Srik	 * not counting unavailable and severely errored seconds. */
835126177Srik	if (c->cursec / 60 == 0) {
836126177Srik		if (c->degerr > c->degsec * 2048 / 1000)
837126177Srik			++c->currnt.dm;
838126177Srik		c->degsec = 0;
839126177Srik		c->degerr = 0;
840126177Srik	}
841126177Srik
842126177Srik	/* Rotate statistics every 15 minutes. */
843126177Srik	if (c->cursec > 15*60) {
844126177Srik		int i;
845126177Srik
846126177Srik		for (i=47; i>0; --i)
847126177Srik			c->interval[i] = c->interval[i-1];
848126177Srik		c->interval[0] = c->currnt;
849126177Srik
850126177Srik		/* Accumulate total statistics. */
851126177Srik		c->total.bpv   += c->currnt.bpv;
852126177Srik		c->total.fse   += c->currnt.fse;
853126177Srik		c->total.crce  += c->currnt.crce;
854126177Srik		c->total.rcrce += c->currnt.rcrce;
855126177Srik		c->total.uas   += c->currnt.uas;
856126177Srik		c->total.les   += c->currnt.les;
857126177Srik		c->total.es    += c->currnt.es;
858126177Srik		c->total.bes   += c->currnt.bes;
859126177Srik		c->total.ses   += c->currnt.ses;
860126177Srik		c->total.oofs  += c->currnt.oofs;
861126177Srik		c->total.css   += c->currnt.css;
862126177Srik		c->total.dm    += c->currnt.dm;
863126177Srik		for (i=0; i<sizeof (c->currnt); ++i)
864126177Srik			*(((char *)(&c->currnt))+i)=0;
865126177Srik
866126177Srik		c->totsec += c->cursec;
867126177Srik		c->cursec = 0;
868126177Srik	}
869126177Srik}
870126177Srik
871126177Srikstatic void ct_hdlc_interrupt (ct_chan_t *c, int imvr)
872126177Srik{
873126177Srik	int i, dsr, st1, st2, cda;
874126177Srik
875126177Srik	switch (imvr & IMVR_VECT_MASK) {
876126177Srik	case IMVR_RX_DMOK:		/* receive DMA normal end */
877126177Srik		dsr = inb (c->RX.DSR);
878126177Srik		cda = inw (c->RX.CDA);
879126177Srik		for (i=0; i<NBUF; ++i)
880126177Srik			if (cda == (unsigned short) c->rdphys[i])
881126177Srik				break;
882126177Srik		if (i >= NBUF)
883126177Srik			i = c->rn; /* cannot happen */
884126177Srik		while (c->rn != i) {
885126177Srik			int cst = B_STATUS (c->rdesc[c->rn]);
886126177Srik			if (cst == FST_EOM) {
887126177Srik				/* process data */
888126177Srik				if (c->call_on_rx)
889126177Srik					 c->call_on_rx (c, c->rbuf[c->rn],
890126177Srik						B_LEN(c->rdesc[c->rn]));
891126177Srik				++c->ipkts;
892126177Srik				c->ibytes += B_LEN(c->rdesc[c->rn]);
893126177Srik			} else if (cst & ST2_OVRN) {
894126177Srik				/* Receive overrun error */
895126177Srik				if (c->call_on_err)
896126177Srik					c->call_on_err (c, CT_OVERRUN);
897126177Srik				++c->ierrs;
898126177Srik			} else if (cst & (ST2_HDLC_RBIT |
899126177Srik				ST2_HDLC_ABT | ST2_HDLC_SHRT)) {
900126177Srik				/* Receive frame error */
901126177Srik				if (c->call_on_err)
902126177Srik					c->call_on_err (c, CT_FRAME);
903126177Srik				++c->ierrs;
904126177Srik			} else if ((cst & ST2_HDLC_EOM)
905126177Srik				&& (cst & ST2_HDLC_CRCE)) {
906126177Srik				/* Receive CRC error */
907126177Srik				if (c->call_on_err)
908126177Srik					c->call_on_err (c, CT_CRC);
909126177Srik				++c->ierrs;
910126177Srik			} else if (! (cst & ST2_HDLC_EOM)) {
911126177Srik				/* Frame dose not fit in the buffer.*/
912126177Srik				if (c->call_on_err)
913126177Srik					c->call_on_err (c, CT_OVERFLOW);
914126177Srik				++c->ierrs;
915126177Srik			}
916126177Srik
917126177Srik			B_NEXT (c->rdesc[c->rn]) =
918126177Srik				c->rdphys[(c->rn+1) % NBUF] & 0xffff;
919126177Srik			B_PTR (c->rdesc[c->rn]) = c->rphys[c->rn];
920126177Srik			B_LEN (c->rdesc[c->rn]) = DMABUFSZ;
921126177Srik			B_STATUS (c->rdesc[c->rn]) = 0;
922126177Srik			c->rn = (c->rn + 1) % NBUF;
923126177Srik		}
924126177Srik		outw (c->RX.EDA, (unsigned short) c->rdphys[(i+NBUF-1)%NBUF]);
925126177Srik		/* Clear DMA interrupt. */
926126177Srik		if (inb (c->RX.DSR) & DSR_DMA_ENABLE) {
927126177Srik			outb (c->RX.DSR, dsr);
928126177Srik		} else {
929126177Srik			outb (c->RX.DSR, (dsr & 0xfc) | DSR_DMA_ENABLE);
930126177Srik		}
931126177Srik		++c->rintr;
932126177Srik		break;
933126177Srik
934126177Srik	case IMVR_RX_INT:		/* receive status */
935126177Srik		st1 = inb (c->ST1);
936126177Srik		st2 = inb (c->ST2);
937126177Srik		if (st1 & ST1_CDCD){
938126177Srik			if (c->call_on_msig)
939126177Srik				c->call_on_msig (c);
940126177Srik			++c->mintr;
941126177Srik		}
942126177Srik		/* Clear interrupt. */
943126177Srik		outb (c->ST1, st1);
944126177Srik		outb (c->ST2, st2);
945126177Srik		++c->rintr;
946126177Srik		break;
947126177Srik
948126177Srik	case IMVR_RX_DMERR:		/* receive DMA error */
949126177Srik		dsr = inb (c->RX.DSR);
950126177Srik		if (dsr & (DSR_CHAIN_BOF | DSR_CHAIN_COF)) {
951126177Srik			if (c->call_on_err)
952126177Srik				c->call_on_err (c, CT_OVERFLOW);
953126177Srik			++c->ierrs;
954126177Srik			for (i=0; i<NBUF; ++i) {
955126177Srik				B_LEN (c->rdesc[i]) = DMABUFSZ;
956126177Srik				B_STATUS (c->rdesc[i]) = 0;
957126177Srik			}
958126177Srik			ct_start_receiver (c, 1, c->rphys[0], DMABUFSZ,
959126177Srik				c->rdphys[0], c->rdphys[NBUF-1]);
960126177Srik			c->rn = 0;
961126177Srik		}
962126177Srik		/* Clear DMA interrupt. */
963126177Srik		outb (c->RX.DSR, dsr);
964126177Srik		++c->rintr;
965126177Srik		break;
966126177Srik
967126177Srik	case IMVR_TX_DMOK:		/* transmit DMA normal end */
968126177Srik	case IMVR_TX_DMERR:		/* transmit DMA error	   */
969126177Srik		dsr = inb (c->TX.DSR);
970126177Srik		cda = inw (c->TX.CDA);
971126177Srik
972126177Srik		for (i=0; i<NBUF && cda != (unsigned short)c->tdphys[i]; ++i)
973126177Srik			continue;
974126177Srik		if (i >= NBUF)
975126177Srik			i = 1; /* cannot happen */
976126177Srik		if (dsr & DSR_CHAIN_COF) {
977126177Srik			if (c->call_on_err)
978126177Srik				c->call_on_err (c, CT_UNDERRUN);
979126177Srik			++c->oerrs;
980126177Srik		}
981126177Srik		while (c->tn != i) {
982126177Srik			if (c->call_on_tx)
983126177Srik				c->call_on_tx (c, c->attach[c->tn],
984126177Srik					B_LEN(c->tdesc[c->tn]));
985126177Srik			++c->opkts;
986126177Srik			c->obytes += B_LEN(c->tdesc[c->tn]);
987126177Srik
988126177Srik			c->tn = (c->tn + 1) % NBUF;
989126177Srik			/* Clear DMA interrupt. */
990126177Srik			outb (c->TX.DSR, DSR_CHAIN_EOM | DSR_DMA_CONTINUE);
991126177Srik		}
992126177Srik		outb (c->TX.DSR, dsr & ~DSR_CHAIN_EOM);
993126177Srik		++c->tintr;
994126177Srik		break;
995126177Srik
996126177Srik	case IMVR_TX_INT:		/* transmit error, HDLC only */
997126177Srik		st1 = inb (c->ST1);
998126177Srik		if (st1 & ST1_HDLC_UDRN) {
999126177Srik			if (c->call_on_err)
1000126177Srik				c->call_on_err (c, CT_UNDERRUN);
1001126177Srik			++c->oerrs;
1002126177Srik		}
1003126177Srik		outb (c->ST1, st1);
1004126177Srik		++c->tintr;
1005126177Srik		break;
1006126177Srik
1007126177Srik	default:
1008126177Srik		/* Unknown interrupt - cannot happen. */
1009126177Srik		break;
1010126177Srik	}
1011126177Srik}
1012126177Srik
1013126177Srikint ct_receive_enabled (ct_chan_t *c)
1014126177Srik{
1015126177Srik	int st3;
1016126177Srik
1017126177Srik	st3 = inb (c->ST3);
1018126177Srik	return (st3 & ST3_RX_ENABLED) ? 1 : 0;
1019126177Srik}
1020126177Srik
1021126177Srikint ct_transmit_enabled (ct_chan_t *c)
1022126177Srik{
1023126177Srik	int st3;
1024126177Srik
1025126177Srik	st3 = inb (c->ST3);
1026126177Srik	return (st3 & ST3_TX_ENABLED) ? 1 : 0;
1027126177Srik}
1028126177Srik
1029126177Srikint ct_buf_free (ct_chan_t *c)
1030126177Srik{
1031126177Srik	return (NBUF + c->tn - c->te - 1) % NBUF;
1032126177Srik}
1033126177Srik
1034126177Srikint ct_send_packet (ct_chan_t *c, unsigned char *data, int len,
1035126177Srik	void *attachment)
1036126177Srik{
1037126177Srik	int dsr, ne;
1038126177Srik
1039126177Srik	if (len > DMABUFSZ)
1040126177Srik		return -2;
1041126177Srik
1042126177Srik	/* Is it really free? */
1043126177Srik	ne = (c->te+1) % NBUF;
1044126177Srik	if (ne == c->tn)
1045126177Srik		return -1;
1046126177Srik
1047126177Srik	/* Set up the tx descriptor. */
1048126177Srik	B_LEN (c->tdesc[c->te]) = len;
1049126177Srik	B_STATUS (c->tdesc[c->te]) = FST_EOM;
1050126177Srik	c->attach[c->te] = attachment;
1051126177Srik	if (c->tbuf[c->te] != data)
1052126177Srik		memcpy (c->tbuf[c->te], data, len);
1053126177Srik
1054126177Srik	/* Start the transmitter. */
1055126177Srik	c->te = ne;
1056126177Srik	outw (c->TX.EDA, (unsigned short) c->tdphys[ne]);
1057126177Srik	dsr = inb (c->TX.DSR);
1058126177Srik	if (! (dsr & DSR_DMA_ENABLE))
1059126177Srik		outb (c->TX.DSR, DSR_DMA_ENABLE);
1060126177Srik	return 0;
1061126177Srik}
1062126177Srik
1063126177Srikint scc_write (ct_chan_t *c, unsigned char *d, int len)
1064126177Srik{
1065126177Srik	int i, free;
1066126177Srik
1067126177Srik	/* determining free place in buffer */
1068126177Srik	if (c->scctx_empty)
1069126177Srik		free = SCCBUFSZ;
1070126177Srik	else
1071126177Srik		free = (SCCBUFSZ + c->scctx_b - c->scctx_e) % SCCBUFSZ;
1072126177Srik
1073126177Srik	if (len > free)
1074126177Srik		return -1;
1075126177Srik
1076126177Srik	for (i=0; i<len; i++){
1077126177Srik		c->scctx[c->scctx_e] = d[i];
1078126177Srik		c->scctx_e = (c->scctx_e+1) % SCCBUFSZ;
1079126177Srik	}
1080126177Srik	if (c->scctx_empty && len) {
1081126177Srik		cte_out2d (c, c->scctx[c->scctx_b]);
1082126177Srik		c->scctx_empty = 0;
1083126177Srik	}
1084126177Srik	return 0;
1085126177Srik}
1086126177Srik
1087126177Srikint scc_read (ct_chan_t *c, unsigned char *d, int len)
1088126177Srik{
1089126177Srik	int i, bytes;
1090126177Srik
1091126177Srik	if (c->sccrx_empty)
1092126177Srik		bytes = 0;
1093126177Srik	else
1094126177Srik		bytes = (SCCBUFSZ + c->sccrx_e - 1 - c->sccrx_b) %
1095126177Srik				SCCBUFSZ + 1;
1096126177Srik	if (len > bytes)
1097126177Srik		return -1;
1098126177Srik
1099126177Srik	for (i=0; i<len; i++){
1100126177Srik		d[i] = c->sccrx[c->sccrx_b];
1101126177Srik		c->sccrx_b = (c->sccrx_b+1) % SCCBUFSZ;
1102126177Srik	}
1103126177Srik	if (c->sccrx_b==c->sccrx_e)
1104126177Srik		c->sccrx_empty = 1;
1105126177Srik	return 0;
1106126177Srik}
1107126177Srik
1108126177Srikint sccrx_check (ct_chan_t *c)
1109126177Srik{
1110126177Srik	int bytes;
1111126177Srik
1112126177Srik	if (c->sccrx_empty)
1113126177Srik		bytes = 0;
1114126177Srik	else
1115126177Srik		bytes = (SCCBUFSZ + c->sccrx_e - 1 - c->sccrx_b) %
1116126177Srik				SCCBUFSZ + 1;
1117126177Srik	return bytes;
1118126177Srik}
1119126177Srik
1120126177Srikint scc_read_byte (ct_chan_t *c)
1121126177Srik{
1122126177Srik	unsigned char a;
1123126177Srik
1124126177Srik	if (scc_read (c, &a, 1) < 0)
1125126177Srik		return -1;
1126126177Srik	return a;
1127126177Srik}
1128126177Srik
1129126177Srikint scc_write_byte (ct_chan_t *c, unsigned char b)
1130126177Srik{
1131126177Srik	if (scc_write (c, &b, 1) < 0)
1132126177Srik		return -1;
1133126177Srik	return b;
1134126177Srik}
1135126177Srik
1136126177Srik/*
1137126177Srik * Register event processing functions
1138126177Srik */
1139126177Srikvoid ct_register_transmit (ct_chan_t *c, void (*func) (ct_chan_t*, void*, int))
1140126177Srik{
1141126177Srik	c->call_on_tx = func;
1142126177Srik}
1143126177Srik
1144126177Srikvoid ct_register_receive (ct_chan_t *c, void (*func) (ct_chan_t*, char*, int))
1145126177Srik{
1146126177Srik	c->call_on_rx = func;
1147126177Srik}
1148126177Srik
1149126177Srikvoid ct_register_error (ct_chan_t *c, void (*func) (ct_chan_t*, int))
1150126177Srik{
1151126177Srik	c->call_on_err = func;
1152126177Srik}
1153126177Srik
1154126177Srikvoid ct_register_scc (ct_chan_t *c, void (*func) (ct_chan_t*))
1155126177Srik{
1156126177Srik	c->call_on_scc = func;
1157126177Srik}
1158126177Srik
1159126177Srikvoid ct_register_modem (ct_chan_t *c, void (*func) (ct_chan_t*))
1160126177Srik{
1161126177Srik	c->call_on_msig = func;
1162126177Srik}
1163