linux/drivers/hid/hid-roccat-common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Roccat common functions for device specific drivers
   4 *
   5 * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
   6 */
   7
   8/*
   9 */
  10
  11#include <linux/hid.h>
  12#include <linux/slab.h>
  13#include <linux/module.h>
  14#include "hid-roccat-common.h"
  15
  16static inline uint16_t roccat_common2_feature_report(uint8_t report_id)
  17{
  18        return 0x300 | report_id;
  19}
  20
  21int roccat_common2_receive(struct usb_device *usb_dev, uint report_id,
  22                void *data, uint size)
  23{
  24        char *buf;
  25        int len;
  26
  27        buf = kmalloc(size, GFP_KERNEL);
  28        if (buf == NULL)
  29                return -ENOMEM;
  30
  31        len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
  32                        HID_REQ_GET_REPORT,
  33                        USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
  34                        roccat_common2_feature_report(report_id),
  35                        0, buf, size, USB_CTRL_SET_TIMEOUT);
  36
  37        memcpy(data, buf, size);
  38        kfree(buf);
  39        return ((len < 0) ? len : ((len != size) ? -EIO : 0));
  40}
  41EXPORT_SYMBOL_GPL(roccat_common2_receive);
  42
  43int roccat_common2_send(struct usb_device *usb_dev, uint report_id,
  44                void const *data, uint size)
  45{
  46        char *buf;
  47        int len;
  48
  49        buf = kmemdup(data, size, GFP_KERNEL);
  50        if (buf == NULL)
  51                return -ENOMEM;
  52
  53        len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
  54                        HID_REQ_SET_REPORT,
  55                        USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
  56                        roccat_common2_feature_report(report_id),
  57                        0, buf, size, USB_CTRL_SET_TIMEOUT);
  58
  59        kfree(buf);
  60        return ((len < 0) ? len : ((len != size) ? -EIO : 0));
  61}
  62EXPORT_SYMBOL_GPL(roccat_common2_send);
  63
  64enum roccat_common2_control_states {
  65        ROCCAT_COMMON_CONTROL_STATUS_CRITICAL = 0,
  66        ROCCAT_COMMON_CONTROL_STATUS_OK = 1,
  67        ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2,
  68        ROCCAT_COMMON_CONTROL_STATUS_BUSY = 3,
  69        ROCCAT_COMMON_CONTROL_STATUS_CRITICAL_NEW = 4,
  70};
  71
  72static int roccat_common2_receive_control_status(struct usb_device *usb_dev)
  73{
  74        int retval;
  75        struct roccat_common2_control control;
  76
  77        do {
  78                msleep(50);
  79                retval = roccat_common2_receive(usb_dev,
  80                                ROCCAT_COMMON_COMMAND_CONTROL,
  81                                &control, sizeof(struct roccat_common2_control));
  82
  83                if (retval)
  84                        return retval;
  85
  86                switch (control.value) {
  87                case ROCCAT_COMMON_CONTROL_STATUS_OK:
  88                        return 0;
  89                case ROCCAT_COMMON_CONTROL_STATUS_BUSY:
  90                        msleep(500);
  91                        continue;
  92                case ROCCAT_COMMON_CONTROL_STATUS_INVALID:
  93                case ROCCAT_COMMON_CONTROL_STATUS_CRITICAL:
  94                case ROCCAT_COMMON_CONTROL_STATUS_CRITICAL_NEW:
  95                        return -EINVAL;
  96                default:
  97                        dev_err(&usb_dev->dev,
  98                                        "roccat_common2_receive_control_status: "
  99                                        "unknown response value 0x%x\n",
 100                                        control.value);
 101                        return -EINVAL;
 102                }
 103
 104        } while (1);
 105}
 106
 107int roccat_common2_send_with_status(struct usb_device *usb_dev,
 108                uint command, void const *buf, uint size)
 109{
 110        int retval;
 111
 112        retval = roccat_common2_send(usb_dev, command, buf, size);
 113        if (retval)
 114                return retval;
 115
 116        msleep(100);
 117
 118        return roccat_common2_receive_control_status(usb_dev);
 119}
 120EXPORT_SYMBOL_GPL(roccat_common2_send_with_status);
 121
 122int roccat_common2_device_init_struct(struct usb_device *usb_dev,
 123                struct roccat_common2_device *dev)
 124{
 125        mutex_init(&dev->lock);
 126        return 0;
 127}
 128EXPORT_SYMBOL_GPL(roccat_common2_device_init_struct);
 129
 130ssize_t roccat_common2_sysfs_read(struct file *fp, struct kobject *kobj,
 131                char *buf, loff_t off, size_t count,
 132                size_t real_size, uint command)
 133{
 134        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 135        struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
 136        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 137        int retval;
 138
 139        if (off >= real_size)
 140                return 0;
 141
 142        if (off != 0 || count != real_size)
 143                return -EINVAL;
 144
 145        mutex_lock(&roccat_dev->lock);
 146        retval = roccat_common2_receive(usb_dev, command, buf, real_size);
 147        mutex_unlock(&roccat_dev->lock);
 148
 149        return retval ? retval : real_size;
 150}
 151EXPORT_SYMBOL_GPL(roccat_common2_sysfs_read);
 152
 153ssize_t roccat_common2_sysfs_write(struct file *fp, struct kobject *kobj,
 154                void const *buf, loff_t off, size_t count,
 155                size_t real_size, uint command)
 156{
 157        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 158        struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
 159        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 160        int retval;
 161
 162        if (off != 0 || count != real_size)
 163                return -EINVAL;
 164
 165        mutex_lock(&roccat_dev->lock);
 166        retval = roccat_common2_send_with_status(usb_dev, command, buf, real_size);
 167        mutex_unlock(&roccat_dev->lock);
 168
 169        return retval ? retval : real_size;
 170}
 171EXPORT_SYMBOL_GPL(roccat_common2_sysfs_write);
 172
 173MODULE_AUTHOR("Stefan Achatz");
 174MODULE_DESCRIPTION("USB Roccat common driver");
 175MODULE_LICENSE("GPL v2");
 176