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 26 static void isku_profile_activated(struct isku_device *isku, uint new_profile) 27 { 28 isku->actual_profile = new_profile; 29 } 30 31 static 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 37 static 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 47 static 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 59 static 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 67 static 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 } 107 static DEVICE_ATTR(actual_profile, 0660, isku_sysfs_show_actual_profile, 108 isku_sysfs_set_actual_profile); 109 110 static struct attribute *isku_attrs[] = { 111 &dev_attr_actual_profile.attr, 112 NULL, 113 }; 114 115 static 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 137 static 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) \ 158 static 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) \ 167 static 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) \ 176 ISKU_SYSFS_R(thingy, THINGY) \ 177 ISKU_SYSFS_W(thingy, THINGY) 178 179 #define ISKU_BIN_ATTR_RW(thingy, THINGY) \ 180 ISKU_SYSFS_RW(thingy, THINGY); \ 181 static 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) \ 189 ISKU_SYSFS_R(thingy, THINGY); \ 190 static 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) \ 197 ISKU_SYSFS_W(thingy, THINGY); \ 198 static 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 204 ISKU_BIN_ATTR_RW(macro, MACRO); 205 ISKU_BIN_ATTR_RW(keys_function, KEYS_FUNCTION); 206 ISKU_BIN_ATTR_RW(keys_easyzone, KEYS_EASYZONE); 207 ISKU_BIN_ATTR_RW(keys_media, KEYS_MEDIA); 208 ISKU_BIN_ATTR_RW(keys_thumbster, KEYS_THUMBSTER); 209 ISKU_BIN_ATTR_RW(keys_macro, KEYS_MACRO); 210 ISKU_BIN_ATTR_RW(keys_capslock, KEYS_CAPSLOCK); 211 ISKU_BIN_ATTR_RW(light, LIGHT); 212 ISKU_BIN_ATTR_RW(key_mask, KEY_MASK); 213 ISKU_BIN_ATTR_RW(last_set, LAST_SET); 214 ISKU_BIN_ATTR_W(talk, TALK); 215 ISKU_BIN_ATTR_W(talkfx, TALKFX); 216 ISKU_BIN_ATTR_W(control, CONTROL); 217 ISKU_BIN_ATTR_W(reset, RESET); 218 ISKU_BIN_ATTR_R(info, INFO); 219 220 static 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 239 static const struct attribute_group isku_group = { 240 .attrs = isku_attrs, 241 .bin_attrs = isku_bin_attributes, 242 }; 243 244 static const struct attribute_group *isku_groups[] = { 245 &isku_group, 246 NULL, 247 }; 248 249 static const struct class isku_class = { 250 .name = "isku", 251 .dev_groups = isku_groups, 252 }; 253 254 static 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 269 static 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; 305 exit_free: 306 kfree(isku); 307 return retval; 308 } 309 310 static 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 325 static 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 353 exit_stop: 354 hid_hw_stop(hdev); 355 exit: 356 return retval; 357 } 358 359 static void isku_remove(struct hid_device *hdev) 360 { 361 isku_remove_specials(hdev); 362 hid_hw_stop(hdev); 363 } 364 365 static 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 382 static 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 401 static 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 422 static 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 428 MODULE_DEVICE_TABLE(hid, isku_devices); 429 430 static 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 438 static 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 452 static void __exit isku_exit(void) 453 { 454 hid_unregister_driver(&isku_driver); 455 class_unregister(&isku_class); 456 } 457 458 module_init(isku_init); 459 module_exit(isku_exit); 460 461 MODULE_AUTHOR("Stefan Achatz"); 462 MODULE_DESCRIPTION("USB Roccat Isku/FX driver"); 463 MODULE_LICENSE("GPL v2"); 464