⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hfc_2bds0.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: hfc_2bds0.c,v 1.18.2.6 2004/02/11 13:21:33 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * * Author       Karsten Keil * Copyright    by Karsten Keil      <keil@isdn4linux.de> *  * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/init.h>#include "hisax.h"#include "hfc_2bds0.h"#include "isdnl1.h"#include <linux/interrupt.h>/*#define KDEBUG_DEF#include "kdebug.h"*/#define byteout(addr,val) outb(val,addr)#define bytein(addr) inb(addr)static voiddummyf(struct IsdnCardState *cs, u_char * data, int size){	printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n");}static inline u_charReadReg(struct IsdnCardState *cs, int data, u_char reg){	register u_char ret;	if (data) {		if (cs->hw.hfcD.cip != reg) { 			cs->hw.hfcD.cip = reg;			byteout(cs->hw.hfcD.addr | 1, reg);		}		ret = bytein(cs->hw.hfcD.addr);#ifdef HFC_REG_DEBUG		if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))			debugl1(cs, "t3c RD %02x %02x", reg, ret);#endif	} else		ret = bytein(cs->hw.hfcD.addr | 1);	return (ret);}static inline voidWriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value){	if (cs->hw.hfcD.cip != reg) { 		cs->hw.hfcD.cip = reg;		byteout(cs->hw.hfcD.addr | 1, reg);	}	if (data)		byteout(cs->hw.hfcD.addr, value);#ifdef HFC_REG_DEBUG	if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB))		debugl1(cs, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value);#endif}/* Interface functions */static u_charreadreghfcd(struct IsdnCardState *cs, u_char offset){	return(ReadReg(cs, HFCD_DATA, offset));}static voidwritereghfcd(struct IsdnCardState *cs, u_char offset, u_char value){	WriteReg(cs, HFCD_DATA, offset, value);}static inline intWaitForBusy(struct IsdnCardState *cs){	int to = 130;	while (!(ReadReg(cs, HFCD_DATA, HFCD_STAT) & HFCD_BUSY) && to) {		udelay(1);		to--;	}	if (!to)		printk(KERN_WARNING "HiSax: WaitForBusy timeout\n");	return (to);}static inline intWaitNoBusy(struct IsdnCardState *cs){	int to = 130;	while ((ReadReg(cs, HFCD_STATUS, HFCD_STATUS) & HFCD_BUSY) && to) {		udelay(1);		to--;	}	if (!to) 		printk(KERN_WARNING "HiSax: WaitNoBusy timeout\n");	return (to);}static intSelFiFo(struct IsdnCardState *cs, u_char FiFo){	u_char cip;	if (cs->hw.hfcD.fifo == FiFo)		return(1);	switch(FiFo) {		case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1;			break;		case 1: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B1;			break;		case 2: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B2;			break;		case 3: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B2;			break;		case 4: cip = HFCD_FIFO | HFCD_Z1 | HFCD_SEND;			break;		case 5: cip = HFCD_FIFO | HFCD_Z1 | HFCD_REC;			break;		default:			debugl1(cs, "SelFiFo Error");			return(0);	}	cs->hw.hfcD.fifo = FiFo;	WaitNoBusy(cs);	cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0);	WaitForBusy(cs);	return(2);}static intGetFreeFifoBytes_B(struct BCState *bcs){	int s;	if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)		return (bcs->cs->hw.hfcD.bfifosize);	s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];	if (s <= 0)		s += bcs->cs->hw.hfcD.bfifosize;	s = bcs->cs->hw.hfcD.bfifosize - s;	return (s);}static intGetFreeFifoBytes_D(struct IsdnCardState *cs){	int s;	if (cs->hw.hfcD.f1 == cs->hw.hfcD.f2)		return (cs->hw.hfcD.dfifosize);	s = cs->hw.hfcD.send[cs->hw.hfcD.f1] - cs->hw.hfcD.send[cs->hw.hfcD.f2];	if (s <= 0)		s += cs->hw.hfcD.dfifosize;	s = cs->hw.hfcD.dfifosize - s;	return (s);}static intReadZReg(struct IsdnCardState *cs, u_char reg){	int val;	WaitNoBusy(cs);	val = 256 * ReadReg(cs, HFCD_DATA, reg | HFCB_Z_HIGH);	WaitNoBusy(cs);	val += ReadReg(cs, HFCD_DATA, reg | HFCB_Z_LOW);	return (val);}static struct sk_buff*hfc_empty_fifo(struct BCState *bcs, int count){	u_char *ptr;	struct sk_buff *skb;	struct IsdnCardState *cs = bcs->cs;	int idx;	int chksum;	u_char stat, cip;		if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))		debugl1(cs, "hfc_empty_fifo");	idx = 0;	if (count > HSCX_BUFMAX + 3) {		if (cs->debug & L1_DEB_WARN)			debugl1(cs, "hfc_empty_fifo: incoming packet too large");		cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);		while (idx++ < count) {			WaitNoBusy(cs);			ReadReg(cs, HFCD_DATA_NODEB, cip);		}		skb = NULL;	} else if (count < 4) {		if (cs->debug & L1_DEB_WARN)			debugl1(cs, "hfc_empty_fifo: incoming packet too small");		cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);#ifdef ERROR_STATISTIC		bcs->err_inv++;#endif		while ((idx++ < count) && WaitNoBusy(cs))			ReadReg(cs, HFCD_DATA_NODEB, cip);		skb = NULL;	} else if (!(skb = dev_alloc_skb(count - 3)))		printk(KERN_WARNING "HFC: receive out of memory\n");	else {		ptr = skb_put(skb, count - 3);		idx = 0;		cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel);		while (idx < (count - 3)) {			if (!WaitNoBusy(cs))				break;			*ptr = ReadReg(cs,  HFCD_DATA_NODEB, cip);			ptr++;			idx++;		}		if (idx != count - 3) {			debugl1(cs, "RFIFO BUSY error");			printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);			dev_kfree_skb_irq(skb);			skb = NULL;		} else {			WaitNoBusy(cs);			chksum = (ReadReg(cs, HFCD_DATA, cip) << 8);			WaitNoBusy(cs);			chksum += ReadReg(cs, HFCD_DATA, cip);			WaitNoBusy(cs);			stat = ReadReg(cs, HFCD_DATA, cip);			if (cs->debug & L1_DEB_HSCX)				debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",					bcs->channel, chksum, stat);			if (stat) {				debugl1(cs, "FIFO CRC error");				dev_kfree_skb_irq(skb);				skb = NULL;#ifdef ERROR_STATISTIC				bcs->err_crc++;#endif			}		}	}	WaitForBusy(cs);	WaitNoBusy(cs);	stat = ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F2_INC |		HFCB_REC | HFCB_CHANNEL(bcs->channel));	WaitForBusy(cs);	return (skb);}static voidhfc_fill_fifo(struct BCState *bcs){	struct IsdnCardState *cs = bcs->cs;	int idx, fcnt;	int count;	u_char cip;	if (!bcs->tx_skb)		return;	if (bcs->tx_skb->len <= 0)		return;	SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel)); 	cip = HFCB_FIFO | HFCB_F1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);	WaitNoBusy(cs);	bcs->hw.hfc.f1 = ReadReg(cs, HFCD_DATA, cip);	WaitNoBusy(cs);	cip = HFCB_FIFO | HFCB_F2 | HFCB_SEND | HFCB_CHANNEL(bcs->channel);	WaitNoBusy(cs);	bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip);	bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); 	if (cs->debug & L1_DEB_HSCX)		debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",			bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,			bcs->hw.hfc.send[bcs->hw.hfc.f1]);	fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;	if (fcnt < 0)		fcnt += 32;	if (fcnt > 30) {		if (cs->debug & L1_DEB_HSCX)			debugl1(cs, "hfc_fill_fifo more as 30 frames");		return;	}	count = GetFreeFifoBytes_B(bcs);	if (cs->debug & L1_DEB_HSCX)		debugl1(cs, "hfc_fill_fifo %d count(%ld/%d),%lx",			bcs->channel, bcs->tx_skb->len,			count, current->state);	if (count < bcs->tx_skb->len) {		if (cs->debug & L1_DEB_HSCX)			debugl1(cs, "hfc_fill_fifo no fifo mem");		return;	}	cip = HFCB_FIFO | HFCB_FIFO_IN | HFCB_SEND | HFCB_CHANNEL(bcs->channel);	idx = 0;	WaitForBusy(cs);	WaitNoBusy(cs);	WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);	while (idx < bcs->tx_skb->len) {		if (!WaitNoBusy(cs))			break;		WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]);		idx++;	}	if (idx != bcs->tx_skb->len) {		debugl1(cs, "FIFO Send BUSY error");		printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);	} else {		bcs->tx_cnt -= bcs->tx_skb->len;		if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&			(PACKET_NOACK != bcs->tx_skb->pkt_type)) {			u_long	flags;			spin_lock_irqsave(&bcs->aclock, flags);			bcs->ackcnt += bcs->tx_skb->len;			spin_unlock_irqrestore(&bcs->aclock, flags);			schedule_event(bcs, B_ACKPENDING);		}		dev_kfree_skb_any(bcs->tx_skb);		bcs->tx_skb = NULL;	}	WaitForBusy(cs);	WaitNoBusy(cs);	ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F1_INC | HFCB_SEND | HFCB_CHANNEL(bcs->channel));	WaitForBusy(cs);	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);	return;}static voidhfc_send_data(struct BCState *bcs){	struct IsdnCardState *cs = bcs->cs;		if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {		hfc_fill_fifo(bcs);		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);	} else		debugl1(cs,"send_data %d blocked", bcs->channel);}static voidmain_rec_2bds0(struct BCState *bcs){	struct IsdnCardState *cs = bcs->cs;	int z1, z2, rcnt;	u_char f1, f2, cip;	int receive, count = 5;	struct sk_buff *skb;    Begin:	count--;	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {		debugl1(cs,"rec_data %d blocked", bcs->channel);		return;	}	SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel));	cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel);	WaitNoBusy(cs);	f1 = ReadReg(cs, HFCD_DATA, cip);	cip = HFCB_FIFO | HFCB_F2 | HFCB_REC | HFCB_CHANNEL(bcs->channel);	WaitNoBusy(cs);	f2 = ReadReg(cs, HFCD_DATA, cip);	if (f1 != f2) {		if (cs->debug & L1_DEB_HSCX)			debugl1(cs, "hfc rec %d f1(%d) f2(%d)",				bcs->channel, f1, f2);		z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel));		z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel));		rcnt = z1 - z2;		if (rcnt < 0)			rcnt += cs->hw.hfcD.bfifosize;		rcnt++;		if (cs->debug & L1_DEB_HSCX)			debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",				bcs->channel, z1, z2, rcnt);		if ((skb = hfc_empty_fifo(bcs, rcnt))) {			skb_queue_tail(&bcs->rqueue, skb);			schedule_event(bcs, B_RCVBUFREADY);		}		rcnt = f1 -f2;		if (rcnt<0)			rcnt += 32;		if (rcnt>1)			receive = 1;		else			receive = 0;	} else		receive = 0;	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);	if (count && receive)		goto Begin;		return;}static voidmode_2bs0(struct BCState *bcs, int mode, int bc){	struct IsdnCardState *cs = bcs->cs;	if (cs->debug & L1_DEB_HSCX)		debugl1(cs, "HFCD bchannel mode %d bchan %d/%d",			mode, bc, bcs->channel);	bcs->mode = mode;	bcs->channel = bc;	switch (mode) {		case (L1_MODE_NULL):			if (bc) {				cs->hw.hfcD.conn |= 0x18;				cs->hw.hfcD.sctrl &= ~SCTRL_B2_ENA;			} else {				cs->hw.hfcD.conn |= 0x3;				cs->hw.hfcD.sctrl &= ~SCTRL_B1_ENA;			}			break;		case (L1_MODE_TRANS):			if (bc) {				cs->hw.hfcD.ctmt |= 2;				cs->hw.hfcD.conn &= ~0x18;				cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;			} else {				cs->hw.hfcD.ctmt |= 1;				cs->hw.hfcD.conn &= ~0x3;				cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;			}			break;		case (L1_MODE_HDLC):			if (bc) {				cs->hw.hfcD.ctmt &= ~2;				cs->hw.hfcD.conn &= ~0x18;				cs->hw.hfcD.sctrl |= SCTRL_B2_ENA;			} else {				cs->hw.hfcD.ctmt &= ~1;				cs->hw.hfcD.conn &= ~0x3;				cs->hw.hfcD.sctrl |= SCTRL_B1_ENA;			}			break;	}	WriteReg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);	WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);	WriteReg(cs, HFCD_DATA, HFCD_CONN, cs->hw.hfcD.conn);}static voidhfc_l2l1(struct PStack *st, int pr, void *arg){	struct BCState *bcs = st->l1.bcs;	struct sk_buff *skb = arg;	u_long flags;	switch (pr) {		case (PH_DATA | REQUEST):			spin_lock_irqsave(&bcs->cs->lock, flags);			if (bcs->tx_skb) {				skb_queue_tail(&bcs->squeue, skb);			} else {				bcs->tx_skb = skb;//				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);				bcs->cs->BC_Send_Data(bcs);			}			spin_unlock_irqrestore(&bcs->cs->lock, flags);			break;		case (PH_PULL | INDICATION):			spin_lock_irqsave(&bcs->cs->lock, flags);			if (bcs->tx_skb) {				printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");			} else {//				test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);				bcs->tx_skb = skb;				bcs->cs->BC_Send_Data(bcs);			}			spin_unlock_irqrestore(&bcs->cs->lock, flags);			break;		case (PH_PULL | REQUEST):			if (!bcs->tx_skb) {				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);			} else				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);			break;		case (PH_ACTIVATE | REQUEST):			spin_lock_irqsave(&bcs->cs->lock, flags);			test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);			mode_2bs0(bcs, st->l1.mode, st->l1.bc);			spin_unlock_irqrestore(&bcs->cs->lock, flags);			l1_msg_b(st, pr, arg);			break;		case (PH_DEACTIVATE | REQUEST):			l1_msg_b(st, pr, arg);			break;		case (PH_DEACTIVATE | CONFIRM):			spin_lock_irqsave(&bcs->cs->lock, flags);			test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);			mode_2bs0(bcs, 0, st->l1.bc);			spin_unlock_irqrestore(&bcs->cs->lock, flags);			st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);			break;	}}static voidclose_2bs0(struct BCState *bcs){	mode_2bs0(bcs, 0, bcs->channel);	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {		skb_queue_purge(&bcs->rqueue);		skb_queue_purge(&bcs->squeue);		if (bcs->tx_skb) {			dev_kfree_skb_any(bcs->tx_skb);			bcs->tx_skb = NULL;			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);		}	}}static intopen_hfcstate(struct IsdnCardState *cs, struct BCState *bcs){	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {		skb_queue_head_init(&bcs->rqueue);		skb_queue_head_init(&bcs->squeue);	}	bcs->tx_skb = NULL;	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);	bcs->event = 0;	bcs->tx_cnt = 0;	return (0);}static intsetstack_2b(struct PStack *st, struct BCState *bcs){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -