Linux usbtouchscreen Driver Analysis

Source: Internet
Author: User

 

In the Linux kernel with USB touch screen driver, linux-2.6.33.3 \ drivers \ input \ touchscreen. C as an example, the analysis:

1. Driver loading:

Static int _ init usbtouch_init (void)
{
Return usb_register (& usbtouch_driver); // driver registration
}

The usbtouch_driver is defined:

Static struct usb_driver usbtouch_driver = {
. Name = "usbtouchscreen", // driver name
. Probe = usbtouch_probe, // probe function
. Disconnect = usbtouch_disconnect, // The function called during disconnect.
. Id_table = usbtouch_devices, // list of devices supported by USB touch
};

Static struct usb_device_id usbtouch_devices [] = {
# Ifdef config_touchscreen_usb_egalax
/* Ignore the hid capable devices, handled by usbhid */
{Usb_device_hid_class (0x0eef, 0x0001),. driver_info = devtype_ignore },
{Usb_device_hid_class (0x0eef, 0x0002),. driver_info = devtype_ignore },

/* Normal device IDs */
{Usb_device (0x3823, 0x0001),. driver_info = devtype_egalax },
{Usb_device (0x3823, 0x0002),. driver_info = devtype_egalax },
{Usb_device (0x0123, 0x0001),. driver_info = devtype_egalax },

....

0x0123 and 0x0001 are vid and PID respectively. driver_info contains the driver information and its type is usbtouch_device_info.

For example, devtype_egalax] is defined:

