您的位置:首页 > 其它

一个驱动支持多个设备再usb子系统、input子系统、platform、iic子系统 中的实现

2016-02-01 19:58 609 查看

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,
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: