Chinaunix首页 | 论坛 | 博客
  • 博客访问: 154050
  • 博文数量: 72
  • 博客积分: 3680
  • 博客等级: 中校
  • 技术积分: 1051
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-22 13:51
文章分类
文章存档

2010年(72)

我的朋友

分类: LINUX

2010-09-24 08:43:43

1.   模块注册

 

static int __init dm9000_init(void)

{

printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);

 

      return platform_driver_register(&dm9000_driver);

}

 

static struct platform_driver dm9000_driver = {

      .driver     = {

           .name    = "dm9000",

           .owner    = THIS_MODULE,

      },

      .probe   = dm9000_probe,

      .remove  = __devexit_p(dm9000_drv_remove),

      .suspend = dm9000_drv_suspend,

      .resume  = dm9000_drv_resume,

};

 

2. 驱动初始化

 

static int __devinit

dm9000_probe(struct platform_device *pdev)

{

      struct dm9000_plat_data *pdata = pdev->dev.platform_data;

      struct board_info *db;     /* Point a board information structure */

      struct net_device *ndev;

      const unsigned char *mac_src;

      int ret = 0;

      int iosize;

      int i;

      u32 id_val;

 

 

      /* Init network device */

      ndev = alloc_etherdev(sizeof(struct board_info));

      if (!ndev) {

           dev_err(&pdev->dev, "could not allocate device.\n");

           return -ENOMEM;

      }

 

      SET_NETDEV_DEV(ndev, &pdev->dev);

 

      dev_dbg(&pdev->dev, "dm9000_probe()\n");

 

      /* setup board info structure */

      db = netdev_priv(ndev);

      memset(db, 0, sizeof(*db));

 

      db->dev = &pdev->dev;

      db->ndev = ndev;

 

      spin_lock_init(&db->lock);

      mutex_init(&db->addr_lock);

 

      INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);

 

db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);

db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

 

      if (db->addr_res == NULL || db->data_res == NULL ||

          db->irq_res == NULL) {

           dev_err(db->dev, "insufficient resources\n");

           ret = -ENOENT;

           goto out;

      }

 

      iosize = res_size(db->addr_res);

      db->addr_req = request_mem_region(db->addr_res->start, iosize,

                              pdev->name);

 

      if (db->addr_req == NULL) {

           dev_err(db->dev, "cannot claim address reg area\n");

            ret = -EIO;

           goto out;

      }

 

      db->io_addr = ioremap(db->addr_res->start, iosize);

 

      if (db->io_addr == NULL) {

           dev_err(db->dev, "failed to ioremap address reg\n");

           ret = -EINVAL;

           goto out;

      }

 

      iosize = res_size(db->data_res);

      db->data_req = request_mem_region(db->data_res->start, iosize,

                              pdev->name);

 

      if (db->data_req == NULL) {

           dev_err(db->dev, "cannot claim data reg area\n");

           ret = -EIO;

           goto out;

      }

 

      db->io_data = ioremap(db->data_res->start, iosize);

 

      if (db->io_data == NULL) {

            dev_err(db->dev, "failed to ioremap data reg\n");

           ret = -EINVAL;

           goto out;

      }

 

      /* fill in parameters for net-dev structure */

      ndev->base_addr = (unsigned long)db->io_addr;

      ndev->irq     = db->irq_res->start;

 

      /* ensure at least we have a default set of IO routines */

      dm9000_set_io(db, iosize);

 

      /* check to see if anything is being over-ridden */

      if (pdata != NULL) {

           /* check to see if the driver wants to over-ride the

            * default IO width */

 

           if (pdata->flags & DM9000_PLATF_8BITONLY)

                 dm9000_set_io(db, 1);

 

           if (pdata->flags & DM9000_PLATF_16BITONLY)

                 dm9000_set_io(db, 2);

 

           if (pdata->flags & DM9000_PLATF_32BITONLY)

                 dm9000_set_io(db, 4);

 

           /* check to see if there are any IO routine

            * over-rides */

 

           if (pdata->inblk != NULL)

                 db->inblk = pdata->inblk;

 

           if (pdata->outblk != NULL)

                 db->outblk = pdata->outblk;

 

           if (pdata->dumpblk != NULL)

                 db->dumpblk = pdata->dumpblk;

 

           db->flags = pdata->flags;

      }

 

#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL

      db->flags |= DM9000_PLATF_SIMPLE_PHY;

