How to write your own USB host device driver in Linux?

In this post, I will show you how you can easily write minimal USB device driver.

Objective: I have a 16 GB SanDisk USB thumb drive which should be detected by my driver when connected to system and my driver should be notified when this thumb drive gets disconnected from system. This thumb drive has Vendor id - 0X0781 and Product id - 0x5567.



Here is the minimal driver sample code(rax_usb.c):

Let me elaborate above driver code:

First we need to define usb_driver structure which identifies USB interface driver to USB core. 

usb_drive
Following fields are **MUST** for any USB interface driver and others are optional.
  • @name: The driver name should be unique among USB drivers, and should normally be the same as the module name
  • @probe: Called to see if the driver is willing to manage a particular interface on a device.  If it is, probe returns zero and uses usb_set_intfdata() to associate driver-specific data with the interface. It may also use usb_set_interface() to specify the appropriate altsetting. If unwilling to manage the interface, return -ENODEV, if genuine IO errors occurred, an appropriate negative errno value. Note: Read more about probe function in this post.
  • @disconnect: Called when the interface is no longer accessible, usually because its device has been (or is being) disconnected or the driver module is being unloaded.
  • @id_table: USB drivers use ID table to support hotplugging. Export this with MODULE_DEVICE_TABLE(usb,...). This must be set or your driver's probe function will never get called.
module_usb_driver
We have created usb_driver structure now we need to register this driver to USB subsystem of Linux. Linux provides module_usb_driver helper macro to do this job. So we have used this macro which needs usb_driver structure instance as an argument. This macro does not do anything special but be replaced with module_init and module_exit.


MODULE_DEVICE_TABLE

  1. Driver for each device exposes its information using the API MODULE_DEVICE_TABLE. Each device has a unique vendor Id and device Id.
  2. At compilation time, the build process extracts this information out of the driver and builds a table.
  3. When the device is plugged in, the kernel checks this device table to see if any driver is available for the particular Vendor/Device Id. If yes then it loads that driver and initializes the device.

Makefile to compile this driver is as follow:

Steps to build and insert module(sudo is required): 
  • Run "make" command from directory where rax_usb.c and Makefile are present.
  • By default mass storage USB devices like USB thumb drive uses "usb_storage" module from kernel so we need to unload/remove from system to make our own module working. There are multiple ways. I have done it through "rmmod uas" and "rmmod usb_storage". You can verify with "lsmod | grep usb_storage".
  • Now insert rax_usb module with "insmod rax_usb.ko" command.
  • Once module is inserted, attach USB thumb drive and you should see log message of probe function with Vendor Id and Product Id and on disconnecting thumb drive, you should be able to see disconnect log message.
Output 



Comments

  1. Do every individual vendor and product of different variants has to be written a code??
    What if there are other vendors which you don't know as of now

    ReplyDelete
  2. The USB protocol specifications define a set of standards that any device of a specific
    type can follow. If a device follows that standard, then a special driver for that
    device is not necessary. These different types are called classes and consist of things
    like storage devices, keyboards, mice, joysticks, network devices, and modems.
    Other types of devices that do not fit into these classes require a special vendor-specific
    driver to be written for that specific device. Video devices and USB-to-serial
    devices are a good example where there is no defined standard, and a driver is
    needed for every different device from different manufacturers.

    List of device classes - https://www.usb.org/defined-class-codes

    ReplyDelete

Post a Comment

Popular posts from this blog

MBR partitioning with 'parted' utility

Replace default splash screen in Yocto

Disk Partitioning: MBR vs GPT