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

📄 cerf89x0.c

📁 基于S3C2410的Vxworks的CS8900驱动程序源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	int i;#ifdef CONFIG_S3C2410_SMDK    EINTPEND |= (1 << 9); /* External Interrupt Pending clear */    SRCPND |= (1 << 5); /* EINT8_23 source pending clear */    INTPND |= (1 << 5); /* EINT8_23 interrupt pending clear */    INTMOD &= ~(1 << 5); /* IRQ interrupt mode */    INTMSK &= ~(1 << 5); /* interrupt service available */    EXTINT1 &= ~(7 << 4);    EXTINT1 |= (4 << 4); /* EINT9 rising edge */    EINTMASK &= ~(1 << 9); /* External Interrupt Enable */#endif	/* Prevent the crystal chip from generating interrupts */	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ);        enable_irq(IRQ_EINT8_23);	/* Grab the interrupt */	if (request_irq(dev->irq, &net_interrupt, SA_SHIRQ, "cs89x0", dev))	{		if (net_debug)			printk("cerf89x0: request_irq(%d) failed\n", dev->irq);		return -EAGAIN;	}	/* Set up the IRQ - Apparently magic */	if (lp->chip_type == CS8900)		writereg(dev, PP_CS8900_ISAINT, 0);	else		writereg(dev, PP_CS8920_ISAINT, 0);		/* 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));	/* Receive only error free packets addressed to this card */	lp->rx_mode = 0;//RX_OK_ACCEPT | RX_IA_ACCEPT;	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;		writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); 	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 |		TX_COL_COUNT_OVRFLOW_ENBL |		TX_UNDERRUN_ENBL);	/* Turn on both receive and transmit operations */	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) |			SERIAL_RX_ON |			SERIAL_TX_ON);	/* now that we've got our act together, enable everything */	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | IO_CHANNEL_READY_ON);	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);	enable_irq(dev->irq);	MOD_INC_USE_COUNT;	netif_start_queue(dev);	return 0;}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. */        printk(KERN_INFO " CS8900A device is not stable or unplugged \n ");	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;	writereg(dev, PP_BusCTL, 0x0);	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);	if (net_debug > 4)	{		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); /* SW.LEE */	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.		 */	  lp->Gskb = skb;	  spin_unlock_irq(&lp->lock);	  return 0;	/*  	if (net_debug) */	  /*  			printk("cs89x0: Tx buffer not free!\n"); */				  /*  		return 1; */	}	/* Write the contents of the packet */	writeblock(dev, skb->data, skb->len);			spin_unlock_irq(&lp->lock);	dev->trans_start = jiffies;/*  		netif_start_queue(dev);	It NETDEV WATCHDOG time not happens , It will stop */	dev_kfree_skb(skb);	/*	 * We DO NOT call netif_wake_queue() here.	 * We also DO NOT call netif_start_queue().	 *	 * Either of these would cause another bottom half run through	 * net_send_packet() before this packet has fully gone out.  That causes	 * us to hit the "Gasp!" above and the send is rescheduled.  it runs like	 * a dog.  We just return and wait for the Tx completion interrupt handler	 * to restart the netdevice layer	 */	return 0;}/* The typical workload of the driver:   Handle the network interface interrupts. */   static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct net_device *dev = dev_id;	struct net_local *lp;	int ioaddr, status;#ifdef CONFIG_S3C2410_SMDK    EINTPEND |= (1 << 9); /* External Interrupt Pending clear */    SRCPND |= (1 << 5); /* EINT8_23 source pending clear */    INTPND |= (1 << 5); /* EINT8_23 interrupt pending clear */#endif	ioaddr = dev->base_addr;	lp = (struct net_local *)dev->priv;	/* we MUST read all the events out of the ISQ, otherwise we'll never		get interrupted again.  As a consequence, we can't have any limit		on the number of times we loop in the interrupt handler.  The		hardware guarantees that eventually we'll run out of events.  Of		course, if you're on a slow machine, and packets are arriving		faster than you can read them off, you're screwed.  Hasta la		vista, baby!	*/	while ((status = readword(dev, ISQ_PORT)))	{		if (net_debug > 4)			printk("%s: event=%04x\n", dev->name, status);					switch(status & ISQ_EVENT_MASK)		{			case ISQ_RECEIVER_EVENT:				/* Got a packet(s). */				net_rx(dev);				break;						case ISQ_TRANSMITTER_EVENT:				lp->stats.tx_packets++;				netif_wake_queue(dev);	/* Inform upper layers. */				if ((status & (	TX_OK |						TX_LOST_CRS |						TX_SQE_ERROR |						TX_LATE_COL |						TX_16_COL)) != TX_OK)				{					if ((status & TX_OK) == 0) lp->stats.tx_errors++;					if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;					if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;					if (status & TX_LATE_COL) lp->stats.tx_window_errors++;					if (status & TX_16_COL) lp->stats.tx_aborted_errors++;				}				break;						case ISQ_BUFFER_EVENT:				if (status & READY_FOR_TX)				{	    /* we tried to transmit a packet earlier, but inexplicably ran out of buffers.	     * That shouldn't happen since we only ever load one packet.	     *	Shrug. Do the right thing anyway. 	     */				  if ( lp->Gskb ) {				    writeblock(dev,lp->Gskb->data,lp->Gskb->len);				    dev->trans_start = jiffies;				    dev_kfree_skb(lp->Gskb);				    lp->Gskb= NULL;				/*      printk(" ------------> Gskb --------> \n"); */				  } else {				    			  					netif_wake_queue(dev);	/* Inform upper layers. */				  }				}				if (status & TX_UNDERRUN)				{					if (net_debug > 0)						printk("%s: transmit underrun\n", dev->name);					lp->send_underrun++;					if (lp->send_underrun == 3)						lp->send_cmd = TX_AFTER_381;					else if (lp->send_underrun == 6)						lp->send_cmd = TX_AFTER_ALL;					/*					 * transmit cycle is done, although	frame wasn't transmitted - this				 	 * avoids having to wait for the upper	layers to timeout on us,				 	 * in the event of a tx underrun				 	 */					netif_wake_queue(dev);	/* Inform upper layers. */				}				break;						case ISQ_RX_MISS_EVENT:				lp->stats.rx_missed_errors += (status >>6);				break;						case ISQ_TX_COL_EVENT:				lp->stats.collisions += (status >>6);				break;			default:				if (net_debug > 3)					printk("%s: event=%04x\n", dev->name, status);		}	}	writereg(dev, PP_BusCTL,0x0); /* DISABLE_IRQ */	writereg(dev, PP_BusCTL,ENABLE_IRQ);}static voidcount_rx_errors(int status, struct net_local *lp){	lp->stats.rx_errors++;	if (status & RX_RUNT) lp->stats.rx_length_errors++;	if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;	if (status & RX_CRC_ERROR)		if (!(status & (RX_EXTRA_DATA|RX_RUNT)))			/* per str 172 */			lp->stats.rx_crc_errors++;	if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;	return;}/* We have a good packet(s), get it/them out of the buffers. */static voidnet_rx(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	struct sk_buff *skb;	int status = 0, length = 0;		/*  status = readreg(dev, PP_RxStatus); */	status = readword(dev, RX_FRAME_PORT);	if ((status & RX_OK) == 0) {		count_rx_errors(status, lp);		return;	}/*  	length = readreg(dev, PP_RxLength); */	length = readword(dev, RX_FRAME_PORT);	/* Malloc up new buffer. */	skb = alloc_skb(length+2, GFP_ATOMIC);	skb_reserve(skb, 2);	if (skb == NULL)	{		lp->stats.rx_dropped++;		return;	}	skb->len = length;	skb->dev = dev;	readblock(dev, skb->data, skb->len);	if (net_debug > 4)	{		printk("%s: received %d byte packet of type %x\n",			dev->name, length,			(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);	}	skb->protocol=eth_type_trans(skb,dev);	netif_rx(skb);	lp->stats.rx_packets++;	lp->stats.rx_bytes+=skb->len;	return;}/* The inverse routine to net_open(). */static intnet_close(struct net_device *dev){	netif_stop_queue(dev);		writereg(dev, PP_RxCFG, 0);	writereg(dev, PP_TxCFG, 0);	writereg(dev, PP_BufCFG, 0);	writereg(dev, PP_BusCTL, 0);	free_irq(dev->irq, dev);	/* Update the statistics here. */	MOD_DEC_USE_COUNT;	return 0;}/* Get the current statistics.	This may be called with the card open or   closed. */static struct net_device_stats *net_get_stats(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned long flags;	spin_lock_irqsave(&lp->lock, flags);	/* Update the statistics from the device registers. */	lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);	lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);	spin_unlock_irqrestore(&lp->lock, flags);	return &lp->stats;}static void set_multicast_list(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned long flags;	spin_lock_irqsave(&lp->lock, flags);	if(dev->flags&IFF_PROMISC)	{		lp->rx_mode = RX_ALL_ACCEPT;	}	else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)	{		/* The multicast-accept list is initialized to accept-all, and we		   rely on higher-level filtering for now. */		lp->rx_mode = RX_MULTCAST_ACCEPT;	} 	else		lp->rx_mode = 0;	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);	/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */	writereg(dev, PP_RxCFG, lp->curr_rx_cfg |	     (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));	spin_unlock_irqrestore(&lp->lock, flags);}static int set_mac_address(struct net_device *dev, void *addr){	int i;	if (netif_running(dev))		return -EBUSY;	if (net_debug)	{		printk("%s: Setting MAC address to ", dev->name);		for (i = 0; i < 6; i++)			printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);		printk(".\n");	}	/* 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));	return 0;}static char namespace[16] = "";static struct net_device dev_cs89x0 = {        "",        0, 0, 0, 0,        0, 0,        0, 0, 0, NULL, NULL };/* * Support the 'debug' module parm even if we're compiled for non-debug to  * avoid breaking someone's startup scripts  */static int debug = 1;static char media[8];static int duplex = 0;intinit_s3c2410(void){	struct net_local *lp;#if DEBUGGING	net_debug = debug;#endif	dev_cs89x0.init = cerf89x0_probe;	dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);	if (dev_cs89x0.priv == 0)	{		printk(KERN_ERR "cs89x0.c: Out of memory.\n");		return -ENOMEM;	}	memset(dev_cs89x0.priv, 0, sizeof(struct net_local));	lp = (struct net_local *)dev_cs89x0.priv;	spin_lock_init(&lp->lock);	if (register_netdev(&dev_cs89x0) != 0) {		printk(KERN_ERR "cerf89x0.c: No chip found \n");		return -ENXIO;	}    return 0;}voidcleanup_s3c2410(void) {	writeword(&dev_cs89x0, ADD_PORT, PP_ChipID);	if (dev_cs89x0.priv != NULL) {		/* Free up the private structure, or leak memory :-)  */		unregister_netdev(&dev_cs89x0);		kfree(dev_cs89x0.priv);		dev_cs89x0.priv = NULL;	/* gets re-allocated by cerf89x0_probe1 */		/* If we don't do this, we can't re-insmod it later. */		release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT);	}}module_init(init_s3c2410);module_exit(cleanup_s3c2410);

⌨️ 快捷键说明

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