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_OVERLOAD = 0,
  69        ROCCAT_COMMON_CONTROL_STATUS_OK = 1,
  70        ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2,
  71        ROCCAT_COMMON_CONTROL_STATUS_WAIT = 3,
  72};
  73
  74static int roccat_common2_receive_control_status(struct usb_device *usb_dev)
  75{
  76        int retval;
  77        struct roccat_common2_control control;
  78
  79        do {
  80                msleep(50);
  81                retval = roccat_common2_receive(usb_dev,
  82                                ROCCAT_COMMON_COMMAND_CONTROL,
  83                                &control, sizeof(struct roccat_common2_control));
  84
  85                if (retval)
  86                        return retval;
  87
  88                switch (control.value) {
  89                case ROCCAT_COMMON_CONTROL_STATUS_OK:
  90                        return 0;
  91                case ROCCAT_COMMON_CONTROL_STATUS_WAIT:
  92                        msleep(500);
  93                        continue;
  94                case ROCCAT_COMMON_CONTROL_STATUS_INVALID:
  95
  96                case ROCCAT_COMMON_CONTROL_STATUS_OVERLOAD:
  97                        /* seems to be critical - replug necessary */
  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
 125MODULE_AUTHOR("Stefan Achatz");
 126MODULE_DESCRIPTION("USB Roccat common driver");
 127MODULE_LICENSE("GPL v2");
 128