Search code examples
clinuxusbdrivers

Usb device id table understanding


I am trying to understand different ways linux kernel initialize structures. In this query I wrote a sample usb driver but I do not understand some points, pointed as comments preceding ??

static struct usb_device_id pen_table[] =  //?? why pen_table is an array
{
    { USB_DEVICE(0xaaaa , 0x8816) },       //??what type of array initialization is this
    {} /* Terminating entry */             //??how this terminates
};

I tried to initialize device id table in this way, but I am getting errors as near initialization

static struct  usb_device_id pen_table = {
    .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
    .idVendor=0xaaaa,
    .idProduct = 0x8816,
};

Solution

  • You should have Linux kernel source at hand to really understand this.

    • Why pen_table is an array?

    It wil be necessary in MODULE_DEVICE_TABLE (see Hard time in understanding MODULE_DEVICE_TABLE(usb, id_table) usage) and in defining instance of usb_driver struct, see http://opensourceforu.efytimes.com/2011/11/usb-drivers-in-linux-2/.

    • what type of array initialization is this?

    USB_DEVICE is a macro defined in include/linux/usb.h:

    #define USB_DEVICE(vend, prod) \
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
        .idVendor = (vend), \
        .idProduct = (prod)
    
    • how this terminates?

    C standard says:

    The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.

    and:

    If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static storage duration is not initialized explicitly, then:

    • if it has pointer type, it is initialized to a null pointer;
    • if it has arithmetic type, it is initialized to (positive or unsigned) zero;
    • if it is an aggregate, every member is initialized (recursively) according to these rules;
    • if it is a union, the first named member is initialized (recursively) according to these rules.

    Thanks to this, id_table is defined as a pointer and not as an array inside usb_driver:

    const struct usb_device_id *id_table;
    

    Instead of passing an array size independently a function that uses id_table will increment pointer to id_table until one of its elements is NULL. See this short example that represents this technique:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct small
    {
        int a;
        int b;
    };
    
    struct big
    {
        struct small *s;
    };
    
    struct small table[] =
        {
            {1, 1},
            {2, 2},
            {3, 3},
            {}
        };
    
    int main(void)
    {
        struct big b = {
            .s = table
        };
    
        const struct small *s;
            /* traverse through table using pointer arithmetic */
        for (s = b.s; s->a; s++)
            {
                printf("%d\n", s->a);
                printf("%d\n", s->b);
            }
    
        exit(0);
    }
    
    • I tried to initialize device id table in this way, but I am getting errors as near initialization

    I don't, are you sure you're not trying to redefine pen_table? What's an error message?