Root/drivers/hid/hid-roccat-kovaplus.c

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

Archive Download this file



interactive