Static struct usbtouch_device_info usbtouch_dev_info [] = {
# Ifdef config_touchscreen_usb_egalax
[Devtype_egalax] = {
. Min_xc = 0x0, // minimum coordinate of the X axis
. Max_xc = 0x07ff, // maximum coordinate of the X axis
. Min_yc = 0x0, // y axis minimum Coordinate
. Max_yc = 0x07ff, // The maximum coordinate of the Y axis
. Rept_size = 16 ,//
. Process_pkt = usbtouch_process_multi, // used to interrupt the callback function and upload data.
. Get_pkt_len = egalax_get_pkt_len,
. Read_data = egalax_read_data, // used to interrupt the callback function and read data
},
# Endif

Therefore, the device information is injected during registration. If the registration is successful (usb_device_id contains the corresponding hardware), The usbtouch_probe method is called.

2. probe method:

Static int usbtouch_probe (struct usb_interface * INTF,
Const struct usb_device_id * ID)
{
Struct usbtouch_usb * USB touch; // a USB touch device
Struct input_dev * input_dev; // a input device
Struct usb_host_interface * interface;
/* A USB device has a configuration concept, indicating that a device can have multiple configurations,
However, only one device can be activated at a time. For example, some devices can download the firmware or set different global modes,
Cur_altsetting indicates the current setting, or setting. You can view the original code
Description of the usb_interface structure definition. The description shows that an interface can have multiple setting methods */
Struct usb_endpoint_descriptor * endpoint;
Struct usb_device * udev = interface_to_usbdev (INTF); // obtain the device corresponding to the interface

/* Struct usb_device
There is a member struct usb_device_descriptor, while struct usb_device_descriptor
Member _ bcddevice in, indicating the version number of the product specified by the manufacturer, the manufacturer ID
And product ID
To mark a device. bcddevice
Total 16
BCD code is used to save the information, that is, every 4
Decimal number, such as 0011, 0110, 1001, and 0111.
3697 .*/

Struct usbtouch_device_info * type;
Int err =-enomem;

/* Some devices are ignored */
If (ID-> driver_info = devtype_ignore)
Return-enodev;

Interface = INTF-> cur_altsetting;
Endpoint = & Interface-> endpoint [0]. DESC;
// The endpoint 0 descriptor, where 0 represents the control endpoint

Usbtouch = kzarloc (sizeof (struct usbtouch_usb), gfp_kernel); // allocate memory for the device
Input_dev = input_allocate_device (); // apply for the input_dev Structure
If (! Usbtouch |! Input_dev)
Goto out_free;

Type = & usbtouch_dev_info [ID-> driver_info]; // extract the info corresponding to the device
Usbtouch-> type = type;
If (! Type-> process_pkt)
Type-> process_pkt = usbtouch_process_pkt; // used to interrupt the callback function and upload data to the application layer.

Usbtouch-> DATA = usb_buffer_alloc (udev, type-> rept_size,
Gfp_kernel, & usbtouch-> data_dma );

/* Usbtouch-> data: records the memory pointer used for normal transmission */

/* Usb_buffer_alloc (). This function is provided by usbcore. You just need to call it. You can know from the name that it is used to apply for memory. The first parameter is struct.
The pointer of the usb_device struct, so we need to pass a udev, the third parameter, gfp_kernel, is a flag applied for memory. Generally, this flag is used for Memory Applications. Unless it is an interrupt context, it cannot be sleep, you have to use gpf_atomic. There are not many requirements here. the buffer size applied for by the second parameter, and the fourth parameter. This data type is specially prepared for DMA transmission in the Linux kernel. to support DMA transmission, usb_buffer_alloc not only applies for addresses, but also establishes DMA ing. the memory space requested by usb_buffer_alloc needs to be released with its partner usb_buffer_free. */
If (! USB touch-> data)
Goto out_free;

If (Type-> get_pkt_len ){
Usbtouch-> buffer = kmalloc (Type-> rept_size, gfp_kernel );

/* Usbtouch-> Buffer: records the memory pointer used to store read data */

If (! Usbtouch-> buffer)
Goto out_free_buffers;
}

Usbtouch-> IRQ = usb_alloc_urb (0, gfp_kernel );
If (! Usbtouch-> IRQ ){
Dbg ("% s-usb_alloc_urb failed: usbtouch-> IRQ", _ FUNC __);
Goto out_free_buffers;
}

Usbtouch-> udev = udev;
Usbtouch-> input = input_dev;

If (udev-> manufacturer)
Strlcpy (usbtouch-> name, udev-> manufacturer, sizeof (usbtouch-> name ));

If (udev-> product ){
If (udev-> manufacturer)
Strlcat (usbtouch-> name, "", sizeof (usbtouch-> name ));
Strlcat (usbtouch-> name, udev-> product, sizeof (usbtouch-> name ));
}

If (! Strlen (usbtouch-> name ))
Snprintf (usbtouch-> name, sizeof (usbtouch-> name ),
"USB touchscreen % 04x: % 04x ",
Le16_to_cpu (udev-> descriptor. idvendor ),
Le16_to_cpu (udev-> descriptor. idproduct ));

Usb_make_path (udev, usbtouch-> phys, sizeof (usbtouch-> phys ));

/* Fill in the node name in the device struct. Used to obtain the path of the USB device in sysfs. Format: USB-USB Bus No.-path name. */
Strlcat (usbtouch-> phys, "/input0", sizeof (usbtouch-> phys ));

/* Assign the device name to the input subsystem structure embedded in the device */

Input_dev-> name = usbtouch-> name;

/* Assign the device node name to the input subsystem structure embedded in the device */
Input_dev-> phys = usbtouch-> 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.
* The number in is assigned to the embedded input subsystem struct.
*/
Usb_to_input_id (udev, & input_dev-> ID );

Input_dev-> Dev. Parent = & INTF-> dev;

Input_set_drvdata (input_dev, usbtouch );

/* Fill in the input device to open the function pointer */

Input_dev-> open = usbtouch_open;

/* Fill in the input device to close the function pointer */
Input_dev-> close = usbtouch_close;

/* Evbit is used to describe events. ev_key is a key event, ev_abs is an absolute coordinate event, and ev_rel is a relative coordinate event */
Input_dev-> evbit [0] = bit_mask (ev_key) | bit_mask (ev_abs );

/* Keybit indicates the key value */
Input_dev-> keybit [bit_word (btn_touch)] = bit_mask (btn_touch );
Input_set_abs_params (input_dev, abs_x, type-> min_xc, type-> max_xc, 0, 0 );
Input_set_abs_params (input_dev, abs_y, type-> min_yc, type-> max_yc, 0, 0 );
If (Type-> max_press)
Input_set_abs_params (input_dev, abs_pressure, type-> min_press,
Type-> max_press, 0, 0 );

/*
* Fill in the constructed urb, fill the data of the input_dev struct that has just been filled in the urb struct, and submit the urb in open.
* When urb contains a DMA buffer to be transmitted, set urb_no_transfer_dma_map. USB core usage
* The buffer to which the transfer_dma variable points, instead of the buffer to which the transfer_buffer variable points.
* Urb_no_setup_dma_map is used for the setup package, and urb_no_transfer_dma_map is used for all data packages.
*/

Usb_fill_int_urb (usbtouch-> IRQ, usbtouch-> udev,
Usb_rcvintpipe (usbtouch-> udev, endpoint-> bendpointaddress ),
Usbtouch-> data, type-> rept_size,
Usbtouch_irq, usbtouch, endpoint-> binterval );

Usbtouch-> IRQ-> Dev = usbtouch-> udev;
Usbtouch-> IRQ-> transfer_dma = usbtouch-> data_dma;
Usbtouch-> IRQ-> transfer_flags | = urb_no_transfer_dma_map;

/* Device specific init */
If (Type-> init ){
Err = type-> Init (usbtouch );
If (ERR ){
Dbg ("% S-type-> Init () failed, err: % d", _ FUNC __, ERR );
Goto out_free_buffers;
}
}

Err = input_register_device (usbtouch-> input );
If (ERR ){
Dbg ("% s-input_register_device failed, err: % d", _ FUNC __, ERR );
Goto out_free_buffers;
}

/*
* Generally, the probe function stores device-related information in a usb_interface struct for later
* Obtain and use usb_get_intfdata. The device struct information is stored in the device struct embedded in the INTF interface struct.
* In driver_data, INTF-> Dev-> dirver_data = ....
*/
Usb_set_intfdata (INTF, usbtouch );

If (usbtouch-> type-> irq_always)
Usb_submit_urb (usbtouch-> IRQ, gfp_kernel );

Return 0;

Out_free_buffers:
Usbtouch_free_buffers (udev, usbtouch );
Out_free:
Input_free_device (input_dev );
Kfree (USB touch );
Return err;
}

3. callback function:

/*
* Urb callback function. After urb is submitted, the urb callback function is called.
* This function is used as the form parameter of the usb_fill_int_urb function and is the callback function developed for the constructed urb.
*/
Static void usbtouch_irq (struct urb * urb)
{
Struct usbtouch_usb * usbtouch = urb-> context;
Int retval;

Switch (urb-> Status ){
Case 0:
/* Success */
Break;
Case-etime:
/* This urb is timing out */
Dbg ("% s-urb timed out-was the device unplugged? ",
_ FUNC __);
Return;
Case-econnreset:
Case-enoent:
Case-eshudown:
/* This urb is terminated, clean up */
Dbg ("% s-urb shutting down with status: % d ",
_ FUNC __, urb-> status );
Return;
Default:
Dbg ("% s-nonzero urb status terminated ed: % d ",
_ FUNC __, urb-> status );
Goto exit;
}

Usbtouch-> type-> process_pkt (usbtouch, usbtouch-> data, urb-> actual_length );

Exit:
Retval = usb_submit_urb (urb, gfp_atomic );
If (retval)
Err ("% s-usb_submit_urb failed with result: % d ",
_ FUNC __, retval );
}

4. input_sync

Used for event synchronization. It notifies the receiver driver of the event that a complete report has been issued.

This article is original. If reproduced, please indicate the source: Http://hi.baidu.com/chris_zheng

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.