aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Achatz <erazor_de@users.sourceforge.net>2010-11-26 14:57:42 -0500
committerJiri Kosina <jkosina@suse.cz>2011-01-07 19:18:28 -0500
commit47dbdbffe15b9582a41727766d43f1d4208e977e (patch)
tree98713eb7b7089cfd5e93499473246303a0e1718e
parent14a057f80f0c4d45a9e68009f8bcb6b246e87ca0 (diff)
HID: roccat: Add support for Roccat Kone[+] v2
This patch adds support for Roccat Kone[+] gaming mouse. Kone[+] is an enhanced version of the old Kone with more memory for macros, a better sensor and more functionality. This driver is conceptual similar to the existing Kone and Pyra drivers. Userland tools can soon be found at http://sourceforge.net/projects/roccat Signed-off-by: Stefan Achatz <erazor_de@users.sourceforge.net> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus108
-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-koneplus.c837
-rw-r--r--drivers/hid/hid-roccat-koneplus.h232
7 files changed, 1187 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
new file mode 100644
index 000000000000..0ebb64008cf7
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
@@ -0,0 +1,108 @@
1What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile
2Date: October 2010
3Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
4Description: When read, this file returns the number of the actual profile in
5 range 0-4.
6 This file is readonly.
7
8What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version
9Date: October 2010
10Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
11Description: When read, this file returns the raw integer version number of the
12 firmware reported by the mouse. Using the integer value eases
13 further usage in other programs. To receive the real version
14 number the decimal point has to be shifted 2 positions to the
15 left. E.g. a returned value of 121 means 1.21
16 This file is readonly.
17
18What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/macro
19Date: October 2010
20Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
21Description: The mouse can store a macro with max 500 key/button strokes
22 internally.
23 When written, this file lets one set the sequence for a specific
24 button for a specific profile. Button and profile numbers are
25 included in written data. The data has to be 2082 bytes long.
26 This file is writeonly.
27
28What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_buttons
29Date: August 2010
30Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
31Description: The mouse can store 5 profiles which can be switched by the
32 press of a button. A profile is split in settings and buttons.
33 profile_buttons holds informations about button layout.
34 When written, this file lets one write the respective profile
35 buttons back to the mouse. The data has to be 77 bytes long.
36 The mouse will reject invalid data.
37 Which profile to write is determined by the profile number
38 contained in the data.
39 This file is writeonly.
40
41What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_buttons
42Date: August 2010
43Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
44Description: The mouse can store 5 profiles which can be switched by the
45 press of a button. A profile is split in settings and buttons.
46 profile_buttons holds informations about button layout.
47 When read, these files return the respective profile buttons.
48 The returned data is 77 bytes in size.
49 This file is readonly.
50
51What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_settings
52Date: October 2010
53Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
54Description: The mouse can store 5 profiles which can be switched by the
55 press of a button. A profile is split in settings and buttons.
56 profile_settings holds informations like resolution, sensitivity
57 and light effects.
58 When written, this file lets one write the respective profile
59 settings back to the mouse. The data has to be 43 bytes long.
60 The mouse will reject invalid data.
61 Which profile to write is determined by the profile number
62 contained in the data.
63 This file is writeonly.
64
65What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_settings
66Date: August 2010
67Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
68Description: The mouse can store 5 profiles which can be switched by the
69 press of a button. A profile is split in settings and buttons.
70 profile_settings holds informations like resolution, sensitivity
71 and light effects.
72 When read, these files return the respective profile settings.
73 The returned data is 43 bytes in size.
74 This file is readonly.
75
76What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/sensor
77Date: October 2010
78Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
79Description: The mouse has a tracking- and a distance-control-unit. These
80 can be activated/deactivated and the lift-off distance can be
81 set. The data has to be 6 bytes long.
82 This file is writeonly.
83
84What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile
85Date: October 2010
86Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
87Description: The integer value of this attribute ranges from 0-4.
88 When read, this attribute returns the number of the profile
89 that's active when the mouse is powered on.
90 When written, this file sets the number of the startup profile
91 and the mouse activates this profile immediately.
92
93What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/tcu
94Date: October 2010
95Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
96Description: When written a calibration process for the tracking control unit
97 can be initiated/cancelled.
98 The data has to be 3 bytes long.
99 This file is writeonly.
100
101What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/tcu_image
102Date: October 2010
103Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
104Description: When read the mouse returns a 30x30 pixel image of the
105 sampled underground. This works only in the course of a
106 calibration process initiated with tcu.
107 The returned data is 1028 bytes in size.
108 This file is readonly.
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 3d9a95f28aea..d2a27519ed13 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -406,6 +406,13 @@ config HID_ROCCAT_KONE
406 ---help--- 406 ---help---
407 Support for Roccat Kone mouse. 407 Support for Roccat Kone mouse.
408 408
409config HID_ROCCAT_KONEPLUS
410 tristate "Roccat Kone[+] mouse support"
411 depends on USB_HID
412 select HID_ROCCAT
413 ---help---
414 Support for Roccat Kone[+] mouse.
415
409config HID_ROCCAT_PYRA 416config HID_ROCCAT_PYRA
410 tristate "Roccat Pyra mouse support" 417 tristate "Roccat Pyra mouse support"
411 depends on USB_HID 418 depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index b406269d1bcb..6eae9a90b8dd 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
56obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o 56obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
57obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o 57obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
58obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o 58obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
59obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
59obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o 60obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
60obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o 61obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
61obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o 62obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index c4d47e635f95..04b7eb046820 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1397,6 +1397,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1397 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, 1397 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
1398 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, 1398 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
1399 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, 1399 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
1400 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
1400 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, 1401 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
1401 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, 1402 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
1402 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, 1403 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5cd1a6a356a3..a945d795e4ed 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -485,6 +485,7 @@
485 485
486#define USB_VENDOR_ID_ROCCAT 0x1e7d 486#define USB_VENDOR_ID_ROCCAT 0x1e7d
487#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced 487#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
488#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
488#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 489#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
489#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 490#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
490 491
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
new file mode 100644
index 000000000000..1608c8d1efd6
--- /dev/null
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -0,0 +1,837 @@
1/*
2 * Roccat Kone[+] driver for Linux
3 *
4 * Copyright (c) 2010 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 Kone[+] is an updated/improved version of the Kone with more memory
16 * and functionality and without the non-standard behaviours the Kone had.
17 */
18
19#include <linux/device.h>
20#include <linux/input.h>
21#include <linux/hid.h>
22#include <linux/usb.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include "hid-ids.h"
26#include "hid-roccat.h"
27#include "hid-roccat-koneplus.h"
28
29static uint profile_numbers[5] = {0, 1, 2, 3, 4};
30
31static struct class *koneplus_class;
32
33static void koneplus_profile_activated(struct koneplus_device *koneplus,
34 uint new_profile)
35{
36 koneplus->actual_profile = new_profile;
37}
38
39static int koneplus_send_control(struct usb_device *usb_dev, uint value,
40 enum koneplus_control_requests request)
41{
42 int len;
43 struct koneplus_control *control;
44
45 if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
46 request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
47 value > 4)
48 return -EINVAL;
49
50 control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL);
51 if (!control)
52 return -ENOMEM;
53
54 control->command = KONEPLUS_COMMAND_CONTROL;
55 control->value = value;
56 control->request = request;
57
58 len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
59 USB_REQ_SET_CONFIGURATION,
60 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
61 KONEPLUS_USB_COMMAND_CONTROL, 0, control,
62 sizeof(struct koneplus_control),
63 USB_CTRL_SET_TIMEOUT);
64
65 kfree(control);
66
67 if (len != sizeof(struct koneplus_control))
68 return len;
69
70 return 0;
71}
72
73static int koneplus_receive(struct usb_device *usb_dev, uint usb_command,
74 void *buf, uint size) {
75 int len;
76
77 len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
78 USB_REQ_CLEAR_FEATURE,
79 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
80 usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
81
82 return (len != size) ? -EIO : 0;
83}
84
85static int koneplus_receive_control_status(struct usb_device *usb_dev)
86{
87 int retval;
88 struct koneplus_control *control;
89
90 control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL);
91 if (!control)
92 return -ENOMEM;
93
94 do {
95 retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
96 control, sizeof(struct koneplus_control));
97
98 /* check if we get a completely wrong answer */
99 if (retval)
100 goto out;
101
102 if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OK) {
103 retval = 0;
104 goto out;
105 }
106
107 /* indicates that hardware needs some more time to complete action */
108 if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_WAIT) {
109 msleep(500); /* windows driver uses 1000 */
110 continue;
111 }
112
113 /* seems to be critical - replug necessary */
114 if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) {
115 retval = -EINVAL;
116 goto out;
117 }
118
119 dev_err(&usb_dev->dev, "koneplus_receive_control_status: "
120 "unknown response value 0x%x\n", control->value);
121 retval = -EINVAL;
122 goto out;
123
124 } while (1);
125out:
126 kfree(control);
127 return retval;
128}
129
130static int koneplus_send(struct usb_device *usb_dev, uint command,
131 void *buf, uint size) {
132 int len;
133
134 len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
135 USB_REQ_SET_CONFIGURATION,
136 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
137 command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
138
139 if (len != size)
140 return -EIO;
141
142 if (koneplus_receive_control_status(usb_dev))
143 return -EIO;
144
145 return 0;
146}
147
148static int koneplus_select_profile(struct usb_device *usb_dev, uint number,
149 enum koneplus_control_requests request)
150{
151 int retval;
152
153 retval = koneplus_send_control(usb_dev, number, request);
154 if (retval)
155 return retval;
156
157 /* allow time to settle things - windows driver uses 500 */
158 msleep(100);
159
160 retval = koneplus_receive_control_status(usb_dev);
161 if (retval)
162 return retval;
163
164 return 0;
165}
166
167static int koneplus_get_info(struct usb_device *usb_dev,
168 struct koneplus_info *buf)
169{
170 return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO,
171 buf, sizeof(struct koneplus_info));
172}
173
174static int koneplus_get_profile_settings(struct usb_device *usb_dev,
175 struct koneplus_profile_settings *buf, uint number)
176{
177 int retval;
178
179 retval = koneplus_select_profile(usb_dev, number,
180 KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
181 if (retval)
182 return retval;
183
184 return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
185 buf, sizeof(struct koneplus_profile_settings));
186}
187
188static int koneplus_set_profile_settings(struct usb_device *usb_dev,
189 struct koneplus_profile_settings const *settings)
190{
191 return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
192 (void *)settings, sizeof(struct koneplus_profile_settings));
193}
194
195static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
196 struct koneplus_profile_buttons *buf, int number)
197{
198 int retval;
199
200 retval = koneplus_select_profile(usb_dev, number,
201 KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
202 if (retval)
203 return retval;
204
205 return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
206 buf, sizeof(struct koneplus_profile_buttons));
207}
208
209static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
210 struct koneplus_profile_buttons const *buttons)
211{
212 return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
213 (void *)buttons, sizeof(struct koneplus_profile_buttons));
214}
215
216/* retval is 0-4 on success, < 0 on error */
217static int koneplus_get_startup_profile(struct usb_device *usb_dev)
218{
219 struct koneplus_startup_profile *buf;
220 int retval;
221
222 buf = kmalloc(sizeof(struct koneplus_startup_profile), GFP_KERNEL);
223
224 retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
225 buf, sizeof(struct koneplus_startup_profile));
226
227 if (retval)
228 goto out;
229
230 retval = buf->startup_profile;
231out:
232 kfree(buf);
233 return retval;
234}
235
236static int koneplus_set_startup_profile(struct usb_device *usb_dev,
237 int startup_profile)
238{
239 struct koneplus_startup_profile buf;
240
241 buf.command = KONEPLUS_COMMAND_STARTUP_PROFILE;
242 buf.size = sizeof(struct koneplus_startup_profile);
243 buf.startup_profile = startup_profile;
244
245 return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
246 (char *)&buf, sizeof(struct koneplus_profile_buttons));
247}
248
249static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
250 char *buf, loff_t off, size_t count,
251 size_t real_size, uint command)
252{
253 struct device *dev =
254 container_of(kobj, struct device, kobj)->parent->parent;
255 struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
256 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
257 int retval;
258
259 if (off != 0 || count != real_size)
260 return -EINVAL;
261
262 mutex_lock(&koneplus->koneplus_lock);
263 retval = koneplus_receive(usb_dev, command, buf, real_size);
264 mutex_unlock(&koneplus->koneplus_lock);
265
266 if (retval)
267 return retval;
268
269 return real_size;
270}
271
272static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
273 void const *buf, loff_t off, size_t count,
274 size_t real_size, uint command)
275{
276 struct device *dev =
277 container_of(kobj, struct device, kobj)->parent->parent;
278 struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
279 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
280 int retval;
281
282 if (off != 0 || count != real_size)
283 return -EINVAL;
284
285 mutex_lock(&koneplus->koneplus_lock);
286 retval = koneplus_send(usb_dev, command, (void *)buf, real_size);
287 mutex_unlock(&koneplus->koneplus_lock);
288
289 if (retval)
290 return retval;
291
292 return real_size;
293}
294
295static ssize_t koneplus_sysfs_write_macro(struct file *fp,
296 struct kobject *kobj, struct bin_attribute *attr, char *buf,
297 loff_t off, size_t count)
298{
299 return koneplus_sysfs_write(fp, kobj, buf, off, count,
300 sizeof(struct koneplus_macro), KONEPLUS_USB_COMMAND_MACRO);
301}
302
303static ssize_t koneplus_sysfs_read_sensor(struct file *fp,
304 struct kobject *kobj, struct bin_attribute *attr, char *buf,
305 loff_t off, size_t count)
306{
307 return koneplus_sysfs_read(fp, kobj, buf, off, count,
308 sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
309}
310
311static ssize_t koneplus_sysfs_write_sensor(struct file *fp,
312 struct kobject *kobj, struct bin_attribute *attr, char *buf,
313 loff_t off, size_t count)
314{
315 return koneplus_sysfs_write(fp, kobj, buf, off, count,
316 sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
317}
318
319static ssize_t koneplus_sysfs_write_tcu(struct file *fp,
320 struct kobject *kobj, struct bin_attribute *attr, char *buf,
321 loff_t off, size_t count)
322{
323 return koneplus_sysfs_write(fp, kobj, buf, off, count,
324 sizeof(struct koneplus_tcu), KONEPLUS_USB_COMMAND_TCU);
325}
326
327static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp,
328 struct kobject *kobj, struct bin_attribute *attr, char *buf,
329 loff_t off, size_t count)
330{
331 return koneplus_sysfs_read(fp, kobj, buf, off, count,
332 sizeof(struct koneplus_tcu_image), KONEPLUS_USB_COMMAND_TCU);
333}
334
335static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
336 struct kobject *kobj, struct bin_attribute *attr, char *buf,
337 loff_t off, size_t count)
338{
339 struct device *dev =
340 container_of(kobj, struct device, kobj)->parent->parent;
341 struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
342
343 if (off >= sizeof(struct koneplus_profile_settings))
344 return 0;
345
346 if (off + count > sizeof(struct koneplus_profile_settings))
347 count = sizeof(struct koneplus_profile_settings) - off;
348
349 mutex_lock(&koneplus->koneplus_lock);
350 memcpy(buf, ((void const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off,
351 count);
352 mutex_unlock(&koneplus->koneplus_lock);
353
354 return count;
355}
356
357static ssize_t koneplus_sysfs_write_profile_settings(struct file *fp,
358 struct kobject *kobj, struct bin_attribute *attr, char *buf,
359 loff_t off, size_t count)
360{
361 struct device *dev =
362 container_of(kobj, struct device, kobj)->parent->parent;
363 struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
364 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
365 int retval = 0;
366 int difference;
367 int profile_number;
368 struct koneplus_profile_settings *profile_settings;
369
370 if (off != 0 || count != sizeof(struct koneplus_profile_settings))
371 return -EINVAL;
372
373 profile_number = ((struct koneplus_profile_settings const *)buf)->number;
374 profile_settings = &koneplus->profile_settings[profile_number];
375
376 mutex_lock(&koneplus->koneplus_lock);
377 difference = memcmp(buf, profile_settings,
378 sizeof(struct koneplus_profile_settings));
379 if (difference) {
380 retval = koneplus_set_profile_settings(usb_dev,
381 (struct koneplus_profile_settings const *)buf);
382 if (!retval)
383 memcpy(profile_settings, buf,
384 sizeof(struct koneplus_profile_settings));
385 }
386 mutex_unlock(&koneplus->koneplus_lock);
387
388 if (retval)
389 return retval;
390
391 return sizeof(struct koneplus_profile_settings);
392}
393
394static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
395 struct kobject *kobj, struct bin_attribute *attr, char *buf,
396 loff_t off, size_t count)
397{
398 struct device *dev =
399 container_of(kobj, struct device, kobj)->parent->parent;
400 struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
401
402 if (off >= sizeof(struct koneplus_profile_buttons))
403 return 0;
404
405 if (off + count > sizeof(struct koneplus_profile_buttons))
406 count = sizeof(struct koneplus_profile_buttons) - off;
407
408 mutex_lock(&koneplus->koneplus_lock);
409 memcpy(buf, ((void const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off,
410 count);
411 mutex_unlock(&koneplus->koneplus_lock);
412
413 return count;
414}
415
416static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp,
417 struct kobject *kobj, struct bin_attribute *attr, char *buf,
418 loff_t off, size_t count)
419{
420 struct device *dev =
421 container_of(kobj, struct device, kobj)->parent->parent;
422 struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
423 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
424 int retval = 0;
425 int difference;
426 uint profile_number;
427 struct koneplus_profile_buttons *profile_buttons;
428
429 if (off != 0 || count != sizeof(struct koneplus_profile_buttons))
430 return -EINVAL;
431
432 profile_number = ((struct koneplus_profile_buttons const *)buf)->number;
433 profile_buttons = &koneplus->profile_buttons[profile_number];
434
435 mutex_lock(&koneplus->koneplus_lock);
436 difference = memcmp(buf, profile_buttons,
437 sizeof(struct koneplus_profile_buttons));
438 if (difference) {
439 retval = koneplus_set_profile_buttons(usb_dev,
440 (struct koneplus_profile_buttons const *)buf);
441 if (!retval)
442 memcpy(profile_buttons, buf,
443 sizeof(struct koneplus_profile_buttons));
444 }
445 mutex_unlock(&koneplus->koneplus_lock);
446
447 if (retval)
448 return retval;
449
450 return sizeof(struct koneplus_profile_buttons);
451}
452
453static ssize_t koneplus_sysfs_show_startup_profile(struct device *dev,
454 struct device_attribute *attr, char *buf)
455{
456 struct koneplus_device *koneplus =
457 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
458 return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->startup_profile);
459}
460
461static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev,
462 struct device_attribute *attr, char const *buf, size_t size)
463{
464 struct koneplus_device *koneplus;
465 struct usb_device *usb_dev;
466 unsigned long profile;
467 int retval;
468
469 dev = dev->parent->parent;
470 koneplus = hid_get_drvdata(dev_get_drvdata(dev));
471 usb_dev = interface_to_usbdev(to_usb_interface(dev));
472
473 retval = strict_strtoul(buf, 10, &profile);
474 if (retval)
475 return retval;
476
477 mutex_lock(&koneplus->koneplus_lock);
478 retval = koneplus_set_startup_profile(usb_dev, profile);
479 mutex_unlock(&koneplus->koneplus_lock);
480 if (retval)
481 return retval;
482
483 return size;
484}
485
486static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
487 struct device_attribute *attr, char *buf)
488{
489 struct koneplus_device *koneplus =
490 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
491 return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
492}
493
494static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
495 struct device_attribute *attr, char *buf)
496{
497 struct koneplus_device *koneplus =
498 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
499 return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->info.firmware_version);
500}
501
502static struct device_attribute koneplus_attributes[] = {
503 __ATTR(startup_profile, 0660,
504 koneplus_sysfs_show_startup_profile,
505 koneplus_sysfs_set_startup_profile),
506 __ATTR(actual_profile, 0440,
507 koneplus_sysfs_show_actual_profile, NULL),
508 __ATTR(firmware_version, 0440,
509 koneplus_sysfs_show_firmware_version, NULL),
510 __ATTR_NULL
511};
512
513static struct bin_attribute koneplus_bin_attributes[] = {
514 {
515 .attr = { .name = "sensor", .mode = 0220 },
516 .size = sizeof(struct koneplus_sensor),
517 .read = koneplus_sysfs_read_sensor,
518 .write = koneplus_sysfs_write_sensor
519 },
520 {
521 .attr = { .name = "tcu", .mode = 0220 },
522 .size = sizeof(struct koneplus_tcu),
523 .write = koneplus_sysfs_write_tcu
524 },
525 {
526 .attr = { .name = "tcu_image", .mode = 0440 },
527 .size = sizeof(struct koneplus_tcu_image),
528 .read = koneplus_sysfs_read_tcu_image
529 },
530 {
531 .attr = { .name = "profile_settings", .mode = 0220 },
532 .size = sizeof(struct koneplus_profile_settings),
533 .write = koneplus_sysfs_write_profile_settings
534 },
535 {
536 .attr = { .name = "profile1_settings", .mode = 0440 },
537 .size = sizeof(struct koneplus_profile_settings),
538 .read = koneplus_sysfs_read_profilex_settings,
539 .private = &profile_numbers[0]
540 },
541 {
542 .attr = { .name = "profile2_settings", .mode = 0440 },
543 .size = sizeof(struct koneplus_profile_settings),
544 .read = koneplus_sysfs_read_profilex_settings,
545 .private = &profile_numbers[1]
546 },
547 {
548 .attr = { .name = "profile3_settings", .mode = 0440 },
549 .size = sizeof(struct koneplus_profile_settings),
550 .read = koneplus_sysfs_read_profilex_settings,
551 .private = &profile_numbers[2]
552 },
553 {
554 .attr = { .name = "profile4_settings", .mode = 0440 },
555 .size = sizeof(struct koneplus_profile_settings),
556 .read = koneplus_sysfs_read_profilex_settings,
557 .private = &profile_numbers[3]
558 },
559 {
560 .attr = { .name = "profile5_settings", .mode = 0440 },
561 .size = sizeof(struct koneplus_profile_settings),
562 .read = koneplus_sysfs_read_profilex_settings,
563 .private = &profile_numbers[4]
564 },
565 {
566 .attr = { .name = "profile_buttons", .mode = 0220 },
567 .size = sizeof(struct koneplus_profile_buttons),
568 .write = koneplus_sysfs_write_profile_buttons
569 },
570 {
571 .attr = { .name = "profile1_buttons", .mode = 0440 },
572 .size = sizeof(struct koneplus_profile_buttons),
573 .read = koneplus_sysfs_read_profilex_buttons,
574 .private = &profile_numbers[0]
575 },
576 {
577 .attr = { .name = "profile2_buttons", .mode = 0440 },
578 .size = sizeof(struct koneplus_profile_buttons),
579 .read = koneplus_sysfs_read_profilex_buttons,
580 .private = &profile_numbers[1]
581 },
582 {
583 .attr = { .name = "profile3_buttons", .mode = 0440 },
584 .size = sizeof(struct koneplus_profile_buttons),
585 .read = koneplus_sysfs_read_profilex_buttons,
586 .private = &profile_numbers[2]
587 },
588 {
589 .attr = { .name = "profile4_buttons", .mode = 0440 },
590 .size = sizeof(struct koneplus_profile_buttons),
591 .read = koneplus_sysfs_read_profilex_buttons,
592 .private = &profile_numbers[3]
593 },
594 {
595 .attr = { .name = "profile5_buttons", .mode = 0440 },
596 .size = sizeof(struct koneplus_profile_buttons),
597 .read = koneplus_sysfs_read_profilex_buttons,
598 .private = &profile_numbers[4]
599 },
600 {
601 .attr = { .name = "macro", .mode = 0220 },
602 .size = sizeof(struct koneplus_macro),
603 .write = koneplus_sysfs_write_macro
604 },
605 __ATTR_NULL
606};
607
608static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
609 struct koneplus_device *koneplus)
610{
611 int retval, i;
612 static uint wait = 70; /* device will freeze with just 60 */
613
614 mutex_init(&koneplus->koneplus_lock);
615
616 koneplus->startup_profile = koneplus_get_startup_profile(usb_dev);
617
618 msleep(wait);
619 retval = koneplus_get_info(usb_dev, &koneplus->info);
620 if (retval)
621 return retval;
622
623 for (i = 0; i < 5; ++i) {
624 msleep(wait);
625 retval = koneplus_get_profile_settings(usb_dev,
626 &koneplus->profile_settings[i], i);
627 if (retval)
628 return retval;
629
630 msleep(wait);
631 retval = koneplus_get_profile_buttons(usb_dev,
632 &koneplus->profile_buttons[i], i);
633 if (retval)
634 return retval;
635 }
636
637 koneplus_profile_activated(koneplus, koneplus->startup_profile);
638
639 return 0;
640}
641
642static int koneplus_init_specials(struct hid_device *hdev)
643{
644 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
645 struct usb_device *usb_dev = interface_to_usbdev(intf);
646 struct koneplus_device *koneplus;
647 int retval;
648
649 if (intf->cur_altsetting->desc.bInterfaceProtocol
650 == USB_INTERFACE_PROTOCOL_MOUSE) {
651
652 koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL);
653 if (!koneplus) {
654 dev_err(&hdev->dev, "can't alloc device descriptor\n");
655 return -ENOMEM;
656 }
657 hid_set_drvdata(hdev, koneplus);
658
659 retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus);
660 if (retval) {
661 dev_err(&hdev->dev,
662 "couldn't init struct koneplus_device\n");
663 goto exit_free;
664 }
665
666 retval = roccat_connect(koneplus_class, hdev);
667 if (retval < 0) {
668 dev_err(&hdev->dev, "couldn't init char dev\n");
669 } else {
670 koneplus->chrdev_minor = retval;
671 koneplus->roccat_claimed = 1;
672 }
673 } else {
674 hid_set_drvdata(hdev, NULL);
675 }
676
677 return 0;
678exit_free:
679 kfree(koneplus);
680 return retval;
681}
682
683static void koneplus_remove_specials(struct hid_device *hdev)
684{
685 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
686 struct koneplus_device *koneplus;
687
688 if (intf->cur_altsetting->desc.bInterfaceProtocol
689 == USB_INTERFACE_PROTOCOL_MOUSE) {
690 koneplus = hid_get_drvdata(hdev);
691 if (koneplus->roccat_claimed)
692 roccat_disconnect(koneplus->chrdev_minor);
693 kfree(koneplus);
694 }
695}
696
697static int koneplus_probe(struct hid_device *hdev,
698 const struct hid_device_id *id)
699{
700 int retval;
701
702 retval = hid_parse(hdev);
703 if (retval) {
704 dev_err(&hdev->dev, "parse failed\n");
705 goto exit;
706 }
707
708 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
709 if (retval) {
710 dev_err(&hdev->dev, "hw start failed\n");
711 goto exit;
712 }
713
714 retval = koneplus_init_specials(hdev);
715 if (retval) {
716 dev_err(&hdev->dev, "couldn't install mouse\n");
717 goto exit_stop;
718 }
719
720 return 0;
721
722exit_stop:
723 hid_hw_stop(hdev);
724exit:
725 return retval;
726}
727
728static void koneplus_remove(struct hid_device *hdev)
729{
730 koneplus_remove_specials(hdev);
731 hid_hw_stop(hdev);
732}
733
734static void koneplus_keep_values_up_to_date(struct koneplus_device *koneplus,
735 u8 const *data)
736{
737 struct koneplus_mouse_report_button const *button_report;
738
739 switch (data[0]) {
740 case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON:
741 button_report = (struct koneplus_mouse_report_button const *)data;
742 switch (button_report->type) {
743 case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE:
744 koneplus_profile_activated(koneplus, button_report->data1 - 1);
745 break;
746 }
747 break;
748 }
749}
750
751static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus,
752 u8 const *data)
753{
754 struct koneplus_roccat_report roccat_report;
755 struct koneplus_mouse_report_button const *button_report;
756
757 if (data[0] != KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON)
758 return;
759
760 button_report = (struct koneplus_mouse_report_button const *)data;
761
762 if ((button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
763 button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) &&
764 button_report->data2 != KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS)
765 return;
766
767 roccat_report.type = button_report->type;
768 roccat_report.data1 = button_report->data1;
769 roccat_report.data2 = button_report->data2;
770 roccat_report.profile = koneplus->actual_profile + 1;
771 roccat_report_event(koneplus->chrdev_minor,
772 (uint8_t const *)&roccat_report,
773 sizeof(struct koneplus_roccat_report));
774}
775
776static int koneplus_raw_event(struct hid_device *hdev,
777 struct hid_report *report, u8 *data, int size)
778{
779 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
780 struct koneplus_device *koneplus = hid_get_drvdata(hdev);
781
782 if (intf->cur_altsetting->desc.bInterfaceProtocol
783 != USB_INTERFACE_PROTOCOL_MOUSE)
784 return 0;
785
786 koneplus_keep_values_up_to_date(koneplus, data);
787
788 if (koneplus->roccat_claimed)
789 koneplus_report_to_chrdev(koneplus, data);
790
791 return 0;
792}
793
794static const struct hid_device_id koneplus_devices[] = {
795 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
796 { }
797};
798
799MODULE_DEVICE_TABLE(hid, koneplus_devices);
800
801static struct hid_driver koneplus_driver = {
802 .name = "koneplus",
803 .id_table = koneplus_devices,
804 .probe = koneplus_probe,
805 .remove = koneplus_remove,
806 .raw_event = koneplus_raw_event
807};
808
809static int __init koneplus_init(void)
810{
811 int retval;
812
813 /* class name has to be same as driver name */
814 koneplus_class = class_create(THIS_MODULE, "koneplus");
815 if (IS_ERR(koneplus_class))
816 return PTR_ERR(koneplus_class);
817 koneplus_class->dev_attrs = koneplus_attributes;
818 koneplus_class->dev_bin_attrs = koneplus_bin_attributes;
819
820 retval = hid_register_driver(&koneplus_driver);
821 if (retval)
822 class_destroy(koneplus_class);
823 return retval;
824}
825
826static void __exit koneplus_exit(void)
827{
828 class_destroy(koneplus_class);
829 hid_unregister_driver(&koneplus_driver);
830}
831
832module_init(koneplus_init);
833module_exit(koneplus_exit);
834
835MODULE_AUTHOR("Stefan Achatz");
836MODULE_DESCRIPTION("USB Roccat Kone[+] driver");
837MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h
new file mode 100644
index 000000000000..905e33d45354
--- /dev/null
+++ b/drivers/hid/hid-roccat-koneplus.h
@@ -0,0 +1,232 @@
1#ifndef __HID_ROCCAT_KONEPLUS_H
2#define __HID_ROCCAT_KONEPLUS_H
3
4/*
5 * Copyright (c) 2010 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
17/*
18 * Binary data structures used for hardware communication must have no padding.
19 */
20#pragma pack(push)
21#pragma pack(1)
22
23/*
24 * case 1: writes request 80 and reads value 1
25 *
26 */
27struct koneplus_control {
28 uint8_t command; /* KONEPLUS_COMMAND_CONTROL */
29 /*
30 * value is profile number in range 0-4 for requesting settings and buttons
31 * 1 if status ok for requesting status
32 */
33 uint8_t value;
34 uint8_t request;
35};
36
37enum koneplus_control_requests {
38 KONEPLUS_CONTROL_REQUEST_STATUS = 0x00,
39 KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80,
40 KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x90,
41};
42
43enum koneplus_control_values {
44 KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0,
45 KONEPLUS_CONTROL_REQUEST_STATUS_OK = 1,
46 KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3,
47};
48
49struct koneplus_startup_profile {
50 uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */
51 uint8_t size; /* always 3 */
52 uint8_t startup_profile; /* Range 0-4! */
53};
54
55struct koneplus_profile_settings {
56 uint8_t command; /* KONEPLUS_COMMAND_PROFILE_SETTINGS */
57 uint8_t size; /* always 43 */
58 uint8_t number; /* range 0-4 */
59 uint8_t advanced_sensitivity;
60 uint8_t sensitivity_x;
61 uint8_t sensitivity_y;
62 uint8_t cpi_levels_enabled;
63 uint8_t cpi_levels_x[5];
64 uint8_t cpi_startup_level; /* range 0-4 */
65 uint8_t cpi_levels_y[5]; /* range 1-60 means 100-6000 cpi */
66 uint8_t unknown1;
67 uint8_t polling_rate;
68 uint8_t lights_enabled;
69 uint8_t light_effect_mode;
70 uint8_t color_flow_effect;
71 uint8_t light_effect_type;
72 uint8_t light_effect_speed;
73 uint8_t lights[16];
74 uint16_t checksum;
75};
76
77struct koneplus_profile_buttons {
78 uint8_t command; /* KONEPLUS_COMMAND_PROFILE_BUTTONS */
79 uint8_t size; /* always 77 */
80 uint8_t number; /* range 0-4 */
81 uint8_t data[72];
82 uint16_t checksum;
83};
84
85struct koneplus_macro {
86 uint8_t command; /* KONEPLUS_COMMAND_MACRO */
87 uint16_t size; /* always 0x822 little endian */
88 uint8_t profile; /* range 0-4 */
89 uint8_t button; /* range 0-23 */
90 uint8_t data[2075];
91 uint16_t checksum;
92};
93
94struct koneplus_info {
95 uint8_t command; /* KONEPLUS_COMMAND_INFO */
96 uint8_t size; /* always 6 */
97 uint8_t firmware_version;
98 uint8_t unknown[3];
99};
100
101struct koneplus_e {
102 uint8_t command; /* KONEPLUS_COMMAND_E */
103 uint8_t size; /* always 3 */
104 uint8_t unknown; /* TODO 1; 0 before firmware update */
105};
106
107struct koneplus_sensor {
108 uint8_t command; /* KONEPLUS_COMMAND_SENSOR */
109 uint8_t size; /* always 6 */
110 uint8_t data[4];
111};
112
113struct koneplus_firmware_write {
114 uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE */
115 uint8_t unknown[1025];
116};
117
118struct koneplus_firmware_write_control {
119 uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL */
120 /*
121 * value is 1 on success
122 * 3 means "not finished yet"
123 */
124 uint8_t value;
125 uint8_t unknown; /* always 0x75 */
126};
127
128struct koneplus_tcu {
129 uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
130 uint8_t data[2];
131};
132
133struct koneplus_tcu_image {
134 uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
135 uint8_t data[1024];
136 uint16_t checksum;
137};
138
139enum koneplus_commands {
140 KONEPLUS_COMMAND_CONTROL = 0x4,
141 KONEPLUS_COMMAND_STARTUP_PROFILE = 0x5,
142 KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
143 KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
144 KONEPLUS_COMMAND_MACRO = 0x8,
145 KONEPLUS_COMMAND_INFO = 0x9,
146 KONEPLUS_COMMAND_E = 0xe,
147 KONEPLUS_COMMAND_SENSOR = 0xf,
148 KONEPLUS_COMMAND_FIRMWARE_WRITE = 0x1b,
149 KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
150};
151
152enum koneplus_usb_commands {
153 KONEPLUS_USB_COMMAND_CONTROL = 0x304,
154 KONEPLUS_USB_COMMAND_STARTUP_PROFILE = 0x305,
155 KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
156 KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
157 KONEPLUS_USB_COMMAND_MACRO = 0x308,
158 KONEPLUS_USB_COMMAND_INFO = 0x309,
159 KONEPLUS_USB_COMMAND_TCU = 0x30c,
160 KONEPLUS_USB_COMMAND_E = 0x30e,
161 KONEPLUS_USB_COMMAND_SENSOR = 0x30f,
162 KONEPLUS_USB_COMMAND_FIRMWARE_WRITE = 0x31b,
163 KONEPLUS_USB_COMMAND_FIRMWARE_WRITE_CONTROL = 0x31c,
164};
165
166enum koneplus_mouse_report_numbers {
167 KONEPLUS_MOUSE_REPORT_NUMBER_HID = 1,
168 KONEPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
169 KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON = 3,
170};
171
172struct koneplus_mouse_report_button {
173 uint8_t report_number; /* always KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON */
174 uint8_t zero1;
175 uint8_t type;
176 uint8_t data1;
177 uint8_t data2;
178 uint8_t zero2;
179 uint8_t unknown[2];
180};
181
182enum koneplus_mouse_report_button_types {
183 /* data1 = new profile range 1-5 */
184 KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE = 0x20,
185
186 /* data1 = button number range 1-24; data2 = action */
187 KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
188
189 /* data1 = button number range 1-24; data2 = action */
190 KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80,
191
192 /* data1 = setting number range 1-5 */
193 KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0,
194
195 /* data1 and data2 = range 0x1-0xb */
196 KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0,
197
198 /* data1 = 22 = next track...
199 * data2 = action
200 */
201 KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
202};
203
204enum koneplus_mouse_report_button_action {
205 KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS = 0,
206 KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_RELEASE = 1,
207};
208
209struct koneplus_roccat_report {
210 uint8_t type;
211 uint8_t data1;
212 uint8_t data2;
213 uint8_t profile;
214};
215
216#pragma pack(pop)
217
218struct koneplus_device {
219 int actual_profile;
220
221 int roccat_claimed;
222 int chrdev_minor;
223
224 struct mutex koneplus_lock;
225
226 int startup_profile;
227 struct koneplus_info info;
228 struct koneplus_profile_settings profile_settings[5];
229 struct koneplus_profile_buttons profile_buttons[5];
230};
231
232#endif