linux/drivers/hid/hid-roccat-arvo.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Roccat Arvo driver for Linux
   4 *
   5 * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
   6 */
   7
   8/*
   9 */
  10
  11/*
  12 * Roccat Arvo is a gamer keyboard with 5 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-arvo.h"
  25
  26static struct class *arvo_class;
  27
  28static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
  29                struct device_attribute *attr, char *buf)
  30{
  31        struct arvo_device *arvo =
  32                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  33        struct usb_device *usb_dev =
  34                        interface_to_usbdev(to_usb_interface(dev->parent->parent));
  35        struct arvo_mode_key temp_buf;
  36        int retval;
  37
  38        mutex_lock(&arvo->arvo_lock);
  39        retval = roccat_common2_receive(usb_dev, ARVO_COMMAND_MODE_KEY,
  40                        &temp_buf, sizeof(struct arvo_mode_key));
  41        mutex_unlock(&arvo->arvo_lock);
  42        if (retval)
  43                return retval;
  44
  45        return sysfs_emit(buf, "%d\n", temp_buf.state);
  46}
  47
  48static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
  49                struct device_attribute *attr, char const *buf, size_t size)
  50{
  51        struct arvo_device *arvo =
  52                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  53        struct usb_device *usb_dev =
  54                        interface_to_usbdev(to_usb_interface(dev->parent->parent));
  55        struct arvo_mode_key temp_buf;
  56        unsigned long state;
  57        int retval;
  58
  59        retval = kstrtoul(buf, 10, &state);
  60        if (retval)
  61                return retval;
  62
  63        temp_buf.command = ARVO_COMMAND_MODE_KEY;
  64        temp_buf.state = state;
  65
  66        mutex_lock(&arvo->arvo_lock);
  67        retval = roccat_common2_send(usb_dev, ARVO_COMMAND_MODE_KEY,
  68                        &temp_buf, sizeof(struct arvo_mode_key));
  69        mutex_unlock(&arvo->arvo_lock);
  70        if (retval)
  71                return retval;
  72
  73        return size;
  74}
  75static DEVICE_ATTR(mode_key, 0660,
  76                   arvo_sysfs_show_mode_key, arvo_sysfs_set_mode_key);
  77
  78static ssize_t arvo_sysfs_show_key_mask(struct device *dev,
  79                struct device_attribute *attr, char *buf)
  80{
  81        struct arvo_device *arvo =
  82                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  83        struct usb_device *usb_dev =
  84                        interface_to_usbdev(to_usb_interface(dev->parent->parent));
  85        struct arvo_key_mask temp_buf;
  86        int retval;
  87
  88        mutex_lock(&arvo->arvo_lock);
  89        retval = roccat_common2_receive(usb_dev, ARVO_COMMAND_KEY_MASK,
  90                        &temp_buf, sizeof(struct arvo_key_mask));
  91        mutex_unlock(&arvo->arvo_lock);
  92        if (retval)
  93                return retval;
  94
  95        return sysfs_emit(buf, "%d\n", temp_buf.key_mask);
  96}
  97
  98static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
  99                struct device_attribute *attr, char const *buf, size_t size)
 100{
 101        struct arvo_device *arvo =
 102                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 103        struct usb_device *usb_dev =
 104                        interface_to_usbdev(to_usb_interface(dev->parent->parent));
 105        struct arvo_key_mask temp_buf;
 106        unsigned long key_mask;
 107        int retval;
 108
 109        retval = kstrtoul(buf, 10, &key_mask);
 110        if (retval)
 111                return retval;
 112
 113        temp_buf.command = ARVO_COMMAND_KEY_MASK;
 114        temp_buf.key_mask = key_mask;
 115
 116        mutex_lock(&arvo->arvo_lock);
 117        retval = roccat_common2_send(usb_dev, ARVO_COMMAND_KEY_MASK,
 118                        &temp_buf, sizeof(struct arvo_key_mask));
 119        mutex_unlock(&arvo->arvo_lock);
 120        if (retval)
 121                return retval;
 122
 123        return size;
 124}
 125static DEVICE_ATTR(key_mask, 0660,
 126                   arvo_sysfs_show_key_mask, arvo_sysfs_set_key_mask);
 127
 128/* retval is 1-5 on success, < 0 on error */
 129static int arvo_get_actual_profile(struct usb_device *usb_dev)
 130{
 131        struct arvo_actual_profile temp_buf;
 132        int retval;
 133
 134        retval = roccat_common2_receive(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE,
 135                        &temp_buf, sizeof(struct arvo_actual_profile));
 136
 137        if (retval)
 138                return retval;
 139
 140        return temp_buf.actual_profile;
 141}
 142
 143static ssize_t arvo_sysfs_show_actual_profile(struct device *dev,
 144                struct device_attribute *attr, char *buf)
 145{
 146        struct arvo_device *arvo =
 147                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 148
 149        return sysfs_emit(buf, "%d\n", arvo->actual_profile);
 150}
 151
 152static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
 153                struct device_attribute *attr, char const *buf, size_t size)
 154{
 155        struct arvo_device *arvo =
 156                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 157        struct usb_device *usb_dev =
 158                        interface_to_usbdev(to_usb_interface(dev->parent->parent));
 159        struct arvo_actual_profile temp_buf;
 160        unsigned long profile;
 161        int retval;
 162
 163        retval = kstrtoul(buf, 10, &profile);
 164        if (retval)
 165                return retval;
 166
 167        if (profile < 1 || profile > 5)
 168                return -EINVAL;
 169
 170        temp_buf.command = ARVO_COMMAND_ACTUAL_PROFILE;
 171        temp_buf.actual_profile = profile;
 172
 173        mutex_lock(&arvo->arvo_lock);
 174        retval = roccat_common2_send(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE,
 175                        &temp_buf, sizeof(struct arvo_actual_profile));
 176        if (!retval) {
 177                arvo->actual_profile = profile;
 178                retval = size;
 179        }
 180        mutex_unlock(&arvo->arvo_lock);
 181        return retval;
 182}
 183static DEVICE_ATTR(actual_profile, 0660,
 184                   arvo_sysfs_show_actual_profile,
 185                   arvo_sysfs_set_actual_profile);
 186
 187static ssize_t arvo_sysfs_write(struct file *fp,
 188                struct kobject *kobj, void const *buf,
 189                loff_t off, size_t count, size_t real_size, uint command)
 190{
 191        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 192        struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
 193        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 194        int retval;
 195
 196        if (off != 0 || count != real_size)
 197                return -EINVAL;
 198
 199        mutex_lock(&arvo->arvo_lock);
 200        retval = roccat_common2_send(usb_dev, command, buf, real_size);
 201        mutex_unlock(&arvo->arvo_lock);
 202
 203        return (retval ? retval : real_size);
 204}
 205
 206static ssize_t arvo_sysfs_read(struct file *fp,
 207                struct kobject *kobj, void *buf, loff_t off,
 208                size_t count, size_t real_size, uint command)
 209{
 210        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 211        struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
 212        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 213        int retval;
 214
 215        if (off >= real_size)
 216                return 0;
 217
 218        if (off != 0 || count != real_size)
 219                return -EINVAL;
 220
 221        mutex_lock(&arvo->arvo_lock);
 222        retval = roccat_common2_receive(usb_dev, command, buf, real_size);
 223        mutex_unlock(&arvo->arvo_lock);
 224
 225        return (retval ? retval : real_size);
 226}
 227
 228static ssize_t arvo_sysfs_write_button(struct file *fp,
 229                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 230                loff_t off, size_t count)
 231{
 232        return arvo_sysfs_write(fp, kobj, buf, off, count,
 233                        sizeof(struct arvo_button), ARVO_COMMAND_BUTTON);
 234}
 235static BIN_ATTR(button, 0220, NULL, arvo_sysfs_write_button,
 236                sizeof(struct arvo_button));
 237
 238static ssize_t arvo_sysfs_read_info(struct file *fp,
 239                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 240                loff_t off, size_t count)
 241{
 242        return arvo_sysfs_read(fp, kobj, buf, off, count,
 243                        sizeof(struct arvo_info), ARVO_COMMAND_INFO);
 244}
 245static BIN_ATTR(info, 0440, arvo_sysfs_read_info, NULL,
 246                sizeof(struct arvo_info));
 247
 248static struct attribute *arvo_attrs[] = {
 249        &dev_attr_mode_key.attr,
 250        &dev_attr_key_mask.attr,
 251        &dev_attr_actual_profile.attr,
 252        NULL,
 253};
 254
 255static struct bin_attribute *arvo_bin_attributes[] = {
 256        &bin_attr_button,
 257        &bin_attr_info,
 258        NULL,
 259};
 260
 261static const struct attribute_group arvo_group = {
 262        .attrs = arvo_attrs,
 263        .bin_attrs = arvo_bin_attributes,
 264};
 265
 266static const struct attribute_group *arvo_groups[] = {
 267        &arvo_group,
 268        NULL,
 269};
 270
 271static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
 272                struct arvo_device *arvo)
 273{
 274        int retval;
 275
 276        mutex_init(&arvo->arvo_lock);
 277
 278        retval = arvo_get_actual_profile(usb_dev);
 279        if (retval < 0)
 280                return retval;
 281        arvo->actual_profile = retval;
 282
 283        return 0;
 284}
 285
 286static int arvo_init_specials(struct hid_device *hdev)
 287{
 288        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 289        struct usb_device *usb_dev = interface_to_usbdev(intf);
 290        struct arvo_device *arvo;
 291        int retval;
 292
 293        if (intf->cur_altsetting->desc.bInterfaceProtocol
 294                        == USB_INTERFACE_PROTOCOL_KEYBOARD) {
 295                hid_set_drvdata(hdev, NULL);
 296                return 0;
 297        }
 298
 299        arvo = kzalloc(sizeof(*arvo), GFP_KERNEL);
 300        if (!arvo) {
 301                hid_err(hdev, "can't alloc device descriptor\n");
 302                return -ENOMEM;
 303        }
 304        hid_set_drvdata(hdev, arvo);
 305
 306        retval = arvo_init_arvo_device_struct(usb_dev, arvo);
 307        if (retval) {
 308                hid_err(hdev, "couldn't init struct arvo_device\n");
 309                goto exit_free;
 310        }
 311
 312        retval = roccat_connect(arvo_class, hdev,
 313                        sizeof(struct arvo_roccat_report));
 314        if (retval < 0) {
 315                hid_err(hdev, "couldn't init char dev\n");
 316        } else {
 317                arvo->chrdev_minor = retval;
 318                arvo->roccat_claimed = 1;
 319        }
 320
 321        return 0;
 322exit_free:
 323        kfree(arvo);
 324        return retval;
 325}
 326
 327static void arvo_remove_specials(struct hid_device *hdev)
 328{
 329        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 330        struct arvo_device *arvo;
 331
 332        if (intf->cur_altsetting->desc.bInterfaceProtocol
 333                        == USB_INTERFACE_PROTOCOL_KEYBOARD)
 334                return;
 335
 336        arvo = hid_get_drvdata(hdev);
 337        if (arvo->roccat_claimed)
 338                roccat_disconnect(arvo->chrdev_minor);
 339        kfree(arvo);
 340}
 341
 342static int arvo_probe(struct hid_device *hdev,
 343                const struct hid_device_id *id)
 344{
 345        int retval;
 346
 347        retval = hid_parse(hdev);
 348        if (retval) {
 349                hid_err(hdev, "parse failed\n");
 350                goto exit;
 351        }
 352
 353        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 354        if (retval) {
 355                hid_err(hdev, "hw start failed\n");
 356                goto exit;
 357        }
 358
 359        retval = arvo_init_specials(hdev);
 360        if (retval) {
 361                hid_err(hdev, "couldn't install keyboard\n");
 362                goto exit_stop;
 363        }
 364
 365        return 0;
 366
 367exit_stop:
 368        hid_hw_stop(hdev);
 369exit:
 370        return retval;
 371}
 372
 373static void arvo_remove(struct hid_device *hdev)
 374{
 375        arvo_remove_specials(hdev);
 376        hid_hw_stop(hdev);
 377}
 378
 379static void arvo_report_to_chrdev(struct arvo_device const *arvo,
 380                u8 const *data)
 381{
 382        struct arvo_special_report const *special_report;
 383        struct arvo_roccat_report roccat_report;
 384
 385        special_report = (struct arvo_special_report const *)data;
 386
 387        roccat_report.profile = arvo->actual_profile;
 388        roccat_report.button = special_report->event &
 389                        ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON;
 390        if ((special_report->event & ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION) ==
 391                        ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS)
 392                roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_PRESS;
 393        else
 394                roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_RELEASE;
 395
 396        roccat_report_event(arvo->chrdev_minor,
 397                        (uint8_t const *)&roccat_report);
 398}
 399
 400static int arvo_raw_event(struct hid_device *hdev,
 401                struct hid_report *report, u8 *data, int size)
 402{
 403        struct arvo_device *arvo = hid_get_drvdata(hdev);
 404
 405        if (size != 3)
 406                return 0;
 407
 408        if (arvo && arvo->roccat_claimed)
 409                arvo_report_to_chrdev(arvo, data);
 410
 411        return 0;
 412}
 413
 414static const struct hid_device_id arvo_devices[] = {
 415        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
 416        { }
 417};
 418
 419MODULE_DEVICE_TABLE(hid, arvo_devices);
 420
 421static struct hid_driver arvo_driver = {
 422        .name = "arvo",
 423        .id_table = arvo_devices,
 424        .probe = arvo_probe,
 425        .remove = arvo_remove,
 426        .raw_event = arvo_raw_event
 427};
 428
 429static int __init arvo_init(void)
 430{
 431        int retval;
 432
 433        arvo_class = class_create(THIS_MODULE, "arvo");
 434        if (IS_ERR(arvo_class))
 435                return PTR_ERR(arvo_class);
 436        arvo_class->dev_groups = arvo_groups;
 437
 438        retval = hid_register_driver(&arvo_driver);
 439        if (retval)
 440                class_destroy(arvo_class);
 441        return retval;
 442}
 443
 444static void __exit arvo_exit(void)
 445{
 446        hid_unregister_driver(&arvo_driver);
 447        class_destroy(arvo_class);
 448}
 449
 450module_init(arvo_init);
 451module_exit(arvo_exit);
 452
 453MODULE_AUTHOR("Stefan Achatz");
 454MODULE_DESCRIPTION("USB Roccat Arvo driver");
 455MODULE_LICENSE("GPL v2");
 456