aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-savu68
-rw-r--r--drivers/hid/Makefile3
-rw-r--r--drivers/hid/hid-core.c1
-rw-r--r--drivers/hid/hid-ids.h1
-rw-r--r--drivers/hid/hid-roccat-savu.c357
-rw-r--r--drivers/hid/hid-roccat-savu.h103
6 files changed, 532 insertions, 1 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-savu b/Documentation/ABI/testing/sysfs-driver-hid-roccat-savu
new file mode 100644
index 00000000000..e2334900128
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-savu
@@ -0,0 +1,68 @@
1What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/buttons
2Date: Mai 2012
3Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
4Description: The mouse can store 5 profiles which can be switched by the
5 press of a button. A profile is split into general settings and
6 button settings. buttons holds informations about button layout.
7 When written, this file lets one write the respective profile
8 buttons to the mouse. The data has to be 47 bytes long.
9 The mouse will reject invalid data.
10 Which profile to write is determined by the profile number
11 contained in the data.
12 Before reading this file, control has to be written to select
13 which profile to read.
14Users: http://roccat.sourceforge.net
15
16What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/control
17Date: Mai 2012
18Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
19Description: When written, this file lets one select which data from which
20 profile will be read next. The data has to be 3 bytes long.
21 This file is writeonly.
22Users: http://roccat.sourceforge.net
23
24What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/general
25Date: Mai 2012
26Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
27Description: The mouse can store 5 profiles which can be switched by the
28 press of a button. A profile is split into general settings and
29 button settings. profile holds informations like resolution, sensitivity
30 and light effects.
31 When written, this file lets one write the respective profile
32 settings back to the mouse. The data has to be 43 bytes long.
33 The mouse will reject invalid data.
34 Which profile to write is determined by the profile number
35 contained in the data.
36 This file is writeonly.
37Users: http://roccat.sourceforge.net
38
39What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/info
40Date: Mai 2012
41Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
42Description: When read, this file returns general data like firmware version.
43 The data is 8 bytes long.
44 This file is readonly.
45Users: http://roccat.sourceforge.net
46
47What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/macro
48Date: Mai 2012
49Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
50Description: When written, this file lets one store macros with max 500
51 keystrokes for a specific button for a specific profile.
52 Button and profile numbers are included in written data.
53 The data has to be 2083 bytes long.
54 Before reading this file, control has to be written to select
55 which profile and key to read.
56Users: http://roccat.sourceforge.net
57
58What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/profile
59Date: Mai 2012
60Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
61Description: The mouse can store 5 profiles which can be switched by the
62 press of a button. profile holds number of actual profile.
63 This value is persistent, so its value determines the profile
64 that's active when the mouse is powered on next time.
65 When written, the mouse activates the set profile immediately.
66 The data has to be 3 bytes long.
67 The mouse will reject invalid data.
68Users: http://roccat.sourceforge.net
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index ca6cc9f0485..348b9040459 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -69,7 +69,8 @@ obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
69obj-$(CONFIG_HID_PRIMAX) += hid-primax.o 69obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
70obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ 70obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
71 hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ 71 hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
72 hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o 72 hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \
73 hid-roccat-savu.o
73obj-$(CONFIG_HID_SAITEK) += hid-saitek.o 74obj-$(CONFIG_HID_SAITEK) += hid-saitek.o
74obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o 75obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
75obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o 76obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 6ac0286b537..fd95df8d1e0 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1617,6 +1617,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1617 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, 1617 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
1618 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, 1618 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
1619 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, 1619 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) },
1620 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
1620 { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, 1621 { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
1621 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, 1622 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
1622 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, 1623 { 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 d1cdd2d2840..ddc293d827f 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -644,6 +644,7 @@
644#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50 644#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
645#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 645#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
646#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 646#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
647#define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a
647 648
648#define USB_VENDOR_ID_SAITEK 0x06a3 649#define USB_VENDOR_ID_SAITEK 0x06a3
649#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 650#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c
new file mode 100644
index 00000000000..d6c82d57408
--- /dev/null
+++ b/drivers/hid/hid-roccat-savu.c
@@ -0,0 +1,357 @@
1/*
2 * Roccat Savu driver for Linux
3 *
4 * Copyright (c) 2012 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/* Roccat Savu is a gamer mouse with macro keys that can be configured in
15 * 5 profiles.
16 */
17
18#include <linux/device.h>
19#include <linux/input.h>
20#include <linux/hid.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/hid-roccat.h>
24#include "hid-ids.h"
25#include "hid-roccat-common.h"
26#include "hid-roccat-savu.h"
27
28static struct class *savu_class;
29
30static int savu_receive_control_status(struct usb_device *usb_dev)
31{
32 int retval;
33 struct savu_control control;
34
35 do {
36 msleep(50);
37 retval = roccat_common_receive(usb_dev, SAVU_COMMAND_CONTROL,
38 &control, sizeof(struct savu_control));
39
40 if (retval)
41 return retval;
42
43 switch (control.value) {
44 case SAVU_CONTROL_REQUEST_WRITE_CHECK_OK:
45 return 0;
46 case SAVU_CONTROL_REQUEST_WRITE_CHECK_WAIT:
47 continue;
48 case SAVU_CONTROL_REQUEST_WRITE_CHECK_INVALID:
49 /* seems to be critical - replug necessary */
50 case SAVU_CONTROL_REQUEST_WRITE_CHECK_OVERLOAD:
51 return -EINVAL;
52 default:
53 hid_err(usb_dev, "savu_receive_control_status: "
54 "unknown response value 0x%x\n",
55 control.value);
56 return -EINVAL;
57 }
58
59 } while (1);
60}
61
62static int savu_send(struct usb_device *usb_dev, uint command,
63 void const *buf, uint size)
64{
65 int retval;
66
67 retval = roccat_common_send(usb_dev, command, buf, size);
68 if (retval)
69 return retval;
70
71 return savu_receive_control_status(usb_dev);
72}
73
74static ssize_t savu_sysfs_read(struct file *fp, struct kobject *kobj,
75 char *buf, loff_t off, size_t count,
76 size_t real_size, uint command)
77{
78 struct device *dev =
79 container_of(kobj, struct device, kobj)->parent->parent;
80 struct savu_device *savu = hid_get_drvdata(dev_get_drvdata(dev));
81 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
82 int retval;
83
84 if (off >= real_size)
85 return 0;
86
87 if (off != 0 || count != real_size)
88 return -EINVAL;
89
90 mutex_lock(&savu->savu_lock);
91 retval = roccat_common_receive(usb_dev, command, buf, real_size);
92 mutex_unlock(&savu->savu_lock);
93
94 return retval ? retval : real_size;
95}
96
97static ssize_t savu_sysfs_write(struct file *fp, struct kobject *kobj,
98 void const *buf, loff_t off, size_t count,
99 size_t real_size, uint command)
100{
101 struct device *dev =
102 container_of(kobj, struct device, kobj)->parent->parent;
103 struct savu_device *savu = hid_get_drvdata(dev_get_drvdata(dev));
104 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
105 int retval;
106
107 if (off != 0 || count != real_size)
108 return -EINVAL;
109
110 mutex_lock(&savu->savu_lock);
111 retval = savu_send(usb_dev, command, (void *)buf, real_size);
112 mutex_unlock(&savu->savu_lock);
113
114 return retval ? retval : real_size;
115}
116
117#define SAVU_SYSFS_W(thingy, THINGY) \
118static ssize_t savu_sysfs_write_ ## thingy(struct file *fp, \
119 struct kobject *kobj, struct bin_attribute *attr, char *buf, \
120 loff_t off, size_t count) \
121{ \
122 return savu_sysfs_write(fp, kobj, buf, off, count, \
123 SAVU_SIZE_ ## THINGY, SAVU_COMMAND_ ## THINGY); \
124}
125
126#define SAVU_SYSFS_R(thingy, THINGY) \
127static ssize_t savu_sysfs_read_ ## thingy(struct file *fp, \
128 struct kobject *kobj, struct bin_attribute *attr, char *buf, \
129 loff_t off, size_t count) \
130{ \
131 return savu_sysfs_read(fp, kobj, buf, off, count, \
132 SAVU_SIZE_ ## THINGY, SAVU_COMMAND_ ## THINGY); \
133}
134
135#define SAVU_SYSFS_RW(thingy, THINGY) \
136SAVU_SYSFS_W(thingy, THINGY) \
137SAVU_SYSFS_R(thingy, THINGY)
138
139#define SAVU_BIN_ATTRIBUTE_RW(thingy, THINGY) \
140{ \
141 .attr = { .name = #thingy, .mode = 0660 }, \
142 .size = SAVU_SIZE_ ## THINGY, \
143 .read = savu_sysfs_read_ ## thingy, \
144 .write = savu_sysfs_write_ ## thingy \
145}
146
147#define SAVU_BIN_ATTRIBUTE_R(thingy, THINGY) \
148{ \
149 .attr = { .name = #thingy, .mode = 0440 }, \
150 .size = SAVU_SIZE_ ## THINGY, \
151 .read = savu_sysfs_read_ ## thingy, \
152}
153
154#define SAVU_BIN_ATTRIBUTE_W(thingy, THINGY) \
155{ \
156 .attr = { .name = #thingy, .mode = 0220 }, \
157 .size = SAVU_SIZE_ ## THINGY, \
158 .write = savu_sysfs_write_ ## thingy \
159}
160
161SAVU_SYSFS_W(control, CONTROL)
162SAVU_SYSFS_RW(profile, PROFILE)
163SAVU_SYSFS_RW(general, GENERAL)
164SAVU_SYSFS_RW(buttons, BUTTONS)
165SAVU_SYSFS_RW(macro, MACRO)
166SAVU_SYSFS_R(info, INFO)
167
168static struct bin_attribute savu_bin_attributes[] = {
169 SAVU_BIN_ATTRIBUTE_W(control, CONTROL),
170 SAVU_BIN_ATTRIBUTE_RW(profile, PROFILE),
171 SAVU_BIN_ATTRIBUTE_RW(general, GENERAL),
172 SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS),
173 SAVU_BIN_ATTRIBUTE_RW(macro, MACRO),
174 SAVU_BIN_ATTRIBUTE_R(info, INFO),
175 __ATTR_NULL
176};
177
178static int savu_init_savu_device_struct(struct usb_device *usb_dev,
179 struct savu_device *savu)
180{
181 mutex_init(&savu->savu_lock);
182
183 return 0;
184}
185
186static int savu_init_specials(struct hid_device *hdev)
187{
188 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
189 struct usb_device *usb_dev = interface_to_usbdev(intf);
190 struct savu_device *savu;
191 int retval;
192
193 if (intf->cur_altsetting->desc.bInterfaceProtocol
194 != USB_INTERFACE_PROTOCOL_MOUSE) {
195 hid_set_drvdata(hdev, NULL);
196 return 0;
197 }
198
199 savu = kzalloc(sizeof(*savu), GFP_KERNEL);
200 if (!savu) {
201 hid_err(hdev, "can't alloc device descriptor\n");
202 return -ENOMEM;
203 }
204 hid_set_drvdata(hdev, savu);
205
206 retval = savu_init_savu_device_struct(usb_dev, savu);
207 if (retval) {
208 hid_err(hdev, "couldn't init struct savu_device\n");
209 goto exit_free;
210 }
211
212 retval = roccat_connect(savu_class, hdev,
213 sizeof(struct savu_roccat_report));
214 if (retval < 0) {
215 hid_err(hdev, "couldn't init char dev\n");
216 } else {
217 savu->chrdev_minor = retval;
218 savu->roccat_claimed = 1;
219 }
220
221 return 0;
222exit_free:
223 kfree(savu);
224 return retval;
225}
226
227static void savu_remove_specials(struct hid_device *hdev)
228{
229 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
230 struct savu_device *savu;
231
232 if (intf->cur_altsetting->desc.bInterfaceProtocol
233 != USB_INTERFACE_PROTOCOL_MOUSE)
234 return;
235
236 savu = hid_get_drvdata(hdev);
237 if (savu->roccat_claimed)
238 roccat_disconnect(savu->chrdev_minor);
239 kfree(savu);
240}
241
242static int savu_probe(struct hid_device *hdev,
243 const struct hid_device_id *id)
244{
245 int retval;
246
247 retval = hid_parse(hdev);
248 if (retval) {
249 hid_err(hdev, "parse failed\n");
250 goto exit;
251 }
252
253 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
254 if (retval) {
255 hid_err(hdev, "hw start failed\n");
256 goto exit;
257 }
258
259 retval = savu_init_specials(hdev);
260 if (retval) {
261 hid_err(hdev, "couldn't install mouse\n");
262 goto exit_stop;
263 }
264
265 return 0;
266
267exit_stop:
268 hid_hw_stop(hdev);
269exit:
270 return retval;
271}
272
273static void savu_remove(struct hid_device *hdev)
274{
275 savu_remove_specials(hdev);
276 hid_hw_stop(hdev);
277}
278
279static void savu_report_to_chrdev(struct savu_device const *savu,
280 u8 const *data)
281{
282 struct savu_roccat_report roccat_report;
283 struct savu_mouse_report_special const *special_report;
284
285 if (data[0] != SAVU_MOUSE_REPORT_NUMBER_SPECIAL)
286 return;
287
288 special_report = (struct savu_mouse_report_special const *)data;
289
290 roccat_report.type = special_report->type;
291 roccat_report.data[0] = special_report->data[0];
292 roccat_report.data[1] = special_report->data[1];
293 roccat_report_event(savu->chrdev_minor,
294 (uint8_t const *)&roccat_report);
295}
296
297static int savu_raw_event(struct hid_device *hdev,
298 struct hid_report *report, u8 *data, int size)
299{
300 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
301 struct savu_device *savu = hid_get_drvdata(hdev);
302
303 if (intf->cur_altsetting->desc.bInterfaceProtocol
304 != USB_INTERFACE_PROTOCOL_MOUSE)
305 return 0;
306
307 if (savu == NULL)
308 return 0;
309
310 if (savu->roccat_claimed)
311 savu_report_to_chrdev(savu, data);
312
313 return 0;
314}
315
316static const struct hid_device_id savu_devices[] = {
317 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
318 { }
319};
320
321MODULE_DEVICE_TABLE(hid, savu_devices);
322
323static struct hid_driver savu_driver = {
324 .name = "savu",
325 .id_table = savu_devices,
326 .probe = savu_probe,
327 .remove = savu_remove,
328 .raw_event = savu_raw_event
329};
330
331static int __init savu_init(void)
332{
333 int retval;
334
335 savu_class = class_create(THIS_MODULE, "savu");
336 if (IS_ERR(savu_class))
337 return PTR_ERR(savu_class);
338 savu_class->dev_bin_attrs = savu_bin_attributes;
339
340 retval = hid_register_driver(&savu_driver);
341 if (retval)
342 class_destroy(savu_class);
343 return retval;
344}
345
346static void __exit savu_exit(void)
347{
348 hid_unregister_driver(&savu_driver);
349 class_destroy(savu_class);
350}
351
352module_init(savu_init);
353module_exit(savu_exit);
354
355MODULE_AUTHOR("Stefan Achatz");
356MODULE_DESCRIPTION("USB Roccat Savu driver");
357MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-savu.h b/drivers/hid/hid-roccat-savu.h
new file mode 100644
index 00000000000..97b43d5b047
--- /dev/null
+++ b/drivers/hid/hid-roccat-savu.h
@@ -0,0 +1,103 @@
1#ifndef __HID_ROCCAT_SAVU_H
2#define __HID_ROCCAT_SAVU_H
3
4/*
5 * Copyright (c) 2012 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 SAVU_SIZE_CONTROL = 0x03,
19 SAVU_SIZE_PROFILE = 0x03,
20 SAVU_SIZE_GENERAL = 0x10,
21 SAVU_SIZE_BUTTONS = 0x2f,
22 SAVU_SIZE_MACRO = 0x0823,
23 SAVU_SIZE_INFO = 0x08,
24};
25
26struct savu_control {
27 uint8_t command; /* SAVU_COMMAND_CONTROL */
28 /*
29 * value is profile number in range 0-4 for requesting settings and buttons
30 * 1 if status ok for requesting status
31 */
32 uint8_t value;
33 uint8_t request;
34} __packed;
35
36enum savu_control_requests {
37 SAVU_CONTROL_REQUEST_WRITE_CHECK = 0x00,
38 SAVU_CONTROL_REQUEST_GENERAL = 0x80,
39 SAVU_CONTROL_REQUEST_BUTTONS = 0x90,
40};
41
42enum savu_control_values {
43 SAVU_CONTROL_REQUEST_WRITE_CHECK_OVERLOAD = 0,
44 SAVU_CONTROL_REQUEST_WRITE_CHECK_OK = 1,
45 SAVU_CONTROL_REQUEST_WRITE_CHECK_INVALID = 2,
46 SAVU_CONTROL_REQUEST_WRITE_CHECK_WAIT = 3,
47};
48
49enum savu_commands {
50 SAVU_COMMAND_CONTROL = 0x4,
51 SAVU_COMMAND_PROFILE = 0x5,
52 SAVU_COMMAND_GENERAL = 0x6,
53 SAVU_COMMAND_BUTTONS = 0x7,
54 SAVU_COMMAND_MACRO = 0x8,
55 SAVU_COMMAND_INFO = 0x9,
56};
57
58struct savu_mouse_report_special {
59 uint8_t report_number; /* always 3 */
60 uint8_t zero;
61 uint8_t type;
62 uint8_t data[2];
63} __packed;
64
65enum {
66 SAVU_MOUSE_REPORT_NUMBER_SPECIAL = 3,
67};
68
69enum savu_mouse_report_button_types {
70 /* data1 = new profile range 1-5 */
71 SAVU_MOUSE_REPORT_BUTTON_TYPE_PROFILE = 0x20,
72
73 /* data1 = button number range 1-24; data2 = action */
74 SAVU_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
75
76 /* data1 = button number range 1-24; data2 = action */
77 SAVU_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80,
78
79 /* data1 = setting number range 1-5 */
80 SAVU_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0,
81
82 /* data1 and data2 = range 0x1-0xb */
83 SAVU_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0,
84
85 /* data1 = 22 = next track...
86 * data2 = action
87 */
88 SAVU_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
89};
90
91struct savu_roccat_report {
92 uint8_t type;
93 uint8_t data[2];
94} __packed;
95
96struct savu_device {
97 int roccat_claimed;
98 int chrdev_minor;
99
100 struct mutex savu_lock;
101};
102
103#endif