当前位置:首页 > > 充电吧
[导读]作者: Sam(甄峰) sam_code@hotmail.com   1. 解读hiddevice probe程序: static int hid_probe(struct usb_interface

作者: Sam(甄峰) sam_code@hotmail.com

 

1. 解读hiddevice probe程序:

static int hid_probe(struct usb_interface*intf, const struct usb_device_id *id)
{
 struct hid_device *hid;
 char path[64];
 int i;
 char *c;

 dbg_hid("HID probecalled for ifnum %dn",
   intf->altsetting->desc.bInterfaceNumber);

 if (!(hid =usb_hid_configure(intf)))
  return -ENODEV;

 usbhid_init_reports(hid);
 hid_dump_device(hid);
 if (hid->quirks &HID_QUIRK_RESET_LEDS)
  usbhid_set_leds(hid);

 if(!hidinput_connect(hid))
  hid->claimed |=HID_CLAIMED_INPUT;
 if (!hiddev_connect(hid))
  hid->claimed |=HID_CLAIMED_HIDDEV;

 usb_set_intfdata(intf,hid);

 if(!hid->claimed) {
  printk ("HID device not claimedby input or hiddevn");
  hid_disconnect(intf);
  return -ENODEV;
 }

 if((hid->claimed &HID_CLAIMED_INPUT))
  hid_ff_init(hid);

 if(hid->quirks &HID_QUIRK_SONY_PS3_CONTROLLER)
  hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
   intf->cur_altsetting->desc.bInterfaceNumber);

 printk(KERN_INFO);

 if(hid->claimed &HID_CLAIMED_INPUT)
  printk("input");
 if (hid->claimed ==(HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
  printk(",");
 if (hid->claimed &HID_CLAIMED_HIDDEV)
  printk("hiddev%d",hid->minor);

 c = "Device";
 for (i = 0; i maxcollection; i++) {
  if(hid->collection[i].type ==HID_COLLECTION_APPLICATION &&
     (hid->collection[i].usage &HID_USAGE_PAGE) == HID_UP_GENDESK&&
     (hid->collection[i].usage & 0xffff)< ARRAY_SIZE(hid_types)) {
   c =hid_types[hid->collection[i].usage &0xffff];
   break;
  }
 }

 usb_make_path(interface_to_usbdev(intf),path, 63);

 printk(": USB HIDv%x.%02x %s [%s] on %sn",
  hid->version>> 8, hid->version& 0xff, c, hid->name,path);

 return 0;
}

1.1:usb_hid_configure(intf)解读:

从字面来看,它是指配置hid。

static struct hid_device*usb_hid_configure(struct usb_interface *intf)
{
 struct usb_host_interface *interface =intf->cur_altsetting;
 struct usb_device *dev = interface_to_usbdev(intf);
 struct hid_descriptor *hdesc;
 struct hid_device *hid;
 u32 quirks = 0;
 unsigned rsize = 0;
 char *rdesc;
 int n, len, insize = 0;
 struct usbhid_device *usbhid;

 

//得到对应vid,pid的quriks.如果没有,则返回0
 quirks =usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
   le16_to_cpu(dev->descriptor.idProduct));

 

//如果为boot设备且为keyboard或mouse.则quirks=HID_QUIRK_NOGET

 
 if(interface->desc.bInterfaceSubClass ==USB_INTERFACE_SUBCLASS_BOOT) {
  if(interface->desc.bInterfaceProtocol ==USB_INTERFACE_PROTOCOL_KEYBOARD ||
   interface->desc.bInterfaceProtocol== USB_INTERFACE_PROTOCOL_MOUSE)
    quirks|= HID_QUIRK_NOGET;
 }

 

//如果quirks显示要忽略,则退出probe

 if (quirks& HID_QUIRK_IGNORE)
  return NULL;

 

//HID_QUIRK_IGNORE_MOUSE表示如果为mouse,则忽略。

 if ((quirks& HID_QUIRK_IGNORE_MOUSE)&&
  (interface->desc.bInterfaceProtocol== USB_INTERFACE_PROTOCOL_MOUSE))
   returnNULL;

 

//如果interface扩展描述符中没有类型为HID_DT_HID条目,或者interface包含的endpoint数目为0,又或者interfaceendpoint中扩展描述符中没有类型为HID_DT_HID的条目。则退出。
 if(usb_get_extra_descriptor(interface, HID_DT_HID,&hdesc) &&
    (!interface->desc.bNumEndpoints ||
     usb_get_extra_descriptor(&interface->endpoint[0],HID_DT_HID, &hdesc))) {
  dbg_hid("class descriptor notpresentn");
  return NULL;
 }

 

//得到描述符长度:

 for (n = 0; n< hdesc->bNumDescriptors; n++)
  if(hdesc->desc[n].bDescriptorType ==HID_DT_REPORT)
   rsize =le16_to_cpu(hdesc->desc[n].wDescriptorLength);

 

//如果描述符长度不对,则退出

 if (!rsize || rsize> HID_MAX_DESCRIPTOR_SIZE) {
  dbg_hid("weird size of reportdescriptor (%u)n", rsize);
  return NULL;
 }

 

//创建此长度内存空间

 if (!(rdesc =kmalloc(rsize, GFP_KERNEL))) {
  dbg_hid("couldn't allocaterdesc memoryn");
  return NULL;
 }

 

//向dev的endpoint发送HID_REQ_SET_IDLErequest.

 hid_set_idle(dev,interface->desc.bInterfaceNumber, 0, 0);

 

//取得reportdescription的详细信息,放到rdesc中。

 if ((n =hid_get_class_descriptor(dev,interface->desc.bInterfaceNumber, HID_DT_REPORT,rdesc, rsize)) < 0) {
  dbg_hid("reading reportdescriptor failedn");
  kfree(rdesc);
  return NULL;
 }

 usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),
   le16_to_cpu(dev->descriptor.idProduct),rdesc,
   rsize,rdesc_quirks_param);

 dbg_hid("reportdescriptor (size %u, read %d) = ", rsize, n);
 for (n = 0; n < rsize; n++)
  dbg_hid_line(" %02x", (unsignedchar) rdesc[n]);
 dbg_hid_line("n");

 

//解析report。并建立hid_device.返回给hid.

 if (!(hid =hid_parse_report(rdesc, n))) {
  dbg_hid("parsing reportdescriptor failedn");
  kfree(rdesc);
  return NULL;
 }

 kfree(rdesc);
 hid->quirks = quirks;

 

 

 if (!(usbhid =kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
  goto fail_no_usbhid;

 hid->driver_data =usbhid;
 usbhid->hid = hid;

 usbhid->bufsize =HID_MIN_BUFFER_SIZE;
 hid_find_max_report(hid, HID_INPUT_REPORT,&usbhid->bufsize);
 hid_find_max_report(hid, HID_OUTPUT_REPORT,&usbhid->bufsize);
 hid_find_max_report(hid, HID_FEATURE_REPORT,&usbhid->bufsize);

 if(usbhid->bufsize >HID_MAX_BUFFER_SIZE)
  usbhid->bufsize= HID_MAX_BUFFER_SIZE;

 hid_find_max_report(hid,HID_INPUT_REPORT, &insize);

 if (insize> HID_MAX_BUFFER_SIZE)
  insize =HID_MAX_BUFFER_SIZE;

 if(hid_alloc_buffers(dev, hid)) {
  hid_free_buffers(dev,hid);
  goto fail;
 }

 for (n = 0; n< interface->desc.bNumEndpoints; n++){

  structusb_endpoint_descriptor *endpoint;
  int pipe;
  int interval;

  endpoint =&interface->endpoint[n].desc;
  if((endpoint->bmAttributes & 3) !=3)  
   continue;

  interval =endpoint->bInterval;

  
  if(hid->collection->usage ==HID_GD_MOUSE &&hid_mousepoll_interval > 0)
   interval =hid_mousepoll_interval;

  if(usb_endpoint_dir_in(endpoint)) {
   if(usbhid->urbin)
    continue;
   if(!(usbhid->urbin = usb_alloc_urb(0,GFP_KERNEL)))
    gotofail;
   pipe =usb_rcvintpipe(dev,endpoint->bEndpointAddress);
   usb_fill_int_urb(usbhid->urbin,dev, pipe, usbhid->inbuf, insize,
     hid_irq_in, hid, interval);
   usbhid->urbin->transfer_dma= usbhid->inbuf_dma;
   usbhid->urbin->transfer_flags|= URB_NO_TRANSFER_DMA_MAP;
  } else {
   if(usbhid->urbout)
    continue;
   if(!(usbhid->urbout = usb_alloc_urb(0,GFP_KERNEL)))
    gotofail;
   pipe =usb_sndintpipe(dev,endpoint->bEndpointAddress);
   usb_fill_int_urb(usbhid->urbout,dev, pipe, usbhid->outbuf, 0,
     hid_irq_out, hid, interval);
   usbhid->urbout->transfer_dma= usbhid->outbuf_dma;
   usbhid->urbout->transfer_flags|= URB_NO_TRANSFER_DMA_MAP;
  }
 }

 if(!usbhid->urbin) {
  err_hid("couldn't find an inputinterrupt endpoint");
  goto fail;
 }

 init_waitqueue_head(&hid->wait);

 INIT_WORK(&usbhid->reset_work,hid_reset);
 setup_timer(&usbhid->io_retry,hid_retry_timeout, (unsigned long) hid);

 spin_lock_init(&usbhid->inlock);
 spin_lock_init(&usbhid->outlock);
 spin_lock_init(&usbhid->ctrllock);

 hid->version =le16_to_cpu(hdesc->bcdHID);
 hid->country =hdesc->bCountryCode;
 hid->dev =&intf->dev;
 usbhid->intf = intf;
 usbhid->ifnum =interface->desc.bInterfaceNumber;

 hid->name[0] =0;

 if(dev->manufacturer)
  strlcpy(hid->name,dev->manufacturer,sizeof(hid->name));

 if(dev->product) {
  if(dev->manufacturer)
   strlcat(hid->name," ", sizeof(hid->name));
  strlcat(hid->name,dev->product,sizeof(hid->name));
 }

 if(!strlen(hid->name))
  snprintf(hid->name,sizeof(hid->name), "HID %04x:%04x",
   le16_to_cpu(dev->descriptor.idVendor),
   le16_to_cpu(dev->descriptor.idProduct));

 hid->bus= BUS_USB;
 hid->vendor =le16_to_cpu(dev->descriptor.idVendor);
 hid->product =le16_to_cpu(dev->descriptor.idProduct);

 usb_make_path(dev,hid->phys, sizeof(hid->phys));
 strlcat(hid->phys, "/input",sizeof(hid->phys));
 len = strlen(hid->phys);
 if (len phys) - 1)
  snprintf(hid->phys+ len, sizeof(hid->phys) - len,
    "%d",intf->altsetting[0].desc.bInterfaceNumber);

 if (usb_string(dev,dev->descriptor.iSerialNumber,hid->uniq, 64) <= 0)
  hid->uniq[0] =0;

 usbhid->urbctrl =usb_alloc_urb(0, GFP_KERNEL);
 if (!usbhid->urbctrl)
  goto fail;

 usb_fill_control_urb(usbhid->urbctrl,dev, 0, (void *) usbhid->cr,
       usbhid->ctrlbuf, 1, hid_ctrl, hid);
 usbhid->urbctrl->setup_dma= usbhid->cr_dma;
 usbhid->urbctrl->transfer_dma= usbhid->ctrlbuf_dma;
 usbhid->urbctrl->transfer_flags|= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
 hid->hidinput_input_event =usb_hidinput_input_event;
 hid->hid_open = usbhid_open;
 hid->hid_close =usbhid_close;
#ifdef CONFIG_USB_HIDDEV
 hid->hiddev_hid_event =hiddev_hid_event;
 hid->hiddev_report_event =hiddev_report_event;
#endif
 return hid;

fail:
 usb_free_urb(usbhid->urbin);
 usb_free_urb(usbhid->urbout);
 usb_free_urb(usbhid->urbctrl);
 hid_free_buffers(dev, hid);
 kfree(usbhid);
fail_no_usbhid:
 hid_free_device(hid);

 return NULL;
}

 

