|
@@ -977,6 +977,32 @@ static const unsigned int buzz_keymap[] = {
|
|
[20] = BTN_TRIGGER_HAPPY20,
|
|
[20] = BTN_TRIGGER_HAPPY20,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static const unsigned int ds4_absmap[] = {
|
|
|
|
+ [0x30] = ABS_X,
|
|
|
|
+ [0x31] = ABS_Y,
|
|
|
|
+ [0x32] = ABS_RX, /* right stick X */
|
|
|
|
+ [0x33] = ABS_Z, /* L2 */
|
|
|
|
+ [0x34] = ABS_RZ, /* R2 */
|
|
|
|
+ [0x35] = ABS_RY, /* right stick Y */
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const unsigned int ds4_keymap[] = {
|
|
|
|
+ [0x1] = BTN_WEST, /* Square */
|
|
|
|
+ [0x2] = BTN_SOUTH, /* Cross */
|
|
|
|
+ [0x3] = BTN_EAST, /* Circle */
|
|
|
|
+ [0x4] = BTN_NORTH, /* Triangle */
|
|
|
|
+ [0x5] = BTN_TL, /* L1 */
|
|
|
|
+ [0x6] = BTN_TR, /* R1 */
|
|
|
|
+ [0x7] = BTN_TL2, /* L2 */
|
|
|
|
+ [0x8] = BTN_TR2, /* R2 */
|
|
|
|
+ [0x9] = BTN_SELECT, /* Share */
|
|
|
|
+ [0xa] = BTN_START, /* Options */
|
|
|
|
+ [0xb] = BTN_THUMBL, /* L3 */
|
|
|
|
+ [0xc] = BTN_THUMBR, /* R3 */
|
|
|
|
+ [0xd] = BTN_MODE, /* PS */
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
static enum power_supply_property sony_battery_props[] = {
|
|
static enum power_supply_property sony_battery_props[] = {
|
|
POWER_SUPPLY_PROP_PRESENT,
|
|
POWER_SUPPLY_PROP_PRESENT,
|
|
POWER_SUPPLY_PROP_CAPACITY,
|
|
POWER_SUPPLY_PROP_CAPACITY,
|
|
@@ -1143,6 +1169,37 @@ static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ds4_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
|
|
+ struct hid_field *field, struct hid_usage *usage,
|
|
|
|
+ unsigned long **bit, int *max)
|
|
|
|
+{
|
|
|
|
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
|
|
|
|
+ unsigned int key = usage->hid & HID_USAGE;
|
|
|
|
+
|
|
|
|
+ if (key >= ARRAY_SIZE(ds4_keymap))
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ key = ds4_keymap[key];
|
|
|
|
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
|
|
|
|
+ return 1;
|
|
|
|
+ } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) {
|
|
|
|
+ unsigned int abs = usage->hid & HID_USAGE;
|
|
|
|
+
|
|
|
|
+ /* Let the HID parser deal with the HAT. */
|
|
|
|
+ if (usage->hid == HID_GD_HATSWITCH)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (abs >= ARRAY_SIZE(ds4_absmap))
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ abs = ds4_absmap[abs];
|
|
|
|
+ hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc,
|
|
static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc,
|
|
unsigned int *rsize)
|
|
unsigned int *rsize)
|
|
{
|
|
{
|
|
@@ -1416,6 +1473,10 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
if (sc->quirks & PS3REMOTE)
|
|
if (sc->quirks & PS3REMOTE)
|
|
return ps3remote_mapping(hdev, hi, field, usage, bit, max);
|
|
return ps3remote_mapping(hdev, hi, field, usage, bit, max);
|
|
|
|
|
|
|
|
+
|
|
|
|
+ if (sc->quirks & DUALSHOCK4_CONTROLLER)
|
|
|
|
+ return ds4_mapping(hdev, hi, field, usage, bit, max);
|
|
|
|
+
|
|
/* Let hid-core decide for the others */
|
|
/* Let hid-core decide for the others */
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -2578,6 +2639,15 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
else if (sc->quirks & SIXAXIS_CONTROLLER)
|
|
else if (sc->quirks & SIXAXIS_CONTROLLER)
|
|
connect_mask |= HID_CONNECT_HIDDEV_FORCE;
|
|
connect_mask |= HID_CONNECT_HIDDEV_FORCE;
|
|
|
|
|
|
|
|
+ /* Patch the hw version on DS4 compatible devices, so applications can
|
|
|
|
+ * distinguish between the default HID mappings and the mappings defined
|
|
|
|
+ * by the Linux game controller spec. This is important for the SDL2
|
|
|
|
+ * library, which has a game controller database, which uses device ids
|
|
|
|
+ * in combination with version as a key.
|
|
|
|
+ */
|
|
|
|
+ if (sc->quirks & DUALSHOCK4_CONTROLLER)
|
|
|
|
+ hdev->version |= 0x8000;
|
|
|
|
+
|
|
ret = hid_hw_start(hdev, connect_mask);
|
|
ret = hid_hw_start(hdev, connect_mask);
|
|
if (ret) {
|
|
if (ret) {
|
|
hid_err(hdev, "hw start failed\n");
|
|
hid_err(hdev, "hw start failed\n");
|