您的位置:首页 > 运维架构 > Linux

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);  执行适配器中算法的信息处理函数

北京创新乐知信息技术有限公司
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: