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

📄 w6692.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: w6692.c,v 1.12.6.2 2000/11/29 16:00:14 kai Exp $ * * w6692.c   Winbond W6692 specific routines * * Author       Petr Novak <petr.novak@i.cz> *              (based on HiSax driver by Karsten Keil) * *              This file is (c) under GNU PUBLIC LICENSE * */#include <linux/config.h>#include <linux/init.h>#define __NO_VERSION__#include "hisax.h"#include "w6692.h"#include "isdnl1.h"#include <linux/interrupt.h>#include <linux/pci.h>/* table entry in the PCI devices list */typedef struct {	int vendor_id;	int device_id;	char *vendor_name;	char *card_name;} PCI_ENTRY;static const PCI_ENTRY id_list[] ={	{PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},	{PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},	{0, 0, NULL, NULL}};extern const char *CardType[];const char *w6692_revision = "$Revision: 1.12.6.2 $";#define DBUSY_TIMER_VALUE 80static char *W6692Ver[] __initdata ={"W6692 V00", "W6692 V01", "W6692 V10", "W6692 V11"};static voidW6692Version(struct IsdnCardState *cs, char *s){	int val;	val = cs->readW6692(cs, W_D_RBCH);	printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]);}static voidph_command(struct IsdnCardState *cs, unsigned int command){	if (cs->debug & L1_DEB_ISAC)		debugl1(cs, "ph_command %x", command);	cs->writeisac(cs, W_CIX, command);}static voidW6692_new_ph(struct IsdnCardState *cs){	switch (cs->dc.w6692.ph_state) {		case (W_L1CMD_RST):			ph_command(cs, W_L1CMD_DRC);			l1_msg(cs, HW_RESET | INDICATION, NULL);			/* fallthru */		case (W_L1IND_CD):			l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);			break;		case (W_L1IND_DRD):			l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);			break;		case (W_L1IND_CE):			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);			break;		case (W_L1IND_LD):			l1_msg(cs, HW_RSYNC | INDICATION, NULL);			break;		case (W_L1IND_ARD):			l1_msg(cs, HW_INFO2 | INDICATION, NULL);			break;		case (W_L1IND_AI8):			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);			break;		case (W_L1IND_AI10):			l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);			break;		default:			break;	}}static voidW6692_bh(struct IsdnCardState *cs){	struct PStack *stptr;	if (!cs)		return;	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {		if (cs->debug)			debugl1(cs, "D-Channel Busy cleared");		stptr = cs->stlist;		while (stptr != NULL) {			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);			stptr = stptr->next;		}	}	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))		W6692_new_ph(cs);	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))		DChannel_proc_rcv(cs);	if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))		DChannel_proc_xmt(cs);/*   if (test_and_clear_bit(D_RX_MON1, &cs->event))   arcofi_fsm(cs, ARCOFI_RX_END, NULL);   if (test_and_clear_bit(D_TX_MON1, &cs->event))   arcofi_fsm(cs, ARCOFI_TX_END, NULL); */}voidW6692_sched_event(struct IsdnCardState *cs, int event){	test_and_set_bit(event, &cs->event);	queue_task(&cs->tqueue, &tq_immediate);	mark_bh(IMMEDIATE_BH);}static voidW6692B_sched_event(struct BCState *bcs, int event){	bcs->event |= 1 << event;	queue_task(&bcs->tqueue, &tq_immediate);	mark_bh(IMMEDIATE_BH);}static voidW6692_empty_fifo(struct IsdnCardState *cs, int count){	u_char *ptr;	long flags;	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))		debugl1(cs, "W6692_empty_fifo");	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {		if (cs->debug & L1_DEB_WARN)			debugl1(cs, "W6692_empty_fifo overrun %d",				cs->rcvidx + count);		cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);		cs->rcvidx = 0;		return;	}	ptr = cs->rcvbuf + cs->rcvidx;	cs->rcvidx += count;	save_flags(flags);	cli();	cs->readW6692fifo(cs, ptr, count);	cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);	restore_flags(flags);	if (cs->debug & L1_DEB_ISAC_FIFO) {		char *t = cs->dlog;		t += sprintf(t, "W6692_empty_fifo cnt %d", count);		QuickHex(t, ptr, count);		debugl1(cs, cs->dlog);	}}static voidW6692_fill_fifo(struct IsdnCardState *cs){	int count, more;	u_char *ptr;	long flags;	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))		debugl1(cs, "W6692_fill_fifo");	if (!cs->tx_skb)		return;	count = cs->tx_skb->len;	if (count <= 0)		return;	more = 0;	if (count > W_D_FIFO_THRESH) {		more = !0;		count = W_D_FIFO_THRESH;	}	save_flags(flags);	cli();	ptr = cs->tx_skb->data;	skb_pull(cs->tx_skb, count);	cs->tx_cnt += count;	cs->writeW6692fifo(cs, ptr, count);	cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME));	restore_flags(flags);	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {		debugl1(cs, "W6692_fill_fifo dbusytimer running");		del_timer(&cs->dbusytimer);	}	init_timer(&cs->dbusytimer);	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);	add_timer(&cs->dbusytimer);	if (cs->debug & L1_DEB_ISAC_FIFO) {		char *t = cs->dlog;		t += sprintf(t, "W6692_fill_fifo cnt %d", count);		QuickHex(t, ptr, count);		debugl1(cs, cs->dlog);	}}static voidW6692B_empty_fifo(struct BCState *bcs, int count){	u_char *ptr;	struct IsdnCardState *cs = bcs->cs;	long flags;	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))		debugl1(cs, "W6692B_empty_fifo");	if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) {		if (cs->debug & L1_DEB_WARN)			debugl1(cs, "W6692B_empty_fifo: incoming packet too large");		cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);		bcs->hw.w6692.rcvidx = 0;		return;	}	ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx;	bcs->hw.w6692.rcvidx += count;	save_flags(flags);	cli();	READW6692BFIFO(cs, bcs->channel, ptr, count);	cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);	restore_flags(flags);	if (cs->debug & L1_DEB_HSCX_FIFO) {		char *t = bcs->blog;		t += sprintf(t, "W6692B_empty_fifo %c cnt %d",			     bcs->channel + '1', count);		QuickHex(t, ptr, count);		debugl1(cs, bcs->blog);	}}static voidW6692B_fill_fifo(struct BCState *bcs){	struct IsdnCardState *cs = bcs->cs;	int more, count;	u_char *ptr;	long flags;	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))		debugl1(cs, "W6692B_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 > W_B_FIFO_THRESH) {		more = !0;		count = W_B_FIFO_THRESH;	} else		count = bcs->tx_skb->len;	save_flags(flags);	cli();	ptr = bcs->tx_skb->data;	skb_pull(bcs->tx_skb, count);	bcs->tx_cnt -= count;	bcs->hw.w6692.count += count;	WRITEW6692BFIFO(cs, bcs->channel, ptr, count);	cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));	restore_flags(flags);	if (cs->debug & L1_DEB_HSCX_FIFO) {		char *t = bcs->blog;		t += sprintf(t, "W6692B_fill_fifo %c cnt %d",			     bcs->channel + '1', count);		QuickHex(t, ptr, count);		debugl1(cs, bcs->blog);	}}static voidW6692B_interrupt(struct IsdnCardState *cs, u_char bchan){	u_char val;	u_char r;	struct BCState *bcs;	struct sk_buff *skb;	int count;	bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1);	val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);	debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);	if (!test_bit(BC_FLG_INIT, &bcs->Flag)) {		debugl1(cs, "W6692B not INIT yet");		return;	}	if (val & W_B_EXI_RME) {	/* RME */		r = cs->BC_Read_Reg(cs, bchan, W_B_STAR);		if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB | W_B_STAR_XDOW)) {			if ((r & W_B_STAR_RDOV) && bcs->mode)				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "W6692 B RDOV mode=%d",						bcs->mode);			if (r & W_B_STAR_CRCE)				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "W6692 B CRC error");			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT);		} else {			count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1);			if (count == 0)				count = W_B_FIFO_THRESH;			W6692B_empty_fifo(bcs, count);			if ((count = bcs->hw.w6692.rcvidx) > 0) {				if (cs->debug & L1_DEB_HSCX_FIFO)					debugl1(cs, "W6692 Bchan Frame %d", count);				if (!(skb = dev_alloc_skb(count)))					printk(KERN_WARNING "W6692: Bchan receive out of memory\n");				else {					memcpy(skb_put(skb, count), bcs->hw.w6692.rcvbuf, count);					skb_queue_tail(&bcs->rqueue, skb);				}			}		}		bcs->hw.w6692.rcvidx = 0;		W6692B_sched_event(bcs, B_RCVBUFREADY);	}	if (val & W_B_EXI_RMR) {	/* RMR */		W6692B_empty_fifo(bcs, W_B_FIFO_THRESH);		if (bcs->mode == L1_MODE_TRANS) {			/* receive audio data */			if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH)))				printk(KERN_WARNING "HiSax: receive out of memory\n");			else {				memcpy(skb_put(skb, W_B_FIFO_THRESH), bcs->hw.w6692.rcvbuf, W_B_FIFO_THRESH);				skb_queue_tail(&bcs->rqueue, skb);			}			bcs->hw.w6692.rcvidx = 0;			W6692B_sched_event(bcs, B_RCVBUFREADY);		}	}	if (val & W_B_EXI_XFR) {	/* XFR */		if (bcs->tx_skb) {			if (bcs->tx_skb->len) {				W6692B_fill_fifo(bcs);				return;			} else {				if (bcs->st->lli.l1writewakeup &&				 (PACKET_NOACK != bcs->tx_skb->pkt_type))					bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.w6692.count);				dev_kfree_skb_irq(bcs->tx_skb);				bcs->hw.w6692.count = 0;				bcs->tx_skb = NULL;			}		}		if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {			bcs->hw.w6692.count = 0;			test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);			W6692B_fill_fifo(bcs);		} else {			test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);			W6692B_sched_event(bcs, B_XMTBUFREADY);		}	}	if (val & W_B_EXI_XDUN) {	/* XDUN */		if (bcs->mode == 1)			W6692B_fill_fifo(bcs);		else {			/* Here we lost an TX interrupt, so			   * restart transmitting the whole frame.			 */			if (bcs->tx_skb) {				skb_push(bcs->tx_skb, bcs->hw.w6692.count);				bcs->tx_cnt += bcs->hw.w6692.count;				bcs->hw.w6692.count = 0;			}			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);			if (cs->debug & L1_DEB_WARN)				debugl1(cs, "W6692 B EXIR %x Lost TX", val);		}	}}static voidW6692_interrupt(int intno, void *dev_id, struct pt_regs *regs){	struct IsdnCardState *cs = dev_id;	u_char val, exval, v1;	struct sk_buff *skb;	unsigned int count;	long flags;	int icnt = 5;	if (!cs) {		printk(KERN_WARNING "W6692: Spurious interrupt!\n");		return;	}	val = cs->readW6692(cs, W_ISTA);      StartW6692:	if (cs->debug & L1_DEB_ISAC)		debugl1(cs, "W6692 ISTA %x", val);	if (val & W_INT_D_RME) {	/* RME */		exval = cs->readW6692(cs, W_D_RSTA);		if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {			if (exval & W_D_RSTA_RDOV)				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "W6692 RDOV");			if (exval & W_D_RSTA_CRCE)				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "W6692 D-channel CRC error");			if (exval & W_D_RSTA_RMB)				if (cs->debug & L1_DEB_WARN)					debugl1(cs, "W6692 D-channel ABORT");			cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);		} else {			count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1);			if (count == 0)				count = W_D_FIFO_THRESH;			W6692_empty_fifo(cs, count);			save_flags(flags);			cli();			if ((count = cs->rcvidx) > 0) {				cs->rcvidx = 0;				if (!(skb = alloc_skb(count, GFP_ATOMIC)))					printk(KERN_WARNING "HiSax: D receive out of memory\n");				else {					memcpy(skb_put(skb, count), cs->rcvbuf, count);					skb_queue_tail(&cs->rq, skb);				}			}			restore_flags(flags);		}		cs->rcvidx = 0;		W6692_sched_event(cs, D_RCVBUFREADY);	}	if (val & W_INT_D_RMR) {	/* RMR */		W6692_empty_fifo(cs, W_D_FIFO_THRESH);	}	if (val & W_INT_D_XFR) {	/* XFR */		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))			del_timer(&cs->dbusytimer);		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))			W6692_sched_event(cs, D_CLEARBUSY);		if (cs->tx_skb) {			if (cs->tx_skb->len) {				W6692_fill_fifo(cs);				goto afterXFR;			} else {				dev_kfree_skb_irq(cs->tx_skb);				cs->tx_cnt = 0;				cs->tx_skb = NULL;			}		}		if ((cs->tx_skb = skb_dequeue(&cs->sq))) {			cs->tx_cnt = 0;			W6692_fill_fifo(cs);		} else			W6692_sched_event(cs, D_XMTBUFREADY);	}      afterXFR:	if (val & (W_INT_XINT0 | W_INT_XINT1)) {	/* XINT0/1 - never */		if (cs->debug & L1_DEB_ISAC)			debugl1(cs, "W6692 spurious XINT!");	}	if (val & W_INT_D_EXI) {	/* EXI */		exval = cs->readW6692(cs, W_D_EXIR);		if (cs->debug & L1_DEB_WARN)			debugl1(cs, "W6692 D_EXIR %02x", exval);		if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) {	/* Transmit underrun/collision */			debugl1(cs, "W6692 D-chan underrun/collision");			printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n");			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))				del_timer(&cs->dbusytimer);			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))				W6692_sched_event(cs, D_CLEARBUSY);			if (cs->tx_skb) {	/* Restart frame */				skb_push(cs->tx_skb, cs->tx_cnt);				cs->tx_cnt = 0;				W6692_fill_fifo(cs);			} else {				printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n");				debugl1(cs, "W6692 XDUN/XCOL no skb");				cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST);			}		}		if (exval & W_D_EXI_RDOV) {	/* RDOV */			debugl1(cs, "W6692 D-channel RDOV");			printk(KERN_WARNING "HiSax: W6692 D-RDOV\n");			cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST);		}		if (exval & W_D_EXI_TIN2) {	/* TIN2 - never */			debugl1(cs, "W6692 spurious TIN2 interrupt");		}		if (exval & W_D_EXI_MOC) {	/* MOC - not supported */			debugl1(cs, "W6692 spurious MOC interrupt");			v1 = cs->readW6692(cs, W_MOSR);			debugl1(cs, "W6692 MOSR %02x", v1);		}		if (exval & W_D_EXI_ISC) {	/* ISC - Level1 change */			v1 = cs->readW6692(cs, W_CIR);			if (cs->debug & L1_DEB_ISAC)				debugl1(cs, "W6692 ISC CIR=0x%02X", v1);			if (v1 & W_CIR_ICC) {				cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK;				if (cs->debug & L1_DEB_ISAC)					debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state);				W6692_sched_event(cs, D_L1STATECHANGE);			}

⌨️ 快捷键说明

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