接上一篇《蓝牙遥控器连接流程分析》,我们这次正式开始蓝牙遥控器的调试。按理来说,有了上一篇文章的理论支撑,要调试一款蓝牙遥控器应该就不难了,实际也是这样。但是调试过程中,还是遇到了一些问题,在此记录一下。
在上一篇文章我们可以看到,以前在安卓平台想要创建/dev/input/eventX和/dev/hidrawX节点,蓝牙协议栈中一般有一下操作:
int fd = open(/dev/uhid);
write(fd, ...);
不过在我调试的这款cypress 20704蓝牙芯片中,厂家提供的协议栈(协议栈名叫bsa,不是Linux官方的bluez)并不是通过uhid驱动去操作的,而是有他自己的bthid驱动。不过流程相似,只是名字不同而已。我们先简单看一下bthid驱动中的流程。
static const struct file_operations bthid_fops =
{
.owner = THIS_MODULE,
.open = bthid_open,
.release = bthid_release,
.write = bthid_write,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
.unlocked_ioctl = bthid_ioctl
#else
.ioctl = bthid_ioctl
#endif
};
static struct miscdevice bthid_misc =
{
.fops = &bthid_fops,
.minor = BTHID_MINOR,
.name = BTHID_NAME
};
static int __init bthid_init(void)
{
int ret;
ret = misc_register(&bthid_misc);
if (ret)
{
BTHID_ERR("misc driver registration error\n");
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
ret = hid_register_driver(&bthid_driver);
if (ret)
{
BTHID_ERR("hid driver registration error\n");
}
#endif
return ret;
}
流程和uhid驱动一样,注册一个misc设备,并且也挂载到hid总线。将编译出来的bthid驱动注册进系统后,就会多出一个/dev/bthid文件。这个就和/dev/uhid类似了。所以在协议栈中肯定有一个打开/dev/bthid文件的操作,现在我们搜索一下协议栈的代码,果不其然,在某个源码中有一下动作:
#define APP_HH_BTHID_PATH "/dev/bthid"
int app_bthid_open(void)
{
int bthid_fd;
/* Open bthid device. Return if failed */
bthid_fd = open(APP_HH_BTHID_PATH, O_RDWR);
if (bthid_fd < 0)
{
APP_ERROR1("Failed to open %s : %d", APP_HH_BTHID_PATH, errno);
return -1;
}
APP_DEBUG1("fd=%d", bthid_fd);
return bthid_fd;
}
所以我们可以猜测,注册完bthid驱动后,再调用协议栈中上面的这段代码,就大功告成了?我也是这么想的,但是做完这些工作,却迟迟没有看到创建/dev/input/eventX和/dev/hidrawX节点。加了很多打印也没找到原因,只是知道在协议栈中调用ioctl时失败了,却没找到为什么失败,后来网上看到一位大神的文章,恍然大悟。在bthid驱动中,ioctl的接口用的是unlocked_ioctl,但在32位系统64位的内核上面会走compat_ioctl接口,这就是compat_ioctl存在的意义,由于我使用的Linux系统是32位,内核编译的是Arm64,这应该就是这个Bug产生的原因,替换成compat_ioctl,问题就解决了,谢天谢地!
参考链接:https://blog.csdn.net/qq_25402181/article/details/77985143
static const struct file_operations bthid_fops =
{
.owner = THIS_MODULE,
.open = bthid_open,
.release = bthid_release,
.write = bthid_write,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
.compat_ioctl = bthid_ioctl
#else
.ioctl = bthid_ioctl
#endif
};
这只是调试蓝牙遥控器遇到的一个小问题,后续调试过程中如果遇到有价值的问题,会继续写文章总结。