参考:I2C子系统之platform_driver初始化——I2C_adap_s3c_init()

在完成platform_device的添加之后,i2c子系统将进行platform_driver的注册过程。platform_driver的注册通过调用初始化函数i2c_adapter_s3c_init函数来完成。

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",
.pm = S3C24XX_DEV_PM_OPS,
},
}; static int __init i2c_adap_s3c_init(void)
{
return platform_driver_register(&s3c24xx_i2c_driver);
}
subsys_initcall(i2c_adap_s3c_init);

这里先说一下MODULE_DEVICE_TABLE宏的作用:

MODULE_DEVICE_TABLE(platform, xx_driver_ids);

MODULE_DEVICE_TABLE一般用在热插拔的设备驱动中。
上述xx_driver_ids结构,是此驱动所支持的设备列表。
作用是:将xx_driver_ids结构输出到用户空间,这样模块加载系统在加载模块时,就知道了什么模块对应什么硬件设备。
用法是:MODULE_DEVICE_TABLE(设备类型,设备表),其中,设备类型,包括USB,PCI等,也可以自己起名字,
上述代码中是针对不同的平台分的类;设备表也是自己定义的,它的最后一项必须是空,用来标识结束。

平台驱动匹配到平台设备后,调用s3c24xx_i2c_driver.probe函数,即static int s3c24xx_i2c_probe(struct platform_device *pdev)。

static int s3c24xx_i2c_probe(struct platform_device *pdev)
-->struct s3c24xx_i2c *i2c;//分配s3c24xx_i2c结构体并初始化
-->ret = s3c24xx_i2c_init(i2c);//S3C6410 I2C控制器初始化
-->ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
dev_name(&pdev->dev), i2c);//设置中断
-->ret = i2c_add_numbered_adapter(&i2c->adap);

分配一个s3c24xx_i2c结构体,并根据平台设备的内容填充该结构体,如下图

下面具体分析i2c_add_numbered_adapter()函数,该函数根据传入的i2c_adapter结构体的内容分别在i2c_bus_type总线上注册adapter设备和client设备。

该函数执行后在/sys/bus/i2c/devices目录下生成如下图示文件

i2c_add_numbered_adapter(&i2c->adap);
-->i2c_register_adapter(adap);
-->dev_set_name(&adap->dev, "i2c-%d", adap->nr);
-->adap->dev.bus = &i2c_bus_type;
-->adap->dev.type = &i2c_adapter_type;
-->res = device_register(&adap->dev);//注释1,注册i2c总线 adapter设备
-->i2c_scan_static_board_info(adap);
-->list_for_each_entry(devinfo, &__i2c_board_list, list)
-->i2c_new_device(adapter,&devinfo->board_info))
-->struct i2c_client *client;//分配i2c_client结构体并初始化
-->client->adapter = adap;
-->client->dev.parent = &client->adapter->dev;
-->client->dev.bus = &i2c_bus_type;
-->client->dev.type = &i2c_client_type;
-->client->dev.of_node = info->of_node;
-->strlcpy(client->name, info->type, sizeof(client->name));
-->dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),client->addr);
-->status = device_register(&client->dev); //注释2,注册i2c总线 client设备
-->bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);

list_for_each_entry(devinfo, &__i2c_board_list, list)遍历I2C驱动框架(三)中最后图示的链表,以adapter结构体和找到的devinfo结构体中的i2c_board_info结构体为参数在i2c_bus_type总线上添加client设备。

最后还调用bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter)来扫描i2c总线,检测刚注册到i2c总线的adapter是否有对应的驱动。不过目前肯定失败,因为到目前为止还未注册adapter driver。

bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter)与I2C驱动框架(二)中分析的

bus_for_each_dev(&i2c_bus_type, NULL, &dummy_driver, __process_new_driver)相似。

bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);//遍历i2c_bus_type总线上的驱动
//以找到的驱动和i2c_adapter结构体为参数调用__process_new_driver函数
-->__process_new_adapter(struct device_driver *d, void *data)
-->i2c_do_add_adapter(to_i2c_driver(d), data);
-->i2c_detect(adap, driver);
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
-->int adap_id = i2c_adapter_id(adapter);//获取adapter的序列号,即处理器的第几个I2C控制器
-->const unsigned short *address_list = driver->address_list; //获取I2C从设备的地址数组
-->if (!(adapter->class & driver->class)) return ; //类型匹配后才继续执行
-->struct i2c_client *temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);//分配i2c_client结构体
-->temp_client->adapter = adapter;
-->for (i = ; address_list[i] != I2C_CLIENT_END; i += ) //遍历address_list里的i2c地址
-->temp_client->addr = address_list[i];//设置从地址到i2c_client结构体
-->i2c_detect_address(temp_client, driver);//检测该从地址对应的设备是否存在 static int i2c_detect_address(struct i2c_client *temp_client,struct i2c_driver *driver)
-->int addr = temp_client->addr;
-->i2c_check_addr_validity(addr);//检测地址有效性
-->i2c_check_addr_busy(adapter, addr);//检测设备是否正在使用,同一条物理I2Cbus上不能有两个相同address的器件
-->i2c_default_probe(adapter, addr);//检测i2c物理总线上是否有设备应答
-->struct i2c_board_info info.addr=temp_client->addr
-->driver->detect(temp_client, &info);//调用i2c_driver的detect函数检测设备,并经info.type赋值
-->struct i2c_client *client = i2c_new_device(adapter, &info);//在i2b_bus_type总线上创建i2c_client设备
-->list_add_tail(&client->detected, &driver->clients);//创建设备成功则将该i2c_client挂到i2c_driver的链表上

