Linux对hidraw设备output report大小的限制

做了个自定义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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值