Commit e68cc603b063416c85f3e408184219fb71d4a9ff

Authored by Stefan Achatz
Committed by Jiri Kosina
1 parent dacfecdbf3

HID: roccat: Add support for Roccat Arvo keyboard

This patch add support for Roccat Arvo keyboard. Arvo has 5 additional
configurable buttons and the ability to deactivate certain keys.
Userland tools can soon be found at http://sourceforge.net/projects/roccat

Signed-off-by: Stefan Achatz <erazor_de@users.sourceforge.net>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

Showing 7 changed files with 672 additions and 0 deletions Side-by-side Diff

Documentation/ABI/testing/sysfs-driver-hid-roccat-arvo
  1 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/actual_profile
  2 +Date: Januar 2011
  3 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  4 +Description: The integer value of this attribute ranges from 1-5.
  5 + When read, this attribute returns the number of the actual
  6 + profile which is also the profile that's active on device startup.
  7 + When written this attribute activates the selected profile
  8 + immediately.
  9 +
  10 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/button
  11 +Date: Januar 2011
  12 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  13 +Description: The keyboard can store short macros with consist of 1 button with
  14 + several modifier keys internally.
  15 + When written, this file lets one set the sequence for a specific
  16 + button for a specific profile. Button and profile numbers are
  17 + included in written data. The data has to be 24 bytes long.
  18 + This file is writeonly.
  19 +
  20 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/info
  21 +Date: Januar 2011
  22 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  23 +Description: When read, this file returns some info about the device like the
  24 + installed firmware version.
  25 + The size of the data is 8 bytes in size.
  26 + This file is readonly.
  27 +
  28 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/key_mask
  29 +Date: Januar 2011
  30 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  31 +Description: The keyboard lets the user deactivate 5 certain keys like the
  32 + windows and application keys, to protect the user from the outcome
  33 + of accidentally pressing them.
  34 + The integer value of this attribute has bits 0-4 set depending
  35 + on the state of the corresponding key.
  36 + When read, this file returns the current state of the buttons.
  37 + When written, the given buttons are activated/deactivated
  38 + immediately.
  39 +
  40 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/mode_key
  41 +Date: Januar 2011
  42 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  43 +Description: The keyboard has a condensed layout without num-lock key.
  44 + Instead it uses a mode-key which activates a gaming mode where
  45 + the assignment of the number block changes.
  46 + The integer value of this attribute ranges from 0 (OFF) to 1 (ON).
  47 + When read, this file returns the actual state of the key.
  48 + When written, the key is activated/deactivated immediately.
... ... @@ -417,6 +417,13 @@
417 417 Say Y here if you have a Roccat mouse or keyboard and want OSD or
418 418 macro execution support.
419 419  
  420 +config HID_ROCCAT_ARVO
  421 + tristate "Roccat Arvo keyboard support"
  422 + depends on USB_HID
  423 + select HID_ROCCAT
  424 + ---help---
  425 + Support for Roccat Arvo keyboard.
  426 +
420 427 config HID_ROCCAT_KONE
421 428 tristate "Roccat Kone Mouse support"
422 429 depends on USB_HID
drivers/hid/Makefile
... ... @@ -56,6 +56,7 @@
56 56 obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
57 57 obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
58 58 obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
  59 +obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
59 60 obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
60 61 obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
61 62 obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
drivers/hid/hid-core.c
... ... @@ -1405,6 +1405,7 @@
1405 1405 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
1406 1406 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
1407 1407 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
  1408 + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
1408 1409 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
1409 1410 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
1410 1411 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
drivers/hid/hid-ids.h
... ... @@ -496,6 +496,7 @@
496 496 #define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
497 497  
498 498 #define USB_VENDOR_ID_ROCCAT 0x1e7d
  499 +#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
