Linux驱动学习--初识PCI驱动(一)

news/2024/11/15 2:09:21/

PCI是什么
PCI—Peripheral Component Interconnect,外围设备互联总线。是一种广泛采用的总线标准,它提供了许多优于其它总线标准(如EISA)的新特性,目前已经成为计算机系统中应用最为广泛,并且最为通用的总线标准。
对于PCI的一些具体介绍可以参考: PCi具体介绍

一、和PCI驱动程序相关的几个数据结构
驱动程序总是离不开数据结构,在Linux中,用数据结构来表示各色各样的设备或者其他的东西。因此,我们掌握设备驱动程序的关键之一,就是对各种数据结构的理解和运用。

1、pci_device_id:
在介绍该结构之前,让我们来看看PCI的地址空间:I/O空间,存储空间,配置空间。

CPU 可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,而配置空间则由Linux内核中的PCI初始化代码使用,内核在 启动时负责对所有PCI设备进行初始化,配置好所有的PCI设备,包括中断号以及I/O基址,并在文件/proc/pci中列出所有找到的PCI设备,以 及这些我设备的参数和属性。

我们并不需要去了解配置寄存器的所有位代表了什么,有什么含义。我们只要用三个或者五个PCI寄存器去标识一个设备即可。通常,我们会选择下面三个寄存器:
vendorID: 标识硬件制造商,是一个16位的寄存器;

deviceID:设备ID,由制造商选择,也是一个16位的寄存器。一般与厂商ID配对生成一个唯一的32位硬件设备标识符;

class:每个外部设备属于某个类(class),也是一个16位的寄存器。当某个驱动程序可支持多个相似的设备,每个具有不同的签名,但都属于同一个类,这时,就可以用class类对它们的外设进行识别。

下面的数据结构就是–pci_device_id。

 struct pci_device_id {__u32 vendor, device;/* Vendor and device ID or PCI_ANY_ID*/__u32 subvendor, subdevice;/* Subsystem ID's or PCI_ANY_ID */__u32 class, class_mask;/* (class,subclass,prog-if) triplet */kernel_ulong_t driver_data;/* Data private to the driver */};

那现在问题又来了,我们前面说过,一个驱动程序可以匹配一个甚至多个设备。那么,此时我们又该如何呢?可以想到数组,对吧。是的,不过这里有点地方需要注意

 staticstruct pci_device_id example_pci_tbl [] __initdata ={{PCI_VENDOR_ID_EXAMPLE, PCI_DEVICE_ID_EXAMPLE, PCI_ANY_ID, PCI_ANY_ID,0,0, EXAMPLE},{0,}};

不管你这里匹配了多少设备,记得最后一个都是{0,}。

这里还有两个关于初始化该结构体的宏,可以用来简化相关的操作。
PCI_DEVICE(vendor, device)
创建一个仅和特定厂商及设备ID相匹配的struct pci_device_id。它把结构体的subvendor和subdevice设为PCI_ANY_ID。PCI_ANY_ID定义如下:

#define PCI_ANY_ID (~0)

PCI_DEVICE_CLASS(device_class, device_class_mask)
创建一个和特定PCI类相匹配的struct pci_device_id。

2.pci_driver:
按照上面说的,你已经将你要匹配的设备说明了,但这仅仅只是说明,内核如何去识别它们呢?那就要用到下面的数据结构了–pci_driver。

struct pci_driver {struct list_head node;char*name;conststruct pci_device_id *id_table;/* must be non-NULL for probe to be called */int(*probe)(struct pci_dev *dev,conststruct pci_device_id *id);/* New device inserted */void(*remove)(struct pci_dev *dev);/* Device removed (NULL if not a hot-plug capable driver) */int(*suspend)(struct pci_dev *dev,pm_message_t state);/* Device suspended */int(*suspend_late)(struct pci_dev *dev,pm_message_t state);int(*resume_early)(struct pci_dev *dev);int(*resume)(struct pci_dev *dev);/* Device woken up */void(*shutdown)(struct pci_dev *dev);struct pci_error_handlers *err_handler;struct device_driver driver;struct pci_dynids dynids;
};

从上面的结构体定义可以看出,它的作用并不仅仅是识别设备的id_table结构,还包括了检测设备的 函数probe( )和卸载设备的函数remove( ):这种结构体。

3.pci_dev:
让我们来最后最后一个相关的数据结构–pci_dev。

