linux USB Subsystem

Keywords: Linux

1.usb bus device model

Bus device driver model used in linux usb subsystem.
In the linux kernel, there is a USB bus named usb_bus_type

struct bus_type usb_bus_type = {
    .name =     "usb",
    .match =    usb_device_match,
    .uevent =   usb_uevent,
};

Under this bus, there are usb devices and usb drivers.
According to the type of device and driver, it can be divided into two categories.
One is usb device and the other is usb interface device.
usb device and usb device driver are matched, usb interface device and usb interface driver are matched.
Through the match function, the matching of these two classes enters different branches.

static int usb_device_match(struct device *dev, struct device_driver *drv)
{
    /* devices and interfaces are handled separately Separate processing of equipment and interface equipment*/
    if (is_usb_device(dev)) {//usb device

        /* interface drivers never match devices */
        if (!is_usb_device_driver(drv))
            return 0;

        /* TODO: Add real matching code */
        return 1;

    } else if (is_usb_interface(dev)) {//usb interface device
        struct usb_interface *intf;
        struct usb_driver *usb_drv;
        const struct usb_device_id *id;

        /* device drivers never match interfaces */
        if (is_usb_device_driver(drv)) // == 0 represents interface driver and non-0 represents device driver
            return 0;

        intf = to_usb_interface(dev);
        usb_drv = to_usb_driver(drv);

        id = usb_match_id(intf, usb_drv->id_table);
        if (id)
            return 1;

        id = usb_match_dynamic_id(intf, usb_drv);
        if (id)
            return 1;
    }

    return 0;
}

/* -------- */
The USB interface device (device type == usb_if_device_type) is registered by device_add
The USB interface driver (struct usb_driver, which we need to implement) is registered with usb_register
/* -------- */
The USB device (device type == usb_device_type) is registered by device_add
USB device driver () registered by usb_register_device_driver()

2. Access process of USB devices

1. When the usb device inserts the usb interface, the level of the usb differential signal line changes, resulting in the interruption hub_irq of the usb controller, notifying the system of usb device access.
2. The usb hub thread is awakened by hub_irq and the following function calls occur
hub_irq
    kick_khubd
        hub_thread
            hub_events
                hub_port_connect_change//Port connection changed
                    udev = usb_alloc_dev//Assign a usb device
                    hub_port_init//Get Device Descriptor
                    usb_new_device(udev)
                        usb_enumerate_device//Enumeration device
                            usb_get_configuration//Get the configuration descriptor
                                for(; cfgno < ncfg; cfgno++)//How many configurations are captured?
                                {
                                    usb_get_descriptor //Get the configuration descriptor, get the size                               
                                    usb_parse_configuration//Parsing configuration descriptor    
                                        usb_parse_interface//Parsing interface descriptor
                                            usb_parse_endpoint//Analytical endpoint descriptor                                     
                                }
                        device_add(The types of registered equipment are: usb_device_type) //Call the usb_bus_type-> match function. If the match is successful, the probe function of usb_device_driver will be called.                                               

Where is the usb device driver registered?
Register at / driver/usb/core/usb.c

struct usb_device_driver usb_generic_driver = {
    .name = "usb",
    .probe = generic_probe,
    .disconnect = generic_disconnect,
#ifdef  CONFIG_PM
    .suspend = generic_suspend,
    .resume = generic_resume,
#endif
    .supports_autosuspend = 1,
};


usb_init
    usb_register_device_driver(&usb_generic_driver )
        generic_probe //If it matches the usb device, it will cause the probe function to be called
            usb_set_configuration //set configuration
                for (i = 0; i < nintf; ++i) //Register as many usb_if_device_type interface devices as you have
                {       
                    struct usb_interface *intf = cp->interface[i];
                    . . . 
                    intf->dev.bus = &usb_bus_type;
                    intf->dev.type = &usb_if_device_type;//usb interface device
                    ret = device_add(&intf->dev);   // Put device in the dev list of usb_bus_type.                             
                                                // Remove the usb_driver from the driver list of usb_bus_type.                       
                                                // Comparing the id_table of usb_interface and usb_driver
                                                // If it matches, call probe of usb_driver 
                                                // So an interface corresponds to a usb driver
                . . . 
                }

As you can see from the above code, the following events are triggered when accessing the usb device
Register the usb device - > Register the usb interface device according to the interface descriptor of the usb device (there are as many interfaces as there are usb interface devices)
So we need to implement an interface device driver to drive USB interface devices (devices of type usb_if_device_type)

3 usb interface device driver writing

Reference resources: h:\linux_source_code\linux-3.0.1\drivers\hid\usbhid\Usbmouse.c

static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
    struct usb_device *dev = interface_to_usbdev(intf);
    struct usb_host_interface *interface;
    struct usb_endpoint_descriptor *endpoint;
    int pipe;

    interface = intf->cur_altsetting;
    endpoint = &interface->endpoint[0].desc;

    /* a. Assign an input_dev */
    uk_dev = input_allocate_device();

    /* b. Set up */
    /* b.1 What kind of events can occur? */
    set_bit(EV_KEY, uk_dev->evbit);
    set_bit(EV_REP, uk_dev->evbit);

    /* b.2 What events can occur? */
    set_bit(KEY_L, uk_dev->keybit);
    set_bit(KEY_S, uk_dev->keybit);
    set_bit(KEY_ENTER, uk_dev->keybit);

    /* c. register */
    input_register_device(uk_dev);

    /* d. Hardware-related operations */
    /* Three Elements of Data Transmission: Source, Purpose, Length */
    /* Source: An Endpoint of a USB Device */
    pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

    /* Length: */
    len = endpoint->wMaxPacketSize;

    /* Objective: */
    usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);

    /* Use of "three elements" */
    /* Allocate usb request block */
    uk_urb = usb_alloc_urb(0, GFP_KERNEL);
    /* Use "3 Elements to Set up urb" */
    usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
    uk_urb->transfer_dma = usb_buf_phys;
    uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    /* Using URB */
    usb_submit_urb(uk_urb, GFP_KERNEL);

    return 0;
}

//Interface matching idtable
static struct usb_device_id usb_mouse_id_table [] = {
        { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
            USB_INTERFACE_PROTOCOL_MOUSE) },
        { } /* Terminating entry */
};
//usb Interface Driver Architecture
static struct usb_driver usb_mouse_driver = {
    .name       = "usbmouse",
    .probe      = usb_mouse_probe,
    .disconnect = usb_mouse_disconnect,
    .id_table   = usb_mouse_id_table,
};

static int __init usb_mouse_init(void)
{
    int retval = usb_register(&usb_mouse_driver);
}

So much for your reference.

Posted by 3.grosz on Sat, 18 May 2019 05:40:21 -0700