Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save webgeek1234/8ef1bd105d2add3aa9c29028c2befbb0 to your computer and use it in GitHub Desktop.
Save webgeek1234/8ef1bd105d2add3aa9c29028c2befbb0 to your computer and use it in GitHub Desktop.
Shield wireless controller kernel support
From 66e8da50a8e779a1d3a29bc1ef985246ef6b7599 Mon Sep 17 00:00:00 2001
From: Fedora Kernel Team <kernel-team@fedoraproject.org>
Date: Wed, 20 Jun 2018 13:22:00 -0500
Subject: [PATCH 1/3] input: hid: Add HID_QUIRK_INIT_USB_INPUT_REPORTS
---
drivers/hid/usbhid/hid-core.c | 3 +++
include/linux/hid.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 77c50cd..87c5a9d 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1141,6 +1141,9 @@ static int usbhid_start(struct hid_device *hid)
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ if (hid->quirks & HID_QUIRK_INIT_USB_INPUT_REPORTS)
+ usbhid_init_reports(hid);
+
set_bit(HID_STARTED, &usbhid->iofl);
if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 29b981b..21cad07 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -340,6 +340,7 @@ struct hid_item {
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
/* 0x00000200 reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */
#define HID_QUIRK_ALWAYS_POLL 0x00000400
+#define HID_QUIRK_INIT_USB_INPUT_REPORTS 0x00000800
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000
#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000
--
2.17.1
From 06ec2c006b67d49fe16c467d6d49a60534464112 Mon Sep 17 00:00:00 2001
From: Fedora Kernel Team <kernel-team@fedoraproject.org>
Date: Wed, 20 Jun 2018 13:35:31 -0500
Subject: [PATCH 2/3] input: hid: Set quirks for Nvidia Shield wireless
controller
HID_QUIRK_INIT_USB_INPUT_REPORTS is needed because the device does
not initialize correctly in its wireless mode via ozwpan if the
report is not requested immediately.
---
drivers/hid/hid-ids.h | 3 +++
drivers/hid/hid-quirks.c | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index c631d2c..5bbdf92 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -845,6 +845,9 @@
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18 0x0014
#define USB_DEVICE_ID_NTRIG_DUOSENSE 0x1500
+#define USB_VENDOR_ID_NVIDIA 0x0955
+#define USB_DEVICE_ID_NVIDIA_BLAKE 0x7210
+
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index e92b77f..9549706 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -119,6 +119,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NEXTWINDOW, USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN), HID_QUIRK_MULTI_INPUT},
{ HID_USB_DEVICE(USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE), HID_QUIRK_NO_INIT_REPORTS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NVIDIA, USB_DEVICE_ID_NVIDIA_BLAKE), HID_QUIRK_INIT_USB_INPUT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK), HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1640), HID_QUIRK_NOGET },
--
2.17.1
From be7c0bf6f93ddfc2bdb927f4086a9fbf73b30ec8 Mon Sep 17 00:00:00 2001
From: Fedora Kernel Team <kernel-team@fedoraproject.org>
Date: Wed, 20 Jun 2018 13:51:08 -0500
Subject: [PATCH 3/3] input: hid: Add Nvidia Shield wireless controller driver
This handles several additional functions:
- Adjusts sensativity on the analog sticks and triggers
- Allows control of touchpad modes
- Enables force feedback
Code is based on the implemention in the Nvidia android kernel
---
drivers/hid/Kconfig | 7 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-nvidia-blake.c | 590 +++++++++++++++++++++++++++++++++
drivers/hid/hid-quirks.c | 3 +
4 files changed, 601 insertions(+)
create mode 100644 drivers/hid/hid-nvidia-blake.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 19c499f..a9d9a9a 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -632,6 +632,13 @@ config HID_NTRIG
---help---
Support for N-Trig touch screen.
+config HID_NVIDIA
+ tristate "NVIDIA game controller"
+ depends on USB_HID
+ ---help---
+ Support for NVIDIA game controllers. To improve gaming experience, NVIDIA controller
+ has customized axis flat and fuzz values.
+
config HID_ORTEK
tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad"
depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index eb13b9e..67ec80d 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
obj-$(CONFIG_HID_NTI) += hid-nti.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
+obj-$(CONFIG_HID_NVIDIA) += hid-nvidia-blake.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
diff --git a/drivers/hid/hid-nvidia-blake.c b/drivers/hid/hid-nvidia-blake.c
new file mode 100644
index 0000000..7f29aae
--- /dev/null
+++ b/drivers/hid/hid-nvidia-blake.c
@@ -0,0 +1,590 @@
+/*
+ * HID driver for NVIDIA Shield Wireless Joystick
+ *
+ * Copyright (c) 2013-2016, NVIDIA Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "usbhid/usbhid.h"
+#include "hid-ids.h"
+
+#define JOYSTICK_FUZZ 64
+#define TRIGGER_FUZZ 64
+#define JOYSTICK_FLAT 64
+#define TRIGGER_FLAT 0
+
+#define MAX_CHAR 255
+
+#define TOUCHPAD_DEFAULT_X 128
+#define TOUCHPAD_DEFAULT_Y 128
+#define TOUCH_HID_REPORT_SIZE 4
+#define TOUCH_ACTION_MASK 0x8
+#define TOUCH_ACTION_SHFT 3
+#define TOUCH_ACTION_UP 0
+#define TOUCH_ACTION_DOWN 1
+#define TOUCH_REPORT_ID 2
+
+#define MAX_SPEED 10
+#define DEFAULT_SPEED 7
+
+#define SCALE_LEN 6
+
+#define MOUSE_MODE_STR "mouse"
+#define GESTURE_MODE_STR "gesture"
+#define ABSOLUTE_MODE_STR "absolute"
+#define DISABLED_MODE_STR "disabled"
+#define UNKNOWN_MODE_STR "unknown"
+
+#define MAX_REL 255
+#define MAX_ABS 65535
+
+#define MAX_DPAD_MOVE 4
+
+#define XSCALE 1
+#define YSCALE 0
+
+struct nvidia_tp_loc {
+ u8 x;
+ u8 y;
+ u8 action;
+ u8 speed; /* Not used for now but keep as an parameter */
+ u8 mode; /* Trackpad mode */
+ u8 release;
+ u8 tp_size;
+ struct hid_report *ff_report;
+};
+
+enum {
+ MOUSE_MODE = 0,
+ GESTURE_MODE,
+ ABSOLUTE_MODE,
+ DISABLED_MODE,
+};
+
+/*
+ * Scale mapping is a table based on quadratic function
+ */
+static const s8 blake_touch_scale_table_x[SCALE_LEN] = {
+ 0, 1, 4, 8, 13, 15};
+
+static const s8 blake_touch_scale_table_y[SCALE_LEN] = {
+ 0, 3, 10, 17, 22, 25};
+
+static signed short scale_rel(u8 rel, u8 coeff, u8 xy)
+{
+ s8 s_rel = (s8)rel;
+ s8 sign = (s_rel >= 0) ? 1 : -1;
+ s8 abs_rel = s_rel * sign;
+
+ if (abs_rel >= SCALE_LEN)
+ abs_rel = SCALE_LEN - 1;
+
+ /* If Direction is X or Y */
+ if (xy) {
+ return (signed short)((s_rel +
+ sign*blake_touch_scale_table_x[abs_rel]));
+ } else {
+ return (signed short)((s_rel +
+ sign*blake_touch_scale_table_y[abs_rel]));
+ }
+}
+
+static __s32 scale_rel_to_abs(__s32 rel)
+{
+ __s32 val;
+
+ if (rel < 0)
+ val = MAX_REL + rel;
+ else
+ val = rel;
+
+ val = val * MAX_ABS / MAX_REL;
+ return val;
+}
+
+static int nvidia_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size) {
+
+ unsigned id;
+ struct nvidia_tp_loc *loc =
+ (struct nvidia_tp_loc *)hid_get_drvdata(hdev);
+ u8 action;
+ u16 x, y;
+ int press = 0;
+ int release = 0;
+ signed short relx, rely;
+ signed short relx_raw, rely_raw;
+
+ if (!report)
+ return -EINVAL;
+ id = report->id;
+
+ if (!loc)
+ return -EINVAL;
+
+ /* If not valid touch events, let generic driver to handle this */
+ if (id != TOUCH_REPORT_ID)
+ return 0;
+
+ /* If driver is disabled, don't report anything to generic driver */
+ if (loc->mode == DISABLED_MODE)
+ return 1;
+
+ if (!data)
+ return -EINVAL;
+ action = (data[1] & TOUCH_ACTION_MASK) >> TOUCH_ACTION_SHFT;
+ x = data[2];
+ y = data[4];
+
+
+
+ if (!loc->action && action)
+ press = 1;
+ else if (loc->action && !action)
+ release = 1;
+ else if (!loc->action && !action)
+ return 1; /* Double release, don't do anything */
+
+ relx_raw = x - loc->x;
+ rely_raw = y - loc->y;
+
+ relx = scale_rel(relx_raw, loc->speed, XSCALE);
+ rely = scale_rel(rely_raw, (loc->speed), YSCALE);
+
+ loc->action = action;
+
+ dbg_hid("%u %u %u rel %d %d\n", action, x, y, (s8)relx, (s8)rely);
+
+ loc->x = x;
+ loc->y = y;
+
+ /* If it's a press event, don't report. */
+ if (press)
+ return 1;
+
+ /* Not a press event, we need to report it to input subsystem,
+ * set values and pass to generic driver */
+ if (loc->mode == ABSOLUTE_MODE) {
+ /* Report raw absolute data to generic driver */
+ if (loc->tp_size == 8) {
+ data[2] = x & 0xff;
+ data[3] = y & 0xff;
+ }
+ } else if (loc->mode == GESTURE_MODE) {
+ /* Report raw relative data to generic driver */
+ if (loc->tp_size == 8) {
+ data[2] = relx_raw & 0xff;
+ data[3] = rely_raw & 0xff;
+ } else {
+ data[2] = relx_raw & 0xff;
+ data[3] = relx_raw >> 8;
+ data[4] = rely_raw & 0xff;
+ data[5] = rely_raw >> 8;
+ }
+ if (release)
+ loc->release = 1;
+ else
+ loc->release = 0;
+ } else {
+ /* MOUSE_MODE */
+ if (loc->tp_size == 8) {
+ data[2] = relx & 0xff;
+ data[3] = rely & 0xff;
+ } else {
+ data[2] = relx & 0xff;
+ data[3] = relx >> 8;
+ data[4] = rely & 0xff;
+ data[5] = rely >> 8;
+ }
+ }
+ return 0;
+}
+
+static int nvidia_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value) {
+
+ struct nvidia_tp_loc *loc =
+ (struct nvidia_tp_loc *)hid_get_drvdata(hdev);
+ __u16 keycode = ABS_HAT0X;
+
+ if (!loc)
+ return 0;
+
+ /* If not in absolute mode or gesture mode, we pass as it is */
+ if (loc->mode != ABSOLUTE_MODE && loc->mode != GESTURE_MODE)
+ return 0;
+
+ /* If not mouse event, we pass as it is */
+ if (field->physical != HID_GD_MOUSE
+ && field->application != HID_GD_MOUSE)
+ return 0;
+
+ /* If not relative event, we pass as it is */
+ if (usage->type != EV_REL)
+ return 0;
+
+ if (loc->mode == ABSOLUTE_MODE) {
+ value = scale_rel_to_abs(value);
+ input_event(field->hidinput->input, EV_ABS, usage->code,
+ value);
+ } else {
+ /* GESTURE_MODE */
+ value = (value > 1) ? 1 : ((value < -1) ? -1 : 0);
+ if (usage->code == REL_X)
+ keycode = ABS_HAT0X;
+ else if (usage->code == REL_Y)
+ keycode = ABS_HAT0Y;
+
+ if (!loc->release)
+ input_event(field->hidinput->input, EV_ABS, keycode,
+ value);
+ else
+ input_event(field->hidinput->input, EV_ABS, keycode,
+ 0);
+ }
+ return 1;
+}
+
+static ssize_t blake_show_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+
+ struct hid_device *hdev =
+ container_of(dev, struct hid_device, dev);
+
+ struct nvidia_tp_loc *loc =
+ (struct nvidia_tp_loc *)hid_get_drvdata(hdev);
+
+ if (!loc)
+ return snprintf(buf, MAX_CHAR, UNKNOWN_MODE_STR);
+
+ switch (loc->mode) {
+ case MOUSE_MODE:
+ return snprintf(buf, MAX_CHAR, MOUSE_MODE_STR);
+ case GESTURE_MODE:
+ return snprintf(buf, MAX_CHAR, GESTURE_MODE_STR);
+ case ABSOLUTE_MODE:
+ return snprintf(buf, MAX_CHAR, ABSOLUTE_MODE_STR);
+ case DISABLED_MODE:
+ return snprintf(buf, MAX_CHAR, DISABLED_MODE_STR);
+ default:
+ return snprintf(buf, MAX_CHAR, UNKNOWN_MODE_STR);
+ }
+}
+
+static ssize_t blake_store_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count) {
+
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct nvidia_tp_loc *loc =
+ (struct nvidia_tp_loc *)hid_get_drvdata(hdev);
+ size_t buflen;
+ char blake_mode[MAX_CHAR];
+
+ if (!loc)
+ return count;
+
+ blake_mode[sizeof(blake_mode) - 1] = '\0';
+ strncpy(blake_mode, buf, sizeof(blake_mode) - 1);
+ buflen = strlen(blake_mode);
+
+ if (buflen && blake_mode[buflen - 1] == '\n')
+ blake_mode[buflen - 1] = '\0';
+
+ if (!strcmp(blake_mode, MOUSE_MODE_STR))
+ loc->mode = MOUSE_MODE;
+ else if (!strcmp(blake_mode, GESTURE_MODE_STR))
+ loc->mode = GESTURE_MODE;
+ else if (!strcmp(blake_mode, ABSOLUTE_MODE_STR))
+ loc->mode = ABSOLUTE_MODE;
+ else if (!strcmp(blake_mode, DISABLED_MODE_STR))
+ loc->mode = DISABLED_MODE;
+ return count;
+}
+
+static ssize_t blake_show_speed(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+
+ struct hid_device *hdev =
+ container_of(dev, struct hid_device, dev);
+
+ struct nvidia_tp_loc *loc =
+ (struct nvidia_tp_loc *)hid_get_drvdata(hdev);
+
+ return snprintf(buf, MAX_CHAR, "%d\n", loc->speed);
+}
+
+static ssize_t blake_store_speed(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count) {
+
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct nvidia_tp_loc *loc =
+ (struct nvidia_tp_loc *)hid_get_drvdata(hdev);
+ unsigned long speed_val;
+
+ if (!loc)
+ return count;
+
+ if (!buf)
+ return count;
+
+ if (!kstrtoul(buf, 10, &speed_val)) {
+ if (speed_val > MAX_SPEED)
+ return count;
+ loc->speed = (u8)speed_val;
+ }
+
+ return count;
+}
+
+static int nvidia_find_tp_len(struct hid_device *hdev,
+ struct nvidia_tp_loc *loc)
+{
+ struct hid_report *report;
+ struct list_head *report_list =
+ &hdev->report_enum[HID_INPUT_REPORT].report_list;
+ u8 i;
+
+ if (list_empty(report_list)) {
+ hid_err(hdev, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ /* set default */
+ loc->tp_size = 8;
+ list_for_each_entry(report, report_list, list) {
+ if (report->id == TOUCH_REPORT_ID) {
+ /* check if we are reporting u8 or u16
+ * for x/y size need to handle FW change
+ */
+ for (i = 0; i < report->maxfield; i++) {
+ if (report->field[i]->application
+ == HID_GD_MOUSE) {
+ if (report->field[i]->report_size
+ == 16) {
+ loc->tp_size = 16;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ return 0;
+}
+
+static int nvidia_ff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct nvidia_tp_loc *loc = data;
+ int left, right, length;
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+ length = effect->replay.length;
+
+ dbg_hid("called with 0x%04x 0x%04x 0x%04x", left, right, length);
+
+ length = length > 10000 ? 10000 : length;
+
+ loc->ff_report->field[0]->value[0] = left;
+ loc->ff_report->field[0]->value[1] = right;
+ loc->ff_report->field[0]->value[2] = length;
+
+ hid_hw_request(hid, loc->ff_report, HID_REQ_SET_REPORT);
+
+ return 0;
+}
+
+static int nvidia_init_ff(struct hid_device *hdev, struct nvidia_tp_loc *loc)
+{
+ struct hid_report *report;
+ struct hid_input *hidinput = list_entry(hdev->inputs.next,
+ struct hid_input, list);
+ struct list_head *report_list =
+ &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ int error;
+
+ if (list_empty(report_list)) {
+ hid_err(hdev, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ list_for_each_entry(report, report_list, list) {
+ if (report->maxfield < 1) {
+ hid_warn(hdev, "no fields in the report\n");
+ continue;
+ }
+
+ if (report->field[0]->report_count != 3) {
+ hid_warn(hdev, "not right number of values in the field\n");
+ continue;
+ }
+
+ goto found_report;
+ }
+ hid_warn(hdev, "FF report not found\n");
+ loc->ff_report = NULL;
+ return -ENODEV;
+
+found_report:
+ loc->ff_report = report;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+ error = input_ff_create_memless(dev, loc, nvidia_ff_play);
+
+ if (error) {
+ loc->ff_report = NULL;
+ clear_bit(FF_RUMBLE, dev->ffbit);
+ hid_warn(hdev, "Couldn't create FF device");
+ return error;
+ }
+
+ hid_info(hdev, "Force feedback enabled\n");
+
+ return 0;
+}
+
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR,
+ blake_show_speed, blake_store_speed);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+ blake_show_mode, blake_store_mode);
+
+static int nvidia_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct nvidia_tp_loc *loc;
+
+ loc = devm_kzalloc(&hdev->dev, sizeof(*loc), GFP_KERNEL);
+ if (!loc)
+ return -ENOMEM;
+
+ loc->x = TOUCHPAD_DEFAULT_X;
+ loc->y = TOUCHPAD_DEFAULT_Y;
+ loc->action = 0;
+ loc->speed = DEFAULT_SPEED;
+ loc->mode = DISABLED_MODE;
+ hid_set_drvdata(hdev, loc);
+
+ /* Parse the HID report now */
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err_parse;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret)
+ goto err_parse;
+
+ nvidia_init_ff(hdev, loc);
+ nvidia_find_tp_len(hdev, loc);
+
+ ret = device_create_file(&hdev->dev, &dev_attr_speed);
+ if (ret) {
+ hid_warn(hdev,
+ "cannot create sysfs speed attribute err: %d\n", ret);
+ }
+
+ ret = device_create_file(&hdev->dev, &dev_attr_mode);
+ if (ret)
+ hid_warn(hdev,
+ "cannot create sysfs mode attribute err: %d\n", ret);
+
+ kobject_uevent(&hdev->dev.kobj, KOBJ_CHANGE);
+
+ return 0;
+
+err_parse:
+ return ret;
+}
+
+static void nvidia_remove(struct hid_device *hdev)
+{
+ struct nvidia_tp_loc *loc = hid_get_drvdata(hdev);
+
+ if (!loc)
+ return;
+
+ device_remove_file(&hdev->dev, &dev_attr_speed);
+ device_remove_file(&hdev->dev, &dev_attr_mode);
+
+ hid_hw_stop(hdev);
+}
+
+static int nvidia_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ int a = field->logical_minimum;
+ int b = field->logical_maximum;
+ int fuzz;
+ int flat;
+
+ if ((usage->type == EV_ABS) && (field->application == HID_GD_GAMEPAD
+ || field->application == HID_GD_JOYSTICK)) {
+ switch (usage->hid) {
+ case HID_GD_X:
+ case HID_GD_Y:
+ case HID_GD_RX:
+ case HID_GD_RY:
+ fuzz = JOYSTICK_FUZZ;
+ flat = JOYSTICK_FLAT;
+ break;
+ case HID_GD_Z:
+ case HID_GD_RZ:
+ fuzz = TRIGGER_FUZZ;
+ flat = TRIGGER_FLAT;
+ break;
+ default: return 0;/*Use generic mapping for HatX, HatY*/
+ }
+ set_bit(usage->type, hi->input->evbit);
+ set_bit(usage->code, *bit);
+ input_set_abs_params(hi->input, usage->code, a, b, fuzz, flat);
+ input_abs_set_res(hi->input, usage->code,
+ hidinput_calc_abs_res(field, usage->code));
+ return -1;
+ }
+ return 0;
+}
+
+static const struct hid_device_id nvidia_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_NVIDIA, USB_DEVICE_ID_NVIDIA_BLAKE) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, nvidia_devices);
+
+static struct hid_driver nvidia_driver = {
+ .name = "hid-nvidia-blake",
+ .id_table = nvidia_devices,
+ .input_mapped = nvidia_input_mapped,
+ .raw_event = nvidia_raw_event,
+ .event = nvidia_event,
+ .probe = nvidia_probe,
+ .remove = nvidia_remove,
+};
+module_hid_driver(nvidia_driver);
+
+MODULE_AUTHOR("Jun Yan <juyan@nvidia.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 9549706..0a47adc 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -527,6 +527,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
#endif
+#if IS_ENABLED(CONFIG_HID_NVIDIA)
+ { HID_USB_DEVICE(USB_VENDOR_ID_NVIDIA, USB_DEVICE_ID_NVIDIA_BLAKE) },
+#endif
#if IS_ENABLED(CONFIG_HID_ORTEK)
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
--
2.17.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment