Chinaunix首页 | 论坛 | 博客
  • 博客访问: 505384
  • 博文数量: 157
  • 博客积分: 3010
  • 博客等级: 中校
  • 技术积分: 1608
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-16 09:30
文章存档

2010年(155)

2008年(2)

我的朋友

分类: LINUX

2010-03-11 20:43:12


二:从网卡驱动说起。
         以intel 100M 网卡驱动为例简要概述数据包的接收与发送流程。代码见(drivers/net/e100.c)
网卡是属于PCI设备,它的注册跟一般的PCI设备注册没什么两样。
static int __init e100_init_module(void)
{
         if(((1 << debug) - 1) & NETIF_MSG_DRV) {
                   printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
                   printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
         }
 
         //注册PCI
        return pci_module_init(&e100_driver);
}
其中e100_driver对应为网卡的pci_driver.
static struct pci_driver e100_driver = {
         //驱动对应的名字
         .name =         DRV_NAME,
         //匹配类型
         .id_table =     e100_id_table,
         //侦测函数
         .probe =        e100_probe,
         //移除函数,设备移除时将调用此函数
         .remove =       __devexit_p(e100_remove),
#ifdef CONFIG_PM
         .suspend =      e100_suspend,
         .resume =       e100_resume,
#endif
}
当总数探测到PCI设备符合e100_id_table中的参数时,将会调用e100_probe,开始设备的初始化
在e100_probe中:
static int __devinit e100_probe(struct pci_dev *pdev,
         const struct pci_device_id *ent)
{
         struct net_device *netdev;
         struct nic *nic;
         int err;
 
         //分配net_device并为其赋值
         //alloc_etherdev为以太网接口的net_device分配函数。它是alloc_netdev的封装函数
         if(!(netdev = alloc_etherdev(sizeof(struct nic)))) {
                   if(((1 << debug) - 1) & NETIF_MSG_PROBE)
                            printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n");
                   return -ENOMEM;
         }
        
         //对netdev中的函数指针赋初值
         netdev->open = e100_open;
         netdev->stop = e100_close;
         netdev->hard_start_xmit = e100_xmit_frame;
         netdev->get_stats = e100_get_stats;
         netdev->set_multicast_list = e100_set_multicast_list;
         netdev->set_mac_address = e100_set_mac_address;
         netdev->change_mtu = e100_change_mtu;
         netdev->do_ioctl = e100_do_ioctl;
         //支持ethtool工具时有效
         SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
         netdev->tx_timeout = e100_tx_timeout;
         netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
         //轮询函数
         netdev->poll = e100_poll;
         netdev->weight = E100_NAPI_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
         netdev->poll_controller = e100_netpoll;
#endif
 
         //获得net_device私有数据区,并对其赋值
         //私有数据大小是由alloc_etherdev()参数中指定的
         nic = netdev_priv(netdev);
         nic->netdev = netdev;
         nic->pdev = pdev;
         nic->msg_enable = (1 << debug) - 1;
         pci_set_drvdata(pdev, netdev);
 
         //启动网卡.为之后DMA,I/O内存映射做准备
//它实际上是对PCI的控制寄存器赋值来实现的
         if((err = pci_enable_device(pdev))) {
                   DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n");
                   goto err_out_free_dev;
         }
 
         //获取该资源相关联的标志
         //如果该设备存在I/O内存,则置IORESOURCE_MEM
         if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
                   DPRINTK(PROBE, ERR, "Cannot find proper PCI device "
                            "base address, aborting.\n");
                   err = -ENODEV;
                   goto err_out_disable_pdev;
         }
 
         //对PCI的6个寄存器都会调用资源分配函数进行申请
         if((err = pci_request_regions(pdev, DRV_NAME))) {
                   DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n");
                   goto err_out_disable_pdev;
         }
 
         //探制设备的DMA能力。如果设备支持DMA。pci_set_dma_mask返回0
         pci_set_master(pdev);
         if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) {
                   DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
                   goto err_out_free_res;
         }
 
         SET_MODULE_OWNER(netdev);
         SET_NETDEV_DEV(netdev, &pdev->dev);
 
         //映射设备对应的I/O。以后对设备寄存器的操作可以直接转换为对内存的操作
         nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr));
         if(!nic->csr) {
                   DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
                   err = -ENOMEM;
                   goto err_out_free_res;
         }
 
         if(ent->driver_data)
                   nic->flags |= ich;
         else
                   nic->flags &= ~ich;
 
         spin_lock_init(&nic->cb_lock);
         spin_lock_init(&nic->cmd_lock);
         //设置定时器。
         init_timer(&nic->watchdog);
         nic->watchdog.function = e100_watchdog;
         nic->watchdog.data = (unsigned long)nic;
         init_timer(&nic->blink_timer);
         nic->blink_timer.function = e100_blink_led;
         nic->blink_timer.data = (unsigned long)nic;
 
         //为nic->mem建立线性DMA。只是在支持ethtool的时候才有用
if((err = e100_alloc(nic))) {
                   DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
                   goto err_out_iounmap;
         }
         //对nic成员赋初值
         e100_get_defaults(nic);
         e100_hw_reset(nic);
         e100_phy_init(nic);
         //读取网卡的EEPROM。其中存放着网卡的MAC地址。
         //对EEPROM是通过对I/O映射内存的操作实现的,即nic->csr
         if((err = e100_eeprom_load(nic)))
                   goto err_out_free;
         //设置netdev->dev_addr
         memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
         if(!is_valid_ether_addr(netdev->dev_addr)) {
                   DPRINTK(PROBE, ERR, "Invalid MAC address from "
                            "EEPROM, aborting.\n");
                   err = -EAGAIN;
                   goto err_out_free;
         }
 
         /* Wol magic packet can be enabled from eeprom */
         if((nic->mac >= mac_82558_D101_A4) &&
            (nic->eeprom[eeprom_id] & eeprom_id_wol))
                   nic->flags |= wol_magic;
 
         pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
         //注册网络设备
         if((err = register_netdev(netdev))) {
                   DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
                   goto err_out_free;
         }
 
         DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, "
                   "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
                   pci_resource_start(pdev, 0), pdev->irq,
                   netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
                   netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
 
         return 0;
 
err_out_free:
         e100_free(nic);
err_out_iounmap:
         iounmap(nic->csr);
err_out_free_res:
         pci_release_regions(pdev);
err_out_disable_pdev:
         pci_disable_device(pdev);
err_out_free_dev:
         pci_set_drvdata(pdev, NULL);
         free_netdev(netdev);
         return err;
}
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/luoye144200720102030/archive/2009/06/04/4243344.aspx
阅读(748) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~