499 500 #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
500 501 #define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
501 502 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
drivers/hid/hid-roccat-arvo.c
  1 +/*
  2 + * Roccat Arvo driver for Linux
  3 + *
  4 + * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
  5 + */
  6 +
  7 +/*
  8 + * This program is free software; you can redistribute it and/or modify it
  9 + * under the terms of the GNU General Public License as published by the Free
  10 + * Software Foundation; either version 2 of the License, or (at your option)
  11 + * any later version.
  12 + */
  13 +
  14 +/*
  15 + * Roccat Arvo is a gamer keyboard with 5 macro keys that can be configured in
  16 + * 5 profiles.
  17 + */
  18 +
  19 +#include <linux/device.h>
  20 +#include <linux/input.h>
  21 +#include <linux/hid.h>
  22 +#include <linux/usb.h>
  23 +#include <linux/module.h>
  24 +#include <linux/slab.h>
  25 +#include "hid-ids.h"
  26 +#include "hid-roccat.h"
  27 +#include "hid-roccat-arvo.h"
  28 +
  29 +static struct class *arvo_class;
  30 +
  31 +static int arvo_receive(struct usb_device *usb_dev, uint usb_command,
  32 + void *buf, uint size)
  33 +{
  34 + int len;
  35 +
  36 + len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
  37 + USB_REQ_CLEAR_FEATURE,
  38 + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
  39 + usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
  40 +
  41 + return (len != size) ? -EIO : 0;
  42 +}
  43 +
  44 +static int arvo_send(struct usb_device *usb_dev, uint usb_command,
  45 + void const *buf, uint size)
  46 +{
  47 + int len;
  48 +
  49 + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
  50 + USB_REQ_SET_CONFIGURATION,
  51 + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
  52 + usb_command, 0, (void *)buf, size, USB_CTRL_SET_TIMEOUT);
  53 +
  54 + return (len != size) ? -EIO : 0;
  55 +}
  56 +
  57 +static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
  58 + struct device_attribute *attr, char *buf)
  59 +{
  60 + struct arvo_device *arvo =
  61 + hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  62 + struct usb_device *usb_dev =
  63 + interface_to_usbdev(to_usb_interface(dev->parent->parent));
  64 + struct arvo_mode_key *temp_buf;
  65 + int retval;
  66 +
  67 + temp_buf = kmalloc(sizeof(struct arvo_mode_key), GFP_KERNEL);
  68 + if (!temp_buf)
  69 + return -ENOMEM;
  70 +
  71 + mutex_lock(&arvo->arvo_lock);
  72 + retval = arvo_receive(usb_dev, ARVO_USB_COMMAND_MODE_KEY,
  73 + temp_buf, sizeof(struct arvo_mode_key));
  74 + mutex_unlock(&arvo->arvo_lock);
  75 + if (retval)
  76 + goto out;
  77 +
  78 + retval = snprintf(buf, PAGE_SIZE, "%d\n", temp_buf->state);
  79 +out:
  80 + kfree(temp_buf);
  81 + return retval;
  82 +}
  83 +
  84 +static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
  85 + struct device_attribute *attr, char const *buf, size_t size)
  86 +{
  87 + struct arvo_device *arvo =
  88 + hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  89 + struct usb_device *usb_dev =
  90 + interface_to_usbdev(to_usb_interface(dev->parent->parent));
  91 + struct arvo_mode_key *temp_buf;
  92 + unsigned long state;
  93 + int retval;
  94 +
  95 + temp_buf = kmalloc(sizeof(struct arvo_mode_key), GFP_KERNEL);
  96 + if (!temp_buf)
  97 + return -ENOMEM;
  98 +
  99 + retval = strict_strtoul(buf, 10, &state);
  100 + if (retval)
  101 + goto out;
  102 +
  103 + temp_buf->command = ARVO_COMMAND_MODE_KEY;
  104 + temp_buf->state = state;
  105 +
  106 + mutex_lock(&arvo->arvo_lock);
  107 + retval = arvo_send(usb_dev, ARVO_USB_COMMAND_MODE_KEY,
  108 + temp_buf, sizeof(struct arvo_mode_key));
  109 + mutex_unlock(&arvo->arvo_lock);
  110 + if (retval)
  111 + goto out;
  112 +
  113 + retval = size;
  114 +out:
  115 + kfree(temp_buf);
  116 + return retval;
  117 +}
  118 +
  119 +static ssize_t arvo_sysfs_show_key_mask(struct device *dev,
  120 + struct device_attribute *attr, char *buf)
  121 +{
  122 + struct arvo_device *arvo =
  123 + hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  124 + struct usb_device *usb_dev =
  125 + interface_to_usbdev(to_usb_interface(dev->parent->parent));
  126 + struct arvo_key_mask *temp_buf;
  127 + int retval;
  128 +
  129 + temp_buf = kmalloc(sizeof(struct arvo_key_mask), GFP_KERNEL);
  130 + if (!temp_buf)
  131 + return -ENOMEM;
  132 +
  133 + mutex_lock(&arvo->arvo_lock);
  134 + retval = arvo_receive(usb_dev, ARVO_USB_COMMAND_KEY_MASK,
  135 + temp_buf, sizeof(struct arvo_key_mask));
  136 + mutex_unlock(&arvo->arvo_lock);
  137 + if (retval)
  138 + goto out;
  139 +
  140 + retval = snprintf(buf, PAGE_SIZE, "%d\n", temp_buf->key_mask);
  141 +out:
  142 + kfree(temp_buf);
  143 + return retval;
  144 +}
  145 +
  146 +static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
  147 + struct device_attribute *attr, char const *buf, size_t size)
  148 +{
  149 + struct arvo_device *arvo =
  150 + hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  151 + struct usb_device *usb_dev =
  152 + interface_to_usbdev(to_usb_interface(dev->parent->parent));
  153 + struct arvo_key_mask *temp_buf;
  154 + unsigned long key_mask;
  155 + int retval;
  156 +
  157 + temp_buf = kmalloc(sizeof(struct arvo_key_mask), GFP_KERNEL);
  158 + if (!temp_buf)
  159 + return -ENOMEM;
  160 +
  161 + retval = strict_strtoul(buf, 10, &key_mask);
  162 + if (retval)
  163 + goto out;
  164 +
  165 + temp_buf->command = ARVO_COMMAND_KEY_MASK;
  166 + temp_buf->key_mask = key_mask;
  167 +
  168 + mutex_lock(&arvo->arvo_lock);
  169 + retval = arvo_send(usb_dev, ARVO_USB_COMMAND_KEY_MASK,
  170 + temp_buf, sizeof(struct arvo_key_mask));
  171 + mutex_unlock(&arvo->arvo_lock);
  172 + if (retval)
  173 + goto out;
  174 +
  175 + retval = size;
  176 +out:
  177 + kfree(temp_buf);
  178 + return retval;
  179 +}
  180 +
  181 +/* retval is 1-5 on success, < 0 on error */
  182 +static int arvo_get_actual_profile(struct usb_device *usb_dev)
  183 +{
  184 + struct arvo_actual_profile *temp_buf;
  185 + int retval;
  186 +
  187 + temp_buf = kmalloc(sizeof(struct arvo_actual_profile), GFP_KERNEL);
  188 + if (!temp_buf)
  189 + return -ENOMEM;
  190 +
  191 + retval = arvo_receive(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE,
  192 + temp_buf, sizeof(struct arvo_actual_profile));
  193 +
  194 + if (!retval)
  195 + retval = temp_buf->actual_profile;
  196 +
  197 + kfree(temp_buf);
  198 + return retval;
  199 +}
  200 +
  201 +static ssize_t arvo_sysfs_show_actual_profile(struct device *dev,
  202 + struct device_attribute *attr, char *buf)
  203 +{
  204 + struct arvo_device *arvo =
  205 + hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  206 +
  207 + return snprintf(buf, PAGE_SIZE, "%d\n", arvo->actual_profile);
  208 +}
  209 +
  210 +static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
  211 + struct device_attribute *attr, char const *buf, size_t size)
  212 +{
  213 + struct arvo_device *arvo =
  214 + hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  215 + struct usb_device *usb_dev =
  216 + interface_to_usbdev(to_usb_interface(dev->parent->parent));
  217 + struct arvo_actual_profile *temp_buf;
  218 + unsigned long profile;
  219 + int retval;
  220 +
  221 + temp_buf = kmalloc(sizeof(struct arvo_actual_profile), GFP_KERNEL);
  222 + if (!temp_buf)
  223 + return -ENOMEM;
  224 +
  225 + retval = strict_strtoul(buf, 10, &profile);
  226 + if (retval)
  227 + goto out;
  228 +
  229 + temp_buf->command = ARVO_COMMAND_ACTUAL_PROFILE;
  230 + temp_buf->actual_profile = profile;
  231 +
  232 + mutex_lock(&arvo->arvo_lock);
  233 + retval = arvo_send(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE,
  234 + temp_buf, sizeof(struct arvo_actual_profile));
  235 + if (!retval) {
  236 + arvo->actual_profile = profile;
  237 + retval = size;
  238 + }
  239 + mutex_unlock(&arvo->arvo_lock);
  240 +
  241 +out:
  242 + kfree(temp_buf);
  243 + return retval;
  244 +}
  245 +
  246 +static ssize_t arvo_sysfs_write(struct file *fp,
  247 + struct kobject *kobj, void const *buf,
  248 + loff_t off, size_t count, size_t real_size, uint command)
  249 +{
  250 + struct device *dev =
  251 + container_of(kobj, struct device, kobj)->parent->parent;
  252 + struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
  253 + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
  254 + int retval;
  255 +
  256 + if (off != 0 || count != real_size)
  257 + return -EINVAL;
  258 +
  259 + mutex_lock(&arvo->arvo_lock);
  260 + retval = arvo_send(usb_dev, command, buf, real_size);
  261 + mutex_unlock(&arvo->arvo_lock);
  262 +
  263 + return (retval ? retval : real_size);
  264 +}
  265 +
  266 +static ssize_t arvo_sysfs_read(struct file *fp,
  267 + struct kobject *kobj, void *buf, loff_t off,
  268 + size_t count, size_t real_size, uint command)
  269 +{
  270 + struct device *dev =
  271 + container_of(kobj, struct device, kobj)->parent->parent;
  272 + struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
  273 + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
  274 + int retval;
  275 +
  276 + if (off >= real_size)
  277 + return 0;
  278 +
  279 + if (off != 0 || count != real_size)
  280 + return -EINVAL;
  281 +
  282 + mutex_lock(&arvo->arvo_lock);
  283 + retval = arvo_receive(usb_dev, command, buf, real_size);
  284 + mutex_unlock(&arvo->arvo_lock);
  285 +
  286 + return (retval ? retval : real_size);
  287 +}
  288 +
  289 +static ssize_t arvo_sysfs_write_button(struct file *fp,
  290 + struct kobject *kobj, struct bin_attribute *attr, char *buf,
  291 + loff_t off, size_t count)
  292 +{
  293 + return arvo_sysfs_write(fp, kobj, buf, off, count,
  294 + sizeof(struct arvo_button), ARVO_USB_COMMAND_BUTTON);
  295 +}
  296 +
  297 +static ssize_t arvo_sysfs_read_info(struct file *fp,
  298 + struct kobject *kobj, struct bin_attribute *attr, char *buf,
  299 + loff_t off, size_t count)
  300 +{
  301 + return arvo_sysfs_read(fp, kobj, buf, off, count,
  302 + sizeof(struct arvo_info), ARVO_USB_COMMAND_INFO);
  303 +}
  304 +
  305 +
  306 +static struct device_attribute arvo_attributes[] = {
  307 + __ATTR(mode_key, 0660,
  308 + arvo_sysfs_show_mode_key, arvo_sysfs_set_mode_key),
  309 + __ATTR(key_mask, 0660,
  310 + arvo_sysfs_show_key_mask, arvo_sysfs_set_key_mask),
  311 + __ATTR(actual_profile, 0660,
  312 + arvo_sysfs_show_actual_profile,
  313 + arvo_sysfs_set_actual_profile),
  314 + __ATTR_NULL
  315 +};
  316 +
  317 +static struct bin_attribute arvo_bin_attributes[] = {
  318 + {
  319 + .attr = { .name = "button", .mode = 0220 },
  320 + .size = sizeof(struct arvo_button),
  321 + .write = arvo_sysfs_write_button
  322 + },
  323 + {
  324 + .attr = { .name = "info", .mode = 0440 },
  325 + .size = sizeof(struct arvo_info),
  326 + .read = arvo_sysfs_read_info
  327 + },
  328 + __ATTR_NULL
  329 +};
  330 +
  331 +static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
  332 + struct arvo_device *arvo)
  333 +{
  334 + int retval;
  335 +
  336 + mutex_init(&arvo->arvo_lock);
  337 +
  338 + retval = arvo_get_actual_profile(usb_dev);
  339 + if (retval < 0)
  340 + return retval;
  341 + arvo->actual_profile = retval;
  342 +
  343 + return 0;
  344 +}
  345 +
  346 +static int arvo_init_specials(struct hid_device *hdev)
  347 +{
  348 + struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  349 + struct usb_device *usb_dev = interface_to_usbdev(intf);
  350 + struct arvo_device *arvo;
  351 + int retval;
  352 +
  353 + if (intf->cur_altsetting->desc.bInterfaceProtocol
  354 + == USB_INTERFACE_PROTOCOL_KEYBOARD) {
  355 + hid_set_drvdata(hdev, NULL);
  356 + return 0;
  357 + }
  358 +
  359 + arvo = kzalloc(sizeof(*arvo), GFP_KERNEL);
  360 + if (!arvo) {
  361 + dev_err(&hdev->dev, "can't alloc device descriptor\n");
  362 + return -ENOMEM;
  363 + }
  364 + hid_set_drvdata(hdev, arvo);
  365 +
  366 + retval = arvo_init_arvo_device_struct(usb_dev, arvo);
  367 + if (retval) {
  368 + dev_err(&hdev->dev,
  369 + "couldn't init struct arvo_device\n");
  370 + goto exit_free;
  371 + }
  372 +
  373 + retval = roccat_connect(arvo_class, hdev);
  374 + if (retval < 0) {
  375 + dev_err(&hdev->dev, "couldn't init char dev\n");
  376 + } else {
  377 + arvo->chrdev_minor = retval;
  378 + arvo->roccat_claimed = 1;
  379 + }
  380 +
  381 + return 0;
  382 +exit_free:
  383 + kfree(arvo);
  384 + return retval;
  385 +}
  386 +
  387 +static void arvo_remove_specials(struct hid_device *hdev)
  388 +{
  389 + struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  390 + struct arvo_device *arvo;
  391 +
  392 + if (intf->cur_altsetting->desc.bInterfaceProtocol
  393 + == USB_INTERFACE_PROTOCOL_KEYBOARD)
  394 + return;
  395 +
  396 + arvo = hid_get_drvdata(hdev);
  397 + if (arvo->roccat_claimed)
  398 + roccat_disconnect(arvo->chrdev_minor);
  399 + kfree(arvo);
  400 +}
  401 +
  402 +static int arvo_probe(struct hid_device *hdev,
  403 + const struct hid_device_id *id)
  404 +{
  405 + int retval;
  406 +
  407 + retval = hid_parse(hdev);
  408 + if (retval) {
  409 + dev_err(&hdev->dev, "parse failed\n");
  410 + goto exit;
  411 + }
  412 +
  413 + retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
  414 + if (retval) {
  415 + dev_err(&hdev->dev, "hw start failed\n");
  416 + goto exit;
  417 + }
  418 +
  419 + retval = arvo_init_specials(hdev);
  420 + if (retval) {
  421 + dev_err(&hdev->dev, "couldn't install keyboard\n");
  422 + goto exit_stop;
  423 + }
  424 +
  425 + return 0;
  426 +
  427 +exit_stop:
  428 + hid_hw_stop(hdev);
  429 +exit:
  430 + return retval;
  431 +}
  432 +
  433 +static void arvo_remove(struct hid_device *hdev)
  434 +{
  435 + arvo_remove_specials(hdev);
  436 + hid_hw_stop(hdev);
  437 +}
  438 +
  439 +static void arvo_report_to_chrdev(struct arvo_device const *arvo,
  440 + u8 const *data)
  441 +{
  442 + struct arvo_special_report const *special_report;
  443 + struct arvo_roccat_report roccat_report;
  444 +
  445 + special_report = (struct arvo_special_report const *)data;
  446 +
  447 + roccat_report.profile = arvo->actual_profile;
  448 + roccat_report.button = special_report->event &
  449 + ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON;
  450 + if ((special_report->event & ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION) ==
  451 + ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS)
  452 + roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_PRESS;
  453 + else
  454 + roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_RELEASE;
  455 +
  456 + roccat_report_event(arvo->chrdev_minor, (uint8_t const *)&roccat_report,
  457 + sizeof(struct arvo_roccat_report));
  458 +}
  459 +
  460 +static int arvo_raw_event(struct hid_device *hdev,
  461 + struct hid_report *report, u8 *data, int size)
  462 +{
  463 + struct arvo_device *arvo = hid_get_drvdata(hdev);
  464 +
  465 + if (size != 3)
  466 + return 0;
  467 +
  468 + if (arvo->roccat_claimed)
  469 + arvo_report_to_chrdev(arvo, data);
  470 +
  471 + return 0;
  472 +}
  473 +
  474 +static const struct hid_device_id arvo_devices[] = {
  475 + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
  476 + { }
  477 +};
  478 +
  479 +MODULE_DEVICE_TABLE(hid, arvo_devices);
  480 +
  481 +static struct hid_driver arvo_driver = {
  482 + .name = "arvo",
  483 + .id_table = arvo_devices,
  484 + .probe = arvo_probe,
  485 + .remove = arvo_remove,
  486 + .raw_event = arvo_raw_event
  487 +};
  488 +
  489 +static int __init arvo_init(void)
  490 +{
  491 + int retval;
  492 +
  493 + arvo_class = class_create(THIS_MODULE, "arvo");
  494 + if (IS_ERR(arvo_class))
  495 + return PTR_ERR(arvo_class);
  496 + arvo_class->dev_attrs = arvo_attributes;
  497 + arvo_class->dev_bin_attrs = arvo_bin_attributes;
  498 +
  499 + retval = hid_register_driver(&arvo_driver);
  500 + if (retval)
  501 + class_destroy(arvo_class);
  502 + return retval;
  503 +}
  504 +
  505 +static void __exit arvo_exit(void)
  506 +{
  507 + class_destroy(arvo_class);
  508 + hid_unregister_driver(&arvo_driver);
  509 +}
  510 +
  511 +module_init(arvo_init);
  512 +module_exit(arvo_exit);
  513 +
  514 +MODULE_AUTHOR("Stefan Achatz");
  515 +MODULE_DESCRIPTION("USB Roccat Arvo driver");
  516 +MODULE_LICENSE("GPL v2");
