Linux USB Device Driver Part4 - Dumping Interface and Endpoint Information in Driver
Before diving into writing code, let's know the important structures of the usb subsystem.
1. struct usb_interface -> Representation of the USB Interface of the structure. We receive this as an argument in the probe function.
2. struct usb_device -> Kernel representation of a USB Device.
To get usb_device in driver, developers call interface_to_usbdev passing struct usb_interface as input.
3. struct usb_endpoint_descriptor -> Structure containing the endpoint information
3. struct usb_host_interface -> Host side wrapper for one interface setting
#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 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 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 0;
}
static void usb_disconnect(struct usb_interface *interface)
{
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);
Output:
Notes:
1. The probe function will be called for each interface of the device, if the device has multiple interfaces, then probe function will be called multiple times. If the driver does not support that interface it should return non zero value.
2. interface->cur_altsetting -> contains the setting of current active interface
3. bNumEndpoints -> Contains the number of endpoints supported by the interface
4. bmAttributes field in Endpoint descriptor -> Contains information about the type of endpoint : control, isochronous, interrupt or bulk
5. wMaxPacketSize in Endpoint descriptor -> Maximum packet size the endpoint is capable of receiving or sending
6. bInterfaceClass, bInterfaceSubClass in Interface Descriptor -> Specifies the class and subclass code (E.g. HID, Communication, mass storage etc)
1. struct usb_interface -> Representation of the USB Interface of the structure. We receive this as an argument in the probe function.
2. struct usb_device -> Kernel representation of a USB Device.
To get usb_device in driver, developers call interface_to_usbdev passing struct usb_interface as input.
3. struct usb_endpoint_descriptor -> Structure containing the endpoint information
3. struct usb_host_interface -> Host side wrapper for one interface setting
#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 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 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 0;
}
static void usb_disconnect(struct usb_interface *interface)
{
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);
Output:
Notes:
1. The probe function will be called for each interface of the device, if the device has multiple interfaces, then probe function will be called multiple times. If the driver does not support that interface it should return non zero value.
2. interface->cur_altsetting -> contains the setting of current active interface
3. bNumEndpoints -> Contains the number of endpoints supported by the interface
4. bmAttributes field in Endpoint descriptor -> Contains information about the type of endpoint : control, isochronous, interrupt or bulk
5. wMaxPacketSize in Endpoint descriptor -> Maximum packet size the endpoint is capable of receiving or sending
6. bInterfaceClass, bInterfaceSubClass in Interface Descriptor -> Specifies the class and subclass code (E.g. HID, Communication, mass storage etc)
Comments
Post a Comment