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

📄 cs89x0.c

📁 基于S3C2410的Vxworks的CS8900驱动程序源码
💻 C
📖 第 1 页 / 共 4 页
字号:
        /* 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) {#if 0                case FORCE_AUTO:			printk("%s: cs8900 doesn't autonegotiate\n",dev->name);                        return DETECTED_NONE;#endif		/* 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 net_device *dev){	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 */	outsw(dev->base_addr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1);	if (net_debug > 1) printk("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 net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	if (net_debug > 1) printk("%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 net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	if (net_debug > 1) printk("%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 net_device *dev, int chip_type, int irq){	int i;	if (chip_type == CS8900) {		/* Search the mapping table for the corresponding IRQ pin. */		for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++)			if (cs8900_irq_map[i] == irq)				break;		/* Not found */		if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))			i = 3;		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.   *//* AKPM: do we need to do any locking here? */static intnet_open(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int result = 0;	int i;	int ret;	if (dev->irq < 2) {		/* Allow interrupts to be generated by the chip *//* Cirrus' release had this: */#if 0		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );#endif/* And 2.3.47 had this: */		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);		for (i = 2; i < CS8920_NO_INTS; i++) {			if ((1 << dev->irq) & lp->irq_map) {				if (request_irq(i, net_interrupt, 0, dev->name, dev) == 0) {					dev->irq = i;					write_irq(dev, lp->chip_type, i);					/* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */					break;				}			}		}		if (i >= CS8920_NO_INTS) {			writereg(dev, PP_BusCTL, 0);	/* disable interrupts. */			printk(KERN_ERR "cs89x0: can't get an interrupt\n");			ret = -EAGAIN;			goto bad_out;		}	} 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);			ret = -EAGAIN;			goto bad_out;		}/* FIXME: Cirrus' release had this: */		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ );/* And 2.3.47 had this: */#if 0		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);#endif		write_irq(dev, lp->chip_type, dev->irq);		ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev);		if (ret) {			if (net_debug)				printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq);			goto bad_out;		}	}#if ALLOW_DMA	if (lp->use_dma) {		if (lp->isa_config & ANY_ISA_DMA) {			unsigned long flags;			lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,							get_order(lp->dmasize * 1024));			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(	"%s: dma %lx %lx\n",					dev->name,					(unsigned long)lp->dma_buff,					(unsigned long)virt_to_bus(lp->dma_buff));			}			if ((unsigned long) 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;			}			memset(lp->dma_buff, 0, lp->dmasize * 1024);	/* Why? */			if (request_dma(dev->dma, dev->name)) {				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;			spin_lock_irqsave(&lp->lock, flags);			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);			spin_unlock_irqrestore(&lp->lock, flags);		}	}#endif	/* ALLOW_DMA */	/* 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:#if ALLOW_DMA		release_dma_buff(lp);#endif                writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));                free_irq(dev->irq, dev);		ret = -EAGAIN;		goto bad_out;	}        /* 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;#if ALLOW_DMA	set_dma_cfg(dev);#endif	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 |#if ALLOW_DMA		dma_bufcfg(dev) |#endif		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 */#if ALLOW_DMA		 | dma_busctl(dev)#endif                 );        netif_start_queue(dev);	if (net_debug > 1)		printk("cs89x0: net_open() succeeded\n");	return 0;bad_out:	return ret;}static void net_timeout(struct net_device *dev){	/* If we get here, some higher level has decided we are broken.	   There should really be a "kick me" function call instead. */	if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,		   tx_done(dev) ? "IRQ conflict ?" : "network cable problem");	/* Try to restart the adaptor. */	netif_wake_queue(dev);}static int net_send_packet(struct sk_buff *skb, struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	if (net_debug > 3) {		printk("%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]);	}	/* keep the upload from being interrupted, since we                  ask the chip to start transmitting before the                  whole packet has been completely uploaded. */	spin_lock_irq(&lp->lock);	netif_stop_queue(dev);	/* initiate a transmit sequence */	writeword(dev, TX_CMD_PORT, lp->send_cmd);	writeword(dev, TX_LEN_PORT, skb->len);	/* Test to see if the chip has allocated memory for the packet */	if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {		/*		 * Gasp!  It hasn't.  But that shouldn't happen since		 * we're waiting for TxOk, so return 1 and requeue this packet.		 */				spin_unlock_irq(&lp->lock);		if (net_debug) printk("cs89x0: Tx buffer not free!\n");		return 1;	}	/* Write the contents of the packet */	outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);	spin_unlock_irq(&lp->lock);	dev->trans_start = jiffies;	dev_kfree_skb (skb);	/*	 * We DO NOT call netif_wake_queue() here.	 * We also DO NOT call netif_start_queue().

⌨️ 快捷键说明

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