1.1.1:usbhid_lookup_quirk(pid,vid)解析:

分别使用usbhid_exists_dquirk(pid,vid),usbhid_exists_squirk(pid,vid)来查看动态和静态的quirks-list.如果有,则返回此quirks.没有,则返回0。

 

1.1.2:usb_get_extra_descriptor(descriptor, type,&hdesc)解析:

它调用__usb_get_extra_descriptor()来解析参数一(interface或endpoint描述符)中的扩展描述符区--extra。看是否有类型为参数二(type)的条目,然后把地址交给参数三。

Sam未经证明的猜测:HID设备中,interface描述符中包含的这个扩展描述符。其中存放的都是HID信息,以hid_descriptor结构存放。

对于HID设备来说,在interface description之后会附加一个hid description, hiddescription中的最后部份包含有Report description或者PhysicalDescriptors的长度.

hid_descriptor->usb_descriptor_header->bDescriptorType为HID_DT_HID

后面描述符(包括它自己)hid_descriptor->hid_class_descriptor->bDescriptorType为HID_DT_REPORT

 

1.1.3:hid_set_idle(structusb_device *dev, int ifnum, int report, intidle):

它简单的调用usb_control_msg() 发送或接收一个usb控制消息。

具体到这个例子中:

usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
  HID_REQ_SET_IDLE,USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle<< 8) | report,
  ifnum, NULL, 0,USB_CTRL_SET_TIMEOUT);

usb_sndctrlpipe(dev,0):指出将dev中endpoint 0 设为发送control管道。

HID_REQ_SET_IDLE:此控制消息的Request。

USB_TYPE_CLASS |USB_RECIP_INTERFACE:请求类型.

调用成功才会返回。

 

1.1.4:hid_get_class_descriptor(dev,interface->desc.bInterfaceNumber, HID_DT_REPORT,rdesc, rsize)

也是通过调用usb_control_msg() 发送或接收一个usb控制消息。

发送USB_REQ_GET_DESCRIPTOR,将得到的report descriptor放到rdesc中。

 

1.1.5: hid_parse_report(__u8*start, unsigned size)

参数一:通过usb_control_msg发送request(USB_REQ_GET_DESCRIPTOR)从设备得到的report descriptor.

参数二:是此report Descriptor的长度。

1).首先创建hid_device类型设备。

2).将参数一中数据保存在hid_device->rdesc中。长度保存在hid_device->rsize中。

3). 使用fetch_item(__u8 *start, __u8 *end, struct hid_item*item)得到report description的下一项数据。放到item中。

4). 根据不同的item.type.分别调用

hid_parser_main,
  hid_parser_global,
  hid_parser_local,
  hid_parser_reserved

来处理。

 


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