newstyle方式的i2c设备驱动
来源:互联网 发布:linux 执行脚本 编辑:程序博客网 时间:2024/05/29 18:34
<一>定义并填充i2c_driver:
对于newstyle方式,需要通过i2c_register_board_info()函数注册i2c_board_info,向内核提供i2c设备的相关信息。
在arch/arm/mach-s3c2440/mach-mini2440.c添加如下代码:
<四>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适配器功能常量列表,参考<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):
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()转自:http://www.arm9home.net/read.php?tid-18473-fpage-0-toread--page-1.html
- newstyle方式的i2c设备驱动
- 两种方式的i2c设备驱动的编写方法
- I2C设备驱动的编写
- i2c设备驱动的来龙去脉
- I2C设备与驱动的关联
- LINUX I2C设备驱动的编写方法
- I2C设备驱动的编写(一)
- I2C设备驱动的编写(二)
- I2C设备驱动的编写(二)
- I2C设备驱动的编写(一)
- I2C设备驱动的编写(一) .
- I2C设备驱动的编写(二)
- I2C设备驱动的编写(二)
- I2C设备驱动的编写(一)
- I2C设备与驱动的关联
- I2C设备驱动的编写(一)
- I2C设备驱动的编写(二)
- 在内核里写i2c设备驱动的两种方式
- C#连接mysql的两种方法
- 论文相关名词解释
- Geos编译方法详谈(Release版本)
- WDK驱动开发中WCSSTR导致的蓝屏
- 练习1.1.5
- newstyle方式的i2c设备驱动
- JspFragment类
- 多线程的那些事(之数据同步)
- 黑马程序员 交换数组中的元素
- Shell && vs || operator
- 练习1.1.6
- CSS @规则(at-rules)
- mysql索引优化
- 练习1.1.7