918 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Roccat Kone driver for Linux4 *5 * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>6 */7 8/*9 */10 11/*12 * Roccat Kone is a gamer mouse which consists of a mouse part and a keyboard13 * part. The keyboard part enables the mouse to execute stored macros with mixed14 * key- and button-events.15 *16 * TODO implement on-the-fly polling-rate change17 * The windows driver has the ability to change the polling rate of the18 * device on the press of a mousebutton.19 * Is it possible to remove and reinstall the urb in raw-event- or any20 * other handler, or to defer this action to be executed somewhere else?21 *22 * TODO is it possible to overwrite group for sysfs attributes via udev?23 */24 25#include <linux/device.h>26#include <linux/input.h>27#include <linux/hid.h>28#include <linux/module.h>29#include <linux/slab.h>30#include <linux/hid-roccat.h>31#include "hid-ids.h"32#include "hid-roccat-common.h"33#include "hid-roccat-kone.h"34 35static uint profile_numbers[5] = {0, 1, 2, 3, 4};36 37static void kone_profile_activated(struct kone_device *kone, uint new_profile)38{39 kone->actual_profile = new_profile;40 kone->actual_dpi = kone->profiles[new_profile - 1].startup_dpi;41}42 43static void kone_profile_report(struct kone_device *kone, uint new_profile)44{45 struct kone_roccat_report roccat_report;46 47 roccat_report.event = kone_mouse_event_switch_profile;48 roccat_report.value = new_profile;49 roccat_report.key = 0;50 roccat_report_event(kone->chrdev_minor, (uint8_t *)&roccat_report);51}52 53static int kone_receive(struct usb_device *usb_dev, uint usb_command,54 void *data, uint size)55{56 char *buf;57 int len;58 59 buf = kmalloc(size, GFP_KERNEL);60 if (buf == NULL)61 return -ENOMEM;62 63 len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),64 HID_REQ_GET_REPORT,65 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,66 usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);67 68 memcpy(data, buf, size);69 kfree(buf);70 return ((len < 0) ? len : ((len != size) ? -EIO : 0));71}72 73static int kone_send(struct usb_device *usb_dev, uint usb_command,74 void const *data, uint size)75{76 char *buf;77 int len;78 79 buf = kmemdup(data, size, GFP_KERNEL);80 if (buf == NULL)81 return -ENOMEM;82 83 len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),84 HID_REQ_SET_REPORT,85 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,86 usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);87 88 kfree(buf);89 return ((len < 0) ? len : ((len != size) ? -EIO : 0));90}91 92static void kone_set_settings_checksum(struct kone_settings *settings)93{94 uint16_t checksum = 0;95 unsigned char *address = (unsigned char *)settings;96 int i;97 98 for (i = 0; i < sizeof(struct kone_settings) - 2; ++i, ++address)99 checksum += *address;100 settings->checksum = cpu_to_le16(checksum);101}102 103/*104 * Checks success after writing data to mouse105 * On success returns 0106 * On failure returns errno107 */108static int kone_check_write(struct usb_device *usb_dev)109{110 int retval;111 uint8_t data;112 113 do {114 /*115 * Mouse needs 50 msecs until it says ok, but there are116 * 30 more msecs needed for next write to work.117 */118 msleep(80);119 120 retval = kone_receive(usb_dev,121 kone_command_confirm_write, &data, 1);122 if (retval)123 return retval;124 125 /*126 * value of 3 seems to mean something like127 * "not finished yet, but it looks good"128 * So check again after a moment.129 */130 } while (data == 3);131 132 if (data == 1) /* everything alright */133 return 0;134 135 /* unknown answer */136 dev_err(&usb_dev->dev, "got retval %d when checking write\n", data);137 return -EIO;138}139 140/*141 * Reads settings from mouse and stores it in @buf142 * On success returns 0143 * On failure returns errno144 */145static int kone_get_settings(struct usb_device *usb_dev,146 struct kone_settings *buf)147{148 return kone_receive(usb_dev, kone_command_settings, buf,149 sizeof(struct kone_settings));150}151 152/*153 * Writes settings from @buf to mouse154 * On success returns 0155 * On failure returns errno156 */157static int kone_set_settings(struct usb_device *usb_dev,158 struct kone_settings const *settings)159{160 int retval;161 162 retval = kone_send(usb_dev, kone_command_settings,163 settings, sizeof(struct kone_settings));164 if (retval)165 return retval;166 return kone_check_write(usb_dev);167}168 169/*170 * Reads profile data from mouse and stores it in @buf171 * @number: profile number to read172 * On success returns 0173 * On failure returns errno174 */175static int kone_get_profile(struct usb_device *usb_dev,176 struct kone_profile *buf, int number)177{178 int len;179 180 if (number < 1 || number > 5)181 return -EINVAL;182 183 len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),184 USB_REQ_CLEAR_FEATURE,185 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,186 kone_command_profile, number, buf,187 sizeof(struct kone_profile), USB_CTRL_SET_TIMEOUT);188 189 if (len != sizeof(struct kone_profile))190 return -EIO;191 192 return 0;193}194 195/*196 * Writes profile data to mouse.197 * @number: profile number to write198 * On success returns 0199 * On failure returns errno200 */201static int kone_set_profile(struct usb_device *usb_dev,202 struct kone_profile const *profile, int number)203{204 int len;205 206 if (number < 1 || number > 5)207 return -EINVAL;208 209 len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),210 USB_REQ_SET_CONFIGURATION,211 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,212 kone_command_profile, number, (void *)profile,213 sizeof(struct kone_profile),214 USB_CTRL_SET_TIMEOUT);215 216 if (len != sizeof(struct kone_profile))217 return len;218 219 if (kone_check_write(usb_dev))220 return -EIO;221 222 return 0;223}224 225/*226 * Reads value of "fast-clip-weight" and stores it in @result227 * On success returns 0228 * On failure returns errno229 */230static int kone_get_weight(struct usb_device *usb_dev, int *result)231{232 int retval;233 uint8_t data;234 235 retval = kone_receive(usb_dev, kone_command_weight, &data, 1);236 237 if (retval)238 return retval;239 240 *result = (int)data;241 return 0;242}243 244/*245 * Reads firmware_version of mouse and stores it in @result246 * On success returns 0247 * On failure returns errno248 */249static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)250{251 int retval;252 uint16_t data;253 254 retval = kone_receive(usb_dev, kone_command_firmware_version,255 &data, 2);256 if (retval)257 return retval;258 259 *result = le16_to_cpu(data);260 return 0;261}262 263static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,264 struct bin_attribute *attr, char *buf,265 loff_t off, size_t count) {266 struct device *dev = kobj_to_dev(kobj)->parent->parent;267 struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));268 269 if (off >= sizeof(struct kone_settings))270 return 0;271 272 if (off + count > sizeof(struct kone_settings))273 count = sizeof(struct kone_settings) - off;274 275 mutex_lock(&kone->kone_lock);276 memcpy(buf, ((char const *)&kone->settings) + off, count);277 mutex_unlock(&kone->kone_lock);278 279 return count;280}281 282/*283 * Writing settings automatically activates startup_profile.284 * This function keeps values in kone_device up to date and assumes that in285 * case of error the old data is still valid286 */287static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,288 struct bin_attribute *attr, char *buf,289 loff_t off, size_t count) {290 struct device *dev = kobj_to_dev(kobj)->parent->parent;291 struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));292 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));293 int retval = 0, difference, old_profile;294 struct kone_settings *settings = (struct kone_settings *)buf;295 296 /* I need to get my data in one piece */297 if (off != 0 || count != sizeof(struct kone_settings))298 return -EINVAL;299 300 mutex_lock(&kone->kone_lock);301 difference = memcmp(settings, &kone->settings,302 sizeof(struct kone_settings));303 if (difference) {304 if (settings->startup_profile < 1 ||305 settings->startup_profile > 5) {306 retval = -EINVAL;307 goto unlock;308 }309 310 retval = kone_set_settings(usb_dev, settings);311 if (retval)312 goto unlock;313 314 old_profile = kone->settings.startup_profile;315 memcpy(&kone->settings, settings, sizeof(struct kone_settings));316 317 kone_profile_activated(kone, kone->settings.startup_profile);318 319 if (kone->settings.startup_profile != old_profile)320 kone_profile_report(kone, kone->settings.startup_profile);321 }322unlock:323 mutex_unlock(&kone->kone_lock);324 325 if (retval)326 return retval;327 328 return sizeof(struct kone_settings);329}330static BIN_ATTR(settings, 0660, kone_sysfs_read_settings,331 kone_sysfs_write_settings, sizeof(struct kone_settings));332 333static ssize_t kone_sysfs_read_profilex(struct file *fp,334 struct kobject *kobj, struct bin_attribute *attr,335 char *buf, loff_t off, size_t count) {336 struct device *dev = kobj_to_dev(kobj)->parent->parent;337 struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));338 339 if (off >= sizeof(struct kone_profile))340 return 0;341 342 if (off + count > sizeof(struct kone_profile))343 count = sizeof(struct kone_profile) - off;344 345 mutex_lock(&kone->kone_lock);346 memcpy(buf, ((char const *)&kone->profiles[*(uint *)(attr->private)]) + off, count);347 mutex_unlock(&kone->kone_lock);348 349 return count;350}351 352/* Writes data only if different to stored data */353static ssize_t kone_sysfs_write_profilex(struct file *fp,354 struct kobject *kobj, struct bin_attribute *attr,355 char *buf, loff_t off, size_t count) {356 struct device *dev = kobj_to_dev(kobj)->parent->parent;357 struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));358 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));359 struct kone_profile *profile;360 int retval = 0, difference;361 362 /* I need to get my data in one piece */363 if (off != 0 || count != sizeof(struct kone_profile))364 return -EINVAL;365 366 profile = &kone->profiles[*(uint *)(attr->private)];367 368 mutex_lock(&kone->kone_lock);369 difference = memcmp(buf, profile, sizeof(struct kone_profile));370 if (difference) {371 retval = kone_set_profile(usb_dev,372 (struct kone_profile const *)buf,373 *(uint *)(attr->private) + 1);374 if (!retval)375 memcpy(profile, buf, sizeof(struct kone_profile));376 }377 mutex_unlock(&kone->kone_lock);378 379 if (retval)380 return retval;381 382 return sizeof(struct kone_profile);383}384#define PROFILE_ATTR(number) \385static struct bin_attribute bin_attr_profile##number = { \386 .attr = { .name = "profile" #number, .mode = 0660 }, \387 .size = sizeof(struct kone_profile), \388 .read = kone_sysfs_read_profilex, \389 .write = kone_sysfs_write_profilex, \390 .private = &profile_numbers[number-1], \391}392PROFILE_ATTR(1);393PROFILE_ATTR(2);394PROFILE_ATTR(3);395PROFILE_ATTR(4);396PROFILE_ATTR(5);397 398static ssize_t kone_sysfs_show_actual_profile(struct device *dev,399 struct device_attribute *attr, char *buf)400{401 struct kone_device *kone =402 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));403 return sysfs_emit(buf, "%d\n", kone->actual_profile);404}405static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL);406 407static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,408 struct device_attribute *attr, char *buf)409{410 struct kone_device *kone =411 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));412 return sysfs_emit(buf, "%d\n", kone->actual_dpi);413}414static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL);415 416/* weight is read each time, since we don't get informed when it's changed */417static ssize_t kone_sysfs_show_weight(struct device *dev,418 struct device_attribute *attr, char *buf)419{420 struct kone_device *kone;421 struct usb_device *usb_dev;422 int weight = 0;423 int retval;424 425 dev = dev->parent->parent;426 kone = hid_get_drvdata(dev_get_drvdata(dev));427 usb_dev = interface_to_usbdev(to_usb_interface(dev));428 429 mutex_lock(&kone->kone_lock);430 retval = kone_get_weight(usb_dev, &weight);431 mutex_unlock(&kone->kone_lock);432 433 if (retval)434 return retval;435 return sysfs_emit(buf, "%d\n", weight);436}437static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL);438 439static ssize_t kone_sysfs_show_firmware_version(struct device *dev,440 struct device_attribute *attr, char *buf)441{442 struct kone_device *kone =443 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));444 return sysfs_emit(buf, "%d\n", kone->firmware_version);445}446static DEVICE_ATTR(firmware_version, 0440, kone_sysfs_show_firmware_version,447 NULL);448 449static ssize_t kone_sysfs_show_tcu(struct device *dev,450 struct device_attribute *attr, char *buf)451{452 struct kone_device *kone =453 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));454 return sysfs_emit(buf, "%d\n", kone->settings.tcu);455}456 457static int kone_tcu_command(struct usb_device *usb_dev, int number)458{459 unsigned char value;460 461 value = number;462 return kone_send(usb_dev, kone_command_calibrate, &value, 1);463}464 465/*466 * Calibrating the tcu is the only action that changes settings data inside the467 * mouse, so this data needs to be reread468 */469static ssize_t kone_sysfs_set_tcu(struct device *dev,470 struct device_attribute *attr, char const *buf, size_t size)471{472 struct kone_device *kone;473 struct usb_device *usb_dev;474 int retval;475 unsigned long state;476 477 dev = dev->parent->parent;478 kone = hid_get_drvdata(dev_get_drvdata(dev));479 usb_dev = interface_to_usbdev(to_usb_interface(dev));480 481 retval = kstrtoul(buf, 10, &state);482 if (retval)483 return retval;484 485 if (state != 0 && state != 1)486 return -EINVAL;487 488 mutex_lock(&kone->kone_lock);489 490 if (state == 1) { /* state activate */491 retval = kone_tcu_command(usb_dev, 1);492 if (retval)493 goto exit_unlock;494 retval = kone_tcu_command(usb_dev, 2);495 if (retval)496 goto exit_unlock;497 ssleep(5); /* tcu needs this time for calibration */498 retval = kone_tcu_command(usb_dev, 3);499 if (retval)500 goto exit_unlock;501 retval = kone_tcu_command(usb_dev, 0);502 if (retval)503 goto exit_unlock;504 retval = kone_tcu_command(usb_dev, 4);505 if (retval)506 goto exit_unlock;507 /*508 * Kone needs this time to settle things.509 * Reading settings too early will result in invalid data.510 * Roccat's driver waits 1 sec, maybe this time could be511 * shortened.512 */513 ssleep(1);514 }515 516 /* calibration changes values in settings, so reread */517 retval = kone_get_settings(usb_dev, &kone->settings);518 if (retval)519 goto exit_no_settings;520 521 /* only write settings back if activation state is different */522 if (kone->settings.tcu != state) {523 kone->settings.tcu = state;524 kone_set_settings_checksum(&kone->settings);525 526 retval = kone_set_settings(usb_dev, &kone->settings);527 if (retval) {528 dev_err(&usb_dev->dev, "couldn't set tcu state\n");529 /*530 * try to reread valid settings into buffer overwriting531 * first error code532 */533 retval = kone_get_settings(usb_dev, &kone->settings);534 if (retval)535 goto exit_no_settings;536 goto exit_unlock;537 }538 /* calibration resets profile */539 kone_profile_activated(kone, kone->settings.startup_profile);540 }541 542 retval = size;543exit_no_settings:544 dev_err(&usb_dev->dev, "couldn't read settings\n");545exit_unlock:546 mutex_unlock(&kone->kone_lock);547 return retval;548}549static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu);550 551static ssize_t kone_sysfs_show_startup_profile(struct device *dev,552 struct device_attribute *attr, char *buf)553{554 struct kone_device *kone =555 hid_get_drvdata(dev_get_drvdata(dev->parent->parent));556 return sysfs_emit(buf, "%d\n", kone->settings.startup_profile);557}558 559static ssize_t kone_sysfs_set_startup_profile(struct device *dev,560 struct device_attribute *attr, char const *buf, size_t size)561{562 struct kone_device *kone;563 struct usb_device *usb_dev;564 int retval;565 unsigned long new_startup_profile;566 567 dev = dev->parent->parent;568 kone = hid_get_drvdata(dev_get_drvdata(dev));569 usb_dev = interface_to_usbdev(to_usb_interface(dev));570 571 retval = kstrtoul(buf, 10, &new_startup_profile);572 if (retval)573 return retval;574 575 if (new_startup_profile < 1 || new_startup_profile > 5)576 return -EINVAL;577 578 mutex_lock(&kone->kone_lock);579 580 kone->settings.startup_profile = new_startup_profile;581 kone_set_settings_checksum(&kone->settings);582 583 retval = kone_set_settings(usb_dev, &kone->settings);584 if (retval) {585 mutex_unlock(&kone->kone_lock);586 return retval;587 }588 589 /* changing the startup profile immediately activates this profile */590 kone_profile_activated(kone, new_startup_profile);591 kone_profile_report(kone, new_startup_profile);592 593 mutex_unlock(&kone->kone_lock);594 return size;595}596static DEVICE_ATTR(startup_profile, 0660, kone_sysfs_show_startup_profile,597 kone_sysfs_set_startup_profile);598 599static struct attribute *kone_attrs[] = {600 /*601 * Read actual dpi settings.602 * Returns raw value for further processing. Refer to enum603 * kone_polling_rates to get real value.604 */605 &dev_attr_actual_dpi.attr,606 &dev_attr_actual_profile.attr,607 608 /*609 * The mouse can be equipped with one of four supplied weights from 5610 * to 20 grams which are recognized and its value can be read out.611 * This returns the raw value reported by the mouse for easy evaluation612 * by software. Refer to enum kone_weights to get corresponding real613 * weight.614 */615 &dev_attr_weight.attr,616 617 /*618 * Prints firmware version stored in mouse as integer.619 * The raw value reported by the mouse is returned for easy evaluation,620 * to get the real version number the decimal point has to be shifted 2621 * positions to the left. E.g. a value of 138 means 1.38.622 */623 &dev_attr_firmware_version.attr,624 625 /*626 * Prints state of Tracking Control Unit as number where 0 = off and627 * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and628 * activates the tcu629 */630 &dev_attr_tcu.attr,631 632 /* Prints and takes the number of the profile the mouse starts with */633 &dev_attr_startup_profile.attr,634 NULL,635};636 637static struct bin_attribute *kone_bin_attributes[] = {638 &bin_attr_settings,639 &bin_attr_profile1,640 &bin_attr_profile2,641 &bin_attr_profile3,642 &bin_attr_profile4,643 &bin_attr_profile5,644 NULL,645};646 647static const struct attribute_group kone_group = {648 .attrs = kone_attrs,649 .bin_attrs = kone_bin_attributes,650};651 652static const struct attribute_group *kone_groups[] = {653 &kone_group,654 NULL,655};656 657/* kone_class is used for creating sysfs attributes via roccat char device */658static const struct class kone_class = {659 .name = "kone",660 .dev_groups = kone_groups,661};662 663static int kone_init_kone_device_struct(struct usb_device *usb_dev,664 struct kone_device *kone)665{666 uint i;667 int retval;668 669 mutex_init(&kone->kone_lock);670 671 for (i = 0; i < 5; ++i) {672 retval = kone_get_profile(usb_dev, &kone->profiles[i], i + 1);673 if (retval)674 return retval;675 }676 677 retval = kone_get_settings(usb_dev, &kone->settings);678 if (retval)679 return retval;680 681 retval = kone_get_firmware_version(usb_dev, &kone->firmware_version);682 if (retval)683 return retval;684 685 kone_profile_activated(kone, kone->settings.startup_profile);686 687 return 0;688}689 690/*691 * Since IGNORE_MOUSE quirk moved to hid-apple, there is no way to bind only to692 * mousepart if usb_hid is compiled into the kernel and kone is compiled as693 * module.694 * Secial behaviour is bound only to mousepart since only mouseevents contain695 * additional notifications.696 */697static int kone_init_specials(struct hid_device *hdev)698{699 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);700 struct usb_device *usb_dev = interface_to_usbdev(intf);701 struct kone_device *kone;702 int retval;703 704 if (intf->cur_altsetting->desc.bInterfaceProtocol705 == USB_INTERFACE_PROTOCOL_MOUSE) {706 707 kone = kzalloc(sizeof(*kone), GFP_KERNEL);708 if (!kone)709 return -ENOMEM;710 hid_set_drvdata(hdev, kone);711 712 retval = kone_init_kone_device_struct(usb_dev, kone);713 if (retval) {714 hid_err(hdev, "couldn't init struct kone_device\n");715 goto exit_free;716 }717 718 retval = roccat_connect(&kone_class, hdev,719 sizeof(struct kone_roccat_report));720 if (retval < 0) {721 hid_err(hdev, "couldn't init char dev\n");722 /* be tolerant about not getting chrdev */723 } else {724 kone->roccat_claimed = 1;725 kone->chrdev_minor = retval;726 }727 } else {728 hid_set_drvdata(hdev, NULL);729 }730 731 return 0;732exit_free:733 kfree(kone);734 return retval;735}736 737static void kone_remove_specials(struct hid_device *hdev)738{739 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);740 struct kone_device *kone;741 742 if (intf->cur_altsetting->desc.bInterfaceProtocol743 == USB_INTERFACE_PROTOCOL_MOUSE) {744 kone = hid_get_drvdata(hdev);745 if (kone->roccat_claimed)746 roccat_disconnect(kone->chrdev_minor);747 kfree(hid_get_drvdata(hdev));748 }749}750 751static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id)752{753 int retval;754 755 if (!hid_is_usb(hdev))756 return -EINVAL;757 758 retval = hid_parse(hdev);759 if (retval) {760 hid_err(hdev, "parse failed\n");761 goto exit;762 }763 764 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);765 if (retval) {766 hid_err(hdev, "hw start failed\n");767 goto exit;768 }769 770 retval = kone_init_specials(hdev);771 if (retval) {772 hid_err(hdev, "couldn't install mouse\n");773 goto exit_stop;774 }775 776 return 0;777 778exit_stop:779 hid_hw_stop(hdev);780exit:781 return retval;782}783 784static void kone_remove(struct hid_device *hdev)785{786 kone_remove_specials(hdev);787 hid_hw_stop(hdev);788}789 790/* handle special events and keep actual profile and dpi values up to date */791static void kone_keep_values_up_to_date(struct kone_device *kone,792 struct kone_mouse_event const *event)793{794 switch (event->event) {795 case kone_mouse_event_switch_profile:796 kone->actual_dpi = kone->profiles[event->value - 1].797 startup_dpi;798 fallthrough;799 case kone_mouse_event_osd_profile:800 kone->actual_profile = event->value;801 break;802 case kone_mouse_event_switch_dpi:803 case kone_mouse_event_osd_dpi:804 kone->actual_dpi = event->value;805 break;806 }807}808 809static void kone_report_to_chrdev(struct kone_device const *kone,810 struct kone_mouse_event const *event)811{812 struct kone_roccat_report roccat_report;813 814 switch (event->event) {815 case kone_mouse_event_switch_profile:816 case kone_mouse_event_switch_dpi:817 case kone_mouse_event_osd_profile:818 case kone_mouse_event_osd_dpi:819 roccat_report.event = event->event;820 roccat_report.value = event->value;821 roccat_report.key = 0;822 roccat_report_event(kone->chrdev_minor,823 (uint8_t *)&roccat_report);824 break;825 case kone_mouse_event_call_overlong_macro:826 case kone_mouse_event_multimedia:827 if (event->value == kone_keystroke_action_press) {828 roccat_report.event = event->event;829 roccat_report.value = kone->actual_profile;830 roccat_report.key = event->macro_key;831 roccat_report_event(kone->chrdev_minor,832 (uint8_t *)&roccat_report);833 }834 break;835 }836 837}838 839/*840 * Is called for keyboard- and mousepart.841 * Only mousepart gets informations about special events in its extended event842 * structure.843 */844static int kone_raw_event(struct hid_device *hdev, struct hid_report *report,845 u8 *data, int size)846{847 struct kone_device *kone = hid_get_drvdata(hdev);848 struct kone_mouse_event *event = (struct kone_mouse_event *)data;849 850 /* keyboard events are always processed by default handler */851 if (size != sizeof(struct kone_mouse_event))852 return 0;853 854 if (kone == NULL)855 return 0;856 857 /*858 * Firmware 1.38 introduced new behaviour for tilt and special buttons.859 * Pressed button is reported in each movement event.860 * Workaround sends only one event per press.861 */862 if (memcmp(&kone->last_mouse_event.tilt, &event->tilt, 5))863 memcpy(&kone->last_mouse_event, event,864 sizeof(struct kone_mouse_event));865 else866 memset(&event->wipe, 0, sizeof(event->wipe));867 868 kone_keep_values_up_to_date(kone, event);869 870 if (kone->roccat_claimed)871 kone_report_to_chrdev(kone, event);872 873 return 0; /* always do further processing */874}875 876static const struct hid_device_id kone_devices[] = {877 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },878 { }879};880 881MODULE_DEVICE_TABLE(hid, kone_devices);882 883static struct hid_driver kone_driver = {884 .name = "kone",885 .id_table = kone_devices,886 .probe = kone_probe,887 .remove = kone_remove,888 .raw_event = kone_raw_event889};890 891static int __init kone_init(void)892{893 int retval;894 895 /* class name has to be same as driver name */896 retval = class_register(&kone_class);897 if (retval)898 return retval;899 900 retval = hid_register_driver(&kone_driver);901 if (retval)902 class_unregister(&kone_class);903 return retval;904}905 906static void __exit kone_exit(void)907{908 hid_unregister_driver(&kone_driver);909 class_unregister(&kone_class);910}911 912module_init(kone_init);913module_exit(kone_exit);914 915MODULE_AUTHOR("Stefan Achatz");916MODULE_DESCRIPTION("USB Roccat Kone driver");917MODULE_LICENSE("GPL v2");918