Driver on

USB Drivers in Linux Continued

This twelfth article, which is a part of the collection on Linux system drivers, will get you additional with writing your first USB driver in Linux – a continuation from the earlier article.

Pugs continued, “Let’s construct upon the USB system driver coded in our earlier session, utilizing the identical useful JetFlash pen drive from Transcend with vendor id 0x058f and product id 0x6387. For that, we might dig additional into the USB protocol after which convert the training into code.”

USB endpoints and their sorts

Relying on the kind and attributes of data to be transferred, a USB system could have a number of endpoints, every belonging to one of many following 4 classes:

  • Management – For transferring management data. Examples embody resetting the system, querying details about the system, and so on. All USB gadgets all the time have the default management endpoint level zero.
  • Interrupt – For small and quick knowledge switch, usually of as much as Eight bytes. Examples embody knowledge switch for serial ports, human interface gadgets (HIDs) like keyboard, mouse, and so on.
  • Bulk – For large however comparatively sluggish knowledge switch. A typical instance is knowledge transfers for mass storage gadgets.
  • Isochronous – For large knowledge switch with bandwidth assure, although knowledge integrity will not be assured. Typical sensible utilization examples embody transfers of time-sensitive knowledge like of audio, video, and so on.

Moreover, all however management endpoints may very well be “in” or “out”, indicating its course of information switch. “in” signifies knowledge stream from USB system to the host machine and “out” signifies knowledge stream from the host machine to USB system. Technically, an endpoint is recognized utilizing a 8-bit quantity, most important bit (MSB) of which signifies the course – Zero that means out, and 1 that means in. Management endpoints are bi-directional and the MSB is ignored.

Figure 19

Determine 19 exhibits a typical snippet of USB system specs for gadgets related on a system. To be particular, the “E: ” traces within the determine exhibits instance of an interrupt endpoint of a UHCI Host Controller and two bulk endpoints of the pen drive into account. Additionally, the endpoint numbers (in hex) are respectively 0x81, 0x01, 0x82. The MSB of the primary and third being 1 indicating “in” endpoints, represented by “(I)” within the determine. Second one is an “(O)” for the “out” endpoint. “MaxPS” specifies the utmost packet dimension, i.e. the information dimension that may be transferred in a single go. Once more as anticipated, for the interrupt endpoint it’s 2 (<= 8), and 64 for the majority endpoints. “Ivl” specifies the interval in milliseconds to be given between two consecutive knowledge packet transfers for correct switch and is extra vital for the interrupt endpoints.

Decoding a USB system part

As we’ve simply mentioned the “E: ” line, it’s proper time to decode the related fields of others as nicely. In brief, these traces in a USB system part provides the entire overview of the USB system as per the USB specs, as mentioned in our earlier article. Refer again to Determine 19. The primary letter of the primary line of each system part is a “T” indicating the place of the system within the USB tree, uniquely recognized by the triplet . “D” represents the system descriptor containing at the very least the system model, system class/class, and the variety of configurations out there for this system. There could be as many “C” traces because the variety of configurations, usually one. “C” represents the configuration descriptor containing its index, system attributes on this configuration, most energy (really present) the system would draw on this configuration, and the variety of interfaces below this configuration. Relying on that there could be at the very least that many “I” traces. There may very well be extra in case of an interface having alternates, i.e. identical interface quantity however with completely different properties – a typical state of affairs for web-cams.

“I” represents the interface descriptor with its index, alternate quantity, performance class/class of this interface, driver related to this interface, and the variety of endpoints below this interface. The interface class could or will not be identical as that of the system class. And relying on the variety of endpoints, there could be as many “E” traces, particulars of which have already been mentioned above. The “*” after the “C” & “I” represents the at present lively configuration and interface, respectively. “P” line supplies the seller id, product id, and the product revision. “S” traces are string descriptors exhibiting up some vendor particular descriptive details about the system.

“Peeping into /proc/bus/usb/gadgets is sweet to determine whether or not a tool has been detected or not and presumably to get the primary minimize overview of the system. However likely this data could be required in writing the driving force for the system as nicely. So, is there a strategy to entry it utilizing ‘C’ code?”, requested Shweta. “Sure undoubtedly, that’s what I’m going to inform you subsequent. Do you keep in mind that as quickly as a USB system is plugged into the system, the USB host controller driver populates its data into the generic USB core layer? To be exact, it places that right into a set of buildings embedded into each other, precisely as per the USB specs”, replied Pugs. The next are the precise knowledge buildings outlined in – ordered right here in reverse for stream readability:

struct usb_device
{
    ...
    struct usb_device_descriptor descriptor;
    struct usb_host_config *config, *actconfig;
    ...
};
struct usb_host_config
{
    struct usb_config_descriptor desc;
    ...
    struct usb_interface *interface[USB_MAXINTERFACES];
    ...
};
struct usb_interface
{
    struct usb_host_interface *altsetting , *cur_altsetting;
    ...
};
struct usb_host_interface
{
    struct usb_interface_descriptor desc;
    struct usb_host_endpoint *endpoint ;
    ...
};
struct usb_host_endpoint
{
    struct usb_endpoint_descriptor  desc;
    ...
};

