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

📄 hfc_pci.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: hfc_pci.c,v 1.48.2.4 2004/02/11 13:21:33 keil Exp $ * * low level driver for CCD磗 hfc-pci based cards * * Author       Werner Cornelius *              based on existing driver for CCD hfc ISA cards * Copyright    by Werner Cornelius  <werner@isdn4linux.de> *              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. * * For changes and modifications please read * Documentation/isdn/HiSax.cert * */#include <linux/init.h>#include <linux/config.h>#include "hisax.h"#include "hfc_pci.h"#include "isdnl1.h"#include <linux/pci.h>#include <linux/interrupt.h>extern const char *CardType[];static const char *hfcpci_revision = "$Revision: 1.48.2.4 $";/* table entry in the PCI devices list */typedef struct {	int vendor_id;	int device_id;	char *vendor_name;	char *card_name;} PCI_ENTRY;#define NT_T1_COUNT	20	/* number of 3.125ms interrupts for G2 timeout */#define CLKDEL_TE	0x0e	/* CLKDEL in TE mode */#define CLKDEL_NT	0x6c	/* CLKDEL in NT mode */static const PCI_ENTRY id_list[] ={	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"},	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"},	{PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"},	{PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"},	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"},	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"},	{PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"},	{PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"},	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"},	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"},	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"},	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"},	{PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2, "Sitecom Europe", "DC-105 ISDN PCI"},	{0, 0, NULL, NULL},};#ifdef CONFIG_PCI/******************************************//* free hardware resources used by driver *//******************************************/static voidrelease_io_hfcpci(struct IsdnCardState *cs){	printk(KERN_INFO "HiSax: release hfcpci at %p\n",		cs->hw.hfcpci.pci_io);	cs->hw.hfcpci.int_m2 = 0;					/* interrupt output off ! */	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);			/* Reset On */	mdelay(10);	Write_hfc(cs, HFCPCI_CIRM, 0);					/* Reset Off */	mdelay(10);	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);	pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0);	/* disable memory mapped ports + busmaster */	del_timer(&cs->hw.hfcpci.timer);	kfree(cs->hw.hfcpci.share_start);	cs->hw.hfcpci.share_start = NULL;	iounmap((void *)cs->hw.hfcpci.pci_io);}/********************************************************************************//* function called to reset the HFC PCI chip. A complete software reset of chip *//* and fifos is done.                                                           *//********************************************************************************/static voidreset_hfcpci(struct IsdnCardState *cs){	pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO);	/* enable memory mapped ports, disable busmaster */	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);	printk(KERN_INFO "HFC_PCI: resetting card\n");	pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER);	/* enable memory ports + busmaster */	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */	mdelay(10);	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */	mdelay(10);	if (Read_hfc(cs, HFCPCI_STATUS) & 2)		printk(KERN_WARNING "HFC-PCI init bit busy\n");	cs->hw.hfcpci.fifo_en = 0x30;	/* only D fifos enabled */	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);	cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK;	/* no echo connect , threshold */	Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);	Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */	cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;	Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);	/* S/T Auto awake */	cs->hw.hfcpci.bswapped = 0;	/* no exchange */	cs->hw.hfcpci.nt_mode = 0;	/* we are in TE mode */	cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER;	Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt);	cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC |	    HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER;	Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);	/* Clear already pending ints */	if (Read_hfc(cs, HFCPCI_INT_S1));	Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2);	/* HFC ST 2 */	udelay(10);	Write_hfc(cs, HFCPCI_STATES, 2);	/* HFC ST 2 */	cs->hw.hfcpci.mst_m = HFCPCI_MASTER;	/* HFC Master Mode */	Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m);	cs->hw.hfcpci.sctrl = 0x40;	/* set tx_lo mode, error in datasheet ! */	Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl);	cs->hw.hfcpci.sctrl_r = 0;	Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r);	/* Init GCI/IOM2 in master mode */	/* Slots 0 and 1 are set for B-chan 1 and 2 */	/* D- and monitor/CI channel are not enabled */	/* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */	/* STIO2 is used as data input, B1+B2 from IOM->ST */	/* ST B-channel send disabled -> continous 1s */	/* The IOM slots are always enabled */	cs->hw.hfcpci.conn = 0x36;	/* set data flow directions */	Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn);	Write_hfc(cs, HFCPCI_B1_SSL, 0x80);	/* B1-Slot 0 STIO1 out enabled */	Write_hfc(cs, HFCPCI_B2_SSL, 0x81);	/* B2-Slot 1 STIO1 out enabled */	Write_hfc(cs, HFCPCI_B1_RSL, 0x80);	/* B1-Slot 0 STIO2 in enabled */	Write_hfc(cs, HFCPCI_B2_RSL, 0x81);	/* B2-Slot 1 STIO2 in enabled */	/* Finally enable IRQ output */	cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE;	Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);	if (Read_hfc(cs, HFCPCI_INT_S1));}/***************************************************//* Timer function called when kernel timer expires *//***************************************************/static voidhfcpci_Timer(struct IsdnCardState *cs){	cs->hw.hfcpci.timer.expires = jiffies + 75;	/* WD RESET *//*      WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcpci.ctmt | 0x80);   add_timer(&cs->hw.hfcpci.timer); */}/*********************************//* schedule a new D-channel task *//*********************************/static voidsched_event_D_pci(struct IsdnCardState *cs, int event){	test_and_set_bit(event, &cs->event);	schedule_work(&cs->tqueue);}/*********************************//* schedule a new b_channel task *//*********************************/static voidhfcpci_sched_event(struct BCState *bcs, int event){	test_and_set_bit(event, &bcs->event);	schedule_work(&bcs->tqueue);}/************************************************//* select a b-channel entry matching and active *//************************************************/staticstruct BCState *Sel_BCS(struct IsdnCardState *cs, int channel){	if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))		return (&cs->bcs[0]);	else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))		return (&cs->bcs[1]);	else		return (NULL);}/***************************************//* clear the desired B-channel rx fifo *//***************************************/static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo){       u_char fifo_state;        bzfifo_type *bzr;	if (fifo) {	        bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2;		fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2RX;	} else {	        bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1;		fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1RX;	}	if (fifo_state)	        cs->hw.hfcpci.fifo_en ^= fifo_state;	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);	cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0;	bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;	bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1;	bzr->f1 = MAX_B_FRAMES;	bzr->f2 = bzr->f1;	/* init F pointers to remain constant */	if (fifo_state)	        cs->hw.hfcpci.fifo_en |= fifo_state;	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);}   /***************************************//* clear the desired B-channel tx fifo *//***************************************/static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo){       u_char fifo_state;        bzfifo_type *bzt;	if (fifo) {	        bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2;		fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2TX;	} else {	        bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1;		fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1TX;	}	if (fifo_state)	        cs->hw.hfcpci.fifo_en ^= fifo_state;	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);	bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1;	bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1;	bzt->f1 = MAX_B_FRAMES;	bzt->f2 = bzt->f1;	/* init F pointers to remain constant */	if (fifo_state)	        cs->hw.hfcpci.fifo_en |= fifo_state;	Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);}   /*********************************************//* read a complete B-frame out of the buffer *//*********************************************/static struct sk_buff*hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type * bz, u_char * bdata, int count){	u_char *ptr, *ptr1, new_f2;	struct sk_buff *skb;	struct IsdnCardState *cs = bcs->cs;	int total, maxlen, new_z2;	z_type *zp;	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))		debugl1(cs, "hfcpci_empty_fifo");	zp = &bz->za[bz->f2];	/* point to Z-Regs */	new_z2 = zp->z2 + count;	/* new position in fifo */	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */	new_f2 = (bz->f2 + 1) & MAX_B_FRAMES;	if ((count > HSCX_BUFMAX + 3) || (count < 4) ||	    (*(bdata + (zp->z1 - B_SUB_VAL)))) {		if (cs->debug & L1_DEB_WARN)			debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);#ifdef ERROR_STATISTIC		bcs->err_inv++;#endif		bz->za[new_f2].z2 = new_z2;		bz->f2 = new_f2;	/* next buffer */		skb = NULL;	} else if (!(skb = dev_alloc_skb(count - 3)))		printk(KERN_WARNING "HFCPCI: receive out of memory\n");	else {		total = count;		count -= 3;		ptr = skb_put(skb, count);		if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL)			maxlen = count;		/* complete transfer */		else			maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2;	/* maximum */		ptr1 = bdata + (zp->z2 - B_SUB_VAL);	/* start of data */		memcpy(ptr, ptr1, maxlen);	/* copy data */		count -= maxlen;		if (count) {	/* rest remaining */			ptr += maxlen;			ptr1 = bdata;	/* start of buffer */			memcpy(ptr, ptr1, count);	/* rest */		}		bz->za[new_f2].z2 = new_z2;		bz->f2 = new_f2;	/* next buffer */	}	return (skb);}/*******************************//* D-channel receive procedure *//*******************************/staticintreceive_dmsg(struct IsdnCardState *cs){	struct sk_buff *skb;	int maxlen;	int rcnt, total;	int count = 5;	u_char *ptr, *ptr1;	dfifo_type *df;	z_type *zp;	df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx;	if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {		debugl1(cs, "rec_dmsg blocked");		return (1);	}	while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {		zp = &df->za[df->f2 & D_FREG_MASK];		rcnt = zp->z1 - zp->z2;		if (rcnt < 0)			rcnt += D_FIFO_SIZE;		rcnt++;		if (cs->debug & L1_DEB_ISAC)			debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)",				df->f1, df->f2, zp->z1, zp->z2, rcnt);		if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) ||		    (df->data[zp->z1])) {			if (cs->debug & L1_DEB_WARN)				debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]);#ifdef ERROR_STATISTIC			cs->err_rx++;#endif			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */			df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1);		} else if ((skb = dev_alloc_skb(rcnt - 3))) {			total = rcnt;			rcnt -= 3;			ptr = skb_put(skb, rcnt);			if (zp->z2 + rcnt <= D_FIFO_SIZE)				maxlen = rcnt;	/* complete transfer */			else				maxlen = D_FIFO_SIZE - zp->z2;	/* maximum */			ptr1 = df->data + zp->z2;	/* start of data */			memcpy(ptr, ptr1, maxlen);	/* copy data */			rcnt -= maxlen;			if (rcnt) {	/* rest remaining */				ptr += maxlen;				ptr1 = df->data;	/* start of buffer */				memcpy(ptr, ptr1, rcnt);	/* rest */			}			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */			df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1);			skb_queue_tail(&cs->rq, skb);			sched_event_D_pci(cs, D_RCVBUFREADY);		} else			printk(KERN_WARNING "HFC-PCI: D receive out of memory\n");	}	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);	return (1);}/*******************************************************************************//* check for transparent receive data and read max one threshold size if avail *//*******************************************************************************/static inthfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata){	unsigned short *z1r, *z2r;	int new_z2, fcnt, maxlen;	struct sk_buff *skb;	u_char *ptr, *ptr1;	z1r = &bz->za[MAX_B_FRAMES].z1;		/* pointer to z reg */	z2r = z1r + 1;	if (!(fcnt = *z1r - *z2r))		return (0);	/* no data avail */	if (fcnt <= 0)		fcnt += B_FIFO_SIZE;	/* bytes actually buffered */	if (fcnt > HFCPCI_BTRANS_THRESHOLD)		fcnt = HFCPCI_BTRANS_THRESHOLD;		/* limit size */	new_z2 = *z2r + fcnt;	/* new position in fifo */	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */	if (!(skb = dev_alloc_skb(fcnt)))		printk(KERN_WARNING "HFCPCI: receive out of memory\n");	else {		ptr = skb_put(skb, fcnt);		if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL)			maxlen = fcnt;	/* complete transfer */		else			maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r;	/* maximum */		ptr1 = bdata + (*z2r - B_SUB_VAL);	/* start of data */		memcpy(ptr, ptr1, maxlen);	/* copy data */		fcnt -= maxlen;		if (fcnt) {	/* rest remaining */			ptr += maxlen;			ptr1 = bdata;	/* start of buffer */			memcpy(ptr, ptr1, fcnt);	/* rest */		}

⌨️ 快捷键说明

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