请教Android在用户空间操作I2C

板砖先生 2017-11-24 04:06:33
小弟最近在RK3128调试一款I2C接口的GPS,u-blox MAX-7Q。
源码是供应商给的,放在hardware/u-blox/gps/目录下。

以下是hardware操作I2C代码:
ssize_t CSerialPort::i2cGetNumAvailBytes(void) const
{
if (m_fd <= 0)
return -1;

struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs;
__u32 nmsgs;
};
struct i2c_rdwr_ioctl_data rdwr;
struct i2c_msg out_in[2], *out, *in;
unsigned char out_data;
unsigned char in_data[2];
ssize_t result = -1;

out = out_in;
in = out_in + 1;

out_data = 0xFD;

out->addr = s_i2cRecvAddr;
out->flags = 0; // indicates a write
out->len = 1;
out->buf = &out_data;

in->addr = s_i2cRecvAddr;
in->flags = I2C_M_RD;
in->len = 2;
in->buf = in_data;

in_data[0] = 0;
in_data[1] = 0;

rdwr.nmsgs = 2;
rdwr.msgs = out_in;

int io = ioctl(m_fd, I2C_RDWR, &rdwr);

if (io < 0)
{
UBXSERLOG("IOCTL for reading nob registers failed. io = %d",io);
}
else
{
result = in_data[0] * 256 + in_data[1];
}
return result;
}

ioctl返回-1,然后去kernel中添加log,发现在i2cdev_ioctl_rdrw时出错了。
以下是添加的log:
static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
unsigned long arg)
{
struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_msg *rdwr_pa;
u8 __user **data_ptrs;
int i, res;

if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_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;

printk("rdwr_arg.msgs[1].len = %d\n",rdwr_arg.msgs[1].len);
rdwr_pa = memdup_user(rdwr_arg.msgs,
rdwr_arg.nmsgs * sizeof(struct i2c_msg));
if (IS_ERR(rdwr_pa))
return PTR_ERR(rdwr_pa);

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 */
printk("rdwr_pa[%d].len = %d \n",i, rdwr_pa[i].len);
if (rdwr_pa[i].len > 8192) {
printk("i2cdev_ioctl_rdrw 111 res = %d, rdwr_pa[%d].len = %d\n", res, i, rdwr_pa[i].len);
res = -EINVAL;
break;
}

打印如下:
[ 78.822079] rdwr_arg.msgs[1].len = 42684
[ 78.822187] rdwr_pa[0].len = 1
[ 78.822213] rdwr_pa[1].len = 42684
[ 78.822236] i2cdev_ioctl_rdrw 111 res = 0, rdwr_pa[1].len = 42684


很奇怪length怎么就不对了呢?
可以看到copy_from_user之后就已经不对了,百思不得其解,求大神指点!
...全文
703 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
板砖先生 2017-12-01
  • 打赏
  • 举报
回复
问题解决了,原因在与i2c_msg这个结构体,我是rockchip平台,kernel的定义在kernel/include/uapi/linux/i2c.h,而hardware目录下引用的头文件路径是bionic/libc/kernel/uapi/linux/i2c.h,而rockchip修改了i2c_msg的定义,添加了一个结构体成员,并且没有同步到bionic目录下,两个地方引用的结构体不一致,当然出错了。
板砖先生 2017-11-27
  • 打赏
  • 举报
回复
引用 5 楼 zxc18076752045 的回复:
节点权限问题?
权限已经添加,应该不是
枫叶会再红吗 2017-11-27
  • 打赏
  • 举报
回复
节点权限问题?
板砖先生 2017-11-27
  • 打赏
  • 举报
回复
引用 3 楼 wenxy1 的回复:
1. 为什么要用在user space操作i2c 从设备。 2. User space访问设备有几个限制,不能处理中断,必须要mmap。 没有细看你的代码,思路见以上。 建议参考:LDD、ULK、LKD、 ELDD。
是原厂给的代码,我只是移植,要改到内核操作也不大容易啊。
Wenxy1 2017-11-24
  • 打赏
  • 举报
回复
1. 为什么要用在user space操作i2c 从设备。 2. User space访问设备有几个限制,不能处理中断,必须要mmap。 没有细看你的代码,思路见以上。 建议参考:LDD、ULK、LKD、 ELDD。
板砖先生 2017-11-24
  • 打赏
  • 举报
回复
而且rdwr_pa[1].len的数值还经常不一样,相同点是都很大,难道是copy_from_user的时候出错了?可返回值是0啊。
板砖先生 2017-11-24
  • 打赏
  • 举报
回复



代码截图,看起来方便一些

1,318

社区成员

发帖
与我相关
我的任务
社区描述
主要是开发驱动技术
社区管理员
  • 驱动程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