1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Roccat Isku driver for Linux 4 * 5 * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net> 6 */ 7 8/* 9 */ 10 11/* 12 * Roccat Isku is a gamer keyboard with macro keys that can be configured in 13 * 5 profiles. 14 */ 15 16#include <linux/device.h> 17#include <linux/input.h> 18#include <linux/hid.h> 19#include <linux/module.h> 20#include <linux/slab.h> 21#include <linux/hid-roccat.h> 22#include "hid-ids.h" 23#include "hid-roccat-common.h" 24#include "hid-roccat-isku.h" 25 26static void isku_profile_activated(struct isku_device *isku, uint new_profile) 27{ 28 isku->actual_profile = new_profile; 29} 30 31static int isku_receive(struct usb_device *usb_dev, uint command, 32 void *buf, uint size) 33{ 34 return roccat_common2_receive(usb_dev, command, buf, size); 35} 36 37static int isku_get_actual_profile(struct usb_device *usb_dev) 38{ 39 struct isku_actual_profile buf; 40 int retval; 41 42 retval = isku_receive(usb_dev, ISKU_COMMAND_ACTUAL_PROFILE, 43 &buf, sizeof(struct isku_actual_profile)); 44 return retval ? retval : buf.actual_profile; 45} 46 47static int isku_set_actual_profile(struct usb_device *usb_dev, int new_profile) 48{ 49 struct isku_actual_profile buf; 50 51 buf.command = ISKU_COMMAND_ACTUAL_PROFILE; 52 buf.size = sizeof(struct isku_actual_profile); 53 buf.actual_profile = new_profile; 54 return roccat_common2_send_with_status(usb_dev, 55 ISKU_COMMAND_ACTUAL_PROFILE, &buf, 56 sizeof(struct isku_actual_profile)); 57} 58 59static ssize_t isku_sysfs_show_actual_profile(struct device *dev, 60 struct device_attribute *attr, char *buf) 61{ 62 struct isku_device *isku = 63 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 64 return snprintf(buf, PAGE_SIZE, "%d\n", isku->actual_profile); 65} 66 67static ssize_t isku_sysfs_set_actual_profile(struct device *dev, 68 struct device_attribute *attr, char const *buf, size_t size) 69{ 70 struct isku_device *isku; 71 struct usb_device *usb_dev; 72 unsigned long profile; 73 int retval; 74 struct isku_roccat_report roccat_report; 75 76 dev = dev->parent->parent; 77 isku = hid_get_drvdata(dev_get_drvdata(dev)); 78 usb_dev = interface_to_usbdev(to_usb_interface(dev)); 79 80 retval = kstrtoul(buf, 10, &profile); 81 if (retval) 82 return retval; 83 84 if (profile > 4) 85 return -EINVAL; 86 87 mutex_lock(&isku->isku_lock); 88 89 retval = isku_set_actual_profile(usb_dev, profile); 90 if (retval) { 91 mutex_unlock(&isku->isku_lock); 92 return retval; 93 } 94 95 isku_profile_activated(isku, profile); 96 97 roccat_report.event = ISKU_REPORT_BUTTON_EVENT_PROFILE; 98 roccat_report.data1 = profile + 1; 99 roccat_report.data2 = 0; 100 roccat_report.profile = profile + 1; 101 roccat_report_event(isku->chrdev_minor, (uint8_t const *)&roccat_report); 102 103 mutex_unlock(&isku->isku_lock); 104 105 return size; 106} 107static DEVICE_ATTR(actual_profile, 0660, isku_sysfs_show_actual_profile, 108 isku_sysfs_set_actual_profile); 109 110static struct attribute *isku_attrs[] = { 111 &dev_attr_actual_profile.attr, 112 NULL, 113}; 114 115static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj, 116 char *buf, loff_t off, size_t count, 117 size_t real_size, uint command) 118{ 119 struct device *dev = kobj_to_dev(kobj)->parent->parent; 120 struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev)); 121 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 122 int retval; 123 124 if (off >= real_size) 125 return 0; 126 127 if (off != 0 || count > real_size) 128 return -EINVAL; 129 130 mutex_lock(&isku->isku_lock); 131 retval = isku_receive(usb_dev, command, buf, count); 132 mutex_unlock(&isku->isku_lock); 133 134 return retval ? retval : count; 135} 136 137static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj, 138 void const *buf, loff_t off, size_t count, 139 size_t real_size, uint command) 140{ 141 struct device *dev = kobj_to_dev(kobj)->parent->parent; 142 struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev)); 143 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 144 int retval; 145 146 if (off != 0 || count > real_size) 147 return -EINVAL; 148 149 mutex_lock(&isku->isku_lock); 150 retval = roccat_common2_send_with_status(usb_dev, command, 151 (void *)buf, count); 152 mutex_unlock(&isku->isku_lock); 153 154 return retval ? retval : count; 155} 156 157#define ISKU_SYSFS_W(thingy, THINGY) \ 158static ssize_t isku_sysfs_write_ ## thingy(struct file *fp, struct kobject *kobj, \ 159 struct bin_attribute *attr, char *buf, \ 160 loff_t off, size_t count) \ 161{ \ 162 return isku_sysfs_write(fp, kobj, buf, off, count, \ 163 ISKU_SIZE_ ## THINGY, ISKU_COMMAND_ ## THINGY); \ 164} 165 166#define ISKU_SYSFS_R(thingy, THINGY) \ 167static ssize_t isku_sysfs_read_ ## thingy(struct file *fp, struct kobject *kobj, \ 168 struct bin_attribute *attr, char *buf, \ 169 loff_t off, size_t count) \ 170{ \ 171 return isku_sysfs_read(fp, kobj, buf, off, count, \ 172 ISKU_SIZE_ ## THINGY, ISKU_COMMAND_ ## THINGY); \ 173} 174 175#define ISKU_SYSFS_RW(thingy, THINGY) \ 176ISKU_SYSFS_R(thingy, THINGY) \ 177ISKU_SYSFS_W(thingy, THINGY) 178 179#define ISKU_BIN_ATTR_RW(thingy, THINGY) \ 180ISKU_SYSFS_RW(thingy, THINGY); \ 181static struct bin_attribute bin_attr_##thingy = { \ 182 .attr = { .name = #thingy, .mode = 0660 }, \ 183 .size = ISKU_SIZE_ ## THINGY, \ 184 .read = isku_sysfs_read_ ## thingy, \ 185 .write = isku_sysfs_write_ ## thingy \ 186} 187 188#define ISKU_BIN_ATTR_R(thingy, THINGY) \ 189ISKU_SYSFS_R(thingy, THINGY); \ 190static struct bin_attribute bin_attr_##thingy = { \ 191 .attr = { .name = #thingy, .mode = 0440 }, \ 192 .size = ISKU_SIZE_ ## THINGY, \ 193 .read = isku_sysfs_read_ ## thingy, \ 194} 195 196#define ISKU_BIN_ATTR_W(thingy, THINGY) \ 197ISKU_SYSFS_W(thingy, THINGY); \ 198static struct bin_attribute bin_attr_##thingy = { \ 199 .attr = { .name = #thingy, .mode = 0220 }, \ 200 .size = ISKU_SIZE_ ## THINGY, \ 201 .write = isku_sysfs_write_ ## thingy \ 202} 203 204ISKU_BIN_ATTR_RW(macro, MACRO); 205ISKU_BIN_ATTR_RW(keys_function, KEYS_FUNCTION); 206ISKU_BIN_ATTR_RW(keys_easyzone, KEYS_EASYZONE); 207ISKU_BIN_ATTR_RW(keys_media, KEYS_MEDIA); 208ISKU_BIN_ATTR_RW(keys_thumbster, KEYS_THUMBSTER); 209ISKU_BIN_ATTR_RW(keys_macro, KEYS_MACRO); 210ISKU_BIN_ATTR_RW(keys_capslock, KEYS_CAPSLOCK); 211ISKU_BIN_ATTR_RW(light, LIGHT); 212ISKU_BIN_ATTR_RW(key_mask, KEY_MASK); 213ISKU_BIN_ATTR_RW(last_set, LAST_SET); 214ISKU_BIN_ATTR_W(talk, TALK); 215ISKU_BIN_ATTR_W(talkfx, TALKFX); 216ISKU_BIN_ATTR_W(control, CONTROL); 217ISKU_BIN_ATTR_W(reset, RESET); 218ISKU_BIN_ATTR_R(info, INFO); 219 220static struct bin_attribute *isku_bin_attributes[] = { 221 &bin_attr_macro, 222 &bin_attr_keys_function, 223 &bin_attr_keys_easyzone, 224 &bin_attr_keys_media, 225 &bin_attr_keys_thumbster, 226 &bin_attr_keys_macro, 227 &bin_attr_keys_capslock, 228 &bin_attr_light, 229 &bin_attr_key_mask, 230 &bin_attr_last_set, 231 &bin_attr_talk, 232 &bin_attr_talkfx, 233 &bin_attr_control, 234 &bin_attr_reset, 235 &bin_attr_info, 236 NULL, 237}; 238 239static const struct attribute_group isku_group = { 240 .attrs = isku_attrs, 241 .bin_attrs = isku_bin_attributes, 242}; 243 244static const struct attribute_group *isku_groups[] = { 245 &isku_group, 246 NULL, 247}; 248 249static const struct class isku_class = { 250 .name = "isku", 251 .dev_groups = isku_groups, 252}; 253 254static int isku_init_isku_device_struct(struct usb_device *usb_dev, 255 struct isku_device *isku) 256{ 257 int retval; 258 259 mutex_init(&isku->isku_lock); 260 261 retval = isku_get_actual_profile(usb_dev); 262 if (retval < 0) 263 return retval; 264 isku_profile_activated(isku, retval); 265 266 return 0; 267} 268 269static int isku_init_specials(struct hid_device *hdev) 270{ 271 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 272 struct usb_device *usb_dev = interface_to_usbdev(intf); 273 struct isku_device *isku; 274 int retval; 275 276 if (intf->cur_altsetting->desc.bInterfaceProtocol 277 != ISKU_USB_INTERFACE_PROTOCOL) { 278 hid_set_drvdata(hdev, NULL); 279 return 0; 280 } 281 282 isku = kzalloc(sizeof(*isku), GFP_KERNEL); 283 if (!isku) { 284 hid_err(hdev, "can't alloc device descriptor\n"); 285 return -ENOMEM; 286 } 287 hid_set_drvdata(hdev, isku); 288 289 retval = isku_init_isku_device_struct(usb_dev, isku); 290 if (retval) { 291 hid_err(hdev, "couldn't init struct isku_device\n"); 292 goto exit_free; 293 } 294 295 retval = roccat_connect(&isku_class, hdev, 296 sizeof(struct isku_roccat_report)); 297 if (retval < 0) { 298 hid_err(hdev, "couldn't init char dev\n"); 299 } else { 300 isku->chrdev_minor = retval; 301 isku->roccat_claimed = 1; 302 } 303 304 return 0; 305exit_free: 306 kfree(isku); 307 return retval; 308} 309 310static void isku_remove_specials(struct hid_device *hdev) 311{ 312 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 313 struct isku_device *isku; 314 315 if (intf->cur_altsetting->desc.bInterfaceProtocol 316 != ISKU_USB_INTERFACE_PROTOCOL) 317 return; 318 319 isku = hid_get_drvdata(hdev); 320 if (isku->roccat_claimed) 321 roccat_disconnect(isku->chrdev_minor); 322 kfree(isku); 323} 324 325static int isku_probe(struct hid_device *hdev, 326 const struct hid_device_id *id) 327{ 328 int retval; 329 330 if (!hid_is_usb(hdev)) 331 return -EINVAL; 332 333 retval = hid_parse(hdev); 334 if (retval) { 335 hid_err(hdev, "parse failed\n"); 336 goto exit; 337 } 338 339 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 340 if (retval) { 341 hid_err(hdev, "hw start failed\n"); 342 goto exit; 343 } 344 345 retval = isku_init_specials(hdev); 346 if (retval) { 347 hid_err(hdev, "couldn't install keyboard\n"); 348 goto exit_stop; 349 } 350 351 return 0; 352 353exit_stop: 354 hid_hw_stop(hdev); 355exit: 356 return retval; 357} 358 359static void isku_remove(struct hid_device *hdev) 360{ 361 isku_remove_specials(hdev); 362 hid_hw_stop(hdev); 363} 364 365static void isku_keep_values_up_to_date(struct isku_device *isku, 366 u8 const *data) 367{ 368 struct isku_report_button const *button_report; 369 370 switch (data[0]) { 371 case ISKU_REPORT_NUMBER_BUTTON: 372 button_report = (struct isku_report_button const *)data; 373 switch (button_report->event) { 374 case ISKU_REPORT_BUTTON_EVENT_PROFILE: 375 isku_profile_activated(isku, button_report->data1 - 1); 376 break; 377 } 378 break; 379 } 380} 381 382static void isku_report_to_chrdev(struct isku_device const *isku, 383 u8 const *data) 384{ 385 struct isku_roccat_report roccat_report; 386 struct isku_report_button const *button_report; 387 388 if (data[0] != ISKU_REPORT_NUMBER_BUTTON) 389 return; 390 391 button_report = (struct isku_report_button const *)data; 392 393 roccat_report.event = button_report->event; 394 roccat_report.data1 = button_report->data1; 395 roccat_report.data2 = button_report->data2; 396 roccat_report.profile = isku->actual_profile + 1; 397 roccat_report_event(isku->chrdev_minor, 398 (uint8_t const *)&roccat_report); 399} 400 401static int isku_raw_event(struct hid_device *hdev, 402 struct hid_report *report, u8 *data, int size) 403{ 404 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 405 struct isku_device *isku = hid_get_drvdata(hdev); 406 407 if (intf->cur_altsetting->desc.bInterfaceProtocol 408 != ISKU_USB_INTERFACE_PROTOCOL) 409 return 0; 410 411 if (isku == NULL) 412 return 0; 413 414 isku_keep_values_up_to_date(isku, data); 415 416 if (isku->roccat_claimed) 417 isku_report_to_chrdev(isku, data); 418 419 return 0; 420} 421 422static const struct hid_device_id isku_devices[] = { 423 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, 424 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKUFX) }, 425 { } 426}; 427 428MODULE_DEVICE_TABLE(hid, isku_devices); 429 430static struct hid_driver isku_driver = { 431 .name = "isku", 432 .id_table = isku_devices, 433 .probe = isku_probe, 434 .remove = isku_remove, 435 .raw_event = isku_raw_event 436}; 437 438static int __init isku_init(void) 439{ 440 int retval; 441 442 retval = class_register(&isku_class); 443 if (retval) 444 return retval; 445 446 retval = hid_register_driver(&isku_driver); 447 if (retval) 448 class_unregister(&isku_class); 449 return retval; 450} 451 452static void __exit isku_exit(void) 453{ 454 hid_unregister_driver(&isku_driver); 455 class_unregister(&isku_class); 456} 457 458module_init(isku_init); 459module_exit(isku_exit); 460 461MODULE_AUTHOR("Stefan Achatz"); 462MODULE_DESCRIPTION("USB Roccat Isku/FX driver"); 463MODULE_LICENSE("GPL v2"); 464