aboutsummaryrefslogtreecommitdiffstats
path: root/src/kernel/hid-lg-g710-plus.c
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2015-12-27 21:11:21 -0500
committerClyne Sullivan <tullivan99@gmail.com>2015-12-27 21:11:21 -0500
commitaa9b93ac71abd98b2058258fc0514ed122a52ceb (patch)
treecbc82213f5536a9f0ce31c75f95371cb3d9a8ecc /src/kernel/hid-lg-g710-plus.c
parentecd2099065b48e7b365ebb30620ee3429eb39287 (diff)
changed M key functionHEADmaster
Diffstat (limited to 'src/kernel/hid-lg-g710-plus.c')
-rw-r--r--src/kernel/hid-lg-g710-plus.c358
1 files changed, 0 insertions, 358 deletions
diff --git a/src/kernel/hid-lg-g710-plus.c b/src/kernel/hid-lg-g710-plus.c
deleted file mode 100644
index a0db963..0000000
--- a/src/kernel/hid-lg-g710-plus.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Logitech G710+ Keyboard Input Driver
- *
- * Driver generates additional key events for the keys M1-MR, G1-G6
- * and supports setting the backlight levels of the keyboard
- *
- * Copyright (c) 2013 Filip Wieladke <Wattos@gmail.com>
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/hid.h>
-#include <linux/input.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/version.h>
-
-#include "hid-ids.h"
-#include "usbhid/usbhid.h"
-
-#define USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS 0xc24d
-
-// 20 seeconds timeout
-#define WAIT_TIME_OUT 20000
-
-#define LOGITECH_KEY_MAP_SIZE 16
-
-static const u8 g710_plus_key_map[LOGITECH_KEY_MAP_SIZE] = {
- 0, /* unused */
- 0, /* unused */
- 0, /* unused */
- 0, /* unused */
- KEY_F13, /* M1 */
- KEY_F14, /* M2 */
- KEY_F15, /* M3 */
- KEY_F16, /* MR */
- KEY_F17, /* G1 */
- KEY_F18, /* G2 */
- KEY_F19, /* G3 */
- KEY_F20, /* G4 */
- KEY_F21, /* G5 */
- KEY_F22, /* G6 */
- 0, /* unused */
- 0, /* unused */
-};
-
-/* Convenience macros */
-#define lg_g710_plus_get_data(hdev) \
- ((struct lg_g710_plus_data *)(hid_get_drvdata(hdev)))
-
-#define BIT_AT(var,pos) ((var) & (1<<(pos)))
-
-struct lg_g710_plus_data {
- struct hid_report *g_mr_buttons_support_report; /* Needs to be written to enable G1-G6 and M1-MR keys */
- struct hid_report *mr_buttons_led_report; /* Controls the backlight of M1-MR buttons */
- struct hid_report *other_buttons_led_report; /* Controls the backlight of other buttons */
- struct hid_report *gamemode_report; /* Controls the backlight of other buttons */
-
- u16 macro_button_state; /* Holds the last state of the G1-G6, M1-MR buttons. Required to know which buttons were pressed and which were released */
- struct hid_device *hdev;
- struct input_dev *input_dev;
- struct attribute_group attr_group;
-
- u8 led_macro; /* state of the M1-MR macro leds as returned by the keyboard ==> binary coded 0 -> 0xF*/
- u8 led_keys; /* state of the WASD key leds as returned by the keyboard ==> 0 -> 4 */
-
- spinlock_t lock; /* lock for communication with user space */
- struct completion ready; /* ready indicator */
-};
-
-static ssize_t lg_g710_plus_show_led_macro(struct device *device, struct device_attribute *attr, char *buf);
-static ssize_t lg_g710_plus_store_led_macro(struct device *device, struct device_attribute *attr, const char *buf, size_t count);
-static ssize_t lg_g710_plus_show_led_keys(struct device *device, struct device_attribute *attr, char *buf);
-static ssize_t lg_g710_plus_store_led_keys(struct device *device, struct device_attribute *attr, const char *buf, size_t count);
-
-static DEVICE_ATTR(led_macro, 0660, lg_g710_plus_show_led_macro, lg_g710_plus_store_led_macro);
-static DEVICE_ATTR(led_keys, 0660, lg_g710_plus_show_led_keys, lg_g710_plus_store_led_keys);
-
-static struct attribute *lg_g710_plus_attrs[] = {
- &dev_attr_led_macro.attr,
- &dev_attr_led_keys.attr,
- NULL,
-};
-
-static int lg_g710_plus_extra_key_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) {
- u8 i;
- u16 keys_pressed;
- struct lg_g710_plus_data* g710_data = lg_g710_plus_get_data(hdev);
- if (g710_data == NULL || size < 3 || data[0] != 3) {
- return 1; /* cannot handle the event */
- }
-
- keys_pressed= data[1] << 8 | data[2];
- for (i = 0; i < LOGITECH_KEY_MAP_SIZE; i++) {
- if (g710_plus_key_map[i] != 0 && (BIT_AT(keys_pressed, i) != BIT_AT(g710_data->macro_button_state, i))) {
- input_report_key(g710_data->input_dev, g710_plus_key_map[i], BIT_AT(keys_pressed, i) != 0);
- }
- }
- input_sync(g710_data->input_dev);
- g710_data->macro_button_state= keys_pressed;
- return 1;
-}
-
-static int lg_g710_plus_extra_led_mr_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) {
- struct lg_g710_plus_data* g710_data = lg_g710_plus_get_data(hdev);
- g710_data->led_macro= (data[1] >> 4) & 0xF;
- complete_all(&g710_data->ready);
- return 1;
-}
-
-static int lg_g710_plus_extra_led_keys_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) {
- struct lg_g710_plus_data* g710_data = lg_g710_plus_get_data(hdev);
- g710_data->led_keys= data[1] << 4 | data[2];
- complete_all(&g710_data->ready);
- return 1;
-}
-
-static int lg_g710_plus_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size)
-{
- switch(report->id) {
- case 3: return lg_g710_plus_extra_key_event(hdev, report, data, size);
- case 6: return lg_g710_plus_extra_led_mr_event(hdev, report, data, size);
- case 8: return lg_g710_plus_extra_led_keys_event(hdev, report, data, size);
- default: return 0;
- }
-}
-
-static int lg_g710_plus_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max)
-{
- struct lg_g710_plus_data* data = lg_g710_plus_get_data(hdev);
- if (data != NULL && data->input_dev == NULL) {
- data->input_dev= hi->input;
- }
- return 0;
-}
-
-enum req_type {
- REQTYPE_READ,
- REQTYPE_WRITE
-};
-
-static void hidhw_request(struct hid_device *hdev, struct hid_report *report, enum req_type reqtype) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
- hid_hw_request(hdev, report, reqtype == REQTYPE_READ ? HID_REQ_GET_REPORT : HID_REQ_SET_REPORT);
-#else
- usbhid_submit_report(hdev, report, reqtype == REQTYPE_READ ? USB_DIR_IN : USB_DIR_OUT);
-#endif
-}
-
-static int lg_g710_plus_initialize(struct hid_device *hdev) {
- int ret = 0;
- struct lg_g710_plus_data *data;
- struct list_head *feature_report_list = &hdev->report_enum[HID_FEATURE_REPORT].report_list;
- struct hid_report *report;
-
- if (list_empty(feature_report_list)) {
- return 0; /* Currently, the keyboard registers as two different devices */
- }
-
- data = lg_g710_plus_get_data(hdev);
- list_for_each_entry(report, feature_report_list, list) {
- switch(report->id) {
- case 6: data->mr_buttons_led_report= report; break;
- case 8: data->other_buttons_led_report= report; break;
- case 9:
- data->g_mr_buttons_support_report= report;
- hidhw_request(hdev, report, REQTYPE_WRITE);
- break;
- }
- }
-
- ret= sysfs_create_group(&hdev->dev.kobj, &data->attr_group);
- return ret;
-}
-
-static struct lg_g710_plus_data* lg_g710_plus_create(struct hid_device *hdev)
-{
- struct lg_g710_plus_data* data;
- data= kzalloc(sizeof(struct lg_g710_plus_data), GFP_KERNEL);
- if (data == NULL) {
- return NULL;
- }
-
- data->attr_group.name= "logitech-g710";
- data->attr_group.attrs= lg_g710_plus_attrs;
- data->hdev= hdev;
-
- spin_lock_init(&data->lock);
- init_completion(&data->ready);
- return data;
-}
-
-static int lg_g710_plus_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- int ret;
- struct lg_g710_plus_data *data;
-
- data = lg_g710_plus_create(hdev);
- if (data == NULL) {
- dev_err(&hdev->dev, "can't allocate space for Logitech G710+ device attributes\n");
- ret= -ENOMEM;
- goto err_free;
- }
- hid_set_drvdata(hdev, data);
-
- /*
- * Without this, the device would send a first report with a key down event for
- * certain buttons, but never the key up event
- */
- hdev->quirks |= HID_QUIRK_NOGET;
-
- ret = hid_parse(hdev);
- if (ret) {
- hid_err(hdev, "parse failed\n");
- goto err_free;
- }
-
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
- if (ret) {
- hid_err(hdev, "hw start failed\n");
- goto err_free;
- }
-
- ret= lg_g710_plus_initialize(hdev);
- if (ret) {
- ret = -ret;
- hid_hw_stop(hdev);
- goto err_free;
- }
-
- return 0;
-
-err_free:
- if (data != NULL) {
- kfree(data);
- }
- return ret;
-}
-
-static void lg_g710_plus_remove(struct hid_device *hdev)
-{
- struct lg_g710_plus_data* data = lg_g710_plus_get_data(hdev);
- struct list_head *feature_report_list = &hdev->report_enum[HID_FEATURE_REPORT].report_list;
-
- if (data != NULL && !list_empty(feature_report_list))
- sysfs_remove_group(&hdev->dev.kobj, &data->attr_group);
-
- hid_hw_stop(hdev);
- if (data != NULL) {
- kfree(data);
- }
-}
-
-static ssize_t lg_g710_plus_show_led_macro(struct device *device, struct device_attribute *attr, char *buf)
-{
- struct lg_g710_plus_data* data = hid_get_drvdata(dev_get_drvdata(device->parent));
- if (data != NULL) {
- spin_lock(&data->lock);
- init_completion(&data->ready);
- hidhw_request(data->hdev, data->mr_buttons_led_report, REQTYPE_READ);
- wait_for_completion_timeout(&data->ready, WAIT_TIME_OUT);
- spin_unlock(&data->lock);
- return sprintf(buf, "%d\n", data->led_macro);
- }
- return 0;
-}
-
-static ssize_t lg_g710_plus_show_led_keys(struct device *device, struct device_attribute *attr, char *buf)
-{
- struct lg_g710_plus_data* data = hid_get_drvdata(dev_get_drvdata(device->parent));
- if (data != NULL) {
- spin_lock(&data->lock);
- init_completion(&data->ready);
- hidhw_request(data->hdev, data->other_buttons_led_report, REQTYPE_READ);
- wait_for_completion_timeout(&data->ready, WAIT_TIME_OUT);
- spin_unlock(&data->lock);
- return sprintf(buf, "%d\n", data->led_keys);
- }
- return 0;
-}
-
-static ssize_t lg_g710_plus_store_led_macro(struct device *device, struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned long key_mask;
- int retval;
- struct lg_g710_plus_data* data = hid_get_drvdata(dev_get_drvdata(device->parent));
- retval = kstrtoul(buf, 10, &key_mask);
- if (retval)
- return retval;
-
- spin_lock(&data->lock);
- data->mr_buttons_led_report->field[0]->value[0]= (key_mask & 0xF) << 4;
- hidhw_request(data->hdev, data->mr_buttons_led_report, REQTYPE_WRITE);
- spin_unlock(&data->lock);
- return count;
-}
-
-static ssize_t lg_g710_plus_store_led_keys(struct device *device, struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long key_mask;
- u8 wasd_mask, keys_mask;
- struct lg_g710_plus_data* data = hid_get_drvdata(dev_get_drvdata(device->parent));
- retval = kstrtoul(buf, 10, &key_mask);
- if (retval)
- return retval;
-
- wasd_mask= (key_mask >> 4) & 0xF;
- keys_mask= (key_mask) & 0xF;
-
- wasd_mask= wasd_mask > 4 ? 4 : wasd_mask;
- keys_mask= keys_mask > 4 ? 4 : keys_mask;
-
- spin_lock(&data->lock);
- data->other_buttons_led_report->field[0]->value[0]= wasd_mask;
- data->other_buttons_led_report->field[0]->value[1]= keys_mask;
- hidhw_request(data->hdev, data->other_buttons_led_report, REQTYPE_WRITE);
- spin_unlock(&data->lock);
- return count;
-}
-
-static const struct hid_device_id lg_g710_plus_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS) },
- { }
-};
-
-MODULE_DEVICE_TABLE(hid, lg_g710_plus_devices);
-static struct hid_driver lg_g710_plus_driver = {
- .name = "hid-lg-g710-plus",
- .id_table = lg_g710_plus_devices,
- .raw_event = lg_g710_plus_raw_event,
- .input_mapping = lg_g710_plus_input_mapping,
- .probe= lg_g710_plus_probe,
- .remove= lg_g710_plus_remove,
-};
-
-static int __init lg_g710_plus_init(void)
-{
- return hid_register_driver(&lg_g710_plus_driver);
-}
-
-static void __exit lg_g710_plus_exit(void)
-{
- hid_unregister_driver(&lg_g710_plus_driver);
-}
-
-module_init(lg_g710_plus_init);
-module_exit(lg_g710_plus_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Filip Wieladek <Wattos@gmail.com>");
-MODULE_DESCRIPTION("Logitech G710+ driver");