Commit 2a242932 authored by Frank Praznik's avatar Frank Praznik Committed by Jiri Kosina

HID: sony: Defer the initial USB Sixaxis output report

When initially connected via USB the Sixaxis isn't fully initialized
until the PS logo button is pressed and won't send any input reports
nor will any state set by output reports be retained.

This adds a 'defer_initialization' flag to the sony_sc struct which,
when set, will delay sending any output reports until the first input
report has arrived. This flag is used with the USB Sixaxis to ensure
that any state sent will persist since, until the PS button is pushed,
any changes sent to the controller via an output report will be lost
after a couple of seconds.

The initial state of the controller is still configured at the time
of the initial connection and won't be internally modified after that,
so any state set by the user between that time and the recepit of the
first input report won't be lost.
Signed-off-by: default avatarFrank Praznik <frank.praznik@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 0f398230
...@@ -1050,6 +1050,7 @@ struct sony_sc { ...@@ -1050,6 +1050,7 @@ struct sony_sc {
u8 mac_address[6]; u8 mac_address[6];
u8 worker_initialized; u8 worker_initialized;
u8 defer_initialization;
u8 cable_state; u8 cable_state;
u8 battery_charging; u8 battery_charging;
u8 battery_capacity; u8 battery_capacity;
...@@ -1060,6 +1061,12 @@ struct sony_sc { ...@@ -1060,6 +1061,12 @@ struct sony_sc {
u8 led_count; u8 led_count;
}; };
static inline void sony_schedule_work(struct sony_sc *sc)
{
if (!sc->defer_initialization)
schedule_work(&sc->state_worker);
}
static u8 *sixaxis_fixup(struct hid_device *hdev, u8 *rdesc, static u8 *sixaxis_fixup(struct hid_device *hdev, u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
...@@ -1319,6 +1326,11 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, ...@@ -1319,6 +1326,11 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
dualshock4_parse_report(sc, rd, size); dualshock4_parse_report(sc, rd, size);
} }
if (sc->defer_initialization) {
sc->defer_initialization = 0;
sony_schedule_work(sc);
}
return 0; return 0;
} }
...@@ -1556,7 +1568,7 @@ static void buzz_set_leds(struct sony_sc *sc) ...@@ -1556,7 +1568,7 @@ static void buzz_set_leds(struct sony_sc *sc)
static void sony_set_leds(struct sony_sc *sc) static void sony_set_leds(struct sony_sc *sc)
{ {
if (!(sc->quirks & BUZZ_CONTROLLER)) if (!(sc->quirks & BUZZ_CONTROLLER))
schedule_work(&sc->state_worker); sony_schedule_work(sc);
else else
buzz_set_leds(sc); buzz_set_leds(sc);
} }
...@@ -1667,7 +1679,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on, ...@@ -1667,7 +1679,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
new_off != drv_data->led_delay_off[n]) { new_off != drv_data->led_delay_off[n]) {
drv_data->led_delay_on[n] = new_on; drv_data->led_delay_on[n] = new_on;
drv_data->led_delay_off[n] = new_off; drv_data->led_delay_off[n] = new_off;
schedule_work(&drv_data->state_worker); sony_schedule_work(drv_data);
} }
return 0; return 0;
...@@ -1978,7 +1990,7 @@ static int sony_play_effect(struct input_dev *dev, void *data, ...@@ -1978,7 +1990,7 @@ static int sony_play_effect(struct input_dev *dev, void *data,
sc->left = effect->u.rumble.strong_magnitude / 256; sc->left = effect->u.rumble.strong_magnitude / 256;
sc->right = effect->u.rumble.weak_magnitude / 256; sc->right = effect->u.rumble.weak_magnitude / 256;
schedule_work(&sc->state_worker); sony_schedule_work(sc);
return 0; return 0;
} }
...@@ -2365,9 +2377,16 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -2365,9 +2377,16 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
* the Sixaxis does not want the report_id as part of the data * the Sixaxis does not want the report_id as part of the data
* packet, so we have to discard buf[0] when sending the actual * packet, so we have to discard buf[0] when sending the actual
* control message, even for numbered reports, humpf! * control message, even for numbered reports, humpf!
*
* Additionally, the Sixaxis on USB isn't properly initialized
* until the PS logo button is pressed and as such won't retain
* any state set by an output report, so the initial
* configuration report is deferred until the first input
* report arrives.
*/ */
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID; hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
sc->defer_initialization = 1;
ret = sixaxis_set_operational_usb(hdev); ret = sixaxis_set_operational_usb(hdev);
sony_init_output_report(sc, sixaxis_send_output_report); sony_init_output_report(sc, sixaxis_send_output_report);
} else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) || } else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) ||
...@@ -2510,8 +2529,10 @@ static int sony_resume(struct hid_device *hdev) ...@@ -2510,8 +2529,10 @@ static int sony_resume(struct hid_device *hdev)
* reinitialized on resume or they won't behave properly. * reinitialized on resume or they won't behave properly.
*/ */
if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
(sc->quirks & NAVIGATION_CONTROLLER_USB)) (sc->quirks & NAVIGATION_CONTROLLER_USB)) {
sixaxis_set_operational_usb(sc->hdev); sixaxis_set_operational_usb(sc->hdev);
sc->defer_initialization = 1;
}
sony_set_leds(sc); sony_set_leds(sc);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment