zoukankan      html  css  js  c++  java
  • hidraw设备简要分析

    关键词:hid、hidraw、usbhid、hidp等等。

    下面首先介绍hidraw设备主要用途,然后简要分析hidraw设备驱动(但是不涉及到相关USB/Bluwtooth驱动),最后分析用户空间接口并实例。

    1. hidraw介绍

    在内核Documentation/hid/hidraw.txt中对hidra设备进行介绍,以及和hiddev的区别。

    hidraw提供了一个通过USB/Bluetooth接口的裸数据接口,它和hiddev的区别体现在其数据不经过HID parser解析,而是直接将数据传输。

    如果用户空间应用程序知道怎么恰当和硬件设备通信,和能够手动构建HID 报表,那么hidraw应该被使用。这通常是在用户控件驱动自定义HID 设备的时候。

    Hidraw与不符合规范的HID 设备通信也是有利 的,这些设备以一种不符合报表描述符不一致的方式发送和接收数据。因为Hiddev解析器通过他发送和接收报表,检测设备的报表描述符,这样的通信是不可能使用hiddev。Hidraw是唯一的选择,为这些不兼容的设备编写一个定制的内核驱动程序。

    Hidraw一个好处是用户空间应用程序使用独立的底层硬件类型。当前,hidraw是通过bluetooth 和 usb实现。在将来,随着硬件总线的发展,hidraw将支持更多的类型。

    2. hidraw驱动

    hidraw也是hid类设备,hidraw_init()被hid_init调用,在调用之前创建了虚拟的hid总线hid_bus_type,并且创建/sys/kernel/debug/hid调试接口。

    static int __init hid_init(void)
    {
        int ret;
    ...
        ret = bus_register(&hid_bus_type);
    ...
        ret = hidraw_init();
        if (ret)
            goto err_bus;
    
        hid_debug_init();
    ...
    }
    
    static void __exit hid_exit(void)
    {
        hid_debug_exit();
        hidraw_exit();
        bus_unregister(&hid_bus_type);
    }

    struct hidraw是hidraw设备实例,struct hid_device是hid框架下表示hid设备的实例。

    hidraw_list是hidraw设备一次传输的实例。

    struct hidraw {
        unsigned int minor;----------------------从设备号。
        int exist;-------------------------------表示设备是否连接。
        int open;--------------------------------表示设备open计数。
        wait_queue_head_t wait;
        struct hid_device *hid;------------------对应hid设备实例。
        struct device *dev;
        spinlock_t list_lock;
        struct list_head list;
    };
    
    struct hidraw_report {
        __u8 *value;
        int len;
    };
    
    struct hidraw_list {
        struct hidraw_report buffer[HIDRAW_BUFFER_SIZE];
        int head;
        int tail;
        struct fasync_struct *fasync;
        struct hidraw *hidraw;
        struct list_head node;
        struct mutex read_mutex;
    };

    2.1 hid总线

    hid_bus_type提供了hid总线上进行match、probe、remove的接口,以及uevent上报接口。

    static struct bus_type hid_bus_type = {
        .name        = "hid",
        .dev_groups    = hid_dev_groups,
        .match        = hid_bus_match,
        .probe        = hid_device_probe,
        .remove        = hid_device_remove,
        .uevent        = hid_uevent,
    };
    
    static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
    {
        struct hid_device *hdev = to_hid_device(dev);    
    
        if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X",
                hdev->bus, hdev->vendor, hdev->product))
            return -ENOMEM;
    
        if (add_uevent_var(env, "HID_NAME=%s", hdev->name))
            return -ENOMEM;
    
        if (add_uevent_var(env, "HID_PHYS=%s", hdev->phys))
            return -ENOMEM;
    
        if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
            return -ENOMEM;
    
        if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
                   hdev->bus, hdev->group, hdev->vendor, hdev->product))
            return -ENOMEM;
    
        return 0;
    }

    2.1 hidraw初始化

    hidraw首先创建了字符设备hidraw_class,并和字符设备hidraw_cdev绑定,对应的文件操作函数集为hidraw_ops

    其中字符设备hidraw_cdev从设备好范围为0~63,后面创建设备通过hidraw_class即可。

    int __init hidraw_init(void)
    {
        int result;
        dev_t dev_id;
    
        result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
                HIDRAW_MAX_DEVICES, "hidraw");---------------------------------从设备号0~63。
        if (result < 0) {
            pr_warn("can't get major number
    ");
            goto out;
        }
    
        hidraw_major = MAJOR(dev_id);
    
        hidraw_class = class_create(THIS_MODULE, "hidraw");------------------创建hidraw设备类。
        if (IS_ERR(hidraw_class)) {
            result = PTR_ERR(hidraw_class);
            goto error_cdev;
        }
    
            cdev_init(&hidraw_cdev, &hidraw_ops);------------------------------初始化一个字符设备hidraw_dev,操作函数集为hidraw_ops。
        result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
        if (result < 0)
            goto error_class;
    
        printk(KERN_INFO "hidraw: raw HID events driver (C) Jiri Kosina
    ");
    out:
        return result;
    
    error_class:
        class_destroy(hidraw_class);
    error_cdev:
        unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
        goto out;
    }
    
    void hidraw_exit(void)
    {
        dev_t dev_id = MKDEV(hidraw_major, 0);
    
        cdev_del(&hidraw_cdev);
        class_destroy(hidraw_class);
        unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
    
    }

    对于hidraw设备的操作,都在hidraw_ops中体现,包括open/close/read/write/ioctl,以及poll、fasync。

    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,
        .fasync =    hidraw_fasync,
    #ifdef CONFIG_COMPAT
        .compat_ioctl   = hidraw_ioctl,
    #endif
        .llseek =    noop_llseek,
    };
    
    static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
    {
        struct hidraw_list *list = file->private_data;
        int ret = 0, len;
        DECLARE_WAITQUEUE(wait, current);
    
        mutex_lock(&list->read_mutex);
    
        while (ret == 0) {
            if (list->head == list->tail) {
                add_wait_queue(&list->hidraw->wait, &wait);
                set_current_state(TASK_INTERRUPTIBLE);
    
                while (list->head == list->tail) {
                    if (signal_pending(current)) {
                        ret = -ERESTARTSYS;
                        break;
                    }
                    if (!list->hidraw->exist) {
                        ret = -EIO;
                        break;
                    }
                    if (file->f_flags & O_NONBLOCK) {
                        ret = -EAGAIN;
                        break;
                    }
    
                    /* allow O_NONBLOCK to work well from other threads */
                    mutex_unlock(&list->read_mutex);
                    schedule();
                    mutex_lock(&list->read_mutex);
                    set_current_state(TASK_INTERRUPTIBLE);
                }
    
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&list->hidraw->wait, &wait);
            }
    
            if (ret)
                goto out;
    
            len = list->buffer[list->tail].len > count ?
                count : list->buffer[list->tail].len;
    
            if (list->buffer[list->tail].value) {
                if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
                    ret = -EFAULT;
                    goto out;
                }
                ret = len;
            }
    
            kfree(list->buffer[list->tail].value);
            list->buffer[list->tail].value = NULL;
            list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
        }
    out:
        mutex_unlock(&list->read_mutex);
        return ret;
    }
    
    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_inode(file));
        struct hid_device *dev;
        __u8 *buf;
        int ret = 0;
    
        if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
            ret = -ENODEV;
            goto out;
        }
    
        dev = hidraw_table[minor]->hid;-----------------------------------------------根据minor号找到对应hidraw设备的hid_device。
    ...
        buf = memdup_user(buffer, count);
        if (IS_ERR(buf)) {
            ret = PTR_ERR(buf);
            goto out;
        }
    
        if ((report_type == HID_OUTPUT_REPORT) &&
            !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
            ret = hid_hw_output_report(dev, buf, count);
            if (ret != -ENOSYS)
                goto out_free;
        }
    
        ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
                    HID_REQ_SET_REPORT);----------------------------------------------调用实际硬件接口发送report,比如usb、bluetooth等。
    
    out_free:
        kfree(buf);
    out:
        return ret;
    }
    
    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;
    }
    
    static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
    {
        unsigned int minor = iminor(file_inode(file));
        struct hid_device *dev;
        __u8 *buf;
        int ret = 0, len;
        unsigned char report_number;
    
        dev = hidraw_table[minor]->hid;
    ...
        buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
        if (!buf) {
            ret = -ENOMEM;
            goto out;
        }
    
        if (copy_from_user(&report_number, buffer, 1)) {
            ret = -EFAULT;
            goto out_free;
        }
    
        ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
                     HID_REQ_GET_REPORT);---------------------------------------------从硬件接口接收数据。
    ...
        if (copy_to_user(buffer, buf, len)) {
            ret = -EFAULT;
            goto out_free;
        }
    
        ret = len;
    
    out_free:
        kfree(buf);
    out:
        return ret;
    }
    
    static unsigned int hidraw_poll(struct file *file, poll_table *wait)
    {
        struct hidraw_list *list = file->private_data;
    
        poll_wait(file, &list->hidraw->wait, wait);
        if (list->head != list->tail)
            return POLLIN | POLLRDNORM;
        if (!list->hidraw->exist)
            return POLLERR | POLLHUP;
        return 0;
    }
    
    static int hidraw_open(struct inode *inode, struct file *file)
    {
        unsigned int minor = iminor(inode);
        struct hidraw *dev;
        struct hidraw_list *list;
        unsigned long flags;
        int err = 0;
    
        if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
            err = -ENOMEM;
            goto out;
        }
    
        mutex_lock(&minors_lock);
        if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
            err = -ENODEV;
            goto out_unlock;
        }
    
        dev = hidraw_table[minor];
        if (!dev->open++) {
            err = hid_hw_power(dev->hid, PM_HINT_FULLON);--------------调用底层设备即具体接口的power()函数,hdev->ll_driver->power()。
            if (err < 0) {
                dev->open--;
                goto out_unlock;
            }
    
            err = hid_hw_open(dev->hid);-------------------------------调用底层设备的open()函数,hdev->ll_driver->open()。
            if (err < 0) {
                hid_hw_power(dev->hid, PM_HINT_NORMAL);
                dev->open--;
                goto out_unlock;
            }
        }
    
        list->hidraw = hidraw_table[minor];
        mutex_init(&list->read_mutex);
        spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
        list_add_tail(&list->node, &hidraw_table[minor]->list);
        spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
        file->private_data = list;
    ...
    }
    
    static int hidraw_fasync(int fd, struct file *file, int on)
    {
        struct hidraw_list *list = file->private_data;
    
        return fasync_helper(fd, file, on, &list->fasync);--------------发送异步通知信号。
    }
    
    static void drop_ref(struct hidraw *hidraw, int exists_bit)
    {
        if (exists_bit) {
            hidraw->exist = 0;
            if (hidraw->open) {
                hid_hw_close(hidraw->hid);
                wake_up_interruptible(&hidraw->wait);
            }
            device_destroy(hidraw_class,
                       MKDEV(hidraw_major, hidraw->minor));
        } else {
            --hidraw->open;---------------------------------------------打开计算减1。
        }
        if (!hidraw->open) {--------------------------------------------当计数为0后,开始释放资源。
            if (!hidraw->exist) {
                hidraw_table[hidraw->minor] = NULL;
                kfree(hidraw);
            } else {
                /* close device for last reader */
                hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
                hid_hw_close(hidraw->hid);
            }
        }
    }
    
    static int hidraw_release(struct inode * inode, struct file * file)
    {
        unsigned int minor = iminor(inode);
        struct hidraw_list *list = file->private_data;
        unsigned long flags;
    
        mutex_lock(&minors_lock);
    
        spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
        list_del(&list->node);
        spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
        kfree(list);
    
        drop_ref(hidraw_table[minor], 0);
    
        mutex_unlock(&minors_lock);
        return 0;
    }
    
    static long hidraw_ioctl(struct file *file, unsigned int cmd,
                                unsigned long arg)
    {
        struct inode *inode = file_inode(file);
        unsigned int minor = iminor(inode);
        long ret = 0;
        struct hidraw *dev;
        void __user *user_arg = (void __user*) arg;
    
        mutex_lock(&minors_lock);
        dev = hidraw_table[minor];
        if (!dev) {
            ret = -ENODEV;
            goto out;
        }
    
        switch (cmd) {
            case HIDIOCGRDESCSIZE:----------------------------------------------Get report descriptor size。
                if (put_user(dev->hid->rsize, (int __user *)arg))
                    ret = -EFAULT;
                break;
    
            case HIDIOCGRDESC:--------------------------------------------------Get report descriptor。
                {
                    __u32 len;
    
                    if (get_user(len, (int __user *)arg))
                        ret = -EFAULT;
                    else if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
                        ret = -EINVAL;
                    else if (copy_to_user(user_arg + offsetof(
                        struct hidraw_report_descriptor,
                        value[0]),
                        dev->hid->rdesc,
                        min(dev->hid->rsize, len)))
                        ret = -EFAULT;
                    break;
                }
            case HIDIOCGRAWINFO:------------------------------------------------Get raw info,包括bus类型,vid和pid。
                {
                    struct hidraw_devinfo dinfo;
    
                    dinfo.bustype = dev->hid->bus;
                    dinfo.vendor = dev->hid->vendor;
                    dinfo.product = dev->hid->product;
                    if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
                        ret = -EFAULT;
                    break;
                }
            default:
                {
                    struct hid_device *hid = dev->hid;
                    if (_IOC_TYPE(cmd) != 'H') {
                        ret = -EINVAL;
                        break;
                    }
    
                    if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {-------------Send a feature report。
                        int len = _IOC_SIZE(cmd);
                        ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
                        break;
                    }
                    if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {-------------Get a feature report。
                        int len = _IOC_SIZE(cmd);
                        ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
                        break;
                    }
    
                    /* Begin Read-only ioctls. */
                    if (_IOC_DIR(cmd) != _IOC_READ) {
                        ret = -EINVAL;
                        break;
                    }
    
                    if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {--------------Get raw name。
                        int len = strlen(hid->name) + 1;
                        if (len > _IOC_SIZE(cmd))
                            len = _IOC_SIZE(cmd);
                        ret = copy_to_user(user_arg, hid->name, len) ?
                            -EFAULT : len;
                        break;
                    }
    
                    if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {---------------Get physical address。
                        int len = strlen(hid->phys) + 1;
                        if (len > _IOC_SIZE(cmd))
                            len = _IOC_SIZE(cmd);
                        ret = copy_to_user(user_arg, hid->phys, len) ?
                            -EFAULT : len;
                        break;
                    }
                }
    
            ret = -ENOTTY;
        }
    out:
        mutex_unlock(&minors_lock);
        return ret;
    }

    由于一个系统下可能存在多个hidraw设备,常通过HIDIOCGRAWINFO获取信息,判断对应的hidraw设备。

    2.3 创建hidraw设备

    int hidraw_connect(struct hid_device *hid)
    {
        int minor, result;
        struct hidraw *dev;
    
        /* we accept any HID device, all applications */
    
        dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
        if (!dev)
            return -ENOMEM;
    
        result = -EINVAL;
    
        mutex_lock(&minors_lock);
    
        for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {--------------------分配hidraw设备的minor号,并将dev赋给hidraw_table[]。
            if (hidraw_table[minor])
                continue;
            hidraw_table[minor] = dev;
            result = 0;
            break;
        }
    
        if (result) {
            mutex_unlock(&minors_lock);
            kfree(dev);
            goto out;
        }
    
        dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
                     NULL, "%s%d", "hidraw", minor);------------------------------创建/dev/hidrawX设备节点。
    
        if (IS_ERR(dev->dev)) {
            hidraw_table[minor] = NULL;
            mutex_unlock(&minors_lock);
            result = PTR_ERR(dev->dev);
            kfree(dev);
            goto out;
        }
    
        init_waitqueue_head(&dev->wait);
        spin_lock_init(&dev->list_lock);
        INIT_LIST_HEAD(&dev->list);
    
        dev->hid = hid;
        dev->minor = minor;
    
        dev->exist = 1;
        hid->hidraw = dev;
    
        mutex_unlock(&minors_lock);
    out:
        return result;
    
    }
    EXPORT_SYMBOL_GPL(hidraw_connect);
    
    void hidraw_disconnect(struct hid_device *hid)
    {
        struct hidraw *hidraw = hid->hidraw;
    
        mutex_lock(&minors_lock);
    
        drop_ref(hidraw, 1);
    
        mutex_unlock(&minors_lock);
    }
    EXPORT_SYMBOL_GPL(hidraw_disconnect);

    所以hidraw的驱动分为两部分,一是hidraw_init()发起的整个hidraw设备驱动的初始化,二是底层驱动检测到hidraw设备后通过hidraw_connect()/hidraw_disconnect()创建或者销毁设备。

    当USB/Bluetooth检查到设备是hidraw类型之后,就会调用hidraw提供的接口创建设备,表现为创建节点/dev/hidrawx。

    后续用户空间程序对/dev/hidrawx进行read/write/ioctl等操作。

    3. hidraw测试程序

    内核提供了一个示例程序hid-example.c,下面结合内核代码简单分析一下。遍历/dev下所有的hidraw设备,然后读取信息。

    /* Linux */
    #include <linux/types.h>
    #include <linux/input.h>
    #include <linux/hidraw.h>
    #include <dirent.h>
    
    #ifndef HIDIOCSFEATURE
    #warning Please have your distro update the userspace kernel headers
    #define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
    #define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
    #endif
    
    /* Unix */
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    /* C */
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <errno.h>
    
    const char *bus_str(int bus);
    
    int main(int argc, char **argv)
    {
        int fd;
        int i, res, desc_size = 0;
        char buf[256];
        struct hidraw_report_descriptor rpt_desc;
        struct hidraw_devinfo info;
        char device[32] = "/dev/hidraw0";
        DIR *dir = NULL;
        struct dirent *ptr;
    
        /* Open dir /dev. */
        dir = opendir("/dev");-------------------------------------------------打开/dev目录。
        if(!dir) {
            perror("Popen dir failed...");
            return -ENOENT;
        }
    
        /*  */
        while(ptr = readdir(dir)) {--------------------------------------------遍历/dev目录下所有的文件。
            if(ptr->d_type != DT_CHR)------------------------------------------判断设备是否为字符设备,其他设备包括DT_UNKNOWN/DT_FIFO/DT_CHR DT_DIR/DT_BLK/DT_REG/DT_LNK/DT_SOCK/DT_WHT。
    continue;
    if(!strncmp(ptr->d_name, "hidraw", 6)) {
    
                snprintf(device, sizeof(device), "%s/%s", "/dev", ptr->d_name);
    
                /* Open the Device with non-blocking reads. In real life,
                   don't use a hard coded path; use libudev instead. */
                fd = open(device, O_RDWR|O_NONBLOCK);--------------------------打开hidraw设备,对应内核的hidraw_open()if (fd < 0) {
                    printf("Unable to open device %s.
    ", device);
                    return 1;
                }
    
                memset(&rpt_desc, 0x0, sizeof(rpt_desc));
                memset(&info, 0x0, sizeof(info));
                memset(buf, 0x0, sizeof(buf));
    
                printf("
    
    =================================Device %s info=================================
    ", device);
                /* Get Raw Name */
                res = ioctl(fd, HIDIOCGRAWNAME(256), buf);---------------------对应hidraw_ioctl()的HIDIOCGRAWNAMEif (res < 0)
                    perror("HIDIOCGRAWNAME");
                else
                    printf("Raw Name: %s
    ", buf);
    
                /* Get Physical Location */
                res = ioctl(fd, HIDIOCGRAWPHYS(256), buf);---------------------对应HIDIOCGRAWPHYSif (res < 0)
                    perror("HIDIOCGRAWPHYS");
                else
                    printf("Raw Phys: %s
    ", buf);
    
                /* Get Raw Info */
                res = ioctl(fd, HIDIOCGRAWINFO, &info);-------------------------对应HIDIOCGRAWINFOif (res < 0) {
                    perror("HIDIOCGRAWINFO");
                } else {
                    printf("Raw Info:
    ");
                    printf("	bustype: %d (%s)
    ",
                        info.bustype, bus_str(info.bustype));
                    printf("	vendor: 0x%04hx
    ", info.vendor);
                    printf("	product: 0x%04hx
    ", info.product);
                }
    
                /* Get Report Descriptor Size */
                res = ioctl(fd, HIDIOCGRDESCSIZE, &desc_size);------------------对应HIDIOCGRDESCSIZE
                if (res < 0)
                    perror("HIDIOCGRDESCSIZE");
                else
                    printf("Report Descriptor Size: %d
    ", desc_size);
    
                /* Get Report Descriptor */
                rpt_desc.size = desc_size;
                res = ioctl(fd, HIDIOCGRDESC, &rpt_desc);------------------------对应HIDIOCGRDESCif (res < 0) {
                    perror("HIDIOCGRDESC");
                } else {
                    printf("Report Descriptor:
    ");
                    for (i = 0; i < rpt_desc.size; i++)
                        printf("%hhx ", rpt_desc.value[i]);
                    puts("
    ");
                }
    
                /* Set Feature */
                buf[0] = 0x9; /* Report Number */
                buf[1] = 0xff;
                buf[2] = 0xff;
                buf[3] = 0xff;
                res = ioctl(fd, HIDIOCSFEATURE(4), buf);-------------------------对应HIDIOCSFEATUREif (res < 0)
                    perror("HIDIOCSFEATURE");
                else
                    printf("ioctl HIDIOCGFEATURE returned: %d
    ", res);
    
                /* Get Feature */
                buf[0] = 0x9; /* Report Number */
                res = ioctl(fd, HIDIOCGFEATURE(256), buf);-----------------------对应HIDIOCGFEATUREif (res < 0) {
                    perror("HIDIOCGFEATURE");
                } else {
                    printf("ioctl HIDIOCGFEATURE returned: %d
    ", res);
                    printf("Report data (not containing the report number):
    	");
                    for (i = 0; i < res; i++)
                        printf("%hhx ", buf[i]);
                    puts("
    ");
                }
    
                /* Send a Report to the Device */
                buf[0] = 0x1; /* Report Number */
                buf[1] = 0x77;
                res = write(fd, buf, 2);
                if (res < 0) {
                    printf("Error: %d
    ", errno);
                    perror("write");
                } else {
                    printf("write() wrote %d bytes
    ", res);
                }
    
                /* Get a report from the device */
                res = read(fd, buf, 16);
                if (res < 0) {
                    perror("read");
                } else {
                    printf("read() read %d bytes:
    	", res);
                    for (i = 0; i < res; i++)
                        printf("%hhx ", buf[i]);
                    puts("
    ");
                }
    
                close(fd);
            }
        }
        return 0;
    }
    
    const char *
    bus_str(int bus)
    {
        switch (bus) {
        case BUS_USB:
            return "USB";
            break;
        case BUS_HIL:
            return "HIL";
            break;
        case BUS_BLUETOOTH:
            return "Bluetooth";
            break;
        case BUS_VIRTUAL:
            return "Virtual";
            break;
        default:
            return "Other";
            break;
        }
    } 

    综合来看hidraw设备是hid的一种,传输裸数据,对应的底层硬件可能是USB/Bluetooth等。

    通过对hidraw设备的操作,ioctl可以配置hidraw设备,read/write可以对hidraw设备进行读写。

    参考文档:

    HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices》:包括简要介绍以及hidraw相关API介绍,尤其是ioctl命令。

    Linux之访问/dev/hidraw》是对上文的翻译,附加了两个示例。 

  • 相关阅读:
    ES集群性能调优链接汇总
    【转】dmesg 时间转换
    广师大笔记汉诺塔
    广师大python学习笔记求派的值
    155. 最小栈(c++)
    160. 相交链表(c++)
    论文 数据集总结
    论文阅读 总结 复习
    121. 买卖股票的最佳时机(c++)
    9. 回文数(c++)
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/11418391.html
Copyright © 2011-2022 走看看