summaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-sony.c
diff options
context:
space:
mode:
authorTodd Kelner <tsopdump@gmail.com>2018-02-17 18:47:10 -0500
committerJiri Kosina <jkosina@suse.cz>2018-03-06 09:22:06 -0500
commitb7289cb1cf99d432c894b9da7a54e24f73ae4c93 (patch)
tree1205f90a5e45e7673e3bd22c285a9dbb52182c64 /drivers/hid/hid-sony.c
parent183b6366cf473ff0e706a6751adc082faa44843d (diff)
HID: sony: Add touchpad support for NSG-MR5U and NSG-MR7U remotes
Sony's NSG-MR5U and NSG-MR7U remote controls have a full keyboard and a touchpad. The keyboard is already supported by the existing Linux kernel and drivers but the touchpad is not recognized. This patch adds the coded needed to bring full functionality to the touchpad. Note that these remotes use the vendor code for SMK even though they are Sony branded. Known limitations - The built-in accelerometers are not supported by these changes - When the Drag (Fn) key is used as a mouse button, the button is automatically released when the key begins repeating. There are two workarounds for this 1) Use the button behind the touchpad instead of the Drag (Fn) key or 2) Disable the key repeat functionality or increase the key repeat delay. Signed-off-by: Todd Kelner <tsopdump@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r--drivers/hid/hid-sony.c131
1 files changed, 125 insertions, 6 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index ccdc5f2d01b1..e475c5073c99 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -9,6 +9,7 @@
9 * Copyright (c) 2006-2013 Jiri Kosina 9 * Copyright (c) 2006-2013 Jiri Kosina
10 * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> 10 * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
11 * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com> 11 * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com>
12 * Copyright (c) 2018 Todd Kelner
12 */ 13 */
13 14
14/* 15/*
@@ -55,6 +56,8 @@
55#define NAVIGATION_CONTROLLER_BT BIT(11) 56#define NAVIGATION_CONTROLLER_BT BIT(11)
56#define SINO_LITE_CONTROLLER BIT(12) 57#define SINO_LITE_CONTROLLER BIT(12)
57#define FUTUREMAX_DANCE_MAT BIT(13) 58#define FUTUREMAX_DANCE_MAT BIT(13)
59#define NSG_MR5U_REMOTE_BT BIT(14)
60#define NSG_MR7U_REMOTE_BT BIT(15)
58 61
59#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) 62#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
60#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) 63#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT)
@@ -72,8 +75,11 @@
72 MOTION_CONTROLLER) 75 MOTION_CONTROLLER)
73#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\ 76#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\
74 MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT) 77 MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT)
78#define NSG_MRXU_REMOTE (NSG_MR5U_REMOTE_BT | NSG_MR7U_REMOTE_BT)
75 79
76#define MAX_LEDS 4 80#define MAX_LEDS 4
81#define NSG_MRXU_MAX_X 1667
82#define NSG_MRXU_MAX_Y 1868
77 83
78 84
79/* PS/3 Motion controller */ 85/* PS/3 Motion controller */
@@ -1098,6 +1104,80 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
1098 } 1104 }
1099} 1105}
1100 1106
1107static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size)
1108{
1109 int n, offset, relx, rely;
1110 u8 active;
1111
1112 /*
1113 * The NSG-MRxU multi-touch trackpad data starts at offset 1 and
1114 * the touch-related data starts at offset 2.
1115 * For the first byte, bit 0 is set when touchpad button is pressed.
1116 * Bit 2 is set when a touch is active and the drag (Fn) key is pressed.
1117 * This drag key is mapped to BTN_LEFT. It is operational only when a
1118 * touch point is active.
1119 * Bit 4 is set when only the first touch point is active.
1120 * Bit 6 is set when only the second touch point is active.
1121 * Bits 5 and 7 are set when both touch points are active.
1122 * The next 3 bytes are two 12 bit X/Y coordinates for the first touch.
1123 * The following byte, offset 5, has the touch width and length.
1124 * Bits 0-4=X (width), bits 5-7=Y (length).
1125 * A signed relative X coordinate is at offset 6.
1126 * The bytes at offset 7-9 are the second touch X/Y coordinates.
1127 * Offset 10 has the second touch width and length.
1128 * Offset 11 has the relative Y coordinate.
1129 */
1130 offset = 1;
1131
1132 input_report_key(sc->touchpad, BTN_LEFT, rd[offset] & 0x0F);
1133 active = (rd[offset] >> 4);
1134 relx = (s8) rd[offset+5];
1135 rely = ((s8) rd[offset+10]) * -1;
1136
1137 offset++;
1138
1139 for (n = 0; n < 2; n++) {
1140 u16 x, y;
1141 u8 contactx, contacty;
1142
1143 x = rd[offset] | ((rd[offset+1] & 0x0F) << 8);
1144 y = ((rd[offset+1] & 0xF0) >> 4) | (rd[offset+2] << 4);
1145
1146 input_mt_slot(sc->touchpad, n);
1147 input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active & 0x03);
1148
1149 if (active & 0x03) {
1150 contactx = rd[offset+3] & 0x0F;
1151 contacty = rd[offset+3] >> 4;
1152 input_report_abs(sc->touchpad, ABS_MT_TOUCH_MAJOR,
1153 max(contactx, contacty));
1154 input_report_abs(sc->touchpad, ABS_MT_TOUCH_MINOR,
1155 min(contactx, contacty));
1156 input_report_abs(sc->touchpad, ABS_MT_ORIENTATION,
1157 (bool) (contactx > contacty));
1158 input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x);
1159 input_report_abs(sc->touchpad, ABS_MT_POSITION_Y,
1160 NSG_MRXU_MAX_Y - y);
1161 /*
1162 * The relative coordinates belong to the first touch
1163 * point, when present, or to the second touch point
1164 * when the first is not active.
1165 */
1166 if ((n == 0) || ((n == 1) && (active & 0x01))) {
1167 input_report_rel(sc->touchpad, REL_X, relx);
1168 input_report_rel(sc->touchpad, REL_Y, rely);
1169 }
1170 }
1171
1172 offset += 5;
1173 active >>= 2;
1174 }
1175
1176 input_mt_sync_frame(sc->touchpad);
1177
1178 input_sync(sc->touchpad);
1179}
1180
1101static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, 1181static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
1102 u8 *rd, int size) 1182 u8 *rd, int size)
1103{ 1183{
@@ -1206,6 +1286,10 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
1206 } 1286 }
1207 1287
1208 dualshock4_parse_report(sc, rd, size); 1288 dualshock4_parse_report(sc, rd, size);
1289
1290 } else if ((sc->quirks & NSG_MRXU_REMOTE) && rd[0] == 0x02) {
1291 nsg_mrxu_parse_report(sc, rd, size);
1292 return 1;
1209 } 1293 }
1210 1294
1211 if (sc->defer_initialization) { 1295 if (sc->defer_initialization) {
@@ -1263,7 +1347,7 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
1263} 1347}
1264 1348
1265static int sony_register_touchpad(struct sony_sc *sc, int touch_count, 1349static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
1266 int w, int h) 1350 int w, int h, int touch_major, int touch_minor, int orientation)
1267{ 1351{
1268 size_t name_sz; 1352 size_t name_sz;
1269 char *name; 1353 char *name;
@@ -1294,10 +1378,6 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
1294 snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name); 1378 snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name);
1295 sc->touchpad->name = name; 1379 sc->touchpad->name = name;
1296 1380
1297 ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER);
1298 if (ret < 0)
1299 goto err;
1300
1301 /* We map the button underneath the touchpad to BTN_LEFT. */ 1381 /* We map the button underneath the touchpad to BTN_LEFT. */
1302 __set_bit(EV_KEY, sc->touchpad->evbit); 1382 __set_bit(EV_KEY, sc->touchpad->evbit);
1303 __set_bit(BTN_LEFT, sc->touchpad->keybit); 1383 __set_bit(BTN_LEFT, sc->touchpad->keybit);
@@ -1306,6 +1386,25 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
1306 input_set_abs_params(sc->touchpad, ABS_MT_POSITION_X, 0, w, 0, 0); 1386 input_set_abs_params(sc->touchpad, ABS_MT_POSITION_X, 0, w, 0, 0);
1307 input_set_abs_params(sc->touchpad, ABS_MT_POSITION_Y, 0, h, 0, 0); 1387 input_set_abs_params(sc->touchpad, ABS_MT_POSITION_Y, 0, h, 0, 0);
1308 1388
1389 if (touch_major > 0) {
1390 input_set_abs_params(sc->touchpad, ABS_MT_TOUCH_MAJOR,
1391 0, touch_major, 0, 0);
1392 if (touch_minor > 0)
1393 input_set_abs_params(sc->touchpad, ABS_MT_TOUCH_MINOR,
1394 0, touch_minor, 0, 0);
1395 if (orientation > 0)
1396 input_set_abs_params(sc->touchpad, ABS_MT_ORIENTATION,
1397 0, orientation, 0, 0);
1398 }
1399
1400 if (sc->quirks & NSG_MRXU_REMOTE) {
1401 __set_bit(EV_REL, sc->touchpad->evbit);
1402 }
1403
1404 ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER);
1405 if (ret < 0)
1406 goto err;
1407
1309 ret = input_register_device(sc->touchpad); 1408 ret = input_register_device(sc->touchpad);
1310 if (ret < 0) 1409 if (ret < 0)
1311 goto err; 1410 goto err;
@@ -2690,7 +2789,7 @@ static int sony_input_configured(struct hid_device *hdev,
2690 * The Dualshock 4 touchpad supports 2 touches and has a 2789 * The Dualshock 4 touchpad supports 2 touches and has a
2691 * resolution of 1920x942 (44.86 dots/mm). 2790 * resolution of 1920x942 (44.86 dots/mm).
2692 */ 2791 */
2693 ret = sony_register_touchpad(sc, 2, 1920, 942); 2792 ret = sony_register_touchpad(sc, 2, 1920, 942, 0, 0, 0);
2694 if (ret) { 2793 if (ret) {
2695 hid_err(sc->hdev, 2794 hid_err(sc->hdev,
2696 "Unable to initialize multi-touch slots: %d\n", 2795 "Unable to initialize multi-touch slots: %d\n",
@@ -2721,6 +2820,20 @@ static int sony_input_configured(struct hid_device *hdev,
2721 } 2820 }
2722 2821
2723 sony_init_output_report(sc, dualshock4_send_output_report); 2822 sony_init_output_report(sc, dualshock4_send_output_report);
2823 } else if (sc->quirks & NSG_MRXU_REMOTE) {
2824 /*
2825 * The NSG-MRxU touchpad supports 2 touches and has a
2826 * resolution of 1667x1868
2827 */
2828 ret = sony_register_touchpad(sc, 2,
2829 NSG_MRXU_MAX_X, NSG_MRXU_MAX_Y, 15, 15, 1);
2830 if (ret) {
2831 hid_err(sc->hdev,
2832 "Unable to initialize multi-touch slots: %d\n",
2833 ret);
2834 goto err_stop;
2835 }
2836
2724 } else if (sc->quirks & MOTION_CONTROLLER) { 2837 } else if (sc->quirks & MOTION_CONTROLLER) {
2725 sony_init_output_report(sc, motion_send_output_report); 2838 sony_init_output_report(sc, motion_send_output_report);
2726 } else { 2839 } else {
@@ -2969,6 +3082,12 @@ static const struct hid_device_id sony_devices[] = {
2969 /* Nyko Core Controller for PS3 */ 3082 /* Nyko Core Controller for PS3 */
2970 { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER), 3083 { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER),
2971 .driver_data = SIXAXIS_CONTROLLER_USB | SINO_LITE_CONTROLLER }, 3084 .driver_data = SIXAXIS_CONTROLLER_USB | SINO_LITE_CONTROLLER },
3085 /* SMK-Link NSG-MR5U Remote Control */
3086 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR5U_REMOTE),
3087 .driver_data = NSG_MR5U_REMOTE_BT },
3088 /* SMK-Link NSG-MR7U Remote Control */
3089 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE),
3090 .driver_data = NSG_MR7U_REMOTE_BT },
2972 { } 3091 { }
2973}; 3092};
2974MODULE_DEVICE_TABLE(hid, sony_devices); 3093MODULE_DEVICE_TABLE(hid, sony_devices);