forked from Minki/linux
HID: sony: Add force feedback support for Dualshock3 USB
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>
This commit is contained in:
parent
ae2aa3a512
commit
a08c22c0df
@ -613,6 +613,14 @@ config HID_SONY
|
|||||||
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
|
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
|
||||||
* Logitech Harmony adapter for Sony Playstation 3 (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
|
config HID_SPEEDLINK
|
||||||
tristate "Speedlink VAD Cezanne mouse support"
|
tristate "Speedlink VAD Cezanne mouse support"
|
||||||
depends on HID
|
depends on HID
|
||||||
|
@ -614,6 +614,54 @@ static void buzz_remove(struct hid_device *hdev)
|
|||||||
drv_data->extra = NULL;
|
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)
|
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -663,6 +711,10 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_stop;
|
goto err_stop;
|
||||||
|
|
||||||
|
ret = sony_init_ff(hdev);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err_stop;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err_stop:
|
err_stop:
|
||||||
hid_hw_stop(hdev);
|
hid_hw_stop(hdev);
|
||||||
|
Loading…
Reference in New Issue
Block a user