#endif

 

      dm9000_reset(db);

 

      /* try multiple times, DM9000 sometimes gets the read wrong */

      for (i = 0; i < 8; i++) {

           id_val  = ior(db, DM9000_VIDL);

           id_val |= (u32)ior(db, DM9000_VIDH) << 8;

           id_val |= (u32)ior(db, DM9000_PIDL) << 16;

           id_val |= (u32)ior(db, DM9000_PIDH) << 24;

 

           if (id_val == DM9000_ID)

                 break;

           dev_err(db->dev, "read wrong id 0x%08x\n", id_val);

      }

 

      if (id_val != DM9000_ID) {

           dev_err(db->dev, "wrong id: 0x%08x\n", id_val);

           ret = -ENODEV;

           goto out;

      }

 

      /* Identify what type of DM9000 we are working on */

 

      id_val = ior(db, DM9000_CHIPR);

      dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);

 

      switch (id_val) {

      case CHIPR_DM9000A:

           db->type = TYPE_DM9000A;

           break;

      case CHIPR_DM9000B:

           db->type = TYPE_DM9000B;

           break;

      default:

           dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);

           db->type = TYPE_DM9000E;

      }

 

      /* from this point we assume that we have found a DM9000 */

 

      /* driver system function */

      ether_setup(ndev);

 

      ndev->open      = &dm9000_open;

      ndev->hard_start_xmit    = &dm9000_start_xmit;

      ndev->tx_timeout         = &dm9000_timeout;

      ndev->watchdog_timeo = msecs_to_jiffies(watchdog);

      ndev->stop       = &dm9000_stop;

      ndev->set_multicast_list = &dm9000_hash_table;

      ndev->ethtool_ops     = &dm9000_ethtool_ops;

      ndev->do_ioctl      = &dm9000_ioctl;

 

#ifdef CONFIG_NET_POLL_CONTROLLER

      ndev->poll_controller      = &dm9000_poll_controller;

#endif

 

      db->msg_enable       = NETIF_MSG_LINK;

      db->mii.phy_id_mask  = 0x1f;

      db->mii.reg_num_mask = 0x1f;

      db->mii.force_media  = 0;

      db->mii.full_duplex  = 0;

      db->mii.dev      = ndev;

      db->mii.mdio_read    = dm9000_phy_read;

      db->mii.mdio_write   = dm9000_phy_write;

 

      mac_src = "eeprom";

 

      /* try reading the node address from the attached EEPROM */

      for (i = 0; i < 6; i += 2)

           dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);

 

      if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {

           mac_src = "platform data";

           memcpy(ndev->dev_addr, pdata->dev_addr, 6);

      }

 

      if (!is_valid_ether_addr(ndev->dev_addr)) {

           /* try reading from mac */

          

           mac_src = "chip";

           for (i = 0; i < 6; i++)

                 ndev->dev_addr[i] = ior(db, i+DM9000_PAR);

      }

 

      if (!is_valid_ether_addr(ndev->dev_addr))

           dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "

                  "set using ifconfig\n", ndev->name);

 

      platform_set_drvdata(pdev, ndev);

      ret = register_netdev(ndev);

 

      if (ret == 0)

           printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",

                  ndev->name, dm9000_type_to_char(db->type),

                  db->io_addr, db->io_data, ndev->irq,

                  ndev->dev_addr, mac_src);

      return 0;

 

 

out:

      dev_err(db->dev, "not found (%d).\n", ret);

 

      dm9000_release_board(pdev, db);

      free_netdev(ndev);

 

      return ret;

}

 

 

 

3.打开网卡

 

static int dm9000_open(struct net_device *dev)

{

      board_info_t *db = netdev_priv(dev);

      unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

 

      if (netif_msg_ifup(db))

           dev_dbg(db->dev, "enabling %s\n", dev->name);

 

      /* If there is no IRQ type specified, default to something that

       * may work, and tell the user that this is a problem */

 

      if (irqflags == IRQF_TRIGGER_NONE)

           dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");

 

      irqflags |= IRQF_SHARED;

 

      if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))

           return -EAGAIN;

 

      /* Initialize DM9000 board */

      dm9000_reset(db);

      dm9000_init_dm9000(dev);

 

      /* Init driver variable */

      db->dbug_cnt = 0;

 

      mii_check_media(&db->mii, netif_msg_link(db), 1);

      netif_start_queue(dev);

     

      dm9000_schedule_poll(db);

 

      return 0;

}

 

4.数据发送

 

static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)

{

      unsigned long flags;

      board_info_t *db = netdev_priv(dev);

 

      dm9000_dbg(db, 3, "%s:\n", __func__);

 

      if (db->tx_pkt_cnt > 1)

           return 1;

 

      spin_lock_irqsave(&db->lock, flags);

 

      /* Move data to DM9000 TX RAM */

      writeb(DM9000_MWCMD, db->io_addr);

 

      (db->outblk)(db->io_data, skb->data, skb->len);

      dev->stats.tx_bytes += skb->len;

 

      db->tx_pkt_cnt++;

 

/* TX control: First packet immediately send, second packet queue */

      if (db->tx_pkt_cnt == 1) {

           /* Set TX length to DM9000 */

           iow(db, DM9000_TXPLL, skb->len);

           iow(db, DM9000_TXPLH, skb->len >> 8);

 

           /* Issue TX polling command */

iow(db, DM9000_TCR, TCR_TXREQ);     /* Cleared after TX complete */

 

           dev->trans_start = jiffies;     /* save the time stamp */

      } else {

           /* Second packet */

           db->queue_pkt_len = skb->len;

           netif_stop_queue(dev);

      }

 

      spin_unlock_irqrestore(&db->lock, flags);

 

      /* free this SKB */

      dev_kfree_skb(skb);

 

      return 0;

}

 

 

