How to compile a USB keyboard driver in Linux

Source: Internet
Author: User
Tags 04x
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.

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.