在IIC驱动(一)中,我们初步分析了需要移植部分的代码,当然还留下了不少未解之谜,为了把这些问题给弄清楚,所以本部分我们分析一下I2C-CORE.C的代码。
分析之前先看一下I2C驱动的结构图:
一条I2C线上可以挂很多个I2C设备,每一条I2C线对应一个适配器(Adapter),每一个I2C设备对应一个Client。
简单点理解,adapter就是一个集合,里面包含了多个client。
分析完这个文件之后,发现这里文件中又运用了以下几个新的知识点:
1、 completion
2、 IDR。
3、 Linux设备模型
分析完这份文件之后,又产出了一个新的问题:algo是怎么挂到适配器上的?
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
struct i2c_devinfo {
struct list_head list;
int busnum;
struct i2c_board_info board_info;
};
static LIST_HEAD(adapters); //初始化链表adapters(I2C适配器)
static LIST_HEAD(drivers); //初始化链表drivers(设备)
static DEFINE_MUTEX(core_lists); //初始化互斥锁core_lists
static DEFINE_IDR(i2c_adapter_idr); //IDR,暂时没有深入研究,先忽略,用的时候再说
//检查结构体中,probe和remove成员是否被设置(新风格这两个函数被设置)
#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
先看两个宏:
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
static int i2c_device_match(
struct device *dev,
struct device_driver *drv)
{
//根据dev,获取该dev所在的i2c_client结构体
//struct i2c_client {… struct device dev; …}
struct i2c_client *client = to_i2c_client(dev);
//根据drv获取i2c_driver结构体
//struct i2c_driver {… struct device_driver driver; …}
struct i2c_driver *driver = to_i2c_driver(drv);
//不是新的风格的驱动,直接返回
if (!is_newstyle_driver(driver))
return 0;
//新风格的驱动要比较设备名
return strcmp(client->driver_name, drv->name) == 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//热插拔检测
//这个函数分析有点不清楚
static int i2c_device_uevent(
struct device *dev,
struct kobj_uevent_env *env)
{
struct i2c_client *client = to_i2c_client(dev);
//设备有驱动,但 无驱名,不需要检测
if (dev->driver || !client->driver_name)
return 0;
if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
return -ENOMEM;
dev_dbg(dev, "uevent\n");
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
新风格中用到的探测函数
static int i2c_device_probe(struct device *dev)
{
//根据设备获取对应的结构体
struct i2c_client *client = to_i2c_client(dev);
struct i2c_driver *driver = to_i2c_driver(dev->driver);
//如果没有probe函数,返回错误
if (!driver->probe)
return -ENODEV;
//关联上驱动
client->driver = driver;
dev_dbg(dev, "probe\n");
return driver->probe(client); //执行探测功能
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
新风格中用到的remove函数
static int i2c_device_remove(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_driver *driver;
int status;
//设备没有关联上驱动
if (!dev->driver)
return 0;
driver = to_i2c_driver(dev->driver);
if (driver->remove) { //如果驱动有指定remove函数,则执行
dev_dbg(dev, "remove\n");
status = driver->remove(client);
} else { //如果驱动没有关联remove函数,则将设备的驱动直接挂空
dev->driver = NULL;
status = 0;
}
//status为0,client没有挂驱动
if (status == 0)
client->driver = NULL;
return status;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static void i2c_device_shutdown(struct device *dev)
{
struct i2c_driver *driver;
if (!dev->driver)
return;
driver = to_i2c_driver(dev->driver);
if (driver->shutdown)
driver->shutdown(to_i2c_client(dev));
}
i2c_device_suspend
i2c_device_resume
以上几个函数的结构都是类似的,从传入参数中获取参数所在的结构体,然后执行具体设备指定的函数
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static void i2c_client_release(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
complete(&client->released);
}
//释放设备
static void i2c_client_dev_release(struct device *dev)
{
kfree(to_i2c_client(dev));
}
显示设备的name
show_client_name
显示设备对应的驱动的name
show_modalias
//定义一个数组,用途不明,后面用到时再看
//看变量名应该是设备属性
static struct device_attribute i2c_dev_attrs[]
//最后,定义一个总线变量,将刚才的函数操作都归类进去
static struct bus_type i2c_bus_type = {
.name = "i2c",
.dev_attrs = i2c_dev_attrs,
.match = i2c_device_match,
.uevent = i2c_device_uevent,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.suspend = i2c_device_suspend,
.resume = i2c_device_resume,
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//新建一个I2C设备的client(一个client表示一个设备端)
struct i2c_client *i2c_new_device(
struct i2c_adapter *adap, //适配器
struct i2c_board_info const *info) //板子属性
{
struct i2c_client *client;
int status;
//申请一块内存,用于保存一个I2C设备的client
client = kzalloc(sizeof *client, GFP_KERNEL);
if (!client)
return NULL;
client->adapter = adap; //关联上适配器
client->dev.platform_data = info->platform_data;
device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);
client->flags = info->flags & ~I2C_CLIENT_WAKE;
client->addr = info->addr;
client->irq = info->irq;
//上面这部分的代码是设置client的一些参数,当然,这些参数的来源目前我们还不知道,先放放
strlcpy(client->driver_name, info->driver_name,
sizeof(client->driver_name));
strlcpy(client->name, info->type, sizeof(client->name));
//探测设备client是否存在
//这个函数在本文件后一点
status = i2c_attach_client(client);
if (status < 0) { //设备不存在,释放内存
kfree(client);
client = NULL;
}
return client;
}
EXPORT_SYMBOL_GPL(i2c_new_device);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//卸载设备
void i2c_unregister_device(struct i2c_client *client)
{
//从设备端中获取适配器和驱动
struct i2c_adapter *adapter = client->adapter;
struct i2c_driver *driver = client->driver;
//驱动存在 但是旧风格的驱动,打印警告并返回
if (driver && !is_newstyle_driver(driver)) {
dev_err(&client->dev, "can't unregister devices "
"with legacy drivers\n");
WARN_ON(1);
return;
}
mutex_lock(&adapter->clist_lock);
list_del(&client->list); //将本client从适配器链表中删除
mutex_unlock(&adapter->clist_lock);
device_unregister(&client->dev); //设备注销
}
EXPORT_SYMBOL_GPL(i2c_unregister_device);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
总线适配器操作
//调用适配器的dev_released函数
static void i2c_adapter_dev_release(struct device *dev)
{
struct i2c_adapter *adap = to_i2c_adapter(dev);
complete(&adap->dev_released);
//唤醒complete(complete是一种同步机制)
//这里应该是唤醒adap->dev_released函数
}
显示适配器名
static ssize_t show_adapter_name(
struct device *dev, //设备
struct device_attribute *attr, //设备属性
char *buf) //缓存
{
struct i2c_adapter *adap = to_i2c_adapter(dev);
return sprintf(buf, "%s\n", adap->name);
}
static struct device_attribute i2c_adapter_attrs[] = {
__ATTR(name, S_IRUGO, show_adapter_name, NULL),
{ },
};
//设置适配器关联函数
static struct class i2c_adapter_class = {
.owner = THIS_MODULE,
.name = "i2c-adapter",
.dev_attrs = i2c_adapter_attrs,
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//扫描板子上静态的I2C设备
//这个函数应该是扫描板子上已知的I2C设备,所以是静态扫描
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
struct i2c_devinfo *devinfo;
mutex_lock(&__i2c_board_lock); //互斥锁
//遍历链表头为__i2c_board_list的链表,取出devinfo成员
//devinfo->list是该设备在__i2c_board_list中的成员
list_for_each_entry(devinfo, &__i2c_board_list, list) {
//注意,这里有一个C的基础知识,在这个if语句里面,只有第一个条件满足了,才会执行第二个条件的判断,也就是说,只有nr与busnum匹配了,才会执行i2c_new_device函数
if (devinfo->busnum == adapter->nr //适配器的nr和设备信息匹配
&& !i2c_new_device(adapter, &devinfo->board_info)) //新建一个设备
//出错
printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",
i2c_adapter_id(adapter),
devinfo->board_info.addr);
}
mutex_unlock(&__i2c_board_lock); //解锁
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//注册适配器,同时探测目标板上静态注册的I2C设备和已经注册的I2C设备
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0;
struct list_head *item;
struct i2c_driver *driver;
mutex_init(&adap->bus_lock);
mutex_init(&adap->clist_lock); //两个互斥锁
INIT_LIST_HEAD(&adap->clients); //初始化clients链表
mutex_lock(&core_lists); //上锁(文件头初始化该锁)
list_add_tail(&adap->list, &adapters); //将adap->list加入到适配器链表中
//如果适配器父节点为空
if (adap->dev.parent == NULL) {
//platform_bus定义在drivers/base/Platform.c中
adap->dev.parent = &platform_bus; //将适配器挂上设备总线
pr_debug("I2C adapter driver [%s] forgot to specify "
"physical device\n", adap->name);
}
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); //显示适配器的nr(序号)
//给适配器关联上操作对象:release函数和类(名字和属性,前文有分析)
adap->dev.release = &i2c_adapter_dev_release;
adap->dev.class = &i2c_adapter_class;
res = device_register(&adap->dev); //将适配器设备注册进内核
if (res)
goto out_list; //出错
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
/* create pre-declared device nodes for new-style drivers */
//__i2c_first_dynamic_bus_num是一个分界线,小于该值的,说明是目标板上的静态I2C设备(drivers\i2c\i2c-boardinfo.c中i2c_register_board_info函数下有对应的代码操作这个变量)
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap); //是板上的设备,用静态扫描的方法注册
/* let legacy drivers scan this bus for matching devices */
//这里是执行旧方法注册的I2C设备的探测函数
//遍历drivers链表,依次取出他的成员
list_for_each(item, &drivers) {
//取出item所在的i2c_driver结构体指针
driver = list_entry(item, struct i2c_driver, list);
if (driver->attach_adapter)
driver->attach_adapter(adap); //如果该驱动有指定attach_adapter,则执行他
}
out_unlock:
mutex_unlock(&core_lists); //解锁
return res;
//适配器设备注册失败,直接到这里
out_list:
list_del(&adap->list); //从adapters链表中将本适配器删除
idr_remove(&i2c_adapter_idr, adap->nr); //在添加adapter函数中有申请一个IDR号,所以这里要释放(见i2c_add_adapter函数)
goto out_unlock;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//添加一个适配器
int i2c_add_adapter(struct i2c_adapter *adapter)
{
int id, res = 0;
retry:
//获取一个IDR号(这也解释了为什么上一个函数注册adapter失败后要idr_remove了)
//简单用SI关联了一下这个函数的实现,他是用kmem_cache_alloc申请了一块内存,失败则返回0
if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
return -ENOMEM;
//这里COPY网上的一段描述:在这里涉及到一个idr结构.idr结构本来是为了配合page cache中的radix tree而设计的.在这里我们只需要知道,它是一种高效的搜索树,且这个树预先存放了一些内存.避免在内存不够的时候出现问题.所在,在往idr中插入结构的时候,首先要调用idr_pre_get()为它预留足够的空闲内存,然后再调用idr_get_new_above()将结构插入idr中,该函数以参数的形式返回一个id.以后凭这个id就可以在idr中找到相对应的结构了
//注意一下idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id)的参数的含义,它是将adapter结构插入到i2c_adapter_idr中,存放位置的id必须要大于或者等于__i2c_first_dynamic_bus_num
mutex_lock(&core_lists);
/* "above" here means "above or equal to", sigh */
res = idr_get_new_above(&i2c_adapter_idr, adapter,
__i2c_first_dynamic_bus_num, &id);
mutex_unlock(&core_lists);
//出错处理
if (res < 0) {
if (res == -EAGAIN)
goto retry;
return res;
}
//将idr_get_new_above获得的ID号放入adapter->nr中
//从这个函数的操作可以知道,这时候,nr>=__i2c_first_dynamic_bus_num
adapter->nr = id;
//注册适配器,有了上面的保证,这里注册的适配器不会去搜索板上的静态I2C设备
return i2c_register_adapter(adapter);
}
EXPORT_SYMBOL(i2c_add_adapter);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
添加一个适配器
这个函数和i2c_add_adapter的驱动在于,i2c_add_adapter保证了适配器的nr大于目标板的静态nr,从而不扫描目标板上的静态I2C设备,而这个函数是从输入adap的nr开始分配新的nr
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
int id;
int status;
if (adap->nr & ~MAX_ID_MASK)
return -EINVAL;
retry:
//为IDR分配内存
if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
return -ENOMEM;
//我们先来看下idr_get_new_above的原型
//int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
// idp: 之前通过idr_init初始化的idr指针
//id: 由内核自动分配的ID号
//ptr: 和ID号相关联的指针
//start_id: 起始ID号.内核在分配ID号时,会从start_id开始
mutex_lock(&core_lists);
status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
if (status == 0 && id != adap->nr) {
status = -EBUSY;
idr_remove(&i2c_adapter_idr, id);
}
mutex_unlock(&core_lists);
if (status == -EAGAIN)
goto retry;
if (status == 0)
status = i2c_register_adapter(adap); //注册设备
return status;
}
EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
删除适配器
int i2c_del_adapter(struct i2c_adapter *adap)
{
struct list_head *item, *_n;
struct i2c_adapter *adap_from_list;
struct i2c_driver *driver;
struct i2c_client *client;
int res = 0;
mutex_lock(&core_lists);
/* First make sure that this adapter was ever added */
//从adapters链表中找到指定的适配器
list_for_each_entry(adap_from_list, &adapters, list) {
if (adap_from_list == adap)
break;
}
//没有找到适配器
if (adap_from_list != adap) {
pr_debug("i2c-core: attempting to delete unregistered "
"adapter [%s]\n", adap->name);
res = -EINVAL;
goto out_unlock;
}
//从drivers列表中提取每一个list_head成员(主要是执行驱动的detach_adapter函数)
//而实际上,至少在ds1337上,是没指定这个函数的
list_for_each(item, &drivers) {
//取出item成员所在的宿主结构体
driver = list_entry(item, struct i2c_driver, list);
//如果驱动的detach_adapter成员有设置,则执行他
if (driver->detach_adapter)
if ((res = driver->detach_adapter(adap))) {
dev_err(&adap->dev, "detach_adapter failed "
"for driver [%s]\n",
driver->driver.name);
goto out_unlock;
}
}
//_n = item->next
//遍历挂在适配器adap上的所有clients
//新风格的驱动,卸载设备
//旧风格的驱动,执行驱动的detach_client函数
list_for_each_safe(item, _n, &adap->clients) {
struct i2c_driver *driver;
//获取item所在的i2c_client宿主
client = list_entry(item, struct i2c_client, list);
driver = client->driver; //获取client的驱动
//驱动不存在,或者是新风格的驱动
if (!driver || is_newstyle_driver(driver)) {
//从适配器上卸载本client,函数的实现在前文有分析,主要步骤是断开client->list的链表连接,并卸载client->dev(device_unregister())
i2c_unregister_device(client);
continue;
}
//运行到这里,说明驱动存在,且为旧风格的驱动
if ((res = driver->detach_client(client))) { //执行驱动的detach_client函数
dev_err(&adap->dev, "detach_client failed for client "
"[%s] at address 0x%02x\n", client->name,
client->addr);
goto out_unlock;
}
}
/* clean up the sysfs representation */
init_completion(&adap->dev_released); //初始化completion同步机制
device_unregister(&adap->dev); //将适配器设备卸载
list_del(&adap->list); //将本适配器从adapters链表中断开
/* wait for sysfs to drop all references */
//等待文件系统调用本适配器的release函数
wait_for_completion(&adap->dev_released);
/* free bus id */
//释放本适配器占用的IDR结构内存(i2c_add_adapter添加adapter时申请,在注册失败的时候也会idr_remove)
idr_remove(&i2c_adapter_idr, adap->nr);
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
//没有找到适配器,直接到这里
out_unlock:
mutex_unlock(&core_lists);
return res;
}
EXPORT_SYMBOL(i2c_del_adapter);
程序分析到这里,我们基本已经可以理清楚I2C驱动的结构了。
S3C2440的I2C总线上有一个adapters链表,而目标板上的I2C设备,则是按功能分为一个个adapter,每增加一个adapter,则执行以下操作:
1、 申请一个IDR用于快速的找到本adapter。
2、 将adapter作为一个设备注册到内核中
3、 将adapter挂载到adapters链表上
然后新增一个I2C设备时,相当于新加了一个client,这时候要执行以下操作:
1、 为client关联上这个设备的驱动操作函数,以及适配器
2、 将client关联到父adapter的clients链表中。
所以卸载适配器的时候,就执行了以下操作:
1、 在adapters中遍历,找到要删除的adapter。
2、 从驱动链表drivers中遍历所有的驱动,执行驱动关联的detach_adapter函数。一般这个函数没有关联,而参数adapter则是传递父adapter给detach_adapter,这个应该是作为本函数是否执行的一个依据。
3、 遍历adapter的clients链表,找出挂在本adapter下的所有设备,然后卸载他们。
4、 等待文件系统调用release函数来最后释放适配器(也就是说,在文件系统调用release之前,本adapter只是处于僵死状态)
5、 卸载adapter设备并释放IDR内存
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
I2C驱动注册,在I2C设备注册时调用
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
//驱动检查,因为新旧两种风格只能指定一种
//新风格只需要指定probe和remove
if (is_newstyle_driver(driver)) {
if (driver->attach_adapter || driver->detach_adapter
|| driver->detach_client) {
printk(KERN_WARNING
"i2c-core: driver [%s] is confused\n",
driver->driver.name);
return -EINVAL;
}
}
/* add the driver to the list of i2c drivers in the driver core */
//这部分代码是给新风格的驱动注册用的
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type; //i2c_bus_type关联了I2C总线支持的操作函数
//注册驱动
res = driver_register(&driver->driver);
if (res)
return res;
mutex_lock(&core_lists);
list_add_tail(&driver->list, &drivers); //将驱动挂载到drivers驱动链表上
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
//这个操作是旧风格的驱动注册
if (driver->attach_adapter) { //如果适配器的探测函数存在
struct i2c_adapter *adapter;
//从适配器链表adapters中取出每一个适配器
list_for_each_entry(adapter, &adapters, list) {
//调用探测函数
//从这里可以看出,这个函数的作用是探测驱动属于哪一个适配器的
driver->attach_adapter(adapter);
}
}
mutex_unlock(&core_lists);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
删除驱动,卸载时调用
void i2c_del_driver(struct i2c_driver *driver)
{
struct list_head *item1, *item2, *_n;
struct i2c_client *client;
struct i2c_adapter *adap;
mutex_lock(&core_lists);
//新风格驱动的处理
if (is_newstyle_driver(driver))
goto unregister;
//旧风格驱动的处理
list_for_each(item1, &adapters) {
//从适配器链表中获取每一个适配器
adap = list_entry(item1, struct i2c_adapter, list);
//调用卸载适配器探测(至少DS1337驱动上没有挂载这个函数的实现)
if (driver->detach_adapter) {
if (driver->detach_adapter(adap)) {
dev_err(&adap->dev, "detach_adapter failed "
"for driver [%s]\n",
driver->driver.name);
}
} else {
//如果没有detach_adapter函数,则从适配器的clients链表中找驱动
list_for_each_safe(item2, _n, &adap->clients) {
client = list_entry(item2, struct i2c_client, list);
if (client->driver != driver)
continue; //不是指定的驱动,下一个
//找到指定的驱动(其实主要是找这个驱动的宿主client)
dev_dbg(&adap->dev, "detaching client [%s] "
"at 0x%02x\n", client->name,
client->addr);
//执行detach_client函数
if (driver->detach_client(client)) {
dev_err(&adap->dev, "detach_client "
"failed for client [%s] at "
"0x%02x\n", client->name,
client->addr);
}
}
}
}
//新风格时直接到这里
unregister:
driver_unregister(&driver->driver); //卸载驱动
list_del(&driver->list); //将驱动从drivers链表中删除
pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
mutex_unlock(&core_lists);
}
EXPORT_SYMBOL(i2c_del_driver);
看完这个函数,有点小疯,难怪要更改新的风格呢,按旧风格的做法,卸载的效率太低了。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
这个函数是检查适配器adapter中是否已经存在地址为addr的设备。不存在则返回0
static int __i2c_check_addr(
struct i2c_adapter *adapter,
unsigned int addr)
{
struct list_head *item;
struct i2c_client *client;
//遍历适配器的clients链表,取出他的每一个设备
list_for_each(item, &adapter->clients) {
client = list_entry(item, struct i2c_client, list); //获取设备的宿主client
if (client->addr == addr)
return -EBUSY; //找到设备地址相同的设备,错误返回
}
return 0;
}
这个是上一个函数的对外接口
static int i2c_check_addr(
struct i2c_adapter *adapter,
int addr)
{
int rval;
mutex_lock(&adapter->clist_lock);
rval = __i2c_check_addr(adapter, addr);
mutex_unlock(&adapter->clist_lock);
return rval;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
检测设备的client,其核心操作就是将设备的client挂载到宿主adapter的clients链表上
int i2c_attach_client(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter; //获取设备的宿主适配器
int res = 0;
mutex_lock(&adapter->clist_lock);
//检查设备地址是否已经存在于适配器中
//如果已经存在则直接返回错误
//如果地址不冲突,则将新的设备client加入到适配器的clients链表中
if (__i2c_check_addr(client->adapter, client->addr)) {
res = -EBUSY;
goto out_unlock;
}
list_add_tail(&client->list,&adapter->clients);
client->usage_count = 0; //本设备的使用者计数(好象没用到)
client->dev.parent = &client->adapter->dev; //本设备的宿主设备=适配器设备
client->dev.bus = &i2c_bus_type; //复制设备的I2C总线支持(主要是I2C支持的公用操作)
if (client->driver)
client->dev.driver = &client->driver->driver;
//这个地方要返回到ds1337的文件里看驱动结构体的定义才行,不然会晕
//实际上,driver->driver里面只有一个.name成员用来标记驱动的名字
//关联上release操作函数
if (client->driver && !is_newstyle_driver(client->driver)) {
client->dev.release = i2c_client_release; //关联上release函数
client->dev.uevent_suppress = 1;
} else
client->dev.release = i2c_client_dev_release;
snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
"%d-%04x", i2c_adapter_id(adapter), client->addr);
dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
client->name, client->dev.bus_id);
//将client设备注册
res = device_register(&client->dev);
if (res)
goto out_list; //注册失败
mutex_unlock(&adapter->clist_lock);
//如果adapter中有指定client_register函数,则执行
//实际上,到目前为止,暂时没有看到这个函数有被指定
if (adapter->client_register) {
if (adapter->client_register(client)) {
dev_dbg(&adapter->dev, "client_register "
"failed for client [%s] at 0x%02x\n",
client->name, client->addr);
}
}
return 0;
//client设备注册失败,直接到这里
out_list:
list_del(&client->list); //将自己从adapter->clients链表中断开
dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
"(%d)\n", client->name, client->addr, res);
//适配器中已经有相同地址的设备时候直接进入这里
out_unlock:
mutex_unlock(&adapter->clist_lock);
return res;
}
EXPORT_SYMBOL(i2c_attach_client);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//卸载驱动时会调用这个函数
int i2c_detach_client(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
int res = 0;
//如果使用者不为0,警告设备仍然被使用
if (client->usage_count > 0) {
dev_warn(&client->dev, "Client [%s] still busy, "
"can't detach\n", client->name);
return -EBUSY;
}
//如果适配器上有这个函数指定,则执行他
//实际到目前为止,还未看到这个函数的挂载
if (adapter->client_unregister) {
res = adapter->client_unregister(client);
if (res) {
dev_err(&client->dev,
"client_unregister [%s] failed, "
"client not detached\n", client->name);
goto out;
}
}
//断开client在适配器上的链接
//设备卸载
//等待文件系统调用released函数
mutex_lock(&adapter->clist_lock);
list_del(&client->list);
init_completion(&client->released);
device_unregister(&client->dev);
mutex_unlock(&adapter->clist_lock);
wait_for_completion(&client->released);
out:
return res;
}
EXPORT_SYMBOL(i2c_detach_client);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//增加驱动的引用计数
int i2c_use_client(struct i2c_client *client)
{
int ret;
//这里调用try_module_get来检测模块是否被插入内核
ret = i2c_inc_use_client(client);
if (ret)
return ret;
client->usage_count++;
return 0;
}
EXPORT_SYMBOL(i2c_use_client);
//减少驱动的引用计数
int i2c_release_client(struct i2c_client *client)
{
if (!client->usage_count) {
pr_debug("i2c-core: %s used one too many times\n",
__FUNCTION__);
return -EPERM;
}
client->usage_count--;
i2c_dec_use_client(client);
return 0;
}
EXPORT_SYMBOL(i2c_release_client);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
执行适配器中,设备驱动所支持的”.command”函数
void i2c_clients_command(
struct i2c_adapter *adap,
unsigned int cmd,
void *arg)
{
struct list_head *item;
struct i2c_client *client;
mutex_lock(&adap->clist_lock);
list_for_each(item, &adap->clients) {
client = list_entry(item, struct i2c_client, list); //获取设备的client结构体
//如果模块没有被插入内核,则这里返回0
if (!try_module_get(client->driver->driver.owner))
continue;
//驱动的”.command”成员不为空
if (NULL != client->driver->command) {
mutex_unlock(&adap->clist_lock);
client->driver->command(client,cmd,arg); //执行命令
mutex_lock(&adap->clist_lock);
}
//这里发现一个问题,command是对该适配器的每一个client发出的,如果两个client的cmd参数冲突,那么其中一个就会被误执行,所以写命令参数的时候,要注意避免冲突
module_put(client->driver->driver.owner);
}
mutex_unlock(&adap->clist_lock);
}
EXPORT_SYMBOL(i2c_clients_command);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static int __init i2c_init(void)
{
int retval;
retval = bus_register(&i2c_bus_type); //注册I2C总线
if (retval)
return retval;
return class_register(&i2c_adapter_class); //类注册
}
static void __exit i2c_exit(void)
{
class_unregister(&i2c_adapter_class);
bus_unregister(&i2c_bus_type); //卸载总线和类
}
subsys_initcall(i2c_init);
module_exit(i2c_exit);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
这里有个疑问,adapter->algo是什么时候给挂上去的?
//数据的通讯,主要是调用了adap->algo->master_xfer函数
int i2c_transfer(
struct i2c_adapter * adap,
struct i2c_msg *msgs,
int num)
{
int ret;
if (adap->algo->master_xfer) {
mutex_lock_nested(&adap->bus_lock, adap->level);
ret = adap->algo->master_xfer(adap,msgs,num);
mutex_unlock(&adap->bus_lock);
return ret;
} else {
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
return -ENOSYS;
}
}
EXPORT_SYMBOL(i2c_transfer);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
这里调用了i2c_transfer
int i2c_master_send(
struct i2c_client *client,
const char *buf ,
int count)
{
int ret;
struct i2c_adapter *adap=client->adapter; //获取设备的宿主适配器
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
ret = i2c_transfer(adap, &msg, 1);
return (ret == 1) ? count : ret;
}
EXPORT_SYMBOL(i2c_master_send);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
int i2c_master_recv(
struct i2c_client *client,
char *buf ,
int count)
{
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
int ret;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.flags |= I2C_M_RD;
msg.len = count;
msg.buf = buf;
ret = i2c_transfer(adap, &msg, 1);
return (ret == 1) ? count : ret;
}
EXPORT_SYMBOL(i2c_master_recv);
小结:
i2c_master_send
i2c_master_recv
这两个函数都是调用了i2c_transfer来进行最终的数据操作,而send和recv函数几乎是一样的,唯一的区别在于对msg.flag的设置,所以我们现在虽然还没有具体分析i2c_transfer中核心函数master_xfer的实现方法,但是从这里基本可以猜测出,msg的作用——设置I2C SMBUS的读写方式。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//在适配器中检查地址为addr的设备是否存在。(主要是靠是否返回ACK判断)
//核心函数为i2c_smbus_xfer
static int i2c_probe_address(
struct i2c_adapter *adapter,
int addr,
int kind,
int (*found_proc) (struct i2c_adapter *, int, int))
{
int err;
//检查I2C设备地址有效
if (addr < 0x03 || addr > 0x77) {
dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
addr);
return -EINVAL;
}
//检查设备地址addr是否已经在适配器中
if (i2c_check_addr(adapter, addr))
return 0;
//类型(kind)未知
//i2c_smbus_xfer应该是实际操作I2C时序的实现函数,这里用来探测I2C设备有没有返回ACK
if (kind < 0) {
if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
I2C_SMBUS_QUICK, NULL) < 0)
return 0;
//如果地址是0x5x,再检查一次
if ((addr & ~0x0f) == 0x50)
i2c_smbus_xfer(adapter, addr, 0, 0, 0,
I2C_SMBUS_QUICK, NULL);
}
//运行到这里,说明已经找到了设备(至少I2C有回ACK),调用设备传进来的回调函数found_proc
err = found_proc(adapter, addr, kind);
//出错的处理
if (err == -ENODEV)
err = 0;
if (err)
dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
addr, err);
return err;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//探测函数,IIC驱动(一)的时候已经分析过这个函数了,这里就不重新COPY了
int i2c_probe(
struct i2c_adapter *adapter,
struct i2c_client_address_data *address_data,
int (*found_proc) (struct i2c_adapter *, int, int))
{
return 0;
}
EXPORT_SYMBOL(i2c_probe);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//探测是否有新的I2C设备,探测目标设备的地址写在addr_list中
struct i2c_client *i2c_new_probed_device(
struct i2c_adapter *adap,
struct i2c_board_info *info,
unsigned short const *addr_list)
{
int i;
//检测adapter是否支持这个函数
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) {
dev_err(&adap->dev, "Probing not supported\n");
return NULL;
}
mutex_lock(&adap->clist_lock);
for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
//检测地址有效
if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
dev_warn(&adap->dev, "Invalid 7-bit address "
"0x%02x\n", addr_list[i]);
continue;
}
//检测地址是否已存在
if (__i2c_check_addr(adap, addr_list[i])) {
dev_dbg(&adap->dev, "Address 0x%02x already in "
"use, not probing\n", addr_list[i]);
continue;
}
//核心代码
if ((addr_list[i] & ~0x07) == 0x30
|| (addr_list[i] & ~0x0f) == 0x50
|| !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) {
if (i2c_smbus_xfer(adap, addr_list[i], 0,
I2C_SMBUS_READ, 0,
I2C_SMBUS_BYTE, NULL) >= 0)
break;
} else {
if (i2c_smbus_xfer(adap, addr_list[i], 0,
I2C_SMBUS_WRITE, 0,
I2C_SMBUS_QUICK, NULL) >= 0)
break;
}
}
mutex_unlock(&adap->clist_lock);
if (addr_list[i] == I2C_CLIENT_END) {
dev_dbg(&adap->dev, "Probing failed, no device found\n");
return NULL;
}
info->addr = addr_list[i];
return i2c_new_device(adap, info); //新建一个设备
}
EXPORT_SYMBOL_GPL(i2c_new_probed_device);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据ID号取出对应的adapter
struct i2c_adapter* i2c_get_adapter(int id)
{
struct i2c_adapter *adapter;
mutex_lock(&core_lists);
adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
if (adapter && !try_module_get(adapter->owner))
adapter = NULL;
mutex_unlock(&core_lists);
return adapter;
}
EXPORT_SYMBOL(i2c_get_adapter);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void i2c_put_adapter(struct i2c_adapter *adap)
{
module_put(adap->owner);
}
EXPORT_SYMBOL(i2c_put_adapter);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
SMBUS操作部分
//计算data的crc8值
//关于CRC算法,可以BAIDU相关资料,或看我STM32笔记的第0章,里面有具体介绍
#define POLY (0x1070U << 3)
static u8 crc8(u16 data)
{
int i;
for(i = 0; i < 8; i++) {
if (data & 0x8000)
data = data ^ POLY;
data = data << 1;
}
return (u8)(data >> 8);
}
//连续的CRC计算
static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
{
int i;
for(i = 0; i < count; i++)
crc = crc8((crc ^ p[i]) << 8);
return crc;
}
//计算msg中数据的CRC值(含设备地址)
static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
{
//这里是设置第一个字节: addr<<1 | 读写标记(1-读,0-写)
u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD);
pec = i2c_smbus_pec(pec, &addr, 1); //计算一次crc
return i2c_smbus_pec(pec, msg->buf, msg->len);
}
//将上面函数计算好的CRC值添加进帧(pec)中
static inline void i2c_smbus_add_pec(struct i2c_msg *msg)
{
msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg);
msg->len++;
}
这一组函数看到这里,基本是明白了作者想干什么了——就是给I2C通讯的数据里面加一个字节的校验位,来保证传输数据的可靠。
//不出所料,这个函数就用来检查CRC是否一致了
static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
{
u8 rpec = msg->buf[--msg->len]; //取最后一个字节(CRC字节)
cpec = i2c_smbus_msg_pec(cpec, msg); //计算msg中的crc
//比较crc是否一致
if (rpec != cpec) {
pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",
rpec, cpec);
return -1;
}
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
以下这组函数,实际都是调用i2c_smbus_xfer来实现I2C的实际物理操作,只是不同的函数,传递进i2c_smbus_xfer的参数不一样而已。
s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value)
s32 i2c_smbus_read_byte(struct i2c_client *client)
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values)
s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
u8 length, const u8 *values)
s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command,
u8 length, u8 *values)
s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
u8 length, const u8 *values)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
分析这个函数之前,我们先来看一个结构体:
#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
union i2c_smbus_data {
__u8 byte;
__u16 word;
__u8 block[I2C_SMBUS_BLOCK_MAX + 2];
/* block[0] is used for length */
/* and one more for user-space compatibility */
};
s32 i2c_smbus_xfer(
struct i2c_adapter * adapter, //适配器
u16 addr, //I2C设备地址
unsigned short flags, //操作标记
char read_write, //读/写
u8 command, //
int size, //操作字节大小
union i2c_smbus_data * data) //数据指针
{
s32 res;
//只保留这两个标记位
flags &= I2C_M_TEN | I2C_CLIENT_PEC;
if (adapter->algo->smbus_xfer) {
//适配器smbus_xfer函数存在,执行适配器的smbus_xfer函数
mutex_lock(&adapter->bus_lock);
res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
command,size,data);
mutex_unlock(&adapter->bus_lock);
} else //函数不存在,直接透传下去
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
command,size,data);
return res;
}
EXPORT_SYMBOL(i2c_smbus_xfer);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static s32 i2c_smbus_xfer_emulated(
struct i2c_adapter * adapter, //适配器
u16 addr, //I2C设备地址
unsigned short flags, //操作标记
char read_write, //读写
u8 command, //命令(寄存器地址)
int size, //操作几个字节
union i2c_smbus_data * data) //操作数据
{
unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
int num = read_write == I2C_SMBUS_READ?2:1; //读为2,写为1
struct i2c_msg msg[2] = {
//地址,标记,长度,缓存
{ addr, flags, 1, msgbuf0 }, //写操作字节
{ addr, flags | I2C_M_RD, 0, msgbuf1 } //读操作字节
};
int i;
u8 partial_pec = 0;
msgbuf0[0] = command; //写操作的第一个字节为命令(寄存器地址)
switch(size) {
case I2C_SMBUS_QUICK: //0
msg[0].len = 0; //写长度为0
//是否加读属性
msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
num = 1; //操作为写
break;
case I2C_SMBUS_BYTE: //1
if (read_write == I2C_SMBUS_READ) {
msg[0].flags = I2C_M_RD | flags; //加读属性
num = 1; //操作为写
}
break;
case I2C_SMBUS_BYTE_DATA: //2
if (read_write == I2C_SMBUS_READ)
//读操作,长度为1(第一个字节为command),不理解的话参考一下I2C通讯协议的读操作时序
msg[1].len = 1;
else {
msg[0].len = 2; //写操作,长度为2
msgbuf0[1] = data->byte; //要写的数据
}
break;
case I2C_SMBUS_WORD_DATA: //3
if (read_write == I2C_SMBUS_READ)
msg[1].len = 2; //读操作,长度为2
else {
msg[0].len=3; //写操作,长度为3,设置要写的数据
msgbuf0[1] = data->word & 0xff;
msgbuf0[2] = data->word >> 8;
}
break;
case I2C_SMBUS_PROC_CALL: //4
num = 2; //特殊操作,固定为读
read_write = I2C_SMBUS_READ; //读写属性改为读
msg[0].len = 3; //写操作长度为3
msg[1].len = 2; //读操作长度为2
msgbuf0[1] = data->word & 0xff;
msgbuf0[2] = data->word >> 8; //要写的数据
break;
case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1; //读长度
} else {
msg[0].len = data->block[0] + 2; //写长度(多加上目标地址)
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
dev_err(&adapter->dev, "smbus_access called with "
"invalid block write size (%d)\n",
data->block[0]);
return -1;
}
for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1]; //设置要写的数据
}
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
num = 2; //固定为读
read_write = I2C_SMBUS_READ; //读操作
if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
dev_err(&adapter->dev, "%s called with invalid "
"block proc call size (%d)\n", __FUNCTION__,
data->block[0]);
return -1;
}
msg[0].len = data->block[0] + 2;
for (i = 1; i < msg[0].len; i++)
msgbuf0[i] = data->block[i-1];
msg[1].flags |= I2C_M_RECV_LEN;
msg[1].len = 1;
break;
case I2C_SMBUS_I2C_BLOCK_DATA: //读一块数据
if (read_write == I2C_SMBUS_READ) {
msg[1].len = data->block[0];
} else {
msg[0].len = data->block[0] + 1;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "
"invalid block write size (%d)\n",
data->block[0]);
return -1;
}
for (i = 1; i <= data->block[0]; i++)
msgbuf0[i] = data->block[i];
}
break;
default:
dev_err(&adapter->dev, "smbus_access called with invalid size (%d)\n",
size);
return -1;
}
//带CRC校验标记
//大小不为0(I2C_SMBUS_QUICK)
//大小不为8(I2C_SMBUS_I2C_BLOCK_DATA)
i = ((flags & I2C_CLIENT_PEC)
&& (size != I2C_SMBUS_QUICK)
&& (size != I2C_SMBUS_I2C_BLOCK_DATA));
//以上条件成立(带CRC校验属性)
if (i) {
if (!(msg[0].flags & I2C_M_RD)) { //不带读属性
if (num == 1) /* Write only */
i2c_smbus_add_pec(&msg[0]); //计算CRC校验字节进最后一个字节
else /* Write followed by read */
partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
//返回msg中数据的CRC字节
}
if (msg[num-1].flags & I2C_M_RD) //带读属性,多读一个字节的校验
msg[num-1].len++;
}
//通讯主体
if (i2c_transfer(adapter, msg, num) < 0)
return -1;
/* Check PEC if last message is a read */
if (i && (msg[num-1].flags & I2C_M_RD)) { //带读属性,CRC检查
if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0)
return -1;
}
//读操作,将读到的数据复制到data中
if (read_write == I2C_SMBUS_READ)
switch(size) {
case I2C_SMBUS_BYTE:
data->byte = msgbuf0[0];
break;
case I2C_SMBUS_BYTE_DATA:
data->byte = msgbuf1[0];
break;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < data->block[0]; i++)
data->block[i+1] = msgbuf1[i];
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
for (i = 0; i < msgbuf1[0] + 1; i++)
data->block[i] = msgbuf1[i];
break;
}
return 0;
}