brintos

brintos / linux-shallow public Read only

0
0
Text · 23.5 KiB · 3f8f459 Raw
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