/*
* The pci_dev structure is used to describe PCI devices.
*/
struct pci_dev {struct list_head bus_list;/* node in per-bus list */struct pci_bus *bus;/* bus this device is on */struct pci_bus *subordinate;/* bus this device bridges to */void*sysdata;/* hook for sys-specific extension */struct proc_dir_entry *procent;/* device entry in /proc/bus/pci */struct pci_slot *slot;/* Physical slot this device is in */unsignedint devfn;/* encoded device & function index */unsignedshort vendor;unsignedshort device;unsignedshort subsystem_vendor;unsignedshort subsystem_device;unsignedintclass;/* 3 bytes: (base,sub,prog-if) */u8 revision;/* PCI revision, low byte of class word */u8 hdr_type;/* PCI header type (`multi' flag masked out) */u8 pcie_cap;/* PCI-E capability offset */u8 pcie_type;/* PCI-E device/port type */u8 rom_base_reg;/* which config register controls the ROM */u8 pin;/* which interrupt pin this device uses */struct pci_driver *driver;/* which driver has allocated this device */u64 dma_mask;/* Mask of the bits of bus address thisdevice implements. Normally this is0xffffffff. You only need to changethis if your device has broken DMAor supports 64-bit transfers. */struct device_dma_parameters dma_parms;pci_power_t current_state;/* Current operating state. In ACPI-speak,this is D0-D3, D0 being fully functional,and D3 being off. */int pm_cap;/* PM capability offset in theconfiguration space */unsignedint pme_support:5;/* Bitmask of states from which PME#can be generated */unsignedint pme_interrupt:1;unsignedint d1_support:1;/* Low power state D1 is supported */unsignedint d2_support:1;/* Low power state D2 is supported */unsignedint no_d1d2:1;/* Only allow D0 and D3 */unsignedint mmio_always_on:1;/* disallow turning off io/memdecoding during bar sizing */unsignedint wakeup_prepared:1;unsignedint d3_delay;/* D3->D0 transition time in ms */#ifdef CONFIG_PCIEASPMstruct pcie_link_state *link_state;/* ASPM link state. */#endifpci_channel_state_t error_state;/* current connectivity state */struct device dev;/* Generic device interface */int cfg_size;/* Size of configuration space *//** Instead of touching interrupt line and base address registers* directly, use the values stored here. They might be different!*/unsignedint irq;struct resource resource[DEVICE_COUNT_RESOURCE];/* I/O and memory regions + expansion ROMs */resource_size_t fw_addr[DEVICE_COUNT_RESOURCE];/* FW-assigned addr *//* These fields are used by common fixups */unsignedint transparent:1;/* Transparent PCI bridge */unsignedint multifunction:1;/* Part of multi-function device *//* keep track of device state */unsignedint is_added:1;unsignedint is_busmaster:1;/* device is busmaster */unsignedint no_msi:1;/* device may not use msi */unsignedint block_ucfg_access:1;/* userspace config space access is blocked */unsignedint broken_parity_status:1;/* Device generates false positive parity */unsignedint irq_reroute_variant:2;/* device needs IRQ rerouting variant */unsignedint msi_enabled:1;unsignedint msix_enabled:1;unsignedint ari_enabled:1;/* ARI forwarding */unsignedint is_managed:1;unsignedint is_pcie:1;/* Obsolete. Will be removed.Use pci_is_pcie() instead */unsignedint needs_freset:1;/* Dev requires fundamental reset */unsignedint state_saved:1;unsignedint is_physfn:1;unsignedint is_virtfn:1;unsignedint reset_fn:1;unsignedint is_hotplug_bridge:1;unsignedint __aer_firmware_first_valid:1;unsignedint __aer_firmware_first:1;pci_dev_flags_t dev_flags;atomic_t enable_cnt;/* pci_enable_device has been called */u32 saved_config_space[16];/* config space saved at suspend time */struct hlist_head saved_cap_space;struct bin_attribute *rom_attr;/* attribute descriptor for sysfs ROM entry */int rom_attr_enabled;/* has display of the rom attribute been enabled? */struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE];/* sysfs file for resources */struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE];/* sysfs file for WC mapping of resources */#ifdef CONFIG_PCI_MSIstruct list_head msi_list;#endifstruct pci_vpd *vpd;#ifdef CONFIG_PCI_IOVunion{struct pci_sriov *sriov;/* SR-IOV capability related */struct pci_dev *physfn;/* the PF this VF is associated with */};struct pci_ats *ats;/* Address Translation Service */#endif
};

由上面的定义可以知道,它详细描述了一个PCI设备几乎所有的硬件信息,包括厂商ID、设备ID、各种资源等。

二、基本框架
上面将我们要用到的一些基本信息都做了一些简单的介绍。下面,我们就来看看PCI驱动程序的一个基本的框架,如何将这些东西进行整理成一个程序。

