diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 53747245d904171756b094a07ecffa4cdedc36e6..48525de02a392fc26a1e302b5ac8cba89b784160 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -613,6 +613,14 @@ config HID_SONY * Sony PS3 Blue-ray Disk Remote Control (Bluetooth) * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth) +config SONY_FF + bool "Sony PS2/3 accessories force feedback support" + depends on HID_SONY + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you have a Sony PS2/3 accessory and want to enable force + feedback support for it. + config HID_SPEEDLINK tristate "Speedlink VAD Cezanne mouse support" depends on HID diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index bc37a1800166067af660aa108d2f528c8628a260..da551d11376257a328419e22ad7cd487784bea51 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -614,6 +614,54 @@ static void buzz_remove(struct hid_device *hdev) drv_data->extra = NULL; } +#ifdef CONFIG_SONY_FF +static int sony_play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + unsigned char buf[] = { + 0x01, + 0x00, 0xff, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0xff, 0x27, 0x10, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00 + }; + __u8 left; + __u8 right; + struct hid_device *hid = input_get_drvdata(dev); + + if (effect->type != FF_RUMBLE) + return 0; + + left = effect->u.rumble.strong_magnitude / 256; + right = effect->u.rumble.weak_magnitude ? 1 : 0; + + buf[3] = right; + buf[5] = left; + + return hid->hid_output_raw_report(hid, buf, sizeof(buf), + HID_OUTPUT_REPORT); +} + +static int sony_init_ff(struct hid_device *hdev) +{ + struct hid_input *hidinput = list_entry(hdev->inputs.next, + struct hid_input, list); + struct input_dev *input_dev = hidinput->input; + + input_set_capability(input_dev, EV_FF, FF_RUMBLE); + return input_ff_create_memless(input_dev, NULL, sony_play_effect); +} + +#else +static int sony_init_ff(struct hid_device *hdev) +{ + return 0; +} +#endif + static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; @@ -663,6 +711,10 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret < 0) goto err_stop; + ret = sony_init_ff(hdev); + if (ret < 0) + goto err_stop; + return 0; err_stop: hid_hw_stop(hdev);