USB Driver--keyboard driver (control transfer)

Source: Internet
Author: User
Tags 04x

This article takes USBKBD.C as an example to analyze the USB keyboard driver.

static int __init usb_kbd_init (void) {int result = Usb_register (&usb_kbd_driver); if (result = = 0) printk (kern_info Kbuild_modname ":" Driver_version ":" Driver_desc "\ n"); return result;}
static struct Usb_driver usb_kbd_driver = {. Name = "USBKBD",. Probe =usb_kbd_probe,.disconnect =usb_kbd_disconnect,.id_ Table =usb_kbd_id_table,};
or look at id_table, compared to the mouse, only the protocol is not the same.

static struct usb_device_id usb_kbd_id_table [] = {{Usb_interface_info (Usb_interface_class_hid, Usb_interface_ Subclass_boot,usb_interface_protocol_keyboard)},{}/* terminating entry * *};

Let's look at the probe function

static int usb_kbd_probe (struct usb_interface *iface, const struct USB_DEVICE_ID *id) {/* get Usb_device */struct Usb_device *dev = Interface_to_usbdev (iface);/* Interface settings */struct usb_host_interface *interface;/* Endpoint Descriptor */struct Usb_endpoint_ Descriptor *endpoint;/* Keyboard Structural body */struct usb_kbd *kbd;/* input device */struct input_dev *input_dev;int i, pipe, maxp;int error =-E Nomem;/* gets the current setting of the interface */interface = iface->cur_altsetting;/* If the number of endpoints currently set is not 1, then error, return */if (interface-> Desc.bnumendpoints! = 1) return-enodev;/* If the type of the first endpoint currently set is not an interrupt endpoint, error, return */endpoint = &interface->endpoint[0].desc if (!usb_endpoint_is_int_in (endpoint)) return-enodev;/* the first endpoint of the pipeline */pipe = Usb_rcvintpipe (Dev, endpoint-> bendpointaddress);/* Maximum transmission packet size */MAXP = usb_maxpacket (dev, pipe, usb_pipeout (pipe));/* Allocates space for the keyboard structure */KBD = Kzalloc (sizeof ( struct USB_KBD), gfp_kernel);/* Assign an input device */input_dev = Input_allocate_device ();/* Kbd->irq = usb_alloc_urb (0, Gfp_ KERNEL) kbd->led = usb_alloc_urb (0, gfp_kernel) kbd->new = Usb_buffer_allOC (Dev, 8, gfp_atomic, &AMP;KBD-&GT;NEW_DMA) kbd->cr = Usb_buffer_alloc (dev, sizeof (struct usb_ctrlrequest), Gfp_ ATOMIC, &AMP;KBD-&GT;CR_DMA) kbd->leds = Usb_buffer_alloc (Dev, 1, gfp_atomic, &AMP;KBD-&GT;LEDS_DMA) */if (usb_kbd_ Alloc_mem (Dev, kbd)) Goto fail2;/* fills the keyboard structure. and some strings */kbd->usbdev = Dev;kbd->dev = Input_dev;if (dev->manufacturer) strlcpy (Kbd->name, dev-> Manufacturer, sizeof (kbd->name)), if (dev->product) {if (dev->manufacturer) strlcat (Kbd->name, "", sizeof ( Kbd->name)); Strlcat (Kbd->name, dev->product, sizeof (Kbd->name));} if (!strlen (kbd->name)) snprintf (kbd->name, sizeof (Kbd->name), "USB hidbp Keyboard%04x:%04x", Le16_to_cpu ( Dev->descriptor.idvendor), Le16_to_cpu (dev->descriptor.idproduct)) Usb_make_path (Dev, Kbd->phys, sizeof ( Kbd->phys)); strlcpy (Kbd->phys, "/input0", sizeof (Kbd->phys));/* Fill input device */input_dev->name = kbd->name; Input_dev->phys = kbd->phys;usb_to_input_id (dev, &input_dev->id);Nput_dev->dev.parent = &iface->dev;input_set_drvdata (Input_dev, KBD);/* Sets the type of event it supports and the specific event 1, key class event 2, LED lamp (case lamp, etc.) 3, repeat escalation */input_dev->evbit[0] = Bit_mask (Ev_key) | Bit_mask (ev_led) | Bit_mask (Ev_rep); input_dev->ledbit[0] = Bit_mask (LED_NUML) | Bit_mask (LED_CAPSL) | Bit_mask (led_scrolll) | Bit_mask (Led_compose) | Bit_mask (Led_kana); for (i = 0; i < 255; i++) Set_bit (Usb_kbd_keycode[i], input_dev->keybit); Clear_bit (0, Input_ Dev->keybit);/* For an event with an LED type, the event is first called to dev->event and then invoked to the incident handler layer */input_dev->event = usb_kbd_event;input_dev- >open = Usb_kbd_open;input_dev->close = usb_kbd_close;/* Fill Break type Urb */usb_fill_int_urb (KBD-&GT;IRQ, Dev, pipe, Kbd->new, (Maxp > 8 8:maxp), USB_KBD_IRQ, KBD, endpoint->binterval); KBD-&GT;IRQ-&GT;TRANSFER_DMA = Kbd->ne W_dma;kbd->irq->transfer_flags |= urb_no_transfer_dma_map;/* * Bit7 control the direction of transmission data phase 0 host to device 1 device to host, here 0 host to device *bit5 6 is the request type, Standard or factory defined, and here is the HID class definition *bit0-4 Indicates whether this is a device, interface, or endpoint, which is the interface */kbd->cR->brequesttype = Usb_type_class | usb_recip_interface;//0x01 << 5 | /* #define Usb_req_get_status0x00#define usb_req_clear_feature0x01#define usb_req_set_feature0x03#define USB_REQ_ Set_address0x05#define Usb_req_get_descriptor0x06#define Usb_req_set_descriptor0x07#define USB_REQ_GET_ Configuration0x08#define Usb_req_set_configuration0x09#define Usb_req_get_interface0x0a#define USB_REQ_SET_ Interface0x0b#define usb_req_synch_frame0x0c*/kbd->cr->brequest = parameter of usb_req_set_configuration;/* request */ Kbd->cr->wvalue = Cpu_to_le16 (0x200);/* Brequesttype, for interfaces, endpoints, it represents that interface or endpoint */kbd->cr->windex = cpu_to_ Le16 (interface->desc.binterfacenumber); */* data phase length */kbd->cr->wlength = CPU_TO_LE16 (1);/* Static inline void Usb_fill_control_urb (struct URB *urb,struct usb_device *dev,unsigned int pipe,unsigned Char *setup_packet,void * Transfer_buffer,int buffer_length,usb_complete_t complete_fn,void *context) *//* is using the default endpoint 0 */usb_fill_control_urb ( kbd->led, Dev, usb_Sndctrlpipe (Dev, 0), (void *) KBD-&GT;CR, kbd->leds, 1, usb_kbd_led, kbd); KBD-&GT;LED-&GT;SETUP_DMA = kbd->cr_dma; KBD-&GT;LED-&GT;TRANSFER_DMA = Kbd->leds_dma;kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); error = Input_register_device (Kbd->dev); Usb_set_intfdata (Iface, KBD); return 0;}
compared with the mouse driver, there is a control transfer process, and this control transmission of the brequesttype that the transmission is not a standard request, but class, our keyboard is the HID type, so also look at the USB HID protocol, about how this request is defined, in order to know what wvalue, Windex, etc. (refer to: http://blog.csdn.net/leo_wonty/article/details/6721214), this is the knd-> A byte of data within the LEDs is sent to the slave device. In the mouse driver, the interrupt Urb is submitted in the Open function, and here is no exception.

static int Usb_kbd_open (struct Input_dev *dev) {struct USB_KBD *kbd = input_get_drvdata (dev); Kbd->irq->dev = kbd-& Gt;usbdev;if (Usb_submit_urb (KBD->IRQ, Gfp_kernel)) Return-eio;return 0;}
The completion function is called after the interrupt transfer is complete, USB_KBD_IRQ
static void Usb_kbd_irq (struct urb *urb) {struct USB_KBD *kbd = Urb->context;int I;switch (urb->status) {case 0:/* su ccess */break;case-econnreset:/* unlink */case-enoent:case-eshutdown:return;/*-epipe:should clear the halt */default :/* error */goto resubmit;} Report usb_kbd_keycode[224..231]8 Key State//key_leftctrl,key_leftshift,key_leftalt,key_leftmeta,//key_rightctrl,key_ Rightshift,key_rightalt,key_rightmetafor (i = 0; i < 8; i++) Input_report_key (Kbd->dev, Usb_kbd_keycode[i + 224], (k Bd->new[0] >> i) & 1);//If you press the 1 keys at the same time in the [2] byte, if there are two keys at the same time the second is in the [3] byte, the analogy can have a maximum of 6 keys simultaneously press for (i = 2; i < 8; i++) {/ Take the keyboard off the interrupt//without the key's pressed state if (Kbd->old[i] > 3 && memscan (kbd->new + 2, Kbd->old[i], 6) = = Kbd->new + 8 ) {if (Usb_kbd_keycode[kbd->old[i]]) Input_report_key (Kbd->dev, Usb_kbd_keycode[kbd->old[i]], 0); elsehid_ Info (Urb->dev, "Unknown key (scancode% #x) released.\n", Kbd->old[i]);} Gets the keyboard pressed interrupt//without the left state of the key if (Kbd->new[i] > 3 && memScan (Kbd->old + 2, Kbd->new[i], 6) = = Kbd->old + 8) {if (Usb_kbd_keycode[kbd->new[i]]) Input_report_key (kbd-& Gt;dev, Usb_kbd_keycode[kbd->new[i]], 1); Elsehid_info (Urb->dev, "Unknown key (scancode% #x) released.\n", kbd- >new[i]);}} Input_sync (Kbd->dev);//Synchronize the device, informing the event that the receiver driver has issued a complete report memcpy (Kbd->old, kbd->new, 8);// Avoid being treated as a new key when not released resubmit:i = Usb_submit_urb (URB, gfp_atomic); Hid_err (Urb->dev, "can" T resubmit Intr,%s-%s/ Input0, status%d ", Kbd->usbdev->bus->bus_name,kbd->usbdev->devpath, i);}
here, are reported the key class event, we in the front of the probe function, set the input Device Support button class event, there is an LED class event, but search the code also did not find, led event is where reported. Also, a dev->event function is defined in the probe function, and when browsing the data it is found that some people say that at the time of Input_event, invoking the event function of the incident handler will call Dev->event, which I think is incorrect. Read the Input_event code of the classmate should not be difficult to find, only to report the LED class and other events will trigger the dev->event, we here simply reported the key class event does not trigger dev->event. So is the Dev->event function defined in the PROBE function a device? Indeed, I have not found any use for it for the time being. There is no USB keyboard at hand, this behind the experiment confirms.

static int Usb_kbd_event (struct Input_dev *dev, unsigned int type, unsigned int code, int value) {struct USB_KBD *kbd = INPUT_GET_DRVD ATA (dev); if (type! = ev_led) Return-1;kbd->newleds = (!! Test_bit (Led_kana, dev->led) << 3) | (!!       Test_bit (Led_compose, dev->led) << 3) | (!! Test_bit (led_scrolll, dev->led) << 2) | (!!       Test_bit (LED_CAPSL, dev->led) << 1) | (!! Test_bit (LED_NUML, dev->led)); if (kbd->led->status = =-einprogress) return 0;if (* (kbd->leds) = = Kbd->ne Wleds) return 0;* (kbd->leds) = Kbd->newleds;kbd->led->dev = Kbd->usbdev;if (Usb_submit_urb (kbd->led , gfp_atomic)) Err_hid ("Usb_submit_urb (LEDs) failed"); return 0;} 
the dev->led here record the status of the LEDs, for example, when we report an LED event, the corresponding event is recorded in the dev->led in Input_event. This detects whether the LED event occurs and then transmits 1 bytes of data to the USB keyboard via the control transfer, and the lamp of the USB keyboard changes accordingly. However, in the final analysis, the code did not report the LED class event, everything is white pull.
static void usb_kbd_led (struct urb *urb) {struct USB_KBD *kbd = urb->context;if (urb->status) Dev_warn (&urb- >dev->dev, "led Urb status%d received\n", urb->status); if (* (kbd->leds) = = kbd->newleds) return;* (kbd- >leds) = Kbd->newleds;kbd->led->dev = Kbd->usbdev;if (Usb_submit_urb (kbd->led, GFP_ATOMIC)) Err_hid ("Usb_submit_urb (LEDs) failed");}
is the control transfer completion function here a nuisance? Each time a LED event is reported, then the control transmission URB is automatically submitted. So, * (kbd->leds) = = Kbd->newleds must be equal, unless a new event is reported, but the new event is reported, in the Usb_kbd_event function URB not automatically submitted it? Will there be unequal conditions?


This article has a lot of questions, if the great god see, please also answer.








USB Driver--keyboard driver (control transfer)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.