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

📄 cs8900a.c

📁 基于S3C2410的Vxworks的CS8900驱动程序源码
💻 C
📖 第 1 页 / 共 2 页
字号:
    //netif_wake_queue(dev);    net_close(dev);    writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);    net_open(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);    DPRINTK(3, "%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);      DPRINTK(1, "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;    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;    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))) {      DPRINTK(4, "%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. */	  netif_wake_queue(dev);	/* Inform upper layers. */	}	if (status & TX_UNDERRUN) {	  DPRINTK(1, "%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;      }    }}static void count_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 void net_rx(struct net_device *dev) {    struct net_local *lp = (struct net_local *)dev->priv;    struct sk_buff *skb;    int status, length;    int ioaddr = dev->base_addr;    status = inw(ioaddr + RX_FRAME_PORT);    if ((status & RX_OK) == 0) {      count_rx_errors(status, lp);      return;    }    length = inw(ioaddr + RX_FRAME_PORT);    /* Malloc up new buffer. */    skb = dev_alloc_skb(length + 2);    if (skb == NULL) {      lp->stats.rx_dropped++;      return;    }    skb_reserve(skb, 2);	/* longword align L3 header */    skb->len = length;    skb->dev = dev;    readblock(dev, skb->data, skb->len);    DPRINTK(3, "%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);    dev->last_rx = jiffies;    lp->stats.rx_packets++;    lp->stats.rx_bytes += length;}/* The inverse routine to net_open(). */static int net_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. */	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;    DPRINTK(1, "%s: Setting MAC address to ", dev->name);    for (i = 0; i < 6; i++) {      dev->dev_addr[i] = ((unsigned char *)addr)[i];      DPRINTK(1, " %2.2x", dev->dev_addr[i]);    }    DPRINTK(1, ".\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;}#ifdef MODULEstatic 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 io = 0xd0000300;static int irq = IRQ_LAN;static char media[8];static int duplex= 0;MODULE_PARM(io, "i");MODULE_PARM(irq, "i");MODULE_PARM(media, "c8");MODULE_PARM(duplex, "i");MODULE_PARM_DESC(io, "cs89x0 I/O base address");MODULE_PARM_DESC(irq, "cs89x0 IRQ number");MODULE_PARM_DESC(media, "Set cs89x0 adapter(s) media type(s) (rj45,bnc,aui)");/* No other value than -1 for duplex seems to be currently interpreted */MODULE_PARM_DESC(duplex, "(ignored)");MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;/** media=t             - specify media type   or media=2   or media=aui   or medai=auto* duplex=0            - specify forced half/full/autonegotiate duplex* debug=#             - debug level* Default Chip Configuration:  * DMA Burst = enabled  * IOCHRDY Enabled = enabled    * UseSA = enabled    * CS8900 defaults to half-duplex if not specified on command-line    * CS8920 defaults to autoneg if not specified on command-line    * Use reset defaults for other config parameters* Assumptions:  * media type specified is supported (circuitry is present)  * if memory address is > 1MB, then required mem decode hw is present  * if 10B-2, then agent other than driver will enable DC/DC converter    (hw or software util)*/static int __init init_cs8900a_s3c2410(void) {    struct net_local *lp;    int ret = 0;    dev_cs89x0.irq = irq;    dev_cs89x0.base_addr = io;    dev_cs89x0.init = cs89x0_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;    request_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT, "cs8900a");    spin_lock_init(&lp->lock);    /* boy, they'd better get these right */    if (!strcmp(media, "rj45"))      lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;    else if (!strcmp(media, "aui"))      lp->adapter_cnf = A_CNF_MEDIA_AUI   | A_CNF_AUI;    else if (!strcmp(media, "bnc"))      lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2;    else      lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;    if (duplex==-1)      lp->auto_neg_cnf = AUTO_NEG_ENABLE;    if (io == 0) {      printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n");      printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n");      ret = -EPERM;      goto out;    }    if (register_netdev(&dev_cs89x0) != 0) {      printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io);      ret = -ENXIO;      goto out;    }out:    if (ret)      kfree(dev_cs89x0.priv);    return ret;}static void __exit cleanup_cs8900a_s3c2410(void) {    if (dev_cs89x0.priv != NULL) {      /* Free up the private structure, or leak memory :-)  */      unregister_netdev(&dev_cs89x0);      outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT);      kfree(dev_cs89x0.priv);      dev_cs89x0.priv = NULL;	/* gets re-allocated by cs89x0_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_cs8900a_s3c2410);module_exit(cleanup_cs8900a_s3c2410);#endif/* | $Id: cs8900a.c,v 1.1.2.5 2002/10/16 09:08:07 tolkien Exp $ | | Local Variables: | mode: c | mode: font-lock | version-control: t | delete-old-versions: t | End: | | -*- End-Of-File -*- */

⌨️ 快捷键说明

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