linux/drivers/hid/hidraw.c
<<
>>
Prefs
   1/*
   2 * HID raw devices, giving access to raw HID events.
   3 *
   4 * In comparison to hiddev, this device does not process the
   5 * hid events at all (no parsing, no lookups). This lets applications
   6 * to work on raw hid events as they want to, and avoids a need to
   7 * use a transport-specific userspace libhid/libusb libraries.
   8 *
   9 *  Copyright (c) 2007-2014 Jiri Kosina
  10 */
  11
  12/*
  13 * This program is free software; you can redistribute it and/or modify it
  14 * under the terms and conditions of the GNU General Public License,
  15 * version 2, as published by the Free Software Foundation.
  16 *
  17 * You should have received a copy of the GNU General Public License along with
  18 * this program; if not, write to the Free Software Foundation, Inc.,
  19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  20 */
  21
  22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  23
  24#include <linux/fs.h>
  25#include <linux/module.h>
  26#include <linux/errno.h>
  27#include <linux/kernel.h>
  28#include <linux/init.h>
  29#include <linux/cdev.h>
  30#include <linux/poll.h>
  31#include <linux/device.h>
  32#include <linux/major.h>
  33#include <linux/slab.h>
  34#include <linux/hid.h>
  35#include <linux/mutex.h>
  36#include <linux/sched/signal.h>
  37#include <linux/string.h>
  38
  39#include <linux/hidraw.h>
  40
  41static int hidraw_major;
  42static struct cdev hidraw_cdev;
  43static struct class *hidraw_class;
  44static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
  45static DEFINE_MUTEX(minors_lock);
  46
  47static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
  48{
  49        struct hidraw_list *list = file->private_data;
  50        int ret = 0, len;
  51        DECLARE_WAITQUEUE(wait, current);
  52
  53        mutex_lock(&list->read_mutex);
  54
  55        while (ret == 0) {
  56                if (list->head == list->tail) {
  57                        add_wait_queue(&list->hidraw->wait, &wait);
  58                        set_current_state(TASK_INTERRUPTIBLE);
  59
  60                        while (list->head == list->tail) {
  61                                if (signal_pending(current)) {
  62                                        ret = -ERESTARTSYS;
  63                                        break;
  64                                }
  65                                if (!list->hidraw->exist) {
  66                                        ret = -EIO;
  67                                        break;
  68                                }
  69                                if (file->f_flags & O_NONBLOCK) {
  70                                        ret = -EAGAIN;
  71                                        break;
  72                                }
  73
  74                                /* allow O_NONBLOCK to work well from other threads */
  75                                mutex_unlock(&list->read_mutex);
  76                                schedule();
  77                                mutex_lock(&list->read_mutex);
  78                                set_current_state(TASK_INTERRUPTIBLE);
  79                        }
  80
  81                        set_current_state(TASK_RUNNING);
  82                        remove_wait_queue(&list->hidraw->wait, &wait);
  83                }
  84
  85                if (ret)
  86                        goto out;
  87
  88                len = list->buffer[list->tail].len > count ?
  89                        count : list->buffer[list->tail].len;
  90
  91                if (list->buffer[list->tail].value) {
  92                        if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
  93                                ret = -EFAULT;
  94                                goto out;
  95                        }
  96                        ret = len;
  97                }
  98
  99                kfree(list->buffer[list->tail].value);
 100                list->buffer[list->tail].value = NULL;
 101                list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
 102        }
 103out:
 104        mutex_unlock(&list->read_mutex);
 105        return ret;
 106}
 107
 108/*
 109 * The first byte of the report buffer is expected to be a report number.
 110 *
 111 * This function is to be called with the minors_lock mutex held.
 112 */
 113static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
 114{
 115        unsigned int minor = iminor(file_inode(file));
 116        struct hid_device *dev;
 117        __u8 *buf;
 118        int ret = 0;
 119
 120        if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
 121                ret = -ENODEV;
 122                goto out;
 123        }
 124
 125        dev = hidraw_table[minor]->hid;
 126
 127        if (count > HID_MAX_BUFFER_SIZE) {
 128                hid_warn(dev, "pid %d passed too large report\n",
 129                         task_pid_nr(current));
 130                ret = -EINVAL;
 131                goto out;
 132        }
 133
 134        if (count < 2) {
 135                hid_warn(dev, "pid %d passed too short report\n",
 136                         task_pid_nr(current));
 137                ret = -EINVAL;
 138                goto out;
 139        }
 140
 141        buf = memdup_user(buffer, count);
 142        if (IS_ERR(buf)) {
 143                ret = PTR_ERR(buf);
 144                goto out;
 145        }
 146
 147        if ((report_type == HID_OUTPUT_REPORT) &&
 148            !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
 149                ret = hid_hw_output_report(dev, buf, count);
 150                /*
 151                 * compatibility with old implementation of USB-HID and I2C-HID:
 152                 * if the device does not support receiving output reports,
 153                 * on an interrupt endpoint, fallback to SET_REPORT HID command.
 154                 */
 155                if (ret != -ENOSYS)
 156                        goto out_free;
 157        }
 158
 159        ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
 160                                HID_REQ_SET_REPORT);
 161
 162out_free:
 163        kfree(buf);
 164out:
 165        return ret;
 166}
 167
 168static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 169{
 170        ssize_t ret;
 171        mutex_lock(&minors_lock);
 172        ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
 173        mutex_unlock(&minors_lock);
 174        return ret;
 175}
 176
 177
 178/*
 179 * This function performs a Get_Report transfer over the control endpoint
 180 * per section 7.2.1 of the HID specification, version 1.1.  The first byte
 181 * of buffer is the report number to request, or 0x0 if the defice does not
 182 * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
 183 * or HID_INPUT_REPORT.
 184 *
 185 * This function is to be called with the minors_lock mutex held.
 186 */
 187static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
 188{
 189        unsigned int minor = iminor(file_inode(file));
 190        struct hid_device *dev;
 191        __u8 *buf;
 192        int ret = 0, len;
 193        unsigned char report_number;
 194
 195        if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
 196                ret = -ENODEV;
 197                goto out;
 198        }
 199
 200        dev = hidraw_table[minor]->hid;
 201
 202        if (!dev->ll_driver->raw_request) {
 203                ret = -ENODEV;
 204                goto out;
 205        }
 206
 207        if (count > HID_MAX_BUFFER_SIZE) {
 208                printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
 209                                task_pid_nr(current));
 210                ret = -EINVAL;
 211                goto out;
 212        }
 213
 214        if (count < 2) {
 215                printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
 216                                task_pid_nr(current));
 217                ret = -EINVAL;
 218                goto out;
 219        }
 220
 221        buf = kmalloc(count, GFP_KERNEL);
 222        if (!buf) {
 223                ret = -ENOMEM;
 224                goto out;
 225        }
 226
 227        /*
 228         * Read the first byte from the user. This is the report number,
 229         * which is passed to hid_hw_raw_request().
 230         */
 231        if (copy_from_user(&report_number, buffer, 1)) {
 232                ret = -EFAULT;
 233                goto out_free;
 234        }
 235
 236        ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
 237                                 HID_REQ_GET_REPORT);
 238
 239        if (ret < 0)
 240                goto out_free;
 241
 242        len = (ret < count) ? ret : count;
 243
 244        if (copy_to_user(buffer, buf, len)) {
 245                ret = -EFAULT;
 246                goto out_free;
 247        }
 248
 249        ret = len;
 250
 251out_free:
 252        kfree(buf);
 253out:
 254        return ret;
 255}
 256
 257static __poll_t hidraw_poll(struct file *file, poll_table *wait)
 258{
 259        struct hidraw_list *list = file->private_data;
 260
 261        poll_wait(file, &list->hidraw->wait, wait);
 262        if (list->head != list->tail)
 263                return EPOLLIN | EPOLLRDNORM;
 264        if (!list->hidraw->exist)
 265                return EPOLLERR | EPOLLHUP;
 266        return 0;
 267}
 268
 269static int hidraw_open(struct inode *inode, struct file *file)
 270{
 271        unsigned int minor = iminor(inode);
 272        struct hidraw *dev;
 273        struct hidraw_list *list;
 274        unsigned long flags;
 275        int err = 0;
 276
 277        if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
 278                err = -ENOMEM;
 279                goto out;
 280        }
 281
 282        mutex_lock(&minors_lock);
 283        if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
 284                err = -ENODEV;
 285                goto out_unlock;
 286        }
 287
 288        dev = hidraw_table[minor];
 289        if (!dev->open++) {
 290                err = hid_hw_power(dev->hid, PM_HINT_FULLON);
 291                if (err < 0) {
 292                        dev->open--;
 293                        goto out_unlock;
 294                }
 295
 296                err = hid_hw_open(dev->hid);
 297                if (err < 0) {
 298                        hid_hw_power(dev->hid, PM_HINT_NORMAL);
 299                        dev->open--;
 300                        goto out_unlock;
 301                }
 302        }
 303
 304        list->hidraw = hidraw_table[minor];
 305        mutex_init(&list->read_mutex);
 306        spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
 307        list_add_tail(&list->node, &hidraw_table[minor]->list);
 308        spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
 309        file->private_data = list;
 310out_unlock:
 311        mutex_unlock(&minors_lock);
 312out:
 313        if (err < 0)
 314                kfree(list);
 315        return err;
 316
 317}
 318
 319static int hidraw_fasync(int fd, struct file *file, int on)
 320{
 321        struct hidraw_list *list = file->private_data;
 322
 323        return fasync_helper(fd, file, on, &list->fasync);
 324}
 325
 326static void drop_ref(struct hidraw *hidraw, int exists_bit)
 327{
 328        if (exists_bit) {
 329                hidraw->exist = 0;
 330                if (hidraw->open) {
 331                        hid_hw_close(hidraw->hid);
 332                        wake_up_interruptible(&hidraw->wait);
 333                }
 334                device_destroy(hidraw_class,
 335                               MKDEV(hidraw_major, hidraw->minor));
 336        } else {
 337                --hidraw->open;
 338        }
 339        if (!hidraw->open) {
 340                if (!hidraw->exist) {
 341                        hidraw_table[hidraw->minor] = NULL;
 342                        kfree(hidraw);
 343                } else {
 344                        /* close device for last reader */
 345                        hid_hw_close(hidraw->hid);
 346                        hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
 347                }
 348        }
 349}
 350
 351static int hidraw_release(struct inode * inode, struct file * file)
 352{
 353        unsigned int minor = iminor(inode);
 354        struct hidraw_list *list = file->private_data;
 355        unsigned long flags;
 356
 357        mutex_lock(&minors_lock);
 358
 359        spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
 360        list_del(&list->node);
 361        spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
 362        kfree(list);
 363
 364        drop_ref(hidraw_table[minor], 0);
 365
 366        mutex_unlock(&minors_lock);
 367        return 0;
 368}
 369
 370static long hidraw_ioctl(struct file *file, unsigned int cmd,
 371                                                        unsigned long arg)
 372{
 373        struct inode *inode = file_inode(file);
 374        unsigned int minor = iminor(inode);
 375        long ret = 0;
 376        struct hidraw *dev;
 377        void __user *user_arg = (void __user*) arg;
 378
 379        mutex_lock(&minors_lock);
 380        dev = hidraw_table[minor];
 381        if (!dev) {
 382                ret = -ENODEV;
 383                goto out;
 384        }
 385
 386        switch (cmd) {
 387                case HIDIOCGRDESCSIZE:
 388                        if (put_user(dev->hid->rsize, (int __user *)arg))
 389                                ret = -EFAULT;
 390                        break;
 391
 392                case HIDIOCGRDESC:
 393                        {
 394                                __u32 len;
 395
 396                                if (get_user(len, (int __user *)arg))
 397                                        ret = -EFAULT;
 398                                else if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
 399                                        ret = -EINVAL;
 400                                else if (copy_to_user(user_arg + offsetof(
 401                                        struct hidraw_report_descriptor,
 402                                        value[0]),
 403                                        dev->hid->rdesc,
 404                                        min(dev->hid->rsize, len)))
 405                                        ret = -EFAULT;
 406                                break;
 407                        }
 408                case HIDIOCGRAWINFO:
 409                        {
 410                                struct hidraw_devinfo dinfo;
 411
 412                                dinfo.bustype = dev->hid->bus;
 413                                dinfo.vendor = dev->hid->vendor;
 414                                dinfo.product = dev->hid->product;
 415                                if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
 416                                        ret = -EFAULT;
 417                                break;
 418                        }
 419                default:
 420                        {
 421                                struct hid_device *hid = dev->hid;
 422                                if (_IOC_TYPE(cmd) != 'H') {
 423                                        ret = -EINVAL;
 424                                        break;
 425                                }
 426
 427                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
 428                                        int len = _IOC_SIZE(cmd);
 429                                        ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
 430                                        break;
 431                                }
 432                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
 433                                        int len = _IOC_SIZE(cmd);
 434                                        ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
 435                                        break;
 436                                }
 437
 438                                /* Begin Read-only ioctls. */
 439                                if (_IOC_DIR(cmd) != _IOC_READ) {
 440                                        ret = -EINVAL;
 441                                        break;
 442                                }
 443
 444                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
 445                                        int len = strlen(hid->name) + 1;
 446                                        if (len > _IOC_SIZE(cmd))
 447                                                len = _IOC_SIZE(cmd);
 448                                        ret = copy_to_user(user_arg, hid->name, len) ?
 449                                                -EFAULT : len;
 450                                        break;
 451                                }
 452
 453                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
 454                                        int len = strlen(hid->phys) + 1;
 455                                        if (len > _IOC_SIZE(cmd))
 456                                                len = _IOC_SIZE(cmd);
 457                                        ret = copy_to_user(user_arg, hid->phys, len) ?
 458                                                -EFAULT : len;
 459                                        break;
 460                                }
 461                        }
 462
 463                ret = -ENOTTY;
 464        }
 465out:
 466        mutex_unlock(&minors_lock);
 467        return ret;
 468}
 469
 470static const struct file_operations hidraw_ops = {
 471        .owner =        THIS_MODULE,
 472        .read =         hidraw_read,
 473        .write =        hidraw_write,
 474        .poll =         hidraw_poll,
 475        .open =         hidraw_open,
 476        .release =      hidraw_release,
 477        .unlocked_ioctl = hidraw_ioctl,
 478        .fasync =       hidraw_fasync,
 479#ifdef CONFIG_COMPAT
 480        .compat_ioctl   = hidraw_ioctl,
 481#endif
 482        .llseek =       noop_llseek,
 483};
 484
 485int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
 486{
 487        struct hidraw *dev = hid->hidraw;
 488        struct hidraw_list *list;
 489        int ret = 0;
 490        unsigned long flags;
 491
 492        spin_lock_irqsave(&dev->list_lock, flags);
 493        list_for_each_entry(list, &dev->list, node) {
 494                int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
 495
 496                if (new_head == list->tail)
 497                        continue;
 498
 499                if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
 500                        ret = -ENOMEM;
 501                        break;
 502                }
 503                list->buffer[list->head].len = len;
 504                list->head = new_head;
 505                kill_fasync(&list->fasync, SIGIO, POLL_IN);
 506        }
 507        spin_unlock_irqrestore(&dev->list_lock, flags);
 508
 509        wake_up_interruptible(&dev->wait);
 510        return ret;
 511}
 512EXPORT_SYMBOL_GPL(hidraw_report_event);
 513
 514int hidraw_connect(struct hid_device *hid)
 515{
 516        int minor, result;
 517        struct hidraw *dev;
 518
 519        /* we accept any HID device, all applications */
 520
 521        dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
 522        if (!dev)
 523                return -ENOMEM;
 524
 525        result = -EINVAL;
 526
 527        mutex_lock(&minors_lock);
 528
 529        for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
 530                if (hidraw_table[minor])
 531                        continue;
 532                hidraw_table[minor] = dev;
 533                result = 0;
 534                break;
 535        }
 536
 537        if (result) {
 538                mutex_unlock(&minors_lock);
 539                kfree(dev);
 540                goto out;
 541        }
 542
 543        dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
 544                                 NULL, "%s%d", "hidraw", minor);
 545
 546        if (IS_ERR(dev->dev)) {
 547                hidraw_table[minor] = NULL;
 548                mutex_unlock(&minors_lock);
 549                result = PTR_ERR(dev->dev);
 550                kfree(dev);
 551                goto out;
 552        }
 553
 554        init_waitqueue_head(&dev->wait);
 555        spin_lock_init(&dev->list_lock);
 556        INIT_LIST_HEAD(&dev->list);
 557
 558        dev->hid = hid;
 559        dev->minor = minor;
 560
 561        dev->exist = 1;
 562        hid->hidraw = dev;
 563
 564        mutex_unlock(&minors_lock);
 565out:
 566        return result;
 567
 568}
 569EXPORT_SYMBOL_GPL(hidraw_connect);
 570
 571void hidraw_disconnect(struct hid_device *hid)
 572{
 573        struct hidraw *hidraw = hid->hidraw;
 574
 575        mutex_lock(&minors_lock);
 576
 577        drop_ref(hidraw, 1);
 578
 579        mutex_unlock(&minors_lock);
 580}
 581EXPORT_SYMBOL_GPL(hidraw_disconnect);
 582
 583int __init hidraw_init(void)
 584{
 585        int result;
 586        dev_t dev_id;
 587
 588        result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
 589                        HIDRAW_MAX_DEVICES, "hidraw");
 590        if (result < 0) {
 591                pr_warn("can't get major number\n");
 592                goto out;
 593        }
 594
 595        hidraw_major = MAJOR(dev_id);
 596
 597        hidraw_class = class_create(THIS_MODULE, "hidraw");
 598        if (IS_ERR(hidraw_class)) {
 599                result = PTR_ERR(hidraw_class);
 600                goto error_cdev;
 601        }
 602
 603        cdev_init(&hidraw_cdev, &hidraw_ops);
 604        result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
 605        if (result < 0)
 606                goto error_class;
 607
 608        printk(KERN_INFO "hidraw: raw HID events driver (C) Jiri Kosina\n");
 609out:
 610        return result;
 611
 612error_class:
 613        class_destroy(hidraw_class);
 614error_cdev:
 615        unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
 616        goto out;
 617}
 618
 619void hidraw_exit(void)
 620{
 621        dev_t dev_id = MKDEV(hidraw_major, 0);
 622
 623        cdev_del(&hidraw_cdev);
 624        class_destroy(hidraw_class);
 625        unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
 626
 627}
 628