Skip to content

Commit

Permalink
HID: sony: Add force feedback support for Dualshock3 USB
Browse files Browse the repository at this point in the history
Sony Dualshock 3 controllers have two motors which can be used to provide
simple force feedback rumble effects. The right motor is can be used to create
a weak rumble effect but does not allow to set the force. The left motor is
used to create a strong rumble effect with adjustable intensity.

The state of both motors can be changed using HID_OUTPUT_REPORT packets and
have no timing information. FF memless is used to keep track of the timing and
the sony driver just generates the necessary URBs.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
  • Loading branch information
Sven Eckelmann authored and Jiri Kosina committed Nov 11, 2013
1 parent ae2aa3a commit a08c22c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
8 changes: 8 additions & 0 deletions drivers/hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 52 additions & 0 deletions drivers/hid/hid-sony.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit a08c22c

Please sign in to comment.