[RK3128][Android 6.0] u-blox GPS芯片 MAX-7Q调试记录

 

 

硬件平台:RK3128

Android版本:6.0

Kernel版本:3.10.92

 

最近调试一款gps芯片,u-bloxMAX-7Q,支持I2CUART接口,由于UART口不够用,只能用I2C接口,之前没有接触过I2C接口的gps芯片,并且在hardware层调用I2C也是第一次接触,故记录在此。

 

1、在hardware目录下新建文件夹u-blox,将客户提供的hal层源码复制到该目录下。

修改hardware/u-blox/gps/u-blox.confSERIAL_DEVICE/dev/i2c-2,如下:

# Device to be used by the driver
#SERIAL_DEVICE                   /dev/ttyACM0 # USB (Default interface)
#SERIAL_DEVICE                   /dev/ttymxc4 # UART on Sabre SD (IMX6Q)
SERIAL_DEVICE                   /dev/i2c-2   # I2C on Sabre SD (IMX6Q)
#SERIAL_DEVICE                   /dev/ttyO3   # UART on Panda board
#SERIAL_DEVICE                   /dev/i2c-4   # I2C on Panda board

2、复制ubx-setup.shdevice/rockchip/rk312x/目录下,并在device/rockchip/rk312x/rk312x.mk中添加如下内容:

# add for u-blox
PRODUCT_COPY_FILES += \
        device/rockchip/rk312x/ubx-setup.sh:system/etc/ubx-setup.sh \
        hardware/u-blox/gps/gps.conf:system/etc/gps.conf \
        hardware/u-blox/gps/u-blox.conf:system/etc/u-blox.conf

3、device/rockchip/common/init.rockchip.rc中添加服务:

# add for u-blox
service ubx-setup /system/etc/ubx-setup.sh
  user root
  group root
  oneshot

并在on boot中开启服务:

# add for u-blox
chmod 0755 /system/etc/ubx-setup.sh
start ubx-setup

4、使用 mmm hardware/u-blox/gps/编译hal,然后make一下。这个地方比较奇怪,我用make全编hardware/u-blox/gps/并没有编译到,又用mmm才编到。生成out/target/product/rk312x/system/lib/hw/gps.default.so文件说明编译成功。

 

5、烧录后,先用打印logcat搜索u-blox确认服务运行,如果没有运行,可能是selinux导致,用adb shell setenforce 0来确认是否是selinux问题。

 

遇到的问题:

移植完成后,logcat中有大量以下错误:

01-18 08:51:06.274   289  1027 D u-blox  : IOCTL for reading nob registers failed. io = -1
01-18 08:51:06.324   289  1027 D u-blox  : IOCTL for reading nob registers failed. io = -1
01-18 08:51:06.375   289  1027 D u-blox  : IOCTL for reading nob registers failed. io = -1
01-18 08:51:06.425   289  1027 D u-blox  : IOCTL for reading nob registers failed. io = -1

先来看hardware层出错的地方代码:

ubx_serial.cpp

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;
    out->scl_rate = 200 * 1000;
 
    in->addr = s_i2cRecvAddr;
    in->flags = I2C_M_RD;
    in->len = 2;
    in->buf = in_data;
    in->scl_rate = 200 * 1000;
 
    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出错了,在kernel中添加打印,发现在i2cdev_ioctl_rdrw出错,rdwr_pa[1].len是一个超大值,导致校验不过,代码如下:

I2c-dev.c

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;
 
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 */
if (rdwr_pa[i].len > 8192) { //这里出错
res = -EINVAL;
break;
}
 
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
if (IS_ERR(rdwr_pa[i].buf)) {
res = PTR_ERR(rdwr_pa[i].buf);
break;
}
 
/*
 * If the message length is received from the slave (similar
 * to SMBus block read), we must ensure that the buffer will
 * be large enough to cope with a message length of
 * I2C_SMBUS_BLOCK_MAX as this is the maximum underlying bus
 * drivers allow. The first byte in the buffer must be
 * pre-filled with the number of extra bytes, which must be
 * at least one to hold the message length, but can be
 * greater (for example to account for a checksum byte at
 * the end of the message.)
 */
if (rdwr_pa[i].flags & I2C_M_RECV_LEN) {
if (!(rdwr_pa[i].flags & I2C_M_RD) ||
    rdwr_pa[i].buf[0] < 1 ||
    rdwr_pa[i].len < rdwr_pa[i].buf[0] +
     I2C_SMBUS_BLOCK_MAX) {
res = -EINVAL;
break;
}
 
rdwr_pa[i].len = rdwr_pa[i].buf[0];
}
}
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, 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;
}


查了好久,明明hardwarelen=2,怎么到kernel就不对了?

 

原因在于i2c_msg这个结构体,它在kernel中定义在:

kernel/include/uapi/linux/i2c.h

hardware层引用的定义在:

bionic/libc/kernel/uapi/linux/i2c.h

 

hardware层调用I2Ci2c_msg的定义必须与内核一致,rockchip修改了内核,在kernel/include/uapi/linux/i2c.h中为i2c_msg添加了一个成员,并且没有同步到bionic。所以两边引用的i2c_msg定义不一样,结果就是当然出错了。

bionic/libc/kernel/uapi/linux/i2c.h这个文件是自动生成的,当修改了内核后,运行bionic/libc/kernel/tools/update_all.py脚本来同步(注意:此脚本慎用,因为我发现rockchip并没有用此脚本同步,而是直接修改了bionic下文件)。

bionic/libc/kernel/uapi/linux/i2c.hi2c_msg定义修改成跟内核一样就可以了。

 

注意:可能还要在device/rockchip/common/ueventd.rockchip.rc中添加i2c-2的权限。

/dev/i2c-2                0666   system      system

 

 

 

 

你可能感兴趣的:(Rockchip)