~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/hid/hid-roccat-kovaplus.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno
  • Date: 2011-06-07 12:14:05 UTC
  • mfrom: (43.1.9 sid)
  • Revision ID: james.westby@ubuntu.com-20110607121405-i3h1rd7nrnd2b73h
Tags: 2.6.39-2
[ Ben Hutchings ]
* [x86] Enable BACKLIGHT_APPLE, replacing BACKLIGHT_MBP_NVIDIA
  (Closes: #627492)
* cgroups: Disable memory resource controller by default. Allow it
  to be enabled using kernel parameter 'cgroup_enable=memory'.
* rt2800usb: Enable support for more USB devices including
  Linksys WUSB600N (Closes: #596626) (this change was accidentally
  omitted from 2.6.39-1)
* [x86] Remove Celeron from list of processors supporting PAE. Most
  'Celeron M' models do not.
* Update debconf template translations:
  - Swedish (Martin Bagge) (Closes: #628932)
  - French (David Prévot) (Closes: #628191)
* aufs: Update for 2.6.39 (Closes: #627837)
* Add stable 2.6.39.1, including:
  - ext4: dont set PageUptodate in ext4_end_bio()
  - pata_cmd64x: fix boot crash on parisc (Closes: #622997, #622745)
  - ext3: Fix fs corruption when make_indexed_dir() fails
  - netfilter: nf_ct_sip: validate Content-Length in TCP SIP messages
  - sctp: fix race between sctp_bind_addr_free() and
    sctp_bind_addr_conflict()
  - sctp: fix memory leak of the ASCONF queue when free asoc
  - md/bitmap: fix saving of events_cleared and other state
  - cdc_acm: Fix oops when Droids MuIn LCD is connected
  - cx88: Fix conversion from BKL to fine-grained locks (Closes: #619827)
  - keys: Set cred->user_ns in key_replace_session_keyring (CVE-2011-2184)
  - tmpfs: fix race between truncate and writepage
  - nfs41: Correct offset for LAYOUTCOMMIT
  - xen/mmu: fix a race window causing leave_mm BUG()
  - ext4: fix possible use-after-free in ext4_remove_li_request()
  For the complete list of changes, see:
   http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.39.1
* Bump ABI to 2
* netfilter: Enable IP_SET, IP_SET_BITMAP_IP, IP_SET_BITMAP_IPMAC,
  IP_SET_BITMAP_PORT, IP_SET_HASH_IP, IP_SET_HASH_IPPORT,
  IP_SET_HASH_IPPORTIP, IP_SET_HASH_IPPORTNET, IP_SET_HASH_NET,
  IP_SET_HASH_NETPORT, IP_SET_LIST_SET, NETFILTER_XT_SET as modules
  (Closes: #629401)

[ Aurelien Jarno ]
* [mipsel/loongson-2f] Disable_SCSI_LPFC to workaround GCC ICE.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Roccat Kova[+] 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 Kova[+] is a bigger version of the Pyra with two more side buttons.
 
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-kovaplus.h"
 
27
 
 
28
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
 
29
 
 
30
static struct class *kovaplus_class;
 
31
 
 
32
static uint kovaplus_convert_event_cpi(uint value)
 
33
{
 
34
        return (value == 7 ? 4 : (value == 4 ? 3 : value));
 
35
}
 
36
 
 
37
static void kovaplus_profile_activated(struct kovaplus_device *kovaplus,
 
38
                uint new_profile_index)
 
39
{
 
40
        kovaplus->actual_profile = new_profile_index;
 
41
        kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level;
 
42
        kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x;
 
43
        kovaplus->actual_y_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_y;
 
44
}
 
45
 
 
46
static int kovaplus_send_control(struct usb_device *usb_dev, uint value,
 
47
                enum kovaplus_control_requests request)
 
48
{
 
49
        int retval;
 
50
        struct kovaplus_control control;
 
51
 
 
52
        if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
 
53
                        request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
 
54
                        value > 4)
 
55
                return -EINVAL;
 
56
 
 
57
        control.command = KOVAPLUS_COMMAND_CONTROL;
 
58
        control.value = value;
 
59
        control.request = request;
 
60
 
 
61
        retval = roccat_common_send(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL,
 
62
                        &control, sizeof(struct kovaplus_control));
 
63
 
 
64
        return retval;
 
65
}
 
66
 
 
67
static int kovaplus_receive_control_status(struct usb_device *usb_dev)
 
68
{
 
69
        int retval;
 
70
        struct kovaplus_control control;
 
71
 
 
72
        do {
 
73
                retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL,
 
74
                                &control, sizeof(struct kovaplus_control));
 
75
 
 
76
                /* check if we get a completely wrong answer */
 
77
                if (retval)
 
78
                        return retval;
 
79
 
 
80
                if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OK)
 
81
                        return 0;
 
82
 
 
83
                /* indicates that hardware needs some more time to complete action */
 
84
                if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT) {
 
85
                        msleep(500); /* windows driver uses 1000 */
 
86
                        continue;
 
87
                }
 
88
 
 
89
                /* seems to be critical - replug necessary */
 
90
                if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD)
 
91
                        return -EINVAL;
 
92
 
 
93
                hid_err(usb_dev, "kovaplus_receive_control_status: "
 
94
                                "unknown response value 0x%x\n", control.value);
 
95
                return -EINVAL;
 
96
        } while (1);
 
97
}
 
98
 
 
99
static int kovaplus_send(struct usb_device *usb_dev, uint command,
 
100
                void const *buf, uint size)
 
101
{
 
102
        int retval;
 
103
 
 
104
        retval = roccat_common_send(usb_dev, command, buf, size);
 
105
        if (retval)
 
106
                return retval;
 
107
 
 
108
        msleep(100);
 
109
 
 
110
        return kovaplus_receive_control_status(usb_dev);
 
111
}
 
112
 
 
113
static int kovaplus_select_profile(struct usb_device *usb_dev, uint number,
 
114
                enum kovaplus_control_requests request)
 
115
{
 
116
        return kovaplus_send_control(usb_dev, number, request);
 
117
}
 
118
 
 
119
static int kovaplus_get_info(struct usb_device *usb_dev,
 
120
                struct kovaplus_info *buf)
 
121
{
 
122
        return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_INFO,
 
123
                        buf, sizeof(struct kovaplus_info));
 
124
}
 
125
 
 
126
static int kovaplus_get_profile_settings(struct usb_device *usb_dev,
 
127
                struct kovaplus_profile_settings *buf, uint number)
 
128
{
 
129
        int retval;
 
130
 
 
131
        retval = kovaplus_select_profile(usb_dev, number,
 
132
                        KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
 
133
        if (retval)
 
134
                return retval;
 
135
 
 
136
        return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS,
 
137
                        buf, sizeof(struct kovaplus_profile_settings));
 
138
}
 
139
 
 
140
static int kovaplus_set_profile_settings(struct usb_device *usb_dev,
 
141
                struct kovaplus_profile_settings const *settings)
 
142
{
 
143
        return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS,
 
144
                        settings, sizeof(struct kovaplus_profile_settings));
 
145
}
 
