我们基于mstar 一款4.9 的内核进行分析,针对原生内核我们做以下配置:
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_PROPERTIES=y
CONFIG_HID_MULTITOUCH=y
就可以适配一些标准的HID触摸屏和HID 触摸框。
HID 触摸驱动注册
hid-multitouch.c
static struct hid_driver mt_driver = {
.name = "hid-multitouch",
.id_table = mt_devices,
.probe = mt_probe,
.remove = mt_remove,
.input_mapping = mt_input_mapping,
.input_mapped = mt_input_mapped,
.input_configured = mt_input_configured,
.feature_mapping = mt_feature_mapping,
.usage_table = mt_grabbed_usages,
.event = mt_event,
.report = mt_report,
#ifdef CONFIG_PM
.reset_resume = mt_reset_resume,
.resume = mt_resume,
#endif
};
module_hid_driver(mt_driver);
最后会通过__hid_register_driver(hid-core.c) 注册到hid_bus_type 总线上面
static struct bus_type hid_bus_type = {
.name = "hid",
.dev_groups = hid_dev_groups,
.match = hid_bus_match,
.probe = hid_device_probe,
.remove = hid_device_remove,
.uevent = hid_uevent,
};
这样有hid 设备拔插时,hid 总线的探测函数会通过hid_bus_match 查找对应的驱动和设备
HID 设备连接
hid 总线找到驱动,设备之后。就会调用探测函数mt_probe(hid-multitouch.c)
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret, i;
struct mt_device *td;
struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) {
mtclass = &(mt_classes[i]);
break;
}
}
......
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
td->serial_maybe = true;
.....
ret = hid_parse(hdev);
if (ret != 0)
return ret;
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
return ret;
......
mt_set_maxcontacts(hdev);
mt_set_input_mode(hdev);
......
return 0;
}
hid_parse 解析完之后,hid_hw_start 配置硬件buffer,启动设备。
static inline int __must_check hid_hw_start(struct hid_device *hdev,
unsigned int connect_mask)
{
// usbhid_start (drivers\hid\usbhid\hid-core.c)
int ret = hdev->ll_driver->start(hdev);
if (ret || !connect_mask)
return ret;
ret = hid_connect(hdev, connect_mask);
if (ret)
hdev->ll_driver->stop(hdev);
return ret;
}
HID 申请注册urb 回调
static int usbhid_start(struct hid_device *hid)
{
struct usb_interface *intf = to_usb_interface(hid->dev.parent);
struct usb_host_interface *interface = intf->cur_altsetting;
struct usb_device *dev = interface_to_usbdev(intf);
struct usbhid_device *usbhid = hid->driver_data;
unsigned int n, insize = 0;
int ret;
clear_bit(HID_DISCONNECTED, &usbhid->iofl);
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)) {
ret = -ENOMEM;
goto fail;
}
for (n = 0; n < interface->desc.bNumEndpoints; n++) {
struct usb_endpoint_descriptor *endpoint;
int pipe;
int interval;
endpoint = &interface->endpoint[n].desc;
if (!usb_endpoint_xfer_int(endpoint))
continue;
interval = endpoint->bInterval;
/* Some vendors give fullspeed interval on highspeed devides */
if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
dev->speed == USB_SPEED_HIGH) {
interval = fls(endpoint->bInterval*8);
printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
hid->name, endpoint->bInterval, interval);
}
/* Change the polling interval of mice. */
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
interval = hid_mousepoll_interval;
ret = -ENOMEM;
if (usb_endpoint_dir_in(endpoint)) {
if (usbhid->urbin)
continue;
if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
goto fail;
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)))
goto fail;
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;
}
}
usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
if (!usbhid->urbctrl) {
ret = -ENOMEM;
goto fail;
}
usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
usbhid->ctrlbuf, 1, hid_ctrl, hid);
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
usbhid_init_reports(hid);
set_bit(HID_STARTED, &usbhid->iofl);
if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
ret = usb_autopm_get_interface(usbhid->intf);
if (ret)
goto fail;
usbhid->intf->needs_remote_wakeup = 1;
ret = hid_start_in(hid);
if (ret) {
dev_err(&hid->dev,
"failed to start in urb: %d\n", ret);
}
usb_autopm_put_interface(usbhid->intf);
}
/* Some keyboards don't work until their LEDs have been set.
* Since BIOSes do set the LEDs, it must be safe for any device
* that supports the keyboard boot protocol.
* In addition, enable remote wakeup by default for all keyboard
* devices supporting the boot protocol.
*/
if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT &&
interface->desc.bInterfaceProtocol ==
USB_INTERFACE_PROTOCOL_KEYBOARD) {
usbhid_set_leds(hid);
device_set_wakeup_enable(&dev->dev, 1);
}
return 0;
fail:
usb_free_urb(usbhid->urbin);
usb_free_urb(usbhid->urbout);
usb_free_urb(usbhid->urbctrl);
usbhid->urbin = NULL;
usbhid->urbout = NULL;
usbhid->urbctrl = NULL;
hid_free_buffers(dev, hid);
return ret;
}
- 设置最大buffer,hid_find_max_report设置最大上报大小
- usb_alloc_urb 申请urb
- usb_rcvintpipe 设置端点
- usb_fill_int_urb 注册urb 数据回调
分别注册了hid_irq_in,hid_irq_out,hid_ctrl。
HID 设备事件类型配置
hdev->ll_driver->start成功之后,会通过hid_connect
调用hidinput_connect 来接着完成HID 设置支持的事件类型。最终会调用到驱动的回调函数input_mapping,input_mapped。
最终会通过input_set_capability ,set_abs,input_set_abs_params 设置该hid 设备支持的事件类型。
HID数据上抛流程
usb_giveback_urb_bh (drivers\usb\core\hcd.c)
__usb_hcd_giveback_urb (drivers\usb\core\hcd.c)
hid_irq_in (drivers\hid\usbhid\hid-core.c)
hid_input_report (drivers\hid\hid-core.c)
hid_report_raw_event (drivers\hid\hid-core.c) 原始触摸数据
hid_input_field (drivers\hid\hid-core.c)
hid_process_event (drivers\hid\hid-core.c)
hdrv->event,hdrv->report (drivers\hid\hid-core.c)
mt_event (drivers\hid\hid-multitouch.c)
mt_report (drivers\hid\hid-multitouch.c)
客户协议数据解析
…