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