Linux对hidraw设备output report大小的限制
2021-09-24
963
0
做了个自定义HID设备,可以收发数据,用它来作固件升级。
主要是host通过output report下发固件数据,所以output report的size设置的比较大,有4kb,这样升级速度会快一些。经过测试在Windows xp、win7,win10上都木有问题,在linux上出现问题了。
设备插入ubuntu linux系统,会在/dev目录下增加一个hidraw1设备,打开之后,通过write函数下发一包4096字节的数据直接报错了,提示参数无效。
为了探明原因,打开linux 3.0.8的系统代码,分析。
static const struct file_operations hidraw_ops = { .owner = THIS_MODULE, .read = hidraw_read, .write = hidraw_write, .poll = hidraw_poll, .open = hidraw_open, .release = hidraw_release, .unlocked_ioctl = hidraw_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = hidraw_ioctl, #endif .llseek = noop_llseek, };
可见hidraw驱动在应用层调用write函数时会调用hidraw_write函数来响应。
static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
ssize_t ret;
mutex_lock(&minors_lock);
ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
mutex_unlock(&minors_lock);
return ret;
}
而hidraw_write会调用hidraw_send_report
static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
{
unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct hid_device *dev;
__u8 *buf;
int ret = 0;
if (!hidraw_table[minor]) {
ret = -ENODEV;
goto out;
}
dev = hidraw_table[minor]->hid;
if (!dev->hid_output_raw_report) {
ret = -ENODEV;
goto out;
}
if (count > HID_MAX_BUFFER_SIZE) {
hid_warn(dev, "pid %d passed too large report\n",
task_pid_nr(current));
ret = -EINVAL;
goto out;
}
if (count < 2) {
hid_warn(dev, "pid %d passed too short report\n",
task_pid_nr(current));
ret = -EINVAL;
goto out;
}
buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto out;
}
if (copy_from_user(buf, buffer, count)) {
ret = -EFAULT;
goto out_free;
}
ret = dev->hid_output_raw_report(dev, buf, count, report_type);
out_free:
kfree(buf);
out:
return ret;
}
hidraw_send_report会对reportsize大小进行判断,if (count > HID_MAX_BUFFER_SIZE) 就直接报错退出了。
#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */
而HID_MAX_BUFFER_SIZE的大小就是4kb。
hidraw的write和windows下的WriteFile一样,第一字节是output report的index,后面的才是output report的实际数据,因此要一次下发4kb数据,buf size就要加1,变成4097,驱动检测到大小超了,就直接报错返回了。
总结一下,linux的hidraw设备output report size最大为4095.
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936