diff options
author | Jun Yan <juyan@nvidia.com> | 2014-04-10 17:09:23 -0700 |
---|---|---|
committer | Mandar Padmawar <mpadmawar@nvidia.com> | 2014-06-25 00:49:04 -0700 |
commit | 52a12936626cad03c615636e9769a12064e5460c (patch) | |
tree | e9eda8ee17dedd6f7de51e9309043c7f75b9e8fc | |
parent | 36c68f3edb0a5f4be541e8168e2bd404c9a1357e (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/Makefile | 3 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 1 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 1 | ||||
-rw-r--r-- | drivers/hid/hid-nvidia-blake.c | 260 |
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"); |