The USB Serial Driver Layer
In my last column [see LJ December 2002], we covered the serial layer in the 2.5 (hopefully soon to be 2.6) kernel tree. We mentioned in passing that a USB-to-serial driver layer in the kernel helps out in working with those types of device drivers. This time we discuss that layer in more depth.
A long time ago (in kernel development time, at least), a single USB-to-serial device driver was written and accepted into the kernel tree. It barely worked for one type of device and didn't work at all on SMP machines. As no standard USB-to-serial protocol existed, all devices used a custom protocol created by the individual vendors. The reason why there is no standard protocol is a long and sordid story; check the archives of the linux-usb-devel mailing list for the details. Soon a second type of USB-to-serial device was implemented within the first driver, sharing the reserved major and minor numbers. Over time, more and more devices were added to the driver until it was becoming an unwieldy mess. With the help of Peter Berger and Al Borchers, the original author of the driver rewrote the infrastructure and created what is now known as the USB-to-serial layer. This bit of code allows different USB-to-serial drivers to be written with a minimal amount of code, all sharing the same major and minor number range. It insulates the individual drivers from some of the complexity in the tty layer and the USB layer. It also allows the drivers to be compiled as individual modules and loaded only when they are needed.
In the 2.5 development cycle, the serial layer was created in order to provide an easier way to write serial port drivers, so as not to have to deal with the tty layer directly. Hopefully, someday the USB and serial layers will be merged. Both maintainers want to see this happen, but they do not have the time to do it. (They would gladly accept patches to accomplish this, if someone is looking for a project.)
In this article we cover the basics of the USB-to-serial layer, detailing how to register and unregister a driver and how to set up the main structures needed for a driver.
All of the code and examples in this article are for the 2.5/2.6 kernel tree. The 2.4 and 2.2 kernel trees also support USB-to-serial drivers, but their interfaces are a bit different in places. For ease of use, we focus on only one kernel tree. If you have any problems porting a USB-to-serial driver to these older trees (once it is running on 2.5), please let me know.
To register a USB-to-serial driver with the kernel, the driver has to do two things: register with the USB-to-serial core and register with the USB core. Registering with the USB-to-serial core tells it to call your driver when new devices are found by the USB subsystem, and registering with the USB core is needed to tell it what kind of devices your driver can accept.
To register with the USB core, all you need is a list of USB devices that your driver will work for, in traditional USB device ID format:
static struct usb_device_id id_table [] = {
{USB_DEVICE(MY_PRODUCT_ID, MY_DEVICE_ID)},
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, id_table);
This table is needed so the USB core knows what devices the driver can accept and the user-space hot-plug code knows what kind of devices are used. See my article “How the PCI Hot Plug Driver Filesystem Works”, LJ May 2002, for more information about this table and how the hot-plug code uses it.
Then, a simple USB device-driver structure is created with this ID information:
static struct usb_driver tiny_driver = {
.name = "tiny",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
};
The .probe and .disconnect fields must be set to point to the USB serial core's functions because that type of logic is handled by it and not by your driver.
Then, a simple call registers this driver with the USB core:
usb_register (&tiny_driver);
After this, the USB serial driver must be notified of the driver with a call to:
usb_serial_register (&tiny_device);This function takes a pointer to a struct usb_serial_driver_type, which will be explained in the following section.
To unregister a driver, the same steps have to happen, but in reverse order. First, we unregister with the USB serial core:
usb_serial_unregister (&tiny_device);
Then, we unregister with the USB core:
usb_unregister (&tiny_driver);
Trending Topics
| The Linux powered LAN Gaming House | Feb 08, 2012 |
| Creating a vDSO: the Colonel's Other Chicken | Feb 06, 2012 |
| Your CMS Is Not Your Web Site | Feb 01, 2012 |
| Casper, the Friendly (and Persistent) Ghost | Jan 31, 2012 |
| Razor-qt 0.4 - Qt based Desktop Environment | Jan 30, 2012 |
| Using Plop Boot Manager for USB Boot | Jan 25, 2012 |
- The Linux RAID-1, 4, 5 Code
- Readers' Choice Awards 2011
- The Linux powered LAN Gaming House
- Validate an E-Mail Address with PHP, the Right Way
- Why Python?
- Creating a vDSO: the Colonel's Other Chicken
- Building a Two-Node Linux Cluster with Heartbeat
- Python for Android
- Boot with GRUB
- Writing a Simple USB Driver
- I'll give it a whirl
3 hours 33 min ago - TFPT, don't you mean TFTP!? I
12 hours 1 min ago - wunderbar!!
12 hours 20 min ago - Best online store
16 hours 42 min ago - Best online store
16 hours 42 min ago - Best online store
16 hours 45 min ago - Best online store
16 hours 45 min ago - Best online store
16 hours 45 min ago - ----- http://ai.vc/zd
16 hours 46 min ago - Best online store
16 hours 46 min ago






Comments
Interesting article, when
Interesting article, when searching for Linux compatible USB serial adapters
this is a good source.