Linux USB驱动源代码分析
+ -

LINUX驱动USB设备结构体转换关系及usb-skeleton的skel_probe函数

2024-03-07 29 0

usb-skeleton驱动中:https://elixir.bootlin.com/linux/v5.5-rc2/source/drivers/usb/usb-skeleton.c#L488

static int skel_probe(struct usb_interface *interface,
              const struct usb_device_id *id)
{
    dev->udev = usb_get_dev(interface_to_usbdev(interface));
    dev->interface = usb_get_intf(interface);
}
`

其中usb_get_dev定义如下:

#define    to_usb_device(d) container_of(d, struct usb_device, dev)
static inline struct usb_device *interface_to_usbdev(struct usb_interface *intf)
{
    return to_usb_device(intf->dev.parent);
}

可见,在struct usb_interface *interface的成员dev中,是其LINUX的普通设备对象,其parent是其父节点。而父节点是普通的设备对象类型,故需要to_usb_device转换为usb_device结构体。
USB设备栈

存储驱动私有数据

申请的自定义结构体usb_skel:

struct usb_skel *dev;

/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
...
usb_set_intfdata(interface, dev);

使用usb_interface *interface中成员中的dev的private来保存。

所以这里可以认为是DEVICE_OBJECT的扩展结构体

static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
{
    dev_set_drvdata(&intf->dev, data);
}
static inline void dev_set_drvdata(struct device *dev, void *data)
{
    dev->driver_data = data;
}

usb_set_intfdata(),他向内核注册一个data,这个data的结构可以是任意的,这段程序向内核注册了一个usb_skel结构,就是我们刚刚看到的被初始化的那个,这个data可以在以后用usb_get_intfdata来得到

usb_set_intfdata(interface, dev);

USB设备注册

因类USB设备可以可能是一个复合设备,在Windows系统中可以通过usbccgp来抽象出多个逻辑设备。而逻辑设备的基本单元就是USB接口描述符。所以对于usb设备可以有多个interface,每个interface所定义的IO操作可能不一样,所以向系统注册的usb_class_driver要求注册到某一个interface,而不是device,因此,usb_register_dev的第一个参数才是interface,而第二个参数就是某一个usb_class_driver。

static const struct file_operations skel_fops = {
    .owner =    THIS_MODULE,
    .read =        skel_read,
    .write =    skel_write,
    .open =        skel_open,
    .release =    skel_release,
    .flush =    skel_flush,
    .llseek =    noop_llseek,
};

/*
 * usb class driver info in order to get a minor number from the usb core,
 * and to have the device registered with the driver core
 */
static struct usb_class_driver skel_class = {
    .name =        "skel%d",
    .fops =        &skel_fops,
    .minor_base =    USB_SKEL_MINOR_BASE,
};

static int skel_probe(struct usb_interface *interface,
              const struct usb_device_id *id){
...
retval = usb_register_dev(interface, &skel_class);
}

usb_register_dev中主要是查找一个空的mirror

    for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
        if (usb_minors[minor])
            continue;

        usb_minors[minor] = class_driver->fops;
        intf->minor = minor;
        break;
    }

其中usb_mirror是一个全局数组:

#define MAX_USB_MINORS    256
static const struct file_operations *usb_minors[MAX_USB_MINORS];

而interface中的usb_dev成员,则通过 device_create创建

    /* create a usb class device for this usb interface */
    snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
    intf->usb_dev = device_create(usb_class->class, &intf->dev,
                      MKDEV(USB_MAJOR, minor), class_driver,
                      "%s", kbasename(name));

函数实现如下:

struct device *device_create(struct class *class, struct device *parent,
                 dev_t devt, void *drvdata, const char *fmt, ...)
{
    va_list vargs;
    struct device *dev;

    va_start(vargs, fmt);
    dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
    va_end(vargs);
    return dev;
}
struct device *device_create_vargs(struct class *class, struct device *parent,
                   dev_t devt, void *drvdata, const char *fmt,
                   va_list args)
{
    return device_create_groups_vargs(class, parent, devt, drvdata, NULL,
                      fmt, args);
}
static __printf(6, 0) struct device *
device_create_groups_vargs(struct class *class, struct device *parent,
               dev_t devt, void *drvdata,
               const struct attribute_group **groups,
               const char *fmt, va_list args)
{
    struct device *dev = NULL;
    int retval = -ENODEV;

    if (class == NULL || IS_ERR(class))
        goto error;

    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev) {
        retval = -ENOMEM;
        goto error;
    }

    device_initialize(dev);
    dev->devt = devt;
    dev->class = class;
    dev->parent = parent;
    dev->groups = groups;
    dev->release = device_create_release;
    dev_set_drvdata(dev, drvdata);

    retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
    if (retval)
        goto error;

    retval = device_add(dev);
    if (retval)
        goto error;

    return dev;

error:
    put_device(dev);
    return ERR_PTR(retval);
}

0 篇笔记 写笔记

关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!