Linux hardware driver: USB driver development

Source: Internet
Author: User
Linux hardware driver: USB driver development-Linux general technology-Linux programming and kernel information. For more information, see the following section. Author: Zhao Ming Source: Lenovo Software

USB skeleton Program (usb-skeleton) is the basis of USB driver. By learning and understanding its source code, we can quickly understand the USB driver architecture, quickly develop our own USB hardware driver.

Preface

In the previous article "hardware drivers in Linux-USB devices (I) (driver preparation)", we learned how to use some of the most common USB devices in Linux. However, this is far from enough for system design programmers. We also need to have the ability to read, modify, and develop drivers. In the next article, we will use a simple USB driver example to bring you into the world of USB driver development.

USB driver development

After mastering the configuration of the USB device, programmers can try to modify and develop some simple USB drivers. In this section, we will explain two small USB driver examples based on a basic USB frame.

USB skeleton

Driver/usb/usb-skeleton.c in the Linux kernel source code Directory provides us with a basic usb driver. We call it a USB skeleton. With this, we only need to modify a few parts to complete the driver of a USB device. Our USB driver development started from her.
Almost all USB devices not supported in linux are products specific to the manufacturer. If the manufacturer uses their own Protocols in their products, they need to create a specific driver for the device. Of course, we know that some manufacturers disclose their USB protocol and help develop Linux drivers, but some manufacturers do not disclose their USB protocol at all. Because each protocol generates a new driver, a general USB driver skeleton is available, which uses the pci skeleton as the template.

If you want to write a linux driver, first familiarize yourself with the USB protocol specifications. The USB homepage is helpful. Some typical drivers can be found above, and the concept of USB urbs is also introduced, which is the most basic of USB drivers.

The first thing the Linux USB driver needs to do is to register it in the Linux USB subsystem and provide relevant information, such as the device that the driver supports, what actions are taken when a supported device is inserted or pulled out from the system. All this information is transmitted to the USB subsystem, as shown in the following figure in the usb skeleton DRIVER:


Static struct usb_driver skel_driver = {
Name: "skeleton ",
Probe: skel_probe,
Disconnect: skel_disconnect,
Fops: & skel_fops,
Minor: USB_SKEL_MINOR_BASE,
Id_table: skel_table,
};

The variable name is a string that describes the driver. Probe and disconnect are function pointers. When the device matches the variable information in id_table, this function is called.

The fops and minor variables are optional. Most USB Drivers hook another driver system, such as SCSI, network, or tty subsystem. These drivers are registered in other driver systems, and interaction operations in any user space are provided through those interfaces. For example, we use the SCSI device driver as another driver system hooked by our USB driver, then, the read and write operations of the USB device are accessed according to the read and write Functions of the SCSI device. However, no matching driver system can be used for drivers such as scanners. Therefore, we need to process the interaction functions such as read and write with the user space on our own. The Usb sub-system provides a method to register a sub-device number and file_operations function pointer to facilitate interaction with the user space.

The key points of the USB skeleton program are as follows:
1. registration and cancellation of USB Drivers
The USB driver sends a command to usb_register during registration, usually in the initialization function of the driver.
To uninstall the driver from the system, you need to cancel the usb subsystem. This requires the usb_unregister function:


Static void _ exit usb_skel_exit (void)
{
/* Deregister this driver with the USB subsystem */
Usb_deregister (& skel_driver );
}
Module_exit (usb_skel_exit );



When a usb device is inserted, you need to create a MODULE_DEVICE_TABLE to enable the linux-hotplug system to automatically load the driver. The Code is as follows (this module only supports a specific device ):

