全部博文(166)
分类: LINUX
2009-04-03 09:02:59
struct i2c_msg { __u16 addr; /* slave address */ __u16 flags; #define I2C_M_TEN 0x10 /* we have a ten bit chip address */ #define I2C_M_RD 0x01 #define I2C_M_NOSTART 0x4000 #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_NO_RD_ACK 0x0800 #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ __u16 len; /* msg length */ __u8 *buf; /* pointer to msg data */ }; struct i2c_rdwr_ioctl_data { struct i2c_msg __user *msgs; /* pointers to i2c_msgs */ __u32 nmsgs; /* number of i2c_msgs */ }; |
case I2C_RDWR: if (copy_from_user(&rdwr_arg, (struct i2c_rdwr_ioctl_data __user *)arg, sizeof(rdwr_arg))) // arg 传递过来的是地址,强制转换为结构体类型指针 return -EFAULT; /* Put an arbitrary limit on the number of messages that can * be sent at once */ if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) return -EINVAL; rdwr_pa = (struct i2c_msg *) kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); if (rdwr_pa == NULL) return -ENOMEM; if (copy_from_user(rdwr_pa, rdwr_arg.msgs, rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { kfree(rdwr_pa); return -EFAULT; } // 第一个copy,已经拷贝arg->msgs指针到rdwr_arg的msgs指针,这里的COPY会把msgs指向的内容拷贝到rdwr_pa中,同时rdwr_pa->buf 指针指向用户空间msgs->buf 的指针 data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { kfree(rdwr_pa); return -ENOMEM; } res = 0; for( i=0; i<rdwr_arg.nmsgs; i++ ) { /* Limit the size of the message to a sane amount */ if (rdwr_pa[i].len > 8192) { res = -EINVAL; break; } data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; // data_prts 指向 RDWR_pa.buf,即指向用户空间穿过来的buf中数据缓冲区 rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);//重新分配buf if(rdwr_pa[i].buf == NULL) { res = -ENOMEM; break; } if(copy_from_user(rdwr_pa[i].buf, data_ptrs[i], // 把用户空间数据拷贝到 rdwr_pa.buf 中 rdwr_pa[i].len)) { ++i; /* Needs to be kfreed too */ res = -EFAULT; break; } } if (res < 0) { int j; for (j = 0; j < i; ++j) kfree(rdwr_pa[j].buf); kfree(data_ptrs); kfree(rdwr_pa); return res; } res = i2c_transfer(client->adapter, // 最终会调用s3c24xx_i2c_xfer函数 rdwr_pa, rdwr_arg.nmsgs); // 拷贝完毕,开始发送 while(i-- > 0) { if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) { if(copy_to_user( data_ptrs[i], rdwr_pa[i].buf, rdwr_pa[i].len)) { res = -EFAULT; // 如果为读,把数据拷贝到用户空间 } } kfree(rdwr_pa[i].buf); } kfree(data_ptrs); kfree(rdwr_pa); return res; |
if (i2c->msg->flags & I2C_M_RD) i2c->state = STATE_READ; else i2c->state = STATE_WRITE; // 判断为读还是写 if (is_lastmsg(i2c) && i2c->msg->len == 0) { //没有消息,或者长度为0,停止总线 s3c24xx_i2c_stop(i2c, 0); goto out_ack; } if (i2c->state == STATE_READ) // 若是读,直接跳到读命令分支 goto prepare_read; // 否则,进入写分支 case STATE_WRITE: retry_write: if (!is_msgend(i2c)) { // 判断是否单个消息中的发送内容msg->buf已经传输完毕 byte = i2c->msg->buf[i2c->msg_ptr++]; // 发送下一个内容 writeb(byte, i2c->regs + S3C2410_IICDS); ndelay(i2c->tx_setup); } else if (!is_lastmsg(i2c)) // 判断多个消息msgs是否已经结束 了 { /* we need to go to the next i2c message */ dev_dbg(i2c->dev, "WRITE: Next Message\n"); i2c->msg_ptr = 0; i2c->msg_idx ++; i2c->msg++; // 指向下一个消息 /* check to see if we need to do another message */ if (i2c->msg->flags & I2C_M_NOSTART) { // 不需要重新启动,注释说不支持此模式 if (i2c->msg->flags & I2C_M_RD) { s3c24xx_i2c_stop(i2c, -EINVAL); } goto retry_write; } else { s3c24xx_i2c_message_start(i2c, i2c->msg); // 发送下条消息,重新启动,发送从机地址 i2c->state = STATE_START; } } else { // 全部发送完成,结束 /* send stop */ s3c24xx_i2c_stop(i2c, 0); } break; |