linux i2c子系统代码分析6 ---操作函数i2c数据处理函数
2016-09-05 14:27
746 查看
下面介绍i2c的数据处理函数
1、 i2c_master_send 在主模式下发送一个信息
kernel/driver/linux/i2c/i2c-core.c
/**
* i2c_master_send - issue a single I2C message in master transmit mode
* @client: Handle to slave device
* @buf: Data that will be written to the slave
* @count: How many bytes to write, must be less than 64k since msg.len is u16
*
* Returns negative errno, or else the number of bytes written.
*/
int i2c_master_send(const 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);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
struct i2c_adapter *adap = client->adapter; 获取i2c设备对于适配器
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
以上是给一个i2c消息结构体赋值
i2c_transfer(adap, &msg, 1); i2c执行一个消息,该函数是发送和接收的通用接口函数
2、i2c_master_recv i2c主模式下接收一个消息
kernel/driver/linux/i2c/i2c-core.c
/**
* i2c_master_recv - issue a single I2C message in master receive mode
* @client: Handle to slave device
* @buf: Where to store data read from slave
* @count: How many bytes to read, must be less than 64k since msg.len is u16
*
* Returns negative errno, or else the number of bytes read.
*/
int i2c_master_recv(const 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);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
i2c_adapter *adap = client->adapter; 获取i2c设备适配器
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.flags |= I2C_M_RD;
msg.len = count;
msg.buf = buf;
i2c_transfer(adap, &msg, 1); i2c执行一个消息,该函数是发送和接收的通用接口函数
3、 i2c_transfer
driver/linux/i2c/i2c-core.c
/**
* i2c_transfer - execute a single or combined I2C message
* @adap: Handle to I2C bus
* @msgs: One or more messages to execute before STOP is issued to
* terminate the operation; each message begins with a START.
* @num: Number of messages to be executed.
*
* Returns negative errno, else the number of messages executed.
*
* Note that there is no requirement that each message be sent to
* the same slave address, although that is the most common model.
*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
/* REVISIT the fault reporting model here is weak:
*
* - When we get an error after receiving N bytes from a slave,
* there is no way to report "N".
*
* - When we get a NAK after transmitting N bytes to a slave,
* there is no way to report "N" ... or to let the master
* continue executing the rest of this combined message, if
* that's the appropriate response.
*
* - When for example "num" is two and we successfully complete
* the first message but get an error part way through the
* second, it's unclear whether that should be reported as
* one (discarding status on the second message) or errno
* (discarding status on the first one).
*/
if (adap->algo->master_xfer) {
#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
}
#endif
if (in_atomic() || irqs_disabled()) {
ret = i2c_trylock_adapter(adap);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
i2c_lock_adapter(adap);
}
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
i2c_unlock_adapter(adap);
return ret;
} else {
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
return -EOPNOTSUPP;
}
}
adap->algo->master_xfer 判断适配器算法中是否有传输数据处理函数
for (ret = 0; ret < num; ret++) 调试信息:打印要传输的消息
if (in_atomic() || irqs_disabled()) 判断是否处于原子操作上下文 禁止中断
kernel/include/linux/hardirq.h
/*
* Are we running in atomic context? WARNING: this macro cannot
* always detect atomic context; in particular, it cannot know about
* held spinlocks in non-preemptible kernels. Thus it should not be
* used in the general case to determine whether sleeping is possible.
* Do not use in_atomic() in driver code.
*/
#define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != 0)
查看是否处于原子操作上下文
irqs_disabled 禁止中断
i2c_trylock_adapte 尝试锁上i2c适配器
driver/linux/i2c/i2c-core.c
static int i2c_trylock_adapter(struct
i2c_adapter *adapter)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
if (parent)
return i2c_trylock_adapter(parent);
else
return rt_mutex_trylock(&adapter->bus_lock);
}
i2c_parent_is_i2c_adapter 获取父适配器设备指针
if (parent)
return i2c_trylock_adapter(parent); 一直到适配器最根部父设备才上锁
rt_mutex_trylock(&adapter->bus_lock);
尝试锁上rt_mutex锁
kerenl/kernel/rtmutex.c
/**
* rt_mutex_trylock - try to lock a rt_mutex
*
* @lock: the rt_mutex to be locked
*
* Returns 1 on success and 0 on contention
*/
int __sched rt_mutex_trylock(struct rt_mutex *lock)
{
return rt_mutex_fasttrylock(lock, rt_mutex_slowtrylock);
}
小结: i2c_trylock_adapter尝试锁上i2c适配器-》 rt_mutex_trylock
i2c_lock_adapter(adap); 锁i2c适配器
driver/linux/i2c/i2c-core.c
/**
* i2c_lock_adapter - Get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
*/
void i2c_lock_adapter(struct i2c_adapter *adapter)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
if (parent)
i2c_lock_adapter(parent);
else
rt_mutex_lock(&adapter->bus_lock);
}
i2c_parent_is_i2c_adapter(adapter); 获取父适配器指针
if (parent)
i2c_lock_adapter(parent); 一直找到最根本i2c父设备才上锁
rt_mutex_lock(&adapter->bus_lock); rt_mutex上锁
kerenl/kernel/rtmutex.c
/**
* rt_mutex_lock - lock a rt_mutex
*
* @lock: the rt_mutex to be locked
*/
void __sched rt_mutex_lock(struct rt_mutex *lock)
{
might_sleep();
rt_mutex_fastlock(lock, TASK_UNINTERRUPTIBLE, 0, rt_mutex_slowlock);
}
小结: i2c_lock_adapter锁上i2c适配器-》 rt_mutex_lock
orig_jiffies = jiffies; 获取现在的节拍值,为了后面做时间比较用
for (ret = 0, try = 0; try <= adap->retries; try++)
循环尝试执行信息处理,上限是适配器retries值
adap->algo->master_xfer(adap,
msgs, num); 执行适配器中算法的信息处理函数
北京创新乐知信息技术有限公司
1、 i2c_master_send 在主模式下发送一个信息
kernel/driver/linux/i2c/i2c-core.c
/**
* i2c_master_send - issue a single I2C message in master transmit mode
* @client: Handle to slave device
* @buf: Data that will be written to the slave
* @count: How many bytes to write, must be less than 64k since msg.len is u16
*
* Returns negative errno, or else the number of bytes written.
*/
int i2c_master_send(const 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);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
struct i2c_adapter *adap = client->adapter; 获取i2c设备对于适配器
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
以上是给一个i2c消息结构体赋值
i2c_transfer(adap, &msg, 1); i2c执行一个消息,该函数是发送和接收的通用接口函数
2、i2c_master_recv i2c主模式下接收一个消息
kernel/driver/linux/i2c/i2c-core.c
/**
* i2c_master_recv - issue a single I2C message in master receive mode
* @client: Handle to slave device
* @buf: Where to store data read from slave
* @count: How many bytes to read, must be less than 64k since msg.len is u16
*
* Returns negative errno, or else the number of bytes read.
*/
int i2c_master_recv(const 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);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
i2c_adapter *adap = client->adapter; 获取i2c设备适配器
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.flags |= I2C_M_RD;
msg.len = count;
msg.buf = buf;
i2c_transfer(adap, &msg, 1); i2c执行一个消息,该函数是发送和接收的通用接口函数
3、 i2c_transfer
driver/linux/i2c/i2c-core.c
/**
* i2c_transfer - execute a single or combined I2C message
* @adap: Handle to I2C bus
* @msgs: One or more messages to execute before STOP is issued to
* terminate the operation; each message begins with a START.
* @num: Number of messages to be executed.
*
* Returns negative errno, else the number of messages executed.
*
* Note that there is no requirement that each message be sent to
* the same slave address, although that is the most common model.
*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
/* REVISIT the fault reporting model here is weak:
*
* - When we get an error after receiving N bytes from a slave,
* there is no way to report "N".
*
* - When we get a NAK after transmitting N bytes to a slave,
* there is no way to report "N" ... or to let the master
* continue executing the rest of this combined message, if
* that's the appropriate response.
*
* - When for example "num" is two and we successfully complete
* the first message but get an error part way through the
* second, it's unclear whether that should be reported as
* one (discarding status on the second message) or errno
* (discarding status on the first one).
*/
if (adap->algo->master_xfer) {
#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
}
#endif
if (in_atomic() || irqs_disabled()) {
ret = i2c_trylock_adapter(adap);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
i2c_lock_adapter(adap);
}
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
i2c_unlock_adapter(adap);
return ret;
} else {
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
return -EOPNOTSUPP;
}
}
adap->algo->master_xfer 判断适配器算法中是否有传输数据处理函数
for (ret = 0; ret < num; ret++) 调试信息:打印要传输的消息
if (in_atomic() || irqs_disabled()) 判断是否处于原子操作上下文 禁止中断
kernel/include/linux/hardirq.h
/*
* Are we running in atomic context? WARNING: this macro cannot
* always detect atomic context; in particular, it cannot know about
* held spinlocks in non-preemptible kernels. Thus it should not be
* used in the general case to determine whether sleeping is possible.
* Do not use in_atomic() in driver code.
*/
#define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != 0)
查看是否处于原子操作上下文
irqs_disabled 禁止中断
i2c_trylock_adapte 尝试锁上i2c适配器
driver/linux/i2c/i2c-core.c
static int i2c_trylock_adapter(struct
i2c_adapter *adapter)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
if (parent)
return i2c_trylock_adapter(parent);
else
return rt_mutex_trylock(&adapter->bus_lock);
}
i2c_parent_is_i2c_adapter 获取父适配器设备指针
if (parent)
return i2c_trylock_adapter(parent); 一直到适配器最根部父设备才上锁
rt_mutex_trylock(&adapter->bus_lock);
尝试锁上rt_mutex锁
kerenl/kernel/rtmutex.c
/**
* rt_mutex_trylock - try to lock a rt_mutex
*
* @lock: the rt_mutex to be locked
*
* Returns 1 on success and 0 on contention
*/
int __sched rt_mutex_trylock(struct rt_mutex *lock)
{
return rt_mutex_fasttrylock(lock, rt_mutex_slowtrylock);
}
小结: i2c_trylock_adapter尝试锁上i2c适配器-》 rt_mutex_trylock
i2c_lock_adapter(adap); 锁i2c适配器
driver/linux/i2c/i2c-core.c
/**
* i2c_lock_adapter - Get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
*/
void i2c_lock_adapter(struct i2c_adapter *adapter)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
if (parent)
i2c_lock_adapter(parent);
else
rt_mutex_lock(&adapter->bus_lock);
}
i2c_parent_is_i2c_adapter(adapter); 获取父适配器指针
if (parent)
i2c_lock_adapter(parent); 一直找到最根本i2c父设备才上锁
rt_mutex_lock(&adapter->bus_lock); rt_mutex上锁
kerenl/kernel/rtmutex.c
/**
* rt_mutex_lock - lock a rt_mutex
*
* @lock: the rt_mutex to be locked
*/
void __sched rt_mutex_lock(struct rt_mutex *lock)
{
might_sleep();
rt_mutex_fastlock(lock, TASK_UNINTERRUPTIBLE, 0, rt_mutex_slowlock);
}
小结: i2c_lock_adapter锁上i2c适配器-》 rt_mutex_lock
orig_jiffies = jiffies; 获取现在的节拍值,为了后面做时间比较用
for (ret = 0, try = 0; try <= adap->retries; try++)
循环尝试执行信息处理,上限是适配器retries值
adap->algo->master_xfer(adap,
msgs, num); 执行适配器中算法的信息处理函数
北京创新乐知信息技术有限公司
相关文章推荐
- linux i2c子系统代码分析5 ---操作函数i2c_new_device i2c_new_probed_device i2c_register_board_info介绍
- linux i2c子系统代码分析4 ---操作函数i2c_add_driver i2c_register_driver介绍
- linux i2c子系统代码分析3 ---操作函数i2c_add_adapter i2c_add_numbered_adapter介绍
- linux i2c子系统代码分析2 ---操作函数i2c_init介绍
- linux i2c子系统代码分析7 ---i2c适配器注册时机、方法以及例程
- linux i2c子系统代码分析1 ---概述以及主要数据结构
- linux i2c子系统代码分析8 ---i2c子系统内核目录介绍
- linux i2c子系统代码分析9---i2c设备的注册方法
- linux IIC子系统分析(七)——实例分析通过i2c-dev操作I2C设备
- linux input子系统分析--主要函数
- Linux "零拷贝" sendfile函数中文说明及实际操作分析
- Linux I2C子系统分析-I2C设备驱动 2
- linux设备驱动之 i2c设备驱动 at24c08驱动程序分析【全部地址的操作】
- Linux I2C子系统分析之(一) ----- 用GPIO模拟I2C总线
- Linux "零拷贝" sendfile函数中文说明及实际操作分析
- Linux 启动代码 Start_kernel()函数分析
- Linux I2C子系统分析-I2C总线驱动&&Linux I2C子系统分析-I2C设备驱动
- Linux2.6 I2C子系统分析
- Linux 网桥代码分析 六 网桥数据转发函数分析
- Linux I2C子系统分析-I2C设备驱动