/* Table of devices that work with this driver */
Static struct usb_device_id skel_table [] = {
{USB_DEVICE (USB_SKEL_VENDOR_ID,
USB_SKEL_PRODUCT_ID )},
{}/* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, skel_table );



The USB _ DEVICE macro uses the vendor ID and product ID to provide a unique identifier for the device. When the system inserts a USB device with an ID matching to the USB bus, the driver is registered in the USB core. The probe function in the driver will be called. The usb_device structure pointer, interface number, and interface ID are all passed to the function.


Static void * skel_probe (struct usb_device * dev,
Unsigned int ifnum, const struct usb_device_id * id)

The driver needs to confirm whether the inserted device is acceptable. If not, or if any error occurs during initialization, the probe function returns a NULL value. Otherwise, a pointer containing the driver status is returned. With this pointer, you can access the callback functions in all structures.
In the skeleton driver, the last point is to register devfs. We create a buffer to save the data sent to the usb device and the data received from the device, USB urb is initialized, And we register the device in the devfs subsystem, allow devfs users to access our devices. The registration process is as follows:



/* Initialize the devfs node for this device and register it */sprintf (name, "skel % d", skel->; minor); skel->; devfs = devfs_register (Region, name, region, USB_MAJOR, Region + skel->; minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, & skel_fops, NULL );



If the devfs_register function fails, do not worry. The devfs subsystem reports this situation to the user.

At last, if the device is unplugged from the usb bus, the device pointer will call the disconnect function. The driver needs to clear all the private data allocated, disable urbs, and deregister itself from devfs.



/* Remove our devfs node */devfs_unregister (skel->; devfs );



Now, the skeleton driver has been bound to the device. Any user-State program to operate on this device can use the function defined in the file_operations structure. First, open the device. In the open function, the MODULE_INC_USE_COUNT macro is a key function. It serves as a count. When a user-State program opens a device, the counter is incremented by one. For example, we add a driver as a module. If the counter is not zero, it indicates that there are still user programs using this driver. At this time, You Cannot uninstall the driver through the rmmod command.


/* Increment our usage count for the module */MOD_INC_USE_COUNT; ++ skel->; open_count;/* save our object in the file's private structure */file->; private_data = skel;



After the device is opened, the read and write Functions can receive and send data.

2. skel's write, and read Functions

They respond to read/write operations.

In skel_write, A FILL_BULK_URB function completes the connection between the callbak of the urb system and our own skel_write_bulk_callback. Note that skel_write_bulk_callback is the method of interruption, so it should be noted that the time cannot be too long. In this program, it only reports the status of some urb.
The read function is slightly different from the write function in that the program does not use urb to transmit data from the device to the driver. Instead, we use the usb_bulk_msg function instead, this function can send data to or receive data from devices without creating urbs and operating urb functions. We call the usb_bulk_msg function and upload a bucket to buffer and place the data received by the driver. If the data is not received, the system fails and returns an error message.

3. usb_bulk_msg Function

The usb_bulk_msg function is very useful when a usb device is read or written. However, when you need to read/write the device continuously, we recommend that you create your own urbs and submit the urbs to the usb subsystem.

4. skel_disconnect Function

This function is called when the device file handle is released. The MOD_DEC_USE_COUNT Macro will be used (exactly the same as MOD_INC_USE_COUNT, which reduces a counter). First, check whether other programs are currently accessing this device. If the last user is using it, we can disable any ongoing write operations as follows:




/* Decrement our usage count for the device */-- skel->; open_count; if (skel->; open_count <= 0) {/* shutdown any bulk writes that might be going on */usb_unlink_urb (skel->; write_urb); skel->; open_count = 0 ;} /* decrement our usage count for the module */MOD_DEC_USE_COUNT;

The most difficult thing is that a usb device can be removed from the system at any point in time, even if the program is currently accessing it. The usb driver must be able to solve this problem well. It must be able to cut off any current read/write and notify the user space program that the usb device has been removed.
If the program has an opened device handle, in the current structure, we only need to assign it null, as if it has disappeared. For every function operation such as device read/write, we need to check whether the usb_device structure exists. If the device does not exist, the device disappears and A-ENODEV error is returned to the user program. When the release function is called, The skel_disconnect function is cleared no matter whether the usb_device structure exists or not when no file is opened.

The Usb skeleton Driver provides enough examples to help the starters develop a driver in the shortest time. For more information, go to the linux usb development newsgroup. USB flash drives, USB card readers, MP3, and digital camera drivers may not be supported in Linux for a USB flash drive, USB card reader, MP3, or digital camera that is used in windows. What should I do? In fact, you don't need to be sad. Maybe after a little bit of work, you can easily use it. Generally, this USB flash drive, USB card reader, MP3, or digital camera can be recognized as a mobile storage device in Windows XP without a dedicated driver, the rest depends on your luck.

USB storage devices. Their read and write operations are all hooked to the SCSI device through the hooks mentioned in the previous chapter. We do not need to perform specific data read/write processing.
Step 1: We use cat/proc/bus/usb/devices to obtain the device information on the USB bus detected by the current system. It includes Vendor, ProdID, and Product. The following is the information segment after the insertion of a miscellaneous card CF card reader I bought:



T: Bus = 01 lev= 01 Prnt = 01 Port = 01 Cnt = 02 Dev # = 5 Spd = 12 MxCh = 0 D: Ver = 1.10 Cls = 00 (>; ifc) sub = 00 Prot = 00 MxPS = 8 # Cfgs = 1 P: Vendor = 07c4 ProdID = a400 Rev = 1.13 S: Manufacturer = usb s: Product = Mass Storage C: * # Ifs = 1 Cfg # = 1 xcode = 80 MxPwr = 70mA I: If # = 0 Alt = 0 # EPs = 2 Cls = 08 (vend .) sub = 06 Prot = 50 Driver = usb-storage E: Ad = 81 (I) xcode = 02 (Bulk) MxPS = 64 Ivl = 0msE: Ad = 02 (O) xcode = 02 (Bulk) MxPS = 64 Ivl = 0 ms



Among them, we are most concerned about the Vendor = 07c4 ProdID = a400 and Manufacturer = USB (it is really a miscellaneous card, the Vendor name is not seen) Product = Mass Storage.

For these mobile storage devices, we know that Linux is simulated into scsi devices through the usb-storage.o driver to support, the reason is not supported, generally, the usb-storage driver does not include the vendor identification and product identification information (the USB was blocked when it was initially detected like skel_probe ). The hardware access part of the USB storage device is usually consistent. To support it, you only need to modify the vendor identification and product identification list section in usb-storage.

Second, open the drivers/usb/storage/register file. We can see that all the known product registration forms are based on UNUSUAL_DEV (idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, vendor_name, product_name, use_protocol, use_transport, init_function, Flags. You can determine the corresponding meaning based on the name. So as long as we fill in our own registration as follows, we can let the usb-storage driver to recognize and discover it.


UNUSUAL_DEV (07c4, a400, 0x0000, 0 xffff, "USB", "Mass Storage", US_ SC _SCSI, US_PR_BULK, NULL, empty | US_FL_START_STOP | US_FL_MODE_XLATE)




Note: The positions of the preceding statements must be correct. It is found that the usb-storage driver is based on idVendor for all registrations, and the idProduct values are listed in ascending order. We also need to place it in the appropriate position.

Finally, fill in the above information, we can re-compile the kernel or usb-storage.o module. At this time, our device can be accessed as a SCSI device like other USB flash drives.
Currently, many keyboard types are supported by the keyboard shuttle and tablet. Next we will try to add a driver to the keyboard shuttle. In general, when we insert a USB interface keyboard, multiple usb devices are displayed in/proc/bus/USB/devices. For example, the shuttle on your USB keyboard will be one, and your tablet will be one. If your USB keyboard has a USB expansion port, you will also see it.

The following information is displayed:



T: Bus = 02 lev= 00 Prnt = 00 Port = 00 Cnt = 00 Dev # = 1 Spd = 12 MxCh = 2B: Alloc = 11/900 us (1% ), # Int = 1, # Iso = 0D: Ver = 1.00 Cls = 09 (hub) Sub = 00 Prot = 00 MxPS = 8 # Cfgs = 1 P: vendor = 0000 ProdID = 0000 Rev = 0.00 S: Product = usb uhci Root HubS: SerialNumber = d800C: * # Ifs = 1 Cfg # = 1 Recognition = 40 MxPwr = 0mAI: if # = 0 Alt = 0 # EPs = 1 Cls = 09 (hub) Sub = 00 Prot = 00 Driver = hubE: Ad = 81 (I) ASD = 03 (Int .) mxPS = 8 Ivl = 255msT: Bus = 02 EV = 01 Prnt = 01 Port = 01 Cnt = 01 Dev # = 3 Spd = 12 MxCh = 3D: ver = 1.10 Cls = 09 (hub) Sub = 00 Prot = 00 MxPS = 8 # Cfgs = 1 P: Vendor = 07e4 ProdID = 9473 Rev = 0.02 S: Manufacturer = ALCORS: product = Movado USB KeyboardC: * # Ifs = 1 Cfg # = 1 xcode = e0 MxPwr = 100mAI: If # = 0 Alt = 0 # EPs = 1 Cls = 09 (hub) sub = 00 Prot = 00 Driver = hubE: Ad = 81 (I) xcode = 03 (Int .) mxPS = 1 Ivl = 255 ms



After finding the corresponding information, you can start working. In fact, the definition of the shuttle is usually the same as the keyboard key code, so we can make some changes by referring to the drivers/usb/usbkbd .. c code. Because I failed to obtain the corresponding hardware USB protocol, I had no idea what the communication protocol was about when the shuttle was pressed. I had to extract the information for analysis. Fortunately, it is relatively simple. In the usb_kbd_irq function of the following code, if (kbd->; new [0] = (char) 0x01) and if (kbd->; new [1] >;>; 4) & 0x0f )! = 0x7) is to judge the left side of the shuttle. The usb_kbd_irq function is the keyboard interrupt response function. The hook is in the usb_kbd_probe function.



