Udev tutorial 2

6 minute read

Published:

Automating USB Kernel Module Loading with Udev and MODALIAS in Linux

The first blog page defines udev rules to match a plugged-in device and trigger a shell script to insert a kernel module that enables ARM performance accounting. In this post, I’ll demonstrate how to embed USB device information directly into the kernel module so that when the USB stick is plugged in, the kernel module will automatically load. The general idea comes from this source.

Every device driver/kernel module carries a list of known aliases for devices it can handle. The list is contained in the kernel module file itself. The program depmod reads the ID lists and creates the file modules.alias in the kernel’s /lib/modules directory for all currently available modules. With this infrastructure, module loading is as easy as calling modprobe for every event that carries a MODALIAS key. If modprobe $MODALIAS is called, it matches the device alias composed for the device with the aliases provided by the modules. If a matching entry is found, that module is loaded. All this is automatically triggered by udev.

Drivers, Kernel Modules and Devices

Define device IDs in Kernel Module

You must define the specific USB device IDs that your custom kernel module will handle. This is done using a usb_device_id table in your module.

#include  <linux/usb.h>
#include  <linux/module.h>
const  uint16_t  VENDOR_ID  =  0x0951;
const  uint16_t  PRODUCT_ID  =  0x1666;
/* Define USB device ID table */
static  const  struct  usb_device_id  my_usb_table[]  = {
{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, // Replace VENDOR_ID and PRODUCT_ID with your device's values
{ } /* Terminating entry. this is the end of the array, so it doesn't try to process beyond this point*/
};
MODULE_DEVICE_TABLE(usb, my_usb_table);

VENDOR_ID and PRODUCT_ID are the hexadecimal values specific to your USB device. This can be found by lsusb. For more Data fields of usb_device_id, check mod_devicetable.h

Bus 002 Device 004: ID 0951:1666 Kingston Technology DataTraveler 100 G3/G4/SE9 G2

Register USB Driver

register your kernel module as a USB driver that will bind to devices matching the specified device IDs. You can do this by creating and registering a usb_driver structure

/* Probe function: called when the device is connected */
static  int  my_usb_probe(struct  usb_interface  *interface, const  struct  usb_device_id  *id)
{
	printk(KERN_INFO "My custom USB device is connected\n");
	// Initialization code here
	return  0;
}
/* Disconnect function: called when the device is disconnected */
static  void  my_usb_disconnect(struct  usb_interface  *interface)
{
	printk(KERN_INFO "My custom USB device is disconnected\n");
	// Cleanup code here
}
static  struct  usb_driver  my_usb_driver  = {
	.name =  "my_custom_usb_driver",
	.id_table =  my_usb_table, // Referencing the ID table defined earlier
	.probe =  my_usb_probe, // Function called when the device is plugged in
	.disconnect =  my_usb_disconnect, // Function called when the device is unplugged
};
/* Register the USB driver */
static  int  __init  my_usb_init(void)
{
	return  usb_register(&my_usb_driver);
}
/* Deregister the USB driver */
static  void __exit my_usb_exit(void)
{
	usb_deregister(&my_usb_driver);
}
module_init(my_usb_init);
module_exit(my_usb_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Custom USB Driver Module");

This code sets up your module to handle the following:

  • The probe function is executed when the USB device is connected.
  • The disconnect function is executed when the USB device is unplugged.
  • usb_register() and usb_deregister() handle registering and deregistering your custom driver.

Build

Makefile

obj-m += my_usb_driver.o
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
make
sudo insmod my_usb_driver.ko

Update modules.alias

To automate the loading of your module using modprobe. Firstly, ensure that your module is installed and properly located in

ls /lib/modules/$(uname -r)/kernel/drivers/usb/my_usb_driver.ko

Then

`sudo depmod -a`
  • This updates the /lib/modules/$(uname -r)/modules.alias file to include the new device aliases.
  • When your USB device is connected, udev will trigger a MODALIAS event, and modprobe will load your custom kernel module if the alias matches.

How do I know if modules.alias contains the new device aliases?

$ grep my_usb_driver /lib/modules/$(uname -r)/modules.alias
alias usb:v0951p1666d*dc*dsc*dp*ic*isc*ip*in* usb_mod

Once you plug your USB device. use lsmod to find if the kernel module is loaded successfully.

$ lsmod
usb_mod                16384  0

https://github.com/lizeren/rasp-udev