linux HID驅(qū)動(dòng)分析
http://blog.csdn.net/walkingman321/article/details/7213710
HID 總線(xiàn)
HID的總線(xiàn)在hid-core.c的hid-init中初始化:
bus_register(&hid_bus_type);
hid_bus_type的定義:
static struct bus_type hid_bus_type = {
.name = "hid",*
.match = hid_bus_match,*
.probe = hid_device_probe,*
.remove = hid_device_remove,*
.uevent = hid_uevent,*
};
一般來(lái)說(shuō),HID驅(qū)動(dòng)很少定義自己的probe函數(shù)吐根,所以HID設(shè)備的匹配基本都是由總線(xiàn)probe和match函數(shù)完成正歼。
HID的匹配
hid_bus_match用于檢查設(shè)備和驅(qū)動(dòng)的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-開(kāi)頭的驅(qū)動(dòng),那么只要不在黑名單中即可匹配*
if (!strncmp(hdrv->name, "generic-", 8))*
return !hid_match_id(hdev, hid_blacklist);*
return 1;*
匹配了PID喜爷、VID之后冗疮,就進(jìn)入到hid_device_probe函數(shù):
*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) {*
// 再匹配一次,這里似乎與前面的hid_bus_match有些重復(fù)*
id = hid_match_device(hdev, hdrv);
if (id == NULL)*
return -ENODEV;*
hdev->driver = hdrv;*
if (hdrv->probe) { // 若驅(qū)動(dòng)定義了自己的probe函數(shù)則調(diào)用該probe檩帐,但一般HID驅(qū)動(dòng)不會(huì)定義*
ret = hdrv->probe(hdev, id);*
} else { // 默認(rèn)的probe過(guò)程*
ret = hid_parse(hdev);*
if (!ret)*
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);*
}*
if (ret)*
hdev->driver = NULL;*
}*
return ret;*
hid_parse函數(shù)的作用是解析HID描述符术幔,具體實(shí)現(xiàn)由hid_device->ll_driver->parse函數(shù)完成。關(guān)于HID描述符的文檔可在www.usb.org下載湃密。
*static inline int __must_check hid_parse(struct hid_device hdev)
ret = hdev->ll_driver->parse(hdev);*
由于HID描述符的解析是通用操作诅挑,所以HID框架中實(shí)現(xiàn)了一個(gè)解析函數(shù)hid_parse_report。一般來(lái)說(shuō)泛源,hdev->ll_driver->parse函數(shù)中只要調(diào)用hid_parse_report即可拔妥。
hid_parse_report比較復(fù)雜,其功能是解析HID描述符达箍,然后把解析出的結(jié)果放在hid_device->report_enum[type]-> report_list中没龙。每個(gè)解析出的HID結(jié)構(gòu)由一個(gè)hid_report描述。report_enum中的type可以是HID_INPUT_REPORT缎玫、HID_OUTPUT_REPORT或者HID_FEATURE_REPORT硬纤。
parse之后,probe函數(shù)又會(huì)調(diào)用hid_hw_start啟動(dòng)HID設(shè)備:
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中赃磨,首先會(huì)調(diào)用hdev->ll_driver->start啟動(dòng)設(shè)備筝家,然后是hid_connect將設(shè)備與HID框架關(guān)聯(lián)起來(lái)。
hdev->ll_driver->start函數(shù)由hid的具體設(shè)備提供邻辉,由該設(shè)備所屬的總線(xiàn)提供溪王,用于底層的初始化,這里暫不討論恩沛。
hid_connect會(huì)將hid_dev與具體驅(qū)動(dòng)關(guān)聯(lián)起來(lái)在扰。
*int hid_connect(struct hid_device hdev, unsigned int connect_mask)
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE) // 一般不會(huì)到這里*
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);*
if (hdev->bus != BUS_USB) // 如果不是USB總線(xiàn),那么去掉HID_CONNECT_HIDDEV標(biāo)記*
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;*
由此可見(jiàn)雷客,hid_connect共支持3種設(shè)備芒珠,首先是input設(shè)備,調(diào)用hidinput_connect登記搅裙;其次是hid_dev設(shè)備皱卓,調(diào)用hdev->hiddev_connect登記裹芝;最后是raw設(shè)備,調(diào)用hidraw_connect登記娜汁。
HID input
HID中最常用的是input設(shè)備嫂易,使用hidinput_connect登記到系統(tǒng)。hidinput_connect的主要作用是對(duì)hiddev中的每一個(gè)report掐禁,都建立一個(gè)input_dev設(shè)備怜械,并登記到input框架中。
*int hidinput_connect(struct hid_device hid, unsigned int force)
// 對(duì)每一個(gè)report傅事,建立一個(gè)input設(shè)備*
for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {*
if (!hidinput) {*
hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);*
input_dev = input_allocate_device();*
缕允。。蹭越。*
input_set_drvdata(input_dev, hid);*
input_dev->event = hid->ll_driver->hidinput_input_event;*
input_dev->open = hidinput_open;*
input_dev->close = hidinput_close;*
input_dev->setkeycode = hidinput_setkeycode;*
input_dev->getkeycode = hidinput_getkeycode;*
input_dev->name = hid->name;*
input_dev->phys = hid->phys;*
input_dev->uniq = hid->uniq;*
input_dev->id.bustype = hid->bus;*
input_dev->id.vendor = hid->vendor;*
input_dev->id.product = hid->product;*
input_dev->id.version = hid->version;*
input_dev->dev.parent = hid->dev.parent;*
hidinput->input = input_dev;*
list_add_tail(&hidinput->list, &hid->inputs);*
}*
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
HID dev設(shè)備目前僅在USB總線(xiàn)中用到障本,其用于登記的hiddev_connect函數(shù)指針目前僅有一個(gè)實(shí)例hiddev_connect,在usbhid_probe函數(shù)中被賦值响鹃。
hid->hiddev_connect = hiddev_connect;
HID raw dev
hidraw.c中定義了一個(gè)class hidraw驾霜,并創(chuàng)建設(shè)備設(shè)備驅(qū)動(dòng)
alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR, HIDRAW_MAX_DEVICES, "hidraw");
cdev_init(&hidraw_cdev, &hidraw_ops);
hidraw_ops中定義了一個(gè)基本的字符設(shè)備驅(qū)動(dòng)
static const struct file_operations hidraw_ops = {
.owner = THIS_MODULE,*
.read = hidraw_read,*
.write = hidraw_write,*
.poll = hidraw_poll,*
.open = hidraw_open,*
.release = hidraw_release,*
.unlocked_ioctl = hidraw_ioctl,*
};
由于是raw設(shè)備,所以這個(gè)驅(qū)動(dòng)中不會(huì)解析任何數(shù)據(jù)买置,只是簡(jiǎn)單的將應(yīng)用層數(shù)據(jù)傳給下層設(shè)備粪糙,以及將設(shè)備產(chǎn)生的數(shù)據(jù)傳給應(yīng)用層。具體實(shí)現(xiàn)可查看代碼堕义。
hid-core.c
http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/drivers/hid/hid-core.c#L495
hid-sersor-gyro-3d.c
http://lxr.free-electrons.com/source/drivers/iio/gyro/hid-sensor-gyro-3d.c#L264
android 驅(qū)動(dòng)學(xué)習(xí)
http://blog.csdn.net/vv0_0vv/article/category/1067351