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