当向linux系统总线添加设备或驱动时,总是会调用各总线对应的match匹配函数来判断驱动和设备是否匹配,这些match函数之间都存在一定的差异,本文先对常用的match匹配函数进行讲解,以后会陆续添加新的内容。
struct of_device_id
char name[32];#ifdef __KERNEL__
char type[32];
char compatible[128];
void *data;#else
kernel_ulong_t data;#endif
};
struct platform_device_id {
char name[PLATFORM_NAME_SIZE];
kernel_ulong_t driver_data __attribute__((aligned(sizeof(kernel_ulong_t))));
};
向系统添加平台驱动或添加设备时会调用平台总线platform_bus_type中的platform_match函数来匹配平台驱动和平台设备。
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/*通过驱动里定义了of_device_id项,则通过这一项来比对;*
if (of_driver_match_device(dev, drv))
return 1;
/*如果在平台驱动中定义了id_table项,则通过对比id_table来判断*/
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/*通过对比平台设备名字和平台驱动名字来判断*/
return (strcmp(pdev->name, drv->name) == 0);
}
由platform_match可以看出,驱动和设备是否匹配可以通过三种方式来进行判断,首先是通过of_device_id结构:
static inline int of_driver_match_device(struct device *dev, const struct device_driver *drv)
{
return of_match_device(drv->of_match_table, dev) != NULL;
}
struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev)
{
if ((!matches) || (!dev->of_node))
return NULL;
return of_match_node(matches, dev->of_node);
}
const struct of_device_id *of_match_node(const struct of_device_id *matches, const struct device_node *node)
{
if (!matches)
return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;if (matches->name[0])
match &= node->name && !strcmp(matches->name, node->name);
if (matches->type[0])
match &= node->type && !strcmp(matches->type, node->type);
if (matches->compatible[0])
match &= of_device_is_compatible(node, matches->compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
如果driver中定义了of_device_id,则通过driver中的of_device_id和device中的device_node内容进行匹配判断,匹配工作由of_match_node来完成,该函数会遍历of_device_id列表,查找是否有成员与device_node相匹配,具体由matches的name,type和compatioble来进行对比,如果找到则返回相应的表项,否则返回null.如果没有定义of_device_id,device_node或不能找到对应的匹配项,则通过第二种方式platform_device_id来进行对比匹配,通过platform_match_id来完成:
static const struct platform_device_id *platform_match_id( const struct platform_device_id *id, struct platform_device *pdev)
{
while (id->name[0]) {
if (strcmp(pdev->name, id->name) == 0) {
pdev->id_entry = id;
return id;
}
id++;
}
return NULL;
}
platform_match_id函数遍历platfrom_device_id列表,通过比对平台设备与id的name来确定是否有匹配项,如果找到匹配的,则返回对应的id项,否则返回null。如果没有定义platform_device_id或没有找到匹配项,则通过第三种方式进行匹配,第三种方式通过比对平台设备和平台驱动的名字,如果相等,则匹配成功,否则失败。
当向i2c总线添加驱动或设备时会调用i2c_device_match来进行匹配判断,i2c_device_match函数定义如下所示:
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client*client = i2c_verify_client(dev);
struct i2c_driver * driver;
if (!client)
return 0;
/* 通过of_device_id匹配 */
if (of_driver_match_device(dev, drv))
return 1;
driver = to_i2c_driver(drv);
/*如果I2C 驱动中定义了id_table,则通过id_table进行匹配;*/
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
return 0;
}
如i2c_device_match所示,i2c通过两种方式进行匹配设备和驱动,一种是of_device_id,另一种是i2c_device_id,i2c_device_id数据结构和platform_device_id一样。I2C里的两种匹配方式和之前的platform判断方式都是一样,这里就不展开。
当向usb总线上注册驱动或添加设备时,就会调用usb_match_device进行驱动和设备配对,函数如下:
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
if (is_usb_device(dev)) {
if (!is_usb_device_driver(drv))
return 0;
return 1;
} else if (is_usb_interface(dev)) {
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
if (is_usb_device_driver(drv))
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;
}
从函数可以看出,match分成两部分,一部分用于匹配usb设备,另一部分用于匹配usb 接口,对于usb设备,在初始化时会设置成usb_device_type,而usb接口,则会设成usb_if_device_type。而函数中的is_usb_device和is_usb_interface就是通过这两个属性来判别的,如果为判定为设备,则进入到设备分支,否则进入到接口分支继续判断。
usb设备驱动通过usb_register_device_driver接口来注册到系统,而usb接口驱动则通过usb_register来注册到系统,驱动工程师的工作基本上集中在接口驱动上,所以通常是通过usb_register来注册usb驱动的。
不管是设备驱动usb_device_driver,还是接口驱动usb_driver数据结构中都包含了struct usbdrv_wrap项,其定义如下:
struct usbdrv_wrap {
struct device_driver driver;
int for_devices;
}
数据结构中的for_devices用来表示该驱动是设备驱动还是接口驱动,如果为设备驱动,则在用usb_register_device_driver注册时,会将该变量for_devices设置成1,而接口驱动则设为0.
usb_device_match中的is_usb_device_driver函数就是通过获取上而结构中的for_devices来进行判断是设备还是接口驱动的,函数定义如下:
static inline int is_usb_device_driver(struct device_driver *drv)
{
return container_of(drv, struct usbdrv_wrap, driver)->for_devices;
}
当进入is_usb_device分支后,再通过is_usb_device_driver来判断是否为设备驱动,如果是则返回1,表示匹配成功,它接受所有usb设备。
当进入到接口分支后,也会先用is_usb_device_driver来进行判断,如果不是设备驱动则继续判断,否则退出;然后再通过usb_match_id函数来判断设备和驱动中的usb_device_id是否匹配,usb_match_id定义如下:
const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
{
if (id == NULL)
return NULL;
for (; id->idVendor || id->idProduct || id->bDeviceClass || id->bInterfaceClass || id->driver_info; id++) {
if (usb_match_one_id(interface, id))
return id;
}
return NULL;
}
遍历接口驱动中的usb_device_id列表项,只要usb_device_id结构中的idVendor,idProduct,DeviceClass,binterfaceClass,driver_info项有效就调用usb_match_one_id进行判断,如找到匹配项则函数返回1,否则返回0 。
int usb_match_one_id(struct usb_interface *interface,const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
if (id == NULL)
return 0;
intf = interface->cur_altsetting;
dev = interface_to_usbdev(interface);
if (!usb_match_device(dev, id))
return 0;
if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
return 0;
return 1;
}
usb_match_one_id和函数中的usb_match_device都是围绕着usb_device_id进行匹配的,该结构定义如下:
struct usb_device_id {
/* which fields to match against? */
__u16 match_flags;
/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* not matched against */
kernel_ulong_tdriver_info;
};
match_flags用来规定驱动匹配时的具体项,如match_flags包含USB_DEVICE_ID_MATCH_VENDOR,则是通过驱动中的usb_device_id和设备dev中的idVendor来判断。