FILL_INT_URB (& kbd->; irq, dev, pipe, kbd->; new, maxp>; 8? 8: maxp, usb_kbd_irq, kbd, endpoint->; bInterval );




In a sentence.

From the usb skeleton, we know that the usb_kbd_probe function runs on a USB device. Other parts are not critical. You can make some modifications based on the specific test value (Vendor = 07e4 ProdID = 9473. It is worth mentioning that when the keyboard is disconnected, we simulate the USB shuttle message as the left arrow key and right arrow key. Here, it depends on how you want to respond to it. Of course, you can also simulate extended key codes such as F14 and F15.
After learning about this basic driver, you should be able to develop the corresponding driver for a keyboard with a communication protocol.
For the program, see Appendix 1: keyboard shuttle driver.

When using this driver, you must first uninstall the hid device, load the usbhkey. o module, and then load the hid. o module. If hid exists, its probe will shield the system from discovering our devices using our drivers. Actually, fliggy is a hid device. The correct method is to modify the probe function of hid and then integrate our driver into it.
References
1. LINUX Device Driver
By ALESSANDRO RUBINI
LISOLEG Translation
2. Linux system analysis and Advanced Programming Technology
Edited by Zhou weisong
3. Linux Kernel-2.4.20 source code and documentation
Appendix 1: keyboard shuttle driver
QUOTE:
Related Article

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.