PCI驱动程序(第十二章 ) | pci设备驱动开发步骤

PCI驱动程序(第十二章 ) | pci设备驱动开发步骤

1、PCI(Peripheral Component Interconnect) 外围设备互联 2、PCI接口

(1)PCI寻址:每个PCI外设由一个总线编号,一个设备编号及一个功能编号来标识( biāo zhì 同“标志”,“①表明特征的记号。②表明某种特征。”)。

(2)在显示硬件地址时,有时显示为两个值(一个8位的总线编号和一个8位的设备及功能编号),有时显示为三个值(总线、设备和功能),有时显示为四个值(域、总线、设备和功能)。

3、引导阶段

(1)PCI字节序是小端的。

(2)用三个或者五个PCI寄存器可标识一个设备:vendorID、deviceID和class是常用的三个寄存器。有时厂商还利用subsystem vendorID和subSystem deviceID两个字段来进一步区分相似的设备。

vendorID:16位寄存器,用于标识硬件制造商

deviceID:16位寄存器,由制造商选择,无需对设备ID进行官方注册,通常与厂商ID配对成唯一一个32位硬件设备标识符。

class

subsystem vendorID

subsystem deviceID

struct pci_device_id结构体用于定义该驱动程序支持的不同类型的PCI设备列表。包含以下字段:

__u32 vendor;

__u32 device;

他们指定了设备的PCI厂商和设备ID。如果驱动程序可以处理任何厂商或者设备ID,这些字段应该使用值PCI_ANY_ID.

__u32 subvendor;

__u32 subdevice;

他们制定了设备的PCI子系统厂商和子系统设备ID。如果驱动程序可以处理任何类型的子系统ID,这些字段应该使用值PCI_ANY_ID

__u32 class;

__u32 class_mask;

kernel_ulong_t driver_data;

应该使用两个辅助的宏来进行struct pci_device_id结构砼的初始化:

PCI_DEVICE(vendor, device);

PCI_DEVICE_CLASS(device_class, device_class_mask);

4、MODULE_DEVICE_TABLE:完成将pci_device_id结构体需要被导出到用户控件的工作

5、注册PCI驱动程序:

为了正确注册带内核,所有的PCI驱动程序都必须创建的主要结构体是:struct pci_devicer结构体。该结构体由许多回调函数和变量组成。下面列出需要注意的字段:

const char *name;

const struct pci_device_id *id_table;

int (*probe) (struct pci_dev *dev, const strcut pci_device_id *id);

void (*remove) (struct pci_dev *dev);

int (*suspend) (struct pci_dev *dev);

int (*resume) (struct pci_dev *dev);

注:前四个字段是必须要初始化的。

struct pci_driver注册于卸载

例如:

static int __init pci_skel_init(void)

{

return pci_register_driver(&pci_driver);

}


static void __exit pci_skel_exit(void)

{

pci_unregister_driver(&pci_driver);

}

6、老式PCI探测

如果真的需要查找特定PCI设备的能力的话,可以使用下面的函数:

(1)struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from);

(2)struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from);

(3)strcut pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);

7、激活PCI设备

int pci_enable_device(struct pci_dev *dev);

8、访问配置空间

函数原型定义在<linux/pci.h>

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

word和dword函数会将读取到的little-endian值转换处理器固有的字节序,因此无需我们转换。

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

word和dword函数在把值写入外设之前,会将其换换成小字节序。上面的6个函数都实现为inline函数,他们实际上调用下面的函数:

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_world(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);

9、访问I/O和内存空间

在内核中,PCI设备的I/O区域已经被集成到通用资源管理,我们无需访问配置变量来了解设备映射到内存或I/O空间的何处,获取区域信息的首选接口由如下函数组成:

unsigned long pci_resource_start(strcut 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);

flags标志定义在<linux/ioport.h>中,下面是最重要的几个:

IORESOURCE_IO:

IORESOURCE_MEM:

IORESOURCE_PREFETCH:

IORESOURCE_READONLY:

10、PCI中断

11、硬件抽象:

配置寄存器访问的相关结构仅包含2个字段:

struct pci_ops {

int (*read) (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val);

int (*write) (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val);

};

免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部