How to Write a USB keyboard driver in Linux 1. specify the header file required by the USB keyboard driver: # include <Linux/kernel. h>/* kernel header file, which contains prototype definitions of some common kernel functions */# include <Linux/slab. h>/* defines some memory allocation functions */# include <Linux/module. h>/* required header file for module compilation */# include <Linux/input. h>/* header file for input device-related functions */# include <Linux/init. h>/* Linux Initialization module function definition */# include <Linux/USB. h>/* function definition for USB devices */2. define keyboard code table array:/* use the first Keyboard Scan code table: A-1E; B-30; C-2E... */Static unsigned char usb_kbd_keycode [256] = {0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, 27, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,150,158,159,128,136,177,178,176,142,152,173,140}; 3. compile the device ID table: static struct usb_device_id usb_kbd_id_table [] ={{ usb_interface_info (3, 1, 1)},/*, 1 represents the interface class, interface subclass, and interface protocol respectively; 3, 1 is the keyboard interface class; the mouse is 3, 1, 2 */{}/* terminating entry */}; module_device_table (USB, usb_kbd_id_table);/* specify the device ID table */ 4. define the USB keyboard structure: struct usb_kbd {struct input_dev * dev;/* define an input device */struct usb_device * usbdev; /* define a USB device */unsigned char old [8]; /* data buffer used when the key leaves */struct urb * IRQ/* interrupt request block of USB keyboard */, * led/* request block of USB keyboard indicator */; unsigned char newleds;/* specify the target light status */Char name [128];/* store the vendor name and product name */Char phys [64]; /* node of the device */unsigned char * New;/* data buffer used when the key is pressed */struct usb_ctrlrequest * Cr;/* control request structure */unsigned char * LEDs; /* current indicator status */ Dma_addr_t cr_dma;/* control the request DMA buffer address */dma_addr_t new_dma;/* use the DMA buffer when urb is interrupted */dma_addr_t leds_dma;/* indicator dam buffer address */}; 5. write a USB keyboard driver structure (any driver in Linux has a similar driver structure):/* USB keyboard driver structure */static struct usb_driver usb_kbd_driver = {. name = "usbkbd",/* driver name */. probe = usb_kbd_probe,/* driver probe function, used for loading */. disconnect = usb_kbd_disconnect,/* driver disconnect function, used during uninstallation */. id_table = usb_kbd_id_table,/* driver device ID table, used to specify the device or interface */}; 6. compile the module load function (Each driver will have a loading function called by module_init):/* the start point of the driver life cycle, register the keyboard driver with USB core. */Static int _ init usb_kbd_init (void) {int result = usb_register (& usb_kbd_driver);/* register the USB keyboard driver */If (result = 0) /* Registration failed */info (driver_version ":" driver_desc); return result;} 7. compile the module uninstallation function (each driver has an uninstallation function called by module_exit):/* the end point of the driver's lifecycle, and deregister the keyboard driver from USB core. */Static void _ exit usb_kbd_exit (void) {printk ("SUNWILL-USBKBD: usb_kbd_exit begin... \ n "); usb_deregister (& usb_kbd_driver);/* disconnect the USB keyboard driver */} 8. specify the module initialization function (called when the specified function is driven by insmod): module_init (usb_kbd_init); 9. specify the module exit function (called when the specified function is driven by rmmod): module_exit (usb_kbd_exit); 10. compile the interrupt request processing function:/* the interrupt request processing function, which is called when an interrupt request arrives */static void usb_kbd_irq (struct urb * urb, struct pt_regs * regs) {struct usb_kbd * KBD = urb-> Context; int I; Switch (urb-> Status) {Case 0:/* success */break; Case-econnreset:/* unlink */case-enoent: case-eshudown: return;/*-epipe: shocould clear the halt */Default:/* Error */goto resubmit;} // input_regs (KBD-> Dev, regs ); /* if you do not know what it means, you can still comment out this part. */for (I = 0; I <8; I ++)/* The values for 8 times are: 29-42-56-125-97-54-100-126 */{input_report_key (KBD-> Dev, usb_kbd_keycode [I + 224], (KBD-> New [0]> I) & 1);}/* if only one key is pressed at the same time, the value is in byte [2]. If two keys are simultaneously pressed, the second value is in byte [3, up to 6 buttons can be pressed simultaneously */for (I = 2; I <8; I ++) {/* Get the keyboard exit interrupt */If (KBD-> old [I]> 3 & memscan (KBD-> New + 2, KBD-> old [I], 6) = KBD-> New + 8) {/* The Press status of the key does not exist */If (usb_kbd_keycode [KBD-> old [I]) {input_report_key (KBD-> Dev, usb_kbd_keycode [KBD-> old [I], 0);} else Info ("unknown key (scancode % # X) released. ", KBD-> old [I]);}/* Get the keyboard press interruption */If (KBD-> New [I ]> 3 & memscan (KBD-> old + 2, KBD-> New [I], 6) = KBD-> old + 8) {/* The key does not exit */If (usb_kbd_keycode [KBD-> New [I]) {input_report_key (KBD-> Dev, usb_kbd_keycode [KBD-> New [I], 1);} else Info ("unknown key (scancode % # X) pressed. ", KBD-> New [I]) ;}/ * the synchronization device informs the receiver of the event that the driver has issued a complete report */input_sync (KBD-> Dev ); memcpy (KBD-> old, KBD-> New, 8);/* prevents being treated as a new button when not released */resubmit: I = usb_submit_urb (urb, gfp_atomic ); /* Send a USB request block */if (I) Err ("can't resubmit intr, % s-% S/input0, status % d ", KBD-> usbdev-> bus-> bus_name, KBD-> usbdev-> devpath, I);} 11. compile the event processing function:/* event processing function */static int usb_kbd_event (struct input_dev * Dev, unsigned int type, unsigned int code, int value) {struct usb_kbd * KBD = Dev-> private; If (type! = Ev_led)/* The led event is not supported */Return-1;/* get the target status of the indicator */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 the indicator is in the target status, no operation is required */If (* (KBD-> LEDs) = KBD-> newleds) return 0; * (KBD-> LEDs) = KBD-> newleds; KBD-> led-> Dev = KBD-> usbdev; /* Send a USB request block */If (usb_submit_urb (KBD-> led, gfp_atomic) Err ("usb_submit_urb (LEDs) failed"); Return 0;} 12. compile the LED event processing function:/* after the event, which is actually available in usb_kbd_event. The function may be used to prevent event operation failure, comment out all All rows can work normally */static void usb_kbd_led (struct urb * urb, struct pt_regs * regs) {struct usb_kbd * KBD = urb-> context; If (urb-> Status) warn ("led urb status % d received", urb-> status); If (* (KBD-> LEDs) = KBD-> newleds) /* if the indicator is in the target status, no operation is required */return; * (KBD-> LEDs) = KBD-> newleds; KBD-> led-> Dev = KBD-> usbdev; If (usb_submit_urb (KBD-> led, gfp_atomic) Err ("usb_submit_urb (LEDs) failed");} 13. write a USB device opening letter Count:/* When the keyboard device is turned on, start to submit the urb built in the probe function to enter the urb cycle. */Static int usb_kbd_open (struct input_dev * Dev) {struct usb_kbd * KBD = Dev-> private; KBD-> IRQ-> Dev = KBD-> usbdev; if (usb_submit_urb (KBD-> IRQ, gfp_kernel) Return-EIO; return 0 ;}14. the urb lifecycle ends when the USB device is disabled/* the keyboard is disabled. */Static void usb_kbd_close (struct input_dev * Dev) {struct usb_kbd * KBD = Dev-> private; usb_kill_urb (KBD-> IRQ ); /* cancel the KBD-> irq usb request block */} 15. create urb/* allocate urb memory space to create urb */static int usb_kbd_alloc_mem (struct usb_device * Dev, struct usb_kbd * KBD) {If (! (KBD-> IRQ = usb_alloc_urb (0, gfp_kernel) Return-1; if (! (KBD-> led = usb_alloc_urb (0, gfp_kernel) Return-1; if (! (KBD-> New = usb_buffer_alloc (Dev, 8, gfp_atomic, & KBD-> new_dma) Return-1; if (! (KBD-> Cr = usb_buffer_alloc (Dev, sizeof (struct usb_ctrlrequest), gfp_atomic, & KBD-> cr_dma) Return-1; if (! (KBD-> LEDs = usb_buffer_alloc (Dev, 1, gfp_atomic, & KBD-> leds_dma) Return-1; return 0;} 16. destroy urb/* release urb memory space: Destroy urb */static void usb_kbd_free_mem (struct usb_device * Dev, struct usb_kbd * KBD) {If (KBD-> IRQ) usb_free_urb (KBD-> IRQ); If (KBD-> led) usb_free_urb (KBD-> led); If (KBD-> New) usb_buffer_free (Dev, 8, KBD-> New, KBD-> new_dma); If (KBD-> Cr) usb_buffer_free (Dev, sizeof (struct usb_ctrlrequest), KBD-> Cr, KBD-> cr_dma); If (KBD-> LEDs) usb_buffer_free (Dev, 1, KBD-> LEDs, KBD-> leds_dma);} 17. USB keyboard driver probe function:/* USB keyboard driver probe function, initialize the device and specify the address of some processing functions */static int usb_kbd_probe (struct usb_interface * iface, const struct usb_device_id * ID) {struct usb_device * Dev = interface_to_usbdev (iface); struct usb_host_interface * interface; struct usb_endpoint_descriptor * endpoint; struct usb_kbd * KBD; struct input _ Dev * input_dev; int I, pipe, maxp;/* currently selected interface */interface = iface-> cur_altsetting; /* the keyboard has only one interrupt in endpoint */If (interface-> DESC. bnumendpoints! = 1) Return-enodev;/* Get the endpoint descriptor */Endpoint = & Interface-> endpoint [0]. DESC; If (! (Endpoint-> bendpointaddress & usb_dir_in) Return-enodev; If (endpoint-> bmattributes & usb_endpoint_xfertype_mask )! = Usb_endpoint_xfer_int) Return-enodev;/* set the endpoint to the interrupt in endpoint */pipe = usb_rcvintpipe (Dev, endpoint-> bendpointaddress ); /* obtain the maximum value of the package */maxp = usb_maxpacket (Dev, pipe, usb_pipeout (PIPE); KBD = kzarloc (sizeof (struct usb_kbd), gfp_kernel ); input_dev = input_allocate_device (); If (! KBD |! Input_dev) goto fail1; If (usb_kbd_alloc_mem (Dev, KBD) goto fail2;/* fill in the USB device structure and input device structure */KBD-> USB Dev = dev; KBD-> Dev = input_dev;/* write it into KBD-> name */If (Dev-> manufacturer) in the format of "vendor name product name) 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);}/* No vendor name Detected Word */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);/* device link address */usb_make_path (Dev, KBD-> phys, sizeof (KBD-> phys); strlcpy (KBD-> phys, "/input0", sizeof (KBD-> phys); input_dev-> name = KBD-> name; input_dev-> phys = KBD-> phys; /** the input_id struct in input_dev is used to store the vendor, device type, and device number. This function is used to set the device descriptor * Assigned to the embedded input subsystem struct */usb_to_input_id (Dev, & input_dev-> ID);/* cdev is the device category (Class Device) */input_dev-> cdev. dev = & iface-> dev;/* The private data item of input_dev is used to indicate the type of the current input device. Here, the keyboard struct object is assigned to it */input_dev-> private = KBD; input_dev-> evbit [0] = bit (ev_key)/* key event */| bit (ev_led)/* led event */| bit (ev_rep) /* auto override value */; input_dev-> ledbit [0] = bit (led_numl)/* Number lamp */| bit (led_capsl) /* case-sensitive light */| bit (led_scrolll)/* scroll light */| BI T (led_compose) | bit (led_kana); for (I = 0; I <255; I ++) set_bit (usb_kbd_keycode [I], input_dev-> keybit ); clear_bit (0, input_dev-> keybit); input_dev-> event = usb_kbd_event;/* register the event processing function entry */input_dev-> open = usb_kbd_open; /* register the device and open the function entry */input_dev-> close = usb_kbd_close; /* register the device to close the function entry * // * initialize the interrupt urb */usb_fill_int_urb (KBD-> IRQ/* initialize the urb of KBD-> IRQ */, dev/* This urb will be sent to the dev device */, pipe/* This urb will be sent to the pipe endpoint */, KBD-> Ne W/* pointer to buffer */, (maxp> 8? 8: maxp)/* buffer length */, usb_kbd_irq/* The processing function called when urb is complete */, KBD/* pointer to the data block, after being added to this urb structure, the processing function can be obtained */, endpoint-> binterval/* interval at which urb should be scheduled */); KBD-> IRQ-> transfer_dma = KBD-> new_dma;/* specify the DMA buffer to be transmitted by the urb */KBD-> IRQ-> transfer_flags | = urb_no_transfer_dma_map; /* This urb has a DMA buffer to transmit */KBD-> Cr-> brequesttype = usb_type_class | usb_recip_interface; /* operation is the class interface object */KBD-> Cr-> brequest = 0x09;/* interrupt request number */KBD-> Cr-> wvalue = cpu_to_le 16 (0x200); KBD-> Cr-> Windex = cpu_to_le16 (interface-> DESC. binterfacenumber);/* interface number */KBD-> Cr-> wlength = cpu_to_le16 (1 ); /* How many bytes are transmitted during data transmission * // * initialize the control URL */usb_fill_control_urb (KBD-> led, Dev, usb_sndctrlpipe (Dev, 0), (void *) KBD-> Cr, KBD-> LEDs, 1, usb_kbd_led, KBD); KBD-> led-> setup_dma = KBD-> cr_dma; KBD-> led-> transfer_dma = KBD-> leds_dma; KBD-> led-> transfer_flags | = (urb_no_transfer_dma_map | urb_no _ Setup_dma_map/* If DMA transmission is used, the setup_dma pointer in urb points to the DMA buffer rather than the buffer pointed by setup_packet */); /* register the input device */input_register_device (KBD-> Dev); usb_set_intfdata (iface, KBD);/* set private data for the interface */return 0; fail2: usb_kbd_free_mem (Dev, KBD); fail1: input_free_device (input_dev); kfree (KBD); Return-enomem;} 18. write the function for disconnecting:/* the function for disconnecting (such as pulling out a keyboard device) */static void usb_kbd_disconnect (struct usb_interface * INTF) {struct usb_kbd * KBD = Usb_get_intfdata (INTF);/* Get the private data of the interface to KBD */usb_set_intfdata (INTF, null);/* set the private data of the interface to null */If (KBD) {usb_kill_urb (KBD-> IRQ);/* cancel the interrupt request */cancel (KBD-> Dev);/* cancel the device */usb_kbd_free_mem (interface_to_usbdev (INTF), KBD ); /* release memory space */kfree (KBD) ;}} 19. compile makefile: ############################# usbkdb makefile for Linux ##### ######################## obj-M: = usbkbd. O kerneldir? =/Lib/modules/$ (shell uname-R)/build PWD :=$ (shell PWD) Default: $ (make)-C $ (kerneldir) M = $ (PWD)-I/home/usbkbd/modules 20.