全部博文(72)
2010年(72)
分类: LINUX
2010-09-24 08:44:55
PCI网卡驱动程序分析
1. 概述
该分析报告针对 GNIC-II的千兆以太网卡,源程序文件:drivers/net/hamachi.c,由于该分析报告旨在对介绍PCI驱动程序结构,所以程序中关于硬件操作的具体部分不作介绍。
2. 初始化
static int __init hamachi_init (void)
{
if (pci_register_driver(&hamachi_driver) > 0)
return 0;
pci_unregister_driver(&hamachi_driver);
return -ENODEV;
}
在模块初始化时采用pci_register_driver注册pci驱动程序。
static struct pci_driver hamachi_driver = {
name: DRV_NAME,
id_table: hamachi_pci_tbl,
probe: hamachi_init_one,
remove: __devexit_p(hamachi_remove_one),
};
static struct pci_device_id hamachi_pci_tbl[] __initdata = {
{ 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, },
}
该表记录的是该驱动能够支持的PCI设备,分别是厂商号,设备号,子厂商号,子设备号,其中子厂商号,子设备号为PCI_ANY_ID,表示支持各种子类型。 该表到底有什么实际用处?(通过分析函数pci_register_driver得出结论)
probe: hamachi_init_one (该函数的调用时机可通过分析pci_register_driver得出)
static int __init hamachi_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
/* 使能PCI设备 */
if (pci_enable_device(pdev)) {
ret = -EIO;
goto err_out;
}
/* 获取基地址 */
ioaddr = pci_resource_start(pdev, 0);
/* 申请将要使用的地址空间 */
i = pci_request_regions(pdev, DRV_NAME);
if (i) return i;
/* 获取中断号 */
irq = pdev->irq;
/* 思考为什么这里要使用ioremap? */
ioaddr = (long) ioremap(ioaddr, 0x400);
if (!ioaddr)
goto err_out_release;
dev = alloc_etherdev(sizeof(struct hamachi_private));
if (!dev)
goto err_out_iounmap;
SET_MODULE_OWNER(dev);
/* 硬件相关操作,省略 */
/* The Hamachi-specific entries in the device structure. */
dev->open = &hamachi_open;
dev->hard_start_xmit = &hamachi_start_xmit;
dev->stop = &hamachi_close;
dev->get_stats = &hamachi_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &netdev_ioctl;
dev->tx_timeout = &hamachi_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
if (mtu)
dev->mtu = mtu;
i = register_netdev(dev);
if (i) {
ret = i;
goto err_out_unmap_rx;
}
/* Configure gigabit autonegotiation. */
writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */
writew(0x08e0, ioaddr + ANAdvertise); /* Set our advertise word. */
writew(0x1000, ioaddr + ANCtrl);
card_idx++;
return 0;
}