146
 
 
147
static int kovaplus_get_profile_buttons(struct usb_device *usb_dev,
 
148
                struct kovaplus_profile_buttons *buf, int number)
 
149
{
 
150
        int retval;
 
151
 
 
152
        retval = kovaplus_select_profile(usb_dev, number,
 
153
                        KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
 
154
        if (retval)
 
155
                return retval;
 
156
 
 
157
        return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS,
 
158
                        buf, sizeof(struct kovaplus_profile_buttons));
 
159
}
 
160
 
 
161
static int kovaplus_set_profile_buttons(struct usb_device *usb_dev,
 
162
                struct kovaplus_profile_buttons const *buttons)
 
163
{
 
164
        return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS,
 
165
                        buttons, sizeof(struct kovaplus_profile_buttons));
 
166
}
 
167
 
 
168
/* retval is 0-4 on success, < 0 on error */
 
169
static int kovaplus_get_actual_profile(struct usb_device *usb_dev)
 
170
{
 
171
        struct kovaplus_actual_profile buf;
 
172
        int retval;
 
173
 
 
174
        retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE,
 
175
                        &buf, sizeof(struct kovaplus_actual_profile));
 
176
 
 
177
        return retval ? retval : buf.actual_profile;
 
178
}
 
179
 
 
180
static int kovaplus_set_actual_profile(struct usb_device *usb_dev,
 
181
                int new_profile)
 
