pci和isa总线的基础知识:
pci编程原理
cpu查找pci总线或设备的途径:配置命令,有两类性的配置命令,即类型0和1。
类型1配置命令包含一个pci总线序号,这种命令只会被桥接器解析,所以,类型1命令是传给桥接器的。每个PCI-PCI桥接器都拥有一个主干总线接口序号(位于PCI-PCI桥接器上方的总线序号)以及一个二级总线接口序号(位于PCI-PCI桥接器下方的总线序号)。任何PCI-PCI桥接器还包含一个从属总线序号,这是所有二级总线接口所桥接的PCI总线中序号最大的那个。当PCI-PCI桥接器看到类型1 PCI配置命令时它将进行如下操作:
- 如果此总线序号不在桥接器的二级总线序号和从属总线序号之间则忽略掉它。
- 如果此总线序号与桥接器的二级总线序号相同则将其转换成类型0 配置命令。(设备在此桥接器的二级总线上)
- 如果此总线序号位于桥接器的二级总线序号与从属总线序号之间则将它不作改变的传递到二级总线接口中。(传递给下层桥接器继续解析)
类型0配置命令不包含pci总线序号,同时在此PCI总线上(大家看到了,pci总线会由类型1确定下来)对应于这个PCI配置地址的所有PCI设备都会来对它们进行解释。
例如:所以如果想寻址PCI-PCI配置总线3上的设备1,我们首先从CPU中产生一个类型1配置命令。桥接器1将其传递给总线1。桥接器2虽然忽略它但会将其转换成一个类型0配置命令并送到总线3上,在那里设备1将作出相应反应。所以,简单的说就是,cpu使用配置1得到总线地址,使用配置0得到设备地址。
详细过程请查看以下网址:(关于pci编程原理的超级精华文章)
linux下的pci编程
一直以来,我们都知道,pci设备是在调用pci_register_driver(&pci_driver)的时候被枚举出来的,pci驱动拿设备的id信息依次和pci_driver结构体中的id_table数组里边的值比较,若发下一致,则注册它。但是设备的id信息是什么时候设置的呢 ?其实这里说的设备的id信息就是设备配置寄存器的一部分。那么设备配置寄存器是什么时候配置的呢?pci设备上电的时候!当pci设备上电的时候,设备只响应配置交易。在上电时,设备没有内存并且io端口没有被映射在计算机的地址空间,每个其他设备特定的特征,例如中断报告,也被关闭。幸运的时,每个主板装配有可以识别pci的固件,称为BIOS,nvram,或者prom。这个固件通过读和写pci控制器中的寄存器提供对pci设备配置地址空间的存取。在系统启动时,固件(或者linux内核,如果配置成这样的话)和每个pci外设进行配置交易,这样在驱动存取设备的时候,它的内存空间和io空间已经被映射到处理器的地址空间。当Linux内核启动并完成对所有PCI设备进行扫描、登录和分配资源等初始化操作的同时,会建立起系统中所有PCI设备的拓扑结构,此后当PCI驱动程序需要对设备进行初始化时,一般都会调用如下的代码:
static int __init serial8250_pci_init(void)
{
if (!pci_register_driver(&serial8250_pci_driver)) {
pci_unregister_driver(&serial8250_pci_driver);
return -ENODEV;
}
/* ... */
return 0;
}
详细请见ibm的一篇文章:linux下pci设备驱动开发:
http://www.ibm.com/developerworks/cn/linux/l-pci/index.html?ca=dwcn-isc&me=ccid
pci的probe函数
static int __init serial8250_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
这个函数被调用的时候pci_dev已经是探测到得某个设备的pci_dev结构,pci_device_id也已经是探测到的设备
对应的ID信息。
代码如下:
static int __init demo_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
{
struct demo_card *card;
/* 启动PCI设备 */
if (pci_enable_device(pci_dev))
return -EIO;
/* 设备DMA标识 */
if (pci_set_dma_mask(pci_dev, DEMO_DMA_MASK)) {
return -ENODEV;
}
/* 在内核空间中动态申请内存 */
if ((card = kmalloc(sizeof(struct demo_card), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "pci_demo: out of memory\n");
return -ENOMEM;
}
memset(card, 0, sizeof(*card));
/* 读取PCI配置信息 */
card->iobase = pci_resource_start (pci_dev, 1);
card->pci_dev = pci_dev;
card->pci_id = pci_id->device;
card->irq = pci_dev->irq;//card为具体的pci设备
card->next = devs;
card->magic = DEMO_CARD_MAGIC;
/* 设置成总线主DMA模式 */
pci_set_master(pci_dev);
/* 申请I/O资源 */
request_region(card->iobase, 64, card_names[pci_id->driver_data]);
return 0;
}
pci驱动如何找到pci设备
http://blog.chinaunix.net/u1/43502/showart_1896158.html
系统上电后,pci设备的初始化
首先是从根总线开始, 然后就是扫描这个根总线上的每一条子BUS...
http://hi.baidu.com/rwen2012/blog/item/7f81063473d6224d241f141a.html
阅读(1965) | 评论(1) | 转发(0) |