Linux Device Driver Tutorial Part 34 – USB Device Driver Example – 2

This is the Series on Linux Device Driver. The aim of this series is to provide easy and practical examples that anyone can understand. This is the Linux Device Driver Tutorial Part 34 – USB Device Driver Example program in the Linux Device Driver.

USB Device Driver Example

Prerequisites

Before starting this USB device driver example, I would recommend you to understand the USB device concepts using the below link.

Introduction

In our last tutorial, we have gone through the big theory part that explains the functionality of the USB device and its subsystem in Linux. So now, we can go straight away to the example.

USB Driver API

This is just like a character device driver. But the structure and others will be different. Let’s see.

usb_driver structure

USB driver needs to do is register itself with the Linux USB subsystem (USB core). So while registering we need to give some information about which devices the driver supports and which functions to call when a device supported by the driver is inserted or removed from the system. All of this information is passed to the USB subsystem via usb_driver structure.

Where,

<name>: The driver name should be unique among USB drivers, and should normally be the same as the module name.

<probe>: The function needs to be called when a USB device is connected. 

<disconnect>: The function needs to be called when a USB device is disconnected.

<ioctl>: Used for drivers that want to talk to userspace through the usbfs filesystem.

<suspend>: Called when the device is going to be suspended by the system.

<resume>: Called when the device is being resumed by the system.

<reset_resume>: Called when the suspended device has been reset instead of being resumed.

<pre_reset>: Called by usb_reset_device when the device is about to be reset.

<post_reset>: Called by usb_reset_device after the device has been reset.

<id_table>: USB drivers use an 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.

<dynids>: used internally to hold the list of dynamically added device ids for this driver.

<drvwrap>: Driver-model core structure wrapper.

<no_dynamic_id>: if set to 1, the USB core will not allow dynamic ids to be added to this driver by preventing the sysfs file from being created.

<supports_autosuspend>: if set to 0, the USB core will not allow auto suspend for interfaces bound to this driver.

<soft_unbind>: if set to 1, the USB core will not kill URBs and disable endpoints before calling the driver’s disconnect method.

USB interface drivers must provide a name, probe and disconnect methods, and an id_table. Other driver fields are optional.

id_table

The id_table is used in hotplugging. It holds a set of descriptors, and specialized data may be associated with each entry. That table is used by both user and kernel mode hotplugging support.

The following code tells the hotplug scripts that this module supports a single device with a specific vendor and product ID:

Notes: Make sure that you have replaced the vendor id & device id with your USB device in the above code example.

probe

When a device is plugged into the USB bus that matches the device ID pattern that your driver registered with the USB core, the probe function is called.

The driver now needs to verify that this device is actually accepted or not. If it is accepted, it returns 0. If not, or if any error occurs during initialization, an error code (such as -ENOMEM or -ENODEV) is returned from the probe function.

Example snippet of the probe

disconnect

When a device is plugged out or removed, this function will be getting called.

Example snippet of the disconnect

Example snippet of usb_driver structure

Once you have written the probe, disconnect functions, and id_table, then you have to assign their address to the usb_driver structure like below.

As of now, we have finished the basic kinds of stuff. Now we need to register the USB device with a USB core.

Register the USB device driver to the USB Subsystem (USB core)

This API is used to register the USB driver to the USB subsystem.

usb_register (struct usb_driver * your_usb_driver);

Where,

<your_usb_driver>: The structure which will tell the address of probe, disconnect, and id_table.

Example

Deregister the USB device driver from the USB subsystem

This API is used to deregister the USB driver from the USB subsystem.

usb_deregister (struct usb_driver * your_usb_driver);

Where,

<your_usb_driver>: The structure which will tell the address of probe, disconnect, and id_table.

Example

Initialize and exit function

We have completed all the things. But where should we call the usb_register and usb_deregister function? It is just simple. Like a character device driver, we have to do this in __init and __exit functions. Refer to the below example.

module_usb_driver

Is that all? Yes if you use the kernel older than 3.3. But if you are using the latest Linux kernel which is greater than 3.3, then there is one another option that you can use. You can eliminate this usb_register, usb_deregister ,__init , __exit, module_init and module_exit functions in one line. ie, You can eliminate all the code which has been provided above can be replaced by below one line.

module_usb_driver(__usb_driver);

Where,

<__usb_driver>: usb_driver structure

This is the helper macro for registering a USB driver. This macro for USB drivers which do not do anything special in module init/exit. This eliminates a lot of boilerplate. Each module may only use this macro once, and calling it replaces module_init and module_exit.

Example Programming

We have written some very basic USB device drivers which will just print the Interface descriptor and Endpoint descriptor while inserting the device. And we have used both the old method ( module_init and module_exit) and the new method (module_usb_driver). You can choose anyone by changing the macro IS_NEW_METHOD_USEDIf you set 0, then it will use the old method. If you set 1 or non-zero value, it will use the new method.

And one more point, we have used the dev_info API here to print the data. dev_info is similar to pr_infobut also print some information about device(struct device), passed to them as the first argument. This information may help to filter the system log for messages, belonging to the concrete device.

Just go through the code below. You can easily understand this if you have followed our previous character device driver tutorials.

Note: In this tutorial, I have not used any separate microcontrollers. I have used my ubuntu as a host which is installed by using VirtualBox and My mobile phone as a USB device. This is just for learning purposes. And I have used the Linux kernel 5.3.0-42-generic.

Driver Source Code

Makefile

Execution

Notes: Make sure that you have replaced the vendor id & device id with your USB device in the above code example.

  • Build the driver by using Makefile (sudo make)
  • Load the driver using sudo insmod usb_driver.ko
  • Check the dmesg

  • Our driver is linked with the USB subsystem.
  • Connect the appropriate USB device with the correct vendor id and product id. We should see our etx_usb_probe function getting called.
  • Check the dmesg

  • Cool. Now disconnect the USB device and check dmesg

  • Unload the driver using sudo rmmod usb_driver and check the dmesg

  • Now the driver is removed from the USB subsystem.

That’s all now. In our next tutorial, we will discuss other functionalities of the USB driver.

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of
%d bloggers like this: