diff options
| -rw-r--r-- | Documentation/ABI/testing/sysfs-driver-hid-roccat-kone | 111 | ||||
| -rw-r--r-- | drivers/hid/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/hid/Makefile | 1 | ||||
| -rw-r--r-- | drivers/hid/hid-core.c | 1 | ||||
| -rw-r--r-- | drivers/hid/hid-ids.h | 3 | ||||
| -rw-r--r-- | drivers/hid/hid-roccat-kone.c | 1006 | ||||
| -rw-r--r-- | drivers/hid/hid-roccat-kone.h | 214 |
7 files changed, 1343 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone new file mode 100644 index 000000000000..88340a23ce91 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_dpi | ||
| 2 | Date: March 2010 | ||
| 3 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 4 | Description: It is possible to switch the dpi setting of the mouse with the | ||
| 5 | press of a button. | ||
| 6 | When read, this file returns the raw number of the actual dpi | ||
| 7 | setting reported by the mouse. This number has to be further | ||
| 8 | processed to receive the real dpi value. | ||
| 9 | |||
| 10 | VALUE DPI | ||
| 11 | 1 800 | ||
| 12 | 2 1200 | ||
| 13 | 3 1600 | ||
| 14 | 4 2000 | ||
| 15 | 5 2400 | ||
| 16 | 6 3200 | ||
| 17 | |||
| 18 | This file is readonly. | ||
| 19 | |||
| 20 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile | ||
| 21 | Date: March 2010 | ||
| 22 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 23 | Description: When read, this file returns the number of the actual profile. | ||
| 24 | This file is readonly. | ||
| 25 | |||
| 26 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version | ||
| 27 | Date: March 2010 | ||
| 28 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 29 | Description: When read, this file returns the raw integer version number of the | ||
| 30 | firmware reported by the mouse. Using the integer value eases | ||
| 31 | further usage in other programs. To receive the real version | ||
| 32 | number the decimal point has to be shifted 2 positions to the | ||
| 33 | left. E.g. a returned value of 138 means 1.38 | ||
| 34 | This file is readonly. | ||
| 35 | |||
| 36 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version | ||
| 37 | Date: March 2010 | ||
| 38 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 39 | Description: When read, this file returns the driver version. | ||
| 40 | The format of the string is "v<major>.<minor>.<patchlevel>". | ||
| 41 | This attribute is used by the userland tools to find the sysfs- | ||
| 42 | paths of installed kone-mice and determine the capabilites of | ||
| 43 | the driver. Versions of this driver for old kernels replace | ||
| 44 | usbhid instead of generic-usb. The way to scan for this file | ||
| 45 | has been chosen to provide a consistent way for all supported | ||
| 46 | kernel versions. | ||
| 47 | This file is readonly. | ||
| 48 | |||
| 49 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5] | ||
| 50 | Date: March 2010 | ||
| 51 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 52 | Description: The mouse can store 5 profiles which can be switched by the | ||
| 53 | press of a button. A profile holds informations like button | ||
| 54 | mappings, sensitivity, the colors of the 5 leds and light | ||
| 55 | effects. | ||
| 56 | When read, these files return the respective profile. The | ||
| 57 | returned data is 975 bytes in size. | ||
| 58 | When written, this file lets one write the respective profile | ||
| 59 | data back to the mouse. The data has to be 975 bytes long. | ||
| 60 | The mouse will reject invalid data, whereas the profile number | ||
| 61 | stored in the profile doesn't need to fit the number of the | ||
| 62 | store. | ||
| 63 | |||
| 64 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/settings | ||
| 65 | Date: March 2010 | ||
| 66 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 67 | Description: When read, this file returns the settings stored in the mouse. | ||
| 68 | The size of the data is 36 bytes and holds information like the | ||
| 69 | startup_profile, tcu state and calibration_data. | ||
| 70 | When written, this file lets write settings back to the mouse. | ||
| 71 | The data has to be 36 bytes long. The mouse will reject invalid | ||
| 72 | data. | ||
| 73 | |||
| 74 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile | ||
| 75 | Date: March 2010 | ||
| 76 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 77 | Description: The integer value of this attribute ranges from 1 to 5. | ||
| 78 | When read, this attribute returns the number of the profile | ||
| 79 | that's active when the mouse is powered on. | ||
| 80 | When written, this file sets the number of the startup profile | ||
| 81 | and the mouse activates this profile immediately. | ||
| 82 | |||
| 83 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/tcu | ||
| 84 | Date: March 2010 | ||
| 85 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 86 | Description: The mouse has a "Tracking Control Unit" which lets the user | ||
| 87 | calibrate the laser power to fit the mousepad surface. | ||
| 88 | When read, this file returns the current state of the TCU, | ||
| 89 | where 0 means off and 1 means on. | ||
| 90 | Writing 0 in this file will switch the TCU off. | ||
| 91 | Writing 1 in this file will start the calibration which takes | ||
| 92 | around 6 seconds to complete and activates the TCU. | ||
| 93 | |||
| 94 | What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/weight | ||
| 95 | Date: March 2010 | ||
| 96 | Contact: Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 97 | Description: The mouse can be equipped with one of four supplied weights | ||
| 98 | ranging from 5 to 20 grams which are recognized by the mouse | ||
| 99 | and its value can be read out. When read, this file returns the | ||
| 100 | raw value returned by the mouse which eases further processing | ||
| 101 | in other software. | ||
| 102 | The values map to the weights as follows: | ||
| 103 | |||
| 104 | VALUE WEIGHT | ||
| 105 | 0 none | ||
| 106 | 1 5g | ||
| 107 | 2 10g | ||
| 108 | 3 15g | ||
| 109 | 4 20g | ||
| 110 | |||
| 111 | This file is readonly. | ||
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 71d4c0703629..d819b0271b41 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
| @@ -268,6 +268,13 @@ config HID_QUANTA | |||
| 268 | ---help--- | 268 | ---help--- |
| 269 | Support for Quanta Optical Touch dual-touch panels. | 269 | Support for Quanta Optical Touch dual-touch panels. |
| 270 | 270 | ||
| 271 | config HID_ROCCAT_KONE | ||
| 272 | tristate "Roccat Kone" if EMBEDDED | ||
| 273 | depends on USB_HID | ||
| 274 | default !EMBEDDED | ||
| 275 | ---help--- | ||
| 276 | Support for Roccat Kone mouse. | ||
| 277 | |||
| 271 | config HID_SAMSUNG | 278 | config HID_SAMSUNG |
| 272 | tristate "Samsung" if EMBEDDED | 279 | tristate "Samsung" if EMBEDDED |
| 273 | depends on USB_HID | 280 | depends on USB_HID |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0b2618f092ca..08b83ccd9d1b 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
| @@ -44,6 +44,7 @@ obj-$(CONFIG_HID_ORTEK) += hid-ortek.o | |||
| 44 | obj-$(CONFIG_HID_QUANTA) += hid-quanta.o | 44 | obj-$(CONFIG_HID_QUANTA) += hid-quanta.o |
| 45 | obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o | 45 | obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o |
| 46 | obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o | 46 | obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o |
| 47 | obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o | ||
| 47 | obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o | 48 | obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o |
| 48 | obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o | 49 | obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o |
| 49 | obj-$(CONFIG_HID_SONY) += hid-sony.o | 50 | obj-$(CONFIG_HID_SONY) += hid-sony.o |
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2e2aa759d230..5c5a821cd4cb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
| @@ -1346,6 +1346,7 @@ static const struct hid_device_id hid_blacklist[] = { | |||
| 1346 | { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, | 1346 | { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, |
| 1347 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, | 1347 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, |
| 1348 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, | 1348 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, |
| 1349 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, | ||
| 1349 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, | 1350 | { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, |
| 1350 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, | 1351 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, |
| 1351 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, | 1352 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, |
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 797e06470356..014acfcde562 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
| @@ -399,6 +399,9 @@ | |||
| 399 | #define USB_VENDOR_ID_PRODIGE 0x05af | 399 | #define USB_VENDOR_ID_PRODIGE 0x05af |
| 400 | #define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 | 400 | #define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 |
| 401 | 401 | ||
| 402 | #define USB_VENDOR_ID_ROCCAT 0x1e7d | ||
| 403 | #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced | ||
| 404 | |||
| 402 | #define USB_VENDOR_ID_SAITEK 0x06a3 | 405 | #define USB_VENDOR_ID_SAITEK 0x06a3 |
| 403 | #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 | 406 | #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 |
| 404 | 407 | ||
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c new file mode 100644 index 000000000000..2b1412e4ff6f --- /dev/null +++ b/drivers/hid/hid-roccat-kone.c | |||
| @@ -0,0 +1,1006 @@ | |||
| 1 | /* | ||
| 2 | * Roccat Kone driver for Linux | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License as published by the Free | ||
| 10 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 11 | * any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | /* | ||
| 15 | * Roccat Kone is a gamer mouse which consists of a mouse part and a keyboard | ||
| 16 | * part. The keyboard part enables the mouse to execute stored macros with mixed | ||
| 17 | * key- and button-events. | ||
| 18 | * | ||
| 19 | * TODO implement on-the-fly polling-rate change | ||
| 20 | * The windows driver has the ability to change the polling rate of the | ||
| 21 | * device on the press of a mousebutton. | ||
| 22 | * Is it possible to remove and reinstall the urb in raw-event- or any | ||
| 23 | * other handler, or to defer this action to be executed somewhere else? | ||
| 24 | * | ||
| 25 | * TODO implement notification mechanism for overlong macro execution | ||
| 26 | * If user wants to execute an overlong macro only the names of macroset | ||
| 27 | * and macro are given. Should userland tap hidraw or is there an | ||
| 28 | * additional streaming mechanism? | ||
| 29 | * | ||
| 30 | * TODO is it possible to overwrite group for sysfs attributes via udev? | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <linux/device.h> | ||
| 34 | #include <linux/input.h> | ||
| 35 | #include <linux/hid.h> | ||
| 36 | #include <linux/usb.h> | ||
| 37 | #include <linux/module.h> | ||
| 38 | #include "hid-ids.h" | ||
| 39 | #include "hid-roccat-kone.h" | ||
| 40 | |||
| 41 | static void kone_set_settings_checksum(struct kone_settings *settings) | ||
| 42 | { | ||
| 43 | uint16_t checksum = 0; | ||
| 44 | unsigned char *address = (unsigned char *)settings; | ||
| 45 | int i; | ||
| 46 | |||
| 47 | for (i = 0; i < sizeof(struct kone_settings) - 2; ++i, ++address) | ||
| 48 | checksum += *address; | ||
| 49 | settings->checksum = cpu_to_le16(checksum); | ||
| 50 | } | ||
| 51 | |||
| 52 | /* | ||
| 53 | * Checks success after writing data to mouse | ||
| 54 | * On success returns 0 | ||
| 55 | * On failure returns errno | ||
| 56 | */ | ||
| 57 | static int kone_check_write(struct usb_device *usb_dev) | ||
| 58 | { | ||
| 59 | int len; | ||
| 60 | unsigned char *data; | ||
| 61 | |||
| 62 | data = kmalloc(1, GFP_KERNEL); | ||
| 63 | if (!data) | ||
| 64 | return -ENOMEM; | ||
| 65 | |||
| 66 | do { | ||
| 67 | /* | ||
| 68 | * Mouse needs 50 msecs until it says ok, but there are | ||
| 69 | * 30 more msecs needed for next write to work. | ||
| 70 | */ | ||
| 71 | msleep(80); | ||
| 72 | |||
| 73 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
| 74 | USB_REQ_CLEAR_FEATURE, | ||
| 75 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | | ||
| 76 | USB_DIR_IN, | ||
| 77 | kone_command_confirm_write, 0, data, 1, | ||
| 78 | USB_CTRL_SET_TIMEOUT); | ||
| 79 | |||
| 80 | if (len != 1) { | ||
| 81 | kfree(data); | ||
| 82 | return -EIO; | ||
| 83 | } | ||
| 84 | |||
| 85 | /* | ||
| 86 | * value of 3 seems to mean something like | ||
| 87 | * "not finished yet, but it looks good" | ||
| 88 | * So check again after a moment. | ||
| 89 | */ | ||
| 90 | } while (*data == 3); | ||
| 91 | |||
| 92 | if (*data == 1) { /* everything alright */ | ||
| 93 | kfree(data); | ||
| 94 | return 0; | ||
| 95 | } else { /* unknown answer */ | ||
| 96 | dev_err(&usb_dev->dev, "got retval %d when checking write\n", | ||
| 97 | *data); | ||
| 98 | kfree(data); | ||
| 99 | return -EIO; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Reads settings from mouse and stores it in @buf | ||
| 105 | * @buf has to be alloced with GFP_KERNEL | ||
| 106 | * On success returns 0 | ||
| 107 | * On failure returns errno | ||
| 108 | */ | ||
| 109 | static int kone_get_settings(struct usb_device *usb_dev, | ||
| 110 | struct kone_settings *buf) | ||
| 111 | { | ||
| 112 | int len; | ||
| 113 | |||
| 114 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
| 115 | USB_REQ_CLEAR_FEATURE, | ||
| 116 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 117 | kone_command_settings, 0, buf, | ||
| 118 | sizeof(struct kone_settings), USB_CTRL_SET_TIMEOUT); | ||
| 119 | |||
| 120 | if (len != sizeof(struct kone_settings)) | ||
| 121 | return -EIO; | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Writes settings from @buf to mouse | ||
| 128 | * On success returns 0 | ||
| 129 | * On failure returns errno | ||
| 130 | */ | ||
| 131 | static int kone_set_settings(struct usb_device *usb_dev, | ||
| 132 | struct kone_settings const *settings) | ||
| 133 | { | ||
| 134 | int len; | ||
| 135 | |||
| 136 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
| 137 | USB_REQ_SET_CONFIGURATION, | ||
| 138 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
| 139 | kone_command_settings, 0, (char *)settings, | ||
| 140 | sizeof(struct kone_settings), | ||
| 141 | USB_CTRL_SET_TIMEOUT); | ||
| 142 | |||
| 143 | if (len != sizeof(struct kone_settings)) | ||
| 144 | return -EIO; | ||
| 145 | |||
| 146 | if (kone_check_write(usb_dev)) | ||
| 147 | return -EIO; | ||
| 148 | |||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* | ||
| 153 | * Reads profile data from mouse and stores it in @buf | ||
| 154 | * @number: profile number to read | ||
| 155 | * On success returns 0 | ||
| 156 | * On failure returns errno | ||
| 157 | */ | ||
| 158 | static int kone_get_profile(struct usb_device *usb_dev, | ||
| 159 | struct kone_profile *buf, int number) | ||
| 160 | { | ||
| 161 | int len; | ||
| 162 | |||
| 163 | if (number < 1 || number > 5) | ||
| 164 | return -EINVAL; | ||
| 165 | |||
| 166 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
| 167 | USB_REQ_CLEAR_FEATURE, | ||
| 168 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 169 | kone_command_profile, number, buf, | ||
| 170 | sizeof(struct kone_profile), USB_CTRL_SET_TIMEOUT); | ||
| 171 | |||
| 172 | if (len != sizeof(struct kone_profile)) | ||
| 173 | return -EIO; | ||
| 174 | |||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Writes profile data to mouse. | ||
| 180 | * @number: profile number to write | ||
| 181 | * On success returns 0 | ||
| 182 | * On failure returns errno | ||
| 183 | */ | ||
| 184 | static int kone_set_profile(struct usb_device *usb_dev, | ||
| 185 | struct kone_profile const *profile, int number) | ||
| 186 | { | ||
| 187 | int len; | ||
| 188 | |||
| 189 | if (number < 1 || number > 5) | ||
| 190 | return -EINVAL; | ||
| 191 | |||
| 192 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
| 193 | USB_REQ_SET_CONFIGURATION, | ||
| 194 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
| 195 | kone_command_profile, number, (char *)profile, | ||
| 196 | sizeof(struct kone_profile), | ||
| 197 | USB_CTRL_SET_TIMEOUT); | ||
| 198 | |||
| 199 | if (len != sizeof(struct kone_profile)) | ||
| 200 | return len; | ||
| 201 | |||
| 202 | if (kone_check_write(usb_dev)) | ||
| 203 | return -EIO; | ||
| 204 | |||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 209 | * Reads value of "fast-clip-weight" and stores it in @result | ||
| 210 | * On success returns 0 | ||
| 211 | * On failure returns errno | ||
| 212 | */ | ||
| 213 | static int kone_get_weight(struct usb_device *usb_dev, int *result) | ||
| 214 | { | ||
| 215 | int len; | ||
| 216 | uint8_t *data; | ||
| 217 | |||
| 218 | data = kmalloc(1, GFP_KERNEL); | ||
| 219 | if (!data) | ||
| 220 | return -ENOMEM; | ||
| 221 | |||
| 222 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
| 223 | USB_REQ_CLEAR_FEATURE, | ||
| 224 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 225 | kone_command_weight, 0, data, 1, USB_CTRL_SET_TIMEOUT); | ||
| 226 | |||
| 227 | if (len != 1) { | ||
| 228 | kfree(data); | ||
| 229 | return -EIO; | ||
| 230 | } | ||
| 231 | *result = (int)*data; | ||
| 232 | kfree(data); | ||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | |||
| 236 | /* | ||
| 237 | * Reads firmware_version of mouse and stores it in @result | ||
| 238 | * On success returns 0 | ||
| 239 | * On failure returns errno | ||
| 240 | */ | ||
| 241 | static int kone_get_firmware_version(struct usb_device *usb_dev, int *result) | ||
| 242 | { | ||
| 243 | int len; | ||
| 244 | unsigned char *data; | ||
| 245 | |||
| 246 | data = kmalloc(2, GFP_KERNEL); | ||
| 247 | if (!data) | ||
| 248 | return -ENOMEM; | ||
| 249 | |||
| 250 | len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), | ||
| 251 | USB_REQ_CLEAR_FEATURE, | ||
| 252 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 253 | kone_command_firmware_version, 0, data, 2, | ||
| 254 | USB_CTRL_SET_TIMEOUT); | ||
| 255 | |||
| 256 | if (len != 2) { | ||
| 257 | kfree(data); | ||
| 258 | return -EIO; | ||
| 259 | } | ||
| 260 | *result = le16_to_cpu(*data); | ||
| 261 | kfree(data); | ||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | static ssize_t kone_sysfs_read_settings(struct kobject *kobj, | ||
| 266 | struct bin_attribute *attr, char *buf, | ||
| 267 | loff_t off, size_t count) { | ||
| 268 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 269 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 270 | |||
| 271 | if (off >= sizeof(struct kone_settings)) | ||
| 272 | return 0; | ||
| 273 | |||
| 274 | if (off + count > sizeof(struct kone_settings)) | ||
| 275 | count = sizeof(struct kone_settings) - off; | ||
| 276 | |||
| 277 | mutex_lock(&kone->kone_lock); | ||
| 278 | memcpy(buf, &kone->settings + off, count); | ||
| 279 | mutex_unlock(&kone->kone_lock); | ||
| 280 | |||
| 281 | return count; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* | ||
| 285 | * Writing settings automatically activates startup_profile. | ||
| 286 | * This function keeps values in kone_device up to date and assumes that in | ||
| 287 | * case of error the old data is still valid | ||
| 288 | */ | ||
| 289 | static ssize_t kone_sysfs_write_settings(struct kobject *kobj, | ||
| 290 | struct bin_attribute *attr, char *buf, | ||
| 291 | loff_t off, size_t count) { | ||
| 292 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 293 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 294 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
| 295 | int retval = 0, difference; | ||
| 296 | |||
| 297 | /* I need to get my data in one piece */ | ||
| 298 | if (off != 0 || count != sizeof(struct kone_settings)) | ||
| 299 | return -EINVAL; | ||
| 300 | |||
| 301 | mutex_lock(&kone->kone_lock); | ||
| 302 | difference = memcmp(buf, &kone->settings, sizeof(struct kone_settings)); | ||
| 303 | if (difference) { | ||
| 304 | retval = kone_set_settings(usb_dev, | ||
| 305 | (struct kone_settings const *)buf); | ||
| 306 | if (!retval) | ||
| 307 | memcpy(&kone->settings, buf, | ||
| 308 | sizeof(struct kone_settings)); | ||
| 309 | } | ||
| 310 | mutex_unlock(&kone->kone_lock); | ||
| 311 | |||
| 312 | if (retval) | ||
| 313 | return retval; | ||
| 314 | |||
| 315 | /* | ||
| 316 | * If we get here, treat settings as okay and update actual values | ||
| 317 | * according to startup_profile | ||
| 318 | */ | ||
| 319 | kone->actual_profile = kone->settings.startup_profile; | ||
| 320 | kone->actual_dpi = kone->profiles[kone->actual_profile - 1].startup_dpi; | ||
| 321 | |||
| 322 | return sizeof(struct kone_settings); | ||
| 323 | } | ||
| 324 | |||
| 325 | static ssize_t kone_sysfs_read_profilex(struct kobject *kobj, | ||
| 326 | struct bin_attribute *attr, char *buf, | ||
| 327 | loff_t off, size_t count, int number) { | ||
| 328 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 329 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 330 | |||
| 331 | if (off >= sizeof(struct kone_profile)) | ||
| 332 | return 0; | ||
| 333 | |||
| 334 | if (off + count > sizeof(struct kone_profile)) | ||
| 335 | count = sizeof(struct kone_profile) - off; | ||
| 336 | |||
| 337 | mutex_lock(&kone->kone_lock); | ||
| 338 | memcpy(buf, &kone->profiles[number - 1], sizeof(struct kone_profile)); | ||
| 339 | mutex_unlock(&kone->kone_lock); | ||
| 340 | |||
| 341 | return count; | ||
| 342 | } | ||
| 343 | |||
| 344 | static ssize_t kone_sysfs_read_profile1(struct kobject *kobj, | ||
| 345 | struct bin_attribute *attr, char *buf, | ||
| 346 | loff_t off, size_t count) { | ||
| 347 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 1); | ||
| 348 | } | ||
| 349 | |||
| 350 | static ssize_t kone_sysfs_read_profile2(struct kobject *kobj, | ||
| 351 | struct bin_attribute *attr, char *buf, | ||
| 352 | loff_t off, size_t count) { | ||
| 353 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 2); | ||
| 354 | } | ||
| 355 | |||
| 356 | static ssize_t kone_sysfs_read_profile3(struct kobject *kobj, | ||
| 357 | struct bin_attribute *attr, char *buf, | ||
| 358 | loff_t off, size_t count) { | ||
| 359 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 3); | ||
| 360 | } | ||
| 361 | |||
| 362 | static ssize_t kone_sysfs_read_profile4(struct kobject *kobj, | ||
| 363 | struct bin_attribute *attr, char *buf, | ||
| 364 | loff_t off, size_t count) { | ||
| 365 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 4); | ||
| 366 | } | ||
| 367 | |||
| 368 | static ssize_t kone_sysfs_read_profile5(struct kobject *kobj, | ||
| 369 | struct bin_attribute *attr, char *buf, | ||
| 370 | loff_t off, size_t count) { | ||
| 371 | return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 5); | ||
| 372 | } | ||
| 373 | |||
| 374 | /* Writes data only if different to stored data */ | ||
| 375 | static ssize_t kone_sysfs_write_profilex(struct kobject *kobj, | ||
| 376 | struct bin_attribute *attr, char *buf, | ||
| 377 | loff_t off, size_t count, int number) { | ||
| 378 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 379 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 380 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
| 381 | struct kone_profile *profile; | ||
| 382 | int retval = 0, difference; | ||
| 383 | |||
| 384 | /* I need to get my data in one piece */ | ||
| 385 | if (off != 0 || count != sizeof(struct kone_profile)) | ||
| 386 | return -EINVAL; | ||
| 387 | |||
| 388 | profile = &kone->profiles[number - 1]; | ||
| 389 | |||
| 390 | mutex_lock(&kone->kone_lock); | ||
| 391 | difference = memcmp(buf, profile, sizeof(struct kone_profile)); | ||
| 392 | if (difference) { | ||
| 393 | retval = kone_set_profile(usb_dev, | ||
| 394 | (struct kone_profile const *)buf, number); | ||
| 395 | if (!retval) | ||
| 396 | memcpy(profile, buf, sizeof(struct kone_profile)); | ||
| 397 | } | ||
| 398 | mutex_unlock(&kone->kone_lock); | ||
| 399 | |||
| 400 | if (retval) | ||
| 401 | return retval; | ||
| 402 | |||
| 403 | return sizeof(struct kone_profile); | ||
| 404 | } | ||
| 405 | |||
| 406 | static ssize_t kone_sysfs_write_profile1(struct kobject *kobj, | ||
| 407 | struct bin_attribute *attr, char *buf, | ||
| 408 | loff_t off, size_t count) { | ||
| 409 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 1); | ||
| 410 | } | ||
| 411 | |||
| 412 | static ssize_t kone_sysfs_write_profile2(struct kobject *kobj, | ||
| 413 | struct bin_attribute *attr, char *buf, | ||
| 414 | loff_t off, size_t count) { | ||
| 415 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 2); | ||
| 416 | } | ||
| 417 | |||
| 418 | static ssize_t kone_sysfs_write_profile3(struct kobject *kobj, | ||
| 419 | struct bin_attribute *attr, char *buf, | ||
| 420 | loff_t off, size_t count) { | ||
| 421 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 3); | ||
| 422 | } | ||
| 423 | |||
| 424 | static ssize_t kone_sysfs_write_profile4(struct kobject *kobj, | ||
| 425 | struct bin_attribute *attr, char *buf, | ||
| 426 | loff_t off, size_t count) { | ||
| 427 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 4); | ||
| 428 | } | ||
| 429 | |||
| 430 | static ssize_t kone_sysfs_write_profile5(struct kobject *kobj, | ||
| 431 | struct bin_attribute *attr, char *buf, | ||
| 432 | loff_t off, size_t count) { | ||
| 433 | return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 5); | ||
| 434 | } | ||
| 435 | |||
| 436 | static ssize_t kone_sysfs_show_actual_profile(struct device *dev, | ||
| 437 | struct device_attribute *attr, char *buf) | ||
| 438 | { | ||
| 439 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 440 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile); | ||
| 441 | } | ||
| 442 | |||
| 443 | static ssize_t kone_sysfs_show_actual_dpi(struct device *dev, | ||
| 444 | struct device_attribute *attr, char *buf) | ||
| 445 | { | ||
| 446 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 447 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi); | ||
| 448 | } | ||
| 449 | |||
| 450 | /* weight is read each time, since we don't get informed when it's changed */ | ||
| 451 | static ssize_t kone_sysfs_show_weight(struct device *dev, | ||
| 452 | struct device_attribute *attr, char *buf) | ||
| 453 | { | ||
| 454 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 455 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
| 456 | int weight = 0; | ||
| 457 | int retval; | ||
| 458 | |||
| 459 | mutex_lock(&kone->kone_lock); | ||
| 460 | retval = kone_get_weight(usb_dev, &weight); | ||
| 461 | mutex_unlock(&kone->kone_lock); | ||
| 462 | |||
| 463 | if (retval) | ||
| 464 | return retval; | ||
| 465 | return snprintf(buf, PAGE_SIZE, "%d\n", weight); | ||
| 466 | } | ||
| 467 | |||
| 468 | static ssize_t kone_sysfs_show_firmware_version(struct device *dev, | ||
| 469 | struct device_attribute *attr, char *buf) | ||
| 470 | { | ||
| 471 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 472 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version); | ||
| 473 | } | ||
| 474 | |||
| 475 | static ssize_t kone_sysfs_show_tcu(struct device *dev, | ||
| 476 | struct device_attribute *attr, char *buf) | ||
| 477 | { | ||
| 478 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 479 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu); | ||
| 480 | } | ||
| 481 | |||
| 482 | static int kone_tcu_command(struct usb_device *usb_dev, int number) | ||
| 483 | { | ||
| 484 | int len; | ||
| 485 | char *value; | ||
| 486 | |||
| 487 | value = kmalloc(1, GFP_KERNEL); | ||
| 488 | if (!value) | ||
| 489 | return -ENOMEM; | ||
| 490 | |||
| 491 | *value = number; | ||
| 492 | |||
| 493 | len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), | ||
| 494 | USB_REQ_SET_CONFIGURATION, | ||
| 495 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
| 496 | kone_command_calibrate, 0, value, 1, | ||
| 497 | USB_CTRL_SET_TIMEOUT); | ||
| 498 | |||
| 499 | kfree(value); | ||
| 500 | return ((len != 1) ? -EIO : 0); | ||
| 501 | } | ||
| 502 | |||
| 503 | /* | ||
| 504 | * Calibrating the tcu is the only action that changes settings data inside the | ||
| 505 | * mouse, so this data needs to be reread | ||
| 506 | */ | ||
| 507 | static ssize_t kone_sysfs_set_tcu(struct device *dev, | ||
| 508 | struct device_attribute *attr, char const *buf, size_t size) | ||
| 509 | { | ||
| 510 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 511 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
| 512 | int retval; | ||
| 513 | unsigned long state; | ||
| 514 | |||
| 515 | retval = strict_strtoul(buf, 10, &state); | ||
| 516 | if (retval) | ||
| 517 | return retval; | ||
| 518 | |||
| 519 | if (state != 0 && state != 1) | ||
| 520 | return -EINVAL; | ||
| 521 | |||
| 522 | mutex_lock(&kone->kone_lock); | ||
| 523 | |||
| 524 | if (state == 1) { /* state activate */ | ||
| 525 | retval = kone_tcu_command(usb_dev, 1); | ||
| 526 | if (retval) | ||
| 527 | goto exit_unlock; | ||
| 528 | retval = kone_tcu_command(usb_dev, 2); | ||
| 529 | if (retval) | ||
| 530 | goto exit_unlock; | ||
| 531 | ssleep(5); /* tcu needs this time for calibration */ | ||
| 532 | retval = kone_tcu_command(usb_dev, 3); | ||
| 533 | if (retval) | ||
| 534 | goto exit_unlock; | ||
| 535 | retval = kone_tcu_command(usb_dev, 0); | ||
| 536 | if (retval) | ||
| 537 | goto exit_unlock; | ||
| 538 | retval = kone_tcu_command(usb_dev, 4); | ||
| 539 | if (retval) | ||
| 540 | goto exit_unlock; | ||
| 541 | /* | ||
| 542 | * Kone needs this time to settle things. | ||
| 543 | * Reading settings too early will result in invalid data. | ||
| 544 | * Roccat's driver waits 1 sec, maybe this time could be | ||
| 545 | * shortened. | ||
| 546 | */ | ||
| 547 | ssleep(1); | ||
| 548 | } | ||
| 549 | |||
| 550 | /* calibration changes values in settings, so reread */ | ||
| 551 | retval = kone_get_settings(usb_dev, &kone->settings); | ||
| 552 | if (retval) | ||
| 553 | goto exit_no_settings; | ||
| 554 | |||
| 555 | /* only write settings back if activation state is different */ | ||
| 556 | if (kone->settings.tcu != state) { | ||
| 557 | kone->settings.tcu = state; | ||
| 558 | kone_set_settings_checksum(&kone->settings); | ||
| 559 | |||
| 560 | retval = kone_set_settings(usb_dev, &kone->settings); | ||
| 561 | if (retval) { | ||
| 562 | dev_err(&usb_dev->dev, "couldn't set tcu state\n"); | ||
| 563 | /* | ||
| 564 | * try to reread valid settings into buffer overwriting | ||
| 565 | * first error code | ||
| 566 | */ | ||
| 567 | retval = kone_get_settings(usb_dev, &kone->settings); | ||
| 568 | if (retval) | ||
| 569 | goto exit_no_settings; | ||
| 570 | goto exit_unlock; | ||
| 571 | } | ||
| 572 | } | ||
| 573 | |||
| 574 | retval = size; | ||
| 575 | exit_no_settings: | ||
| 576 | dev_err(&usb_dev->dev, "couldn't read settings\n"); | ||
| 577 | exit_unlock: | ||
| 578 | mutex_unlock(&kone->kone_lock); | ||
| 579 | return retval; | ||
| 580 | } | ||
| 581 | |||
| 582 | static ssize_t kone_sysfs_show_startup_profile(struct device *dev, | ||
| 583 | struct device_attribute *attr, char *buf) | ||
| 584 | { | ||
| 585 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 586 | return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile); | ||
| 587 | } | ||
| 588 | |||
| 589 | static ssize_t kone_sysfs_set_startup_profile(struct device *dev, | ||
| 590 | struct device_attribute *attr, char const *buf, size_t size) | ||
| 591 | { | ||
| 592 | struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); | ||
| 593 | struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); | ||
| 594 | int retval; | ||
| 595 | unsigned long new_startup_profile; | ||
| 596 | |||
| 597 | retval = strict_strtoul(buf, 10, &new_startup_profile); | ||
| 598 | if (retval) | ||
| 599 | return retval; | ||
| 600 | |||
| 601 | if (new_startup_profile < 1 || new_startup_profile > 5) | ||
| 602 | return -EINVAL; | ||
| 603 | |||
| 604 | mutex_lock(&kone->kone_lock); | ||
| 605 | |||
| 606 | kone->settings.startup_profile = new_startup_profile; | ||
| 607 | kone_set_settings_checksum(&kone->settings); | ||
| 608 | |||
| 609 | retval = kone_set_settings(usb_dev, &kone->settings); | ||
| 610 | |||
| 611 | mutex_unlock(&kone->kone_lock); | ||
| 612 | |||
| 613 | if (retval) | ||
| 614 | return retval; | ||
| 615 | |||
| 616 | /* changing the startup profile immediately activates this profile */ | ||
| 617 | kone->actual_profile = new_startup_profile; | ||
| 618 | kone->actual_dpi = kone->profiles[kone->actual_profile - 1].startup_dpi; | ||
| 619 | |||
| 620 | return size; | ||
| 621 | } | ||
| 622 | |||
| 623 | /* | ||
| 624 | * This file is used by userland software to find devices that are handled by | ||
| 625 | * this driver. This provides a consistent way for actual and older kernels | ||
| 626 | * where this driver replaced usbhid instead of generic-usb. | ||
| 627 | * Driver capabilities are determined by version number. | ||
| 628 | */ | ||
| 629 | static ssize_t kone_sysfs_show_driver_version(struct device *dev, | ||
| 630 | struct device_attribute *attr, char *buf) | ||
| 631 | { | ||
| 632 | return snprintf(buf, PAGE_SIZE, DRIVER_VERSION "\n"); | ||
| 633 | } | ||
| 634 | |||
| 635 | /* | ||
| 636 | * Read actual dpi settings. | ||
| 637 | * Returns raw value for further processing. Refer to enum kone_polling_rates to | ||
| 638 | * get real value. | ||
| 639 | */ | ||
| 640 | static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL); | ||
| 641 | |||
| 642 | static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL); | ||
| 643 | |||
| 644 | /* | ||
| 645 | * The mouse can be equipped with one of four supplied weights from 5 to 20 | ||
| 646 | * grams which are recognized and its value can be read out. | ||
| 647 | * This returns the raw value reported by the mouse for easy evaluation by | ||
| 648 | * software. Refer to enum kone_weights to get corresponding real weight. | ||
| 649 | */ | ||
| 650 | static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL); | ||
| 651 | |||
| 652 | /* | ||
| 653 | * Prints firmware version stored in mouse as integer. | ||
| 654 | * The raw value reported by the mouse is returned for easy evaluation, to get | ||
| 655 | * the real version number the decimal point has to be shifted 2 positions to | ||
| 656 | * the left. E.g. a value of 138 means 1.38. | ||
| 657 | */ | ||
| 658 | static DEVICE_ATTR(firmware_version, 0440, | ||
| 659 | kone_sysfs_show_firmware_version, NULL); | ||
| 660 | |||
| 661 | /* | ||
| 662 | * Prints state of Tracking Control Unit as number where 0 = off and 1 = on | ||
| 663 | * Writing 0 deactivates tcu and writing 1 calibrates and activates the tcu | ||
| 664 | */ | ||
| 665 | static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu); | ||
| 666 | |||
| 667 | /* Prints and takes the number of the profile the mouse starts with */ | ||
| 668 | static DEVICE_ATTR(startup_profile, 0660, | ||
| 669 | kone_sysfs_show_startup_profile, | ||
| 670 | kone_sysfs_set_startup_profile); | ||
| 671 | |||
| 672 | static DEVICE_ATTR(kone_driver_version, 0440, | ||
| 673 | kone_sysfs_show_driver_version, NULL); | ||
| 674 | |||
| 675 | static struct attribute *kone_attributes[] = { | ||
| 676 | &dev_attr_actual_dpi.attr, | ||
| 677 | &dev_attr_actual_profile.attr, | ||
| 678 | &dev_attr_weight.attr, | ||
| 679 | &dev_attr_firmware_version.attr, | ||
| 680 | &dev_attr_tcu.attr, | ||
| 681 | &dev_attr_startup_profile.attr, | ||
| 682 | &dev_attr_kone_driver_version.attr, | ||
| 683 | NULL | ||
| 684 | }; | ||
| 685 | |||
| 686 | static struct attribute_group kone_attribute_group = { | ||
| 687 | .attrs = kone_attributes | ||
| 688 | }; | ||
| 689 | |||
| 690 | static struct bin_attribute kone_settings_attr = { | ||
| 691 | .attr = { .name = "settings", .mode = 0660 }, | ||
| 692 | .size = sizeof(struct kone_settings), | ||
| 693 | .read = kone_sysfs_read_settings, | ||
| 694 | .write = kone_sysfs_write_settings | ||
| 695 | }; | ||
| 696 | |||
| 697 | static struct bin_attribute kone_profile1_attr = { | ||
| 698 | .attr = { .name = "profile1", .mode = 0660 }, | ||
| 699 | .size = sizeof(struct kone_profile), | ||
| 700 | .read = kone_sysfs_read_profile1, | ||
| 701 | .write = kone_sysfs_write_profile1 | ||
| 702 | }; | ||
| 703 | |||
| 704 | static struct bin_attribute kone_profile2_attr = { | ||
| 705 | .attr = { .name = "profile2", .mode = 0660 }, | ||
| 706 | .size = sizeof(struct kone_profile), | ||
| 707 | .read = kone_sysfs_read_profile2, | ||
| 708 | .write = kone_sysfs_write_profile2 | ||
| 709 | }; | ||
| 710 | |||
| 711 | static struct bin_attribute kone_profile3_attr = { | ||
| 712 | .attr = { .name = "profile3", .mode = 0660 }, | ||
| 713 | .size = sizeof(struct kone_profile), | ||
| 714 | .read = kone_sysfs_read_profile3, | ||
| 715 | .write = kone_sysfs_write_profile3 | ||
| 716 | }; | ||
| 717 | |||
| 718 | static struct bin_attribute kone_profile4_attr = { | ||
| 719 | .attr = { .name = "profile4", .mode = 0660 }, | ||
| 720 | .size = sizeof(struct kone_profile), | ||
| 721 | .read = kone_sysfs_read_profile4, | ||
| 722 | .write = kone_sysfs_write_profile4 | ||
| 723 | }; | ||
| 724 | |||
| 725 | static struct bin_attribute kone_profile5_attr = { | ||
| 726 | .attr = { .name = "profile5", .mode = 0660 }, | ||
| 727 | .size = sizeof(struct kone_profile), | ||
| 728 | .read = kone_sysfs_read_profile5, | ||
| 729 | .write = kone_sysfs_write_profile5 | ||
| 730 | }; | ||
| 731 | |||
| 732 | static int kone_create_sysfs_attributes(struct usb_interface *intf) | ||
| 733 | { | ||
| 734 | int retval; | ||
| 735 | |||
| 736 | retval = sysfs_create_group(&intf->dev.kobj, &kone_attribute_group); | ||
| 737 | if (retval) | ||
| 738 | goto exit_1; | ||
| 739 | |||
| 740 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_settings_attr); | ||
| 741 | if (retval) | ||
| 742 | goto exit_2; | ||
| 743 | |||
| 744 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile1_attr); | ||
| 745 | if (retval) | ||
| 746 | goto exit_3; | ||
| 747 | |||
| 748 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile2_attr); | ||
| 749 | if (retval) | ||
| 750 | goto exit_4; | ||
| 751 | |||
| 752 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile3_attr); | ||
| 753 | if (retval) | ||
| 754 | goto exit_5; | ||
| 755 | |||
| 756 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile4_attr); | ||
| 757 | if (retval) | ||
| 758 | goto exit_6; | ||
| 759 | |||
| 760 | retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile5_attr); | ||
| 761 | if (retval) | ||
| 762 | goto exit_7; | ||
| 763 | |||
| 764 | return 0; | ||
| 765 | |||
| 766 | exit_7: | ||
| 767 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr); | ||
| 768 | exit_6: | ||
| 769 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr); | ||
| 770 | exit_5: | ||
| 771 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr); | ||
| 772 | exit_4: | ||
| 773 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr); | ||
| 774 | exit_3: | ||
| 775 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr); | ||
| 776 | exit_2: | ||
| 777 | sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group); | ||
| 778 | exit_1: | ||
| 779 | return retval; | ||
| 780 | } | ||
| 781 | |||
| 782 | static void kone_remove_sysfs_attributes(struct usb_interface *intf) | ||
| 783 | { | ||
| 784 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile5_attr); | ||
| 785 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr); | ||
| 786 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr); | ||
| 787 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr); | ||
| 788 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr); | ||
| 789 | sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr); | ||
| 790 | sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group); | ||
| 791 | } | ||
| 792 | |||
| 793 | static int kone_init_kone_device_struct(struct usb_device *usb_dev, | ||
| 794 | struct kone_device *kone) | ||
| 795 | { | ||
| 796 | uint i; | ||
| 797 | int retval; | ||
| 798 | |||
| 799 | mutex_init(&kone->kone_lock); | ||
| 800 | |||
| 801 | for (i = 0; i < 5; ++i) { | ||
| 802 | retval = kone_get_profile(usb_dev, &kone->profiles[i], i + 1); | ||
| 803 | if (retval) | ||
| 804 | return retval; | ||
| 805 | } | ||
| 806 | |||
| 807 | retval = kone_get_settings(usb_dev, &kone->settings); | ||
| 808 | if (retval) | ||
| 809 | return retval; | ||
| 810 | |||
| 811 | retval = kone_get_firmware_version(usb_dev, &kone->firmware_version); | ||
| 812 | if (retval) | ||
| 813 | return retval; | ||
| 814 | |||
| 815 | kone->actual_profile = kone->settings.startup_profile; | ||
| 816 | kone->actual_dpi = kone->profiles[kone->actual_profile].startup_dpi; | ||
| 817 | |||
| 818 | return 0; | ||
| 819 | } | ||
| 820 | |||
| 821 | /* | ||
| 822 | * Since IGNORE_MOUSE quirk moved to hid-apple, there is no way to bind only to | ||
| 823 | * mousepart if usb_hid is compiled into the kernel and kone is compiled as | ||
| 824 | * module. | ||
| 825 | * Secial behaviour is bound only to mousepart since only mouseevents contain | ||
| 826 | * additional notifications. | ||
| 827 | */ | ||
| 828 | static int kone_init_specials(struct hid_device *hdev) | ||
| 829 | { | ||
| 830 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
| 831 | struct usb_device *usb_dev = interface_to_usbdev(intf); | ||
| 832 | struct kone_device *kone; | ||
| 833 | int retval; | ||
| 834 | |||
| 835 | if (intf->cur_altsetting->desc.bInterfaceProtocol | ||
| 836 | == USB_INTERFACE_PROTOCOL_MOUSE) { | ||
| 837 | |||
| 838 | kone = kzalloc(sizeof(*kone), GFP_KERNEL); | ||
| 839 | if (!kone) { | ||
| 840 | dev_err(&hdev->dev, "can't alloc device descriptor\n"); | ||
| 841 | return -ENOMEM; | ||
| 842 | } | ||
| 843 | hid_set_drvdata(hdev, kone); | ||
| 844 | |||
| 845 | retval = kone_init_kone_device_struct(usb_dev, kone); | ||
| 846 | if (retval) { | ||
| 847 | dev_err(&hdev->dev, | ||
| 848 | "couldn't init struct kone_device\n"); | ||
| 849 | goto exit_free; | ||
| 850 | } | ||
| 851 | retval = kone_create_sysfs_attributes(intf); | ||
| 852 | if (retval) { | ||
| 853 | dev_err(&hdev->dev, "cannot create sysfs files\n"); | ||
| 854 | goto exit_free; | ||
| 855 | } | ||
| 856 | } else { | ||
| 857 | hid_set_drvdata(hdev, NULL); | ||
| 858 | } | ||
| 859 | |||
| 860 | return 0; | ||
| 861 | exit_free: | ||
| 862 | kfree(kone); | ||
| 863 | return retval; | ||
| 864 | } | ||
| 865 | |||
| 866 | |||
| 867 | static void kone_remove_specials(struct hid_device *hdev) | ||
| 868 | { | ||
| 869 | struct usb_interface *intf = to_usb_interface(hdev->dev.parent); | ||
| 870 | |||
| 871 | if (intf->cur_altsetting->desc.bInterfaceProtocol | ||
| 872 | == USB_INTERFACE_PROTOCOL_MOUSE) { | ||
| 873 | kone_remove_sysfs_attributes(intf); | ||
| 874 | kfree(hid_get_drvdata(hdev)); | ||
| 875 | } | ||
| 876 | } | ||
| 877 | |||
| 878 | static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
| 879 | { | ||
| 880 | int retval; | ||
| 881 | |||
| 882 | retval = hid_parse(hdev); | ||
| 883 | if (retval) { | ||
| 884 | dev_err(&hdev->dev, "parse failed\n"); | ||
| 885 | goto exit; | ||
| 886 | } | ||
| 887 | |||
| 888 | retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
| 889 | if (retval) { | ||
| 890 | dev_err(&hdev->dev, "hw start failed\n"); | ||
| 891 | goto exit; | ||
| 892 | } | ||
| 893 | |||
| 894 | retval = kone_init_specials(hdev); | ||
| 895 | if (retval) { | ||
| 896 | dev_err(&hdev->dev, "couldn't install mouse\n"); | ||
| 897 | goto exit_stop; | ||
| 898 | } | ||
| 899 | |||
| 900 | return 0; | ||
| 901 | |||
| 902 | exit_stop: | ||
| 903 | hid_hw_stop(hdev); | ||
| 904 | exit: | ||
| 905 | return retval; | ||
| 906 | } | ||
| 907 | |||
| 908 | static void kone_remove(struct hid_device *hdev) | ||
| 909 | { | ||
| 910 | kone_remove_specials(hdev); | ||
| 911 | hid_hw_stop(hdev); | ||
| 912 | } | ||
| 913 | |||
| 914 | /* | ||
| 915 | * Is called for keyboard- and mousepart. | ||
| 916 | * Only mousepart gets informations about special events in its extended event | ||
| 917 | * structure. | ||
| 918 | */ | ||
| 919 | static int kone_raw_event(struct hid_device *hdev, struct hid_report *report, | ||
| 920 | u8 *data, int size) | ||
| 921 | { | ||
| 922 | struct kone_device *kone = hid_get_drvdata(hdev); | ||
| 923 | struct kone_mouse_event *event = (struct kone_mouse_event *)data; | ||
| 924 | |||
| 925 | /* keyboard events are always processed by default handler */ | ||
| 926 | if (size != sizeof(struct kone_mouse_event)) | ||
| 927 | return 0; | ||
| 928 | |||
| 929 | /* | ||
| 930 | * Firmware 1.38 introduced new behaviour for tilt buttons. | ||
| 931 | * Pressed tilt button is reported in each movement event. | ||
| 932 | * Workaround sends only one event per press. | ||
| 933 | */ | ||
| 934 | if (kone->last_tilt_state == event->tilt) | ||
| 935 | event->tilt = 0; | ||
| 936 | else | ||
| 937 | kone->last_tilt_state = event->tilt; | ||
| 938 | |||
| 939 | /* | ||
| 940 | * handle special events and keep actual profile and dpi values | ||
| 941 | * up to date | ||
| 942 | */ | ||
| 943 | switch (event->event) { | ||
| 944 | case kone_mouse_event_osd_dpi: | ||
| 945 | dev_dbg(&hdev->dev, "osd dpi event. actual dpi %d\n", | ||
| 946 | event->value); | ||
| 947 | return 1; /* return 1 if event was handled */ | ||
| 948 | case kone_mouse_event_switch_dpi: | ||
| 949 | kone->actual_dpi = event->value; | ||
| 950 | dev_dbg(&hdev->dev, "switched dpi to %d\n", event->value); | ||
| 951 | return 1; | ||
| 952 | case kone_mouse_event_osd_profile: | ||
| 953 | dev_dbg(&hdev->dev, "osd profile event. actual profile %d\n", | ||
| 954 | event->value); | ||
| 955 | return 1; | ||
| 956 | case kone_mouse_event_switch_profile: | ||
| 957 | kone->actual_profile = event->value; | ||
| 958 | kone->actual_dpi = kone->profiles[kone->actual_profile - 1]. | ||
| 959 | startup_dpi; | ||
| 960 | dev_dbg(&hdev->dev, "switched profile to %d\n", event->value); | ||
| 961 | return 1; | ||
| 962 | case kone_mouse_event_call_overlong_macro: | ||
| 963 | dev_dbg(&hdev->dev, "overlong macro called, button %d %s/%s\n", | ||
| 964 | event->macro_key, | ||
| 965 | kone->profiles[kone->actual_profile - 1]. | ||
| 966 | button_infos[event->macro_key].macro_set_name, | ||
| 967 | kone->profiles[kone->actual_profile - 1]. | ||
| 968 | button_infos[event->macro_key].macro_name | ||
| 969 | ); | ||
| 970 | return 1; | ||
| 971 | } | ||
| 972 | |||
| 973 | return 0; /* do further processing */ | ||
| 974 | } | ||
| 975 | |||
| 976 | static const struct hid_device_id kone_devices[] = { | ||
| 977 | { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, | ||
| 978 | { } | ||
| 979 | }; | ||
| 980 | |||
| 981 | MODULE_DEVICE_TABLE(hid, kone_devices); | ||
| 982 | |||
| 983 | static struct hid_driver kone_driver = { | ||
| 984 | .name = "kone", | ||
| 985 | .id_table = kone_devices, | ||
| 986 | .probe = kone_probe, | ||
| 987 | .remove = kone_remove, | ||
| 988 | .raw_event = kone_raw_event | ||
| 989 | }; | ||
| 990 | |||
| 991 | static int kone_init(void) | ||
| 992 | { | ||
| 993 | return hid_register_driver(&kone_driver); | ||
| 994 | } | ||
| 995 | |||
| 996 | static void kone_exit(void) | ||
| 997 | { | ||
| 998 | hid_unregister_driver(&kone_driver); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | module_init(kone_init); | ||
| 1002 | module_exit(kone_exit); | ||
| 1003 | |||
| 1004 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 1005 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 1006 | MODULE_LICENSE(DRIVER_LICENSE); | ||
diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h new file mode 100644 index 000000000000..ee6898c9d92c --- /dev/null +++ b/drivers/hid/hid-roccat-kone.h | |||
| @@ -0,0 +1,214 @@ | |||
| 1 | #ifndef __HID_ROCCAT_KONE_H | ||
| 2 | #define __HID_ROCCAT_KONE_H | ||
| 3 | |||
| 4 | /* | ||
| 5 | * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net> | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by the Free | ||
| 11 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 12 | * any later version. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/types.h> | ||
| 16 | |||
| 17 | #define DRIVER_VERSION "v0.3.0" | ||
| 18 | #define DRIVER_AUTHOR "Stefan Achatz" | ||
| 19 | #define DRIVER_DESC "USB Roccat Kone driver" | ||
| 20 | #define DRIVER_LICENSE "GPL v2" | ||
| 21 | |||
| 22 | #pragma pack(push) | ||
| 23 | #pragma pack(1) | ||
| 24 | |||
| 25 | struct kone_keystroke { | ||
| 26 | uint8_t key; | ||
| 27 | uint8_t action; | ||
| 28 | uint16_t period; /* in milliseconds */ | ||
| 29 | }; | ||
| 30 | |||
| 31 | enum kone_keystroke_buttons { | ||
| 32 | kone_keystroke_button_1 = 0xf0, /* left mouse button */ | ||
| 33 | kone_keystroke_button_2 = 0xf1, /* right mouse button */ | ||
| 34 | kone_keystroke_button_3 = 0xf2, /* wheel */ | ||
| 35 | kone_keystroke_button_9 = 0xf3, /* side button up */ | ||
| 36 | kone_keystroke_button_8 = 0xf4 /* side button down */ | ||
| 37 | }; | ||
| 38 | |||
| 39 | enum kone_keystroke_actions { | ||
| 40 | kone_keystroke_action_press = 0, | ||
| 41 | kone_keystroke_action_release = 1 | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct kone_button_info { | ||
| 45 | uint8_t number; /* range 1-8 */ | ||
| 46 | uint8_t type; | ||
| 47 | uint8_t macro_type; /* 0 = short, 1 = overlong */ | ||
| 48 | uint8_t macro_set_name[16]; /* can be max 15 chars long */ | ||
| 49 | uint8_t macro_name[16]; /* can be max 15 chars long */ | ||
| 50 | uint8_t count; | ||
| 51 | struct kone_keystroke keystrokes[20]; | ||
| 52 | }; | ||
| 53 | |||
| 54 | enum kone_button_info_types { | ||
| 55 | /* valid button types until firmware 1.32 */ | ||
| 56 | kone_button_info_type_button_1 = 0x1, /* click (left mouse button) */ | ||
| 57 | kone_button_info_type_button_2 = 0x2, /* menu (right mouse button)*/ | ||
| 58 | kone_button_info_type_button_3 = 0x3, /* scroll (wheel) */ | ||
| 59 | kone_button_info_type_double_click = 0x4, | ||
| 60 | kone_button_info_type_key = 0x5, | ||
| 61 | kone_button_info_type_macro = 0x6, | ||
| 62 | kone_button_info_type_off = 0x7, | ||
| 63 | /* TODO clarify function and rename */ | ||
| 64 | kone_button_info_type_osd_xy_prescaling = 0x8, | ||
| 65 | kone_button_info_type_osd_dpi = 0x9, | ||
| 66 | kone_button_info_type_osd_profile = 0xa, | ||
| 67 | kone_button_info_type_button_9 = 0xb, /* ie forward */ | ||
| 68 | kone_button_info_type_button_8 = 0xc, /* ie backward */ | ||
| 69 | kone_button_info_type_dpi_up = 0xd, /* internal */ | ||
| 70 | kone_button_info_type_dpi_down = 0xe, /* internal */ | ||
| 71 | kone_button_info_type_button_7 = 0xf, /* tilt left */ | ||
| 72 | kone_button_info_type_button_6 = 0x10, /* tilt right */ | ||
| 73 | kone_button_info_type_profile_up = 0x11, /* internal */ | ||
| 74 | kone_button_info_type_profile_down = 0x12, /* internal */ | ||
| 75 | /* additional valid button types since firmware 1.38 */ | ||
| 76 | kone_button_info_type_multimedia_open_player = 0x20, | ||
| 77 | kone_button_info_type_multimedia_next_track = 0x21, | ||
| 78 | kone_button_info_type_multimedia_prev_track = 0x22, | ||
| 79 | kone_button_info_type_multimedia_play_pause = 0x23, | ||
| 80 | kone_button_info_type_multimedia_stop = 0x24, | ||
| 81 | kone_button_info_type_multimedia_mute = 0x25, | ||
| 82 | kone_button_info_type_multimedia_volume_up = 0x26, | ||
| 83 | kone_button_info_type_multimedia_volume_down = 0x27 | ||
| 84 | }; | ||
| 85 | |||
| 86 | struct kone_light_info { | ||
| 87 | uint8_t number; /* number of light 1-5 */ | ||
| 88 | uint8_t mod; /* 1 = on, 2 = off */ | ||
| 89 | uint8_t red; /* range 0x00-0xff */ | ||
| 90 | uint8_t green; /* range 0x00-0xff */ | ||
| 91 | uint8_t blue; /* range 0x00-0xff */ | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct kone_profile { | ||
| 95 | uint16_t size; /* always 975 */ | ||
| 96 | uint16_t unused; /* always 0 */ | ||
| 97 | |||
| 98 | /* | ||
| 99 | * range 1-5 | ||
| 100 | * This number does not need to correspond with location where profile | ||
| 101 | * saved | ||
| 102 | */ | ||
| 103 | uint8_t profile; /* range 1-5 */ | ||
| 104 | |||
| 105 | uint16_t main_sensitivity; /* range 100-1000 */ | ||
| 106 | uint8_t xy_sensitivity_enabled; /* 1 = on, 2 = off */ | ||
| 107 | uint16_t x_sensitivity; /* range 100-1000 */ | ||
| 108 | uint16_t y_sensitivity; /* range 100-1000 */ | ||
| 109 | uint8_t dpi_rate; /* bit 1 = 800, ... */ | ||
| 110 | uint8_t startup_dpi; /* range 1-6 */ | ||
| 111 | uint8_t polling_rate; /* 1 = 125Hz, 2 = 500Hz, 3 = 1000Hz */ | ||
| 112 | /* kone has no dcu | ||
| 113 | * value is always 2 in firmwares <= 1.32 and | ||
| 114 | * 1 in firmwares > 1.32 | ||
| 115 | */ | ||
| 116 | uint8_t dcu_flag; | ||
| 117 | uint8_t light_effect_1; /* range 1-3 */ | ||
| 118 | uint8_t light_effect_2; /* range 1-5 */ | ||
| 119 | uint8_t light_effect_3; /* range 1-4 */ | ||
| 120 | uint8_t light_effect_speed; /* range 0-255 */ | ||
| 121 | |||
| 122 | struct kone_light_info light_infos[5]; | ||
| 123 | struct kone_button_info button_infos[8]; | ||
| 124 | |||
| 125 | uint16_t checksum; /* \brief holds checksum of struct */ | ||
| 126 | }; | ||
| 127 | |||
| 128 | enum kone_polling_rates { | ||
| 129 | kone_polling_rate_125 = 1, | ||
| 130 | kone_polling_rate_500 = 2, | ||
| 131 | kone_polling_rate_1000 = 3 | ||
| 132 | }; | ||
| 133 | |||
| 134 | struct kone_settings { | ||
| 135 | uint16_t size; /* always 36 */ | ||
| 136 | uint8_t startup_profile; /* 1-5 */ | ||
| 137 | uint8_t unknown1; | ||
| 138 | uint8_t tcu; /* 0 = off, 1 = on */ | ||
| 139 | uint8_t unknown2[23]; | ||
| 140 | uint8_t calibration_data[4]; | ||
| 141 | uint8_t unknown3[2]; | ||
| 142 | uint16_t checksum; | ||
| 143 | }; | ||
| 144 | |||
| 145 | /* | ||
| 146 | * 12 byte mouse event read by interrupt_read | ||
| 147 | */ | ||
| 148 | struct kone_mouse_event { | ||
| 149 | uint8_t report_number; /* always 1 */ | ||
| 150 | uint8_t button; | ||
| 151 | uint16_t x; | ||
| 152 | uint16_t y; | ||
| 153 | uint8_t wheel; /* up = 1, down = -1 */ | ||
| 154 | uint8_t tilt; /* right = 1, left = -1 */ | ||
| 155 | uint8_t unknown; | ||
| 156 | uint8_t event; | ||
| 157 | uint8_t value; /* press = 0, release = 1 */ | ||
| 158 | uint8_t macro_key; /* 0 to 8 */ | ||
| 159 | }; | ||
| 160 | |||
| 161 | enum kone_mouse_events { | ||
| 162 | /* osd events are thought to be display on screen */ | ||
| 163 | kone_mouse_event_osd_dpi = 0xa0, | ||
| 164 | kone_mouse_event_osd_profile = 0xb0, | ||
| 165 | /* TODO clarify meaning and occurence of kone_mouse_event_calibration */ | ||
| 166 | kone_mouse_event_calibration = 0xc0, | ||
| 167 | kone_mouse_event_call_overlong_macro = 0xe0, | ||
| 168 | /* switch events notify if user changed values wiht mousebutton click */ | ||
| 169 | kone_mouse_event_switch_dpi = 0xf0, | ||
| 170 | kone_mouse_event_switch_profile = 0xf1 | ||
| 171 | }; | ||
| 172 | |||
| 173 | enum kone_commands { | ||
| 174 | kone_command_profile = 0x5a, | ||
| 175 | kone_command_settings = 0x15a, | ||
| 176 | kone_command_firmware_version = 0x25a, | ||
| 177 | kone_command_weight = 0x45a, | ||
| 178 | kone_command_calibrate = 0x55a, | ||
| 179 | kone_command_confirm_write = 0x65a, | ||
| 180 | kone_command_firmware = 0xe5a | ||
| 181 | }; | ||
| 182 | |||
| 183 | #pragma pack(pop) | ||
| 184 | |||
| 185 | struct kone_device { | ||
| 186 | /* | ||
| 187 | * Storing actual values when we get informed about changes since there | ||
| 188 | * is no way of getting this information from the device on demand | ||
| 189 | */ | ||
| 190 | int actual_profile, actual_dpi; | ||
| 191 | /* Used for neutralizing abnormal tilt button behaviour */ | ||
| 192 | int last_tilt_state; | ||
| 193 | /* | ||
| 194 | * It's unlikely that multiple sysfs attributes are accessed at a time, | ||
| 195 | * so only one mutex is used to secure hardware access and profiles and | ||
| 196 | * settings of this struct. | ||
| 197 | */ | ||
| 198 | struct mutex kone_lock; | ||
| 199 | |||
| 200 | /* | ||
| 201 | * Storing the data here reduces IO and ensures that data is available | ||
| 202 | * when its needed (E.g. interrupt handler). | ||
| 203 | */ | ||
| 204 | struct kone_profile profiles[5]; | ||
| 205 | struct kone_settings settings; | ||
| 206 | |||
| 207 | /* | ||
| 208 | * firmware doesn't change unless firmware update is implemented, | ||
| 209 | * so it's read only once | ||
| 210 | */ | ||
| 211 | int firmware_version; | ||
| 212 | }; | ||
| 213 | |||
| 214 | #endif | ||
