背景
接上一篇《藍牙遙控器連接流程分析》,我們這次正式開始藍牙遙控器的調試。按理來說,有了上一篇文章的理論支撐,要調試一款藍牙遙控器應該就不難了,實際也是這樣。但是調試過程中,還是遇到了一些問題,在此記錄一下。
正文
在上一篇文章我們可以看到,以前在安卓平臺想要創建/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
};
結束
這只是調試藍牙遙控器遇到的一個小問題,後續調試過程中如果遇到有價值的問題,會繼續寫文章總結。