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