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

📄 hscx_irq.c

📁 linux-2.6.15.6
💻 C
字号:
/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $ * * low level b-channel stuff for Siemens HSCX * * 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. * * This is an include file for fast inline IRQ stuff * */static inline voidwaitforCEC(struct IsdnCardState *cs, int hscx){	int to = 50;	while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {		udelay(1);		to--;	}	if (!to)		printk(KERN_WARNING "HiSax: waitforCEC timeout\n");}static inline voidwaitforXFW(struct IsdnCardState *cs, int hscx){	int to = 50;	while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {		udelay(1);		to--;	}	if (!to)		printk(KERN_WARNING "HiSax: waitforXFW timeout\n");}static inline voidWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data){	waitforCEC(cs, hscx);	WRITEHSCX(cs, hscx, HSCX_CMDR, data);}static voidhscx_empty_fifo(struct BCState *bcs, int count){	u_char *ptr;	struct IsdnCardState *cs = bcs->cs;	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))		debugl1(cs, "hscx_empty_fifo");	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {		if (cs->debug & L1_DEB_WARN)			debugl1(cs, "hscx_empty_fifo: incoming packet too large");		WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);		bcs->hw.hscx.rcvidx = 0;		return;	}	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;	bcs->hw.hscx.rcvidx += count;	READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);	WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);	if (cs->debug & L1_DEB_HSCX_FIFO) {		char *t = bcs->blog;		t += sprintf(t, "hscx_empty_fifo %c cnt %d",			     bcs->hw.hscx.hscx ? 'B' : 'A', count);		QuickHex(t, ptr, count);		debugl1(cs, bcs->blog);	}}static voidhscx_fill_fifo(struct BCState *bcs){	struct IsdnCardState *cs = bcs->cs;	int more, count;	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;	u_char *ptr;	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))		debugl1(cs, "hscx_fill_fifo");	if (!bcs->tx_skb)		return;	if (bcs->tx_skb->len <= 0)		return;	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;	if (bcs->tx_skb->len > fifo_size) {		more = !0;		count = fifo_size;	} else		count = bcs->tx_skb->len;	waitforXFW(cs, bcs->hw.hscx.hscx);	ptr = bcs->tx_skb->data;	skb_pull(bcs->tx_skb, count);	bcs->tx_cnt -= count;	bcs->hw.hscx.count += count;	WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);	WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);	if (cs->debug & L1_DEB_HSCX_FIFO) {		char *t = bcs->blog;		t += sprintf(t, "hscx_fill_fifo %c cnt %d",			     bcs->hw.hscx.hscx ? 'B' : 'A', count);		QuickHex(t, ptr, count);		debugl1(cs, bcs->blog);	}}static inline voidhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx){	u_char r;	struct BCState *bcs = cs->bcs + hscx;	struct sk_buff *skb;	int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;	int count;	if (!test_bit(BC_FLG_INIT, &bcs->Flag))		return;	if (val & 0x80) {	/* RME */		r = READHSCX(cs, hscx, HSCX_RSTA);		if ((r & 0xf0) != 0xa0) {			if (!(r & 0x80)) {				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "HSCX invalid frame");#ifdef ERROR_STATISTIC				bcs->err_inv++;#endif			}			if ((r & 0x40) && bcs->mode) {				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "HSCX RDO mode=%d",						bcs->mode);#ifdef ERROR_STATISTIC				bcs->err_rdo++;#endif			}			if (!(r & 0x20)) {				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "HSCX CRC error");#ifdef ERROR_STATISTIC				bcs->err_crc++;#endif			}			WriteHSCXCMDR(cs, hscx, 0x80);		} else {			count = READHSCX(cs, hscx, HSCX_RBCL) & (				test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f);			if (count == 0)				count = fifo_size;			hscx_empty_fifo(bcs, count);			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {				if (cs->debug & L1_DEB_HSCX_FIFO)					debugl1(cs, "HX Frame %d", count);				if (!(skb = dev_alloc_skb(count)))					printk(KERN_WARNING "HSCX: receive out of memory\n");				else {					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);					skb_queue_tail(&bcs->rqueue, skb);				}			}		}		bcs->hw.hscx.rcvidx = 0;		schedule_event(bcs, B_RCVBUFREADY);	}	if (val & 0x40) {	/* RPF */		hscx_empty_fifo(bcs, fifo_size);		if (bcs->mode == L1_MODE_TRANS) {			/* receive audio data */			if (!(skb = dev_alloc_skb(fifo_size)))				printk(KERN_WARNING "HiSax: receive out of memory\n");			else {				memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);				skb_queue_tail(&bcs->rqueue, skb);			}			bcs->hw.hscx.rcvidx = 0;			schedule_event(bcs, B_RCVBUFREADY);		}	}	if (val & 0x10) {	/* XPR */		if (bcs->tx_skb) {			if (bcs->tx_skb->len) {				hscx_fill_fifo(bcs);				return;			} else {				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->hw.hscx.count;					spin_unlock_irqrestore(&bcs->aclock, flags);					schedule_event(bcs, B_ACKPENDING);				}				dev_kfree_skb_irq(bcs->tx_skb);				bcs->hw.hscx.count = 0; 				bcs->tx_skb = NULL;			}		}		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {			bcs->hw.hscx.count = 0;			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);			hscx_fill_fifo(bcs);		} else {			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);			schedule_event(bcs, B_XMTBUFREADY);		}	}}static inline voidhscx_int_main(struct IsdnCardState *cs, u_char val){	u_char exval;	struct BCState *bcs;	if (val & 0x01) {		bcs = cs->bcs + 1;		exval = READHSCX(cs, 1, HSCX_EXIR);		if (exval & 0x40) {			if (bcs->mode == 1)				hscx_fill_fifo(bcs);			else {#ifdef ERROR_STATISTIC				bcs->err_tx++;#endif				/* Here we lost an TX interrupt, so				   * restart transmitting the whole frame.				 */				if (bcs->tx_skb) {					skb_push(bcs->tx_skb, bcs->hw.hscx.count);					bcs->tx_cnt += bcs->hw.hscx.count;					bcs->hw.hscx.count = 0;				}				WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "HSCX B EXIR %x Lost TX", exval);			}		} else if (cs->debug & L1_DEB_HSCX)			debugl1(cs, "HSCX B EXIR %x", exval);	}	if (val & 0xf8) {		if (cs->debug & L1_DEB_HSCX)			debugl1(cs, "HSCX B interrupt %x", val);		hscx_interrupt(cs, val, 1);	}	if (val & 0x02) {		bcs = cs->bcs;		exval = READHSCX(cs, 0, HSCX_EXIR);		if (exval & 0x40) {			if (bcs->mode == L1_MODE_TRANS)				hscx_fill_fifo(bcs);			else {				/* Here we lost an TX interrupt, so				   * restart transmitting the whole frame.				 */#ifdef ERROR_STATISTIC				bcs->err_tx++;#endif				if (bcs->tx_skb) {					skb_push(bcs->tx_skb, bcs->hw.hscx.count);					bcs->tx_cnt += bcs->hw.hscx.count;					bcs->hw.hscx.count = 0;				}				WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "HSCX A EXIR %x Lost TX", exval);			}		} else if (cs->debug & L1_DEB_HSCX)			debugl1(cs, "HSCX A EXIR %x", exval);	}	if (val & 0x04) {		exval = READHSCX(cs, 0, HSCX_ISTA);		if (cs->debug & L1_DEB_HSCX)			debugl1(cs, "HSCX A interrupt %x", exval);		hscx_interrupt(cs, exval, 0);	}}

⌨️ 快捷键说明

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