PCI总线(二)

来源:互联网 发布:windows最多分区多少 编辑:程序博客网 时间:2024/04/26 07:43

PCI网卡驱动程序分析 针对GNIC- II的千兆以太网卡,源程序文件/drivers/net/hamachi.c

1:初始化

static int  __init hamachi_init (void) {

if(pci_register_driver (&hamachi_driver)  >  0)

return 0;

pci_unregister_driver (&hamachi_driver)

return -ENODEV ;

}

static  struct pci_driver   hamachi_driver = {

name :  DRVNAME ,      //驱动名字

id_table:  hamachi_pci_tbl , //支持的信息的表

probe :  hamachi_init_one , //当找到支持的设备调用的函数

remove :  __devexit_p (hamachi_remove_one) //判断是否支持热插拔

} ;

 

PCI设备注册原理

pci_register_driver driver) :分析

#define pci_register_driver(driver) \

__pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

进入 __pci_register_driver()

 

int __pci_register_driver(struct pci_driver *drv, struct module *owner,

  const char *mod_name)   {

.............................................

error = driver_register(&drv->driver);

..................................

}

进入 driver_register()

int driver_register(struct device_driver *drv) {

。。。。。。。。。。。。。。。。。。。

ret = bus_add_driver(drv);

。。。。。。。。。。。。。。。。。。。

} 进入bus_add_driver()

int bus_add_driver(struct device_driver *drv) {

.............................

error = driver_attach(drv);

...........................

}

int driver_attach(struct device_driver *drv)  {

return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

}

进入bus_for_each_dev

int bus_for_each_dev(struct bus_type *bus, struct device *start,

     void *data, int (*fn)(struct device *, void *)) //遍历总线上的每个设备

 

{

...........................................

while ((dev = next_device(&i)) && !error)

error = fn(dev, data); //对每个设备都执行fn()操作 fn--------> __driver_attach

...........................................

}

static int __driver_attach(struct device *dev, void *data)

{ 。。。。。。。。。。。。。。。。。。。。。。

driver_probe_device(drv, dev);

。。。。。。。。。。。。。。。。。。。。。。

}

int driver_probe_device(struct device_driver *drv, struct device *dev) {

。。。。。。。。。。。。。。。。

if(drv->bus->match && ! drv->bus->match (dev, drv)) //调用驱动程序属于的总线的match()driverdevice匹配。

ret = really_probe(dev, drv) ;

。。。。。。。。。。。。。。。。

}

当注册驱动程序时,内核去遍历驱动程序属于的PCI总线所有的设备,拿驱动和设备match,如果匹配就调用really_probe(),最终会去调用driverprobe(dev)函数。下面看如何match

 

static const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_dev *dev) {

。。。。。。。。。。。。。。。。

list_for_each_entry(dynid, &drv->dynids.list, node) {

//对每个设备都要遍历

if (pci_match_one_device(&dynid->id, dev)) {

//dynid->id里是驱动支持的id_table,拿devid_table链表list_for_each比对。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。

}

 

static inline const struct pci_device_id *

pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) {

if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&

    (id->device == PCI_ANY_ID || id->device == dev->device) &&

    (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&

    (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&

    !((id->class ^ dev->class) & id->class_mask))

return id;

return NULL; }

//匹配一个设备,把驱动所支持的制造商标识、设备标识、类设备标识,拿来和系统存在的设备比较。

 

 

 

static  int  __init hamachi_init_one  (struct pci_dev *pdev ,  const  pci_device_id  *ent) {

//使能PCI设备

if(pci_enable_device (pdev))   {

ret = -EIO ;

goto  -err_out ;

}

ioaddr = pci_resource_start (pdev,  0) ;//获取物理基地址,访问芯片必须知道芯片基地址

i = pci_register_region (pdev,  DRV_NAME) ; //申请要使用的地址空间

if( i )  return i ;

irq = pdev->irq ;  //获取中断号

ioaddr = (long) ioremap (ioaddr,  0x400) ;  //完成物理地址映射虚拟地址。

dev = alloc_ethder(sizeof(struct  hamachi_private)) ; //分配struct net_device结构

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;。。。。。。。。。。。。。。

 

i = register_netdev (dev) ;

.............................

}

 

 


0 0
原创粉丝点击