drivers/hid/hid-roccat-arvo.h
  1 +#ifndef __HID_ROCCAT_ARVO_H
  2 +#define __HID_ROCCAT_ARVO_H
  3 +
  4 +/*
  5 + * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
  6 + */
  7 +
  8 +/*
  9 + * This program is free software; you can redistribute it and/or modify it
  10 + * under the terms of the GNU General Public License as published by the Free
  11 + * Software Foundation; either version 2 of the License, or (at your option)
  12 + * any later version.
  13 + */
  14 +
  15 +#include <linux/types.h>
  16 +
  17 +struct arvo_mode_key { /* 2 bytes */
  18 + uint8_t command; /* ARVO_COMMAND_MODE_KEY */
  19 + uint8_t state;
  20 +} __packed;
  21 +
  22 +struct arvo_button {
  23 + uint8_t unknown[24];
  24 +} __packed;
  25 +
  26 +struct arvo_info {
  27 + uint8_t unknown[8];
  28 +} __packed;
  29 +
  30 +struct arvo_key_mask { /* 2 bytes */
  31 + uint8_t command; /* ARVO_COMMAND_KEY_MASK */
  32 + uint8_t key_mask;
  33 +} __packed;
  34 +
  35 +/* selected profile is persistent */
  36 +struct arvo_actual_profile { /* 2 bytes */
  37 + uint8_t command; /* ARVO_COMMAND_ACTUAL_PROFILE */
  38 + uint8_t actual_profile;
  39 +} __packed;
  40 +
  41 +enum arvo_commands {
  42 + ARVO_COMMAND_MODE_KEY = 0x3,
  43 + ARVO_COMMAND_BUTTON = 0x4,
  44 + ARVO_COMMAND_INFO = 0x5,
  45 + ARVO_COMMAND_KEY_MASK = 0x6,
  46 + ARVO_COMMAND_ACTUAL_PROFILE = 0x7,
  47 +};
  48 +
  49 +enum arvo_usb_commands {
  50 + ARVO_USB_COMMAND_MODE_KEY = 0x303,
  51 + /*
  52 + * read/write
  53 + * Read uses both index bytes as profile/key indexes
  54 + * Write has index 0, profile/key is determined by payload
  55 + */
  56 + ARVO_USB_COMMAND_BUTTON = 0x304,
  57 + ARVO_USB_COMMAND_INFO = 0x305,
  58 + ARVO_USB_COMMAND_KEY_MASK = 0x306,
  59 + ARVO_USB_COMMAND_ACTUAL_PROFILE = 0x307,
  60 +};
  61 +
  62 +struct arvo_special_report {
  63 + uint8_t unknown1; /* always 0x01 */
  64 + uint8_t event;
  65 + uint8_t unknown2; /* always 0x70 */
  66 +} __packed;
  67 +
  68 +enum arvo_special_report_events {
  69 + ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS = 0x10,
  70 + ARVO_SPECIAL_REPORT_EVENT_ACTION_RELEASE = 0x0,
  71 +};
  72 +
  73 +enum arvo_special_report_event_masks {
  74 + ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION = 0xf0,
  75 + ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON = 0x0f,
  76 +};
  77 +
  78 +struct arvo_roccat_report {
  79 + uint8_t profile;
  80 + uint8_t button;
  81 + uint8_t action;
  82 +} __packed;
  83 +
  84 +enum arvo_roccat_report_action {
  85 + ARVO_ROCCAT_REPORT_ACTION_RELEASE = 0,
  86 + ARVO_ROCCAT_REPORT_ACTION_PRESS = 1,
  87 +};
  88 +
  89 +struct arvo_device {
  90 + int roccat_claimed;
  91 + int chrdev_minor;
  92 +
  93 + struct mutex arvo_lock;
  94 +
  95 + int actual_profile;
  96 +};
  97 +
  98 +#endif