114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Roccat Kone driver for Linux
314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz *
414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * This program is free software; you can redistribute it and/or modify it
914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * under the terms of the GNU General Public License as published by the Free
1014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Software Foundation; either version 2 of the License, or (at your option)
1114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * any later version.
1214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
1314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
1414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
1514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Roccat Kone is a gamer mouse which consists of a mouse part and a keyboard
1614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * part. The keyboard part enables the mouse to execute stored macros with mixed
1714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * key- and button-events.
1814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz *
1914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * TODO implement on-the-fly polling-rate change
2014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz *      The windows driver has the ability to change the polling rate of the
2114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz *      device on the press of a mousebutton.
2214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz *      Is it possible to remove and reinstall the urb in raw-event- or any
2314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz *      other handler, or to defer this action to be executed somewhere else?
2414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz *
2514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * TODO is it possible to overwrite group for sysfs attributes via udev?
2614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
2714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
2814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include <linux/device.h>
2914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include <linux/input.h>
3014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include <linux/hid.h>
3114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include <linux/module.h>
32ed28f04b2753ce1b07b9c3dab7d186c43ce19e8cTejun Heo#include <linux/slab.h>
335dc0c9835fb96c75c8dbf657393764bd0abbac04Stefan Achatz#include <linux/hid-roccat.h>
3414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include "hid-ids.h"
355772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz#include "hid-roccat-common.h"
3614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include "hid-roccat-kone.h"
3714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
3814a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatzstatic uint profile_numbers[5] = {0, 1, 2, 3, 4};
3914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz
40bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatzstatic void kone_profile_activated(struct kone_device *kone, uint new_profile)
41bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz{
42bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	kone->actual_profile = new_profile;
43bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	kone->actual_dpi = kone->profiles[new_profile - 1].startup_dpi;
44bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz}
45bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz
463200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatzstatic void kone_profile_report(struct kone_device *kone, uint new_profile)
473200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz{
483200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz	struct kone_roccat_report roccat_report;
493200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz	roccat_report.event = kone_mouse_event_switch_profile;
503200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz	roccat_report.value = new_profile;
513200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz	roccat_report.key = 0;
523200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz	roccat_report_event(kone->chrdev_minor, (uint8_t *)&roccat_report);
533200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz}
543200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz
551edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatzstatic int kone_receive(struct usb_device *usb_dev, uint usb_command,
561edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz		void *data, uint size)
571edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz{
581edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	char *buf;
591edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	int len;
601edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz
611edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	buf = kmalloc(size, GFP_KERNEL);
621edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	if (buf == NULL)
631edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz		return -ENOMEM;
641edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz
651edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
661edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz			HID_REQ_GET_REPORT,
671edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
681edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz			usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
691edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz
701edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	memcpy(data, buf, size);
711edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	kfree(buf);
721edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	return ((len < 0) ? len : ((len != size) ? -EIO : 0));
731edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz}
741edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz
751edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatzstatic int kone_send(struct usb_device *usb_dev, uint usb_command,
761edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz		void const *data, uint size)
771edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz{
781edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	char *buf;
791edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	int len;
801edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz
814c33a885a5c8a9ad573249fa4ee4fb39af866599Thomas Meyer	buf = kmemdup(data, size, GFP_KERNEL);
821edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	if (buf == NULL)
831edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz		return -ENOMEM;
841edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz
851edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
861edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz			HID_REQ_SET_REPORT,
871edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
881edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz			usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
891edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz
901edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	kfree(buf);
911edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	return ((len < 0) ? len : ((len != size) ? -EIO : 0));
921edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz}
931edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz
945012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz/* kone_class is used for creating sysfs attributes via roccat char device */
955012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatzstatic struct class *kone_class;
965012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz
9714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic void kone_set_settings_checksum(struct kone_settings *settings)
9814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
9914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	uint16_t checksum = 0;
10014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	unsigned char *address = (unsigned char *)settings;
10114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int i;
10214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
10314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	for (i = 0; i < sizeof(struct kone_settings) - 2; ++i, ++address)
10414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		checksum += *address;
10514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	settings->checksum = cpu_to_le16(checksum);
10614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
10714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
10814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
10914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Checks success after writing data to mouse
11014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0
11114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno
11214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
11314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_check_write(struct usb_device *usb_dev)
11414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
1155772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	int retval;
1165772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	uint8_t data;
11714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
11814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	do {
11914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		/*
12014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * Mouse needs 50 msecs until it says ok, but there are
12114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * 30 more msecs needed for next write to work.
12214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 */
12314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		msleep(80);
12414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
1251edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz		retval = kone_receive(usb_dev,
1265772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz				kone_command_confirm_write, &data, 1);
1275772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz		if (retval)
1285772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz			return retval;
12914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
13014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		/*
13114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * value of 3 seems to mean something like
13214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * "not finished yet, but it looks good"
13314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * So check again after a moment.
13414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 */
1355772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	} while (data == 3);
13614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
1375772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	if (data == 1) /* everything alright */
13814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return 0;
1395772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz
1405772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	/* unknown answer */
1415772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	hid_err(usb_dev, "got retval %d when checking write\n", data);
1425772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	return -EIO;
14314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
14414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
14514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
14614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reads settings from mouse and stores it in @buf
14714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0
14814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno
14914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
15014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_get_settings(struct usb_device *usb_dev,
15114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct kone_settings *buf)
15214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
1531edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	return kone_receive(usb_dev, kone_command_settings, buf,
1545772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz			sizeof(struct kone_settings));
15514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
15614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
15714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
15814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Writes settings from @buf to mouse
15914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0
16014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno
16114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
16214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_set_settings(struct usb_device *usb_dev,
16314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct kone_settings const *settings)
16414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
1655772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	int retval;
1661edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	retval = kone_send(usb_dev, kone_command_settings,
1675772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz			settings, sizeof(struct kone_settings));
1685772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	if (retval)
1695772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz		return retval;
1705772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	return kone_check_write(usb_dev);
17114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
17214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
17314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
17414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reads profile data from mouse and stores it in @buf
17514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * @number: profile number to read
17614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0
17714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno
17814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
17914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_get_profile(struct usb_device *usb_dev,
18014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct kone_profile *buf, int number)
18114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
18214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int len;
18314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
18414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (number < 1 || number > 5)
18514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return -EINVAL;
18614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
18714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
18814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			USB_REQ_CLEAR_FEATURE,
18914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
19014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			kone_command_profile, number, buf,
19114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			sizeof(struct kone_profile), USB_CTRL_SET_TIMEOUT);
19214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
19314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (len != sizeof(struct kone_profile))
19414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return -EIO;
19514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
19614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return 0;
19714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
19814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
19914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
20014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Writes profile data to mouse.
20114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * @number: profile number to write
20214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0
20314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno
20414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
20514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_set_profile(struct usb_device *usb_dev,
20614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct kone_profile const *profile, int number)
20714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
20814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int len;
20914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
21014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (number < 1 || number > 5)
21114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return -EINVAL;
21214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
21314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
21414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			USB_REQ_SET_CONFIGURATION,
21514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
2165772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz			kone_command_profile, number, (void *)profile,
21714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			sizeof(struct kone_profile),
21814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			USB_CTRL_SET_TIMEOUT);
21914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
22014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (len != sizeof(struct kone_profile))
22114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return len;
22214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
22314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (kone_check_write(usb_dev))
22414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return -EIO;
22514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
22614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return 0;
22714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
22814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
22914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
23014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reads value of "fast-clip-weight" and stores it in @result
23114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0
23214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno
23314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
23414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_get_weight(struct usb_device *usb_dev, int *result)
23514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
2365772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	int retval;
2375772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	uint8_t data;
23814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
2391edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	retval = kone_receive(usb_dev, kone_command_weight, &data, 1);
24014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
2415772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	if (retval)
2425772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz		return retval;
24314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
2445772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	*result = (int)data;
24514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return 0;
24614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
24714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
24814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
24914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reads firmware_version of mouse and stores it in @result
25014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0
25114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno
25214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
25314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
25414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
2555772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	int retval;
2565772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	uint16_t data;
25714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
2581edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	retval = kone_receive(usb_dev, kone_command_firmware_version,
2595772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz			&data, 2);
2605772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	if (retval)
2615772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz		return retval;
26214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
2635772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	*result = le16_to_cpu(data);
26414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return 0;
26514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
26614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
2675f2776293f7a4390f587642b1b7e1e6288e11a01Stephen Rothwellstatic ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
26814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct bin_attribute *attr, char *buf,
26914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		loff_t off, size_t count) {
2705012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct device *dev =
2715012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			container_of(kobj, struct device, kobj)->parent->parent;
27214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
27314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
27414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (off >= sizeof(struct kone_settings))
27514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return 0;
27614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
27714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (off + count > sizeof(struct kone_settings))
27814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		count = sizeof(struct kone_settings) - off;
27914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
28014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_lock(&kone->kone_lock);
281cab6b16aca4ac12f731a523fe14770add2f9394aStefan Achatz	memcpy(buf, ((char const *)&kone->settings) + off, count);
28214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_unlock(&kone->kone_lock);
28314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
28414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return count;
28514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
28614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
28714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
28814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Writing settings automatically activates startup_profile.
28914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * This function keeps values in kone_device up to date and assumes that in
29014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * case of error the old data is still valid
29114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
2925f2776293f7a4390f587642b1b7e1e6288e11a01Stephen Rothwellstatic ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
29314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct bin_attribute *attr, char *buf,
29414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		loff_t off, size_t count) {
2955012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct device *dev =
2965012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			container_of(kobj, struct device, kobj)->parent->parent;
29714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
29814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
2993200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz	int retval = 0, difference, old_profile;
30014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
30114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	/* I need to get my data in one piece */
30214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (off != 0 || count != sizeof(struct kone_settings))
30314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return -EINVAL;
30414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
30514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_lock(&kone->kone_lock);
30614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	difference = memcmp(buf, &kone->settings, sizeof(struct kone_settings));
30714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (difference) {
30814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_set_settings(usb_dev,
30914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz				(struct kone_settings const *)buf);
310bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz		if (retval) {
311bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz			mutex_unlock(&kone->kone_lock);
312bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz			return retval;
313bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz		}
31414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
3153200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz		old_profile = kone->settings.startup_profile;
316bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz		memcpy(&kone->settings, buf, sizeof(struct kone_settings));
31714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
318bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz		kone_profile_activated(kone, kone->settings.startup_profile);
3193200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz
3203200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz		if (kone->settings.startup_profile != old_profile)
3213200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz			kone_profile_report(kone, kone->settings.startup_profile);
322bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	}
323bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	mutex_unlock(&kone->kone_lock);
32414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
32514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return sizeof(struct kone_settings);
32614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
32714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
32814a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatzstatic ssize_t kone_sysfs_read_profilex(struct file *fp,
32914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		struct kobject *kobj, struct bin_attribute *attr,
33014a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		char *buf, loff_t off, size_t count) {
3315012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct device *dev =
3325012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			container_of(kobj, struct device, kobj)->parent->parent;
33314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
33414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
33514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (off >= sizeof(struct kone_profile))
33614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return 0;
33714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
33814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (off + count > sizeof(struct kone_profile))
33914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		count = sizeof(struct kone_profile) - off;
34014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
34114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_lock(&kone->kone_lock);
34214a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz	memcpy(buf, ((char const *)&kone->profiles[*(uint *)(attr->private)]) + off, count);
34314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_unlock(&kone->kone_lock);
34414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
34514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return count;
34614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
34714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
34814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* Writes data only if different to stored data */
34914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatzstatic ssize_t kone_sysfs_write_profilex(struct file *fp,
35014a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		struct kobject *kobj, struct bin_attribute *attr,
35114a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		char *buf, loff_t off, size_t count) {
3525012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct device *dev =
3535012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			container_of(kobj, struct device, kobj)->parent->parent;
35414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
35514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
35614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct kone_profile *profile;
35714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int retval = 0, difference;
35814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
35914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	/* I need to get my data in one piece */
36014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (off != 0 || count != sizeof(struct kone_profile))
36114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return -EINVAL;
36214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
36314a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz	profile = &kone->profiles[*(uint *)(attr->private)];
36414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
36514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_lock(&kone->kone_lock);
36614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	difference = memcmp(buf, profile, sizeof(struct kone_profile));
36714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (difference) {
36814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_set_profile(usb_dev,
36914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz				(struct kone_profile const *)buf,
37014a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz				*(uint *)(attr->private) + 1);
37114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (!retval)
37214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			memcpy(profile, buf, sizeof(struct kone_profile));
37314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
37414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_unlock(&kone->kone_lock);
37514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
37614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval)
37714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return retval;
37814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
37914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return sizeof(struct kone_profile);
38014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
38114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
38214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_actual_profile(struct device *dev,
38314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct device_attribute *attr, char *buf)
38414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
3855012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct kone_device *kone =
3865012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
38714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile);
38814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
38914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
39014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
39114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct device_attribute *attr, char *buf)
39214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
3935012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct kone_device *kone =
3945012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
39514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi);
39614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
39714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
39814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* weight is read each time, since we don't get informed when it's changed */
39914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_weight(struct device *dev,
40014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct device_attribute *attr, char *buf)
40114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
4025012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct kone_device *kone;
4035012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct usb_device *usb_dev;
40414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int weight = 0;
40514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int retval;
40614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
4075012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	dev = dev->parent->parent;
4085012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	kone = hid_get_drvdata(dev_get_drvdata(dev));
4095012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	usb_dev = interface_to_usbdev(to_usb_interface(dev));
4105012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz
41114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_lock(&kone->kone_lock);
41214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = kone_get_weight(usb_dev, &weight);
41314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_unlock(&kone->kone_lock);
41414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
41514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval)
41614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return retval;
41714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return snprintf(buf, PAGE_SIZE, "%d\n", weight);
41814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
41914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
42014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_firmware_version(struct device *dev,
42114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct device_attribute *attr, char *buf)
42214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
4235012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct kone_device *kone =
4245012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
42514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version);
42614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
42714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
42814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_tcu(struct device *dev,
42914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct device_attribute *attr, char *buf)
43014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
4315012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct kone_device *kone =
4325012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
43314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu);
43414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
43514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
43614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_tcu_command(struct usb_device *usb_dev, int number)
43714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
4385772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	unsigned char value;
4395772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz	value = number;
4401edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz	return kone_send(usb_dev, kone_command_calibrate, &value, 1);
44114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
44214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
44314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
44414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Calibrating the tcu is the only action that changes settings data inside the
44514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * mouse, so this data needs to be reread
44614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
44714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_set_tcu(struct device *dev,
44814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct device_attribute *attr, char const *buf, size_t size)
44914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
4505012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct kone_device *kone;
4515012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct usb_device *usb_dev;
45214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int retval;
45314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	unsigned long state;
45414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
4555012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	dev = dev->parent->parent;
4565012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	kone = hid_get_drvdata(dev_get_drvdata(dev));
4575012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	usb_dev = interface_to_usbdev(to_usb_interface(dev));
4585012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz
45914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = strict_strtoul(buf, 10, &state);
46014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval)
46114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return retval;
46214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
46314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (state != 0 && state != 1)
46414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return -EINVAL;
46514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
46614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_lock(&kone->kone_lock);
46714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
46814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (state == 1) { /* state activate */
46914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_tcu_command(usb_dev, 1);
47014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (retval)
47114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			goto exit_unlock;
47214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_tcu_command(usb_dev, 2);
47314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (retval)
47414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			goto exit_unlock;
47514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		ssleep(5); /* tcu needs this time for calibration */
47614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_tcu_command(usb_dev, 3);
47714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (retval)
47814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			goto exit_unlock;
47914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_tcu_command(usb_dev, 0);
48014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (retval)
48114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			goto exit_unlock;
48214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_tcu_command(usb_dev, 4);
48314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (retval)
48414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			goto exit_unlock;
48514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		/*
48614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * Kone needs this time to settle things.
48714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * Reading settings too early will result in invalid data.
48814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * Roccat's driver waits 1 sec, maybe this time could be
48914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 * shortened.
49014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		 */
49114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		ssleep(1);
49214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
49314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
49414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	/* calibration changes values in settings, so reread */
49514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = kone_get_settings(usb_dev, &kone->settings);
49614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval)
49714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		goto exit_no_settings;
49814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
49914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	/* only write settings back if activation state is different */
50014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (kone->settings.tcu != state) {
50114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		kone->settings.tcu = state;
50214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		kone_set_settings_checksum(&kone->settings);
50314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
50414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_set_settings(usb_dev, &kone->settings);
50514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (retval) {
5064291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			hid_err(usb_dev, "couldn't set tcu state\n");
50714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			/*
50814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			 * try to reread valid settings into buffer overwriting
50914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			 * first error code
51014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			 */
51114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			retval = kone_get_settings(usb_dev, &kone->settings);
51214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			if (retval)
51314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz				goto exit_no_settings;
51414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			goto exit_unlock;
51514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		}
516bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz		/* calibration resets profile */
517bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz		kone_profile_activated(kone, kone->settings.startup_profile);
51814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
51914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
52014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = size;
52114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit_no_settings:
5224291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches	hid_err(usb_dev, "couldn't read settings\n");
52314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit_unlock:
52414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_unlock(&kone->kone_lock);
52514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return retval;
52614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
52714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
52814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_startup_profile(struct device *dev,
52914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct device_attribute *attr, char *buf)
53014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
5315012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct kone_device *kone =
5325012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
53314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile);
53414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
53514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
53614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_set_startup_profile(struct device *dev,
53714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct device_attribute *attr, char const *buf, size_t size)
53814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
5395012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct kone_device *kone;
5405012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	struct usb_device *usb_dev;
54114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int retval;
54214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	unsigned long new_startup_profile;
54314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
5445012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	dev = dev->parent->parent;
5455012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	kone = hid_get_drvdata(dev_get_drvdata(dev));
5465012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	usb_dev = interface_to_usbdev(to_usb_interface(dev));
5475012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz
54814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = strict_strtoul(buf, 10, &new_startup_profile);
54914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval)
55014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return retval;
55114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
55214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (new_startup_profile  < 1 || new_startup_profile > 5)
55314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return -EINVAL;
55414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
55514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_lock(&kone->kone_lock);
55614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
55714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	kone->settings.startup_profile = new_startup_profile;
55814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	kone_set_settings_checksum(&kone->settings);
55914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
56014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = kone_set_settings(usb_dev, &kone->settings);
561bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	if (retval) {
562bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz		mutex_unlock(&kone->kone_lock);
56314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return retval;
564bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	}
56514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
56614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	/* changing the startup profile immediately activates this profile */
567bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	kone_profile_activated(kone, new_startup_profile);
5683200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz	kone_profile_report(kone, new_startup_profile);
56914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
570bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	mutex_unlock(&kone->kone_lock);
57114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return size;
57214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
57314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
5745012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatzstatic struct device_attribute kone_attributes[] = {
5755012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	/*
5765012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * Read actual dpi settings.
5775012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * Returns raw value for further processing. Refer to enum
5785012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * kone_polling_rates to get real value.
5795012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 */
5805012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	__ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL),
5815012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	__ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL),
58214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
5835012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	/*
5845012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * The mouse can be equipped with one of four supplied weights from 5
5855012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * to 20 grams which are recognized and its value can be read out.
5865012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * This returns the raw value reported by the mouse for easy evaluation
5875012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * by software. Refer to enum kone_weights to get corresponding real
5885012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * weight.
5895012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 */
5905012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	__ATTR(weight, 0440, kone_sysfs_show_weight, NULL),
59114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
5925012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	/*
5935012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * Prints firmware version stored in mouse as integer.
5945012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * The raw value reported by the mouse is returned for easy evaluation,
5955012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * to get the real version number the decimal point has to be shifted 2
5965012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * positions to the left. E.g. a value of 138 means 1.38.
5975012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 */
5985012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	__ATTR(firmware_version, 0440,
5995012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			kone_sysfs_show_firmware_version, NULL),
60014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
6015012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	/*
6025012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * Prints state of Tracking Control Unit as number where 0 = off and
6035012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and
6045012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 * activates the tcu
6055012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	 */
6065012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	__ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu),
60714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
6085012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	/* Prints and takes the number of the profile the mouse starts with */
6095012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	__ATTR(startup_profile, 0660,
6105012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			kone_sysfs_show_startup_profile,
6115012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz			kone_sysfs_set_startup_profile),
6125012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	__ATTR_NULL
61314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz};
61414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
6155012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatzstatic struct bin_attribute kone_bin_attributes[] = {
6165012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	{
6175012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.attr = { .name = "settings", .mode = 0660 },
6185012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.size = sizeof(struct kone_settings),
6195012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.read = kone_sysfs_read_settings,
6205012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.write = kone_sysfs_write_settings
6215012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	},
6225012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	{
6235012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.attr = { .name = "profile1", .mode = 0660 },
6245012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.size = sizeof(struct kone_profile),
62514a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.read = kone_sysfs_read_profilex,
62614a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.write = kone_sysfs_write_profilex,
62714a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.private = &profile_numbers[0]
6285012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	},
6295012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	{
6305012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.attr = { .name = "profile2", .mode = 0660 },
6315012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.size = sizeof(struct kone_profile),
63214a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.read = kone_sysfs_read_profilex,
63314a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.write = kone_sysfs_write_profilex,
63414a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.private = &profile_numbers[1]
6355012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	},
6365012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	{
6375012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.attr = { .name = "profile3", .mode = 0660 },
6385012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.size = sizeof(struct kone_profile),
63914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.read = kone_sysfs_read_profilex,
64014a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.write = kone_sysfs_write_profilex,
64114a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.private = &profile_numbers[2]
6425012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	},
6435012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	{
6445012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.attr = { .name = "profile4", .mode = 0660 },
6455012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.size = sizeof(struct kone_profile),
64614a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.read = kone_sysfs_read_profilex,
64714a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.write = kone_sysfs_write_profilex,
64814a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.private = &profile_numbers[3]
6495012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	},
6505012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	{
6515012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.attr = { .name = "profile5", .mode = 0660 },
6525012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		.size = sizeof(struct kone_profile),
65314a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.read = kone_sysfs_read_profilex,
65414a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.write = kone_sysfs_write_profilex,
65514a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz		.private = &profile_numbers[4]
6565012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	},
6575012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	__ATTR_NULL
65814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz};
65914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
66014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_init_kone_device_struct(struct usb_device *usb_dev,
66114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		struct kone_device *kone)
66214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
66314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	uint i;
66414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int retval;
66514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
66614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	mutex_init(&kone->kone_lock);
66714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
66814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	for (i = 0; i < 5; ++i) {
66914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_get_profile(usb_dev, &kone->profiles[i], i + 1);
67014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (retval)
67114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			return retval;
67214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
67314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
67414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = kone_get_settings(usb_dev, &kone->settings);
67514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval)
67614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return retval;
67714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
67814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = kone_get_firmware_version(usb_dev, &kone->firmware_version);
67914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval)
68014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return retval;
68114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
682bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz	kone_profile_activated(kone, kone->settings.startup_profile);
68314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
68414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return 0;
68514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
68614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
68714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
68814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Since IGNORE_MOUSE quirk moved to hid-apple, there is no way to bind only to
68914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * mousepart if usb_hid is compiled into the kernel and kone is compiled as
69014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * module.
69114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Secial behaviour is bound only to mousepart since only mouseevents contain
69214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * additional notifications.
69314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
69414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_init_specials(struct hid_device *hdev)
69514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
69614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
69714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct usb_device *usb_dev = interface_to_usbdev(intf);
69814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct kone_device *kone;
69914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int retval;
70014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
70114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (intf->cur_altsetting->desc.bInterfaceProtocol
70214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			== USB_INTERFACE_PROTOCOL_MOUSE) {
70314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
70414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		kone = kzalloc(sizeof(*kone), GFP_KERNEL);
70514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (!kone) {
7064291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			hid_err(hdev, "can't alloc device descriptor\n");
70714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			return -ENOMEM;
70814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		}
70914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		hid_set_drvdata(hdev, kone);
71014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
71114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		retval = kone_init_kone_device_struct(usb_dev, kone);
71214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		if (retval) {
7134291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			hid_err(hdev, "couldn't init struct kone_device\n");
71414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			goto exit_free;
71514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		}
716206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz
7178211e46004518c977f70f2661da961d5ba617399Stefan Achatz		retval = roccat_connect(kone_class, hdev,
7188211e46004518c977f70f2661da961d5ba617399Stefan Achatz				sizeof(struct kone_roccat_report));
719206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		if (retval < 0) {
7204291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			hid_err(hdev, "couldn't init char dev\n");
721206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz			/* be tolerant about not getting chrdev */
722206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		} else {
723206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz			kone->roccat_claimed = 1;
724206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz			kone->chrdev_minor = retval;
725206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		}
72614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	} else {
72714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		hid_set_drvdata(hdev, NULL);
72814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
72914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
73014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return 0;
73114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit_free:
73214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	kfree(kone);
73314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return retval;
73414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
73514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
73614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic void kone_remove_specials(struct hid_device *hdev)
73714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
73814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
739206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	struct kone_device *kone;
74014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
74114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (intf->cur_altsetting->desc.bInterfaceProtocol
74214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz			== USB_INTERFACE_PROTOCOL_MOUSE) {
743206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		kone = hid_get_drvdata(hdev);
744206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		if (kone->roccat_claimed)
745206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz			roccat_disconnect(kone->chrdev_minor);
74614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		kfree(hid_get_drvdata(hdev));
74714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
74814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
74914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
75014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_probe(struct hid_device *hdev, const struct hid_device_id *id)
75114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
75214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	int retval;
75314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
75414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = hid_parse(hdev);
75514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval) {
7564291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "parse failed\n");
75714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		goto exit;
75814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
75914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
76014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
76114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval) {
7624291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "hw start failed\n");
76314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		goto exit;
76414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
76514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
76614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	retval = kone_init_specials(hdev);
76714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (retval) {
7684291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "couldn't install mouse\n");
76914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		goto exit_stop;
77014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	}
77114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
77214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return 0;
77314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
77414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit_stop:
77514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	hid_hw_stop(hdev);
77614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit:
77714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	return retval;
77814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
77914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
78014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic void kone_remove(struct hid_device *hdev)
78114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
78214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	kone_remove_specials(hdev);
78314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	hid_hw_stop(hdev);
78414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
78514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
78648e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz/* handle special events and keep actual profile and dpi values up to date */
78748e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatzstatic void kone_keep_values_up_to_date(struct kone_device *kone,
78848e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz		struct kone_mouse_event const *event)
78948e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz{
79048e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz	switch (event->event) {
79148e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz	case kone_mouse_event_switch_profile:
7921c5784da12e34e98eb0a1b8f4323419dd84ea0b0Stefan Achatz		kone->actual_dpi = kone->profiles[event->value - 1].
7931c5784da12e34e98eb0a1b8f4323419dd84ea0b0Stefan Achatz				startup_dpi;
79448e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz	case kone_mouse_event_osd_profile:
79548e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz		kone->actual_profile = event->value;
79648e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz		break;
79748e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz	case kone_mouse_event_switch_dpi:
79848e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz	case kone_mouse_event_osd_dpi:
79948e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz		kone->actual_dpi = event->value;
80048e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz		break;
80148e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz	}
80248e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz}
80348e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz
804206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatzstatic void kone_report_to_chrdev(struct kone_device const *kone,
805206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		struct kone_mouse_event const *event)
806206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz{
807206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	struct kone_roccat_report roccat_report;
808206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz
809206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	switch (event->event) {
810206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	case kone_mouse_event_switch_profile:
811206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	case kone_mouse_event_switch_dpi:
812206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	case kone_mouse_event_osd_profile:
813206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	case kone_mouse_event_osd_dpi:
814206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		roccat_report.event = event->event;
815206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		roccat_report.value = event->value;
816206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		roccat_report.key = 0;
817206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		roccat_report_event(kone->chrdev_minor,
8188211e46004518c977f70f2661da961d5ba617399Stefan Achatz				(uint8_t *)&roccat_report);
819206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		break;
820206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	case kone_mouse_event_call_overlong_macro:
821206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		if (event->value == kone_keystroke_action_press) {
822206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz			roccat_report.event = kone_mouse_event_call_overlong_macro;
823206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz			roccat_report.value = kone->actual_profile;
824206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz			roccat_report.key = event->macro_key;
825206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz			roccat_report_event(kone->chrdev_minor,
8268211e46004518c977f70f2661da961d5ba617399Stefan Achatz					(uint8_t *)&roccat_report);
827206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		}
828206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		break;
829206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	}
830206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz
831206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz}
832206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz
83314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/*
83414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Is called for keyboard- and mousepart.
83514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Only mousepart gets informations about special events in its extended event
83614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * structure.
83714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */
83814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_raw_event(struct hid_device *hdev, struct hid_report *report,
83914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		u8 *data, int size)
84014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
84114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct kone_device *kone = hid_get_drvdata(hdev);
84214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	struct kone_mouse_event *event = (struct kone_mouse_event *)data;
84314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
84414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	/* keyboard events are always processed by default handler */
84514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	if (size != sizeof(struct kone_mouse_event))
84614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		return 0;
84714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
848901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz	if (kone == NULL)
849901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz		return 0;
850901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz
85114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	/*
85273b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz	 * Firmware 1.38 introduced new behaviour for tilt and special buttons.
85373b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz	 * Pressed button is reported in each movement event.
85414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	 * Workaround sends only one event per press.
85514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	 */
85673b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz	if (memcmp(&kone->last_mouse_event.tilt, &event->tilt, 5))
85773b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz		memcpy(&kone->last_mouse_event, event,
85873b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz				sizeof(struct kone_mouse_event));
85914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	else
86073b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz		memset(&event->tilt, 0, 5);
86114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
86248e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz	kone_keep_values_up_to_date(kone, event);
86314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
864206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz	if (kone->roccat_claimed)
865206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz		kone_report_to_chrdev(kone, event);
866206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz
86748e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz	return 0; /* always do further processing */
86814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
86914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
87014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic const struct hid_device_id kone_devices[] = {
87114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
87214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	{ }
87314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz};
87414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
87514bf62cde79423a02a590e02664ed29a36facec1Stefan AchatzMODULE_DEVICE_TABLE(hid, kone_devices);
87614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
87714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic struct hid_driver kone_driver = {
87814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		.name = "kone",
87914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		.id_table = kone_devices,
88014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		.probe = kone_probe,
88114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		.remove = kone_remove,
88214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz		.raw_event = kone_raw_event
88314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz};
88414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
88500237bc5204c43f67b2e68546012d7bd27efc1b6Stefan Achatzstatic int __init kone_init(void)
88614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
8875012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	int retval;
8885012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz
8895012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	/* class name has to be same as driver name */
8905012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	kone_class = class_create(THIS_MODULE, "kone");
8915012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	if (IS_ERR(kone_class))
8925012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		return PTR_ERR(kone_class);
8935012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	kone_class->dev_attrs = kone_attributes;
8945012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	kone_class->dev_bin_attrs = kone_bin_attributes;
8955012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz
8965012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	retval = hid_register_driver(&kone_driver);
8975012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	if (retval)
8985012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz		class_destroy(kone_class);
8995012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz	return retval;
90014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
90114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
90200237bc5204c43f67b2e68546012d7bd27efc1b6Stefan Achatzstatic void __exit kone_exit(void)
90314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{
90414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz	hid_unregister_driver(&kone_driver);
90574b643dac475e29f53f4132d2349ec1dba3c9e44Stefan Achatz	class_destroy(kone_class);
90614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}
90714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
90814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzmodule_init(kone_init);
90914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzmodule_exit(kone_exit);
91014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz
9111f749d8d5f92c275e35cdcd1fdcb7c8298157118Stefan AchatzMODULE_AUTHOR("Stefan Achatz");
9121f749d8d5f92c275e35cdcd1fdcb7c8298157118Stefan AchatzMODULE_DESCRIPTION("USB Roccat Kone driver");
9131f749d8d5f92c275e35cdcd1fdcb7c8298157118Stefan AchatzMODULE_LICENSE("GPL v2");
914