5.数据接收

 

static irqreturn_t dm9000_interrupt(int irq, void *dev_id)

{

      struct net_device *dev = dev_id;

      board_info_t *db = netdev_priv(dev);

      int int_status;

      unsigned long flags;

      u8 reg_save;

 

      dm9000_dbg(db, 3, "entering %s\n", __func__);

 

      /* A real interrupt coming */

 

      /* holders of db->lock must always block IRQs */

      spin_lock_irqsave(&db->lock, flags);

 

      /* Save previous register address */

      reg_save = readb(db->io_addr);

 

      /* Disable all interrupts */

      iow(db, DM9000_IMR, IMR_PAR);

 

      /* Got DM9000 interrupt status */

      int_status = ior(db, DM9000_ISR); /* Got ISR */

      iow(db, DM9000_ISR, int_status); /* Clear ISR status */

 

      if (netif_msg_intr(db))

           dev_dbg(db->dev, "interrupt status %02x\n", int_status);

 

      /* Received the coming packet */

      if (int_status & ISR_PRS)

           dm9000_rx(dev);

 

      /* Trnasmit Interrupt check */

      if (int_status & ISR_PTS)

           dm9000_tx_done(dev, db);

 

      if (db->type != TYPE_DM9000E) {

           if (int_status & ISR_LNKCHNG) {

                 /* fire a link-change request */

                 schedule_delayed_work(&db->phy_poll, 1);

           }

      }

 

      /* Re-enable interrupt mask */

      iow(db, DM9000_IMR, db->imr_all);

 

      /* Restore previous register address */

      writeb(reg_save, db->io_addr);

 

      spin_unlock_irqrestore(&db->lock, flags);

 

      return IRQ_HANDLED;

}

 

 

 

static void

dm9000_rx(struct net_device *dev)

{

      board_info_t *db = netdev_priv(dev);

      struct dm9000_rxhdr rxhdr;

      struct sk_buff *skb;

      u8 rxbyte, *rdptr;

      bool GoodPacket;

      int RxLen;

 

      /* Check packet ready or not */

      do {

           ior(db, DM9000_MRCMDX); /* Dummy read */

 

           /* Get most updated data */

           rxbyte = readb(db->io_data);

 

           /* Status check: this byte must be 0 or 1 */

           if (rxbyte > DM9000_PKT_RDY) {

                 dev_warn(db->dev, "status check fail: %d\n", rxbyte);

                 iow(db, DM9000_RCR, 0x00);   /* Stop Device */

                 iow(db, DM9000_ISR, IMR_PAR);  /* Stop INT request */

                 return;

           }

 

           if (rxbyte != DM9000_PKT_RDY)

                 return;

 

           /* A packet ready now  & Get status/length */

           GoodPacket = true;

           writeb(DM9000_MRCMD, db->io_addr);

 

           (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));

 

           RxLen = le16_to_cpu(rxhdr.RxLen);

 

           if (netif_msg_rx_status(db))

                 dev_dbg(db->dev, "RX: status %02x, length %04x\n",

                      rxhdr.RxStatus, RxLen);

 

           /* Packet Status check */

           if (RxLen < 0x40) {

                 GoodPacket = false;

                 if (netif_msg_rx_err(db))

                      dev_dbg(db->dev, "RX: Bad Packet (runt)\n");

           }

 

           if (RxLen > DM9000_PKT_MAX) {

                 dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);

           }

 

           /* rxhdr.RxStatus is identical to RSR register. */

           if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |

                            RSR_PLE | RSR_RWTO |

                            RSR_LCS | RSR_RF)) {

                 GoodPacket = false;

                 if (rxhdr.RxStatus & RSR_FOE) {

                      if (netif_msg_rx_err(db))

                            dev_dbg(db->dev, "fifo error\n");

                      dev->stats.rx_fifo_errors++;

                 }

                 if (rxhdr.RxStatus & RSR_CE) {

                      if (netif_msg_rx_err(db))

                            dev_dbg(db->dev, "crc error\n");

                      dev->stats.rx_crc_errors++;

                 }

                 if (rxhdr.RxStatus & RSR_RF) {

                      if (netif_msg_rx_err(db))

                            dev_dbg(db->dev, "length error\n");

                      dev->stats.rx_length_errors++;

                 }

           }

 

           /* Move data from DM9000 */

           if (GoodPacket

               && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {

                 skb_reserve(skb, 2);

                 rdptr = (u8 *) skb_put(skb, RxLen - 4);

 

                 /* Read received packet from RX SRAM */

 

                 (db->inblk)(db->io_data, rdptr, RxLen);

                 dev->stats.rx_bytes += RxLen;

 

                 /* Pass to upper layer */

                 skb->protocol = eth_type_trans(skb, dev);

                 netif_rx(skb);

                 dev->stats.rx_packets++;

 

           } else {

                 /* need to dump the packet's data */

 

                 (db->dumpblk)(db->io_data, RxLen);

           }

      } while (rxbyte == DM9000_PKT_RDY);

}

阅读(805) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-09-26 15:39:45

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com