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

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

DEFINITIONS

This source file includes following definitions.
  1. savu_init_specials
  2. savu_remove_specials
  3. savu_probe
  4. savu_remove
  5. savu_report_to_chrdev
  6. savu_raw_event
  7. savu_init
  8. savu_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Roccat Savu driver for Linux
   4  *
   5  * Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net>
   6  */
   7 
   8 /*
   9  */
  10 
  11 /* Roccat Savu is a gamer mouse with macro keys that can be configured in
  12  * 5 profiles.
  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-savu.h"
  24 
  25 static struct class *savu_class;
  26 
  27 ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x4, 0x03);
  28 ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x5, 0x03);
  29 ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(general, 0x6, 0x10);
  30 ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(buttons, 0x7, 0x2f);
  31 ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(macro, 0x8, 0x0823);
  32 ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(info, 0x9, 0x08);
  33 ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(sensor, 0xc, 0x04);
  34 
  35 static struct bin_attribute *savu_bin_attrs[] = {
  36         &bin_attr_control,
  37         &bin_attr_profile,
  38         &bin_attr_general,
  39         &bin_attr_buttons,
  40         &bin_attr_macro,
  41         &bin_attr_info,
  42         &bin_attr_sensor,
  43         NULL,
  44 };
  45 
  46 static const struct attribute_group savu_group = {
  47         .bin_attrs = savu_bin_attrs,
  48 };
  49 
  50 static const struct attribute_group *savu_groups[] = {
  51         &savu_group,
  52         NULL,
  53 };
  54 
  55 static int savu_init_specials(struct hid_device *hdev)
  56 {
  57         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  58         struct usb_device *usb_dev = interface_to_usbdev(intf);
  59         struct roccat_common2_device *savu;
  60         int retval;
  61 
  62         if (intf->cur_altsetting->desc.bInterfaceProtocol
  63                         != USB_INTERFACE_PROTOCOL_MOUSE) {
  64                 hid_set_drvdata(hdev, NULL);
  65                 return 0;
  66         }
  67 
  68         savu = kzalloc(sizeof(*savu), GFP_KERNEL);
  69         if (!savu) {
  70                 hid_err(hdev, "can't alloc device descriptor\n");
  71                 return -ENOMEM;
  72         }
  73         hid_set_drvdata(hdev, savu);
  74 
  75         retval = roccat_common2_device_init_struct(usb_dev, savu);
  76         if (retval) {
  77                 hid_err(hdev, "couldn't init Savu device\n");
  78                 goto exit_free;
  79         }
  80 
  81         retval = roccat_connect(savu_class, hdev,
  82                         sizeof(struct savu_roccat_report));
  83         if (retval < 0) {
  84                 hid_err(hdev, "couldn't init char dev\n");
  85         } else {
  86                 savu->chrdev_minor = retval;
  87                 savu->roccat_claimed = 1;
  88         }
  89 
  90         return 0;
  91 exit_free:
  92         kfree(savu);
  93         return retval;
  94 }
  95 
  96 static void savu_remove_specials(struct hid_device *hdev)
  97 {
  98         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  99         struct roccat_common2_device *savu;
 100 
 101         if (intf->cur_altsetting->desc.bInterfaceProtocol
 102                         != USB_INTERFACE_PROTOCOL_MOUSE)
 103                 return;
 104 
 105         savu = hid_get_drvdata(hdev);
 106         if (savu->roccat_claimed)
 107                 roccat_disconnect(savu->chrdev_minor);
 108         kfree(savu);
 109 }
 110 
 111 static int savu_probe(struct hid_device *hdev,
 112                 const struct hid_device_id *id)
 113 {
 114         int retval;
 115 
 116         retval = hid_parse(hdev);
 117         if (retval) {
 118                 hid_err(hdev, "parse failed\n");
 119                 goto exit;
 120         }
 121 
 122         retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 123         if (retval) {
 124                 hid_err(hdev, "hw start failed\n");
 125                 goto exit;
 126         }
 127 
 128         retval = savu_init_specials(hdev);
 129         if (retval) {
 130                 hid_err(hdev, "couldn't install mouse\n");
 131                 goto exit_stop;
 132         }
 133 
 134         return 0;
 135 
 136 exit_stop:
 137         hid_hw_stop(hdev);
 138 exit:
 139         return retval;
 140 }
 141 
 142 static void savu_remove(struct hid_device *hdev)
 143 {
 144         savu_remove_specials(hdev);
 145         hid_hw_stop(hdev);
 146 }
 147 
 148 static void savu_report_to_chrdev(struct roccat_common2_device const *savu,
 149                 u8 const *data)
 150 {
 151         struct savu_roccat_report roccat_report;
 152         struct savu_mouse_report_special const *special_report;
 153 
 154         if (data[0] != SAVU_MOUSE_REPORT_NUMBER_SPECIAL)
 155                 return;
 156 
 157         special_report = (struct savu_mouse_report_special const *)data;
 158 
 159         roccat_report.type = special_report->type;
 160         roccat_report.data[0] = special_report->data[0];
 161         roccat_report.data[1] = special_report->data[1];
 162         roccat_report_event(savu->chrdev_minor,
 163                         (uint8_t const *)&roccat_report);
 164 }
 165 
 166 static int savu_raw_event(struct hid_device *hdev,
 167                 struct hid_report *report, u8 *data, int size)
 168 {
 169         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 170         struct roccat_common2_device *savu = hid_get_drvdata(hdev);
 171 
 172         if (intf->cur_altsetting->desc.bInterfaceProtocol
 173                         != USB_INTERFACE_PROTOCOL_MOUSE)
 174                 return 0;
 175 
 176         if (savu == NULL)
 177                 return 0;
 178 
 179         if (savu->roccat_claimed)
 180                 savu_report_to_chrdev(savu, data);
 181 
 182         return 0;
 183 }
 184 
 185 static const struct hid_device_id savu_devices[] = {
 186         { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
 187         { }
 188 };
 189 
 190 MODULE_DEVICE_TABLE(hid, savu_devices);
 191 
 192 static struct hid_driver savu_driver = {
 193                 .name = "savu",
 194                 .id_table = savu_devices,
 195                 .probe = savu_probe,
 196                 .remove = savu_remove,
 197                 .raw_event = savu_raw_event
 198 };
 199 
 200 static int __init savu_init(void)
 201 {
 202         int retval;
 203 
 204         savu_class = class_create(THIS_MODULE, "savu");
 205         if (IS_ERR(savu_class))
 206                 return PTR_ERR(savu_class);
 207         savu_class->dev_groups = savu_groups;
 208 
 209         retval = hid_register_driver(&savu_driver);
 210         if (retval)
 211                 class_destroy(savu_class);
 212         return retval;
 213 }
 214 
 215 static void __exit savu_exit(void)
 216 {
 217         hid_unregister_driver(&savu_driver);
 218         class_destroy(savu_class);
 219 }
 220 
 221 module_init(savu_init);
 222 module_exit(savu_exit);
 223 
 224 MODULE_AUTHOR("Stefan Achatz");
 225 MODULE_DESCRIPTION("USB Roccat Savu driver");
 226 MODULE_LICENSE("GPL v2");

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