close

當向linux系統匯流排添加設備或驅動時,總是會調用各匯流排對應的match匹配函數來判斷驅動和設備是否匹配,這些match函數之間都存在一定的差異,本文先對常用的match匹配函數進行講解,以後會陸續添加新的內容。 

. 驅動和設備匹配過程常用資料結構

1. of_device_id

struct of_device_id
{

charname[32];
char type[32];
char compatible[128];

#ifdef __KERNEL__

void*data;

#else

kernel_ulong_t data;

#endif

};

2. platform_device_id

strut 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可以看出,驅動和設備是否匹配可以通過三種方式來進行判斷,首先是通過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_iddevice中的device_node內容進行匹配判斷,匹配工作由of_match_node來完成,該函數會遍歷of_device_id清單,查找是否有成員與device_node相匹配,具體由matchesname,typecompatioble來進行對比,如果找到則返回相應的表項,否則返回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清單,通過比對平臺設備與idname來確定是否有匹配項,如果找到匹配的,則返回對應的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_idi2c_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_deviceis_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;

};

 

 

 

https://blog.csdn.net/fanqipin/article/details/8153053

          match_flags用來規定驅動匹配時的具體項,如match_flags包含USB_DEVICE_ID_MATCH_VENDOR,則是通過驅動中的usb_device_id和設備dev中的idVendor來判斷。

arrow
arrow
    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()