提交 c5e0c1c4 编写于 作者: F Frank Praznik 提交者: Jiri Kosina

HID: sony: Add support for the Sony Motion Controller

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: NPavel Machek <pavel@ucw.cz>
Signed-off-by: NFrank Praznik <frank.praznik@oh.rr.com>
Acked-by: NPavel Machek <pavel@ucw.cz>
Signed-off-by: NJiri Kosina <jkosina@suse.cz>
上级 7c886d09
...@@ -46,14 +46,16 @@ ...@@ -46,14 +46,16 @@
#define PS3REMOTE BIT(4) #define PS3REMOTE BIT(4)
#define DUALSHOCK4_CONTROLLER_USB BIT(5) #define DUALSHOCK4_CONTROLLER_USB BIT(5)
#define DUALSHOCK4_CONTROLLER_BT BIT(6) #define DUALSHOCK4_CONTROLLER_BT BIT(6)
#define MOTION_CONTROLLER BIT(7)
#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
#define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\ #define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\
DUALSHOCK4_CONTROLLER_BT) DUALSHOCK4_CONTROLLER_BT)
#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\
DUALSHOCK4_CONTROLLER) DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER)
#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_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 #define MAX_LEDS 4
...@@ -134,6 +136,85 @@ static __u8 sixaxis_rdesc[] = { ...@@ -134,6 +136,85 @@ static __u8 sixaxis_rdesc[] = {
0xC0 /* End Collection */ 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 * The default descriptor doesn't provide mapping for the accelerometers
* or orientation sensors. This fixed descriptor maps the accelerometers * or orientation sensors. This fixed descriptor maps the accelerometers
...@@ -798,6 +879,13 @@ union sixaxis_output_report_01 { ...@@ -798,6 +879,13 @@ union sixaxis_output_report_01 {
__u8 buf[36]; __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_0x02_SIZE 37
#define DS4_REPORT_0x05_SIZE 32 #define DS4_REPORT_0x05_SIZE 32
#define DS4_REPORT_0x11_SIZE 78 #define DS4_REPORT_0x11_SIZE 78
...@@ -844,6 +932,13 @@ static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -844,6 +932,13 @@ static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc,
return sixaxis_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, static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
...@@ -924,6 +1019,9 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -924,6 +1019,9 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if (sc->quirks & SIXAXIS_CONTROLLER) if (sc->quirks & SIXAXIS_CONTROLLER)
return sixaxis_fixup(hdev, rdesc, rsize); return sixaxis_fixup(hdev, rdesc, rsize);
if (sc->quirks & MOTION_CONTROLLER)
return motion_fixup(hdev, rdesc, rsize);
if (sc->quirks & PS3REMOTE) if (sc->quirks & PS3REMOTE)
return ps3remote_fixup(hdev, rdesc, rsize); return ps3remote_fixup(hdev, rdesc, rsize);
...@@ -1454,6 +1552,12 @@ static int sony_leds_init(struct sony_sc *sc) ...@@ -1454,6 +1552,12 @@ static int sony_leds_init(struct sony_sc *sc)
use_ds4_names = 1; use_ds4_names = 1;
name_len = 0; name_len = 0;
name_fmt = "%s:%s"; 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 { } else {
sixaxis_set_leds_from_id(sc->device_id, initial_values); sixaxis_set_leds_from_id(sc->device_id, initial_values);
sc->led_count = 4; sc->led_count = 4;
...@@ -1622,6 +1726,28 @@ static void dualshock4_state_worker(struct work_struct *work) ...@@ -1622,6 +1726,28 @@ static void dualshock4_state_worker(struct work_struct *work)
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); 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) static int sony_allocate_output_report(struct sony_sc *sc)
{ {
if (sc->quirks & SIXAXIS_CONTROLLER) if (sc->quirks & SIXAXIS_CONTROLLER)
...@@ -1634,6 +1760,10 @@ static int sony_allocate_output_report(struct sony_sc *sc) ...@@ -1634,6 +1760,10 @@ static int sony_allocate_output_report(struct sony_sc *sc)
else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x05_SIZE, sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x05_SIZE,
GFP_KERNEL); GFP_KERNEL);
else if (sc->quirks & MOTION_CONTROLLER)
sc->output_report_dmabuf =
kmalloc(sizeof(struct motion_output_report_02),
GFP_KERNEL);
else else
return 0; return 0;
...@@ -2043,6 +2173,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -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); sony_init_work(sc, dualshock4_state_worker);
} else if (sc->quirks & MOTION_CONTROLLER) {
sony_init_work(sc, motion_state_worker);
} else { } else {
ret = 0; ret = 0;
} }
...@@ -2123,6 +2255,8 @@ static const struct hid_device_id sony_devices[] = { ...@@ -2123,6 +2255,8 @@ static const struct hid_device_id sony_devices[] = {
.driver_data = SIXAXIS_CONTROLLER_USB }, .driver_data = SIXAXIS_CONTROLLER_USB },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_USB }, .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), { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_BT }, .driver_data = SIXAXIS_CONTROLLER_BT },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册