LCOV - code coverage report
Current view: top level - drivers/hid - hidraw.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 14 332 4.2 %
Date: 2022-03-28 13:20:08 Functions: 1 15 6.7 %
Branches: 3 174 1.7 %

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

Generated by: LCOV version 1.14