root/drivers/hid/hid-roccat-kovaplus.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kovaplus_convert_event_cpi
  2. kovaplus_profile_activated
  3. kovaplus_send_control
  4. kovaplus_select_profile
  5. kovaplus_get_profile_settings
  6. kovaplus_get_profile_buttons
  7. kovaplus_get_actual_profile
  8. kovaplus_set_actual_profile
  9. kovaplus_sysfs_read
  10. kovaplus_sysfs_write
  11. kovaplus_sysfs_read_profilex_settings
  12. kovaplus_sysfs_read_profilex_buttons
  13. kovaplus_sysfs_show_actual_profile
  14. kovaplus_sysfs_set_actual_profile
  15. kovaplus_sysfs_show_actual_cpi
  16. kovaplus_sysfs_show_actual_sensitivity_x
  17. kovaplus_sysfs_show_actual_sensitivity_y
  18. kovaplus_sysfs_show_firmware_version
  19. kovaplus_init_kovaplus_device_struct
  20. kovaplus_init_specials
  21. kovaplus_remove_specials
  22. kovaplus_probe
  23. kovaplus_remove
  24. kovaplus_keep_values_up_to_date
  25. kovaplus_report_to_chrdev
  26. kovaplus_raw_event
  27. kovaplus_init
  28. kovaplus_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Roccat Kova[+] driver for Linux
   4  *
   5  * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
   6  */
   7 
   8 /*
   9  */
  10 
  11 /*
  12  * Roccat Kova[+] is a bigger version of the Pyra with two more side buttons.
  13  */
  14 
  15 #include <linux/device.h>
  16 #include <linux/input.h>
  17 #include <linux/hid.h>
  18 #include <linux/module.h>
  19 #include <linux/slab.h>
  20 #include <linux/hid-roccat.h>
  21 #include "hid-ids.h"
  22 #include "hid-roccat-common.h"
  23 #include "hid-roccat-kovaplus.h"
  24 
  25 static uint profile_numbers[5] = {0, 1, 2, 3, 4};
  26 
  27 static struct class *kovaplus_class;
  28 
  29 static uint kovaplus_convert_event_cpi(uint value)
  30 {
  31         return (value == 7 ? 4 : (value == 4 ? 3 : value));
  32 }
  33 
  34 static void kovaplus_profile_activated(struct kovaplus_device *kovaplus,
  35                 uint new_profile_index)
  36 {
  37         if (new_profile_index >= ARRAY_SIZE(kovaplus->profile_settings))
  38                 return;
  39         kovaplus->actual_profile = new_profile_index;
  40         kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level;
  41         kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x;
  42         kovaplus->actual_y_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_y;
  43 }
  44 
  45 static int kovaplus_send_control(struct usb_device *usb_dev, uint value,
  46                 enum kovaplus_control_requests request)
  47 {
  48         int retval;
  49         struct roccat_common2_control control;
  50 
  51         if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
  52                         request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
  53                         value > 4)
  54                 return -EINVAL;
  55 
  56         control.command = ROCCAT_COMMON_COMMAND_CONTROL;
  57         control.value = value;
  58         control.request = request;
  59 
  60         retval = roccat_common2_send(usb_dev, ROCCAT_COMMON_COMMAND_CONTROL,
  61                         &control, sizeof(struct roccat_common2_control));
  62 
  63         return retval;
  64 }
  65 
  66 static int kovaplus_select_profile(struct usb_device *usb_dev, uint number,
  67                 enum kovaplus_control_requests request)
  68 {
  69         return kovaplus_send_control(usb_dev, number, request);
  70 }
  71 
  72 static int kovaplus_get_profile_settings(struct usb_device *usb_dev,
  73                 struct kovaplus_profile_settings *buf, uint number)
  74 {
  75         int retval;
  76 
  77         retval = kovaplus_select_profile(usb_dev, number,
  78                         KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
  79         if (retval)
  80                 return retval;
  81 
  82         return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS,
  83                         buf, KOVAPLUS_SIZE_PROFILE_SETTINGS);
  84 }
  85 
  86 static int kovaplus_get_profile_buttons(struct usb_device *usb_dev,
  87                 struct kovaplus_profile_buttons *buf, int number)
  88 {
  89         int retval;
  90 
  91         retval = kovaplus_select_profile(usb_dev, number,
  92                         KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
  93         if (retval)
  94                 return retval;
  95 
  96         return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS,
  97                         buf, KOVAPLUS_SIZE_PROFILE_BUTTONS);
  98 }
  99 
 100 /* retval is 0-4 on success, < 0 on error */
 101 static int kovaplus_get_actual_profile(struct usb_device *usb_dev)
 102 {
 103         struct kovaplus_actual_profile buf;
 104         int retval;
 105 
 106         retval = roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE,
 107                         &buf, sizeof(struct kovaplus_actual_profile));
 108 
 109         return retval ? retval : buf.actual_profile;
 110 }
 111 
 112 static int kovaplus_set_actual_profile(struct usb_device *usb_dev,
 113                 int new_profile)
 114 {
 115         struct kovaplus_actual_profile buf;
 116 
 117         buf.command = KOVAPLUS_COMMAND_ACTUAL_PROFILE;
 118         buf.size = sizeof(struct kovaplus_actual_profile);
 119         buf.actual_profile = new_profile;
 120 
 121         return roccat_common2_send_with_status(usb_dev,
 122                         KOVAPLUS_COMMAND_ACTUAL_PROFILE,
 123                         &buf, sizeof(struct kovaplus_actual_profile));
 124 }
 125 
 126 static ssize_t kovaplus_sysfs_read(struct file *fp, struct kobject *kobj,
 127                 char *buf, loff_t off, size_t count,
 128                 size_t real_size, uint command)
 129 {
 130         struct device *dev = kobj_to_dev(kobj)->parent->parent;
 131         struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 132         struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 133         int retval;
 134 
 135         if (off >= real_size)
 136                 return 0;
 137 
 138         if (off != 0 || count != real_size)
 139                 return -EINVAL;
 140 
 141         mutex_lock(&kovaplus->kovaplus_lock);
 142         retval = roccat_common2_receive(usb_dev, command, buf, real_size);
 143         mutex_unlock(&kovaplus->kovaplus_lock);
 144 
 145         if (retval)
 146                 return retval;
 147 
 148         return real_size;
 149 }
 150 
 151 static ssize_t kovaplus_sysfs_write(struct file *fp, struct kobject *kobj,
 152                 void const *buf, loff_t off, size_t count,
 153                 size_t real_size, uint command)
 154 {
 155         struct device *dev = kobj_to_dev(kobj)->parent->parent;
 156         struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 157         struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 158         int retval;
 159 
 160         if (off != 0 || count != real_size)
 161                 return -EINVAL;
 162 
 163         mutex_lock(&kovaplus->kovaplus_lock);
 164         retval = roccat_common2_send_with_status(usb_dev, command,
 165                         buf, real_size);
 166         mutex_unlock(&kovaplus->kovaplus_lock);
 167 
 168         if (retval)
 169                 return retval;
 170 
 171         return real_size;
 172 }
 173 
 174 #define KOVAPLUS_SYSFS_W(thingy, THINGY) \
 175 static ssize_t kovaplus_sysfs_write_ ## thingy(struct file *fp, \
 176                 struct kobject *kobj, struct bin_attribute *attr, char *buf, \
 177                 loff_t off, size_t count) \
 178 { \
 179         return kovaplus_sysfs_write(fp, kobj, buf, off, count, \
 180                         KOVAPLUS_SIZE_ ## THINGY, KOVAPLUS_COMMAND_ ## THINGY); \
 181 }
 182 
 183 #define KOVAPLUS_SYSFS_R(thingy, THINGY) \
 184 static ssize_t kovaplus_sysfs_read_ ## thingy(struct file *fp, \
 185                 struct kobject *kobj, struct bin_attribute *attr, char *buf, \
 186                 loff_t off, size_t count) \
 187 { \
 188         return kovaplus_sysfs_read(fp, kobj, buf, off, count, \
 189                         KOVAPLUS_SIZE_ ## THINGY, KOVAPLUS_COMMAND_ ## THINGY); \
 190 }
 191 
 192 #define KOVAPLUS_SYSFS_RW(thingy, THINGY) \
 193 KOVAPLUS_SYSFS_W(thingy, THINGY) \
 194 KOVAPLUS_SYSFS_R(thingy, THINGY)
 195 
 196 #define KOVAPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
 197 KOVAPLUS_SYSFS_RW(thingy, THINGY); \
 198 static struct bin_attribute bin_attr_##thingy = { \
 199         .attr = { .name = #thingy, .mode = 0660 }, \
 200         .size = KOVAPLUS_SIZE_ ## THINGY, \
 201         .read = kovaplus_sysfs_read_ ## thingy, \
 202         .write = kovaplus_sysfs_write_ ## thingy \
 203 }
 204 
 205 #define KOVAPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
 206 KOVAPLUS_SYSFS_W(thingy, THINGY); \
 207 static struct bin_attribute bin_attr_##thingy = { \
 208         .attr = { .name = #thingy, .mode = 0220 }, \
 209         .size = KOVAPLUS_SIZE_ ## THINGY, \
 210         .write = kovaplus_sysfs_write_ ## thingy \
 211 }
 212 KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
 213 KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO);
 214 KOVAPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
 215 KOVAPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
 216 
 217 static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
 218                 struct kobject *kobj, struct bin_attribute *attr, char *buf,
 219                 loff_t off, size_t count)
 220 {
 221         struct device *dev = kobj_to_dev(kobj)->parent->parent;
 222         struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 223         ssize_t retval;
 224 
 225         retval = kovaplus_select_profile(usb_dev, *(uint *)(attr->private),
 226                         KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
 227         if (retval)
 228                 return retval;
 229 
 230         return kovaplus_sysfs_read(fp, kobj, buf, off, count,
 231                         KOVAPLUS_SIZE_PROFILE_SETTINGS,
 232                         KOVAPLUS_COMMAND_PROFILE_SETTINGS);
 233 }
 234 
 235 static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
 236                 struct kobject *kobj, struct bin_attribute *attr, char *buf,
 237                 loff_t off, size_t count)
 238 {
 239         struct device *dev = kobj_to_dev(kobj)->parent->parent;
 240         struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 241         ssize_t retval;
 242 
 243         retval = kovaplus_select_profile(usb_dev, *(uint *)(attr->private),
 244                         KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
 245         if (retval)
 246                 return retval;
 247 
 248         return kovaplus_sysfs_read(fp, kobj, buf, off, count,
 249                         KOVAPLUS_SIZE_PROFILE_BUTTONS,
 250                         KOVAPLUS_COMMAND_PROFILE_BUTTONS);
 251 }
 252 
 253 #define PROFILE_ATTR(number)                                            \
 254 static struct bin_attribute bin_attr_profile##number##_settings = {     \
 255         .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
 256         .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,                         \
 257         .read = kovaplus_sysfs_read_profilex_settings,                  \
 258         .private = &profile_numbers[number-1],                          \
 259 };                                                                      \
 260 static struct bin_attribute bin_attr_profile##number##_buttons = {      \
 261         .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
 262         .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,                          \
 263         .read = kovaplus_sysfs_read_profilex_buttons,                   \
 264         .private = &profile_numbers[number-1],                          \
 265 };
 266 PROFILE_ATTR(1);
 267 PROFILE_ATTR(2);
 268 PROFILE_ATTR(3);
 269 PROFILE_ATTR(4);
 270 PROFILE_ATTR(5);
 271 
 272 static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev,
 273                 struct device_attribute *attr, char *buf)
 274 {
 275         struct kovaplus_device *kovaplus =
 276                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 277         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_profile);
 278 }
 279 
 280 static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
 281                 struct device_attribute *attr, char const *buf, size_t size)
 282 {
 283         struct kovaplus_device *kovaplus;
 284         struct usb_device *usb_dev;
 285         unsigned long profile;
 286         int retval;
 287         struct kovaplus_roccat_report roccat_report;
 288 
 289         dev = dev->parent->parent;
 290         kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 291         usb_dev = interface_to_usbdev(to_usb_interface(dev));
 292 
 293         retval = kstrtoul(buf, 10, &profile);
 294         if (retval)
 295                 return retval;
 296 
 297         if (profile >= 5)
 298                 return -EINVAL;
 299 
 300         mutex_lock(&kovaplus->kovaplus_lock);
 301         retval = kovaplus_set_actual_profile(usb_dev, profile);
 302         if (retval) {
 303                 mutex_unlock(&kovaplus->kovaplus_lock);
 304                 return retval;
 305         }
 306 
 307         kovaplus_profile_activated(kovaplus, profile);
 308 
 309         roccat_report.type = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1;
 310         roccat_report.profile = profile + 1;
 311         roccat_report.button = 0;
 312         roccat_report.data1 = profile + 1;
 313         roccat_report.data2 = 0;
 314         roccat_report_event(kovaplus->chrdev_minor,
 315                         (uint8_t const *)&roccat_report);
 316 
 317         mutex_unlock(&kovaplus->kovaplus_lock);
 318 
 319         return size;
 320 }
 321 static DEVICE_ATTR(actual_profile, 0660,
 322                    kovaplus_sysfs_show_actual_profile,
 323                    kovaplus_sysfs_set_actual_profile);
 324 
 325 static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev,
 326                 struct device_attribute *attr, char *buf)
 327 {
 328         struct kovaplus_device *kovaplus =
 329                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 330         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi);
 331 }
 332 static DEVICE_ATTR(actual_cpi, 0440, kovaplus_sysfs_show_actual_cpi, NULL);
 333 
 334 static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev,
 335                 struct device_attribute *attr, char *buf)
 336 {
 337         struct kovaplus_device *kovaplus =
 338                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 339         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity);
 340 }
 341 static DEVICE_ATTR(actual_sensitivity_x, 0440,
 342                    kovaplus_sysfs_show_actual_sensitivity_x, NULL);
 343 
 344 static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
 345                 struct device_attribute *attr, char *buf)
 346 {
 347         struct kovaplus_device *kovaplus =
 348                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 349         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity);
 350 }
 351 static DEVICE_ATTR(actual_sensitivity_y, 0440,
 352                    kovaplus_sysfs_show_actual_sensitivity_y, NULL);
 353 
 354 static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
 355                 struct device_attribute *attr, char *buf)
 356 {
 357         struct kovaplus_device *kovaplus;
 358         struct usb_device *usb_dev;
 359         struct kovaplus_info info;
 360 
 361         dev = dev->parent->parent;
 362         kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
 363         usb_dev = interface_to_usbdev(to_usb_interface(dev));
 364 
 365         mutex_lock(&kovaplus->kovaplus_lock);
 366         roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_INFO,
 367                         &info, KOVAPLUS_SIZE_INFO);
 368         mutex_unlock(&kovaplus->kovaplus_lock);
 369 
 370         return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
 371 }
 372 static DEVICE_ATTR(firmware_version, 0440,
 373                    kovaplus_sysfs_show_firmware_version, NULL);
 374 
 375 static struct attribute *kovaplus_attrs[] = {
 376         &dev_attr_actual_cpi.attr,
 377         &dev_attr_firmware_version.attr,
 378         &dev_attr_actual_profile.attr,
 379         &dev_attr_actual_sensitivity_x.attr,
 380         &dev_attr_actual_sensitivity_y.attr,
 381         NULL,
 382 };
 383 
 384 static struct bin_attribute *kovaplus_bin_attributes[] = {
 385         &bin_attr_control,
 386         &bin_attr_info,
 387         &bin_attr_profile_settings,
 388         &bin_attr_profile_buttons,
 389         &bin_attr_profile1_settings,
 390         &bin_attr_profile2_settings,
 391         &bin_attr_profile3_settings,
 392         &bin_attr_profile4_settings,
 393         &bin_attr_profile5_settings,
 394         &bin_attr_profile1_buttons,
 395         &bin_attr_profile2_buttons,
 396         &bin_attr_profile3_buttons,
 397         &bin_attr_profile4_buttons,
 398         &bin_attr_profile5_buttons,
 399         NULL,
 400 };
 401 
 402 static const struct attribute_group kovaplus_group = {
 403         .attrs = kovaplus_attrs,
 404         .bin_attrs = kovaplus_bin_attributes,
 405 };
 406 
 407 static const struct attribute_group *kovaplus_groups[] = {
 408         &kovaplus_group,
 409         NULL,
 410 };
 411 
 412 static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
 413                 struct kovaplus_device *kovaplus)
 414 {
 415         int retval, i;
 416         static uint wait = 70; /* device will freeze with just 60 */
 417 
 418         mutex_init(&kovaplus->kovaplus_lock);
 419 
 420         for (i = 0; i < 5; ++i) {
 421                 msleep(wait);
 422                 retval = kovaplus_get_profile_settings(usb_dev,
 423                                 &kovaplus->profile_settings[i], i);
 424                 if (retval)
 425                         return retval;
 426 
 427                 msleep(wait);
 428                 retval = kovaplus_get_profile_buttons(usb_dev,
 429                                 &kovaplus->profile_buttons[i], i);
 430                 if (retval)
 431                         return retval;
 432         }
 433 
 434         msleep(wait);
 435         retval = kovaplus_get_actual_profile(usb_dev);
 436         if (retval < 0)
 437                 return retval;
 438         kovaplus_profile_activated(kovaplus, retval);
 439 
 440         return 0;
 441 }
 442 
 443 static int kovaplus_init_specials(struct hid_device *hdev)
 444 {
 445         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 446         struct usb_device *usb_dev = interface_to_usbdev(intf);
 447         struct kovaplus_device *kovaplus;
 448         int retval;
 449 
 450         if (intf->cur_altsetting->desc.bInterfaceProtocol
 451                         == USB_INTERFACE_PROTOCOL_MOUSE) {
 452 
 453                 kovaplus = kzalloc(sizeof(*kovaplus), GFP_KERNEL);
 454                 if (!kovaplus) {
 455                         hid_err(hdev, "can't alloc device descriptor\n");
 456                         return -ENOMEM;
 457                 }
 458                 hid_set_drvdata(hdev, kovaplus);
 459 
 460                 retval = kovaplus_init_kovaplus_device_struct(usb_dev, kovaplus);
 461                 if (retval) {
 462                         hid_err(hdev, "couldn't init struct kovaplus_device\n");
 463                         goto exit_free;
 464                 }
 465 
 466                 retval = roccat_connect(kovaplus_class, hdev,
 467                                 sizeof(struct kovaplus_roccat_report));
 468                 if (retval < 0) {
 469                         hid_err(hdev, "couldn't init char dev\n");
 470                 } else {
 471                         kovaplus->chrdev_minor = retval;
 472                         kovaplus->roccat_claimed = 1;
 473                 }
 474 
 475         } else {
 476                 hid_set_drvdata(hdev, NULL);
 477         }
 478 
 479         return 0;
 480 exit_free:
 481         kfree(kovaplus);
 482         return retval;
 483 }
 484 
 485 static void kovaplus_remove_specials(struct hid_device *hdev)
 486 {
 487         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 488         struct kovaplus_device *kovaplus;
 489 
 490         if (intf->cur_altsetting->desc.bInterfaceProtocol
 491                         == USB_INTERFACE_PROTOCOL_MOUSE) {
 492                 kovaplus = hid_get_drvdata(hdev);
 493                 if (kovaplus->roccat_claimed)
 494                         roccat_disconnect(kovaplus->chrdev_minor);
 495                 kfree(kovaplus);
 496         }
 497 }
 498 
 499 static int kovaplus_probe(struct hid_device *hdev,
 500                 const struct hid_device_id *id)
 501 {
 502         int retval;
 503 
 504         retval = hid_parse(hdev);
 505         if (retval) {
 506                 hid_err(hdev, "parse failed\n");
 507                 goto exit;
 508         }
 509 
 510         retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 511         if (retval) {
 512                 hid_err(hdev, "hw start failed\n");
 513                 goto exit;
 514         }
 515 
 516         retval = kovaplus_init_specials(hdev);
 517         if (retval) {
 518                 hid_err(hdev, "couldn't install mouse\n");
 519                 goto exit_stop;
 520         }
 521 
 522         return 0;
 523 
 524 exit_stop:
 525         hid_hw_stop(hdev);
 526 exit:
 527         return retval;
 528 }
 529 
 530 static void kovaplus_remove(struct hid_device *hdev)
 531 {
 532         kovaplus_remove_specials(hdev);
 533         hid_hw_stop(hdev);
 534 }
 535 
 536 static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus,
 537                 u8 const *data)
 538 {
 539         struct kovaplus_mouse_report_button const *button_report;
 540 
 541         if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
 542                 return;
 543 
 544         button_report = (struct kovaplus_mouse_report_button const *)data;
 545 
 546         switch (button_report->type) {
 547         case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1:
 548                 kovaplus_profile_activated(kovaplus, button_report->data1 - 1);
 549                 break;
 550         case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI:
 551                 kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1);
 552                 break;
 553         case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY:
 554                 kovaplus->actual_x_sensitivity = button_report->data1;
 555                 kovaplus->actual_y_sensitivity = button_report->data2;
 556                 break;
 557         default:
 558                 break;
 559         }
 560 }
 561 
 562 static void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus,
 563                 u8 const *data)
 564 {
 565         struct kovaplus_roccat_report roccat_report;
 566         struct kovaplus_mouse_report_button const *button_report;
 567 
 568         if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
 569                 return;
 570 
 571         button_report = (struct kovaplus_mouse_report_button const *)data;
 572 
 573         if (button_report->type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2)
 574                 return;
 575 
 576         roccat_report.type = button_report->type;
 577         roccat_report.profile = kovaplus->actual_profile + 1;
 578 
 579         if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO ||
 580                         roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT ||
 581                         roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
 582                         roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER)
 583                 roccat_report.button = button_report->data1;
 584         else
 585                 roccat_report.button = 0;
 586 
 587         if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI)
 588                 roccat_report.data1 = kovaplus_convert_event_cpi(button_report->data1);
 589         else
 590                 roccat_report.data1 = button_report->data1;
 591 
 592         roccat_report.data2 = button_report->data2;
 593 
 594         roccat_report_event(kovaplus->chrdev_minor,
 595                         (uint8_t const *)&roccat_report);
 596 }
 597 
 598 static int kovaplus_raw_event(struct hid_device *hdev,
 599                 struct hid_report *report, u8 *data, int size)
 600 {
 601         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 602         struct kovaplus_device *kovaplus = hid_get_drvdata(hdev);
 603 
 604         if (intf->cur_altsetting->desc.bInterfaceProtocol
 605                         != USB_INTERFACE_PROTOCOL_MOUSE)
 606                 return 0;
 607 
 608         if (kovaplus == NULL)
 609                 return 0;
 610 
 611         kovaplus_keep_values_up_to_date(kovaplus, data);
 612 
 613         if (kovaplus->roccat_claimed)
 614                 kovaplus_report_to_chrdev(kovaplus, data);
 615 
 616         return 0;
 617 }
 618 
 619 static const struct hid_device_id kovaplus_devices[] = {
 620         { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
 621         { }
 622 };
 623 
 624 MODULE_DEVICE_TABLE(hid, kovaplus_devices);
 625 
 626 static struct hid_driver kovaplus_driver = {
 627                 .name = "kovaplus",
 628                 .id_table = kovaplus_devices,
 629                 .probe = kovaplus_probe,
 630                 .remove = kovaplus_remove,
 631                 .raw_event = kovaplus_raw_event
 632 };
 633 
 634 static int __init kovaplus_init(void)
 635 {
 636         int retval;
 637 
 638         kovaplus_class = class_create(THIS_MODULE, "kovaplus");
 639         if (IS_ERR(kovaplus_class))
 640                 return PTR_ERR(kovaplus_class);
 641         kovaplus_class->dev_groups = kovaplus_groups;
 642 
 643         retval = hid_register_driver(&kovaplus_driver);
 644         if (retval)
 645                 class_destroy(kovaplus_class);
 646         return retval;
 647 }
 648 
 649 static void __exit kovaplus_exit(void)
 650 {
 651         hid_unregister_driver(&kovaplus_driver);
 652         class_destroy(kovaplus_class);
 653 }
 654 
 655 module_init(kovaplus_init);
 656 module_exit(kovaplus_exit);
 657 
 658 MODULE_AUTHOR("Stefan Achatz");
 659 MODULE_DESCRIPTION("USB Roccat Kova[+] driver");
 660 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */