Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: corsair: Add Corsair Vengeance K90 driver

This patch implements a HID driver for the Corsair Vengeance K90 keyboard.

It fixes the behaviour of the keys using incorrect HID usage codes and exposes
the macro playback mode and current profile to the user space through sysfs
attributes. It also adds two LED class devices controlling the "record" LED and
the backlight.

Signed-off-by: Clément Vuchener <clement.vuchener@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Clément Vuchener and committed by
Jiri Kosina
6f78193e 851328fe

+703
+15
Documentation/ABI/testing/sysfs-driver-hid-corsair
··· 1 + What: /sys/bus/drivers/corsair/<dev>/macro_mode 2 + Date: August 2015 3 + KernelVersion: 4.2 4 + Contact: Clement Vuchener <clement.vuchener@gmail.com> 5 + Description: Get/set the current playback mode. "SW" for software mode 6 + where G-keys triggers their regular key codes. "HW" for 7 + hardware playback mode where the G-keys play their macro 8 + from the on-board memory. 9 + 10 + 11 + What: /sys/bus/drivers/corsair/<dev>/current_profile 12 + Date: August 2015 13 + KernelVersion: 4.2 14 + Contact: Clement Vuchener <clement.vuchener@gmail.com> 15 + Description: Get/set the current selected profile. Values are from 1 to 3.
+10
drivers/hid/Kconfig
··· 171 171 ---help--- 172 172 Support for Chicony Tactical pad. 173 173 174 + config HID_CORSAIR 175 + tristate "Corsair devices" 176 + depends on HID && USB && LEDS_CLASS 177 + ---help--- 178 + Support for Corsair devices that are not fully compliant with the 179 + HID standard. 180 + 181 + Supported devices: 182 + - Vengeance K90 183 + 174 184 config HID_PRODIKEYS 175 185 tristate "Prodikeys PC-MIDI Keyboard support" 176 186 depends on HID && SND
+1
drivers/hid/Makefile
··· 29 29 obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o 30 30 obj-$(CONFIG_HID_CHERRY) += hid-cherry.o 31 31 obj-$(CONFIG_HID_CHICONY) += hid-chicony.o 32 + obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o 32 33 obj-$(CONFIG_HID_CP2112) += hid-cp2112.o 33 34 obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o 34 35 obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
+1
drivers/hid/hid-core.c
··· 1828 1828 { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, 1829 1829 { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, 1830 1830 { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) }, 1831 + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) }, 1831 1832 { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, 1832 1833 { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) }, 1833 1834 { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
+673
drivers/hid/hid-corsair.c
··· 1 + /* 2 + * HID driver for Corsair devices 3 + * 4 + * Supported devices: 5 + * - Vengeance K90 Keyboard 6 + * 7 + * Copyright (c) 2015 Clement Vuchener 8 + */ 9 + 10 + /* 11 + * This program is free software; you can redistribute it and/or modify it 12 + * under the terms of the GNU General Public License as published by the Free 13 + * Software Foundation; either version 2 of the License, or (at your option) 14 + * any later version. 15 + */ 16 + 17 + #include <linux/hid.h> 18 + #include <linux/module.h> 19 + #include <linux/usb.h> 20 + #include <linux/leds.h> 21 + 22 + #include "hid-ids.h" 23 + 24 + #define CORSAIR_USE_K90_MACRO (1<<0) 25 + #define CORSAIR_USE_K90_BACKLIGHT (1<<1) 26 + 27 + struct k90_led { 28 + struct led_classdev cdev; 29 + int brightness; 30 + struct work_struct work; 31 + int removed; 32 + }; 33 + 34 + struct k90_drvdata { 35 + struct k90_led record_led; 36 + }; 37 + 38 + struct corsair_drvdata { 39 + unsigned long quirks; 40 + struct k90_drvdata *k90; 41 + struct k90_led *backlight; 42 + }; 43 + 44 + #define K90_GKEY_COUNT 18 45 + 46 + static int corsair_usage_to_gkey(unsigned int usage) 47 + { 48 + /* G1 (0xd0) to G16 (0xdf) */ 49 + if (usage >= 0xd0 && usage <= 0xdf) 50 + return usage - 0xd0 + 1; 51 + /* G17 (0xe8) to G18 (0xe9) */ 52 + if (usage >= 0xe8 && usage <= 0xe9) 53 + return usage - 0xe8 + 17; 54 + return 0; 55 + } 56 + 57 + static unsigned short corsair_gkey_map[K90_GKEY_COUNT] = { 58 + BTN_TRIGGER_HAPPY1, 59 + BTN_TRIGGER_HAPPY2, 60 + BTN_TRIGGER_HAPPY3, 61 + BTN_TRIGGER_HAPPY4, 62 + BTN_TRIGGER_HAPPY5, 63 + BTN_TRIGGER_HAPPY6, 64 + BTN_TRIGGER_HAPPY7, 65 + BTN_TRIGGER_HAPPY8, 66 + BTN_TRIGGER_HAPPY9, 67 + BTN_TRIGGER_HAPPY10, 68 + BTN_TRIGGER_HAPPY11, 69 + BTN_TRIGGER_HAPPY12, 70 + BTN_TRIGGER_HAPPY13, 71 + BTN_TRIGGER_HAPPY14, 72 + BTN_TRIGGER_HAPPY15, 73 + BTN_TRIGGER_HAPPY16, 74 + BTN_TRIGGER_HAPPY17, 75 + BTN_TRIGGER_HAPPY18, 76 + }; 77 + 78 + module_param_array_named(gkey_codes, corsair_gkey_map, ushort, NULL, S_IRUGO); 79 + MODULE_PARM_DESC(gkey_codes, "Key codes for the G-keys"); 80 + 81 + static unsigned short corsair_record_keycodes[2] = { 82 + BTN_TRIGGER_HAPPY19, 83 + BTN_TRIGGER_HAPPY20 84 + }; 85 + 86 + module_param_array_named(recordkey_codes, corsair_record_keycodes, ushort, 87 + NULL, S_IRUGO); 88 + MODULE_PARM_DESC(recordkey_codes, "Key codes for the MR (start and stop record) button"); 89 + 90 + static unsigned short corsair_profile_keycodes[3] = { 91 + BTN_TRIGGER_HAPPY21, 92 + BTN_TRIGGER_HAPPY22, 93 + BTN_TRIGGER_HAPPY23 94 + }; 95 + 96 + module_param_array_named(profilekey_codes, corsair_profile_keycodes, ushort, 97 + NULL, S_IRUGO); 98 + MODULE_PARM_DESC(profilekey_codes, "Key codes for the profile buttons"); 99 + 100 + #define CORSAIR_USAGE_SPECIAL_MIN 0xf0 101 + #define CORSAIR_USAGE_SPECIAL_MAX 0xff 102 + 103 + #define CORSAIR_USAGE_MACRO_RECORD_START 0xf6 104 + #define CORSAIR_USAGE_MACRO_RECORD_STOP 0xf7 105 + 106 + #define CORSAIR_USAGE_PROFILE 0xf1 107 + #define CORSAIR_USAGE_M1 0xf1 108 + #define CORSAIR_USAGE_M2 0xf2 109 + #define CORSAIR_USAGE_M3 0xf3 110 + #define CORSAIR_USAGE_PROFILE_MAX 0xf3 111 + 112 + #define CORSAIR_USAGE_META_OFF 0xf4 113 + #define CORSAIR_USAGE_META_ON 0xf5 114 + 115 + #define CORSAIR_USAGE_LIGHT 0xfa 116 + #define CORSAIR_USAGE_LIGHT_OFF 0xfa 117 + #define CORSAIR_USAGE_LIGHT_DIM 0xfb 118 + #define CORSAIR_USAGE_LIGHT_MEDIUM 0xfc 119 + #define CORSAIR_USAGE_LIGHT_BRIGHT 0xfd 120 + #define CORSAIR_USAGE_LIGHT_MAX 0xfd 121 + 122 + /* USB control protocol */ 123 + 124 + #define K90_REQUEST_BRIGHTNESS 49 125 + #define K90_REQUEST_MACRO_MODE 2 126 + #define K90_REQUEST_STATUS 4 127 + #define K90_REQUEST_GET_MODE 5 128 + #define K90_REQUEST_PROFILE 20 129 + 130 + #define K90_MACRO_MODE_SW 0x0030 131 + #define K90_MACRO_MODE_HW 0x0001 132 + 133 + #define K90_MACRO_LED_ON 0x0020 134 + #define K90_MACRO_LED_OFF 0x0040 135 + 136 + /* 137 + * LED class devices 138 + */ 139 + 140 + #define K90_BACKLIGHT_LED_SUFFIX "::backlight" 141 + #define K90_RECORD_LED_SUFFIX "::record" 142 + 143 + static enum led_brightness k90_backlight_get(struct led_classdev *led_cdev) 144 + { 145 + int ret; 146 + struct k90_led *led = container_of(led_cdev, struct k90_led, cdev); 147 + struct device *dev = led->cdev.dev->parent; 148 + struct usb_interface *usbif = to_usb_interface(dev->parent); 149 + struct usb_device *usbdev = interface_to_usbdev(usbif); 150 + int brightness; 151 + char data[8]; 152 + 153 + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 154 + K90_REQUEST_STATUS, 155 + USB_DIR_IN | USB_TYPE_VENDOR | 156 + USB_RECIP_DEVICE, 0, 0, data, 8, 157 + USB_CTRL_SET_TIMEOUT); 158 + if (ret < 0) { 159 + dev_warn(dev, "Failed to get K90 initial state (error %d).\n", 160 + ret); 161 + return -EIO; 162 + } 163 + brightness = data[4]; 164 + if (brightness < 0 || brightness > 3) { 165 + dev_warn(dev, 166 + "Read invalid backlight brightness: %02hhx.\n", 167 + data[4]); 168 + return -EIO; 169 + } 170 + return brightness; 171 + } 172 + 173 + static enum led_brightness k90_record_led_get(struct led_classdev *led_cdev) 174 + { 175 + struct k90_led *led = container_of(led_cdev, struct k90_led, cdev); 176 + 177 + return led->brightness; 178 + } 179 + 180 + static void k90_brightness_set(struct led_classdev *led_cdev, 181 + enum led_brightness brightness) 182 + { 183 + struct k90_led *led = container_of(led_cdev, struct k90_led, cdev); 184 + 185 + led->brightness = brightness; 186 + schedule_work(&led->work); 187 + } 188 + 189 + static void k90_backlight_work(struct work_struct *work) 190 + { 191 + int ret; 192 + struct k90_led *led = container_of(work, struct k90_led, work); 193 + struct device *dev; 194 + struct usb_interface *usbif; 195 + struct usb_device *usbdev; 196 + 197 + if (led->removed) 198 + return; 199 + 200 + dev = led->cdev.dev->parent; 201 + usbif = to_usb_interface(dev->parent); 202 + usbdev = interface_to_usbdev(usbif); 203 + 204 + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 205 + K90_REQUEST_BRIGHTNESS, 206 + USB_DIR_OUT | USB_TYPE_VENDOR | 207 + USB_RECIP_DEVICE, led->brightness, 0, 208 + NULL, 0, USB_CTRL_SET_TIMEOUT); 209 + if (ret != 0) 210 + dev_warn(dev, "Failed to set backlight brightness (error: %d).\n", 211 + ret); 212 + } 213 + 214 + static void k90_record_led_work(struct work_struct *work) 215 + { 216 + int ret; 217 + struct k90_led *led = container_of(work, struct k90_led, work); 218 + struct device *dev; 219 + struct usb_interface *usbif; 220 + struct usb_device *usbdev; 221 + int value; 222 + 223 + if (led->removed) 224 + return; 225 + 226 + dev = led->cdev.dev->parent; 227 + usbif = to_usb_interface(dev->parent); 228 + usbdev = interface_to_usbdev(usbif); 229 + 230 + if (led->brightness > 0) 231 + value = K90_MACRO_LED_ON; 232 + else 233 + value = K90_MACRO_LED_OFF; 234 + 235 + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 236 + K90_REQUEST_MACRO_MODE, 237 + USB_DIR_OUT | USB_TYPE_VENDOR | 238 + USB_RECIP_DEVICE, value, 0, NULL, 0, 239 + USB_CTRL_SET_TIMEOUT); 240 + if (ret != 0) 241 + dev_warn(dev, "Failed to set record LED state (error: %d).\n", 242 + ret); 243 + } 244 + 245 + /* 246 + * Keyboard attributes 247 + */ 248 + 249 + static ssize_t k90_show_macro_mode(struct device *dev, 250 + struct device_attribute *attr, char *buf) 251 + { 252 + int ret; 253 + struct usb_interface *usbif = to_usb_interface(dev->parent); 254 + struct usb_device *usbdev = interface_to_usbdev(usbif); 255 + const char *macro_mode; 256 + char data[8]; 257 + 258 + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 259 + K90_REQUEST_GET_MODE, 260 + USB_DIR_IN | USB_TYPE_VENDOR | 261 + USB_RECIP_DEVICE, 0, 0, data, 2, 262 + USB_CTRL_SET_TIMEOUT); 263 + if (ret < 0) { 264 + dev_warn(dev, "Failed to get K90 initial mode (error %d).\n", 265 + ret); 266 + return -EIO; 267 + } 268 + 269 + switch (data[0]) { 270 + case K90_MACRO_MODE_HW: 271 + macro_mode = "HW"; 272 + break; 273 + 274 + case K90_MACRO_MODE_SW: 275 + macro_mode = "SW"; 276 + break; 277 + default: 278 + dev_warn(dev, "K90 in unknown mode: %02hhx.\n", 279 + data[0]); 280 + return -EIO; 281 + } 282 + 283 + return snprintf(buf, PAGE_SIZE, "%s\n", macro_mode); 284 + } 285 + 286 + static ssize_t k90_store_macro_mode(struct device *dev, 287 + struct device_attribute *attr, 288 + const char *buf, size_t count) 289 + { 290 + int ret; 291 + struct usb_interface *usbif = to_usb_interface(dev->parent); 292 + struct usb_device *usbdev = interface_to_usbdev(usbif); 293 + __u16 value; 294 + 295 + if (strncmp(buf, "SW", 2) == 0) 296 + value = K90_MACRO_MODE_SW; 297 + else if (strncmp(buf, "HW", 2) == 0) 298 + value = K90_MACRO_MODE_HW; 299 + else 300 + return -EINVAL; 301 + 302 + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 303 + K90_REQUEST_MACRO_MODE, 304 + USB_DIR_OUT | USB_TYPE_VENDOR | 305 + USB_RECIP_DEVICE, value, 0, NULL, 0, 306 + USB_CTRL_SET_TIMEOUT); 307 + if (ret != 0) { 308 + dev_warn(dev, "Failed to set macro mode.\n"); 309 + return ret; 310 + } 311 + 312 + return count; 313 + } 314 + 315 + static ssize_t k90_show_current_profile(struct device *dev, 316 + struct device_attribute *attr, 317 + char *buf) 318 + { 319 + int ret; 320 + struct usb_interface *usbif = to_usb_interface(dev->parent); 321 + struct usb_device *usbdev = interface_to_usbdev(usbif); 322 + int current_profile; 323 + char data[8]; 324 + 325 + ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 326 + K90_REQUEST_STATUS, 327 + USB_DIR_IN | USB_TYPE_VENDOR | 328 + USB_RECIP_DEVICE, 0, 0, data, 8, 329 + USB_CTRL_SET_TIMEOUT); 330 + if (ret < 0) { 331 + dev_warn(dev, "Failed to get K90 initial state (error %d).\n", 332 + ret); 333 + return -EIO; 334 + } 335 + current_profile = data[7]; 336 + if (current_profile < 1 || current_profile > 3) { 337 + dev_warn(dev, "Read invalid current profile: %02hhx.\n", 338 + data[7]); 339 + return -EIO; 340 + } 341 + 342 + return snprintf(buf, PAGE_SIZE, "%d\n", current_profile); 343 + } 344 + 345 + static ssize_t k90_store_current_profile(struct device *dev, 346 + struct device_attribute *attr, 347 + const char *buf, size_t count) 348 + { 349 + int ret; 350 + struct usb_interface *usbif = to_usb_interface(dev->parent); 351 + struct usb_device *usbdev = interface_to_usbdev(usbif); 352 + int profile; 353 + 354 + if (kstrtoint(buf, 10, &profile)) 355 + return -EINVAL; 356 + if (profile < 1 || profile > 3) 357 + return -EINVAL; 358 + 359 + ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 360 + K90_REQUEST_PROFILE, 361 + USB_DIR_OUT | USB_TYPE_VENDOR | 362 + USB_RECIP_DEVICE, profile, 0, NULL, 0, 363 + USB_CTRL_SET_TIMEOUT); 364 + if (ret != 0) { 365 + dev_warn(dev, "Failed to change current profile (error %d).\n", 366 + ret); 367 + return ret; 368 + } 369 + 370 + return count; 371 + } 372 + 373 + static DEVICE_ATTR(macro_mode, 0644, k90_show_macro_mode, k90_store_macro_mode); 374 + static DEVICE_ATTR(current_profile, 0644, k90_show_current_profile, 375 + k90_store_current_profile); 376 + 377 + static struct attribute *k90_attrs[] = { 378 + &dev_attr_macro_mode.attr, 379 + &dev_attr_current_profile.attr, 380 + NULL 381 + }; 382 + 383 + static const struct attribute_group k90_attr_group = { 384 + .attrs = k90_attrs, 385 + }; 386 + 387 + /* 388 + * Driver functions 389 + */ 390 + 391 + static int k90_init_backlight(struct hid_device *dev) 392 + { 393 + int ret; 394 + struct corsair_drvdata *drvdata = hid_get_drvdata(dev); 395 + size_t name_sz; 396 + char *name; 397 + 398 + drvdata->backlight = kzalloc(sizeof(struct k90_led), GFP_KERNEL); 399 + if (!drvdata->backlight) { 400 + ret = -ENOMEM; 401 + goto fail_backlight_alloc; 402 + } 403 + 404 + name_sz = 405 + strlen(dev_name(&dev->dev)) + sizeof(K90_BACKLIGHT_LED_SUFFIX); 406 + name = kzalloc(name_sz, GFP_KERNEL); 407 + if (!name) { 408 + ret = -ENOMEM; 409 + goto fail_name_alloc; 410 + } 411 + snprintf(name, name_sz, "%s" K90_BACKLIGHT_LED_SUFFIX, 412 + dev_name(&dev->dev)); 413 + drvdata->backlight->removed = 0; 414 + drvdata->backlight->cdev.name = name; 415 + drvdata->backlight->cdev.max_brightness = 3; 416 + drvdata->backlight->cdev.brightness_set = k90_brightness_set; 417 + drvdata->backlight->cdev.brightness_get = k90_backlight_get; 418 + INIT_WORK(&drvdata->backlight->work, k90_backlight_work); 419 + ret = led_classdev_register(&dev->dev, &drvdata->backlight->cdev); 420 + if (ret != 0) 421 + goto fail_register_cdev; 422 + 423 + return 0; 424 + 425 + fail_register_cdev: 426 + kfree(drvdata->backlight->cdev.name); 427 + fail_name_alloc: 428 + kfree(drvdata->backlight); 429 + drvdata->backlight = NULL; 430 + fail_backlight_alloc: 431 + return ret; 432 + } 433 + 434 + static int k90_init_macro_functions(struct hid_device *dev) 435 + { 436 + int ret; 437 + struct corsair_drvdata *drvdata = hid_get_drvdata(dev); 438 + struct k90_drvdata *k90; 439 + size_t name_sz; 440 + char *name; 441 + 442 + k90 = kzalloc(sizeof(struct k90_drvdata), GFP_KERNEL); 443 + if (!k90) { 444 + ret = -ENOMEM; 445 + goto fail_drvdata; 446 + } 447 + drvdata->k90 = k90; 448 + 449 + /* Init LED device for record LED */ 450 + name_sz = strlen(dev_name(&dev->dev)) + sizeof(K90_RECORD_LED_SUFFIX); 451 + name = kzalloc(name_sz, GFP_KERNEL); 452 + if (!name) { 453 + ret = -ENOMEM; 454 + goto fail_record_led_alloc; 455 + } 456 + snprintf(name, name_sz, "%s" K90_RECORD_LED_SUFFIX, 457 + dev_name(&dev->dev)); 458 + k90->record_led.removed = 0; 459 + k90->record_led.cdev.name = name; 460 + k90->record_led.cdev.max_brightness = 1; 461 + k90->record_led.cdev.brightness_set = k90_brightness_set; 462 + k90->record_led.cdev.brightness_get = k90_record_led_get; 463 + INIT_WORK(&k90->record_led.work, k90_record_led_work); 464 + k90->record_led.brightness = 0; 465 + ret = led_classdev_register(&dev->dev, &k90->record_led.cdev); 466 + if (ret != 0) 467 + goto fail_record_led; 468 + 469 + /* Init attributes */ 470 + ret = sysfs_create_group(&dev->dev.kobj, &k90_attr_group); 471 + if (ret != 0) 472 + goto fail_sysfs; 473 + 474 + return 0; 475 + 476 + fail_sysfs: 477 + k90->record_led.removed = 1; 478 + led_classdev_unregister(&k90->record_led.cdev); 479 + cancel_work_sync(&k90->record_led.work); 480 + fail_record_led: 481 + kfree(k90->record_led.cdev.name); 482 + fail_record_led_alloc: 483 + kfree(k90); 484 + fail_drvdata: 485 + drvdata->k90 = NULL; 486 + return ret; 487 + } 488 + 489 + static void k90_cleanup_backlight(struct hid_device *dev) 490 + { 491 + struct corsair_drvdata *drvdata = hid_get_drvdata(dev); 492 + 493 + if (drvdata->backlight) { 494 + drvdata->backlight->removed = 1; 495 + led_classdev_unregister(&drvdata->backlight->cdev); 496 + cancel_work_sync(&drvdata->backlight->work); 497 + kfree(drvdata->backlight->cdev.name); 498 + kfree(drvdata->backlight); 499 + } 500 + } 501 + 502 + static void k90_cleanup_macro_functions(struct hid_device *dev) 503 + { 504 + struct corsair_drvdata *drvdata = hid_get_drvdata(dev); 505 + struct k90_drvdata *k90 = drvdata->k90; 506 + 507 + if (k90) { 508 + sysfs_remove_group(&dev->dev.kobj, &k90_attr_group); 509 + 510 + k90->record_led.removed = 1; 511 + led_classdev_unregister(&k90->record_led.cdev); 512 + cancel_work_sync(&k90->record_led.work); 513 + kfree(k90->record_led.cdev.name); 514 + 515 + kfree(k90); 516 + } 517 + } 518 + 519 + static int corsair_probe(struct hid_device *dev, const struct hid_device_id *id) 520 + { 521 + int ret; 522 + unsigned long quirks = id->driver_data; 523 + struct corsair_drvdata *drvdata; 524 + struct usb_interface *usbif = to_usb_interface(dev->dev.parent); 525 + 526 + drvdata = devm_kzalloc(&dev->dev, sizeof(struct corsair_drvdata), 527 + GFP_KERNEL); 528 + if (drvdata == NULL) 529 + return -ENOMEM; 530 + drvdata->quirks = quirks; 531 + hid_set_drvdata(dev, drvdata); 532 + 533 + ret = hid_parse(dev); 534 + if (ret != 0) { 535 + hid_err(dev, "parse failed\n"); 536 + return ret; 537 + } 538 + ret = hid_hw_start(dev, HID_CONNECT_DEFAULT); 539 + if (ret != 0) { 540 + hid_err(dev, "hw start failed\n"); 541 + return ret; 542 + } 543 + 544 + if (usbif->cur_altsetting->desc.bInterfaceNumber == 0) { 545 + if (quirks & CORSAIR_USE_K90_MACRO) { 546 + ret = k90_init_macro_functions(dev); 547 + if (ret != 0) 548 + hid_warn(dev, "Failed to initialize K90 macro functions.\n"); 549 + } 550 + if (quirks & CORSAIR_USE_K90_BACKLIGHT) { 551 + ret = k90_init_backlight(dev); 552 + if (ret != 0) 553 + hid_warn(dev, "Failed to initialize K90 backlight.\n"); 554 + } 555 + } 556 + 557 + return 0; 558 + } 559 + 560 + static void corsair_remove(struct hid_device *dev) 561 + { 562 + k90_cleanup_macro_functions(dev); 563 + k90_cleanup_backlight(dev); 564 + 565 + hid_hw_stop(dev); 566 + } 567 + 568 + static int corsair_event(struct hid_device *dev, struct hid_field *field, 569 + struct hid_usage *usage, __s32 value) 570 + { 571 + struct corsair_drvdata *drvdata = hid_get_drvdata(dev); 572 + 573 + if (!drvdata->k90) 574 + return 0; 575 + 576 + switch (usage->hid & HID_USAGE) { 577 + case CORSAIR_USAGE_MACRO_RECORD_START: 578 + drvdata->k90->record_led.brightness = 1; 579 + break; 580 + case CORSAIR_USAGE_MACRO_RECORD_STOP: 581 + drvdata->k90->record_led.brightness = 0; 582 + break; 583 + default: 584 + break; 585 + } 586 + 587 + return 0; 588 + } 589 + 590 + static int corsair_input_mapping(struct hid_device *dev, 591 + struct hid_input *input, 592 + struct hid_field *field, 593 + struct hid_usage *usage, unsigned long **bit, 594 + int *max) 595 + { 596 + int gkey; 597 + 598 + gkey = corsair_usage_to_gkey(usage->hid & HID_USAGE); 599 + if (gkey != 0) { 600 + hid_map_usage_clear(input, usage, bit, max, EV_KEY, 601 + corsair_gkey_map[gkey - 1]); 602 + return 1; 603 + } 604 + if ((usage->hid & HID_USAGE) >= CORSAIR_USAGE_SPECIAL_MIN && 605 + (usage->hid & HID_USAGE) <= CORSAIR_USAGE_SPECIAL_MAX) { 606 + switch (usage->hid & HID_USAGE) { 607 + case CORSAIR_USAGE_MACRO_RECORD_START: 608 + hid_map_usage_clear(input, usage, bit, max, EV_KEY, 609 + corsair_record_keycodes[0]); 610 + return 1; 611 + 612 + case CORSAIR_USAGE_MACRO_RECORD_STOP: 613 + hid_map_usage_clear(input, usage, bit, max, EV_KEY, 614 + corsair_record_keycodes[1]); 615 + return 1; 616 + 617 + case CORSAIR_USAGE_M1: 618 + hid_map_usage_clear(input, usage, bit, max, EV_KEY, 619 + corsair_profile_keycodes[0]); 620 + return 1; 621 + 622 + case CORSAIR_USAGE_M2: 623 + hid_map_usage_clear(input, usage, bit, max, EV_KEY, 624 + corsair_profile_keycodes[1]); 625 + return 1; 626 + 627 + case CORSAIR_USAGE_M3: 628 + hid_map_usage_clear(input, usage, bit, max, EV_KEY, 629 + corsair_profile_keycodes[2]); 630 + return 1; 631 + 632 + default: 633 + return -1; 634 + } 635 + } 636 + 637 + return 0; 638 + } 639 + 640 + static const struct hid_device_id corsair_devices[] = { 641 + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90), 642 + .driver_data = CORSAIR_USE_K90_MACRO | 643 + CORSAIR_USE_K90_BACKLIGHT }, 644 + {} 645 + }; 646 + 647 + MODULE_DEVICE_TABLE(hid, corsair_devices); 648 + 649 + static struct hid_driver corsair_driver = { 650 + .name = "corsair", 651 + .id_table = corsair_devices, 652 + .probe = corsair_probe, 653 + .event = corsair_event, 654 + .remove = corsair_remove, 655 + .input_mapping = corsair_input_mapping, 656 + }; 657 + 658 + static int __init corsair_init(void) 659 + { 660 + return hid_register_driver(&corsair_driver); 661 + } 662 + 663 + static void corsair_exit(void) 664 + { 665 + hid_unregister_driver(&corsair_driver); 666 + } 667 + 668 + module_init(corsair_init); 669 + module_exit(corsair_exit); 670 + 671 + MODULE_LICENSE("GPL"); 672 + MODULE_AUTHOR("Clement Vuchener"); 673 + MODULE_DESCRIPTION("HID driver for Corsair devices");
+3
drivers/hid/hid-ids.h
··· 251 251 #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 252 252 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff 253 253 254 + #define USB_VENDOR_ID_CORSAIR 0x1b1c 255 + #define USB_DEVICE_ID_CORSAIR_K90 0x1b02 256 + 254 257 #define USB_VENDOR_ID_CREATIVELABS 0x041e 255 258 #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801 256 259