LINUX驱动USB设备结构体转换关系及usb-skeleton的skel_probe函数
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_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);
}