I2C驱动框架(四)的更多相关文章

  1. I2C驱动框架 (kernel-3.4.2)

    先用韦老师的图: 注:  新版本内核的i2c驱动框架采用了    i2c_client -------> i2c_bus_type  <-------- i2c_driver   框架 如 ...

  2. I2C驱动框架(三)

    参考:I2C子系统之platform_device初始化——smdk2440_machine_init() I2C驱动框架还应用了另一种总线-设备-驱动模型,平台设备总线platform_bus_ty ...

  3. Linux 驱动框架---i2c驱动框架

    i2c驱动在Linux通过一个周的学习后发现i2c总线的驱动框架还是和Linux整体的驱动框架是相同的,思想并不特殊比较复杂的内容如i2c核心的内容都是内核驱动框架实现完成的,今天我们暂时只分析驱动开 ...

  4. I2C驱动框架(kernel-2.6.22.6)

    以用i2c通信的实时时钟为例 框架入口源文件:i2c_m41t11.c (可根据入口源文件,再按着框架到内核走一遍) 内核版本:linux_2.6.22.6   硬件平台:JZ2440 以下是驱动框架 ...

  5. 【Linux高级驱动】I2C驱动框架分析

    1.i2c-dev.c(i2c设备驱动组件层) 功能:1)给用户提供接口 i2c_dev_init  //入口函数 /*申请主设备号*/ register_chrdev(I2C_MAJOR(), &q ...

  6. I2C驱动框架(二)

    参考:I2C子系统之I2C bus初始化——I2C_init() 在linux内核启动的时候最先执行的和I2C子系统相关的函数应该是driver/i2c/i2c-core.c文件中的i2c_init( ...

  7. I2C驱动框架(一)

    参考:I2C子系统之内核中I2C子系统的结构 结合vmlinux.lds和Makefile可确定i2c初始化函数的执行顺序如下: 1./dricer/i2c/i2c-core.c中的函数:i2c_in ...

  8. Linux I2C驱动框架

    Linux的I2C体系结构分为3个组成部分: I2C核心(  i2c-core.c ): I2C核心提供了I2C总线驱动和设备驱动的注册.注销方法.I2C通信方法("algorithm&qu ...

  9. I2C驱动框架(五)

    参考:I2C子系统之 adapter driver注册——I2C_dev_init() i2c的操作在内核中是当做字符设备来操作的,相关初始化在由i2c_dev_init函数来初始化. static ...

随机推荐

  1. Hive_Hive的管理_远程服务

    远程服务启动方式 - 端口号10000 - 启动方式: #hive --service hiveserver & 以JDBC或ODBC的程序登陆到hive中操作数据时,必须选用远程服务启动方式 ...

  2. 085 Maximal Rectangle 最大矩形

    给定一个填充了 0 和 1 的二进制矩阵,找到最大的只包含 1 的矩形并返回其面积.例如,给出以下矩阵:1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0返回 6 详见:http ...

  3. Centos 7.5源码编译安装zabbix4.0报fatal error: mysql.h: No such file or directory

    系统环境:CentOS 7.5是最小化安装的 编译信息 编译选项: root@Server01 zabbix-]# ./configure --prefix=/usr/share/applicatio ...

  4. spring boot使用AbstractXlsView导出excel

    一.maven依赖jar包 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi ...

  5. [转]为ReportViewer导出的PDF文档加上水印

    接到一個頗富挑戰性的需求,Reporting Service或RDLC報表可匯出成Excel.PDF等檔案格式,對一般麻瓜型使用者而言,PDF唯讀,Excel則可修改,業務單位希望在拿到報表紙本時加以 ...

  6. Django中多表的增删改查操作及聚合查询、F、Q查询

    一.创建表 创建四个表:书籍,出版社,作者,作者详细信息 四个表之间关系:书籍和作者多对多,作者和作者详细信息一对一,出版社和书籍一对多 创建一对一的关系:OneToOne("要绑定关系的表 ...

  7. let和const注意点

    let 一.块级作用域 下面的代码如果使用var,最后输出的是10. var a = []; for (var i = 0; i < 10; i++) { a[i] = function () ...

  8. CF1061B Views Matter

    思路: 贪心. 实现: #include <bits/stdc++.h> using namespace std; ]; int main() { int n, m; while (cin ...

  9. IE浏览器兼容background-size

    background-size是CSS3新增的属性,IE8以下不支持,通过滤镜实现background-size效果 background-size:contain; // 缩小图片来适应元素的尺寸( ...

  10. Hadoop2.6.2的Eclipse插件的使用

    欢迎转载,且请注明出处,在文章页面明显位置给出原文连接. 本文链接:http://www.cnblogs.com/zdfjf/p/5178197.html 首先给出eclipse插件的下载地址:htt ...