您的位置:首页 > 运维架构 > Linux

《Linux总线、设备与驱动》USBHID设备驱动

2018-03-07 16:40 633 查看
转载地址:http://blog.csdn.net/tankai19880619/article/details/17447791

说明:本分析基于mstar801平台Linux2.6.35.11内核,其他内核版本仅供参考。

一、HID虚拟总线驱动加载

drivers/hid/hid-core.c

[cpp] view
plain copy

module_init(hid_init);  

static int __init hid_init(void){  

  ret = bus_register(&hid_bus_type);  //注册HID虚拟总线  

  ret = hidraw_init();  

}  

static struct bus_type hid_bus_type = {  

  .name       = "hid",  

  .match      = hid_bus_match,  

  .probe      = hid_device_probe,  

  .remove     = hid_device_remove,  

  .uevent     = hid_uevent,  

};  

二、USBHID驱动加载

USBHID驱动同时包含USB总线设备驱动和HID总线设备驱动。

drivers/hid/usbhid/hid-core.c

[cpp] view
plain copy

static int __init hid_init(void){  

  retval = hid_register_driver(&hid_usb_driver);  //注册HID总线设备驱动  

  retval = usb_register(&hid_driver);  //注册USB总线设备驱动  

}  

module_init(hid_init);  

static struct hid_driver hid_usb_driver = { //一般HID驱动都不实现probe方法  

  .name = "generic-usb",  

  .id_table = hid_usb_table,  

};  

static struct usb_driver hid_driver = {  //USB设备驱动方法  

  .name =     "usbhid",  

  .probe =    usbhid_probe,  

  .disconnect =   usbhid_disconnect,  

 #ifdef CONFIG_PM  

  .suspend =  hid_suspend,  

  .resume =   hid_resume,  

  .reset_resume = hid_reset_resume,  

#endif  

  .pre_reset =    hid_pre_reset,  

   .post_reset =   hid_post_reset,  

  .id_table = hid_usb_ids,  

  .supports_autosuspend = 1,  

};  

三、USBHID设备探测

1.USB总线的设备探测并注册HID设备

USB设备发现机制看如下链接:

《Linux总线、设备与驱动》USB设备发现机制

drivers/hid/usbhid/hid-core.c

[cpp] view
plain copy

static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id){  

  hid = hid_allocate_device(); //申请HID设备  

  hid->ll_driver = &usb_hid_driver; //重要!  

  /* 

  static struct hid_ll_driver usb_hid_driver = { 

    .parse = usbhid_parse, 

    .start = usbhid_start, 

    .stop = usbhid_stop, 

    .open = usbhid_open, 

    .close = usbhid_close, 

    .power = usbhid_power, 

    .hidinput_input_event = usb_hidinput_input_event, 

  }; 

  */  

  hid->hiddev_connect = hiddev_connect;  

  hid->hiddev_disconnect = hiddev_disconnect;  

  hid->hiddev_hid_event = hiddev_hid_event;  

  hid->hiddev_report_event = hiddev_report_event;  

  usb_make_path(dev, hid->phys, sizeof(hid->phys));  

  strlcat(hid->phys, "/input", sizeof(hid->phys));  

  if (len < sizeof(hid->phys) - 1)  

    snprintf(hid->phys + len, sizeof(hid->phys) - len, "%d", intf->altsetting[0].desc.bInterfaceNumber);  

  ret = hid_add_device(hid); //注册HID设备  

}  

申请HID设备:

drivers/hid/hid-core.c

[cpp] view
plain copy

struct hid_device *hid_allocate_device(void){  

  struct hid_device *hdev;  

  device_initialize(&hdev->dev);  

  hdev->dev.release = hid_device_release;  

  hdev->dev.bus = &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,  

};  

注册HID设备:

drivers/hid/hid-core.c

[cpp] view
plain copy

int hid_add_device(struct hid_device *hdev){  

  ret = device_add(&hdev->dev); //该函数的调用将导致总线对应match和probe的调用  

}  

2.HID总线的设备探测

参考USB总线探测:http://blog.csdn.net/tankai19880619/article/details/11639185

drivers/hid/hid-core.c

[cpp] view
plain copy

//HID总线match函数  

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

  if (!hid_match_device(hdev, hdrv)) //匹配VID和PID  

    return 0;  

  if (!strncmp(hdrv->name, "generic-", 8)) //名字为generic-都匹配  

    return !hid_match_id(hdev, hid_have_special_driver);  

}  

//HID总线的probe函数  

static int hid_device_probe(struct device *dev){  

  if (hdrv->probe) { //一般HID驱动都没有实现probe方法  

    ret = hdrv->probe(hdev, id);  

  } else { /* default probe */  

     ret = hid_parse(hdev);  

     /* 

     include/linux/hid.h 

     static inline int __must_check hid_parse(struct hid_device *hdev){ 

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

       if (!ret) 

         hdev->status |= HID_STAT_PARSED; 

       return ret; 

     } 

     drivers/hid/usbhid/hid-core.c 

     static int usbhid_parse(struct hid_device *hid){ 

       ret = hid_parse_report(hid, rdesc, rsize); 

     } 

     */  

     if (!ret)  

       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);  

       /* 

       include/linux/hid.h 

       static inline int __must_check hid_hw_start(struct hid_device *hdev, 

unsigned int connect_mask){ 

         int ret = hdev->ll_driver->start(hdev); 

         ret = hid_connect(hdev, connect_mask); 

         if (ret) 

           hdev->ll_driver->stop(hdev); 

       } 

       drivers/hid/usbhid/hid-core.c 

       static int usbhid_start(struct hid_device *hid){ 

   

       } 

       */  

  }  

}  

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

  static const char *types[] = { "Device", "Pointer", "Mouse", "Device",  

    "Joystick", "Gamepad", "Keyboard", "Keypad",  

    "Multi-Axis Controller"  

  };  

  //HIDINPUT设备  

  if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,connect_mask & HID_CONNECT_HIDINPUT_FORCE))  

    hdev->claimed |= HID_CLAIMED_INPUT;  

  //HIDDEV设备  

  if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect && !hdev->hiddev_connect(hdev,connect_mask & HID_CONNECT_HIDDEV_FORCE))  

    hdev->claimed |= HID_CLAIMED_HIDDEV;  

  //HIDRAW设备  

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

    hdev->claimed |= HID_CLAIMED_HIDRAW;  

}  

四、具体设备驱动

1.HIDINPUT设备,如走2.4G的遥控器

drivers/hid/hid-input.c

[cpp] view
plain copy

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

  //申请设备  

  input_dev = input_allocate_device();  

  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;  

  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);  

  /* 

  static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, 

      struct hid_usage *usage){ 

    switch (usage->hid & HID_USAGE_PAGE) { 

      case HID_UP_KEYBOARD: 

        set_bit(EV_REP, input->evbit); 

        if ((usage->hid & HID_USAGE) < 256) { 

          if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore; 

            map_key_clear(hid_keyboard[usage->hid & HID_USAGE]); 

            /* 

            static const unsigned char hid_keyboard[256] = { 

              0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 

              50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3, 

              4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26, 

              27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 

              65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 

              105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 

              72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 

              191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 

              115,114,unk,172,194,121,229, 89, 93,124, 92, 94, 95,unk,unk,unk, 

              122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk, 

              unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, 

              unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk, 

              unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, 

              unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk, 

              29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 

              150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk 

            }; 

            */  

          } else  

             map_key(KEY_UNKNOWN);  

          break;  

        }  

      }  

   }  

  */  

  //注册设备  

  if (hidinput && input_register_device(hidinput->input))  

    goto out_cleanup;  

}  

2.HIDDEV设备

drivers/hid/usbhid/hiddev.c

[cpp] view
plain copy

int hiddev_connect(struct hid_device *hid, unsigned int force){  

  retval = usb_register_dev(usbhid->intf, &hiddev_class);  

}  

3.HIDRAW设备,用来与设备做原始的通讯

这个驱动中不会解析任何数据,只是简单的将设备产生的数据传给应用层。

drivers/hid/hidraw.c

[cpp] view
plain copy

int hidraw_connect(struct hid_device *hid){  

  dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor), NULL, "%s%d", "hidraw", minor);  

}  

五、设备移除部分

1.USB总线设备移除触发USBHID中USB驱动部分调用

drivers/hid/usbhid/hid-core.c

[cpp] view
plain copy

retval = usb_register(&hid_driver);  

static struct usb_driver hid_driver = {  

  .disconnect =   usbhid_disconnect,  

}  

static void usbhid_disconnect(struct usb_interface *intf){  

  hid_destroy_device(hid); //调用HID总线的设备注销函数  

}  

2.HID总线驱动

drivers/hid/hid-core.c

[cpp] view
plain copy

void hid_destroy_device(struct hid_device *hdev){  

  hid_remove_device(hdev);  

}  

static void hid_remove_device(struct hid_device *hdev){  

  device_del(&hdev->dev);  

}  

//总线设备注销触发总线函数调用:  

static struct bus_type hid_bus_type = {  

  .remove     = hid_device_remove,  

}  

static int hid_device_remove(struct device *dev){  

  if (hdrv) {  

    if (hdrv->remove)  

      hdrv->remove(hdev);  

    else /* default remove */  

      hid_hw_stop(hdev);  

      /* 

      include/linux/hid.h 

      static inline void hid_hw_stop(struct hid_device *hdev){ 

        hid_disconnect(hdev); 

      } 

      */  

    hdev->driver = NULL;  

  }  

}  

void hid_disconnect(struct hid_device *hdev){  

  device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc);  

  if (hdev->claimed & HID_CLAIMED_INPUT)  

    hidinput_disconnect(hdev); //HIDINPUT设备  

  if (hdev->claimed & HID_CLAIMED_HIDDEV)  

    hdev->hiddev_disconnect(hdev);  //HIDDEV设备  

  if (hdev->claimed & HID_CLAIMED_HIDRAW)  

    hidraw_disconnect(hdev);  //HIDRAW设备  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: