diff mbox

[1/2] HID: sony: Add force feedback for the Dualshock 4

Message ID alpine.DEB.2.10.1401031518010.29517@franz-virtual-machine (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show

Commit Message

Frank Praznik Jan. 3, 2014, 9:03 p.m. UTC
This patch adds force feedback support for Sony's Dualshock 4 controller.  
It does this by adding a device ID for the new controller and creating a 
new dualshock4_worker function to send data commands formatted for the 
controller.  Unlike the Sixaxis, the Dualshock 4 requires a magnitude 
value for the small motor so the actual value is now sent to the worker 
function and the sixaxis worker was modified to clamp it to 1 or 0 as required.

This patch is built against the for-3.14/sony branch in jikos/hid.git and 
is compatible with the recent fixes.

Signed-off-by Frank Praznik <frank.praznik@oh.rr.com>

---
 drivers/hid/hid-ids.h  |  1 +
 drivers/hid/hid-sony.c | 41 +++++++++++++++++++++++++++++++++++++----
 2 files changed, 38 insertions(+), 4 deletions(-)

Comments

simon@mungewell.org Jan. 5, 2014, 1:10 a.m. UTC | #1
> This patch adds force feedback support for Sony's Dualshock 4 controller.
> It does this by adding a device ID for the new controller and creating a
> new dualshock4_worker function to send data commands formatted for the
> controller.  Unlike the Sixaxis, the Dualshock 4 requires a magnitude
> value for the small motor so the actual value is now sent to the worker
> function and the sixaxis worker was modified to clamp it to 1 or 0 as
> required.

I was able to build this and the LED patch against the 3.13rc6 kernel
having first applied this sequence of patches:
https://patchwork.kernel.org/patch/3203761/

However I am seeing some weird behaviour in whether FF/LED actually
functions. It seems that in a 'complete' kernel installation the driver
does not present FF or LED.

But if I use a stock 3.13rc6 kernel, load the 'hid-sony' module from that
and then remove and install the patched one it does work.
--
$ sudo modprobe hid-sony (stock)
$ sudo rmmod hid-sony
$ sudo insmod hid-sony.ko (patched)
--

Not sure what this means, lsmod looks to be the same in both. Perhaps
there is something which is only initialised in the stock version.

Willing to test if anyone has suggestions/comments. I am testing with the
DS4 connected with USB (not BT).
--
Jan  4 17:55:14 simon-virtual-machine kernel: [  138.964626] usb 1-1: new
full-speed USB device number 3 using ohci-pci
Jan  4 17:55:14 simon-virtual-machine mtp-probe: checking bus 1, device 3:
"/sys/devices/pci0000:00/0000:00:06.0/usb1/1-1"
Jan  4 17:55:14 simon-virtual-machine mtp-probe: bus: 1, device: 3 was not
an MTP device
Jan  4 17:55:14 simon-virtual-machine kernel: [  139.416656] usb 1-1: New
USB device found, idVendor=054c, idProduct=05c4
Jan  4 17:55:14 simon-virtual-machine kernel: [  139.416661] usb 1-1: New
USB device strings: Mfr=1, Product=2, SerialNumber=0
Jan  4 17:55:14 simon-virtual-machine kernel: [  139.416663] usb 1-1:
Product: Wireless Controller
Jan  4 17:55:14 simon-virtual-machine kernel: [  139.416665] usb 1-1:
Manufacturer: Sony Computer Entertainment
Jan  4 17:55:14 simon-virtual-machine kernel: [  139.517356] input: Sony
Computer Entertainment Wireless Controller as
/devices/pci0000:00/0000:00:06.0/usb1/1-1/1-1:1.0/input/input6
Jan  4 17:55:14 simon-virtual-machine kernel: [  139.518359] hid-generic
0003:054C:05C4.0002: input,hidraw0: USB HID v1.11 Gamepad [Sony Computer
Entertainment Wireless Controller] on usb-0000:00:06.0-1/input0
--
simon@simon-virtual-machine:~$ ls /sys/class/leds/
simon@simon-virtual-machine:~$
--

Cheers,
Simon

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
simon@mungewell.org Jan. 9, 2014, 3:46 a.m. UTC | #2
> However I am seeing some weird behaviour in whether FF/LED actually
> functions. It seems that in a 'complete' kernel installation the driver
> does not present FF or LED.
>
> But if I use a stock 3.13rc6 kernel, load the 'hid-sony' module from that
> and then remove and install the patched one it does work.
> --
> $ sudo modprobe hid-sony (stock)
> $ sudo rmmod hid-sony
> $ sudo insmod hid-sony.ko (patched)
> --

I note that using the above modprobe/rmmod/insmod trick the message log
shows additional lines
--
Jan  8 20:12:29 atom kernel: [  144.840112] input: Sony Computer
Entertainment Wireless Controller as
/devices/pci0000:00/0000:00:1d.1/usb3/3-1/3-1:1.0/input/input9
Jan  8 20:12:29 atom kernel: [  144.841044] sony 0003:054C:05C4.0001:
input,hidraw0: USB HID v1.11 Gamepad [Sony Computer Entertainment Wireless
Controller] on usb-0000:00:1d.1-1/input0
Jan  8 20:12:29 atom kernel: [  144.841560] usbcore: registered new
interface driver usbhid
Jan  8 20:12:29 atom kernel: [  144.841563] usbhid: USB HID core driver
--

and the Sony driver is being used
--
root@atom:/sys/bus/usb/devices/3-1:1.0# ls -al 0003\:054C\:05C4.0001/
total 0
drwxr-xr-x 5 root root    0 Jan  8 20:12 .
drwxr-xr-x 7 root root    0 Jan  8 20:12 ..
lrwxrwxrwx 1 root root    0 Jan  8 20:13 driver ->
../../../../../../../bus/hid/drivers/sony
--

Whereas with the fully patched kernel it is not
--
root@atom:/sys/bus/usb/devices/3-1:1.0# ls -al 0003\:054C\:05C4.0001/
total 0
drwxr-xr-x 4 root root    0 Jan  8 20:20 .
drwxr-xr-x 7 root root    0 Jan  8 20:20 ..
lrwxrwxrwx 1 root root    0 Jan  8 20:21 driver ->
../../../../../../../bus/hid/drivers/hid-generic
--


Further more my DS3-SixAxis appears to work OK with the full kernel, where
the DS4 does not.... any suggestions?

Simon

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
simon@mungewell.org Jan. 9, 2014, 6:42 a.m. UTC | #3
>
>> However I am seeing some weird behaviour in whether FF/LED actually
>> functions. It seems that in a 'complete' kernel installation the driver
>> does not present FF or LED.
>>

Found the problem (or at least a solution), there is no entry in 'hid-core.c'
--
static const struct hid_device_id hid_have_special_driver[] = {
...
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY,
USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
--

Adding this makes it work for me, although I don't know why the insmod
trick was working....
Simon

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Antonio Ospite Jan. 9, 2014, 10:38 a.m. UTC | #4
On Fri, 3 Jan 2014 16:03:10 -0500 (EST)
Frank Praznik <frank.praznik@oh.rr.com> wrote:

Hi Frank,

just some notes about the style.

> This patch adds force feedback support for Sony's Dualshock 4 controller.  

You can just use the imperative form in the long commit message too:
"Add force feedback support for Sony's Dualshock 4 controller..."

No need to repeat "This patch ..." in the commit message.

> It does this by adding a device ID for the new controller and creating a 
> new dualshock4_worker function to send data commands formatted for the 
> controller.  Unlike the Sixaxis, the Dualshock 4 requires a magnitude 
> value for the small motor so the actual value is now sent to the worker 
> function and the sixaxis worker was modified to clamp it to 1 or 0 as required.
> 
> This patch is built against the for-3.14/sony branch in jikos/hid.git and 
> is compatible with the recent fixes.

this last sentence is more like an annotation, put annotations after the
three dashes below, just before the diffstat, don't put them in the
commit message because they will become outdated and they will look odd
when someone reads the project history at some point in the future.

An alternative is to generate a cover-letter with git-format-patch and
mention there the prerequisites for the patch series.

> Signed-off-by Frank Praznik <frank.praznik@oh.rr.com>
> 
> ---
>  drivers/hid/hid-ids.h  |  1 +
>  drivers/hid/hid-sony.c | 41 +++++++++++++++++++++++++++++++++++++----
>  2 files changed, 38 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 60336f06..ebbd292 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -769,6 +769,7 @@
>  #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER	0x042f
>  #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER		0x0002
>  #define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER	0x1000
> +#define USB_DEVICE_ID_SONY_PS4_CONTROLLER	0x05c4
>

You can align the value with the other ones using two TABs in this case.

>  #define USB_VENDOR_ID_SOUNDGRAPH	0x15c2
>  #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST	0x0034
> diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
> index f57ab5e..f42c866 100644
> --- a/drivers/hid/hid-sony.c
> +++ b/drivers/hid/hid-sony.c
> @@ -38,6 +38,7 @@
>  #define SIXAXIS_CONTROLLER_BT   BIT(2)
>  #define BUZZ_CONTROLLER         BIT(3)
>  #define PS3REMOTE		BIT(4)
> +#define DUALSHOCK4_CONTROLLER	BIT(5\)

most of the entries are aligned with spaces here so use spaces,
PS3REMOTE will be fixed eventually. Also, what about the backslash
before the parenthesis?

>  #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER)
>  
> @@ -615,7 +616,7 @@ error_leds:
>  	return ret;
>  }
>  
> -static void sony_state_worker(struct work_struct *work)
> +static void sixaxis_state_worker(struct work_struct *work)

this is a rename, I understand it is in preparation for
dualshock4_state_worker() but it's not _directly_ related to the topic
of the patch; split cleanups and cosmetic changes from functional
changes, it is easier to review and validate logically contained
patches.

>  {
>  	struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
>  	unsigned char buf[] = {
> @@ -630,7 +631,7 @@ static void sony_state_worker(struct work_struct *work)
>  	};
>  
>  #ifdef CONFIG_SONY_FF
> -	buf[3] = sc->right;
> +	buf[3] = sc->right ? 1 : 0;
>  	buf[5] = sc->left;
>  #endif
>  
> @@ -640,6 +641,29 @@ static void sony_state_worker(struct work_struct *work)
>  					HID_OUTPUT_REPORT);
>  }
>  
> +static void dualshock4_state_worker(struct work_struct *work)
> +{
> +	struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
> +	unsigned char buf[] = {
> +		0x05,
> +		0x03, 0x00, 0x00, 0x00, 0x00,
> +		0x00, 0x00, 0x00, 0x00, 0x00,
> +		0x00, 0x00, 0x00, 0x00, 0x00,
> +		0x00, 0x00, 0x00, 0x00, 0x00,
> +		0x00, 0x00, 0x00, 0x00, 0x00,
> +		0x00, 0x00, 0x00, 0x00, 0x00,
> +		0x00,
> +	};
> +
> +#ifdef CONFIG_SONY_FF
> +	buf[4] = sc->right;
> +	buf[5] = sc->left;
> +#endif
> +
> +	sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf),
> +					HID_OUTPUT_REPORT);
> +}
> +
>  #ifdef CONFIG_SONY_FF
>  static int sony_play_effect(struct input_dev *dev, void *data,
>  			    struct ff_effect *effect)
> @@ -651,7 +675,7 @@ static int sony_play_effect(struct input_dev *dev, void *data,
>  		return 0;
>  
>  	sc->left = effect->u.rumble.strong_magnitude / 256;
> -	sc->right = effect->u.rumble.weak_magnitude ? 1 : 0;
> +	sc->right = effect->u.rumble.weak_magnitude / 256;
>  
>  	schedule_work(&sc->state_worker);
>  	return 0;
> @@ -724,10 +748,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
>  	if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
>  		hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
>  		ret = sixaxis_set_operational_usb(hdev);
> -		INIT_WORK(&sc->state_worker, sony_state_worker);
> +		INIT_WORK(&sc->state_worker, sixaxis_state_worker);
>  	}
>  	else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
>  		ret = sixaxis_set_operational_bt(hdev);
> +	else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
> +		ret = 0;
> +		INIT_WORK(&sc->state_worker, dualshock4_state_worker);
> +	}
>  	else
>  		ret = 0;
>  
> @@ -787,6 +815,11 @@ static const struct hid_device_id sony_devices[] = {
>  	/* Logitech Harmony Adapter for PS3 */
>  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3),
>  		.driver_data = PS3REMOTE },
> +	/* Sony Dualshock 4 controllers for PS4 */
> +	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
> +		.driver_data = DUALSHOCK4_CONTROLLER },
> +	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
> +		.driver_data = DUALSHOCK4_CONTROLLER },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(hid, sony_devices);
> -- 
> 1.8.3.2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Frank Praznik Jan. 9, 2014, 7:29 p.m. UTC | #5
On 1/9/2014 01:42, simon@mungewell.org wrote:
>>> However I am seeing some weird behaviour in whether FF/LED actually
>>> functions. It seems that in a 'complete' kernel installation the driver
>>> does not present FF or LED.
>>>
> Found the problem (or at least a solution), there is no entry in 'hid-core.c'
> --
> static const struct hid_device_id hid_have_special_driver[] = {
> ...
> 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY,
> USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
> --
>
> Adding this makes it work for me, although I don't know why the insmod
> trick was working....
> Simon
>
Ah, I didn't realize that it needed an entry there.  I'll add this to v2 
of the patch set.  Thanks!
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 60336f06..ebbd292 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -769,6 +769,7 @@ 
 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER	0x042f
 #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER		0x0002
 #define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER	0x1000
+#define USB_DEVICE_ID_SONY_PS4_CONTROLLER	0x05c4
 
 #define USB_VENDOR_ID_SOUNDGRAPH	0x15c2
 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST	0x0034
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index f57ab5e..f42c866 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -38,6 +38,7 @@ 
 #define SIXAXIS_CONTROLLER_BT   BIT(2)
 #define BUZZ_CONTROLLER         BIT(3)
 #define PS3REMOTE		BIT(4)
+#define DUALSHOCK4_CONTROLLER	BIT(5)
 
 #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER)
 
@@ -615,7 +616,7 @@  error_leds:
 	return ret;
 }
 
-static void sony_state_worker(struct work_struct *work)
+static void sixaxis_state_worker(struct work_struct *work)
 {
 	struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
 	unsigned char buf[] = {
@@ -630,7 +631,7 @@  static void sony_state_worker(struct work_struct *work)
 	};
 
 #ifdef CONFIG_SONY_FF
-	buf[3] = sc->right;
+	buf[3] = sc->right ? 1 : 0;
 	buf[5] = sc->left;
 #endif
 
@@ -640,6 +641,29 @@  static void sony_state_worker(struct work_struct *work)
 					HID_OUTPUT_REPORT);
 }
 
+static void dualshock4_state_worker(struct work_struct *work)
+{
+	struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
+	unsigned char buf[] = {
+		0x05,
+		0x03, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00,
+	};
+
+#ifdef CONFIG_SONY_FF
+	buf[4] = sc->right;
+	buf[5] = sc->left;
+#endif
+
+	sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf),
+					HID_OUTPUT_REPORT);
+}
+
 #ifdef CONFIG_SONY_FF
 static int sony_play_effect(struct input_dev *dev, void *data,
 			    struct ff_effect *effect)
@@ -651,7 +675,7 @@  static int sony_play_effect(struct input_dev *dev, void *data,
 		return 0;
 
 	sc->left = effect->u.rumble.strong_magnitude / 256;
-	sc->right = effect->u.rumble.weak_magnitude ? 1 : 0;
+	sc->right = effect->u.rumble.weak_magnitude / 256;
 
 	schedule_work(&sc->state_worker);
 	return 0;
@@ -724,10 +748,14 @@  static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
 		hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
 		ret = sixaxis_set_operational_usb(hdev);
-		INIT_WORK(&sc->state_worker, sony_state_worker);
+		INIT_WORK(&sc->state_worker, sixaxis_state_worker);
 	}
 	else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
 		ret = sixaxis_set_operational_bt(hdev);
+	else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
+		ret = 0;
+		INIT_WORK(&sc->state_worker, dualshock4_state_worker);
+	}
 	else
 		ret = 0;
 
@@ -787,6 +815,11 @@  static const struct hid_device_id sony_devices[] = {
 	/* Logitech Harmony Adapter for PS3 */
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3),
 		.driver_data = PS3REMOTE },
+	/* Sony Dualshock 4 controllers for PS4 */
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
+		.driver_data = DUALSHOCK4_CONTROLLER },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
+		.driver_data = DUALSHOCK4_CONTROLLER },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, sony_devices);