- 论坛徽章:
- 0
|
这些天研究IIC 总线,得到论坛很多大虾的帮助,谢谢你们的无私,才让我们这样的新手能得到提高. 本着班门弄斧的精神,把自己的学习经验共享出来,以供更多的新手能够少走一些弯路. 里面可能也会有错误,希望指正.谢谢. 别笑我哈,我是新手.呵呵
因为I2C.DEV 中的IOCTL 函数就能完成IIC总线的读写数据,因此
首先分析I2C.DEV 中的 ioctl 函数,
=========两个重要的结构体==============
[color="#000000"]struct i2c_msg [color="#0000cc"]{
__u16 addr[color="#0000cc"]; [color="#ff9900"]/* slave address */
__u16 flags[color="#0000cc"];
[color="#0000cc"]#[color="#ff0000"]define I2C_M_TEN 0x10 [color="#ff9900"]/* we have a ten bit chip address */
[color="#0000cc"]#[color="#ff0000"]define I2C_M_RD 0x01
[color="#0000cc"]#[color="#ff0000"]define I2C_M_NOSTART 0x4000
[color="#0000cc"]#[color="#ff0000"]define I2C_M_REV_DIR_ADDR 0x2000
[color="#0000cc"]#[color="#ff0000"]define I2C_M_IGNORE_NAK 0x1000
[color="#0000cc"]#[color="#ff0000"]define I2C_M_NO_RD_ACK 0x0800
[color="#0000cc"]#[color="#ff0000"]define I2C_M_RECV_LEN 0x0400 [color="#ff9900"]/* length will be first received byte */
__u16 len[color="#0000cc"]; [color="#ff9900"]/* msg length */
__u8 [color="#0000cc"]*buf[color="#0000cc"]; [color="#ff9900"]/* pointer to msg data */
[color="#0000cc"]}[color="#0000cc"];
[color="#0000ff"]struct i2c_rdwr_ioctl_data [color="#0000cc"]{
[color="#0000ff"]struct i2c_msg __user [color="#0000cc"]*msgs[color="#0000cc"]; [color="#ff9900"]/* pointers to i2c_msgs */
__u32 nmsgs[color="#0000cc"]; [color="#ff9900"]/* number of i2c_msgs */
[color="#0000cc"]}[color="#0000cc"];
====================================
[color="#000000"]case I2C_RDWR[color="#0000cc"]:
[color="#0000ff"]if [color="#0000cc"](copy_from_user[color="#0000cc"]([color="#0000cc"]&rdwr_arg[color="#0000cc"],
[color="#0000cc"]([color="#0000ff"]struct i2c_rdwr_ioctl_data __user [color="#0000cc"]*[color="#0000cc"])[color="#ff0000"]arg[color="#0000cc"],
[color="#0000ff"]sizeof[color="#0000cc"](rdwr_arg[color="#0000cc"])[color="#0000cc"])[color="#0000cc"]) // arg 传递过来的是地址,强制转换为结构体类型指针
[color="#0000ff"]return [color="#0000cc"]-EFAULT[color="#0000cc"];
/* Put an arbitrary limit on the number of messages that can
* be sent at once */
[color="#0000ff"]if [color="#0000cc"](rdwr_arg[color="#0000cc"].nmsgs [color="#0000cc"]> I2C_RDRW_IOCTL_MAX_MSGS[color="#0000cc"])
[color="#0000ff"]return [color="#0000cc"]-EINVAL[color="#0000cc"];
rdwr_pa [color="#0000cc"]= [color="#0000cc"]([color="#0000ff"]struct i2c_msg [color="#0000cc"]*[color="#0000cc"])
kmalloc[color="#0000cc"](rdwr_arg[color="#0000cc"].nmsgs [color="#0000cc"]* [color="#0000ff"]sizeof[color="#0000cc"]([color="#0000ff"]struct i2c_msg[color="#0000cc"])[color="#0000cc"],
GFP_KERNEL[color="#0000cc"])[color="#0000cc"];
[color="#0000ff"]if [color="#0000cc"](rdwr_pa [color="#0000cc"]=[color="#0000cc"]= [color="#ff0000"]NULL[color="#0000cc"]) [color="#0000ff"]return [color="#0000cc"]-ENOMEM[color="#0000cc"];
[color="#0000ff"]if [color="#0000cc"](copy_from_user[color="#0000cc"](rdwr_pa[color="#0000cc"], rdwr_arg[color="#0000cc"].msgs[color="#0000cc"],
rdwr_arg[color="#0000cc"].nmsgs [color="#0000cc"]* [color="#0000ff"]sizeof[color="#0000cc"]([color="#0000ff"]struct i2c_msg[color="#0000cc"])[color="#0000cc"])[color="#0000cc"]) [color="#0000cc"]{
kfree[color="#0000cc"](rdwr_pa[color="#0000cc"])[color="#0000cc"];
[color="#0000ff"]return [color="#0000cc"]-EFAULT[color="#0000cc"];
[color="#0000cc"]} // 第一个copy,已经拷贝arg->msgs指针到rdwr_arg的msgs指针,这里的COPY会把msgs指向的内容拷贝到rdwr_pa中,同时rdwr_pa->buf 指针指向用户空间msgs->buf 的指针
data_ptrs [color="#0000cc"]= kmalloc[color="#0000cc"](rdwr_arg[color="#0000cc"].nmsgs [color="#0000cc"]* [color="#0000ff"]sizeof[color="#0000cc"](u8 __user [color="#0000cc"]*[color="#0000cc"])[color="#0000cc"], GFP_KERNEL[color="#0000cc"])[color="#0000cc"];
[color="#0000ff"]if [color="#0000cc"](data_ptrs [color="#0000cc"]=[color="#0000cc"]= [color="#ff0000"]NULL[color="#0000cc"]) [color="#0000cc"]{
kfree[color="#0000cc"](rdwr_pa[color="#0000cc"])[color="#0000cc"];
[color="#0000ff"]return [color="#0000cc"]-ENOMEM[color="#0000cc"];
[color="#0000cc"]}
res [color="#0000cc"]= 0[color="#0000cc"];
[color="#0000ff"]for[color="#0000cc"]( i[color="#0000cc"]=0[color="#0000cc"]; i[color="#0000cc"] 8192[color="#0000cc"]) [color="#0000cc"]{
res [color="#0000cc"]= [color="#0000cc"]-EINVAL[color="#0000cc"];
[color="#0000ff"]break[color="#0000cc"];
[color="#0000cc"]}
data_ptrs[color="#0000cc"][i[color="#0000cc"]] [color="#0000cc"]= [color="#0000cc"](u8 __user [color="#0000cc"]*[color="#0000cc"])rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].buf[color="#0000cc"];
// data_prts 指向 RDWR_pa.buf,即指向用户空间穿过来的buf中数据缓冲区
rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].buf [color="#0000cc"]= kmalloc[color="#0000cc"](rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].len[color="#0000cc"], GFP_KERNEL[color="#0000cc"])[color="#0000cc"];//重新分配buf
[color="#0000ff"]if[color="#0000cc"](rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].buf [color="#0000cc"]=[color="#0000cc"]= [color="#ff0000"]NULL[color="#0000cc"]) [color="#0000cc"]{
res [color="#0000cc"]= [color="#0000cc"]-ENOMEM[color="#0000cc"];
[color="#0000ff"]break[color="#0000cc"];
[color="#0000cc"]}
[color="#0000ff"]if[color="#0000cc"](copy_from_user[color="#0000cc"](rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].buf[color="#0000cc"],
data_ptrs[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"], // 把用户空间数据拷贝到 rdwr_pa.buf 中
rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].len[color="#0000cc"])[color="#0000cc"]) [color="#0000cc"]{
[color="#0000cc"]+[color="#0000cc"]+i[color="#0000cc"]; [color="#ff9900"]/* Needs to be kfreed too */
res [color="#0000cc"]= [color="#0000cc"]-EFAULT[color="#0000cc"];
[color="#0000ff"]break[color="#0000cc"];
[color="#0000cc"]}
[color="#0000cc"]}
[color="#0000ff"]if [color="#0000cc"](res [color="#0000cc"]adapter[color="#0000cc"], // 最终会调用s3c24xx_i2c_xfer函数
rdwr_pa[color="#0000cc"],
rdwr_arg[color="#0000cc"].nmsgs[color="#0000cc"])[color="#0000cc"]; // 拷贝完毕,开始发送
[color="#0000ff"]while[color="#0000cc"](i[color="#0000cc"]-[color="#0000cc"]- [color="#0000cc"]> 0[color="#0000cc"]) [color="#0000cc"]{
[color="#0000ff"]if[color="#0000cc"]( res[color="#0000cc"]>[color="#0000cc"]=0 [color="#0000cc"]&[color="#0000cc"]& [color="#0000cc"](rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].flags [color="#0000cc"]& I2C_M_RD[color="#0000cc"])[color="#0000cc"]) [color="#0000cc"]{
[color="#0000ff"]if[color="#0000cc"](copy_to_user[color="#0000cc"](
data_ptrs[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"],
rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].buf[color="#0000cc"],
rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].len[color="#0000cc"])[color="#0000cc"]) [color="#0000cc"]{
res [color="#0000cc"]= [color="#0000cc"]-EFAULT[color="#0000cc"]; // 如果为读,把数据拷贝到用户空间
[color="#0000cc"]}
[color="#0000cc"]}
kfree[color="#0000cc"](rdwr_pa[color="#0000cc"][i[color="#0000cc"]][color="#0000cc"].buf[color="#0000cc"])[color="#0000cc"];
[color="#0000cc"]}
kfree[color="#0000cc"](data_ptrs[color="#0000cc"])[color="#0000cc"];
kfree[color="#0000cc"](rdwr_pa[color="#0000cc"])[color="#0000cc"];
[color="#0000ff"]return res[color="#0000cc"];
=============下面分析i2c_s3c2410.c的传输过程=========
启动s3c24xx_i2c_message_start函数开始传输,
在这个函数里面会首先发送从器件地址
addr = (msg->addr & 0x7f) addr=0x50
if (msg->flags & I2C_M_RD) {
stat |= S3C2410_IICSTAT_MASTER_RX;
addr |= 1;
} else
stat |= S3C2410_IICSTAT_MASTER_TX;
writeb(addr, i2c->regs + S3C2410_IICDS);
发送完后,会进入中断s3c24xx_i2c_irq中,处理中断标志后,进入发送下一个字节i2s_s3c_irq_nextbyte函数,此函数非常重要,几乎所有的功能在此完成
进入s3c24xx_i2c_doxfer函数的时候,会设置status=STATE_START,
因此,i2s_s3c_irq_nextbyte 函数首先分析 case state_start
[color="#000000"]if [color="#0000cc"](i2c[color="#0000cc"]-[color="#0000cc"]>msg[color="#0000cc"]-[color="#0000cc"]>flags [color="#0000cc"]& I2C_M_RD[color="#0000cc"])
i2c[color="#0000cc"]-[color="#0000cc"]>state [color="#0000cc"]= STATE_READ[color="#0000cc"];
[color="#0000ff"]else
i2c[color="#0000cc"]-[color="#0000cc"]>state [color="#0000cc"]= STATE_WRITE[color="#0000cc"]; // 判断为读还是写
[color="#0000ff"]if [color="#0000cc"](is_lastmsg[color="#0000cc"](i2c[color="#0000cc"]) [color="#0000cc"]&[color="#0000cc"]& i2c[color="#0000cc"]-[color="#0000cc"]>msg[color="#0000cc"]-[color="#0000cc"]>len [color="#0000cc"]=[color="#0000cc"]= 0[color="#0000cc"]) [color="#0000cc"]{ //没有消息,或者长度为0,停止总线
s3c24xx_i2c_stop[color="#0000cc"](i2c[color="#0000cc"], 0[color="#0000cc"])[color="#0000cc"];
[color="#0000ff"]goto out_ack[color="#0000cc"];
[color="#0000cc"]}
[color="#0000ff"]if [color="#0000cc"](i2c[color="#0000cc"]-[color="#0000cc"]>state [color="#0000cc"]=[color="#0000cc"]= STATE_READ[color="#0000cc"]) // 若是读,直接跳到读命令分支
[color="#0000ff"]goto prepare_read[color="#0000cc"];
// 否则,进入写分支
[color="#0000ff"]case STATE_WRITE[color="#0000cc"]:
retry_write[color="#0000cc"]:
[color="#0000ff"]if [color="#0000cc"]([color="#0000cc"]!is_msgend[color="#0000cc"](i2c[color="#0000cc"])[color="#0000cc"]) [color="#0000cc"]{ // 判断是否单个消息中的发送内容msg->buf已经传输完毕
byte [color="#0000cc"]= i2c[color="#0000cc"]-[color="#0000cc"]>msg[color="#0000cc"]-[color="#0000cc"]>buf[color="#0000cc"][i2c[color="#0000cc"]-[color="#0000cc"]>msg_ptr[color="#0000cc"]+[color="#0000cc"]+[color="#0000cc"]][color="#0000cc"]; // 发送下一个内容
writeb[color="#0000cc"](byte[color="#0000cc"], i2c[color="#0000cc"]-[color="#0000cc"]>regs [color="#0000cc"]+ S3C2410_IICDS[color="#0000cc"])[color="#0000cc"];
ndelay[color="#0000cc"](i2c[color="#0000cc"]-[color="#0000cc"]>tx_setup[color="#0000cc"])[color="#0000cc"];
[color="#0000cc"]}
[color="#0000ff"]else [color="#0000ff"]if [color="#0000cc"]([color="#0000cc"]!is_lastmsg[color="#0000cc"](i2c[color="#0000cc"])[color="#0000cc"]) // 判断多个消息msgs是否已经结束 了
[color="#0000cc"]{
[color="#ff9900"]/* we need to go to the next i2c message */
dev_dbg[color="#0000cc"](i2c[color="#0000cc"]-[color="#0000cc"]>dev[color="#0000cc"], [color="#ff00ff"]"WRITE: Next Message\n"[color="#0000cc"])[color="#0000cc"];
i2c[color="#0000cc"]-[color="#0000cc"]>msg_ptr [color="#0000cc"]= 0[color="#0000cc"];
i2c[color="#0000cc"]-[color="#0000cc"]>msg_idx [color="#0000cc"]+[color="#0000cc"]+[color="#0000cc"];
i2c[color="#0000cc"]-[color="#0000cc"]>msg[color="#0000cc"]+[color="#0000cc"]+[color="#0000cc"]; // 指向下一个消息
[color="#ff9900"]/* check to see if we need to do another message */
[color="#0000ff"]if [color="#0000cc"](i2c[color="#0000cc"]-[color="#0000cc"]>msg[color="#0000cc"]-[color="#0000cc"]>flags [color="#0000cc"]& I2C_M_NOSTART[color="#0000cc"])
[color="#0000cc"]{ // 不需要重新启动,注释说不支持此模式
[color="#0000ff"]if [color="#0000cc"](i2c[color="#0000cc"]-[color="#0000cc"]>msg[color="#0000cc"]-[color="#0000cc"]>flags [color="#0000cc"]& I2C_M_RD[color="#0000cc"])
[color="#0000cc"]{
s3c24xx_i2c_stop[color="#0000cc"](i2c[color="#0000cc"], [color="#0000cc"]-EINVAL[color="#0000cc"])[color="#0000cc"];
[color="#0000cc"]}
[color="#0000ff"]goto retry_write[color="#0000cc"];
[color="#0000cc"]}
[color="#0000ff"]else
[color="#0000cc"]{
s3c24xx_i2c_message_start[color="#0000cc"](i2c[color="#0000cc"], i2c[color="#0000cc"]-[color="#0000cc"]>msg[color="#0000cc"])[color="#0000cc"]; // 发送下条消息,重新启动,发送从机地址
i2c[color="#0000cc"]-[color="#0000cc"]>state [color="#0000cc"]= STATE_START[color="#0000cc"];
[color="#0000cc"]}
[color="#0000cc"]}
[color="#0000ff"]else
[color="#0000cc"]{ // 全部发送完成,结束
[color="#ff9900"]/* send stop */
s3c24xx_i2c_stop[color="#0000cc"](i2c[color="#0000cc"], 0[color="#0000cc"])[color="#0000cc"];
[color="#0000cc"]}
[color="#0000ff"]break[color="#0000cc"];
case STATE_READ: 读部分,比较简单就不分析了
就这样不停的在中断函数s3c24xx_i2c_irq里面跳啊跳,又跳到i2s_s3c_irq_nextbyte
最后到了结束的时候,s3c24xx_i2c_stop调用s3c24xx_i2c_master_complete函数,
接着使 i2c->msg_num = 0 唤醒睡眠
s3c24xx_i2c_doxfer函数中
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); 返回,
整个传输完成.
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/66024/showart_1889158.html |
|