主题 : 对于linux驱动platform模型i2c总线驱动的疑问 复制链接 | 浏览器收藏 | 打印
级别: 侠客
UID: 87780
精华: 0
发帖: 93
金钱: 470 两
威望: 94 点
综合积分: 186 分
注册时间: 2013-02-26
最后登录: 2016-07-27
楼主  发表于: 2013-07-01 15:07

 对于linux驱动platform模型i2c总线驱动的疑问

在linux中我定义了下面下面几个平台设备
struct platform_device s3c_device_i2c0 = {
.name       = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
.id       = 0,
#else
.id       = -1,
#endif
.num_resources      = ARRAY_SIZE(s3c_i2c_resource),
.resource      = s3c_i2c_resource,
};
struct platform_device s3c_device_i2c1 = {
.name       = "s3c2410-i2c",
.id       = 1,
.num_resources      = ARRAY_SIZE(s3c_i2c_resource),
.resource      = s3c_i2c_resource,
};

然后我在分析设备dev注册的时候,我可以看到设备名字的修改,
if (pdev->id != -1)/*处理platform_device里面设备平台定义的时候的id情况*/
dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);/*将名字进行修改为name.id*/
else
dev_set_name(&pdev->dev, "%s", pdev->name);

再来看我对驱动的定义:
static struct platform_device_id s3c24xx_driver_ids[] = {
{
.name     = "s3c2410-i2c",
.driver_data    = TYPE_S3C2410,
}, {
.name     = "s3c2440-i2c",
.driver_data    = TYPE_S3C2440,
}, { },
};
MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);

static struct platform_driver s3c24xx_i2c_driver = {
.probe     = s3c24xx_i2c_probe,
.remove     = s3c24xx_i2c_remove,
.id_table    = s3c24xx_driver_ids,/*注意此处的定义,它的作用解释下面的名字为什么不一样*/
.driver     = {
.owner    = THIS_MODULE,
.name    = "s3c-i2c", /*注意此处的名称s3c-i2c,和我们先前注册设备的时候用的名字s3c2410-i2c不一样*/  
.pm    = S3C24XX_DEV_PM_OPS,
},
};
但当我分析dev和drv进行匹配的时候,靠id_table里面的drv名字与注册的时候的dev名字进行匹配的。
靠名字匹配,函数为:
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
然后调用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;
}
然后strcmp的源码又为:
int strcmp(const char *cs, const char *ct)
{
unsigned char c1, c2;

while (1) {
c1 = *cs++;
c2 = *ct++;
if (c1 != c2)
return c1 < c2 ? -1 : 1;
if (!c1)
break;
}
return 0;
}
现在问题来了,注册dev的时候因为id的原因,dev的名字做了修改,但drv的名字却没有修改,这样还能匹配吗?
求解决下小弟的笨问题。


后面个人再次阅读源码分析得知
if (pdev->id != -1)/*处理platform_device里面设备平台定义的时候的id情况*/
dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);/*将platform_device中嵌入device结构的的名字进行修改为平台设备pdev->(name+id)*/
else
dev_set_name(&pdev->dev, "%s", pdev->name);
这里面的代码其实不是修改平台设备驱动结构体pdev里面的name,而是修改平台设备驱动结构体
里面的设备驱动pdev->dev这个结构里面的name,所以下面拿出来的名字匹配,是可以匹配上的。

那如果这样的话,1个I2C总线驱动在注册的时候不是可以全部和3个I2C端口全部匹配(都用的同一个名字)?
可他们的对于端口不一样,I2C中断号也不一样,中断服务函数也不一样,那么在哪里开始发生分支?
应该从哪里开始分析开始?
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
1楼  发表于: 2013-07-01 23:13
可他们的对于端口不一样,I2C中断号也不一样,中断服务函数也不一样,那么在哪里开始发生分支?

在s3c24xx_i2c_probe()函数里
复制代码
  1.     /* map the registers */
  2.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  3.     if (res == NULL) {
  4.         dev_err(&pdev->dev, "cannot find IO resource\n");
  5.         ret = -ENOENT;
  6.         goto err_clk;
  7.     }
  8.     i2c->ioarea = request_mem_region(res->start, resource_size(res),
  9.                      pdev->name);
  10. ...
  11.     /* find the IRQ for this unit (note, this relies on the init call to
  12.      * ensure no current IRQs pending
  13.      */
  14.     i2c->irq = ret = platform_get_irq(pdev, 0);
  15.     if (ret <= 0) {
  16.         dev_err(&pdev->dev, "cannot find IRQ\n");
  17.         goto err_iomap;
  18.     }
  19.     ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
  20.               dev_name(&pdev->dev), i2c);
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
级别: 侠客
UID: 87780
精华: 0
发帖: 93
金钱: 470 两
威望: 94 点
综合积分: 186 分
注册时间: 2013-02-26
最后登录: 2016-07-27
2楼  发表于: 2013-07-02 09:12

 回 1楼(kasim) 的帖子

恩,这个我自己分析源码的时候已经明白了,也许是我表达不清楚。
在这个函数里发生了分支,但s3c24xx_i2c_probe(struct platform_device *pdev)这里传进来的总参数是pdev,那么pdev到底是对应3条总线上的s3c_device_i2c0,还是s3c_device_i2c1,或者是s3c_device_i2c2?因为在s3c24xx_i2c_probe发生的分支是根据pdev这个platform device结构体里面的资源进行设置的。
我想在这之前应该就已经发生了一次分支,用于区分这里传进来的pdev参数进行区分,不然按照我的理解,如果每次传进来的都一样,那么设置的硬件初始化也肯定一样。
不知道我的理解是不是对的?
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
3楼  发表于: 2013-07-02 09:42

 回 2楼(lihp1603) 的帖子

三条总线会有三个pdev传进来
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
级别: 侠客
UID: 87780
精华: 0
发帖: 93
金钱: 470 两
威望: 94 点
综合积分: 186 分
注册时间: 2013-02-26
最后登录: 2016-07-27
4楼  发表于: 2013-07-02 10:48

 回 3楼(kasim) 的帖子

恩,分别是怎么判断应该传哪一个pdev?这个是个关键,因为如果光靠里面的name判断的话,那就会出问题。。。因为3条用的全部都一样的名字,而不同的是id,但我没有找到相关源码位置,求解析。。。呵呵
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
5楼  发表于: 2013-07-02 11:15

 回 4楼(lihp1603) 的帖子

这三个pdev对于内核来说是三个不同的变量。虽然name栏位一样(用来匹配同一个驱动),但相关的IO, IRQ resources都是不同的。我不清楚你所说的问题是什么。关于这三个pdev的源代码,定义在arch/arm/plat-samsung/dev-i2c*.c里。
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
级别: 侠客
UID: 87780
精华: 0
发帖: 93
金钱: 470 两
威望: 94 点
综合积分: 186 分
注册时间: 2013-02-26
最后登录: 2016-07-27
6楼  发表于: 2013-07-02 11:50

 回 5楼(kasim) 的帖子

我的意思是说,在内核里面3个pdev是不是被看成3个总线设备?3个设备是不是要匹配他们驱动?驱动和设备之间的匹配是不是靠name来匹配的?
而我现在的意思是说,例如现在我要用i2c2来控制触摸屏,那么在调用s3c24xx_i2c_probe的时候后面传递的参数肯定就是s3c_device_i2c2了,那现在问题是在内核中那个地方判断当我要i2c2来控制触摸屏的时候,他能判断是我们需要传递的是s3c_device_i2c2?而不是s3c_device_i2c0或者s3c_device_i2c1?在程序的那个地方体现出来的?
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
7楼  发表于: 2013-07-03 21:55

 回 6楼(lihp1603) 的帖子

的意思是说,在内核里面3个pdev是不是被看成3个总线设备?

是的,分别对应I2C0,I2C1和I2C2三个I2C总线控制器

3个设备是不是要匹配他们驱动?驱动和设备之间的匹配是不是靠name来匹配的?

是的,而且这3个设备的驱动是同一个。是依靠name来匹配的。

而我现在的意思是说,例如现在我要用i2c2来控制触摸屏,那么在调用s3c24xx_i2c_probe的时候后面传递的参数肯定就是s3c_device_i2c2了,那现在问题是在内核中那个地方判断当我要i2c2来控制触摸屏的时候,他能判断是我们需要传递的是s3c_device_i2c2?而不是s3c_device_i2c0或者s3c_device_i2c1?在程序的那个地方体现出来的?

事实上,在现在tiny210的内核启动过程中,s3c24xx_i2c_probe()总会被依次调用三次,这是因为三个I2C总线的platform device都注册了。在arch/arm/mach-s5pv210/mach-mini210.c里,有
复制代码
  1. static struct platform_device *mini210_devices[] __initdata = {
  2. ...
  3.     &s3c_device_i2c0,
  4.     &s3c_device_i2c1,
  5.     &s3c_device_i2c2,


而每个I2C总线设备上要匹配哪些I2C设备(比如I2C接口的触摸屏),是由和这个I2C总线设备相关联的i2c_board_info结构决定的。需要注意的是,这里的匹配,是通过I2C总线驱动和设备的匹配实现的,和上面的platform device类型的设备和驱动的匹配原理一样,但却是互相独立的两个东西。比如在mach-mini210.c里,有
复制代码
  1. static struct i2c_board_info mini210_i2c_devs2[] __initdata = {
  2. #if defined(CONFIG_REGULATOR_MAX8698)
  3.     {
  4.         I2C_BOARD_INFO("max8698", 0xCC >> 1),
  5.         .platform_data  = &mini210_max8698_pdata,
  6.     },
  7. #endif
  8. #ifdef CONFIG_TOUCHSCREEN_GOODIX
  9.     {
  10.         I2C_BOARD_INFO("gt80x-ts", 0x55),
  11.         .platform_data = &goodix_pdata,
  12.     },
  13. #endif
  14. #ifdef CONFIG_TOUCHSCREEN_FT5X0X
  15.     {
  16.         I2C_BOARD_INFO("ft5x0x_ts", (0x70 >> 1)),
  17.         .platform_data = &ft5x0x_pdata,
  18.     },
  19. #endif
  20. };
  21. ...
  22. static void __init mini210_machine_init(void)
  23. {
  24. ...
  25.     i2c_register_board_info(2, mini210_i2c_devs2,
  26.             ARRAY_SIZE(mini210_i2c_devs2));

这说明在I2C2总线上有可能接了max8698,gt80x触摸屏和FT5x0x触摸屏。
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
级别: 侠客
UID: 87780
精华: 0
发帖: 93
金钱: 470 两
威望: 94 点
综合积分: 186 分
注册时间: 2013-02-26
最后登录: 2016-07-27
8楼  发表于: 2013-07-05 16:25
谢谢!!