HID: sony: Add support for the Sony Motion Controller
authorFrank Praznik <frank.praznik@oh.rr.com>
Wed, 6 May 2015 00:47:30 +0000 (20:47 -0400)
committerJiri Kosina <jkosina@suse.cz>
Thu, 7 May 2015 08:41:35 +0000 (10:41 +0200)
Add a fixed-up HID descriptor for the Sony motion controller and enable
controls for the LED light as well as force-feedback.

The LED is multi-colored (red, green, blue).

The motion controller has a single rumble motor so the higher of the left
and right values is used to set the speed.

Signed-off-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-sony.c

index 4c521b2c6a829ffd841e473bdc3c0b11407a7e54..d0b18a5779d7ad2facf73efe0ed1af141886fe02 100644 (file)
 #define PS3REMOTE                 BIT(4)
 #define DUALSHOCK4_CONTROLLER_USB BIT(5)
 #define DUALSHOCK4_CONTROLLER_BT  BIT(6)
+#define MOTION_CONTROLLER         BIT(7)
 
 #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
 #define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\
                                DUALSHOCK4_CONTROLLER_BT)
 #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\
-                               DUALSHOCK4_CONTROLLER)
+                               DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER)
 #define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
-#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
+#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\
+                               MOTION_CONTROLLER)
 
 #define MAX_LEDS 4
 
@@ -134,6 +136,85 @@ static __u8 sixaxis_rdesc[] = {
        0xC0                /*  End Collection                      */
 };
 
