Root/drivers/hid/hid-roccat-common.c

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

Archive Download this file



interactive