So, with entry to the struct usb_device deal with for a particular system, all of the USB particular details about the system could be decoded, as proven by way of the /proc window. However learn how to get the system deal with? In truth, the system deal with will not be out there straight in a driver, moderately the per interface handles (tips to struct usb_interface) can be found, as USB drivers are written for system interfaces moderately than the system as an entire. Recall that the probe & disconnect callbacks, that are invoked by USB core for each interface of the registered system, have the corresponding interface deal with as their first parameter. Refer the prototypes beneath:

int (*probe)(struct usb_interface *interface, const struct usb_device_id *id);
void (*disconnect)(struct usb_interface *interface);

So with the interface pointer, all details about the corresponding interface could be accessed. And to get the container system deal with, the next macro involves rescue:

struct usb_device system = interface_to_usbdev(interface);

Including these new studying into the final month’s registration solely driver, will get the next code itemizing (pen_info.c):

#embody 
#embody 
#embody 

static struct usb_device *system;

static int pen_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
    struct usb_host_interface *iface_desc;
    struct usb_endpoint_descriptor *endpoint;
    int i;

    iface_desc = interface->cur_altsetting;
    printk(KERN_INFO "Pen i/f %d now probed: (%04X:%04X)n",
            iface_desc->desc.bInterfaceNumber,
            id->idVendor, id->idProduct);
    printk(KERN_INFO "ID->bNumEndpoints: %02Xn",
            iface_desc->desc.bNumEndpoints);
    printk(KERN_INFO "ID->bInterfaceClass: %02Xn",
            iface_desc->desc.bInterfaceClass);

    for (i = 0; i < iface_desc->desc.bNumEndpoints; i++)
    {
        endpoint = &iface_desc->endpoint[i].desc;

        printk(KERN_INFO "ED[%d]->bEndpointAddress: 0x%02Xn",
                i, endpoint->bEndpointAddress);
        printk(KERN_INFO "ED[%d]->bmAttributes: 0x%02Xn",
                i, endpoint->bmAttributes);
        printk(KERN_INFO "ED[%d]->wMaxPacketSize: 0x%04X (%d)n",
                i, endpoint->wMaxPacketSize,
                endpoint->wMaxPacketSize);
    }

    system = interface_to_usbdev(interface);
    return 0;
}

static void pen_disconnect(struct usb_interface *interface)
{
    printk(KERN_INFO "Pen i/f %d now disconnectedn",
            interface->cur_altsetting->desc.bInterfaceNumber);
}

static struct usb_device_id pen_table[] =
{
    { USB_DEVICE(0x058F, 0x6387) },
    {} 
};
MODULE_DEVICE_TABLE (usb, pen_table);

static struct usb_driver pen_driver =
{
    .identify = "pen_info",
    .probe = pen_probe,
    .disconnect = pen_disconnect,
    .id_table = pen_table,
};

static int __init pen_init(void)
{
    return usb_register(&pen_driver);
}

static void __exit pen_exit(void)
{
    usb_deregister(&pen_driver);
}

module_init(pen_init);
module_exit(pen_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia ");
MODULE_DESCRIPTION("USB Pen Data Driver");

Then, the same old steps for any Linux system driver could also be repeated, together with the pen drive steps:

  • Construct the driving force (pen_info.ko file) by working make.
  • Load the driving force utilizing insmod pen_info.ko.
  • Plug-in the pen drive (after ensuring that usb-storage driver will not be already loaded).
  • Unplug-out the pen drive.
  • Verify the output of dmesg for the logs.
  • Unload the driving force utilizing rmmod pen_info.

Determine 22 exhibits a snippet of the above steps on Pugs’ system. Keep in mind to make sure (within the output of cat /proc/bus/usb/gadgets) that the same old usb-storage driver will not be the one related to the pen drive interface, moderately it ought to be the pen_info driver.

Figure 22

Summing up

Earlier than taking one other break, Pugs shared two of the various mechanisms for a driver to specify its system to the USB core, utilizing the struct usb_device_id desk. First one is by specifying the pair utilizing the USB_DEVICE() macro (as carried out above), and the second is by specifying the system class/class utilizing the USB_DEVICE_INFO() macro. In truth, many extra macros can be found in for varied mixtures. Furthermore, a number of of those macros may very well be specified within the usb_device_id desk (terminated by a null entry), for matching with any one of many standards, enabling to put in writing a single driver for presumably many gadgets.

“Earlier you talked about writing a number of drivers for a single system, as nicely. Mainly, how will we selectively register or not register a specific interface of a USB system?”, queried Shweta. “Positive. That’s subsequent in line of our dialogue, together with the final word activity in any system driver – the information switch mechanisms” replied Pugs.

Notes

Just be sure you substitute the vendor id & system id within the above code examples by those of your pen drive. One could surprise, as how does the usb-storage get autoloaded. The reply lies within the module autoload guidelines written down within the file /lib/modules//modules.usbmap. In case you are an professional, chances are you’ll remark out the corresponding line, for it to not get autoloaded. And uncomment it again, as soon as you might be carried out along with your experiments.

In newest distros, chances are you’ll not discover the detailed description of the USB gadgets utilizing cat /proc/bus/usb/gadgets, because the /proc/bus/usb/ itself has been deprecated. You will discover the identical detailed data utilizing cat /sys/kernel/debug/usb/gadgets – although chances are you’ll want root permissions for a similar. Additionally, if you don’t see any file below /sys/kernel/debug (whilst root), then you might have to first mount the debug filesystem, as follows: mount -t debugfs none /sys/kernel/debug

Leave a Reply

Your email address will not be published. Required fields are marked *