+/* PS/3 Motion controller */
+static __u8 motion_rdesc[] = {
+       0x05, 0x01,         /*  Usage Page (Desktop),               */
+       0x09, 0x04,         /*  Usage (Joystick),                   */
+       0xA1, 0x01,         /*  Collection (Application),           */
+       0xA1, 0x02,         /*      Collection (Logical),           */
+       0x85, 0x01,         /*          Report ID (1),              */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x01,         /*          Report Count (1),           */
+       0x15, 0x00,         /*          Logical Minimum (0),        */
+       0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x95, 0x13,         /*          Report Count (19),          */
+       0x15, 0x00,         /*          Logical Minimum (0),        */
+       0x25, 0x01,         /*          Logical Maximum (1),        */
+       0x35, 0x00,         /*          Physical Minimum (0),       */
+       0x45, 0x01,         /*          Physical Maximum (1),       */
+       0x05, 0x09,         /*          Usage Page (Button),        */
+       0x19, 0x01,         /*          Usage Minimum (01h),        */
+       0x29, 0x13,         /*          Usage Maximum (13h),        */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x75, 0x01,         /*          Report Size (1),            */
+       0x95, 0x0D,         /*          Report Count (13),          */
+       0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+       0x81, 0x03,         /*          Input (Constant, Variable), */
+       0x15, 0x00,         /*          Logical Minimum (0),        */
+       0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0xA1, 0x00,         /*          Collection (Physical),      */
+       0x75, 0x08,         /*              Report Size (8),        */
+       0x95, 0x04,         /*              Report Count (4),       */
+       0x35, 0x00,         /*              Physical Minimum (0),   */
+       0x46, 0xFF, 0x00,   /*              Physical Maximum (255), */
+       0x09, 0x30,         /*              Usage (X),              */
+       0x09, 0x31,         /*              Usage (Y),              */
+       0x09, 0x32,         /*              Usage (Z),              */
+       0x09, 0x35,         /*              Usage (Rz),             */
+       0x81, 0x02,         /*              Input (Variable),       */
+       0xC0,               /*          End Collection,             */
+       0x05, 0x01,         /*          Usage Page (Desktop),       */
+       0x95, 0x13,         /*          Report Count (19),          */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0x95, 0x0C,         /*          Report Count (12),          */
+       0x81, 0x01,         /*          Input (Constant),           */
+       0x75, 0x10,         /*          Report Size (16),           */
+       0x95, 0x04,         /*          Report Count (4),           */
+       0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+       0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0x81, 0x02,         /*          Input (Variable),           */
+       0xC0,               /*      End Collection,                 */
+       0xA1, 0x02,         /*      Collection (Logical),           */
+       0x85, 0x02,         /*          Report ID (2),              */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x30,         /*          Report Count (48),          */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0xB1, 0x02,         /*          Feature (Variable),         */
+       0xC0,               /*      End Collection,                 */
+       0xA1, 0x02,         /*      Collection (Logical),           */
+       0x85, 0xEE,         /*          Report ID (238),            */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x30,         /*          Report Count (48),          */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0xB1, 0x02,         /*          Feature (Variable),         */
+       0xC0,               /*      End Collection,                 */
+       0xA1, 0x02,         /*      Collection (Logical),           */
+       0x85, 0xEF,         /*          Report ID (239),            */
+       0x75, 0x08,         /*          Report Size (8),            */
+       0x95, 0x30,         /*          Report Count (48),          */
+       0x09, 0x01,         /*          Usage (Pointer),            */
+       0xB1, 0x02,         /*          Feature (Variable),         */
+       0xC0,               /*      End Collection,                 */
+       0xC0                /*  End Collection                      */
+};
+
+
 /*
  * The default descriptor doesn't provide mapping for the accelerometers
  * or orientation sensors.  This fixed descriptor maps the accelerometers
@@ -798,6 +879,13 @@ union sixaxis_output_report_01 {
        __u8 buf[36];
 };
 
+struct motion_output_report_02 {
+       u8 type, zero;
+       u8 r, g, b;
+       u8 zero2;
+       u8 rumble;
+};
+
 #define DS4_REPORT_0x02_SIZE 37
 #define DS4_REPORT_0x05_SIZE 32
 #define DS4_REPORT_0x11_SIZE 78
@@ -844,6 +932,13 @@ static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc,
        return sixaxis_rdesc;
 }
 
+static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc,
+                            unsigned int *rsize)
+{
+       *rsize = sizeof(motion_rdesc);
+       return motion_rdesc;
+}
+
 static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
                             unsigned int *rsize)
 {
@@ -924,6 +1019,9 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        if (sc->quirks & SIXAXIS_CONTROLLER)
                return sixaxis_fixup(hdev, rdesc, rsize);
 
+       if (sc->quirks & MOTION_CONTROLLER)
+               return motion_fixup(hdev, rdesc, rsize);
+
        if (sc->quirks & PS3REMOTE)
                return ps3remote_fixup(hdev, rdesc, rsize);
 
@@ -1454,6 +1552,12 @@ static int sony_leds_init(struct sony_sc *sc)
                use_ds4_names = 1;
                name_len = 0;
                name_fmt = "%s:%s";
+       } else if (sc->quirks & MOTION_CONTROLLER) {
+               sc->led_count = 3;
+               memset(max_brightness, 255, 3);
+               use_ds4_names = 1;
+               name_len = 0;
+               name_fmt = "%s:%s";
        } else {
                sixaxis_set_leds_from_id(sc->device_id, initial_values);
                sc->led_count = 4;
@@ -1622,6 +1726,28 @@ static void dualshock4_state_worker(struct work_struct *work)
                                HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
 }
 
+static void motion_state_worker(struct work_struct *work)
+{
+       struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
+       struct hid_device *hdev = sc->hdev;
+       struct motion_output_report_02 *report =
+               (struct motion_output_report_02 *)sc->output_report_dmabuf;
+
+       memset(report, 0, sizeof(struct motion_output_report_02));
+
+       report->type = 0x02; /* set leds */
+       report->r = sc->led_state[0];
+       report->g = sc->led_state[1];
+       report->b = sc->led_state[2];
+
+#ifdef CONFIG_SONY_FF
+       report->rumble = max(sc->right, sc->left);
+#endif
+
+       hid_hw_output_report(hdev, (__u8 *)report,
+                       sizeof(struct motion_output_report_02));
+}
+
 static int sony_allocate_output_report(struct sony_sc *sc)
 {
        if (sc->quirks & SIXAXIS_CONTROLLER)
@@ -1634,6 +1760,10 @@ static int sony_allocate_output_report(struct sony_sc *sc)
        else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
                sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x05_SIZE,
                                                GFP_KERNEL);
+       else if (sc->quirks & MOTION_CONTROLLER)
+               sc->output_report_dmabuf =
+                               kmalloc(sizeof(struct motion_output_report_02),
+                               GFP_KERNEL);
        else
                return 0;
 
@@ -2043,6 +2173,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                }
 
                sony_init_work(sc, dualshock4_state_worker);
+       } else if (sc->quirks & MOTION_CONTROLLER) {
+               sony_init_work(sc, motion_state_worker);
        } else {
                ret = 0;
        }
@@ -2123,6 +2255,8 @@ static const struct hid_device_id sony_devices[] = {
                .driver_data = SIXAXIS_CONTROLLER_USB },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER),
                .driver_data = SIXAXIS_CONTROLLER_USB },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER),
+               .driver_data = MOTION_CONTROLLER },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
                .driver_data = SIXAXIS_CONTROLLER_BT },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),