182
{
 
183
        struct kovaplus_actual_profile buf;
 
184
 
 
185
        buf.command = KOVAPLUS_COMMAND_ACTUAL_PROFILE;
 
186
        buf.size = sizeof(struct kovaplus_actual_profile);
 
187
        buf.actual_profile = new_profile;
 
188
 
 
189
        return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE,
 
190
                        &buf, sizeof(struct kovaplus_actual_profile));
 
191
}
 
192
 
 
193
static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
 
194
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 
195
                loff_t off, size_t count)
 
196
{
 
197
        struct device *dev =
 
198
                        container_of(kobj, struct device, kobj)->parent->parent;
 
199
        struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 
200
 
 
201
        if (off >= sizeof(struct kovaplus_profile_settings))
 
202
                return 0;
 
203
 
 
204
        if (off + count > sizeof(struct kovaplus_profile_settings))
 
205
                count = sizeof(struct kovaplus_profile_settings) - off;
 
206
 
 
207
        mutex_lock(&kovaplus->kovaplus_lock);
 
208
        memcpy(buf, ((char const *)&kovaplus->profile_settings[*(uint *)(attr->private)]) + off,
 
209
                        count);
 
210
        mutex_unlock(&kovaplus->kovaplus_lock);
 
211
 
 
212
        return count;
 
213
}
 
214
 
 
215
static ssize_t kovaplus_sysfs_write_profile_settings(struct file *fp,
 
216
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 
217
                loff_t off, size_t count)
 
218
{
 
219
        struct device *dev =
 
220
                        container_of(kobj, struct device, kobj)->parent->parent;
 
221
        struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 
222
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
223
        int retval = 0;
 
224
        int difference;
 
225
        int profile_index;
 
226
        struct kovaplus_profile_settings *profile_settings;
 
227
 
 
228
        if (off != 0 || count != sizeof(struct kovaplus_profile_settings))
 
229
                return -EINVAL;
 
230
 
 
231
        profile_index = ((struct kovaplus_profile_settings const *)buf)->profile_index;
 
232
        profile_settings = &kovaplus->profile_settings[profile_index];
 
233
 
 
234
        mutex_lock(&kovaplus->kovaplus_lock);
 
235
        difference = memcmp(buf, profile_settings,
 
236
                        sizeof(struct kovaplus_profile_settings));
 
237
        if (difference) {
 
238
                retval = kovaplus_set_profile_settings(usb_dev,
 
239
                                (struct kovaplus_profile_settings const *)buf);
 
240
                if (!retval)
 
241
                        memcpy(profile_settings, buf,
 
242
                                        sizeof(struct kovaplus_profile_settings));
 
243
        }
 
244
        mutex_unlock(&kovaplus->kovaplus_lock);
 
245
 
 
246
        if (retval)
 
247
                return retval;
 
248
 
 
249
        return sizeof(struct kovaplus_profile_settings);
 
250
}
 
251
 
 
252
static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
 
253
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 
254
                loff_t off, size_t count)
 
255
{
 
256
        struct device *dev =
 
257
                        container_of(kobj, struct device, kobj)->parent->parent;
 
258
        struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 
259
 
 
260
        if (off >= sizeof(struct kovaplus_profile_buttons))
 
261
                return 0;
 
262
 
 
263
        if (off + count > sizeof(struct kovaplus_profile_buttons))
 
264
                count = sizeof(struct kovaplus_profile_buttons) - off;
 
265
 
 
266
        mutex_lock(&kovaplus->kovaplus_lock);
 
267
        memcpy(buf, ((char const *)&kovaplus->profile_buttons[*(uint *)(attr->private)]) + off,
 
268
                        count);
 
269
        mutex_unlock(&kovaplus->kovaplus_lock);
 
270
 
 
271
        return count;
 
272
}
 
273
 
 
274
static ssize_t kovaplus_sysfs_write_profile_buttons(struct file *fp,
 
275
                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 
276
                loff_t off, size_t count)
 
