
Click the above blue text to follow us!
Introduction
In previous articles, we have discussed the USB device driver framework. In this article, we will look at a specific device driver to further familiarize ourselves with these concepts. We will take the USB mouse as an example.
Analysis of USB Device Driver
Kernel Version: 4.20.12
Driver Path: /drivers/hid/usbhid/usbmouse.c
(1) Load and Unload Functions
static const struct usb_device_id usb_mouse_id_table[] = { { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_MOUSE) }, { } /* Terminating entry */};
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
static struct usb_driver usb_mouse_driver = { .name = "usbmouse", .probe = usb_mouse_probe, .disconnect = usb_mouse_disconnect, .id_table = usb_mouse_id_table,};
module_usb_driver(usb_mouse_driver);
The mouse driver is loaded based on the USB interface information, so it does not require PID and VID.
(2) probe()
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *dev = interface_to_usbdev(intf); struct usb_host_interface *interface; struct usb_endpoint_descriptor *endpoint; struct usb_mouse *mouse; struct input_dev *input_dev; int pipe, maxp; int error = -ENOMEM;
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 1) return -ENODEV; // Get endpoint descriptor endpoint = &interface->endpoint[0].desc; // Check if the endpoint is interrupt input if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; // Get communication pipe via endpoint address pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); // Get maximum data packet size maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL); input_dev = input_allocate_device(); // Allocate an input device
// Allocate a buffer with the same size as DMA // mouse->data_dma: the DMA address corresponding to the buffer, which is of type u32 mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
// Allocate URB mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
mouse->usbdev = dev; // Save usb_device mouse->dev = input_dev; // Save input_device // Device manufacturer and product name if (dev->manufacturer) strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
if (dev->product) { if (dev->manufacturer) strlcat(mouse->name, " ", sizeof(mouse->name)); strlcat(mouse->name, dev->product, sizeof(mouse->name)); }
if (!strlen(mouse->name)) snprintf(mouse->name, sizeof(mouse->name), "USB HIDBP Mouse %04x:%04x", le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct));
usb_make_path(dev, mouse->phys, sizeof(mouse->phys)); strlcat(mouse->phys, "/input0", sizeof(mouse->phys)); // Set input device input_dev->name = mouse->name; input_dev->phys = mouse->phys; usb_to_input_id(dev, &input_dev->id); input_dev->dev.parent = &intf->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
input_set_drvdata(input_dev, mouse); // Set the open and close functions for the input device input_dev->open = usb_mouse_open; input_dev->close = usb_mouse_close; // Initialize URB usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, (maxp > 8 ? 8 : maxp), usb_mouse_irq, mouse, endpoint->bInterval); mouse->irq->transfer_dma = mouse->data_dma; // DMA address mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; // Register input device error = input_register_device(mouse->dev); // Save private data usb_set_intfdata(intf, mouse); return 0; // Omitted error handling...}
The above code initializes the struct mouse. Since the mouse is an input device, it uses the input subsystem to initialize an input_dev.
The mouse is an input device, so it only needs to use the input endpoint. The data volume for the mouse is relatively small, so it uses interrupt transfer. As mentioned before, this type of transfer means that the USB host will continuously poll the device at specified intervals to check for data transmission.
-
disconnect()
static void usb_mouse_disconnect(struct usb_interface *intf){ struct usb_mouse *mouse = usb_get_intfdata (intf); // Release various resources usb_set_intfdata(intf, NULL); if (mouse) { usb_kill_urb(mouse->irq); input_unregister_device(mouse->dev); // Unregister input device usb_free_urb(mouse->irq); usb_free_coherent(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma); kfree(mouse); }}
(3) Input Device Open and Close
static int usb_mouse_open(struct input_dev *dev){ struct usb_mouse *mouse = input_get_drvdata(dev);
mouse->irq->dev = mouse->usbdev; // Submit URB if (usb_submit_urb(mouse->irq, GFP_KERNEL)) return -EIO;
return 0;}
static void usb_mouse_close(struct input_dev *dev){ struct usb_mouse *mouse = input_get_drvdata(dev); // Cancel URB usb_kill_urb(mouse->irq);}
URB is submitted to the endpoint only when the input device is opened, which officially starts communication.
(4) URB Transfer Completion Callback
static void usb_mouse_irq(struct urb *urb){ struct usb_mouse *mouse = urb->context; signed char *data = mouse->data; struct input_dev *dev = mouse->dev; int status;
switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: return; /* -EPIPE: should clear the halt */ default: /* error */ goto resubmit; } // Report events to upper layers input_report_key(dev, BTN_LEFT, data[0] & 0x01); input_report_key(dev, BTN_RIGHT, data[0] & 0x02); input_report_key(dev, BTN_MIDDLE, data[0] & 0x04); input_report_key(dev, BTN_SIDE, data[0] & 0x08); input_report_key(dev, BTN_EXTRA, data[0] & 0x10);
input_report_rel(dev, REL_X, data[1]); input_report_rel(dev, REL_Y, data[2]); input_report_rel(dev, REL_WHEEL, data[3]);
input_sync(dev); resubmit: // Resubmit URB status = usb_submit_urb (urb, GFP_ATOMIC); //......}
After reporting the input events, the URB is submitted to the endpoint again, forming a loop listening process.
Conclusion
The USB mouse is a relatively simple device, consisting of the USB device driver framework combined with the input subsystem. It is relatively easy to understand for those just learning about USB device drivers. Our main focus should be on understanding the overall framework, while more detailed aspects are related to specific devices.

END
Previous Recommendations
-
Analysis of USB Host Controller Driver
-
USB Driver Framework (V)
-
USB Driver Framework (IV)
-
USB Driver Framework (III)
Long press to recognize the QR code in the image to follow us