summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/Kconfig8
-rw-r--r--drivers/hid/hid-sony.c52
2 files changed, 60 insertions, 0 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 53747245d904..48525de02a39 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 bc37a1800166..da551d113762 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);