1. 程式人生 > >一個驅動支援多個裝置再usb子系統、input子系統、platform、iic子系統 中的實現

一個驅動支援多個裝置再usb子系統、input子系統、platform、iic子系統 中的實現

platform

這裡寫圖片描述

你寫的驅動你應該知道它適用與哪些裝置吧,如果你想支援一個裝置,那麼你就構造一個
usb_device_id (USB)、i2c_device_id (IIC)、platform_device_id(Platform)放到對應驅動的id_table中

/**
    先看平臺匯流排。
*/
struct bus_type platform_bus_type = {
    .name       = "platform",
    .dev_attrs  = platform_dev_attrs,
    /**
        匹配驅動與裝置
    */
    .match      = platform_match,  
    .uevent     = platform_uevent,
    .pm     = &platform_dev_pm_ops,
};

    /**
        匹配的方法有兩種 : 
                    1 : 是利用了platform_driver中定義的id_table,(一個驅動可能支援多個裝置)
                        如果定義了id_table,那麼,就會逐一遍歷id_table表中的每一項
                        否則,使用name來匹配
                    2 : 使用name來匹配 (一個驅動只能支援一個裝置)    
    */
static int platform_match(struct device * dev,struct device_driver * drv) { /** 底層呼叫container_of巨集來獲取平臺裝置、平臺裝置驅動 */ struct platform_device = to_platform_device(dev); struct platform_driver = to_platform_driver(drv); /** 這個函式,如果drv->of_match_table不存在,或者dev->of_node不存在 就會返回NULL,實際中用的不多 最終還是比較 drv->of_match_table 和 dev->of_node的name、type等是不是一樣 if ((!matches) || (!dev->of_node)) return NULL; return of_match_node(matches, dev->of_node); */
if(of_driver_match_device(dev,drv)) { return 1; } /** 如果平臺驅動提供了id_table,那麼就會platform_match_id函式 id_table的出現,讓一個驅動支援多個裝置成為可能。 platform_match_id()這個函式會在下面說 */ if(pdrv->id_table) { return
platform_match_id(pdrv->id_table,pdev) != NULL; } /** 如果平臺驅動沒有提供id_table,那麼就會利用名字來比較了 如果是這樣,一個驅動只能支援一個裝置了 */ return (strcmp(pdev->name,drv->name) == 0); } /** 這個函式 會在驅動的id_table表裡面 查詢和platform_device的name欄位相同的一項 如果相同,那麼就返回true,否則返回false, 所以 : 這樣就可以一個驅動支援多個裝置, 如果只是簡單的比較name的話,那麼一個驅動只能支援一個裝置 */ 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; }

iic子系統

在前面的博文中已經詳細的分析過,這裡簡單的說一下,方便對比

struct bus_type i2c_bus_type = {
    .name       = "i2c",
    /**
        匹配函式,下面看這個函式。
    */
    .match      = i2c_device_match,
    /**
        iic匯流排提供了probe,匹配成功後會呼叫這個probe,
        然後再這個probe中呼叫驅動的probe
    */
    .probe      = i2c_device_probe,
    .....
};
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
    /**
        根據type型別來檢查是不是iic_client型別,
    */
    struct i2c_client   *client = i2c_verify_client(dev);
    struct i2c_driver   *driver;
    /**
        不是iic_client型別,就直接返回,因為這裡要匹配是iic_client和對應的驅動
    */
    if (!client) 
    {
        return 0;
    }   
    /**
        獲取iic_driver,是為了在下面取出來它的id_table
    */
    driver = to_i2c_driver(drv);
    /**
        如果提供了id_table就呼叫i2c_match_id()來比較
    */
    if (driver->id_table)
    {
        /**
            這個函式就是遍歷id_table,取出每一個表項來與iic_client的name比較
            其實還是利用了name比較,
        */
        return i2c_match_id(driver->id_table, client) != NULL;
    }   

    return 0;
}
/**
    看最終還是和上面的platform呼叫的是同一個函式。
*/
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
                        const struct i2c_client *client)
{
    while (id->name[0]) {
        if (strcmp(client->name, id->name) == 0)
            return id;
        id++;
    }
    return NULL;
}

usb子系統


struct bus_type usb_bus_type = {
    .name =     "usb",
    /**
        當呼叫usb_register()註冊一個usb_driver的時候
        __driver_attach()
            ....
               driver_match_device()
                     呼叫匯流排提供的match函式  
        如果這個match函式匹配不成功的話,那麼就不會呼叫驅動提供的probe函式(這裡匯流排沒有提供probe)
        具體match函式怎麼做的,下面有分析          
    */
    .match =    usb_device_match,
    .uevent =   usb_uevent,
};

static struct usb_driver usb_mouse_driver = {
    .name       = "usbmouse",
    .probe      = usb_mouse_probe,
    /**
        usb裝置拔出後呼叫的函式
        主要做一些銷燬、釋放、殺死urb的工作
    */
    .disconnect = usb_mouse_disconnect,
    /**
        前面說過,要想你寫的驅動支援某一個裝置的話,
        可以構造一個usb_device_id放到usb_mouse_id_table這個陣列中
        怎麼構造,以前的博文已經說過,可以使用核心提供了一些巨集來構造。
    */
    .id_table   = usb_mouse_id_table,
};