linux - bluetooth - hid - demo

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末猜旬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子倦卖,更是在濱河造成了極大的恐慌洒擦,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怕膛,死亡現(xiàn)場(chǎng)離奇詭異熟嫩,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)褐捻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)掸茅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人柠逞,你說(shuō)我怎么就攤上這事昧狮。” “怎么了板壮?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵逗鸣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)撒璧,這世上最難降的妖魔是什么透葛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮卿樱,結(jié)果婚禮上僚害,老公的妹妹穿的比我還像新娘。我一直安慰自己繁调,他們只是感情好萨蚕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著涉馁,像睡著了一般门岔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烤送,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音糠悯,去河邊找鬼帮坚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛互艾,可吹牛的內(nèi)容都是我干的试和。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼纫普,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼阅悍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起昨稼,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤节视,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后假栓,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體寻行,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年匾荆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拌蜘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牙丽,死狀恐怖简卧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烤芦,我是刑警寧澤举娩,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響晓铆,放射性物質(zhì)發(fā)生泄漏勺良。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一骄噪、第九天 我趴在偏房一處隱蔽的房頂上張望尚困。 院中可真熱鬧,春花似錦链蕊、人聲如沸事甜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逻谦。三九已至,卻和暖如春陪蜻,著一層夾襖步出監(jiān)牢的瞬間邦马,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工宴卖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留滋将,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓症昏,卻偏偏與公主長(zhǎng)得像随闽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肝谭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容