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 (file->f_flags & O_NONBLOCK) {
  61                                        ret = -EAGAIN;
  62                                        break;
  63                                }
  64                                if (signal_pending(current)) {
  65                                        ret = -ERESTARTSYS;
  66                                        break;
  67                                }
  68                                if (!list->hidraw->exist) {
  69                                        ret = -EIO;
  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_release(struct inode * inode, struct file * file)
 299{
 300        unsigned int minor = iminor(inode);
 301        struct hidraw *dev;
 302        struct hidraw_list *list = file->private_data;
 303        int ret;
 304        int i;
 305
 306        mutex_lock(&minors_lock);
 307        if (!hidraw_table[minor]) {
 308                ret = -ENODEV;
 309                goto unlock;
 310        }
 311
 312        list_del(&list->node);
 313        dev = hidraw_table[minor];
 314        if (!--dev->open) {
 315                if (list->hidraw->exist) {
 316                        hid_hw_power(dev->hid, PM_HINT_NORMAL);
 317                        hid_hw_close(dev->hid);
 318                } else {
 319                        kfree(list->hidraw);
 320                }
 321        }
 322
 323        for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
 324                kfree(list->buffer[i].value);
 325        kfree(list);
 326        ret = 0;
 327unlock:
 328        mutex_unlock(&minors_lock);
 329
 330        return ret;
 331}
 332
 333static long hidraw_ioctl(struct file *file, unsigned int cmd,
 334                                                        unsigned long arg)
 335{
 336        struct inode *inode = file->f_path.dentry->d_inode;
 337        unsigned int minor = iminor(inode);
 338        long ret = 0;
 339        struct hidraw *dev;
 340        void __user *user_arg = (void __user*) arg;
 341
 342        mutex_lock(&minors_lock);
 343        dev = hidraw_table[minor];
 344        if (!dev) {
 345                ret = -ENODEV;
 346                goto out;
 347        }
 348
 349        switch (cmd) {
 350                case HIDIOCGRDESCSIZE:
 351                        if (put_user(dev->hid->rsize, (int __user *)arg))
 352                                ret = -EFAULT;
 353                        break;
 354
 355                case HIDIOCGRDESC:
 356                        {
 357                                __u32 len;
 358
 359                                if (get_user(len, (int __user *)arg))
 360                                        ret = -EFAULT;
 361                                else if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
 362                                        ret = -EINVAL;
 363                                else if (copy_to_user(user_arg + offsetof(
 364                                        struct hidraw_report_descriptor,
 365                                        value[0]),
 366                                        dev->hid->rdesc,
 367                                        min(dev->hid->rsize, len)))
 368                                        ret = -EFAULT;
 369                                break;
 370                        }
 371                case HIDIOCGRAWINFO:
 372                        {
 373                                struct hidraw_devinfo dinfo;
 374
 375                                dinfo.bustype = dev->hid->bus;
 376                                dinfo.vendor = dev->hid->vendor;
 377                                dinfo.product = dev->hid->product;
 378                                if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
 379                                        ret = -EFAULT;
 380                                break;
 381                        }
 382                default:
 383                        {
 384                                struct hid_device *hid = dev->hid;
 385                                if (_IOC_TYPE(cmd) != 'H') {
 386                                        ret = -EINVAL;
 387                                        break;
 388                                }
 389
 390                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
 391                                        int len = _IOC_SIZE(cmd);
 392                                        ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
 393                                        break;
 394                                }
 395                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
 396                                        int len = _IOC_SIZE(cmd);
 397                                        ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
 398                                        break;
 399                                }
 400
 401                                /* Begin Read-only ioctls. */
 402                                if (_IOC_DIR(cmd) != _IOC_READ) {
 403                                        ret = -EINVAL;
 404                                        break;
 405                                }
 406
 407                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
 408                                        int len = strlen(hid->name) + 1;
 409                                        if (len > _IOC_SIZE(cmd))
 410                                                len = _IOC_SIZE(cmd);
 411                                        ret = copy_to_user(user_arg, hid->name, len) ?
 412                                                -EFAULT : len;
 413                                        break;
 414                                }
 415
 416                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
 417                                        int len = strlen(hid->phys) + 1;
 418                                        if (len > _IOC_SIZE(cmd))
 419                                                len = _IOC_SIZE(cmd);
 420                                        ret = copy_to_user(user_arg, hid->phys, len) ?
 421                                                -EFAULT : len;
 422                                        break;
 423                                }
 424                        }
 425
 426                ret = -ENOTTY;
 427        }
 428out:
 429        mutex_unlock(&minors_lock);
 430        return ret;
 431}
 432
 433static const struct file_operations hidraw_ops = {
 434        .owner =        THIS_MODULE,
 435        .read =         hidraw_read,
 436        .write =        hidraw_write,
 437        .poll =         hidraw_poll,
 438        .open =         hidraw_open,
 439        .release =      hidraw_release,
 440        .unlocked_ioctl = hidraw_ioctl,
 441#ifdef CONFIG_COMPAT
 442        .compat_ioctl   = hidraw_ioctl,
 443#endif
 444        .llseek =       noop_llseek,
 445};
 446
 447int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
 448{
 449        struct hidraw *dev = hid->hidraw;
 450        struct hidraw_list *list;
 451        int ret = 0;
 452
 453        list_for_each_entry(list, &dev->list, node) {
 454                int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
 455
 456                if (new_head == list->tail)
 457                        continue;
 458
 459                if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
 460                        ret = -ENOMEM;
 461                        break;
 462                }
 463                list->buffer[list->head].len = len;
 464                list->head = new_head;
 465                kill_fasync(&list->fasync, SIGIO, POLL_IN);
 466        }
 467
 468        wake_up_interruptible(&dev->wait);
 469        return ret;
 470}
 471EXPORT_SYMBOL_GPL(hidraw_report_event);
 472
 473int hidraw_connect(struct hid_device *hid)
 474{
 475        int minor, result;
 476        struct hidraw *dev;
 477
 478        /* we accept any HID device, no matter the applications */
 479
 480        dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
 481        if (!dev)
 482                return -ENOMEM;
 483
 484        result = -EINVAL;
 485
 486        mutex_lock(&minors_lock);
 487
 488        for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
 489                if (hidraw_table[minor])
 490                        continue;
 491                hidraw_table[minor] = dev;
 492                result = 0;
 493                break;
 494        }
 495
 496        if (result) {
 497                mutex_unlock(&minors_lock);
 498                kfree(dev);
 499                goto out;
 500        }
 501
 502        dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
 503                                 NULL, "%s%d", "hidraw", minor);
 504
 505        if (IS_ERR(dev->dev)) {
 506                hidraw_table[minor] = NULL;
 507                mutex_unlock(&minors_lock);
 508                result = PTR_ERR(dev->dev);
 509                kfree(dev);
 510                goto out;
 511        }
 512
 513        mutex_unlock(&minors_lock);
 514        init_waitqueue_head(&dev->wait);
 515        INIT_LIST_HEAD(&dev->list);
 516
 517        dev->hid = hid;
 518        dev->minor = minor;
 519
 520        dev->exist = 1;
 521        hid->hidraw = dev;
 522
 523out:
 524        return result;
 525
 526}
 527EXPORT_SYMBOL_GPL(hidraw_connect);
 528
 529void hidraw_disconnect(struct hid_device *hid)
 530{
 531        struct hidraw *hidraw = hid->hidraw;
 532
 533        mutex_lock(&minors_lock);
 534        hidraw->exist = 0;
 535
 536        device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
 537
 538        hidraw_table[hidraw->minor] = NULL;
 539
 540        if (hidraw->open) {
 541                hid_hw_close(hid);
 542                wake_up_interruptible(&hidraw->wait);
 543        } else {
 544                kfree(hidraw);
 545        }
 546        mutex_unlock(&minors_lock);
 547}
 548EXPORT_SYMBOL_GPL(hidraw_disconnect);
 549
 550int __init hidraw_init(void)
 551{
 552        int result;
 553        dev_t dev_id;
 554
 555        result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
 556                        HIDRAW_MAX_DEVICES, "hidraw");
 557
 558        hidraw_major = MAJOR(dev_id);
 559
 560        if (result < 0) {
 561                pr_warn("can't get major number\n");
 562                result = 0;
 563                goto out;
 564        }
 565
 566        hidraw_class = class_create(THIS_MODULE, "hidraw");
 567        if (IS_ERR(hidraw_class)) {
 568                result = PTR_ERR(hidraw_class);
 569                unregister_chrdev(hidraw_major, "hidraw");
 570                goto out;
 571        }
 572
 573        cdev_init(&hidraw_cdev, &hidraw_ops);
 574        cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
 575out:
 576        return result;
 577}
 578
 579void hidraw_exit(void)
 580{
 581        dev_t dev_id = MKDEV(hidraw_major, 0);
 582
 583        cdev_del(&hidraw_cdev);
 584        class_destroy(hidraw_class);
 585        unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
 586
 587}
 588
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.