linux HID驅動分析

2021-06-03 08:38:27 字數 4475 閱讀 9676

最近研究藍芽的鍵盤滑鼠,所以粗略看了一下linux的hid框架。

hid的匯流排在hid-core.c的hid-init中初始化:

bus_register(&hid_bus_type);

hid_bus_type的定義:

static struct bus_type hid_bus_type = ;

一般來說,hid驅動很少定義自己的probe函式,所以hid裝置的匹配基本都是由匯流排probe和match函式完成。

hid_bus_match用於檢查裝置和驅動的vid、pid是否匹配,**如下:

static int hid_bus_match(struct device *dev, struct device_driver *drv)

struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);

struct hid_device *hdev = container_of(dev, struct hid_device, dev);

// 匹配hdev和hdrv的vendorid和productid

if (!hid_match_device(hdev, hdrv))

return 0;

// 如果是generic-開頭的驅動,那麼只要不在黑名單中即可匹配

if (!strncmp(hdrv->name, "generic-", 8))

return !hid_match_id(hdev, hid_blacklist);

return 1;

匹配了pid、vid之後,就進入到hid_device_probe函式:

static int hid_device_probe(struct device *dev)

struct hid_driver *hdrv = container_of(dev->driver, struct hid_driver, driver);

struct hid_device *hdev = container_of(dev, struct hid_device, dev);

const struct hid_device_id *id;

int ret = 0;

if (!hdev->driver) else

if (ret)

hdev->driver = null; }

return ret;

static inline int __must_check hid_parse(struct hid_device *hdev)

ret = hdev->ll_driver->parse(hdev);

由於hid描述符的解析是通用操作,所以hid框架中實現了乙個解析函式hid_parse_report。一般來說,hdev->ll_driver->parse函式中只要呼叫hid_parse_report即可。

hid_parse_report比較複雜,其功能是解析hid描述符,然後把解析出的結果放在hid_device->report_enum[type]-> report_list中。每個解析出的hid結構由乙個hid_report描述。report_enum中的type可以是hid_input_report、hid_output_report或者hid_feature_report。

parse之後,probe函式又會呼叫hid_hw_start啟動hid裝置:

hid_hw_start(hdev, hid_connect_default);

注意這裡的hid_connect_default被定義為:

#define hid_connect_default       (hid_connect_hidinput|hid_connect_hidraw| \

hid_connect_hiddev|hid_connect_ff)

在hid_hw_start中,首先會呼叫hdev->ll_driver->start啟動裝置,然後是hid_connect將裝置與hid框架關聯起來。

hdev->ll_driver->start函式由hid的具體裝置提供,由該裝置所屬的匯流排提供,用於底層的初始化,這裡暫不討論。

hid_connect會將hid_dev與具體驅動關聯起來。

int hid_connect(struct hid_device *hdev, unsigned int connect_mask)

if (hdev->quirks & hid_quirk_hiddev_force)  // 一般不會到這裡

connect_mask |= (hid_connect_hiddev_force | hid_connect_hiddev);

if (hdev->bus != bus_usb) // 如果不是usb匯流排,那麼去掉hid_connect_hiddev標記

connect_mask &= ~hid_connect_hiddev;

if (hid_hiddev(hdev))  // 匹配某些特定vendorid和productid

connect_mask |= hid_connect_hiddev_force;

if ((connect_mask & hid_connect_hidinput) && !hidinput_connect(hdev,

connect_mask & hid_connect_hidinput_force))

hdev->claimed |= hid_claimed_input;

if ((connect_mask & hid_connect_hiddev) && hdev->hiddev_connect &&

!hdev->hiddev_connect(hdev,

connect_mask & hid_connect_hiddev_force))

hdev->claimed |= hid_claimed_hiddev;

if ((connect_mask & hid_connect_hidraw) && !hidraw_connect(hdev))

hdev->claimed |= hid_claimed_hidraw;

由此可見,hid_connect共支援3種裝置,首先是input裝置,呼叫hidinput_connect登記;其次是hid_dev裝置,呼叫hdev->hiddev_connect登記;最後是raw裝置,呼叫hidraw_connect登記。

hid中最常用的是input裝置,使用hidinput_connect登記到系統。hidinput_connect的主要作用是對hiddev中的每乙個report,都建立乙個input_dev裝置,並登記到input框架中。

int hidinput_connect(struct hid_device *hid, unsigned int force)

// 對每乙個report,建立乙個input裝置

for (k = hid_input_report; k <= max_report_type; k++)

list_for_each_entry(report, &hid->report_enum[k].report_list, list)

for (i = 0; i < report->maxfield; i++)

for (j = 0; j < report->field[i]->maxusage; j++)

hidinput_configure_usage(hidinput, report->field[i],

report->field[i]->usage + j); }

hid dev裝置目前僅在usb匯流排中用到,其用於登記的hiddev_connect函式指標目前僅有乙個例項hiddev_connect,在usbhid_probe函式中被賦值。

hid->hiddev_connect = hiddev_connect;

hidraw.c中定義了乙個class hidraw,並建立裝置裝置驅動

alloc_chrdev_region(&dev_id, hidraw_first_minor, hidraw_max_devices, "hidraw");

cdev_init(&hidraw_cdev, &hidraw_ops);

hidraw_ops中定義了乙個基本的字元裝置驅動

static const struct file_operations hidraw_ops = ;

由於是raw裝置,所以這個驅動中不會解析任何資料,只是簡單的將應用層資料傳給下層裝置,以及將裝置產生的資料傳給應用層。具體實現可檢視**。

hid中資料的傳輸有兩部分,一部分是從應用層到裝置,另一部分是從裝置到應用層。

對於hid input裝置,從裝置到應用層走的是標準的input框架,底層裝置通過hid_input_report函式將收到的資料送入hid框架,由hid框架解析並最終呼叫input_report_key之類的函式將資料上傳。

從應用層到裝置也由input框架完成:

hidinput_connect

input_dev->event = hid->ll_driver->hidinput_input_event;

U Boot NAND FLASH驅動分析

u boot nand flash 驅動分析 西伯利亞的風 一 初始化函式呼叫關係 初始化函式呼叫關係如圖 1.1所示。1.u boot 啟動過程中呼叫 nand init 初始化nand flash。2.函式nand init 呼叫nand init chip 完成nand flash 初始化。3...

platform驅動分析

platform驅動程式設計路線 註冊裝置 platform device 編寫裝置驅動。註冊裝置 struct platform device 其中比較重要的成員struct resource resource 表徵platform device所戰用的資源,當然對於比較簡單的裝置 普通的i 0 ...

U Boot NAND FLASH驅動分析

一 初始化函式呼叫關係 初始化函式呼叫關係如圖 1.1所示。1.u boot 啟動過程中呼叫 nand init 初始化nand flash。2.函式nand init 呼叫nand init chip 完成nand flash 初始化。3.nand init chip 順序呼叫 board nan...