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