diff options
Diffstat (limited to 'drivers/hid/hid-roccat-common.c')
-rw-r--r-- | drivers/hid/hid-roccat-common.c | 72 |
1 files changed, 65 insertions, 7 deletions
diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c index a6d93992c75a..74f704032627 100644 --- a/drivers/hid/hid-roccat-common.c +++ b/drivers/hid/hid-roccat-common.c | |||
@@ -16,12 +16,12 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include "hid-roccat-common.h" | 17 | #include "hid-roccat-common.h" |
18 | 18 | ||
19 | static inline uint16_t roccat_common_feature_report(uint8_t report_id) | 19 | static inline uint16_t roccat_common2_feature_report(uint8_t report_id) |
20 | { | 20 | { |
21 | return 0x300 | report_id; | 21 | return 0x300 | report_id; |
22 | } | 22 | } |
23 | 23 | ||
24 | int roccat_common_receive(struct usb_device *usb_dev, uint report_id, | 24 | int roccat_common2_receive(struct usb_device *usb_dev, uint report_id, |
25 | void *data, uint size) | 25 | void *data, uint size) |
26 | { | 26 | { |
27 | char *buf; | 27 | char *buf; |
@@ -34,16 +34,16 @@ int roccat_common_receive(struct usb_device *usb_dev, uint report_id, | |||
34 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | 34 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), |
35 | HID_REQ_GET_REPORT, | 35 | HID_REQ_GET_REPORT, |
36 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | 36 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
37 | roccat_common_feature_report(report_id), | 37 | roccat_common2_feature_report(report_id), |
38 | 0, buf, size, USB_CTRL_SET_TIMEOUT); | 38 | 0, buf, size, USB_CTRL_SET_TIMEOUT); |
39 | 39 | ||
40 | memcpy(data, buf, size); | 40 | memcpy(data, buf, size); |
41 | kfree(buf); | 41 | kfree(buf); |
42 | return ((len < 0) ? len : ((len != size) ? -EIO : 0)); | 42 | return ((len < 0) ? len : ((len != size) ? -EIO : 0)); |
43 | } | 43 | } |
44 | EXPORT_SYMBOL_GPL(roccat_common_receive); | 44 | EXPORT_SYMBOL_GPL(roccat_common2_receive); |
45 | 45 | ||
46 | int roccat_common_send(struct usb_device *usb_dev, uint report_id, | 46 | int roccat_common2_send(struct usb_device *usb_dev, uint report_id, |
47 | void const *data, uint size) | 47 | void const *data, uint size) |
48 | { | 48 | { |
49 | char *buf; | 49 | char *buf; |
@@ -56,13 +56,71 @@ int roccat_common_send(struct usb_device *usb_dev, uint report_id, | |||
56 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | 56 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), |
57 | HID_REQ_SET_REPORT, | 57 | HID_REQ_SET_REPORT, |
58 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | 58 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, |
59 | roccat_common_feature_report(report_id), | 59 | roccat_common2_feature_report(report_id), |
60 | 0, buf, size, USB_CTRL_SET_TIMEOUT); | 60 | 0, buf, size, USB_CTRL_SET_TIMEOUT); |
61 | 61 | ||
62 | kfree(buf); | 62 | kfree(buf); |
63 | return ((len < 0) ? len : ((len != size) ? -EIO : 0)); | 63 | return ((len < 0) ? len : ((len != size) ? -EIO : 0)); |
64 | } | 64 | } |
65 | EXPORT_SYMBOL_GPL(roccat_common_send); | 65 | EXPORT_SYMBOL_GPL(roccat_common2_send); |
66 | |||
67 | enum 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 | |||
74 | static 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 | |||
110 | int 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 | } | ||
123 | EXPORT_SYMBOL_GPL(roccat_common2_send_with_status); | ||
66 | 124 | ||
67 | MODULE_AUTHOR("Stefan Achatz"); | 125 | MODULE_AUTHOR("Stefan Achatz"); |
68 | MODULE_DESCRIPTION("USB Roccat common driver"); | 126 | MODULE_DESCRIPTION("USB Roccat common driver"); |