linux/drivers/hid/hid-roccat-koneplus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Roccat Kone[+] driver for Linux
   4 *
   5 * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
   6 */
   7
   8/*
   9 */
  10
  11/*
  12 * Roccat Kone[+] is an updated/improved version of the Kone with more memory
  13 * and functionality and without the non-standard behaviours the Kone had.
  14 * KoneXTD has same capabilities but updated sensor.
  15 */
  16
  17#include <linux/device.h>
  18#include <linux/input.h>
  19#include <linux/hid.h>
  20#include <linux/module.h>
  21#include <linux/slab.h>
  22#include <linux/hid-roccat.h>
  23#include "hid-ids.h"
  24#include "hid-roccat-common.h"
  25#include "hid-roccat-koneplus.h"
  26
  27static uint profile_numbers[5] = {0, 1, 2, 3, 4};
  28
  29static struct class *koneplus_class;
  30
  31static void koneplus_profile_activated(struct koneplus_device *koneplus,
  32                uint new_profile)
  33{
  34        koneplus->actual_profile = new_profile;
  35}
  36
  37static int koneplus_send_control(struct usb_device *usb_dev, uint value,
  38                enum koneplus_control_requests request)
  39{
  40        struct roccat_common2_control control;
  41
  42        if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
  43                        request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
  44                        value > 4)
  45                return -EINVAL;
  46
  47        control.command = ROCCAT_COMMON_COMMAND_CONTROL;
  48        control.value = value;
  49        control.request = request;
  50
  51        return roccat_common2_send_with_status(usb_dev,
  52                        ROCCAT_COMMON_COMMAND_CONTROL,
  53                        &control, sizeof(struct roccat_common2_control));
  54}
  55
  56
  57/* retval is 0-4 on success, < 0 on error */
  58static int koneplus_get_actual_profile(struct usb_device *usb_dev)
  59{
  60        struct koneplus_actual_profile buf;
  61        int retval;
  62
  63        retval = roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE,
  64                        &buf, KONEPLUS_SIZE_ACTUAL_PROFILE);
  65
  66        return retval ? retval : buf.actual_profile;
  67}
  68
  69static int koneplus_set_actual_profile(struct usb_device *usb_dev,
  70                int new_profile)
  71{
  72        struct koneplus_actual_profile buf;
  73
  74        buf.command = KONEPLUS_COMMAND_ACTUAL_PROFILE;
  75        buf.size = KONEPLUS_SIZE_ACTUAL_PROFILE;
  76        buf.actual_profile = new_profile;
  77
  78        return roccat_common2_send_with_status(usb_dev,
  79                        KONEPLUS_COMMAND_ACTUAL_PROFILE,
  80                        &buf, KONEPLUS_SIZE_ACTUAL_PROFILE);
  81}
  82
  83static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
  84                char *buf, loff_t off, size_t count,
  85                size_t real_size, uint command)
  86{
  87        struct device *dev = kobj_to_dev(kobj)->parent->parent;
  88        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
  89        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
  90        int retval;
  91
  92        if (off >= real_size)
  93                return 0;
  94
  95        if (off != 0 || count != real_size)
  96                return -EINVAL;
  97
  98        mutex_lock(&koneplus->koneplus_lock);
  99        retval = roccat_common2_receive(usb_dev, command, buf, real_size);
 100        mutex_unlock(&koneplus->koneplus_lock);
 101
 102        if (retval)
 103                return retval;
 104
 105        return real_size;
 106}
 107
 108static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
 109                void const *buf, loff_t off, size_t count,
 110                size_t real_size, uint command)
 111{
 112        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 113        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 114        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 115        int retval;
 116
 117        if (off != 0 || count != real_size)
 118                return -EINVAL;
 119
 120        mutex_lock(&koneplus->koneplus_lock);
 121        retval = roccat_common2_send_with_status(usb_dev, command,
 122                        buf, real_size);
 123        mutex_unlock(&koneplus->koneplus_lock);
 124
 125        if (retval)
 126                return retval;
 127
 128        return real_size;
 129}
 130
 131#define KONEPLUS_SYSFS_W(thingy, THINGY) \
 132static ssize_t koneplus_sysfs_write_ ## thingy(struct file *fp, \
 133                struct kobject *kobj, struct bin_attribute *attr, char *buf, \
 134                loff_t off, size_t count) \
 135{ \
 136        return koneplus_sysfs_write(fp, kobj, buf, off, count, \
 137                        KONEPLUS_SIZE_ ## THINGY, KONEPLUS_COMMAND_ ## THINGY); \
 138}
 139
 140#define KONEPLUS_SYSFS_R(thingy, THINGY) \
 141static ssize_t koneplus_sysfs_read_ ## thingy(struct file *fp, \
 142                struct kobject *kobj, struct bin_attribute *attr, char *buf, \
 143                loff_t off, size_t count) \
 144{ \
 145        return koneplus_sysfs_read(fp, kobj, buf, off, count, \
 146                        KONEPLUS_SIZE_ ## THINGY, KONEPLUS_COMMAND_ ## THINGY); \
 147}
 148
 149#define KONEPLUS_SYSFS_RW(thingy, THINGY) \
 150KONEPLUS_SYSFS_W(thingy, THINGY) \
 151KONEPLUS_SYSFS_R(thingy, THINGY)
 152
 153#define KONEPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
 154KONEPLUS_SYSFS_RW(thingy, THINGY); \
 155static struct bin_attribute bin_attr_##thingy = { \
 156        .attr = { .name = #thingy, .mode = 0660 }, \
 157        .size = KONEPLUS_SIZE_ ## THINGY, \
 158        .read = koneplus_sysfs_read_ ## thingy, \
 159        .write = koneplus_sysfs_write_ ## thingy \
 160}
 161
 162#define KONEPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
 163KONEPLUS_SYSFS_R(thingy, THINGY); \
 164static struct bin_attribute bin_attr_##thingy = { \
 165        .attr = { .name = #thingy, .mode = 0440 }, \
 166        .size = KONEPLUS_SIZE_ ## THINGY, \
 167        .read = koneplus_sysfs_read_ ## thingy, \
 168}
 169
 170#define KONEPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
 171KONEPLUS_SYSFS_W(thingy, THINGY); \
 172static struct bin_attribute bin_attr_##thingy = { \
 173        .attr = { .name = #thingy, .mode = 0220 }, \
 174        .size = KONEPLUS_SIZE_ ## THINGY, \
 175        .write = koneplus_sysfs_write_ ## thingy \
 176}
 177KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
 178KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK);
 179KONEPLUS_BIN_ATTRIBUTE_W(macro, MACRO);
 180KONEPLUS_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE);
 181KONEPLUS_BIN_ATTRIBUTE_RW(info, INFO);
 182KONEPLUS_BIN_ATTRIBUTE_RW(sensor, SENSOR);
 183KONEPLUS_BIN_ATTRIBUTE_RW(tcu, TCU);
 184KONEPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
 185KONEPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
 186
 187static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
 188                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 189                loff_t off, size_t count)
 190{
 191        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 192        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 193        ssize_t retval;
 194
 195        retval = koneplus_send_control(usb_dev, *(uint *)(attr->private),
 196                        KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
 197        if (retval)
 198                return retval;
 199
 200        return koneplus_sysfs_read(fp, kobj, buf, off, count,
 201                        KONEPLUS_SIZE_PROFILE_SETTINGS,
 202                        KONEPLUS_COMMAND_PROFILE_SETTINGS);
 203}
 204
 205static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
 206                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 207                loff_t off, size_t count)
 208{
 209        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 210        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 211        ssize_t retval;
 212
 213        retval = koneplus_send_control(usb_dev, *(uint *)(attr->private),
 214                        KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
 215        if (retval)
 216                return retval;
 217
 218        return koneplus_sysfs_read(fp, kobj, buf, off, count,
 219                        KONEPLUS_SIZE_PROFILE_BUTTONS,
 220                        KONEPLUS_COMMAND_PROFILE_BUTTONS);
 221}
 222
 223#define PROFILE_ATTR(number)                                            \
 224static struct bin_attribute bin_attr_profile##number##_settings = {     \
 225        .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
 226        .size = KONEPLUS_SIZE_PROFILE_SETTINGS,                         \
 227        .read = koneplus_sysfs_read_profilex_settings,                  \
 228        .private = &profile_numbers[number-1],                          \
 229};                                                                      \
 230static struct bin_attribute bin_attr_profile##number##_buttons = {      \
 231        .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
 232        .size = KONEPLUS_SIZE_PROFILE_BUTTONS,                          \
 233        .read = koneplus_sysfs_read_profilex_buttons,                   \
 234        .private = &profile_numbers[number-1],                          \
 235};
 236PROFILE_ATTR(1);
 237PROFILE_ATTR(2);
 238PROFILE_ATTR(3);
 239PROFILE_ATTR(4);
 240PROFILE_ATTR(5);
 241
 242static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
 243                struct device_attribute *attr, char *buf)
 244{
 245        struct koneplus_device *koneplus =
 246                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 247        return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
 248}
 249
 250static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
 251                struct device_attribute *attr, char const *buf, size_t size)
 252{
 253        struct koneplus_device *koneplus;
 254        struct usb_device *usb_dev;
 255        unsigned long profile;
 256        int retval;
 257        struct koneplus_roccat_report roccat_report;
 258
 259        dev = dev->parent->parent;
 260        koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 261        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 262
 263        retval = kstrtoul(buf, 10, &profile);
 264        if (retval)
 265                return retval;
 266
 267        if (profile > 4)
 268                return -EINVAL;
 269
 270        mutex_lock(&koneplus->koneplus_lock);
 271
 272        retval = koneplus_set_actual_profile(usb_dev, profile);
 273        if (retval) {
 274                mutex_unlock(&koneplus->koneplus_lock);
 275                return retval;
 276        }
 277
 278        koneplus_profile_activated(koneplus, profile);
 279
 280        roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE;
 281        roccat_report.data1 = profile + 1;
 282        roccat_report.data2 = 0;
 283        roccat_report.profile = profile + 1;
 284        roccat_report_event(koneplus->chrdev_minor,
 285                        (uint8_t const *)&roccat_report);
 286
 287        mutex_unlock(&koneplus->koneplus_lock);
 288
 289        return size;
 290}
 291static DEVICE_ATTR(actual_profile, 0660,
 292                   koneplus_sysfs_show_actual_profile,
 293                   koneplus_sysfs_set_actual_profile);
 294static DEVICE_ATTR(startup_profile, 0660,
 295                   koneplus_sysfs_show_actual_profile,
 296                   koneplus_sysfs_set_actual_profile);
 297
 298static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
 299                struct device_attribute *attr, char *buf)
 300{
 301        struct koneplus_device *koneplus;
 302        struct usb_device *usb_dev;
 303        struct koneplus_info info;
 304
 305        dev = dev->parent->parent;
 306        koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 307        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 308
 309        mutex_lock(&koneplus->koneplus_lock);
 310        roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_INFO,
 311                        &info, KONEPLUS_SIZE_INFO);
 312        mutex_unlock(&koneplus->koneplus_lock);
 313
 314        return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
 315}
 316static DEVICE_ATTR(firmware_version, 0440,
 317                   koneplus_sysfs_show_firmware_version, NULL);
 318
 319static struct attribute *koneplus_attrs[] = {
 320        &dev_attr_actual_profile.attr,
 321        &dev_attr_startup_profile.attr,
 322        &dev_attr_firmware_version.attr,
 323        NULL,
 324};
 325
 326static struct bin_attribute *koneplus_bin_attributes[] = {
 327        &bin_attr_control,
 328        &bin_attr_talk,
 329        &bin_attr_macro,
 330        &bin_attr_tcu_image,
 331        &bin_attr_info,
 332        &bin_attr_sensor,
 333        &bin_attr_tcu,
 334        &bin_attr_profile_settings,
 335        &bin_attr_profile_buttons,
 336        &bin_attr_profile1_settings,
 337        &bin_attr_profile2_settings,
 338        &bin_attr_profile3_settings,
 339        &bin_attr_profile4_settings,
 340        &bin_attr_profile5_settings,
 341        &bin_attr_profile1_buttons,
 342        &bin_attr_profile2_buttons,
 343        &bin_attr_profile3_buttons,
 344        &bin_attr_profile4_buttons,
 345        &bin_attr_profile5_buttons,
 346        NULL,
 347};
 348
 349static const struct attribute_group koneplus_group = {
 350        .attrs = koneplus_attrs,
 351        .bin_attrs = koneplus_bin_attributes,
 352};
 353
 354static const struct attribute_group *koneplus_groups[] = {
 355        &koneplus_group,
 356        NULL,
 357};
 358
 359static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
 360                struct koneplus_device *koneplus)
 361{
 362        int retval;
 363
 364        mutex_init(&koneplus->koneplus_lock);
 365
 366        retval = koneplus_get_actual_profile(usb_dev);
 367        if (retval < 0)
 368                return retval;
 369        koneplus_profile_activated(koneplus, retval);
 370
 371        return 0;
 372}
 373
 374static int koneplus_init_specials(struct hid_device *hdev)
 375{
 376        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 377        struct usb_device *usb_dev = interface_to_usbdev(intf);
 378        struct koneplus_device *koneplus;
 379        int retval;
 380
 381        if (intf->cur_altsetting->desc.bInterfaceProtocol
 382                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 383
 384                koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL);
 385                if (!koneplus) {
 386                        hid_err(hdev, "can't alloc device descriptor\n");
 387                        return -ENOMEM;
 388                }
 389                hid_set_drvdata(hdev, koneplus);
 390
 391                retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus);
 392                if (retval) {
 393                        hid_err(hdev, "couldn't init struct koneplus_device\n");
 394                        goto exit_free;
 395                }
 396
 397                retval = roccat_connect(koneplus_class, hdev,
 398                                sizeof(struct koneplus_roccat_report));
 399                if (retval < 0) {
 400                        hid_err(hdev, "couldn't init char dev\n");
 401                } else {
 402                        koneplus->chrdev_minor = retval;
 403                        koneplus->roccat_claimed = 1;
 404                }
 405        } else {
 406                hid_set_drvdata(hdev, NULL);
 407        }
 408
 409        return 0;
 410exit_free:
 411        kfree(koneplus);
 412        return retval;
 413}
 414
 415static void koneplus_remove_specials(struct hid_device *hdev)
 416{
 417        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 418        struct koneplus_device *koneplus;
 419
 420        if (intf->cur_altsetting->desc.bInterfaceProtocol
 421                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 422                koneplus = hid_get_drvdata(hdev);
 423                if (koneplus->roccat_claimed)
 424                        roccat_disconnect(koneplus->chrdev_minor);
 425                kfree(koneplus);
 426        }
 427}
 428
 429static int koneplus_probe(struct hid_device *hdev,
 430                const struct hid_device_id *id)
 431{
 432        int retval;
 433
 434        retval = hid_parse(hdev);
 435        if (retval) {
 436                hid_err(hdev, "parse failed\n");
 437                goto exit;
 438        }
 439
 440        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 441        if (retval) {
 442                hid_err(hdev, "hw start failed\n");
 443                goto exit;
 444        }
 445
 446        retval = koneplus_init_specials(hdev);
 447        if (retval) {
 448                hid_err(hdev, "couldn't install mouse\n");
 449                goto exit_stop;
 450        }
 451
 452        return 0;
 453
 454exit_stop:
 455        hid_hw_stop(hdev);
 456exit:
 457        return retval;
 458}
 459
 460static void koneplus_remove(struct hid_device *hdev)
 461{
 462        koneplus_remove_specials(hdev);
 463        hid_hw_stop(hdev);
 464}
 465
 466static void koneplus_keep_values_up_to_date(struct koneplus_device *koneplus,
 467                u8 const *data)
 468{
 469        struct koneplus_mouse_report_button const *button_report;
 470
 471        switch (data[0]) {
 472        case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON:
 473                button_report = (struct koneplus_mouse_report_button const *)data;
 474                switch (button_report->type) {
 475                case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE:
 476                        koneplus_profile_activated(koneplus, button_report->data1 - 1);
 477                        break;
 478                }
 479                break;
 480        }
 481}
 482
 483static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus,
 484                u8 const *data)
 485{
 486        struct koneplus_roccat_report roccat_report;
 487        struct koneplus_mouse_report_button const *button_report;
 488
 489        if (data[0] != KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON)
 490                return;
 491
 492        button_report = (struct koneplus_mouse_report_button const *)data;
 493
 494        if ((button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
 495                        button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) &&
 496                        button_report->data2 != KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS)
 497                return;
 498
 499        roccat_report.type = button_report->type;
 500        roccat_report.data1 = button_report->data1;
 501        roccat_report.data2 = button_report->data2;
 502        roccat_report.profile = koneplus->actual_profile + 1;
 503        roccat_report_event(koneplus->chrdev_minor,
 504                        (uint8_t const *)&roccat_report);
 505}
 506
 507static int koneplus_raw_event(struct hid_device *hdev,
 508                struct hid_report *report, u8 *data, int size)
 509{
 510        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 511        struct koneplus_device *koneplus = hid_get_drvdata(hdev);
 512
 513        if (intf->cur_altsetting->desc.bInterfaceProtocol
 514                        != USB_INTERFACE_PROTOCOL_MOUSE)
 515                return 0;
 516
 517        if (koneplus == NULL)
 518                return 0;
 519
 520        koneplus_keep_values_up_to_date(koneplus, data);
 521
 522        if (koneplus->roccat_claimed)
 523                koneplus_report_to_chrdev(koneplus, data);
 524
 525        return 0;
 526}
 527
 528static const struct hid_device_id koneplus_devices[] = {
 529        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
 530        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEXTD) },
 531        { }
 532};
 533
 534MODULE_DEVICE_TABLE(hid, koneplus_devices);
 535
 536static struct hid_driver koneplus_driver = {
 537                .name = "koneplus",
 538                .id_table = koneplus_devices,
 539                .probe = koneplus_probe,
 540                .remove = koneplus_remove,
 541                .raw_event = koneplus_raw_event
 542};
 543
 544static int __init koneplus_init(void)
 545{
 546        int retval;
 547
 548        /* class name has to be same as driver name */
 549        koneplus_class = class_create(THIS_MODULE, "koneplus");
 550        if (IS_ERR(koneplus_class))
 551                return PTR_ERR(koneplus_class);
 552        koneplus_class->dev_groups = koneplus_groups;
 553
 554        retval = hid_register_driver(&koneplus_driver);
 555        if (retval)
 556                class_destroy(koneplus_class);
 557        return retval;
 558}
 559
 560static void __exit koneplus_exit(void)
 561{
 562        hid_unregister_driver(&koneplus_driver);
 563        class_destroy(koneplus_class);
 564}
 565
 566module_init(koneplus_init);
 567module_exit(koneplus_exit);
 568
 569MODULE_AUTHOR("Stefan Achatz");
 570MODULE_DESCRIPTION("USB Roccat Kone[+]/XTD driver");
 571MODULE_LICENSE("GPL v2");
 572