日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2023/12/18 linux 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux驱动学习--初识PCI驱动(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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設備驅動程序的框架,是一種相對固定的模式。

總結

以上是生活随笔為你收集整理的Linux驱动学习--初识PCI驱动(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。