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

📄 cs89x0.c

📁 Linux系统CS网卡驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	return;}#endif__initfunc(voidreset_chip(struct device *dev)){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	int reset_start_time;	writereg_io(dev, PP_SelfCTL, readreg_io(dev, PP_SelfCTL) | POWER_ON_RESET);	/* wait 30 ms */	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(30*HZ/1000);	if (lp->chip_type != CS8900) {		/* Hardware problem requires PNP registers to be reconfigured after a reset */		outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT);		outb(dev->irq, ioaddr + DATA_PORT);		outb(0,      ioaddr + DATA_PORT + 1);		outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT);		outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT);		outb((dev->mem_start >> 8) & 0xff,   ioaddr + DATA_PORT + 1);	}	/* Wait until the chip is reset */	reset_start_time = jiffies;	while( (readreg_io(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)		;}static voidcontrol_dc_dc(struct device *dev, int on_not_off){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned int selfcontrol;	int timenow = jiffies;	/* control the DC to DC convertor in the SelfControl register.  */	selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */	if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)		selfcontrol |= HCB1;	else		selfcontrol &= ~HCB1;	writereg(dev, PP_SelfCTL, selfcontrol);	/* Wait for the DC/DC converter to power up - 500ms */	while (jiffies - timenow < 100)		;}#define DETECTED_NONE  0#define DETECTED_RJ45H 1#define DETECTED_RJ45F 2#define DETECTED_AUI   3#define DETECTED_BNC   4static intdetect_tp(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int timenow = jiffies;        int fdx;	if (net_debug > 1) printk(KERN_DEBUG "%s: Attempting TP\n", dev->name);        /* If connected to another full duplex capable 10-Base-T card the link pulses           seem to be lost when the auto detect bit in the LineCTL is set.           To overcome this the auto detect bit will be cleared whilst testing the           10-Base-T interface.  This would not be necessary for the sparrow chip but           is simpler to do it anyway. */	writereg(dev, PP_LineCTL, lp->linectl &~ AUI_ONLY);	control_dc_dc(dev, 0);        /* Delay for the hardware to work out if the TP cable is present - 150ms */	for (timenow = jiffies; jiffies - timenow < 15; )                ;	if ((readreg(dev, PP_LineST) & LINK_OK) == 0)		return DETECTED_NONE;	if (lp->chip_type == CS8900) {                switch (lp->force & 0xf0) {/*                case FORCE_AUTO: printk(KERN_WARNING "%s: cs8900 doesn't autonegotiate\n",dev->name);                        return DETECTED_NONE;*/					/* CS8900 doesn't support AUTO, change to HALF*/                case FORCE_AUTO:lp->force &= ~FORCE_AUTO;                                lp->force |= FORCE_HALF;								break;                case FORCE_HALF: break;                case FORCE_FULL: writereg(dev, PP_TestCTL, readreg(dev, PP_TestCTL) | FDX_8900); break;                }		fdx = readreg(dev, PP_TestCTL) & FDX_8900;	} else {                switch (lp->force & 0xf0) {                case FORCE_AUTO: lp->auto_neg_cnf = AUTO_NEG_ENABLE; break;                case FORCE_HALF: lp->auto_neg_cnf = 0; break;                case FORCE_FULL: lp->auto_neg_cnf = RE_NEG_NOW| ALLOW_FDX; break;                }		writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK);		if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {			printk(KERN_INFO "%s: negotiating duplex...\n",dev->name);			while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) {				if (jiffies - timenow > 4000) {					printk(KERN_ERR "Full / half duplex auto-negotiation timed out\n");					break;				}			}		}		fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE;        }        if (fdx)                return DETECTED_RJ45F;        else                return DETECTED_RJ45H;}/* send a test packet - return true if carrier bits are ok */static intsend_test_pkt(struct device *dev){	int ioaddr = dev->base_addr;	char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0,				 0, 46, /* A 46 in network order */				 0, 0, /* DSAP=0 & SSAP=0 fields */				 0xf3, 0 /* Control (Test Req + P bit set) */ };	long timenow = jiffies;	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON);	memcpy(test_packet,          dev->dev_addr, ETH_ALEN);	memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN);        writeword(dev, TX_CMD_PORT, TX_AFTER_ALL);        writeword(dev, TX_LEN_PORT, ETH_ZLEN);	/* Test to see if the chip has allocated memory for the packet */	while (jiffies - timenow < 5)		if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW)			break;	if (jiffies - timenow >= 5)		return 0;	/* this shouldn't happen */	/* Write the contents of the packet */#if REQUIRE_MEMORY		memcpy_toio(dev->mem_start + PP_TxFrame, test_packet, ETH_ZLEN);#else		outsw(ioaddr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);#endif	if (net_debug > 1) printk(KERN_DEBUG "Sending test packet ");	/* wait a couple of jiffies for packet to be received */	for (timenow = jiffies; jiffies - timenow < 3; )                ;        if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {                if (net_debug > 1) printk("succeeded\n");                return 1;        }	if (net_debug > 1) printk("failed\n");	return 0;}static intdetect_aui(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	if (net_debug > 1) printk(KERN_DEBUG "%s: Attempting AUI\n", dev->name);	control_dc_dc(dev, 0);	writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);	if (send_test_pkt(dev))		return DETECTED_AUI;	else		return DETECTED_NONE;}static intdetect_bnc(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	if (net_debug > 1) printk(KERN_DEBUG "%s: Attempting BNC\n", dev->name);	control_dc_dc(dev, 1);	writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY);	if (send_test_pkt(dev))		return DETECTED_BNC;	else		return DETECTED_NONE;}static voidwrite_irq(struct device *dev, int chip_type, int irq){	int i;	if (chip_type == CS8900) {		switch(irq) {		case 10: i = 0; break;		case 11: i = 1; break;		case 12: i = 2; break;		case 5: i =  3; break;		default: i = 3; break;		}		writereg(dev, PP_CS8900_ISAINT, i);	} else {		writereg(dev, PP_CS8920_ISAINT, irq);	}}/* Open/initialize the board.  This is called (in the current kernel)   sometime after booting when the 'ifconfig' program is run.   This routine should set everything up anew at each open, even   registers that "should" only need to be set once at boot, so that   there is non-reboot way to recover if something goes wrong.   */static intnet_open(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int result = 0;	int i;	if (dev->irq < 2) {		/* Allow interrupts to be generated by the chip */		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );		for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) {			if (request_irq (i, NULL, 0, "cs89x0", dev) != -EBUSY) {				write_irq(dev, lp->chip_type, i);				writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);				if (!request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", dev))					break;			}		}		if (i >= CS8920_NO_INTS) {			writereg(dev, PP_BusCTL, 0);	/* disable interrupts. */			return -EAGAIN;		}	} else {		if (((1 << dev->irq) & lp->irq_map) == 0) {			printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",                               dev->name, dev->irq, lp->irq_map);			return -EAGAIN;		}		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );		write_irq(dev, lp->chip_type, dev->irq);		if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) {			return -EAGAIN;		}	}#if ALLOW_DMA	if (lp->isa_config & ANY_ISA_DMA) {		unsigned long flags;#if 0		lp->dma_buff = kmalloc(dmasize*1024,GFP_KERNEL | GFP_DMA);#else		lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL | GFP_DMA, lp->dmasize==16?4:16);#endif		if (!lp->dma_buff) {			printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize);			goto release_irq;		}		if (net_debug > 1) printk(KERN_NOTICE "%s: dma %lx %lx\n", dev->name, (unsigned long)lp->dma_buff, (unsigned long)virt_to_bus(lp->dma_buff));		if ((unsigned long)virt_to_bus(lp->dma_buff) >= MAX_DMA_ADDRESS ||		    !dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) {			printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name);			goto release_irq;		}		{ int i; for (i=0;i<lp->dmasize*1024;i++) { lp->dma_buff[i] = i; }}		if (request_dma(dev->dma, "cs89x0")) {			printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma);			goto release_irq;		}		write_dma(dev, lp->chip_type, dev->dma);		lp->rx_dma_ptr = lp->dma_buff;		lp->end_dma_buff = lp->dma_buff + lp->dmasize*1024;		save_flags(flags);		cli();		disable_dma(dev->dma);		clear_dma_ff(dev->dma);		set_dma_mode(dev->dma, 0x14); /* auto_init as well */		set_dma_addr(dev->dma, virt_to_bus(lp->dma_buff));		set_dma_count(dev->dma, lp->dmasize*1024);		enable_dma(dev->dma);		restore_flags(flags);	}#endif	/* set the Ethernet address */	for (i=0; i < ETH_ALEN/2; i++)		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));	/* while we're testing the interface, leave interrupts disabled */	writereg(dev, PP_BusCTL, MEMORY_ON);	/* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */	if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))                lp->linectl = LOW_RX_SQUELCH;	else                lp->linectl = 0;        /* check to make sure that they have the "right" hardware available */	switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {	case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break;	case A_CNF_MEDIA_AUI:   result = lp->adapter_cnf & A_CNF_AUI; break;	case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;        default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);        }        if (!result) {                printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);        release_irq:                writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));                free_irq(dev->irq, dev); 		return -EAGAIN;	}        /* set the hardware to the configured choice */	switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) {	case A_CNF_MEDIA_10B_T:                result = detect_tp(dev);                if (result==DETECTED_NONE) {                        printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name);                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */                                result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */                }		break;	case A_CNF_MEDIA_AUI:                result = detect_aui(dev);                if (result==DETECTED_NONE) {                        printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name);                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */                                result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */                }		break;	case A_CNF_MEDIA_10B_2:                result = detect_bnc(dev);                if (result==DETECTED_NONE) {                        printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name);                        if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */                                result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */                }		break;	case A_CNF_MEDIA_AUTO:		writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);		if (lp->adapter_cnf & A_CNF_10B_T)			if ((result = detect_tp(dev)) != DETECTED_NONE)				break;		if (lp->adapter_cnf & A_CNF_AUI)			if ((result = detect_aui(dev)) != DETECTED_NONE)				break;		if (lp->adapter_cnf & A_CNF_10B_2)			if ((result = detect_bnc(dev)) != DETECTED_NONE)				break;		printk(KERN_ERR "%s: no media detected\n", dev->name);                goto release_irq;	}	switch(result) {	case DETECTED_NONE: printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name);                goto release_irq;	case DETECTED_RJ45H: printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);break;	case DETECTED_RJ45F: printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);break;	case DETECTED_AUI:   printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name);break;	case DETECTED_BNC:   printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name);break;	}	/* Turn on both receive and transmit operations */	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);	/* Receive only error free packets addressed to this card */	lp->rx_mode = 0;	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;	if (lp->isa_config & STREAM_TRANSFER)		lp->curr_rx_cfg |= RX_STREAM_ENBL;	set_dma_cfg(dev);	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);	writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |	       TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);	writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |                 dma_bufcfg(dev) |		 TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);	/* now that we've got our act together, enable everything */	writereg(dev, PP_BusCTL, ENABLE_IRQ		 | (dev->mem_start?MEMORY_ON : 0) /* turn memory on */		 | dma_busctl(dev)                 );	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;        MOD_INC_USE_COUNT;	return 0;}static intnet_send_packet(struct sk_buff *skb, struct device *dev){#ifdef NOTDEF	print_registers(dev);#endif	if (dev->tbusy) {		/* If we get here, some higher level has decided we are broken.		   There should really be a "kick me" function call instead. */		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 5)			return 1;		if (net_debug > 0) printk(KERN_NOTICE "%s: transmit timed out, %s?\n", dev->name,			   tx_done(dev) ? "IRQ conflict" : "network cable problem");#ifdef NOTDEF                print_registers(dev);#endif		/* Try to restart the adaptor. */		dev->tbusy=0;		dev->trans_start = jiffies;	}	/* Block a timer-based transmit from overlapping.  This could better be	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)		printk(KERN_NOTICE "%s: Transmitter access conflict.\n", dev->name);	else {		struct net_local *lp = (struct net_local *)dev->priv;		short ioaddr = dev->base_addr;		unsigned long flags;		if (net_debug > 3)printk(KERN_DEBUG "%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);

⌨️ 快捷键说明

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