staticstruct pci_device_id example_pci_tbl [] __initdata ={{PCI_VENDOR_ID_EXAMPLE, PCI_DEVICE_ID_EXAMPLE, PCI_ANY_ID, PCI_ANY_ID,0,0, EXAMPLE},{0,}};/* 对特定PCI设备进行描述的数据结构 */struct example_pci {unsignedint magic;/* 使用链表保存所有同类的PCI设备 */struct example_pci *next;/* ... */}/* 中断处理模块 */staticvoid example_interrupt(int irq,void*dev_id,struct pt_regs *regs){/* ... */}/* 设备文件操作接口 */staticstruct file_operations example_fops ={owner: THIS_MODULE,/* demo_fops所属的设备模块 */read: example_read,/* 读设备操作*/write: example_write,/* 写设备操作*/ioctl: example_ioctl,/* 控制设备操作*/open: example_open,/* 打开设备操作*/release: example_release /* 释放设备操作*//* ... */};/* 设备模块信息 */staticstruct pci_driver example_pci_driver ={name: example_MODULE_NAME,/* 设备模块名称 */id_table: example_pci_tbl,/* 能够驱动的设备列表 */probe: example_probe,/* 查找并初始化设备 */remove: example_remove /* 卸载设备模块 *//* ... */};staticint __init example_init_module (void){/* ... */}staticvoid __exit example_cleanup_module (void){pci_unregister_driver(&demo_pci_driver);}/* 加载驱动程序模块入口 */module_init( example_init_module);/* 卸载驱动程序模块入口 */module_exit( example_cleanup_module);

上面这段代码给出了一个典型的PCI设备驱动程序的框架,是一种相对固定的模式。


http://www.ppmy.cn/news/274653.html

相关文章

Linux驱动学习--PCI设备驱动

目录 一、引言 二、PCI总线介绍 三、PCI设备驱动组成 四、查看本机上的PCI设备 一、引言 PCI总线在linux中应用的十分广泛,本文就来简单介绍一下 二、PCI总线描述 1、PCI总线结构 PCI是CPU和外围设备通信的高速传输总线。普通PCI总线带宽一般为132MB/s(在3…

PCI驱动

一、PCI总线 1、PCI桥 Host/PCI桥:用于连接CPU与PCI根总线,即“北桥芯片组” PCI/ISA桥:用于连接PCI与旧的ISA总线,即“南桥芯片组” PCI-to-PCI桥:用于连接PCI主总线与次总线 2、pci_bus结构体(PCI总线结构…

pci驱动框架

PCI 总线架构主要被分成三部分: 1.PCI 设备。符合 PCI 总线标准的设备就被称为 PCI 设备,PCI 总线架构中可以包含多个 PCI 设备。图中的 Audio 、LAN 都是一个 PCI 设备。PCI 设备同时也分为主设备和目标设备两种,主设备是一次访问操作的发…

pci设备驱动

原文地址:https://www.cnblogs.com/xiaoya901109/archive/2012/12/14/2818057.html 一,初始化设备模块 当Linux内核启动并完成对所有PCI设备进行扫描、登录和分配资源等初始化操作的同时,会建立起系统中所有PCI设备的拓扑结构,此后…

PCI驱动开发学习笔记(一)

PCIE简介 PCIe作为串行总线的一种,它的发展必然和另一种总线架构密不可分:并行总线。 像PCIe接口的显卡、声卡、网卡,都属于功能设备,在PCIe规范中,我们统称为Endpoint(简称EP)。还有其他两类设…

Linux PCI总线驱动-1

Linux PCI总线驱动-1 一、PCI总线介绍1. PCI介绍2. PCI接口3. PCI-X介绍4. PCI-E介绍4.1 下图从上到下依次是PCIEX16,X1,X44.2 PCI-E各版本的传输速度4.3 PCI-E不同传输通道数设备的金手指数和长度4.4 三种接口的传输速度比较 二、pci设备基础知识2.1 内…

PCI驱动程序实现

1、数据结构: PCI设备上有三种地址空间:PCI的I/O空间、PCI的存储空间和PCI的配置空间。CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,而配置空间则由Linux内核中的PCI初始化代码使用。内核在…

vxworks pci驱动解析

PCI驱动分为两种类别: 1.CPU通过io方式访问的PCI设备驱动 2.dma方式的PCI设备驱动 其实就是两种方式 在io方式下访问PCI/SRIO设备 通过outbound寄存器将本地存储器映射到remote端pci设备 --------------------------------IOMMU过程 同时一般需要将CPU物理地址转换成…