115177Snate/*-
215284Snate * DDK library for Cronyx-Tau adapters.
315284Snate *
415284Snate * Copyright (C) 1998-1999 Cronyx Engineering.
515284Snate * Author: Alexander Kvitchenko, <aak@cronyx.ru>
615284Snate *
715284Snate * Copyright (C) 1999-2003 Cronyx Engineering.
815284Snate * Author: Roman Kurakin, <rik@cronyx.ru>
915284Snate *
1015284Snate * This source is derived from
1115284Snate * Diagnose utility for Cronyx-Tau adapter:
1215284Snate * by Serge Vakulenko, <vak@cronyx.ru>
1315284Snate *
1415284Snate * This software is distributed with NO WARRANTIES, not even the implied
1515284Snate * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1615284Snate *
1715284Snate * Authors grant any other persons or organisations permission to use
1815284Snate * or modify this software as long as this message is kept with the software,
1915284Snate * all derivative works or modified versions.
2015284Snate *
2115284Snate * Cronyx Id: ctddk.c,v 1.1.2.3 2003/11/14 16:55:36 rik Exp $
2215284Snate */
2315284Snate#include <sys/cdefs.h>
2415284Snate__FBSDID("$FreeBSD$");
2510217Sphk
2630171Scharnier#include <dev/cx/machdep.h>
2730171Scharnier#include <dev/ctau/ctddk.h>
2830171Scharnier#include <dev/ctau/ctaureg.h>
2950479Speter#include <dev/ctau/hdc64570.h>
3030171Scharnier#include <dev/ctau/ds2153.h>
3130171Scharnier#include <dev/ctau/am8530.h>
3259656Siwasaki#include <dev/ctau/lxt318.h>
3359656Siwasaki#include <dev/cx/cronyxfw.h>
3459656Siwasaki#include <dev/ctau/ctaufw.h>
3559656Siwasaki#include <dev/ctau/ctau2fw.h>
3659656Siwasaki
3730171Scharnier#ifndef CT_DDK_NO_G703
3810217Sphk#include <dev/ctau/ctaug7fw.h>
3910217Sphk#endif
4010217Sphk
4130171Scharnier#ifndef CT_DDK_NO_E1
4210217Sphk#include <dev/ctau/ctaue1fw.h>
4310217Sphk#endif
4431290Snate
4510217Sphkstatic void ct_hdlc_interrupt (ct_chan_t *c, int imvr);
4610217Sphkstatic void ct_e1_interrupt (ct_board_t *b);
4710217Sphkstatic void ct_scc_interrupt (ct_board_t *b);
4810217Sphkstatic void ct_e1timer_interrupt (ct_chan_t *c);
4959656Siwasaki
5059656Siwasakistatic short porttab [] = {	       /* standard base port set */
5159656Siwasaki	0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0,
52111507Sgreen	0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0
5359656Siwasaki};
5416487Snate
5516487Snateint ct_find (port_t *board_ports)
5616487Snate{
5716487Snate	int i, n;
5816487Snate
5916487Snate	for (i=0, n=0; porttab[i] && n<NBRD; i++)
6090968Sshiba		if (ct_probe_board (porttab[i], -1, -1))
6159053Siwasaki			board_ports[n++] = porttab[i];
6259656Siwasaki	return n;
6316487Snate}
6416487Snate
6516487Snateint ct_open_board (ct_board_t *b, int num, port_t port, int irq, int dma)
6616487Snate{
6710217Sphk	ct_chan_t *c;
6816487Snate	const unsigned char *fw;
6915177Snate	const cr_dat_tst_t *ft;
7015177Snate	long flen;
7159656Siwasaki
7259656Siwasaki	if (num >= NBRD || ! ct_probe_board (port, irq, dma))
7359656Siwasaki		return 0;
7459656Siwasaki
7559656Siwasaki	/* init callback pointers */
7659656Siwasaki	for (c=b->chan; c<b->chan+NCHAN; ++c) {
7715177Snate		c->call_on_tx = 0;
7815177Snate		c->call_on_rx = 0;
7915177Snate		c->call_on_msig = 0;
8015177Snate		c->call_on_scc = 0;
8115177Snate		c->call_on_err = 0;
8215177Snate	}
8315177Snate
8415177Snate	/* init DDK channel variables */
8515177Snate	for (c=b->chan; c<b->chan+NCHAN; ++c) {
8615177Snate		c->sccrx_empty = c->scctx_empty = 1;
8715177Snate		c->sccrx_b = c->sccrx_e = 0;
8815177Snate		c->scctx_b = c->scctx_e = 0;
8915177Snate		c->e1_first_int = 1;
9015177Snate	}
9115177Snate
9215177Snate	/* init board structure */
9315177Snate	ct_init (b, num, port, irq, dma, ctau_fw_data,
9459656Siwasaki		ctau_fw_len, ctau_fw_tvec, ctau2_fw_data);
9515177Snate
9615177Snate	/* determine which firmware should be loaded */
9715177Snate	fw = ctau_fw_data;
9815177Snate	flen = ctau_fw_len;
9915177Snate	ft = ctau_fw_tvec;
10015177Snate	switch (b->type) {
10115177Snate	case B_TAU2:
10215177Snate	case B_TAU2_G703:
10359656Siwasaki	case B_TAU2_E1:
10459656Siwasaki	case B_TAU2_E1D:
10515177Snate		fw = ctau2_fw_data;
10615177Snate		flen = 0;
10710217Sphk		ft = 0;
10810217Sphk		break;
10910217Sphk#ifndef CT_DDK_NO_G703
11010217Sphk	case B_TAU_G703:
11110217Sphk		fw = ctaug703_fw_data;
11210217Sphk		flen = ctaug703_fw_len;
11310217Sphk		ft = ctaug703_fw_tvec;
11415177Snate		break;
11515177Snate#endif
11615177Snate#ifndef CT_DDK_NO_E1
11710217Sphk	case B_TAU_E1:
11810217Sphk		fw = ctaue1_fw_data;
11910217Sphk		flen = ctaue1_fw_len;
12010217Sphk		ft = ctaue1_fw_tvec;
12115177Snate		break;
12210217Sphk#endif
12310217Sphk	}
12415177Snate	/* Load firmware and set up board */
12561804Sroberto	return ct_setup_board (b, fw, flen, ft);
12615177Snate}
12715177Snate
12810217Sphk/*
12915177Snate * must be called on the exit
13015177Snate */
13115177Snatevoid ct_close_board (ct_board_t *b)
13215177Snate{
13315177Snate	ct_setup_board (b, 0, 0, 0);
13415177Snate
13515177Snate	/* Reset the controller. */
13615177Snate	outb (BCR0(b->port), 0);
13715177Snate
13815177Snate	/* Disable DMA channel. */
13915177Snate	ct_disable_dma (b);
14015177Snate
14115177Snate	ct_led (b, 0);
14215177Snate}
14315177Snate
14415177Snatestatic void ct_g703_rate (ct_chan_t *c, unsigned long rate)
14590968Sshiba{
14690968Sshiba	c->gopt.rate = rate;
14790968Sshiba	ct_setup_g703 (c->board);
14859656Siwasaki}
14959053Siwasaki
15059053Siwasaki/*
15159656Siwasaki * Set up baud rate.
15259656Siwasaki */
15359656Siwasakistatic void ct_chan_baud (ct_chan_t *c, unsigned long baud)
15459656Siwasaki{
15510217Sphk	c->baud = baud;
15610217Sphk	if (baud) {
15715177Snate		c->hopt.txs = CLK_INT;
15810217Sphk	} else {
15915177Snate		ct_set_dpll (c, 0);
16010217Sphk		c->hopt.txs = CLK_LINE;
16110217Sphk	}
16210217Sphk	ct_update_chan (c);
16310217Sphk}
16410217Sphk
16510217Sphkvoid ct_set_baud (ct_chan_t *c, unsigned long baud)
16615177Snate{
16715177Snate	unsigned long r;
16815177Snate
16915177Snate	if (c->mode == M_E1)
17015177Snate		return;
17110217Sphk	if (c->mode == M_G703) {
17215177Snate		if	(baud >= 2048000)  r = 2048;
17310217Sphk		else if (baud >= 1024000)  r = 1024;
17415177Snate		else if (baud >= 512000)   r = 512;
17510217Sphk		else if (baud >= 256000)   r = 256;
17610217Sphk		else if (baud >= 128000)   r = 128;
17710217Sphk		else			   r = 64;
17810217Sphk		ct_g703_rate (c, r);
17915177Snate	} else
18010217Sphk		ct_chan_baud (c, baud);
18115177Snate}
18210217Sphk
18315177Snate/*
18410217Sphk * Configure Tau/E1 board.
18510217Sphk */
18615177Snatestatic void ct_e1_config (ct_board_t *b, unsigned char cfg)
18715177Snate{
18810217Sphk	if (cfg == b->opt.cfg)
18910217Sphk		return;
19015177Snate
19110217Sphk	if (cfg == CFG_B)
19215177Snate		b->chan[1].mode = M_HDLC;
19310217Sphk	else
19410217Sphk		b->chan[1].mode = M_E1;
19515177Snate
19610217Sphk	/* Recovering synchronization */
19710217Sphk	if (b->opt.cfg == CFG_B) {
19810217Sphk		ct_chan_baud (b->chan+1, 0);
19916487Snate		ct_set_invtxc (b->chan+1, 0);
20010217Sphk		ct_set_invrxc (b->chan+1, 0);
20110217Sphk		ct_set_nrzi (b->chan+1, 0);
20210217Sphk	}
20310217Sphk	b->opt.cfg = cfg;
20459656Siwasaki	ct_setup_e1 (b);
20559656Siwasaki}
20659656Siwasaki
20759656Siwasaki/*
20859656Siwasaki * Config Tau/G.703 board
20959656Siwasaki */
21059656Siwasakistatic void ct_g703_config (ct_board_t *b, unsigned char cfg)
21188961Simp{
21288961Simp	if (cfg == b->opt.cfg)
21359656Siwasaki		return;
21459656Siwasaki
21559656Siwasaki	if (cfg == CFG_B)
21659656Siwasaki		b->chan[1].mode = M_HDLC;
21759656Siwasaki	else
21859656Siwasaki		b->chan[1].mode = M_G703;
21959656Siwasaki
22088961Simp	/* Recovering synchronization */
22188961Simp	if (b->opt.cfg == CFG_B) {
22259656Siwasaki		ct_chan_baud (b->chan+1, 0);
22388961Simp		ct_set_invtxc (b->chan+1, 0);
22459656Siwasaki		ct_set_invrxc (b->chan+1, 0);
22559656Siwasaki		ct_set_nrzi (b->chan+1, 0);
22659656Siwasaki	}
22759656Siwasaki	b->opt.cfg = cfg;
22859656Siwasaki	ct_setup_g703 (b);
22959656Siwasaki}
23059656Siwasaki
23188961Simpint ct_set_clk (ct_chan_t *c, int clk)
23288961Simp{
23388961Simp	if (c->num)
23488961Simp		c->board->opt.clk1 = clk;
23559656Siwasaki	else
23659656Siwasaki		c->board->opt.clk0 = clk;
23759656Siwasaki	if (c->mode == M_E1) {
23859656Siwasaki		ct_setup_e1 (c->board);
23959656Siwasaki		return 0;
24059656Siwasaki	} if (c->mode == M_G703) {
24159656Siwasaki		ct_setup_g703 (c->board);
24288961Simp		return 0;
24388961Simp	} else
24410217Sphk		return -1;
24559656Siwasaki}
24690968Sshiba
24790968Sshibaint ct_get_clk (ct_chan_t *c)
24890968Sshiba{
24990968Sshiba	return c->num ? c->board->opt.clk1 : c->board->opt.clk0;
25090968Sshiba}
25190968Sshiba
25290968Sshibaint ct_set_ts (ct_chan_t *c, unsigned long ts)
25390968Sshiba{
25490968Sshiba	if (! (c->mode == M_E1))
25590968Sshiba		return -1;
25690968Sshiba	if (c->num)
25790968Sshiba		c->board->opt.s1 = ts;
25890968Sshiba	else
25990968Sshiba		c->board->opt.s0 = ts;
26059053Siwasaki	ct_setup_e1 (c->board);
26159656Siwasaki	return 0;
26259053Siwasaki}
26359053Siwasaki
26459053Siwasakiint ct_set_subchan (ct_board_t *b, unsigned long ts)
26559053Siwasaki{
26659053Siwasaki	if (b->chan[0].mode != M_E1)
26759053Siwasaki		return -1;
26859053Siwasaki	b->opt.s2 = ts;
26915177Snate	ct_setup_e1 (b);
27059656Siwasaki	return 0;
27159656Siwasaki}
27259656Siwasaki
27359656Siwasakiint ct_set_higain (ct_chan_t *c, int on)
27459656Siwasaki{
27559656Siwasaki	if (! (c->mode == M_E1))
27659656Siwasaki		return -1;
27759656Siwasaki	c->gopt.higain = on ? 1 : 0;
27859656Siwasaki	ct_setup_e1 (c->board);
27959656Siwasaki	return 0;
28059656Siwasaki}
28159656Siwasaki
28259656Siwasaki/*
28359656Siwasaki * Start service channel.
28459656Siwasaki */
28559656Siwasakivoid ct_start_scc (ct_chan_t *c, char *rxbuf, char *txbuf)
28659656Siwasaki{
28759656Siwasaki	c->sccrx = rxbuf;
28859656Siwasaki	c->scctx = txbuf;
28959656Siwasaki
29010217Sphk	/* Enable interrupts from service channel. */
29159656Siwasaki	if (c->board->type != B_TAU_E1 && c->board->type != B_TAU_E1C &&
29259656Siwasaki	    c->board->type != B_TAU2_E1)
29359656Siwasaki		return;
29459656Siwasaki
29559656Siwasaki	cte_out2 (c->board->port, c->num ? AM_IMR : AM_IMR | AM_A,
29659656Siwasaki		 IMR_TX | IMR_RX_ALL);
29759656Siwasaki	cte_out2 (c->board->port, AM_MICR, MICR_MIE);
29859656Siwasaki}
29959656Siwasaki
30059656Siwasaki/*
30159656Siwasaki * Start HDLC channel.
30259656Siwasaki */
30359656Siwasakivoid ct_start_chan (ct_chan_t *c, ct_buf_t *cb, unsigned long phys)
30459656Siwasaki{
30559656Siwasaki	int i, ier0;
30659656Siwasaki	unsigned long bound;
30759656Siwasaki
30859656Siwasaki	if (cb) {
30959656Siwasaki		/* Set up descriptors, align to 64k boundary.
31059656Siwasaki		 * If 64k boundary is inside buffers
31159656Siwasaki		 * buffers will begin on this boundary
31259656Siwasaki		 * (there were allocated additional space for this) */
31359656Siwasaki		c->tdesc = cb->descbuf;
31459656Siwasaki		c->tdphys[0] = phys + ((char*)c->tdesc - (char*)cb);
31559656Siwasaki		bound = ((c->tdphys[0] + 0xffff) & ~(0xffffUL));
31659656Siwasaki		if (bound < c->tdphys[0] + 2*NBUF*sizeof(ct_desc_t)) {
31759656Siwasaki			c->tdesc = (ct_desc_t*) ((char*) c->tdesc +
31859656Siwasaki				(bound - c->tdphys[0]));
31959656Siwasaki			c->tdphys[0] = bound;
32059656Siwasaki		}
32159656Siwasaki		c->rdesc = c->tdesc + NBUF;
32259656Siwasaki
32359656Siwasaki		/* Set buffers. */
32459656Siwasaki		for (i=0; i<NBUF; ++i) {
32559656Siwasaki			c->rbuf[i] = cb->rbuffer[i];
32659656Siwasaki			c->tbuf[i] = cb->tbuffer[i];
32759656Siwasaki		}
32859656Siwasaki
32959656Siwasaki		/* Set buffer physical addresses */
33059656Siwasaki		for (i=0; i<NBUF; ++i) {
33159656Siwasaki			c->rphys[i] = phys + ((char*)c->rbuf[i] - (char*)cb);
33259656Siwasaki			c->tphys[i] = phys + ((char*)c->tbuf[i] - (char*)cb);
33359656Siwasaki			c->rdphys[i] = phys + ((char*)(c->rdesc+i) - (char*)cb);
33459656Siwasaki			c->tdphys[i] = phys + ((char*)(c->tdesc+i) - (char*)cb);
33559656Siwasaki		}
33659656Siwasaki	}
33759656Siwasaki	/* Set up block chains. */
33859656Siwasaki	/* receive buffers */
33959656Siwasaki	for (i=0; i<NBUF; ++i) {
34059656Siwasaki		B_NEXT (c->rdesc[i]) = c->rdphys[(i+1) % NBUF] & 0xffff;
34159656Siwasaki		B_PTR (c->rdesc[i]) = c->rphys[i];
34259656Siwasaki		B_LEN (c->rdesc[i]) = DMABUFSZ;
34359656Siwasaki		B_STATUS (c->rdesc[i]) = 0;
34459656Siwasaki	}
34559656Siwasaki	/* transmit buffers */
34659656Siwasaki	for (i=0; i<NBUF; ++i) {
34759656Siwasaki		B_NEXT (c->tdesc[i]) = c->tdphys[(i+1) % NBUF] & 0xffff;
34859656Siwasaki		B_PTR (c->tdesc[i]) = c->tphys[i];
34959656Siwasaki		B_LEN (c->tdesc[i]) = DMABUFSZ;
35059656Siwasaki		B_STATUS (c->tdesc[i]) = FST_EOM;
35159656Siwasaki		c->attach[i] = 0;
35259656Siwasaki	}
35310217Sphk
35410217Sphk	if (c->type & T_E1) {
35516487Snate		c->mode = M_E1;
35610255Sphk		if (c->num && c->board->opt.cfg == CFG_B)
35710217Sphk			c->mode = M_HDLC;
35815177Snate	}
35910217Sphk	if (c->type & T_G703) {
36010217Sphk		c->mode = M_G703;
36110217Sphk		if (c->num && c->board->opt.cfg == CFG_B)
36210217Sphk			c->mode = M_HDLC;
36310217Sphk	}
36415177Snate	ct_update_chan (c);
36559656Siwasaki
36610217Sphk	/* enable receiver */
36715177Snate	c->rn = 0;
36810217Sphk	ct_start_receiver (c, 1 , c->rphys[0], DMABUFSZ, c->rdphys[0],
36910217Sphk		c->rdphys[NBUF-1]);
37015177Snate	outb (c->IE1, inb (c->IE1) | IE1_CDCDE);
37110217Sphk	outb (c->IE0, inb (c->IE0) | IE0_RX_INTE);
37215177Snate	ier0 = inb (IER0(c->board->port));
37310217Sphk	ier0 |= c->num ? IER0_RX_INTE_1 : IER0_RX_INTE_0;
37410217Sphk	outb (IER0(c->board->port), ier0);
37510217Sphk
37616487Snate	/* Enable transmitter */
37710255Sphk	c->tn = 0;
37810217Sphk	c->te = 0;
37915177Snate	ct_start_transmitter (c, 1 , c->tphys[0], DMABUFSZ, c->tdphys[0],
38059656Siwasaki		c->tdphys[0]);
38110217Sphk	outb (c->TX.DIR, DIR_CHAIN_EOME | DIR_CHAIN_BOFE | DIR_CHAIN_COFE);
38210217Sphk
38310217Sphk	/* Clear DTR and RTS */
38459656Siwasaki	ct_set_dtr (c, 0);
38510217Sphk	ct_set_rts (c, 0);
38610217Sphk}
38715177Snate
38810217Sphk/*
38959656Siwasaki * Turn receiver on/off
39059656Siwasaki */
39159656Siwasakivoid ct_enable_receive (ct_chan_t *c, int on)
39259656Siwasaki{
39359656Siwasaki	unsigned char st3, ier0, ier1;
39459656Siwasaki
39559656Siwasaki	st3 = inb (c->ST3);
39659656Siwasaki	/* enable or disable receiver */
39759656Siwasaki	if (on && ! (st3 & ST3_RX_ENABLED)) {
39859656Siwasaki		c->rn = 0;
39959656Siwasaki		ct_start_receiver (c, 1 , c->rphys[0], DMABUFSZ, c->rdphys[0],
40059656Siwasaki			c->rdphys[NBUF-1]);
40159656Siwasaki		/* enable status interrupt */
40259656Siwasaki		outb (c->IE1, inb (c->IE1) | IE1_CDCDE);
40359656Siwasaki		outb (c->IE0, inb (c->IE0) | IE0_RX_INTE);
40459656Siwasaki		ier0 = inb (IER0(c->board->port));
40559656Siwasaki		ier0 |= c->num ? IER0_RX_INTE_1 : IER0_RX_INTE_0;
40659656Siwasaki		outb (IER0(c->board->port), ier0);
40759656Siwasaki		ct_set_rts (c, 1);
40859656Siwasaki	} else if (! on && (st3 & ST3_RX_ENABLED)) {
40959656Siwasaki		ct_set_rts (c, 0);
41059656Siwasaki		outb (c->CMD, CMD_RX_DISABLE);
41159656Siwasaki
41259656Siwasaki		ier0 = inb (IER0(c->board->port));
41359656Siwasaki		ier0 &= c->num ? ~(IER0_RX_INTE_1 | IER0_RX_RDYE_1) :
41459656Siwasaki			~(IER0_RX_INTE_0 | IER0_RX_RDYE_0);
41559656Siwasaki		outb (IER0(c->board->port), ier0);
41659656Siwasaki
41759656Siwasaki		ier1 = inb (IER1(c->board->port));
41859656Siwasaki		ier1 &= c->num ? ~(IER1_RX_DMERE_1 | IER1_RX_DME_1) :
41959656Siwasaki			~(IER1_RX_DMERE_0 | IER1_RX_DME_0);
42059656Siwasaki		outb (IER1(c->board->port), ier1);
42159656Siwasaki	}
42259656Siwasaki
42359656Siwasaki}
42459656Siwasaki
42510217Sphk/*
42610217Sphk * Turn transmitter on/off
42716487Snate */
42810255Sphkvoid ct_enable_transmit (ct_chan_t *c, int on)
42910217Sphk{
43015177Snate	unsigned char st3, ier0, ier1;
43115177Snate
43215177Snate	st3 = inb (c->ST3);
43315177Snate	/* enable or disable receiver */
43410217Sphk	if (on && ! (st3 & ST3_TX_ENABLED)) {
43510217Sphk		c->tn = 0;
43615177Snate		c->te = 0;
43710217Sphk		ct_start_transmitter (c, 1 , c->tphys[0], DMABUFSZ,
43810217Sphk			c->tdphys[0], c->tdphys[0]);
43910217Sphk		outb (c->TX.DIR,
44015177Snate			DIR_CHAIN_EOME | DIR_CHAIN_BOFE | DIR_CHAIN_COFE);
44110217Sphk	} else if (! on && (st3 & ST3_TX_ENABLED)) {
44259656Siwasaki		outb (c->CMD, CMD_TX_DISABLE);
44359656Siwasaki
44459656Siwasaki		ier0 = inb (IER0(c->board->port));
44559656Siwasaki		ier0 &= c->num ? ~(IER0_TX_INTE_1 | IER0_TX_RDYE_1) :
44659656Siwasaki			~(IER0_TX_INTE_0 | IER0_TX_RDYE_0);
44759656Siwasaki		outb (IER0(c->board->port), ier0);
44810217Sphk
44910217Sphk		ier1 = inb (IER1(c->board->port));
45059656Siwasaki		ier1 &= c->num ? ~(IER1_TX_DMERE_1 | IER1_TX_DME_1) :
45159656Siwasaki			~(IER1_TX_DMERE_0 | IER1_TX_DME_0);
45215177Snate		outb (IER1(c->board->port), ier1);
45310217Sphk	}
45410217Sphk
45510217Sphk}
45610217Sphk
45710217Sphkint ct_set_config (ct_board_t *b, int cfg)
45815177Snate{
45915177Snate	if (b->opt.cfg == cfg)
46015177Snate		return 0;
46110217Sphk	switch (b->type) {
46210217Sphk	case B_TAU_G703:
46310217Sphk	case B_TAU_G703C:
46410217Sphk	case B_TAU2_G703:
46510217Sphk		if (cfg == CFG_C)
46610217Sphk			return -1;
46710217Sphk		ct_g703_config (b, cfg);
46810217Sphk		return 0;
46915177Snate	case B_TAU_E1:
47015177Snate	case B_TAU_E1C:
47110217Sphk	case B_TAU_E1D:
47210217Sphk	case B_TAU2_E1:
47315177Snate	case B_TAU2_E1D:
47410217Sphk		ct_e1_config (b, cfg);
47559656Siwasaki		return 0;
47615177Snate	default:
47759656Siwasaki		return cfg == CFG_A ? 0 : -1;
47859656Siwasaki	}
47959656Siwasaki}
48010217Sphk
48110217Sphkint ct_get_dpll (ct_chan_t *c)
48215177Snate{
48310217Sphk	return (c->hopt.rxs == CLK_RXS_DPLL_INT);
48459656Siwasaki}
48559656Siwasaki
48610217Sphkvoid ct_set_dpll (ct_chan_t *c, int on)
48710217Sphk{
48859656Siwasaki	if (on && ct_get_baud (c))
48959656Siwasaki		c->hopt.rxs = CLK_RXS_DPLL_INT;
49059656Siwasaki	else
49110217Sphk		c->hopt.rxs = CLK_LINE;
49210217Sphk	ct_update_chan (c);
49315177Snate}
49415177Snate
49510217Sphkint ct_get_nrzi (ct_chan_t *c)
49610217Sphk{
49710217Sphk	return (c->opt.md2.encod == MD2_ENCOD_NRZI);
49815177Snate}
49959656Siwasaki
50010217Sphk/*
50110217Sphk * Change line encoding to NRZI, default is NRZ
50215177Snate */
50315177Snatevoid ct_set_nrzi (ct_chan_t *c, int on)
50476343Sdmlb{
50510217Sphk	c->opt.md2.encod = on ? MD2_ENCOD_NRZI : MD2_ENCOD_NRZ;
50676343Sdmlb	outb (c->MD2, *(unsigned char*)&c->opt.md2);
50710217Sphk}
50810217Sphk
50959656Siwasaki/*
51010217Sphk * Transmit clock inversion
51176343Sdmlb */
51210217Sphkvoid ct_set_invtxc (ct_chan_t *c, int on)
51310217Sphk{
51459656Siwasaki	if (on) c->board->bcr2 |=  (c->num ? BCR2_INVTXC1 : BCR2_INVTXC0);
51559656Siwasaki	else	c->board->bcr2 &= ~(c->num ? BCR2_INVTXC1 : BCR2_INVTXC0);
51610217Sphk	outb (BCR2(c->board->port), c->board->bcr2);
51776343Sdmlb}
51859656Siwasaki
51959656Siwasakiint ct_get_invtxc (ct_chan_t *c)
52059656Siwasaki{
52110217Sphk	return (c->board->bcr2 & (c->num ? BCR2_INVTXC1 : BCR2_INVTXC0)) != 0;
52210217Sphk}
52310217Sphk
52415177Snate/*
52510217Sphk * Receive clock inversion
52659656Siwasaki */
52759656Siwasakivoid ct_set_invrxc (ct_chan_t *c, int on)
52859656Siwasaki{
52910217Sphk	if (on) c->board->bcr2 |=  (c->num ? BCR2_INVRXC1 : BCR2_INVRXC0);
53059656Siwasaki	else	c->board->bcr2 &= ~(c->num ? BCR2_INVRXC1 : BCR2_INVRXC0);
53159656Siwasaki	outb (BCR2(c->board->port), c->board->bcr2);
53259656Siwasaki}
53315177Snate
53459656Siwasakiint ct_get_invrxc (ct_chan_t *c)
53559656Siwasaki{
53610217Sphk	return (c->board->bcr2 & (c->num ? BCR2_INVRXC1 : BCR2_INVRXC0)) != 0;
53715177Snate}
53810217Sphk
53959656Siwasaki/*
54015177Snate * Main interrupt handler
54159656Siwasaki */
54210217Sphkvoid ct_int_handler (ct_board_t *b)
54310217Sphk{
54415177Snate	unsigned char bsr0, imvr;
54510217Sphk	ct_chan_t *c;
54615177Snate
54710217Sphk	while ((bsr0 = inb (BSR0(b->port))) & BSR0_INTR) {
54810217Sphk		if (bsr0 & BSR0_RDYERR) {
54910217Sphk			outb (BCR1(b->port), b->bcr1);
55010217Sphk		} else if (bsr0 & BSR0_GINT) {
55110217Sphk			if (b->type == B_TAU_E1 || b->type == B_TAU_E1C ||
55210217Sphk			    b->type == B_TAU_E1D || b->type == B_TAU2_E1 ||
55310217Sphk			    b->type == B_TAU2_E1D)
55410217Sphk				ct_e1_interrupt (b);
55510217Sphk		} else if (bsr0 & BSR0_HDINT) {
55610217Sphk			/* Read the interrupt modified vector register. */
55710217Sphk			imvr = inb (IACK(b->port));
55810217Sphk			c = b->chan + (imvr & IMVR_CHAN1 ? 1 : 0);
55910217Sphk			ct_hdlc_interrupt (c, imvr);
56010217Sphk		}
56110217Sphk	}
56210217Sphk}
56310217Sphk
56410217Sphkstatic void ct_e1_interrupt (ct_board_t *b)
56516487Snate{
56610217Sphk	unsigned char sr;
56710217Sphk
56815177Snate	sr = inb (E1SR(b->port));
56915177Snate
57015177Snate	if (sr & E1SR_SCC_IRQ) ct_scc_interrupt (b);
57115177Snate	if (sr & E1SR_E0_IRQ1) ct_e1timer_interrupt (b->chan + 0);
57210217Sphk	if (sr & E1SR_E1_IRQ1) ct_e1timer_interrupt (b->chan + 1);
57310217Sphk}
57415177Snate
57515177Snatestatic void ct_scc_interrupt (ct_board_t *b)
57615177Snate{
57715177Snate	unsigned char rsr;
57810217Sphk	unsigned char ivr, a = AM_A;		/* assume channel A */
57910217Sphk	ct_chan_t *c = b->chan;
58015177Snate
58110217Sphk	ivr = cte_in2 (b->port, AM_IVR);
58210217Sphk	if (! (ivr & IVR_A))
58315177Snate		++c, a = 0;			/* really channel B */
58415177Snate
58559656Siwasaki	switch (ivr & IVR_REASON) {
58610217Sphk	case IVR_TXRDY: 			/* transmitter empty */
58759656Siwasaki		c->scctx_b = (c->scctx_b + 1) % SCCBUFSZ;
58815177Snate		if (c->scctx_b == c->scctx_e) {
58910217Sphk			c->scctx_empty = 1;
59015177Snate			cte_out2c (c, AM_CR | CR_RST_TXINT);
59115177Snate		} else
59210217Sphk			cte_out2d (c, c->scctx[c->scctx_b]);
59310217Sphk		break;
59410217Sphk
59510217Sphk	case IVR_RXERR: 		/* receive error */
59635310Snate	case IVR_RX:			/* receive character available */
59735310Snate		rsr = cte_in2 (b->port, a|AM_RSR);
59815177Snate
59915177Snate		if (rsr & RSR_RXOVRN) { 	/* rx overrun */
60015177Snate			if (c->call_on_err)
60115177Snate				c->call_on_err (c, CT_SCC_OVERRUN);
60215177Snate		} else if (rsr & RSR_FRME) {	/* frame error */
60315177Snate			if (c->call_on_err)
60415177Snate				c->call_on_err (c, CT_SCC_FRAME);
60515177Snate		} else {
60610217Sphk			c->sccrx[c->sccrx_e] = cte_in2d (c);
60759656Siwasaki			c->sccrx_e = (c->sccrx_e + 1) % SCCBUFSZ;
60815177Snate			c->sccrx_empty &= 0;
60910217Sphk			if (c->call_on_scc)
61015177Snate				c->call_on_scc (c);
61115177Snate			if (c->sccrx_e == c->sccrx_b && ! c->sccrx_empty)
61215177Snate				if (c->call_on_err)
61310217Sphk					c->call_on_err (c, CT_SCC_OVERFLOW);
61415177Snate		}
61510217Sphk		if (rsr)
61610217Sphk			cte_out2c (c, CR_RST_ERROR);
61710217Sphk		break;
61816487Snate
61910217Sphk	case IVR_STATUS:		/* external status interrupt */
62010217Sphk		/* Unexpected SCC status interrupt. */
62115177Snate		cte_out2c (c, CR_RST_EXTINT);
62215177Snate		break;
62315177Snate	}
62415177Snate}
62515177Snate
62659656Siwasaki/*
62759656Siwasaki * G.703 mode channel: process 1-second timer interrupts.
62859656Siwasaki * Read error and request registers, and fill the status field.
62959656Siwasaki */
63010217Sphkvoid ct_g703_timer (ct_chan_t *c)
63115177Snate{
63210217Sphk	int bpv, cd, tsterr, tstreq;
63310217Sphk
63415177Snate	/* Count seconds.
63510217Sphk	 * During the first second after the channel startup
63610217Sphk	 * the status registers are not stable yet,
63710217Sphk	 * we will so skip the first second. */
63810217Sphk	++c->cursec;
63910217Sphk	if (c->mode != M_G703)
64015177Snate		return;
64115177Snate	if (c->totsec + c->cursec <= 1)
64230171Scharnier		return;
64310217Sphk	c->status = 0;
64415177Snate
64510217Sphk	cd = ct_get_cd (c);
64610217Sphk
64710217Sphk	bpv = inb (GERR (c->board->port)) & (c->num ? GERR_BPV1 : GERR_BPV0);
64810217Sphk	outb (GERR (c->board->port), bpv);
64910217Sphk
65059656Siwasaki	tsterr = inb (GERR (c->board->port)) & (c->num ? GERR_ERR1 : GERR_ERR0);
65159656Siwasaki	outb (GERR (c->board->port), tsterr);
65259656Siwasaki
65359656Siwasaki	tstreq = inb (GLDR (c->board->port)) &
65459656Siwasaki		(c->num ? GLDR_LREQ1 : GLDR_LREQ0);
65559656Siwasaki	outb (GLDR (c->board->port), tstreq);
65659656Siwasaki
65759656Siwasaki	/* Compute the SNMP-compatible channel status. */
65859656Siwasaki	if (bpv)
65959656Siwasaki		++c->currnt.bpv;	  /* bipolar violation */
66015177Snate	if (! cd)
66110217Sphk		c->status |= ESTS_LOS;	  /* loss of signal */
66210217Sphk	if (tsterr)
66321371Snate		c->status |= ESTS_TSTERR; /* test error */
66410217Sphk	if (tstreq)
66515177Snate		c->status |= ESTS_TSTREQ; /* test code detected */
66610217Sphk
66710217Sphk	if (! c->status)
66815177Snate		c->status = ESTS_NOALARM;
66915177Snate
67010217Sphk	/* Unavaiable second -- loss of carrier, or receiving test code. */
67110217Sphk	if ((! cd) || tstreq)
67215177Snate		/* Unavailable second -- no other counters. */
67330171Scharnier		++c->currnt.uas;
67410217Sphk	else {
67510217Sphk		/* Line errored second -- any BPV. */
67615177Snate		if (bpv)
67715177Snate			++c->currnt.les;
67815177Snate
67915177Snate		/* Collect data for computing
68015177Snate		 * degraded minutes. */
68115177Snate		++c->degsec;
68210217Sphk		if (cd && bpv)
68359656Siwasaki			++c->degerr;
68459656Siwasaki	}
68559656Siwasaki
68659656Siwasaki	/* Degraded minutes -- having more than 50% error intervals. */
68759656Siwasaki	if (c->cursec / 60 == 0) {
68859656Siwasaki		if (c->degerr*2 > c->degsec)
68959656Siwasaki			++c->currnt.dm;
69059656Siwasaki		c->degsec = 0;
69159656Siwasaki		c->degerr = 0;
69259656Siwasaki	}
69359656Siwasaki
69459656Siwasaki	/* Rotate statistics every 15 minutes. */
695112233Simp	if (c->cursec > 15*60) {
69610217Sphk		int i;
69710217Sphk
69815177Snate		for (i=47; i>0; --i)
69959656Siwasaki			c->interval[i] = c->interval[i-1];
70010217Sphk		c->interval[0] = c->currnt;
70110217Sphk
70210217Sphk		/* Accumulate total statistics. */
70310217Sphk		c->total.bpv   += c->currnt.bpv;
70415177Snate		c->total.fse   += c->currnt.fse;
70515177Snate		c->total.crce  += c->currnt.crce;
70610217Sphk		c->total.rcrce += c->currnt.rcrce;
70715177Snate		c->total.uas   += c->currnt.uas;
70810217Sphk		c->total.les   += c->currnt.les;
70910217Sphk		c->total.es    += c->currnt.es;
71010217Sphk		c->total.bes   += c->currnt.bes;
71116487Snate		c->total.ses   += c->currnt.ses;
71210217Sphk		c->total.oofs  += c->currnt.oofs;
71310217Sphk		c->total.css   += c->currnt.css;
71415177Snate		c->total.dm    += c->currnt.dm;
71510217Sphk		memset (&c->currnt, 0, sizeof (c->currnt));
71610217Sphk
71710217Sphk		c->totsec += c->cursec;
71810217Sphk		c->cursec = 0;
71915177Snate	}
72010217Sphk}
72110217Sphk
72210217Sphkstatic void ct_e1timer_interrupt (ct_chan_t *c)
72310217Sphk{
72410217Sphk	unsigned short port;
72515177Snate	unsigned char sr1, sr2, ssr;
72615177Snate	unsigned long bpv, fas, crc4, ebit, pcv, oof;
72710217Sphk
72815177Snate	port = c->num ? E1CS1(c->board->port) : E1CS0(c->board->port);
72910217Sphk
73010217Sphk	sr2 = cte_ins (port, DS_SR2, 0xff);
73110217Sphk	/* is it timer interrupt ? */
73210217Sphk	if (! (sr2 & SR2_SEC))
73316487Snate		return;
73410217Sphk
73510217Sphk	/* first interrupts should be ignored */
73615177Snate	if (c->e1_first_int > 0) {
73710217Sphk		c->e1_first_int --;
73810217Sphk		return;
73910217Sphk	}
74010217Sphk
74115177Snate	++c->cursec;
74210217Sphk	c->status = 0;
74315177Snate
74410217Sphk	/* Compute the SNMP-compatible channel status. */
74510217Sphk	sr1 = cte_ins (port, DS_SR1, 0xff);
74610217Sphk	ssr = cte_in (port, DS_SSR);
74715177Snate	oof = 0;
74815177Snate
749111507Sgreen	if (sr1 & (SR1_RCL | SR1_RLOS))
750111507Sgreen		c->status |= ESTS_LOS;		/* loss of signal */
751111507Sgreen	if (sr1 & SR1_RUA1)
75215177Snate		c->status |= ESTS_AIS;		/* receiving all ones */
75315177Snate	if (c->gopt.cas && (sr1 & SR1_RSA1))
75415177Snate		c->status |= ESTS_AIS16;	/* signaling all ones */
75515177Snate	if (c->gopt.cas && (sr1 & SR1_RDMA))
75615177Snate		c->status |= ESTS_FARLOMF;	/* alarm in timeslot 16 */
75715177Snate	if (sr1 & SR1_RRA)
75815177Snate		c->status |= ESTS_FARLOF;	/* far loss of framing */
75915177Snate
76010217Sphk	/* Controlled slip second -- any slip event. */
76110217Sphk	if (sr1 & SR1_RSLIP) {
76210217Sphk		++c->currnt.css;
76315177Snate	}
76415177Snate
76510217Sphk	if (ssr & SSR_SYNC) {
76615177Snate		c->status |= ESTS_LOF;		/* loss of framing */
76710217Sphk		++oof;				/* out of framing */
76810217Sphk	}
76910217Sphk	if ((c->gopt.cas && (ssr & SSR_SYNC_CAS)) ||
77016487Snate	    (c->gopt.crc4 && (ssr & SSR_SYNC_CRC4))) {
77110217Sphk		c->status |= ESTS_LOMF; 	/* loss of multiframing */
77210217Sphk		++oof;				/* out of framing */
77315177Snate	}
77410217Sphk
77510217Sphk	if (! c->status)
77610217Sphk		c->status = ESTS_NOALARM;
77715177Snate
77815177Snate	/* Get error counters. */
77910217Sphk	bpv = VCR (cte_in (port, DS_VCR1), cte_in (port, DS_VCR2));
78015177Snate	fas = FASCR (cte_in (port, DS_FASCR1), cte_in (port, DS_FASCR2));
78116487Snate	crc4 = CRCCR (cte_in (port, DS_CRCCR1), cte_in (port, DS_CRCCR2));
78210217Sphk	ebit = EBCR (cte_in (port, DS_EBCR1), cte_in (port, DS_EBCR2));
78310217Sphk
78415177Snate	c->currnt.bpv += bpv;
78510217Sphk	c->currnt.fse += fas;
78610217Sphk	if (c->gopt.crc4) {
78710217Sphk		c->currnt.crce += crc4;
78815177Snate		c->currnt.rcrce += ebit;
78915177Snate	}
79010217Sphk
791	/* Path code violation is frame sync error if CRC4 disabled,
792	 * or CRC error if CRC4 enabled. */
793	pcv = fas;
794	if (c->gopt.crc4)
795		pcv += crc4;
796
797	/* Unavaiable second -- receiving all ones, or
798	 * loss of carrier, or loss of signal. */
799	if (sr1 & (SR1_RUA1 | SR1_RCL | SR1_RLOS))
800		/* Unavailable second -- no other counters. */
801		++c->currnt.uas;
802	else {
803		/* Line errored second -- any BPV. */
804		if (bpv)
805			++c->currnt.les;
806
807		/* Errored second -- any PCV, or out of frame sync,
808		 * or any slip events. */
809		if (pcv || oof || (sr1 & SR1_RSLIP))
810			++c->currnt.es;
811
812		/* Severely errored framing second -- out of frame sync. */
813		if (oof)
814			++c->currnt.oofs;
815
816		/* Severely errored seconds --
817		 * 832 or more PCVs, or 2048 or more BPVs. */
818		if (bpv >= 2048 || pcv >= 832)
819			++c->currnt.ses;
820		else {
821			/* Bursty errored seconds --
822			 * no SES and more than 1 PCV. */
823			if (pcv > 1)
824				++c->currnt.bes;
825
826			/* Collect data for computing
827			 * degraded minutes. */
828			++c->degsec;
829			c->degerr += bpv + pcv;
830		}
831	}
832
833	/* Degraded minutes -- having error rate more than 10e-6,
834	 * not counting unavailable and severely errored seconds. */
835	if (c->cursec / 60 == 0) {
836		if (c->degerr > c->degsec * 2048 / 1000)
837			++c->currnt.dm;
838		c->degsec = 0;
839		c->degerr = 0;
840	}
841
842	/* Rotate statistics every 15 minutes. */
843	if (c->cursec > 15*60) {
844		int i;
845
846		for (i=47; i>0; --i)
847			c->interval[i] = c->interval[i-1];
848		c->interval[0] = c->currnt;
849
850		/* Accumulate total statistics. */
851		c->total.bpv   += c->currnt.bpv;
852		c->total.fse   += c->currnt.fse;
853		c->total.crce  += c->currnt.crce;
854		c->total.rcrce += c->currnt.rcrce;
855		c->total.uas   += c->currnt.uas;
856		c->total.les   += c->currnt.les;
857		c->total.es    += c->currnt.es;
858		c->total.bes   += c->currnt.bes;
859		c->total.ses   += c->currnt.ses;
860		c->total.oofs  += c->currnt.oofs;
861		c->total.css   += c->currnt.css;
862		c->total.dm    += c->currnt.dm;
863		for (i=0; i<sizeof (c->currnt); ++i)
864			*(((char *)(&c->currnt))+i)=0;
865
866		c->totsec += c->cursec;
867		c->cursec = 0;
868	}
869}
870
871static void ct_hdlc_interrupt (ct_chan_t *c, int imvr)
872{
873	int i, dsr, st1, st2, cda;
874
875	switch (imvr & IMVR_VECT_MASK) {
876	case IMVR_RX_DMOK:		/* receive DMA normal end */
877		dsr = inb (c->RX.DSR);
878		cda = inw (c->RX.CDA);
879		for (i=0; i<NBUF; ++i)
880			if (cda == (unsigned short) c->rdphys[i])
881				break;
882		if (i >= NBUF)
883			i = c->rn; /* cannot happen */
884		while (c->rn != i) {
885			int cst = B_STATUS (c->rdesc[c->rn]);
886			if (cst == FST_EOM) {
887				/* process data */
888				if (c->call_on_rx)
889					 c->call_on_rx (c, c->rbuf[c->rn],
890						B_LEN(c->rdesc[c->rn]));
891				++c->ipkts;
892				c->ibytes += B_LEN(c->rdesc[c->rn]);
893			} else if (cst & ST2_OVRN) {
894				/* Receive overrun error */
895				if (c->call_on_err)
896					c->call_on_err (c, CT_OVERRUN);
897				++c->ierrs;
898			} else if (cst & (ST2_HDLC_RBIT |
899				ST2_HDLC_ABT | ST2_HDLC_SHRT)) {
900				/* Receive frame error */
901				if (c->call_on_err)
902					c->call_on_err (c, CT_FRAME);
903				++c->ierrs;
904			} else if ((cst & ST2_HDLC_EOM)
905				&& (cst & ST2_HDLC_CRCE)) {
906				/* Receive CRC error */
907				if (c->call_on_err)
908					c->call_on_err (c, CT_CRC);
909				++c->ierrs;
910			} else if (! (cst & ST2_HDLC_EOM)) {
911				/* Frame dose not fit in the buffer.*/
912				if (c->call_on_err)
913					c->call_on_err (c, CT_OVERFLOW);
914				++c->ierrs;
915			}
916
917			B_NEXT (c->rdesc[c->rn]) =
918				c->rdphys[(c->rn+1) % NBUF] & 0xffff;
919			B_PTR (c->rdesc[c->rn]) = c->rphys[c->rn];
920			B_LEN (c->rdesc[c->rn]) = DMABUFSZ;
921			B_STATUS (c->rdesc[c->rn]) = 0;
922			c->rn = (c->rn + 1) % NBUF;
923		}
924		outw (c->RX.EDA, (unsigned short) c->rdphys[(i+NBUF-1)%NBUF]);
925		/* Clear DMA interrupt. */
926		if (inb (c->RX.DSR) & DSR_DMA_ENABLE) {
927			outb (c->RX.DSR, dsr);
928		} else {
929			outb (c->RX.DSR, (dsr & 0xfc) | DSR_DMA_ENABLE);
930		}
931		++c->rintr;
932		break;
933
934	case IMVR_RX_INT:		/* receive status */
935		st1 = inb (c->ST1);
936		st2 = inb (c->ST2);
937		if (st1 & ST1_CDCD){
938			if (c->call_on_msig)
939				c->call_on_msig (c);
940			++c->mintr;
941		}
942		/* Clear interrupt. */
943		outb (c->ST1, st1);
944		outb (c->ST2, st2);
945		++c->rintr;
946		break;
947
948	case IMVR_RX_DMERR:		/* receive DMA error */
949		dsr = inb (c->RX.DSR);
950		if (dsr & (DSR_CHAIN_BOF | DSR_CHAIN_COF)) {
951			if (c->call_on_err)
952				c->call_on_err (c, CT_OVERFLOW);
953			++c->ierrs;
954			for (i=0; i<NBUF; ++i) {
955				B_LEN (c->rdesc[i]) = DMABUFSZ;
956				B_STATUS (c->rdesc[i]) = 0;
957			}
958			ct_start_receiver (c, 1, c->rphys[0], DMABUFSZ,
959				c->rdphys[0], c->rdphys[NBUF-1]);
960			c->rn = 0;
961		}
962		/* Clear DMA interrupt. */
963		outb (c->RX.DSR, dsr);
964		++c->rintr;
965		break;
966
967	case IMVR_TX_DMOK:		/* transmit DMA normal end */
968	case IMVR_TX_DMERR:		/* transmit DMA error	   */
969		dsr = inb (c->TX.DSR);
970		cda = inw (c->TX.CDA);
971
972		for (i=0; i<NBUF && cda != (unsigned short)c->tdphys[i]; ++i)
973			continue;
974		if (i >= NBUF)
975			i = 1; /* cannot happen */
976		if (dsr & DSR_CHAIN_COF) {
977			if (c->call_on_err)
978				c->call_on_err (c, CT_UNDERRUN);
979			++c->oerrs;
980		}
981		while (c->tn != i) {
982			if (c->call_on_tx)
983				c->call_on_tx (c, c->attach[c->tn],
984					B_LEN(c->tdesc[c->tn]));
985			++c->opkts;
986			c->obytes += B_LEN(c->tdesc[c->tn]);
987
988			c->tn = (c->tn + 1) % NBUF;
989			/* Clear DMA interrupt. */
990			outb (c->TX.DSR, DSR_CHAIN_EOM | DSR_DMA_CONTINUE);
991		}
992		outb (c->TX.DSR, dsr & ~DSR_CHAIN_EOM);
993		++c->tintr;
994		break;
995
996	case IMVR_TX_INT:		/* transmit error, HDLC only */
997		st1 = inb (c->ST1);
998		if (st1 & ST1_HDLC_UDRN) {
999			if (c->call_on_err)
1000				c->call_on_err (c, CT_UNDERRUN);
1001			++c->oerrs;
1002		}
1003		outb (c->ST1, st1);
1004		++c->tintr;
1005		break;
1006
1007	default:
1008		/* Unknown interrupt - cannot happen. */
1009		break;
1010	}
1011}
1012
1013int ct_receive_enabled (ct_chan_t *c)
1014{
1015	int st3;
1016
1017	st3 = inb (c->ST3);
1018	return (st3 & ST3_RX_ENABLED) ? 1 : 0;
1019}
1020
1021int ct_transmit_enabled (ct_chan_t *c)
1022{
1023	int st3;
1024
1025	st3 = inb (c->ST3);
1026	return (st3 & ST3_TX_ENABLED) ? 1 : 0;
1027}
1028
1029int ct_buf_free (ct_chan_t *c)
1030{
1031	return (NBUF + c->tn - c->te - 1) % NBUF;
1032}
1033
1034int ct_send_packet (ct_chan_t *c, unsigned char *data, int len,
1035	void *attachment)
1036{
1037	int dsr, ne;
1038
1039	if (len > DMABUFSZ)
1040		return -2;
1041
1042	/* Is it really free? */
1043	ne = (c->te+1) % NBUF;
1044	if (ne == c->tn)
1045		return -1;
1046
1047	/* Set up the tx descriptor. */
1048	B_LEN (c->tdesc[c->te]) = len;
1049	B_STATUS (c->tdesc[c->te]) = FST_EOM;
1050	c->attach[c->te] = attachment;
1051	if (c->tbuf[c->te] != data)
1052		memcpy (c->tbuf[c->te], data, len);
1053
1054	/* Start the transmitter. */
1055	c->te = ne;
1056	outw (c->TX.EDA, (unsigned short) c->tdphys[ne]);
1057	dsr = inb (c->TX.DSR);
1058	if (! (dsr & DSR_DMA_ENABLE))
1059		outb (c->TX.DSR, DSR_DMA_ENABLE);
1060	return 0;
1061}
1062
1063int scc_write (ct_chan_t *c, unsigned char *d, int len)
1064{
1065	int i, free;
1066
1067	/* determining free place in buffer */
1068	if (c->scctx_empty)
1069		free = SCCBUFSZ;
1070	else
1071		free = (SCCBUFSZ + c->scctx_b - c->scctx_e) % SCCBUFSZ;
1072
1073	if (len > free)
1074		return -1;
1075
1076	for (i=0; i<len; i++){
1077		c->scctx[c->scctx_e] = d[i];
1078		c->scctx_e = (c->scctx_e+1) % SCCBUFSZ;
1079	}
1080	if (c->scctx_empty && len) {
1081		cte_out2d (c, c->scctx[c->scctx_b]);
1082		c->scctx_empty = 0;
1083	}
1084	return 0;
1085}
1086
1087int scc_read (ct_chan_t *c, unsigned char *d, int len)
1088{
1089	int i, bytes;
1090
1091	if (c->sccrx_empty)
1092		bytes = 0;
1093	else
1094		bytes = (SCCBUFSZ + c->sccrx_e - 1 - c->sccrx_b) %
1095				SCCBUFSZ + 1;
1096	if (len > bytes)
1097		return -1;
1098
1099	for (i=0; i<len; i++){
1100		d[i] = c->sccrx[c->sccrx_b];
1101		c->sccrx_b = (c->sccrx_b+1) % SCCBUFSZ;
1102	}
1103	if (c->sccrx_b==c->sccrx_e)
1104		c->sccrx_empty = 1;
1105	return 0;
1106}
1107
1108int sccrx_check (ct_chan_t *c)
1109{
1110	int bytes;
1111
1112	if (c->sccrx_empty)
1113		bytes = 0;
1114	else
1115		bytes = (SCCBUFSZ + c->sccrx_e - 1 - c->sccrx_b) %
1116				SCCBUFSZ + 1;
1117	return bytes;
1118}
1119
1120int scc_read_byte (ct_chan_t *c)
1121{
1122	unsigned char a;
1123
1124	if (scc_read (c, &a, 1) < 0)
1125		return -1;
1126	return a;
1127}
1128
1129int scc_write_byte (ct_chan_t *c, unsigned char b)
1130{
1131	if (scc_write (c, &b, 1) < 0)
1132		return -1;
1133	return b;
1134}
1135
1136/*
1137 * Register event processing functions
1138 */
1139void ct_register_transmit (ct_chan_t *c, void (*func) (ct_chan_t*, void*, int))
1140{
1141	c->call_on_tx = func;
1142}
1143
1144void ct_register_receive (ct_chan_t *c, void (*func) (ct_chan_t*, char*, int))
1145{
1146	c->call_on_rx = func;
1147}
1148
1149void ct_register_error (ct_chan_t *c, void (*func) (ct_chan_t*, int))
1150{
1151	c->call_on_err = func;
1152}
1153
1154void ct_register_scc (ct_chan_t *c, void (*func) (ct_chan_t*))
1155{
1156	c->call_on_scc = func;
1157}
1158
1159void ct_register_modem (ct_chan_t *c, void (*func) (ct_chan_t*))
1160{
1161	c->call_on_msig = func;
1162}
1163