USB device driver mouse
1. Overview
The USB mouse driver is roughly divided into two parts: the driver of the USB device and the driver of the input device. The driver of the USB device only plays the role of mounting the bus and transmitting data, the driver of the specific device type is still the subject of the work.
USB device driver: registers the USB device driver, implements probe and disconnect functions, initializes the USB mouse device type table (id_table) supported by the driver, initializes and submits the urb, according to the hid specification, the mouse has only one endpoint (excluding the endpoint 0) and belongs to the interrupted transmission type.
Input Device Driver: registers the input device and the event types supported by the device; Reports mouse events to the input core layer.
There is a concept to be aware that the interrupted transmission here is different from the interrupted hardware. The interrupted transmission is actually implemented by the USB hostcontrol polling USB device, USB Host control is based on the interrupt mechanism for the CPU. Take the USB mouse as an example. The USB Host Control continuously requests the USB mouse. The request interval is very short. The binterval field in the endpoint descriptor specifies that when the mouse experiences an event, the Mouse sends the data back to the host.
Host Control interrupts the CPU, so usb_mouse_irq is called. In usb_mouse_irq, the data sent from the mouse can be read. After reading the data, the driver calls usb_submit_urb again to send a request, just repeat it all the time, and a USB mouse driver is complete.
During hardware access, we only need to call urb-related interfaces, instead of concerning the details of the underlying USB host controller. Therefore, USB devices become independent of the platform, the same driver can be applied to different SOC.
2. Code Analysis
# Include <Linux/kernel. h> # include <Linux/slab. h> # include <Linux/module. h> # include <Linux/init. h> # include <Linux/USB/input. h> # include <Linux/hid. h>/* for Apple IDs */# ifdef config_usb_hid_module # include ".. /hid-ids.h "# endif/** version information */# define driver_version" v1.6 "# define driver_author" vojtech Pavlik <vojtech@ucw.cz> "# define driver_desc" USB hid boot protocol driver mouse "# define driv Er_license "GPL" loads (driver_author); module_description (driver_desc); module_license (driver_license);/**/struct usb_mouse {char name [128]; char phys [64]; struct usb_device * usbdev; struct input_dev * dev; struct urb * IRQ; signed Char * data; dma_addr_t data_dma;}; static void usb_mouse_irq (struct urb * urb) {struct usb_mouse * mouse = urb-> context;/* context points to the data block allocated by the USB driver */signed Char * Data = Mouse-> data; struct input_dev * Dev = mouse-> dev; int status;/* determine whether the transfer is successful */switch (urb-> Status) {Case 0: /* success */break; Case-econnreset:/* unlink */case-enoent: case-eshudown: return;/*-epipe: shocould clear the halt */default: /* Error */goto resubmit;}/* Report event */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);/* submit next transmission */resubmit: Status = usb_submit_urb (urb, gfp_atomic); If (Status) Err ("can't resubmit intr, % s-% S/input0, status % d ", mouse-> usbdev-> bus-> bus_name, MOU Se-> usbdev-> devpath, status);} 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 to the USB core layer; return 0;} static void usb_mouse_close (struct input_dev * Dev) {struct usb_mouse * mouse = input_get_drvdata (Dev); usb_kill_urb (mouse-> IRQ );} /* call when the USB device matches the driver */static int Usb_mouse_probe (struct usb_interface * INTF, const struct usb_device_id * ID) {/* Device description usb_device * // * interface description usb_interface */struct usb_device * Dev = interface_to_usbdev (INTF ); /* interface Setting Description */struct usb_host_interface * interface;/* endpoint descriptor */struct usb_endpoint_descriptor * endpoint; struct usb_mouse * mouse; struct input_dev * input_dev; int pipe, maxp; int error =-enomem;/* Get current interface settings */interface = INTF-> cur_alt Setting;/* According to the hid specification, the mouse has only one endpoint (excluding the control endpoint 0) */If (interface-> DESC. bnumendpoints! = 1) Return-enodev;/* obtain the endpoint 0 descriptor */Endpoint = & Interface-> endpoint [0]. DESC;/* According to the hid specification, the unique endpoint of the mouse should be the interrupt endpoint */If (! Usb_endpoint_is_int_in (endpoint) Return-enodev;/* generate the interrupted Pipeline */pipe = usb_rcvintpipe (Dev, endpoint-> bendpointaddress ); /* returns the maximum packet length that can be transmitted by the endpoint. The maximum packet length returned by the mouse is 4 bytes. */Maxp = usb_maxpacket (Dev, pipe, usb_pipeout (PIPE);/* Create an input device */mouse = kzarloc (sizeof (struct usb_mouse), gfp_kernel ); input_dev = input_allocate_device (); If (! Mouse |! Input_dev) goto fail1;/* apply for memory space for data transmission. Data is the address pointing to the Space */mouse-> DATA = usb_buffer_alloc (Dev, 8, gfp_atomic, & mouse-> data_dma); If (! Mouse-> data) goto fail1;/* allocate urb */mouse-> IRQ = usb_alloc_urb (0, gfp_kernel); If (! Mouse-> IRQ) goto fail2; mouse-> usbdev = dev; mouse-> Dev = input_dev; 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 the properties of the 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;/* set the event and Event code supported by the input device */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 (bytes); 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_se T_drvdata (input_dev, mouse); input_dev-> open = usb_mouse_open; input_dev-> close = usb_mouse_close;/* initialize interrupt 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; mouse-> IRQ-> transfer_flags | = cursor; /* register the input device with the input core layer */error = input_register_device (mouse-> Dev); If (error) goto fail3; usb_set_intfdata (INTF, mouse); Return 0; fail3: usb_free_urb (mouse-> IRQ); fail2: usb_buffer_free (Dev, 8, mouse-> data, mouse-> data_dma); fail1: input_free_device (input_dev); kfree (Mouse ); return Error;}/* call */static void usb_mouse_disconnect (struct usb_interface * INTF) When removing the USB device {struct usb_mouse * mouse = usb_get_intfdata (INTF); usb_set_intfdata (INTF, null ); if (Mouse) {usb_kill_urb (mouse-> IRQ); then (mouse-> Dev); usb_free_urb (mouse-> IRQ); usb_buffer_free (interface_to_usbdev (INTF), 8, mouse-> data, mouse-> data_dma); kfree (Mouse );}} /* Table of mouse types supported by the USB driver */static struct usb_device_id usb_mouse_id_table [] ={{ usb_interface_info (usb_interface_class_hid, drivers, drivers) },{}/ * terminating entry */}; module_device_table (USB, usb_mouse_id_table); static struct usb_driver usb_mouse_driver = {. name = "usbmouse",/* driver name */. probe = usb_mouse_probe,/* capture function */. disconnect = usb_mouse_disconnect,/* uninstall function */. id_table = usb_mouse_id_table,/* device list */}; static int _ init usb_mouse_init (void) {/* register the mouse driver */INT retval = usb_register (& usb_mouse_driver ); if (retval = 0) printk (kern_info kbuild_modname ":" driver_version ":" driver_desc "\ n"); Return retval;} static void _ exit usb_mouse_exit (void) {usb_deregister (& usb_mouse_driver);} module_init (usb_mouse_init); module_exit (usb_mouse_exit );