一個驅動支援多個裝置再usb子系統、input子系統、platform、iic子系統 中的實現
阿新 • • 發佈:2019-02-04
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,
};