登录
注册
一键加入QQ群
友善之臂官方网站
首 页
联系我们
淘宝店铺
维基教程
资料下载
搜索帖子!
NanoPC-T2
Core4418
NanoPC-T3 Plus
Core6818
NanoPi-M4B
NanoPC-T4
NanoPC-T6
NanoPi-NEO
NanoPi-NEO Core
NanoPi-NEO Air
NanoPi-M1 Plus
NanoPi-Duo2
NanoPi-NEO3
核心板:
Smart210
Tiny210
Smart4418
Smart6818
SOM-RK3399V2
CM3588(新品)
路由器:
R1
R1S
R2S
R2S Plus
R2C Plus
R4S
R5S
R5C
R6C
R6S
热门版块:
友善之臂官方客服中心
Android技术交流区
ROM发布区
NanoPi 玩家交流区
开发板实战手册及教程
我的论坛我的贴
默认风格
用户中心首页
编辑个人资料
查看个人资料
好友列表
用户权限查看
积分管理
积分转换
特殊组购买
收藏夹
我的主题
基本统计信息
到访IP统计
管理团队
管理统计
在线统计
会员排行
版块排行
帖子排行
个人首页
我的收藏
好友近况
友善之家
Linux技术交流区
【分享】new style I2C设备驱动分析
友友粉丝快线
开发板销售中心
嵌入式最新资讯
友善之臂最新动态
友善之臂官方客服中心
开发板实战手册及教程
应用方案和定制开发
NanoPi 交流与讨论
NanoPi 玩家交流区
ROM发布区
硬软DIY及开发
嵌入式交流与讨论
Android技术交流区
Linux技术交流区
U-boot技术交流区
WinCE技术交流区
Ubuntu技术交流区
裸机程序和微型OS
OpenWRT讨论区
开发板硬件讨论区
相关资料下载及使用技巧
站点服务
二手交易区
我的论坛我的贴
站务管理与公告
上一主题
下一主题
«
1
2
3
4
5
»
Pages: 1/11 Go
新 帖
主题 : 【分享】new style I2C设备驱动分析
复制链接
|
浏览器收藏
|
打印
wuweidong
畅游在知识的海洋...
级别: 论坛版主
作者资料
发送短消息
加为好友
UID:
33629
精华:
4
发帖:
554
金钱:
3075 两
威望:
615 点
贡献值:
5 点
综合积分:
1188 分
注册时间:
2010-12-03
最后登录:
2015-09-22
楼主
发表于: 2012-03-24 18:37
只看楼主
|
小
中
大
【分享】new style I2C设备驱动分析
管理提醒:
本帖被 kasim 设置为精华(2012-03-26)
最近看了韦东山驱动视频的i2c部分,总结出相关知识,分享给大家
在内核中有两种方式的
i2c
设备驱动的编写方法,一种
legacy
方式,一种是
newstyle
方式。韦东山视频和宋宝华书籍里讲解的都是
legacy
方式,但是在新版本内核中,
legacy
方式的
i2c
设备驱动已经编译不过去了,因为几个主要的内核函数都已经不存在了,即内核不再支持
legacy
方式的
i2c
设备驱动。
下面讲解下
newstyle
方式的
i2c
设备驱动。
<
一
>
定义并填充
i2c_driver:
复制代码
staticconst struct i2c_device_id at24c08b_id[] = {
{"at24c08b", 0 }, //该i2c_driver所支持的i2c_client
{}
};
MODULE_DEVICE_TABLE(i2c,at24c08b_id);
/*定义并填充i2c_driver:
*probe设备探测函数,i2c_add_driver()时会被调用
*remove设备卸载函数;
*/
staticstruct i2c_driver at24c08b_driver = {
.driver= {
.name= "at24c08b",
.owner = THIS_MODULE,
},
.probe= at24c08b_probe,
.remove= __devexit_p(at24c08b_remove),
.id_table= at24c08b_id,
};
<
二
>
模块初始化函数
复制代码
staticint __init at24c08b_init(void)
{
returni2c_add_driver(&at24c08b_driver);
}
分析
i2c_add_driver():
复制代码
i2c_register_driver()
driver->driver.bus= &i2c_bus_type;//设置i2c_driver的总线类型
driver_register()//这个函数结束后就会调用probe()函数
i2c_for_each_dev(driver,__process_new_driver);//对每一个存在的i2c_adapter,调用__process_new_driver()函数
i2c_do_add_adapter()
i2c_detect(adap,driver);
//我们的i2c_driver没设置address_list和detect()函数,所以到这里就返回了。
address_list= driver->address_list;
if(!driver->detect || !address_list)
return0;
分析
driver_register()
:
复制代码
driver_find()//i2c_driver是否已经被注册
bus_add_driver()//将i2c_driver挂接到i2c总线i2c_bus_type上
driver_attach()
//对i2c总线上的每一个i2c设备i2c_client都会调用__driver_attach,这里的dev即i2c_client,drv即i2c_driver
bus_for_each_dev(drv->bus,NULL, drv, __driver_attach);
driver_match_device(drv,dev)
//调用i2c总线i2c_bus_type的match函数
returndrv->bus->match ? drv->bus->match(dev, drv) : 1;
i2c_device_match()
//若i2c_client的名字和i2c_device_id的中名字相同,则匹配成功,才会调用后面的probe()
i2c_match_id(driver->id_table,client)
driver_probe_device()
really_probe()
//调用i2c总线i2c_bus_type的probe函数
dev->bus->probe(dev);
i2c_device_probe()
//调用到i2c_driver的probe()函数
driver->probe(client, i2c_match_id(driver->id_table, client))
i2c
总线
i2c_bus_type
的定义如下:
复制代码
structbus_type i2c_bus_type = {
.name ="i2c",
.match =i2c_device_match,
.probe =i2c_device_probe,
.remove =i2c_device_remove,
.shutdown =i2c_device_shutdown,
...
};
<
三
>
注册
i2c
设备相关信息
对于
newstyle
方式,需要通过
i2c_register_board_info()
函数注册
i2c_board_info
,向内核提供
i2c
设备的相关信息。
在
arch/arm/mach-s3c2440/mach-mini2440.c
添加如下代码:
复制代码
/*I2C设备at24c08b的相关信息*/
staticstruct i2c_board_info i2c_devices[] __initdata = {
{I2C_BOARD_INFO("at24c08b", 0x50), }, //0x50是at24c08b的设备地址
};
staticvoid __init mini2440_machine_init(void)
{
…
i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));
}
分析
i2c_register_board_info()
:
复制代码
structi2c_devinfo *devinfo;//定义一个i2c_devinfo
devinfo->board_info= *info;//保存i2c_board_info
//将i2c_devinfo挂在链表__i2c_board_list上
list_add_tail(&devinfo->list,&__i2c_board_list);
搜索
__i2c_board_list
可知:
复制代码
i2c_add_numbered_adapter()//i2c-s3c2410.c中调用该函数来注册一个i2c_adapter
i2c_add_adapter()
i2c_register_adapter()
i2c_scan_static_board_info()
list_for_each_entry(devinfo,&__i2c_board_list, list)
//利用i2c_adapter和i2c_board_info构造i2c_client
if(devinfo->busnum == adapter->nr
&&!i2c_new_device(adapter,&devinfo->board_info))
structi2c_client *client;
client->adapter= adap;//设置i2c_client的adapter
client->addr= info->addr;//设置设备地址
…//继续设置i2c_client
device_register()//将i2c设备i2c_client挂接到i2c总线上
分析
device_register()
:
复制代码
device_add()
bus_add_device()
//将设备挂接在总线上,对于i2c而言,即把i2c_client挂接到i2c_bus_type
klist_add_tail(&dev->p->knode_bus,&bus->p->klist_devices);
ps:
上述这一套分析适用于所有符合总线设备驱动模型的驱动
,
如
usb
总线,平台总线,
pci
总线,
i2c
总线等
<
四
>i2c_driver
的
probe()
函数
正常的注册字符设备即可,即:
(1)
分配设备号
:alloc_chrdev_region()
(2)
构造
file_operations
(3)
分配设置注册
cdev
:
cdev_init(&cdev,&file_operations); cdev_add()
<
五
>file_operations
的
read()
和
write()
函数
(1)read:
复制代码
{
/* 检查该i2c_adapter是否支持读字节的功能 */
i2c_check_functionality(I2C_FUNC_SMBUS_READ_BYTE_DATA)
i2c_smbus_read_byte_data()//从eeprom读一个字节的数据
copy_to_user()//拷贝至用户空间
}
不是所有的
I2C
或者
SMBus
适配器实现了
I2C
规范上的所有功能,因此当访问
I2C
适配器时,
并不能完全假定适配器提供了你所需的功能。需要有一种检测适配器是否提供
了所需功能的方法。
对于不断更新的
I2C
适配器功能常量列表,参考
<linux/i2c.h>
I2C_FUNC_I2C
无格式
i2c-level
命令
I2C_FUNC_10BIT_ADDR
处理
10-bit
地址的扩展
I2C_FUNC_SMBUS_READ_BYTE
处理
SMBus read_byte
命令
I2C_FUNC_SMBUS_WRITE_BYTE
处理
SMBus write_byte
命令
I2C_FUNC_SMBUS_READ_BYTE_DATA
处理
SMBus read_byte_data
命令
I2C_FUNC_SMBUS_WRITE_BYTE_DATA
处理
SMBus write_byte_data
命令
I2C_FUNC_SMBUS_READ_WORD_DATA
处理
SMBus read_word_data
命令
I2C_FUNC_SMBUS_WRITE_WORD_DATA
处理
SMBus write_word_data
命令
...
分析
i2c_smbus_read_byte_data(I2C_SMBUS_BYTE_DATA)
:
复制代码
i2c_smbus_xfer(I2C_SMBUS_BYTE_DATA)
i2c_smbus_xfer_emulated(I2C_SMBUS_BYTE_DATA)
msg[1].len = 1;
...//设置读数据时的i2c_msg
i2c_transfer()
//最终调用到i2c-s3c2410.c中设置的i2c_adapter //的master_xfer()函数
adap->algo->master_xfer()
(2)write:
复制代码
{
/* 检查该i2c_adapter是否支持读字节的功能 */
i2c_check_functionality()
copy_from_user(); //获得用户空间的数据
i2c_smbus_write_byte_data()//写数据到eeprom
}
分析
i2c_smbus_write_byte_data(I2C_SMBUS_BYTE_DATA)
:
复制代码
i2c_smbus_xfer(I2C_SMBUS_BYTE_DATA)
i2c_smbus_xfer_emulated(I2C_SMBUS_BYTE_DATA)
msg[1].len = 2;
...//设置写数据时的i2c_msg
i2c_transfer()
//最终调用到i2c-s3c2410.c中设置的i2c_adapter //的master_xfer()函数
adap->algo->master_xfer()
ps:附件中有legacy和new style的at24cxx的驱动代码和测试代码,适用于mini2440
[ 此帖被wuweidong在2012-05-18 18:52重新编辑 ]
附件设置隐藏,需要回复后才能看到
好好学习,天天鲁管
顶端
回复
引用
分享
wuweidong
畅游在知识的海洋...
级别: 论坛版主
作者资料
发送短消息
加为好友
UID:
33629
精华:
4
发帖:
554
金钱:
3075 两
威望:
615 点
贡献值:
5 点
综合积分:
1188 分
注册时间:
2010-12-03
最后登录:
2015-09-22
1楼
发表于: 2012-03-26 12:22
只看该作者
|
小
中
大
一般人都不愿意看代码,其实分析内核代码才是王道
好好学习,天天鲁管
顶端
回复
引用
分享
kasim
*無鈳取玳
级别: 论坛版主
作者资料
发送短消息
加为好友
QQ联系
UID:
27
精华:
12
发帖:
5398
金钱:
40120 两
威望:
17929 点
贡献值:
71 点
综合积分:
11036 分
注册时间:
2008-01-16
最后登录:
2014-11-22
2楼
发表于: 2012-03-26 12:44
只看该作者
|
小
中
大
回 2楼(wuweidong) 的帖子
一般人都不愿意看代码,其实分析内核代码才是王道
+1 :)
"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."
顶端
回复
引用
分享
studying123
级别: 新手上路
作者资料
发送短消息
加为好友
UID:
65462
精华:
0
发帖:
1
金钱:
10 两
威望:
2 点
贡献值:
0 点
综合积分:
2 分
注册时间:
2012-03-19
最后登录:
2012-03-26
3楼
发表于: 2012-03-26 15:26
只看该作者
|
小
中
大
顶端
回复
引用
分享
linuxqt
级别: 侠客
作者资料
发送短消息
加为好友
UID:
58655
精华:
0
发帖:
129
金钱:
645 两
威望:
130 点
贡献值:
0 点
综合积分:
258 分
注册时间:
2011-11-11
最后登录:
2017-09-13
4楼
发表于: 2012-03-26 15:59
只看该作者
|
小
中
大
学习学习
顶端
回复
引用
分享
duzhaoguo
级别: 侠客
作者资料
发送短消息
加为好友
UID:
32635
精华:
0
发帖:
69
金钱:
350 两
威望:
70 点
贡献值:
0 点
综合积分:
138 分
注册时间:
2010-11-18
最后登录:
2014-07-02
5楼
发表于: 2012-03-26 16:51
只看该作者
|
小
中
大
不错,分析的不错
顶端
回复
引用
分享
cx4359481
级别: 骑士
作者资料
发送短消息
加为好友
UID:
32651
精华:
0
发帖:
152
金钱:
760 两
威望:
152 点
贡献值:
0 点
综合积分:
304 分
注册时间:
2010-11-18
最后登录:
2015-11-29
6楼
发表于: 2012-03-26 17:57
只看该作者
|
小
中
大
kankan!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
顶端
回复
引用
分享
kiss35151363
级别: 侠客
作者资料
发送短消息
加为好友
QQ联系
UID:
17217
精华:
0
发帖:
77
金钱:
390 两
威望:
78 点
贡献值:
0 点
综合积分:
154 分
注册时间:
2010-03-26
最后登录:
2017-11-10
7楼
发表于: 2012-03-27 02:45
只看该作者
|
小
中
大
内核不再支持legacy方式的i2c设备驱动?为什么Linux3.08还可以这样注册?我移植了Linux2.6.34的mma7660到3.08上。
顶端
回复
引用
分享
wuweidong
畅游在知识的海洋...
级别: 论坛版主
作者资料
发送短消息
加为好友
UID:
33629
精华:
4
发帖:
554
金钱:
3075 两
威望:
615 点
贡献值:
5 点
综合积分:
1188 分
注册时间:
2010-12-03
最后登录:
2015-09-22
8楼
发表于: 2012-03-27 08:12
只看该作者
|
小
中
大
回 8楼(kiss35151363) 的帖子
图片:
截了部分error的图,许多地方编译不过,再查看3.1.2内核:
i2c_detach_client,i2c_attach_client()等函数消失了,
内核可能还继续支持legacy方式的,但是肯定有地方需要修改,何不直接用new style呢
好好学习,天天鲁管
顶端
回复
引用
分享
kiss35151363
级别: 侠客
作者资料
发送短消息
加为好友
QQ联系
UID:
17217
精华:
0
发帖:
77
金钱:
390 两
威望:
78 点
贡献值:
0 点
综合积分:
154 分
注册时间:
2010-03-26
最后登录:
2017-11-10
9楼
发表于: 2012-03-27 22:00
只看该作者
|
小
中
大
是at24c02驱动太老太老了!i2c_get_adapter, i2c_new_device,i2c_add_driver还是一样的,这几个接口就可以注册了
顶端
回复
引用
分享
上一主题
下一主题
«
1
2
3
4
5
»
Pages: 1/11 Go
友善之家
Linux技术交流区
http://www.aiothome.net
访问内容超出本站范围,不能确定是否安全
继续访问
取消访问