Linux USB Device Driver Part5 - USB Character driver

In this post, we will try to register our USB Device with the character subsystem (/dev/mydevice) allowing the user space to communicate with the USB Device

To register a USB  as character device, we need to call the below API in probe function:

int usb_register_dev(struct usb_interface *intf, struct usb_class_driver *class_driver);

To unregister, call the below API in disconnect function:

void usb_deregister_dev(struct usb_interface *intf, struct usb_class_driver *class_driver);

As we know for a device file we need to specify the major number and minor number. The major number is fixed for the character USB devices. It is 180. We need to specify the following in the members of struct usb_class_driver:
1. Name of the device node
2. File operations structure
3. Minor Number

Code:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
MODULE_LICENSE("GPL");
#define USB_VENDOR_ID 0x18ec
#define USB_PRODUCT_ID 0x3299
#define MYUSB_MINOR_BASE 250
#define DUMP_USB_INTERFACE_DESCRIPTOR( i ) \
{\
pr_info("USB_INTERFACE_DESCRIPTOR:\n"); \
pr_info("-----------------------------\n"); \
pr_info("bLength: 0x%x\n", i.bLength); \
pr_info("bDescriptorType: 0x%x\n", i.bDescriptorType); \
pr_info("bInterfaceNumber: 0x%x\n", i.bInterfaceNumber); \
pr_info("bAlternateSetting: 0x%x\n", i.bAlternateSetting); \
pr_info("bNumEndpoints: 0x%x\n", i.bNumEndpoints); \
pr_info("bInterfaceClass: 0x%x\n", i.bInterfaceClass); \
pr_info("bInterfaceSubClass: 0x%x\n", i.bInterfaceSubClass); \
pr_info("bInterfaceProtocol: 0x%x\n", i.bInterfaceProtocol); \
pr_info("iInterface: 0x%x\n", i.iInterface); \
pr_info("\n"); \
}
#define DUMP_USB_ENDPOINT_DESCRIPTOR( e ) \
{\
pr_info("USB_ENDPOINT_DESCRIPTOR:\n"); \
pr_info("------------------------\n"); \
pr_info("bLength: 0x%x\n", e.bLength); \
pr_info("bDescriptorType: 0x%x\n", e.bDescriptorType); \
pr_info("bEndPointAddress: 0x%x\n", e.bEndpointAddress); \
pr_info("bmAttributes: 0x%x\n", e.bmAttributes); \
pr_info("wMaxPacketSize: 0x%x\n", e.wMaxPacketSize); \
pr_info("bInterval: 0x%x\n", e.bInterval); \
pr_info("\n"); \
}
const struct usb_device_id usb_table[] = {
{ USB_DEVICE(USB_VENDOR_ID, USB_PRODUCT_ID) },
{ }
};
MODULE_DEVICE_TABLE(usb, usb_table);
static int myusb_open(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
return 0;
}
static int myusb_release(struct inode *inode, struct file *file)
{
pr_info("%s\n", __func__);
return 0;
}
static ssize_t myusb_write(struct file *file, const char *user_buffer,
size_t count, loff_t *ppos)
{
pr_info("%s\n", __func__);
return count;
}
static ssize_t myusb_read(struct file *file, char *buffer, size_t count,
loff_t *ppos)
{
pr_info("%s\n", __func__);
return 0;
}
static const struct file_operations myusb_fops = {
.owner = THIS_MODULE,
.open = myusb_open,
.release = myusb_release,
.read = myusb_read,
.write = myusb_write,
};
static struct usb_class_driver myusb_class = {
.name = "mydevice%d",
.fops = &myusb_fops,
.minor_base = MYUSB_MINOR_BASE,
};
static int usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
unsigned int i;
unsigned int num_endpoints;
struct usb_host_interface *iface_desc = interface->cur_altsetting;
dev_info(&interface->dev, "USB Driver Probed: Vendor ID:%02x\t"
"Product ID:%02x\n", id->idVendor, id->idProduct);
num_endpoints = iface_desc->desc.bNumEndpoints;
DUMP_USB_INTERFACE_DESCRIPTOR(iface_desc->desc);
for (i = 0; i < num_endpoints; i++) {
DUMP_USB_ENDPOINT_DESCRIPTOR(iface_desc->endpoint[i].desc);
}
return usb_register_dev(interface, &myusb_class);;
}
static void usb_disconnect(struct usb_interface *interface)
{
usb_deregister_dev(interface, &myusb_class);
dev_info(&interface->dev, "USB Driver Disconected\n");
}
static struct usb_driver usb_hello_driver = {
.name = "hello",
.probe = usb_probe,
.disconnect = usb_disconnect,
.id_table = usb_table,
};
module_usb_driver(usb_hello_driver);
view raw usbdump.c hosted with ❤ by GitHub
O/P: 


You can observe from the output, after I loaded the module and connected the device, I got four entries (/dev/mydevice*), this is because the device which I am using has four interface. If your device has only one interface, you will get /dev/mydevice0.

To test the write functionality executed: echo "hello" > /dev/mydevice0

To test the read functionality executed: cat < /dev/mydevice0

Comments

Popular posts from this blog

bb.utils.contains yocto

Difference between RDEPENDS and DEPENDS in Yocto

PR, PN and PV Variable in Yocto