各种总线match匹配函数

  当向linux系统总线添加设备或驱动(driver_register/device_register)时,总是会调用各总线对应的match匹配函数来判断驱动和设备是否匹配,这些match函数之间都存在一定的差异,本文先对常用的match匹配函数进行讲解,以后会陆续添加新的内容。 

一. 驱动和设备匹配过程常用数据结构

1. of_device_id

struct of_device_id
{
char name[32];
char type[32];
char compatible[128];
#ifdef __KERNEL__
void *data;
#else
kernel_ulong_t data;
#endif

};

2. platform_device_id

struct platform_device_id {

char name[PLATFORM_NAME_SIZE];

kernel_ulong_t driver_data   __attribute__((aligned(sizeof(kernel_ulong_t))));

};

二. 平台设备、驱动匹配platform_match

          向系统添加平台驱动或添加设备时会调用平台总线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可以看出,驱动和设备是否匹配可以通过三种方式来进行判断:

         1. driver->of_match_table与device->of_node匹配。具体分为name、type或compatible其中一个字段进行匹配。

         2.如果存在driver->id_table,就匹配id_talbe与pdev的name字段是否匹配。(常用于一驱动对应多设备的情况)

         3.直接匹配driver与pdev的name字段。


首先是通过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总线添加驱动或设备时会调用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_device_match

当向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来判断。

你可能感兴趣的:(各种总线match匹配函数)