277
{
 
278
        struct device *dev =
 
279
                        container_of(kobj, struct device, kobj)->parent->parent;
 
280
        struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 
281
        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
282
        int retval = 0;
 
283
        int difference;
 
284
        uint profile_index;
 
285
        struct kovaplus_profile_buttons *profile_buttons;
 
286
 
 
287
        if (off != 0 || count != sizeof(struct kovaplus_profile_buttons))
 
288
                return -EINVAL;
 
289
 
 
290
        profile_index = ((struct kovaplus_profile_buttons const *)buf)->profile_index;
 
291
        profile_buttons = &kovaplus->profile_buttons[profile_index];
 
292
 
 
293
        mutex_lock(&kovaplus->kovaplus_lock);
 
294
        difference = memcmp(buf, profile_buttons,
 
295
                        sizeof(struct kovaplus_profile_buttons));
 
296
        if (difference) {
 
297
                retval = kovaplus_set_profile_buttons(usb_dev,
 
298
                                (struct kovaplus_profile_buttons const *)buf);
 
299
                if (!retval)
 
300
                        memcpy(profile_buttons, buf,
 
301
                                        sizeof(struct kovaplus_profile_buttons));
 
302
        }
 
303
        mutex_unlock(&kovaplus->kovaplus_lock);
 
304
 
 
305
        if (retval)
 
306
                return retval;
 
307
 
 
308
        return sizeof(struct kovaplus_profile_buttons);
 
309
}
 
310
 
 
311
static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev,
 
312
                struct device_attribute *attr, char *buf)
 
313
{
 
314
        struct kovaplus_device *kovaplus =
 
315
                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 
316
        return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_profile);
 
317
}
 
318
 
 
319
static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
 
320
                struct device_attribute *attr, char const *buf, size_t size)
 
321
{
 
322
        struct kovaplus_device *kovaplus;
 
323
        struct usb_device *usb_dev;
 
324
        unsigned long profile;
 
325
        int retval;
 
326
 
 
327
        dev = dev->parent->parent;
 
328
        kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 
329
        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 
330
 
 
331
        retval = strict_strtoul(buf, 10, &profile);
 
332
        if (retval)
 
333
                return retval;
 
334
 
 
335
        if (profile >= 5)
 
336
                return -EINVAL;
 
337
 
 
338
        mutex_lock(&kovaplus->kovaplus_lock);
 
339
        retval = kovaplus_set_actual_profile(usb_dev, profile);
 
340
        kovaplus->actual_profile = profile;
 
341
        mutex_unlock(&kovaplus->kovaplus_lock);
 
342
        if (retval)
 
343
                return retval;
 
344
 
 
345
        return size;
 
346
}
 
347
 
 
348
static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev,
 
349
                struct device_attribute *attr, char *buf)
 
350
{
 
351
        struct kovaplus_device *kovaplus =
 
352
                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 
353
        return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi);
 
354
}
 
355
 
 
356
static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev,
 
357
                struct device_attribute *attr, char *buf)
 
358
{
 
359
        struct kovaplus_device *kovaplus =
 
360
                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 
361
        return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity);
 
362
}
 
363
 
 
364
static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
 
365
                struct device_attribute *attr, char *buf)
 
366
{
 
367
        struct kovaplus_device *kovaplus =
 
368
                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 
369
        return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity);
 
370
}
 
371
 
 
372
static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
 
373
                struct device_attribute *attr, char *buf)
 
374
{
 
375
        struct kovaplus_device *kovaplus =
 
376
                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 
377
        return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->info.firmware_version);
 
378
}
 
379
 
 
380
static struct device_attribute kovaplus_attributes[] = {
 
381
        __ATTR(actual_cpi, 0440,
 
382
                kovaplus_sysfs_show_actual_cpi, NULL),
 
383
        __ATTR(firmware_version, 0440,
 
384
                kovaplus_sysfs_show_firmware_version, NULL),
 
385
        __ATTR(actual_profile, 0660,
 
386
                kovaplus_sysfs_show_actual_profile,
 
387
                kovaplus_sysfs_set_actual_profile),
 
388
        __ATTR(actual_sensitivity_x, 0440,
 
389
                kovaplus_sysfs_show_actual_sensitivity_x, NULL),
 
390
        __ATTR(actual_sensitivity_y, 0440,
 
391
                kovaplus_sysfs_show_actual_sensitivity_y, NULL),
 
392
        __ATTR_NULL
 
393
};
 
