Linux驱动知识:PCI驱动

本文介绍了PCI总线相关知识。PCI总线通过高时钟频率实现更好性能,有32位数据总线且有64位扩展。PCI设备无跳线,开机自动配置,通过特定标识识别。配置地址空间是其相对ISA的主要进步,主板固件可访问设备配置地址空间,驱动能方便访问设备。

The PCI bus achieves better performance by using a higher clock rate than ISA; its clock runs at 25 or 33 MHz (its actual rate being a factor of the system clock), and 66-MHz and even 133-MHz implementations have recently been deployed as well. Moreover, it is equipped with a 32-bit data bus, and a 64-bit extension has been included in the specification. Platform independence is often a goal in the design of a computer bus, and it's an especially important feature of PCI, because the PC world has always been dominated by processor-specific interface standards. PCI is currently used extensively on IA-32, Alpha, PowerPC, SPARC64, and IA-64 systems, and some other platforms as well.

PCI devices are jumperless (unlike most older peripherals) and are automatically configured at boot time. Then, the device driver must be able to access configuration information in the device in order to complete initialization. This happens without the need to perform any probing.

 

Each PCI peripheral is identified by domain (16 bits), bus (8 bits), device (5 bits) and function (3 bits).

every PCI slot has four interrupt pins, and each device function can use one of them without being concerned about how those pins are routed to the CPU.
PCI specification requires interrupt lines to be shareable

memory and I/O address region offered by the interface board can be remapped by means of configuration transactions, the firmware initializes PCI hardware at system boot, mapping each region to a different address to avoid collisions. The addresses to which these regions are currently mapped can be read from the configuration space, so the Linux driver can access its devices without probing.

配置地址空间是PCI相对ISA进步的主要特征。The PCI configuration space consists of 256 bytes for each device function (except for PCI Express devices, which have 4 KB )

加电时,PCI设备保持非活动状态,只接受configuration transactions。IO port和IO memory都未被映射到处理器的地址空间。中断也是禁止的。
PCI主板的固件(BIOS/NVRAM/PROM)一般都可识别PCI设备,固件以读写PCI controller寄存器的方式,访问设备的配置地址空间。
在设备被驱动访问之前,IO port和IO memory已被映射到处理器的地址空间,驱动可修改默认的指派,但没必要。

PCI registers are always little-endian

 

drivers/i2c/busses/i2c-i810.c:

static struct pci_device_id i810_ids[ ] = {
  { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1) },
  { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3) },
  { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG) },
  { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC) },
  { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_IG) },
  { 0, },
};

MODULE_DEVICE_TABLE(pci, i810_ids);

 

This statement creates a local variable called _ _mod_pci_device_table that points to the list of struct pci_device_id. Later in the kernel build process, the depmod program searches all modules for the symbol _ _mod_pci_device_table. If that symbol is found, it pulls the data out of the module and adds it to the file /lib/modules/KERNEL_VERSION/modules.pcimap. After depmod completes, all PCI devices that are supported by modules in the kernel are listed, along with their module names, in that file. When the kernel tells the hotplug system that a new PCI device has been found, the hotplug system uses the modules.pcimap file to find the proper driver to load.

static struct pci_driver pci_driver = {
  .name = "pci_skel",
  .id_table = ids,
  .probe = probe,
  .remove = remove,
};

pci_register_driver(&pci_driver);

 

const char *name;
const struct pci_device_id *id_table;
int (*probe) (struct pci_dev *dev, const struct pci_device_id *id);
void (*remove) (struct pci_dev *dev);
int (*suspend) (struct pci_dev *dev, u32 state);
int (*resume) (struct pci_dev *dev);

struct pci_driver 的内容

 

int pci_enable_device(struct pci_dev *dev);

int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val);
int pci_read_config_word(struct pci_dev *dev, int where, u16 *val);
int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val);
int pci_write_config_byte(struct pci_dev *dev, int where, u8 val);
int pci_write_config_word(struct pci_dev *dev, int where, u16 val);
int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);

int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 val);
int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 val);
int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 val);

A PCI device implements up to six I/O address regions. Each region consists of either memory or I/O locations.

In the kernel, the I/O regions of PCI devices have been integrated into the generic resource management. For this reason, you don't need to access the configuration variables in order to know where your device is mapped in memory or I/O space. The preferred interface for getting region information consists of the following functions:

unsigned long pci_resource_start(struct pci_dev *dev, int bar);
unsigned long pci_resource_end(struct pci_dev *dev, int bar);
unsigned long pci_resource_flags(struct pci_dev *dev, int bar);

IORESOURCE_IO
IORESOURCE_MEM
IORESOURCE_PREFETCH
IORESOURCE_READONLY

 

转载于:https://www.cnblogs.com/realplay/p/10918954.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值