summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun Yan <juyan@nvidia.com>2014-04-10 17:09:23 -0700
committerMandar Padmawar <mpadmawar@nvidia.com>2014-06-25 00:49:04 -0700
commit52a12936626cad03c615636e9769a12064e5460c (patch)
treee9eda8ee17dedd6f7de51e9309043c7f75b9e8fc
parent36c68f3edb0a5f4be541e8168e2bd404c9a1357e (diff)
hid: hid driver for Blake Controller
-Converted absolute coordinates to REL events. -Adjusted blake joystick parameters to increase granularity. Bug 1487225 Change-Id: I3f90e79e5519a74d46947ef851b126cca4070719 Reviewed-on: http://git-master/r/394924 (cherry picked from commit ed1bc9b9e6f5d38476ba97f10102b602c9b92aac) Signed-off-by: Jean Huang <jeanh@nvidia.com> Reviewed-on: http://git-master/r/427943 GVS: Gerrit_Virtual_Submit
-rw-r--r--drivers/hid/Makefile3
-rw-r--r--drivers/hid/hid-core.c1
-rw-r--r--drivers/hid/hid-ids.h1
-rw-r--r--drivers/hid/hid-nvidia-blake.c260
4 files changed, 264 insertions, 1 deletions
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 8d583e8f1c7b..108ce20cd6b7 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -85,7 +85,8 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
-obj-$(CONFIG_HID_NVIDIA) += hid-nvidia.o
+obj-$(CONFIG_HID_NVIDIA) += hid-nvidia.o \
+ hid-nvidia-blake.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 245fc0fc97a3..70e5b3f31e78 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1518,6 +1518,7 @@ 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) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NVIDIA, USB_DEVICE_ID_NVIDIA_LOKI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NVIDIA, USB_DEVICE_ID_NVIDIA_BLAKE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT780) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 5b79d55e5fb8..7d3d90e460c5 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -595,6 +595,7 @@
#define USB_VENDOR_ID_NVIDIA 0x0955
#define USB_DEVICE_ID_NVIDIA_LOKI 0x7205
+#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-nvidia-blake.c b/drivers/hid/hid-nvidia-blake.c
new file mode 100644
index 000000000000..78fa814d7333
--- /dev/null
+++ b/drivers/hid/hid-nvidia-blake.c
@@ -0,0 +1,260 @@
+/*
+ * HID driver for NVIDIA Shield Wireless Joystick
+ *
+ * Copyright (c) 2013-2014, 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 "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 12
+
+struct nvidia_tp_loc {
+ u8 x;
+ u8 y;
+ u8 action;
+ u8 speed;/* Not used for now but keep as an parameter */
+};
+
+/*
+ * Scale mapping is a table based on quadratic function
+ */
+static s8 blake_touch_scale_table[SCALE_LEN] = {
+ 0, 1, 10, 20, 35, 45, 61, 70, 75, 79, 100, 125};
+
+static u8 scale_rel(u8 rel, u8 coeff)
+{
+ 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;
+
+ return (u8)(sign * blake_touch_scale_table[abs_rel]);
+}
+
+static int nvidia_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size) {
+
+ if (!report)
+ return 1;
+
+ unsigned id = report->id;
+ struct nvidia_tp_loc *loc =
+ (struct nvidia_tp_loc *)hid_get_drvdata(hdev);
+ if (!loc)
+ return 1;
+
+ u8 action;
+ u8 x, y;
+ int press = 0;
+ int release = 0;
+ u8 relx, rely;
+
+ /* If not valid touch events, let generic driver to handle this */
+ if (id != TOUCH_REPORT_ID)
+ return 0;
+
+ 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 = scale_rel(x - loc->x, loc->speed);
+ rely = scale_rel(y - loc->y, loc->speed);
+
+ loc->action = action;
+
+ dbg_hid("%u %u %u rel %d %d\n", action, x, y, (s8)relx, (s8)rely);
+
+ if (release) {/* If a release event, don't do anything */
+ return 1;
+ } else {
+ /* Record coordinates */
+ loc->x = x;
+ loc->y = y;
+ if (!press) {
+ /*
+ * Neither press or release event, we
+ * need to report it to input subsystem
+ */
+ data[2] = relx;
+ data[3] = rely;
+ return 0;
+ } else {
+ /*
+ * if it's a press event,
+ * don't report.
+ */
+ return 1;
+ }
+ }
+}
+
+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 (!kstrtoul(buf, 10, &speed_val)) {
+ if (speed_val > MAX_SPEED)
+ return count;
+ loc->speed = (u8)speed_val;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR,
+ blake_show_speed, blake_store_speed);
+
+static int nvidia_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct nvidia_tp_loc *loc;
+
+ loc = (struct nvidia_tp_loc *)
+ kmalloc(sizeof(struct nvidia_tp_loc *), GFP_KERNEL);
+
+ if (!loc) {
+ hid_err(hdev, "cannot alloc device touchpad state\n");
+ return -ENOMEM;
+ }
+
+ loc->x = TOUCHPAD_DEFAULT_X;
+ loc->y = TOUCHPAD_DEFAULT_Y;
+ loc->action = 0;
+ loc->speed = DEFAULT_SPEED;
+ hid_set_drvdata(hdev, loc);
+
+ ret = hid_open_report(hdev);
+ if (!ret)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+ if (ret)
+ goto end;
+
+ ret = device_create_file(&hdev->dev, &dev_attr_speed);
+ if (ret)
+ hid_warn(hdev, "cannot create sysfs for speed\n");
+
+end:
+ return ret;
+}
+
+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,
+ .probe = nvidia_probe,
+};
+module_hid_driver(nvidia_driver);
+
+MODULE_AUTHOR("Jun Yan <juyan@nvidia.com>");
+MODULE_LICENSE("GPL");