aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-isku135
-rw-r--r--drivers/hid/Kconfig7
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-core.c1
-rw-r--r--drivers/hid/hid-ids.h1
-rw-r--r--drivers/hid/hid-roccat-isku.c487
-rw-r--r--drivers/hid/hid-roccat-isku.h147
7 files changed, 779 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku b/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku
new file mode 100644
index 00000000000..189dc43891b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku
@@ -0,0 +1,135 @@
1What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/actual_profile
2Date: June 2011
3Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
4Description: The integer value of this attribute ranges from 0-4.
5 When read, this attribute returns the number of the actual
6 profile. This value is persistent, so its equivalent to the
7 profile that's active when the device is powered on next time.
8 When written, this file sets the number of the startup profile
9 and the device activates this profile immediately.
10Users: http://roccat.sourceforge.net
11
12What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/info
13Date: June 2011
14Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
15Description: When read, this file returns general data like firmware version.
16 The data is 6 bytes long.
17 This file is readonly.
18Users: http://roccat.sourceforge.net
19
20What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/key_mask
21Date: June 2011
22Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
23Description: When written, this file lets one deactivate certain keys like
24 windows and application keys, to prevent accidental presses.
25 Profile number for which this settings occur is included in
26 written data. The data has to be 6 bytes long.
27 Before reading this file, control has to be written to select
28 which profile to read.
29Users: http://roccat.sourceforge.net
30
31What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_capslock
32Date: June 2011
33Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
34Description: When written, this file lets one set the function of the
35 capslock key for a specific profile. Profile number is included
36 in written data. The data has to be 6 bytes long.
37 Before reading this file, control has to be written to select
38 which profile to read.
39Users: http://roccat.sourceforge.net
40
41What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_easyzone
42Date: June 2011
43Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
44Description: When written, this file lets one set the function of the
45 easyzone keys for a specific profile. Profile number is included
46 in written data. The data has to be 65 bytes long.
47 Before reading this file, control has to be written to select
48 which profile to read.
49Users: http://roccat.sourceforge.net
50
51What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_function
52Date: June 2011
53Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
54Description: When written, this file lets one set the function of the
55 function keys for a specific profile. Profile number is included
56 in written data. The data has to be 41 bytes long.
57 Before reading this file, control has to be written to select
58 which profile to read.
59Users: http://roccat.sourceforge.net
60
61What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_macro
62Date: June 2011
63Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
64Description: When written, this file lets one set the function of the macro
65 keys for a specific profile. Profile number is included in
66 written data. The data has to be 35 bytes long.
67 Before reading this file, control has to be written to select
68 which profile to read.
69Users: http://roccat.sourceforge.net
70
71What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_media
72Date: June 2011
73Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
74Description: When written, this file lets one set the function of the media
75 keys for a specific profile. Profile number is included in
76 written data. The data has to be 29 bytes long.
77 Before reading this file, control has to be written to select
78 which profile to read.
79Users: http://roccat.sourceforge.net
80
81What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_thumbster
82Date: June 2011
83Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
84Description: When written, this file lets one set the function of the
85 thumbster keys for a specific profile. Profile number is included
86 in written data. The data has to be 23 bytes long.
87 Before reading this file, control has to be written to select
88 which profile to read.
89Users: http://roccat.sourceforge.net
90
91What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/last_set
92Date: June 2011
93Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
94Description: When written, this file lets one set the time in secs since
95 epoch in which the last configuration took place.
96 The data has to be 20 bytes long.
97Users: http://roccat.sourceforge.net
98
99What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/light
100Date: June 2011
101Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
102Description: When written, this file lets one set the backlight intensity for
103 a specific profile. Profile number is included in written data.
104 The data has to be 10 bytes long.
105 Before reading this file, control has to be written to select
106 which profile to read.
107Users: http://roccat.sourceforge.net
108
109What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/macro
110Date: June 2011
111Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
112Description: When written, this file lets one store macros with max 500
113 keystrokes for a specific button for a specific profile.
114 Button and profile numbers are included in written data.
115 The data has to be 2083 bytes long.
116 Before reading this file, control has to be written to select
117 which profile and key to read.
118Users: http://roccat.sourceforge.net
119
120What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/control
121Date: June 2011
122Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
123Description: When written, this file lets one select which data from which
124 profile will be read next. The data has to be 3 bytes long.
125 This file is writeonly.
126Users: http://roccat.sourceforge.net
127
128What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/talk
129Date: June 2011
130Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
131Description: When written, this file lets one trigger easyshift functionality
132 from the host.
133 The data has to be 16 bytes long.
134 This file is writeonly.
135Users: http://roccat.sourceforge.net
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 22a4a051f22..7f119079429 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -492,6 +492,13 @@ config HID_ROCCAT_ARVO
492 ---help--- 492 ---help---
493 Support for Roccat Arvo keyboard. 493 Support for Roccat Arvo keyboard.
494 494
495config HID_ROCCAT_ISKU
496 tristate "Roccat Isku keyboard support"
497 depends on USB_HID
498 depends on HID_ROCCAT
499 ---help---
500 Support for Roccat Isku keyboard.
501
495config HID_ROCCAT_KONE 502config HID_ROCCAT_KONE
496 tristate "Roccat Kone Mouse support" 503 tristate "Roccat Kone Mouse support"
497 depends on USB_HID 504 depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 1e0d2a638b2..88660f7f3a5 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
59obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o 59obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
60obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o 60obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o
61obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o 61obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
62obj-$(CONFIG_HID_ROCCAT_ISKU) += hid-roccat-isku.o
62obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o 63obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
63obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o 64obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
64obj-$(CONFIG_HID_ROCCAT_KOVAPLUS) += hid-roccat-kovaplus.o 65obj-$(CONFIG_HID_ROCCAT_KOVAPLUS) += hid-roccat-kovaplus.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index af353842f75..2f1672a49d5 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1503,6 +1503,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1503 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, 1503 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
1504 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, 1504 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
1505 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, 1505 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
1506 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
1506 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, 1507 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
1507 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, 1508 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
1508 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, 1509 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 4a441a6f996..7d2fae1ebe5 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -586,6 +586,7 @@
586 586
587#define USB_VENDOR_ID_ROCCAT 0x1e7d 587#define USB_VENDOR_ID_ROCCAT 0x1e7d
588#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4 588#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
589#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c
589#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced 590#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
590#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51 591#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
591#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50 592#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
new file mode 100644
index 00000000000..0e4a0ab4714
--- /dev/null
+++ b/drivers/hid/hid-roccat-isku.c
@@ -0,0 +1,487 @@
1/*
2 * Roccat Isku driver for Linux
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/*
15 * Roccat Isku is a gamer keyboard with macro keys that can be configured in
16 * 5 profiles.
17 */
18
19#include <linux/device.h>
20#include <linux/input.h>
21#include <linux/hid.h>
22#include <linux/module.h>
23#include <linux/slab.h>
24#include <linux/hid-roccat.h>
25#include "hid-ids.h"
26#include "hid-roccat-common.h"
27#include "hid-roccat-isku.h"
28
29static struct class *isku_class;
30
31static void isku_profile_activated(struct isku_device *isku, uint new_profile)
32{
33 isku->actual_profile = new_profile;
34}
35
36static int isku_receive(struct usb_device *usb_dev, uint command,
37 void *buf, uint size)
38{
39 return roccat_common_receive(usb_dev, command, buf, size);
40}
41
42static int isku_receive_control_status(struct usb_device *usb_dev)
43{
44 int retval;
45 struct isku_control control;
46
47 do {
48 msleep(50);
49 retval = isku_receive(usb_dev, ISKU_COMMAND_CONTROL,
50 &control, sizeof(struct isku_control));
51
52 if (retval)
53 return retval;
54
55 switch (control.value) {
56 case ISKU_CONTROL_VALUE_STATUS_OK:
57 return 0;
58 case ISKU_CONTROL_VALUE_STATUS_WAIT:
59 continue;
60 case ISKU_CONTROL_VALUE_STATUS_INVALID:
61 /* seems to be critical - replug necessary */
62 case ISKU_CONTROL_VALUE_STATUS_OVERLOAD:
63 return -EINVAL;
64 default:
65 hid_err(usb_dev, "isku_receive_control_status: "
66 "unknown response value 0x%x\n",
67 control.value);
68 return -EINVAL;
69 }
70
71 } while (1);
72}
73
74static int isku_send(struct usb_device *usb_dev, uint command,
75 void const *buf, uint size)
76{
77 int retval;
78
79 retval = roccat_common_send(usb_dev, command, buf, size);
80 if (retval)
81 return retval;
82
83 return isku_receive_control_status(usb_dev);
84}
85
86static int isku_get_actual_profile(struct usb_device *usb_dev)
87{
88 struct isku_actual_profile buf;
89 int retval;
90
91 retval = isku_receive(usb_dev, ISKU_COMMAND_ACTUAL_PROFILE,
92 &buf, sizeof(struct isku_actual_profile));
93 return retval ? retval : buf.actual_profile;
94}
95
96static int isku_set_actual_profile(struct usb_device *usb_dev, int new_profile)
97{
98 struct isku_actual_profile buf;
99
100 buf.command = ISKU_COMMAND_ACTUAL_PROFILE;
101 buf.size = sizeof(struct isku_actual_profile);
102 buf.actual_profile = new_profile;
103 return isku_send(usb_dev, ISKU_COMMAND_ACTUAL_PROFILE, &buf,
104 sizeof(struct isku_actual_profile));
105}
106
107static ssize_t isku_sysfs_show_actual_profile(struct device *dev,
108 struct device_attribute *attr, char *buf)
109{
110 struct isku_device *isku =
111 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
112 return snprintf(buf, PAGE_SIZE, "%d\n", isku->actual_profile);
113}
114
115static ssize_t isku_sysfs_set_actual_profile(struct device *dev,
116 struct device_attribute *attr, char const *buf, size_t size)
117{
118 struct isku_device *isku;
119 struct usb_device *usb_dev;
120 unsigned long profile;
121 int retval;
122 struct isku_roccat_report roccat_report;
123
124 dev = dev->parent->parent;
125 isku = hid_get_drvdata(dev_get_drvdata(dev));
126 usb_dev = interface_to_usbdev(to_usb_interface(dev));
127
128 retval = strict_strtoul(buf, 10, &profile);
129 if (retval)
130 return retval;
131
132 if (profile > 4)
133 return -EINVAL;
134
135 mutex_lock(&isku->isku_lock);
136
137 retval = isku_set_actual_profile(usb_dev, profile);
138 if (retval) {
139 mutex_unlock(&isku->isku_lock);
140 return retval;
141 }
142
143 isku_profile_activated(isku, profile);
144
145 roccat_report.event = ISKU_REPORT_BUTTON_EVENT_PROFILE;
146 roccat_report.data1 = profile + 1;
147 roccat_report.data2 = 0;
148 roccat_report.profile = profile + 1;
149 roccat_report_event(isku->chrdev_minor, (uint8_t const *)&roccat_report);
150
151 mutex_unlock(&isku->isku_lock);
152
153 return size;
154}
155
156static struct device_attribute isku_attributes[] = {
157 __ATTR(actual_profile, 0660,
158 isku_sysfs_show_actual_profile,
159 isku_sysfs_set_actual_profile),
160 __ATTR_NULL
161};
162
163static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
164 char *buf, loff_t off, size_t count,
165 size_t real_size, uint command)
166{
167 struct device *dev =
168 container_of(kobj, struct device, kobj)->parent->parent;
169 struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
170 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
171 int retval;
172
173 if (off >= real_size)
174 return 0;
175
176 if (off != 0 || count != real_size)
177 return -EINVAL;
178
179 mutex_lock(&isku->isku_lock);
180 retval = isku_receive(usb_dev, command, buf, real_size);
181 mutex_unlock(&isku->isku_lock);
182
183 return retval ? retval : real_size;
184}
185
186static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
187 void const *buf, loff_t off, size_t count,
188 size_t real_size, uint command)
189{
190 struct device *dev =
191 container_of(kobj, struct device, kobj)->parent->parent;
192 struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
193 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
194 int retval;
195
196 if (off != 0 || count != real_size)
197 return -EINVAL;
198
199 mutex_lock(&isku->isku_lock);
200 retval = isku_send(usb_dev, command, (void *)buf, real_size);
201 mutex_unlock(&isku->isku_lock);
202
203 return retval ? retval : real_size;
204}
205
206#define ISKU_SYSFS_W(thingy, THINGY) \
207static ssize_t isku_sysfs_write_ ## thingy(struct file *fp, struct kobject *kobj, \
208 struct bin_attribute *attr, char *buf, \
209 loff_t off, size_t count) \
210{ \
211 return isku_sysfs_write(fp, kobj, buf, off, count, \
212 sizeof(struct isku_ ## thingy), ISKU_COMMAND_ ## THINGY); \
213}
214
215#define ISKU_SYSFS_R(thingy, THINGY) \
216static ssize_t isku_sysfs_read_ ## thingy(struct file *fp, struct kobject *kobj, \
217 struct bin_attribute *attr, char *buf, \
218 loff_t off, size_t count) \
219{ \
220 return isku_sysfs_read(fp, kobj, buf, off, count, \
221 sizeof(struct isku_ ## thingy), ISKU_COMMAND_ ## THINGY); \
222}
223
224#define ISKU_SYSFS_RW(thingy, THINGY) \
225ISKU_SYSFS_R(thingy, THINGY) \
226ISKU_SYSFS_W(thingy, THINGY)
227
228#define ISKU_BIN_ATTR_RW(thingy) \
229{ \
230 .attr = { .name = #thingy, .mode = 0660 }, \
231 .size = sizeof(struct isku_ ## thingy), \
232 .read = isku_sysfs_read_ ## thingy, \
233 .write = isku_sysfs_write_ ## thingy \
234}
235
236#define ISKU_BIN_ATTR_R(thingy) \
237{ \
238 .attr = { .name = #thingy, .mode = 0440 }, \
239 .size = sizeof(struct isku_ ## thingy), \
240 .read = isku_sysfs_read_ ## thingy, \
241}
242
243#define ISKU_BIN_ATTR_W(thingy) \
244{ \
245 .attr = { .name = #thingy, .mode = 0220 }, \
246 .size = sizeof(struct isku_ ## thingy), \
247 .write = isku_sysfs_write_ ## thingy \
248}
249
250ISKU_SYSFS_RW(macro, MACRO)
251ISKU_SYSFS_RW(keys_function, KEYS_FUNCTION)
252ISKU_SYSFS_RW(keys_easyzone, KEYS_EASYZONE)
253ISKU_SYSFS_RW(keys_media, KEYS_MEDIA)
254ISKU_SYSFS_RW(keys_thumbster, KEYS_THUMBSTER)
255ISKU_SYSFS_RW(keys_macro, KEYS_MACRO)
256ISKU_SYSFS_RW(keys_capslock, KEYS_CAPSLOCK)
257ISKU_SYSFS_RW(light, LIGHT)
258ISKU_SYSFS_RW(key_mask, KEY_MASK)
259ISKU_SYSFS_RW(last_set, LAST_SET)
260ISKU_SYSFS_W(talk, TALK)
261ISKU_SYSFS_R(info, INFO)
262ISKU_SYSFS_W(control, CONTROL)
263
264static struct bin_attribute isku_bin_attributes[] = {
265 ISKU_BIN_ATTR_RW(macro),
266 ISKU_BIN_ATTR_RW(keys_function),
267 ISKU_BIN_ATTR_RW(keys_easyzone),
268 ISKU_BIN_ATTR_RW(keys_media),
269 ISKU_BIN_ATTR_RW(keys_thumbster),
270 ISKU_BIN_ATTR_RW(keys_macro),
271 ISKU_BIN_ATTR_RW(keys_capslock),
272 ISKU_BIN_ATTR_RW(light),
273 ISKU_BIN_ATTR_RW(key_mask),
274 ISKU_BIN_ATTR_RW(last_set),
275 ISKU_BIN_ATTR_W(talk),
276 ISKU_BIN_ATTR_R(info),
277 ISKU_BIN_ATTR_W(control),
278 __ATTR_NULL
279};
280
281static int isku_init_isku_device_struct(struct usb_device *usb_dev,
282 struct isku_device *isku)
283{
284 int retval;
285
286 mutex_init(&isku->isku_lock);
287
288 retval = isku_get_actual_profile(usb_dev);
289 if (retval < 0)
290 return retval;
291 isku_profile_activated(isku, retval);
292
293 return 0;
294}
295
296static int isku_init_specials(struct hid_device *hdev)
297{
298 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
299 struct usb_device *usb_dev = interface_to_usbdev(intf);
300 struct isku_device *isku;
301 int retval;
302
303 if (intf->cur_altsetting->desc.bInterfaceProtocol
304 != ISKU_USB_INTERFACE_PROTOCOL) {
305 hid_set_drvdata(hdev, NULL);
306 return 0;
307 }
308
309 isku = kzalloc(sizeof(*isku), GFP_KERNEL);
310 if (!isku) {
311 hid_err(hdev, "can't alloc device descriptor\n");
312 return -ENOMEM;
313 }
314 hid_set_drvdata(hdev, isku);
315
316 retval = isku_init_isku_device_struct(usb_dev, isku);
317 if (retval) {
318 hid_err(hdev, "couldn't init struct isku_device\n");
319 goto exit_free;
320 }
321
322 retval = roccat_connect(isku_class, hdev,
323 sizeof(struct isku_roccat_report));
324 if (retval < 0) {
325 hid_err(hdev, "couldn't init char dev\n");
326 } else {
327 isku->chrdev_minor = retval;
328 isku->roccat_claimed = 1;
329 }
330
331 return 0;
332exit_free:
333 kfree(isku);
334 return retval;
335}
336
337static void isku_remove_specials(struct hid_device *hdev)
338{
339 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
340 struct isku_device *isku;
341
342 if (intf->cur_altsetting->desc.bInterfaceProtocol
343 != ISKU_USB_INTERFACE_PROTOCOL)
344 return;
345
346 isku = hid_get_drvdata(hdev);
347 if (isku->roccat_claimed)
348 roccat_disconnect(isku->chrdev_minor);
349 kfree(isku);
350}
351
352static int isku_probe(struct hid_device *hdev,
353 const struct hid_device_id *id)
354{
355 int retval;
356
357 retval = hid_parse(hdev);
358 if (retval) {
359 hid_err(hdev, "parse failed\n");
360 goto exit;
361 }
362
363 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
364 if (retval) {
365 hid_err(hdev, "hw start failed\n");
366 goto exit;
367 }
368
369 retval = isku_init_specials(hdev);
370 if (retval) {
371 hid_err(hdev, "couldn't install keyboard\n");
372 goto exit_stop;
373 }
374
375 return 0;
376
377exit_stop:
378 hid_hw_stop(hdev);
379exit:
380 return retval;
381}
382
383static void isku_remove(struct hid_device *hdev)
384{
385 isku_remove_specials(hdev);
386 hid_hw_stop(hdev);
387}
388
389static void isku_keep_values_up_to_date(struct isku_device *isku,
390 u8 const *data)
391{
392 struct isku_report_button const *button_report;
393
394 switch (data[0]) {
395 case ISKU_REPORT_NUMBER_BUTTON:
396 button_report = (struct isku_report_button const *)data;
397 switch (button_report->event) {
398 case ISKU_REPORT_BUTTON_EVENT_PROFILE:
399 isku_profile_activated(isku, button_report->data1 - 1);
400 break;
401 }
402 break;
403 }
404}
405
406static void isku_report_to_chrdev(struct isku_device const *isku,
407 u8 const *data)
408{
409 struct isku_roccat_report roccat_report;
410 struct isku_report_button const *button_report;
411
412 if (data[0] != ISKU_REPORT_NUMBER_BUTTON)
413 return;
414
415 button_report = (struct isku_report_button const *)data;
416
417 roccat_report.event = button_report->event;
418 roccat_report.data1 = button_report->data1;
419 roccat_report.data2 = button_report->data2;
420 roccat_report.profile = isku->actual_profile + 1;
421 roccat_report_event(isku->chrdev_minor,
422 (uint8_t const *)&roccat_report);
423}
424
425static int isku_raw_event(struct hid_device *hdev,
426 struct hid_report *report, u8 *data, int size)
427{
428 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
429 struct isku_device *isku = hid_get_drvdata(hdev);
430
431 if (intf->cur_altsetting->desc.bInterfaceProtocol
432 != ISKU_USB_INTERFACE_PROTOCOL)
433 return 0;
434
435 if (isku == NULL)
436 return 0;
437
438 isku_keep_values_up_to_date(isku, data);
439
440 if (isku->roccat_claimed)
441 isku_report_to_chrdev(isku, data);
442
443 return 0;
444}
445
446static const struct hid_device_id isku_devices[] = {
447 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
448 { }
449};
450
451MODULE_DEVICE_TABLE(hid, isku_devices);
452
453static struct hid_driver isku_driver = {
454 .name = "isku",
455 .id_table = isku_devices,
456 .probe = isku_probe,
457 .remove = isku_remove,
458 .raw_event = isku_raw_event
459};
460
461static int __init isku_init(void)
462{
463 int retval;
464 isku_class = class_create(THIS_MODULE, "isku");
465 if (IS_ERR(isku_class))
466 return PTR_ERR(isku_class);
467 isku_class->dev_attrs = isku_attributes;
468 isku_class->dev_bin_attrs = isku_bin_attributes;
469
470 retval = hid_register_driver(&isku_driver);
471 if (retval)
472 class_destroy(isku_class);
473 return retval;
474}
475
476static void __exit isku_exit(void)
477{
478 hid_unregister_driver(&isku_driver);
479 class_destroy(isku_class);
480}
481
482module_init(isku_init);
483module_exit(isku_exit);
484
485MODULE_AUTHOR("Stefan Achatz");
486MODULE_DESCRIPTION("USB Roccat Isku driver");
487MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-isku.h b/drivers/hid/hid-roccat-isku.h
new file mode 100644
index 00000000000..075f6efaec5
--- /dev/null
+++ b/drivers/hid/hid-roccat-isku.h
@@ -0,0 +1,147 @@
1#ifndef __HID_ROCCAT_ISKU_H
2#define __HID_ROCCAT_ISKU_H
3
4/*
5 * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
6 */
7
8/*
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 */
14
15#include <linux/types.h>
16
17enum {
18 ISKU_PROFILE_NUM = 5,
19 ISKU_USB_INTERFACE_PROTOCOL = 0,
20};
21
22struct isku_control {
23 uint8_t command; /* ISKU_COMMAND_CONTROL */
24 uint8_t value;
25 uint8_t request;
26} __packed;
27
28enum isku_control_values {
29 ISKU_CONTROL_VALUE_STATUS_OVERLOAD = 0,
30 ISKU_CONTROL_VALUE_STATUS_OK = 1,
31 ISKU_CONTROL_VALUE_STATUS_INVALID = 2,
32 ISKU_CONTROL_VALUE_STATUS_WAIT = 3,
33};
34
35struct isku_actual_profile {
36 uint8_t command; /* ISKU_COMMAND_ACTUAL_PROFILE */
37 uint8_t size; /* always 3 */
38 uint8_t actual_profile;
39} __packed;
40
41struct isku_key_mask {
42 uint8_t command; /* ISKU_COMMAND_KEY_MASK */
43 uint8_t size; /* 6 */
44 uint8_t profile_number; /* 0-4 */
45 uint8_t mask;
46 uint16_t checksum;
47} __packed;
48
49struct isku_keys_function {
50 uint8_t data[0x29];
51} __packed;
52
53struct isku_keys_easyzone {
54 uint8_t data[0x41];
55} __packed;
56
57struct isku_keys_media {
58 uint8_t data[0x1d];
59} __packed;
60
61struct isku_keys_thumbster {
62 uint8_t data[0x17];
63} __packed;
64
65struct isku_keys_macro {
66 uint8_t data[0x23];
67} __packed;
68
69struct isku_keys_capslock {
70 uint8_t data[0x6];
71} __packed;
72
73struct isku_macro {
74 uint8_t data[0x823];
75} __packed;
76
77struct isku_light {
78 uint8_t data[0xa];
79} __packed;
80
81struct isku_info {
82 uint8_t data[2];
83 uint8_t firmware_version;
84 uint8_t unknown[3];
85} __packed;
86
87struct isku_talk {
88 uint8_t data[0x10];
89} __packed;
90
91struct isku_last_set {
92 uint8_t data[0x14];
93} __packed;
94
95enum isku_commands {
96 ISKU_COMMAND_CONTROL = 0x4,
97 ISKU_COMMAND_ACTUAL_PROFILE = 0x5,
98 ISKU_COMMAND_KEY_MASK = 0x7,
99 ISKU_COMMAND_KEYS_FUNCTION = 0x8,
100 ISKU_COMMAND_KEYS_EASYZONE = 0x9,
101 ISKU_COMMAND_KEYS_MEDIA = 0xa,
102 ISKU_COMMAND_KEYS_THUMBSTER = 0xb,
103 ISKU_COMMAND_KEYS_MACRO = 0xd,
104 ISKU_COMMAND_MACRO = 0xe,
105 ISKU_COMMAND_INFO = 0xf,
106 ISKU_COMMAND_LIGHT = 0x10,
107 ISKU_COMMAND_KEYS_CAPSLOCK = 0x13,
108 ISKU_COMMAND_LAST_SET = 0x14,
109 ISKU_COMMAND_15 = 0x15,
110 ISKU_COMMAND_TALK = 0x16,
111 ISKU_COMMAND_FIRMWARE_WRITE = 0x1b,
112 ISKU_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
113};
114
115struct isku_report_button {
116 uint8_t number; /* ISKU_REPORT_NUMBER_BUTTON */
117 uint8_t zero;
118 uint8_t event;
119 uint8_t data1;
120 uint8_t data2;
121};
122
123enum isku_report_numbers {
124 ISKU_REPORT_NUMBER_BUTTON = 3,
125};
126
127enum isku_report_button_events {
128 ISKU_REPORT_BUTTON_EVENT_PROFILE = 0x2,
129};
130
131struct isku_roccat_report {
132 uint8_t event;
133 uint8_t data1;
134 uint8_t data2;
135 uint8_t profile;
136} __packed;
137
138struct isku_device {
139 int roccat_claimed;
140 int chrdev_minor;
141
142 struct mutex isku_lock;
143
144 int actual_profile;
145};
146
147#endif