394
 
 
395
static struct bin_attribute kovaplus_bin_attributes[] = {
 
396
        {
 
397
                .attr = { .name = "profile_settings", .mode = 0220 },
 
398
                .size = sizeof(struct kovaplus_profile_settings),
 
399
                .write = kovaplus_sysfs_write_profile_settings
 
400
        },
 
401
        {
 
402
                .attr = { .name = "profile1_settings", .mode = 0440 },
 
403
                .size = sizeof(struct kovaplus_profile_settings),
 
404
                .read = kovaplus_sysfs_read_profilex_settings,
 
405
                .private = &profile_numbers[0]
 
406
        },
 
407
        {
 
408
                .attr = { .name = "profile2_settings", .mode = 0440 },
 
409
                .size = sizeof(struct kovaplus_profile_settings),
 
410
                .read = kovaplus_sysfs_read_profilex_settings,
 
411
                .private = &profile_numbers[1]
 
412
        },
 
413
        {
 
414
                .attr = { .name = "profile3_settings", .mode = 0440 },
 
415
                .size = sizeof(struct kovaplus_profile_settings),
 
416
                .read = kovaplus_sysfs_read_profilex_settings,
 
417
                .private = &profile_numbers[2]
 
418
        },
 
419
        {
 
420
                .attr = { .name = "profile4_settings", .mode = 0440 },
 
421
                .size = sizeof(struct kovaplus_profile_settings),
 
422
                .read = kovaplus_sysfs_read_profilex_settings,
 
423
                .private = &profile_numbers[3]
 
424
        },
 
425
        {
 
426
                .attr = { .name = "profile5_settings", .mode = 0440 },
 
427
                .size = sizeof(struct kovaplus_profile_settings),
 
428
                .read = kovaplus_sysfs_read_profilex_settings,
 
429
                .private = &profile_numbers[4]
 
430
        },
 
431
        {
 
432
                .attr = { .name = "profile_buttons", .mode = 0220 },
 
433
                .size = sizeof(struct kovaplus_profile_buttons),
 
434
                .write = kovaplus_sysfs_write_profile_buttons
 
435
        },
 
436
        {
 
437
                .attr = { .name = "profile1_buttons", .mode = 0440 },
 
438
                .size = sizeof(struct kovaplus_profile_buttons),
 
439
                .read = kovaplus_sysfs_read_profilex_buttons,
 
440
                .private = &profile_numbers[0]
 
441
        },
 
442
        {
 
443
                .attr = { .name = "profile2_buttons", .mode = 0440 },
 
444
                .size = sizeof(struct kovaplus_profile_buttons),
 
445
                .read = kovaplus_sysfs_read_profilex_buttons,
 
446
                .private = &profile_numbers[1]
 
447
        },
 
448
        {
 
449
                .attr = { .name = "profile3_buttons", .mode = 0440 },
 
450
                .size = sizeof(struct kovaplus_profile_buttons),
 
451
                .read = kovaplus_sysfs_read_profilex_buttons,
 
452
                .private = &profile_numbers[2]
 
453
        },
 
454
        {
 
455
                .attr = { .name = "profile4_buttons", .mode = 0440 },
 
456
                .size = sizeof(struct kovaplus_profile_buttons),
 
457
                .read = kovaplus_sysfs_read_profilex_buttons,
 
458
                .private = &profile_numbers[3]
 
459
        },
 
460
        {
 
461
                .attr = { .name = "profile5_buttons", .mode = 0440 },
 
462
                .size = sizeof(struct kovaplus_profile_buttons),
 
463
                .read = kovaplus_sysfs_read_profilex_buttons,
 
464
                .private = &profile_numbers[4]
 
465
        },
 
466
        __ATTR_NULL
 
467
};
 
468
 
 
469
static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
 
470
                struct kovaplus_device *kovaplus)
 
471
{
 
472
        int retval, i;
 
473
        static uint wait = 70; /* device will freeze with just 60 */
 
474
 
 
475
        mutex_init(&kovaplus->kovaplus_lock);
 
476
 
 
477
        retval = kovaplus_get_info(usb_dev, &kovaplus->info);
 
478
        if (retval)
 
479
                return retval;
 
480
 
 
481
        for (i = 0; i < 5; ++i) {
 
482
                msleep(wait);
 
483
                retval = kovaplus_get_profile_settings(usb_dev,
 
484
                                &kovaplus->profile_settings[i], i);
 
485
                if (retval)
 
486
                        return retval;
 
487
 
 
488
                msleep(wait);
 
489
                retval = kovaplus_get_profile_buttons(usb_dev,
 
490
                                &kovaplus->profile_buttons[i], i);
 
491
                if (retval)
 
492
                        return retval;
 
493
        }
 
494
 
 
495
        msleep(wait);
 
496
        retval = kovaplus_get_actual_profile(usb_dev);
 
497
        if (retval < 0)
 
498
                return retval;
 
499
        kovaplus_profile_activated(kovaplus, retval);
 
500
 
 
501
        return 0;
 
502
}
 
503
 
 
504
static int kovaplus_init_specials(struct hid_device *hdev)
 
505
{
 
506
        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
507
        struct usb_device *usb_dev = interface_to_usbdev(intf);
 
508
        struct kovaplus_device *kovaplus;
 
509
        int retval;
 
510
 
 
511
        if (intf->cur_altsetting->desc.bInterfaceProtocol
 
512
                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 
513
 
 
514
                kovaplus = kzalloc(sizeof(*kovaplus), GFP_KERNEL);
 
515
                if (!kovaplus) {
 
516
                        hid_err(hdev, "can't alloc device descriptor\n");
 
517
                        return -ENOMEM;
 
518
                }
 
519
                hid_set_drvdata(hdev, kovaplus);
 
520
 
 
521
                retval = kovaplus_init_kovaplus_device_struct(usb_dev, kovaplus);
 
522
                if (retval) {
 
523
                        hid_err(hdev, "couldn't init struct kovaplus_device\n");
 
524
                        goto exit_free;
 
525
                }
 
526
 
 
527
                retval = roccat_connect(kovaplus_class, hdev,
 
528
                                sizeof(struct kovaplus_roccat_report));
 
529
                if (retval < 0) {
 
530
                        hid_err(hdev, "couldn't init char dev\n");
 
531
                } else {
 
532
                        kovaplus->chrdev_minor = retval;
 
533
                        kovaplus->roccat_claimed = 1;
 
534
                }
 
535
 
 
536
        } else {
 
537
                hid_set_drvdata(hdev, NULL);
 
538
        }
 
539
 
 
540
        return 0;
 
541
exit_free:
 
542
        kfree(kovaplus);
 
543
        return retval;
 
544
}
 
545
 
 
546
static void kovaplus_remove_specials(struct hid_device *hdev)
 
547
{
 
548
        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
549
        struct kovaplus_device *kovaplus;
 
550
 
 
551
        if (intf->cur_altsetting->desc.bInterfaceProtocol
 
552
                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 
553
                kovaplus = hid_get_drvdata(hdev);
 
554
                if (kovaplus->roccat_claimed)
 
555
                        roccat_disconnect(kovaplus->chrdev_minor);
 
556
                kfree(kovaplus);
 
557
        }
 
558
}
 
559
 
 
560
static int kovaplus_probe(struct hid_device *hdev,
 
561
                const struct hid_device_id *id)
 
562
{
 
563
        int retval;
 
564
 
 
565
        retval = hid_parse(hdev);
 
566
        if (retval) {
 
567
                hid_err(hdev, "parse failed\n");
 
568
                goto exit;
 
569
        }
 
570
 
 
571
        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 
572
        if (retval) {
 
573
                hid_err(hdev, "hw start failed\n");
 
574
                goto exit;
 
575
        }
 
576
 
 
577
        retval = kovaplus_init_specials(hdev);
 
578
        if (retval) {
 
579
                hid_err(hdev, "couldn't install mouse\n");
 
580
                goto exit_stop;
 
581
        }
 
582
 
 
583
        return 0;
 
584
 
 
585
exit_stop:
 
586
        hid_hw_stop(hdev);
 
587
exit:
 
588
        return retval;
 
589
}
 
590
 
 
591
static void kovaplus_remove(struct hid_device *hdev)
 
592
{
 
593
        kovaplus_remove_specials(hdev);
 
594
        hid_hw_stop(hdev);
 
595
}
 
596
 
 
597
static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus,
 
598
                u8 const *data)
 
599
{
 
600
        struct kovaplus_mouse_report_button const *button_report;
 
601
 
 
602
        if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
 
603
                return;
 
604
 
 
605
        button_report = (struct kovaplus_mouse_report_button const *)data;
 
606
 
 
607
        switch (button_report->type) {
 
608
        case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1:
 
609
                kovaplus_profile_activated(kovaplus, button_report->data1 - 1);
 
610
                break;
 
611
        case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI:
 
612
                kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1);
 
613
        case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY:
 
614
                kovaplus->actual_x_sensitivity = button_report->data1;
 
615
                kovaplus->actual_y_sensitivity = button_report->data2;
 
616
        }
 
617
}
 
618
 
 
619
static void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus,
 
620
                u8 const *data)
 
621
{
 
622
        struct kovaplus_roccat_report roccat_report;
 
623
        struct kovaplus_mouse_report_button const *button_report;
 
624
 
 
625
        if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
 
626
                return;
 
627
 
 
628
        button_report = (struct kovaplus_mouse_report_button const *)data;
 
629
 
 
630
        if (button_report->type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2)
 
631
                return;
 
632
 
 
633
        roccat_report.type = button_report->type;
 
634
        roccat_report.profile = kovaplus->actual_profile + 1;
 
635
 
 
636
        if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO ||
 
637
                        roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT ||
 
638
                        roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
 
639
                        roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER)
 
640
                roccat_report.button = button_report->data1;
 
641
        else
 
642
                roccat_report.button = 0;
 
643
 
 
644
        if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI)
 
645
                roccat_report.data1 = kovaplus_convert_event_cpi(button_report->data1);
 
646
        else
 
647
                roccat_report.data1 = button_report->data1;
 
648
 
 
649
        roccat_report.data2 = button_report->data2;
 
650
 
 
651
        roccat_report_event(kovaplus->chrdev_minor,
 
652
                        (uint8_t const *)&roccat_report);
 
653
}
 
654
 
 
655
static int kovaplus_raw_event(struct hid_device *hdev,
 
656
                struct hid_report *report, u8 *data, int size)
 
657
{
 
658
        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 
659
        struct kovaplus_device *kovaplus = hid_get_drvdata(hdev);
 
660
 
 
661
        if (intf->cur_altsetting->desc.bInterfaceProtocol
 
662
                        != USB_INTERFACE_PROTOCOL_MOUSE)
 
663
                return 0;
 
664
 
 
665
        kovaplus_keep_values_up_to_date(kovaplus, data);
 
666
 
 
667
        if (kovaplus->roccat_claimed)
 
668
                kovaplus_report_to_chrdev(kovaplus, data);
 
669
 
 
670
        return 0;
 
671
}
 
672
 
 
673
static const struct hid_device_id kovaplus_devices[] = {
 
674
        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
 
675
        { }
 
676
};
 
677
 
 
678
MODULE_DEVICE_TABLE(hid, kovaplus_devices);
 
679
 
 
680
static struct hid_driver kovaplus_driver = {
 
681
                .name = "kovaplus",
 
682
                .id_table = kovaplus_devices,
 
683
                .probe = kovaplus_probe,
 
684
                .remove = kovaplus_remove,
 
685
                .raw_event = kovaplus_raw_event
 
686
};
 
687
 
 
688
static int __init kovaplus_init(void)
 
689
{
 
690
        int retval;
 
691
 
 
692
        kovaplus_class = class_create(THIS_MODULE, "kovaplus");
 
693
        if (IS_ERR(kovaplus_class))
 
694
                return PTR_ERR(kovaplus_class);
 
695
        kovaplus_class->dev_attrs = kovaplus_attributes;
 
696
        kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes;
 
697
 
 
698
        retval = hid_register_driver(&kovaplus_driver);
 
699
        if (retval)
 
700
                class_destroy(kovaplus_class);
 
701
        return retval;
 
702
}
 
703
 
 
704
static void __exit kovaplus_exit(void)
 
705
{
 
706
        hid_unregister_driver(&kovaplus_driver);
 
707
        class_destroy(kovaplus_class);
 
708
}
 
709
 
 
710
module_init(kovaplus_init);
 
711
module_exit(kovaplus_exit);
 
712
 
 
713
MODULE_AUTHOR("Stefan Achatz");
 
714
MODULE_DESCRIPTION("USB Roccat Kova[+] driver");
 
715
MODULE_LICENSE("GPL v2");