linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Frank Praznik <frank.praznik@oh.rr.com>
To: linux-input@vger.kernel.org
Cc: jkosina@suse.cz, Frank Praznik <frank.praznik@oh.rr.com>
Subject: [PATCH 7/7] HID: sony: Prevent devices from being connected twice
Date: Wed, 29 Jan 2014 12:33:17 -0500	[thread overview]
Message-ID: <1391016797-12842-8-git-send-email-frank.praznik@oh.rr.com> (raw)
In-Reply-To: <1391016797-12842-1-git-send-email-frank.praznik@oh.rr.com>

Prevent one controller from being connected twice and showing up as two devices
if a USB cable is plugged into the controller when it is already connected via
Bluetooth.

A global list of connected devices is maintained and newly connected controllers
are checked against this list. If it is found to already be present, the probe
function exits with an return value of EEXIST.

The MAC address of the Dualshock 4 is used as an identifier to track connected
controllers. It is retrieved with feature report 0x81 when connected via USB and
via the UNIQ identifier on a Bluetooth connection.

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

---
 drivers/hid/hid-sony.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 105 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index e478265..a24d021 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -710,8 +710,12 @@ static enum power_supply_property sony_battery_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 };
 
+static spinlock_t sony_dev_list_lock;
+static LIST_HEAD(sony_device_list);
+
 struct sony_sc {
 	spinlock_t lock;
+	struct list_head device_list;
 	struct hid_device *hdev;
 	struct led_classdev *leds[MAX_LEDS];
 	unsigned long quirks;
@@ -723,6 +727,7 @@ struct sony_sc {
 	__u8 right;
 #endif
 
+	__u8 mac_address[6];
 	__u8 cable_state;
 	__u8 battery_charging;
 	__u8 battery_capacity;
@@ -1471,6 +1476,94 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
 	return 0;
 }
 
+/* If a controller is plugged in via USB while already connected via Bluetooth
+ * it will show up as two devices. A global list of connected controllers and
+ * their MAC addresses is maintained to ensure that a device is only connected
+ * once.
+ */
+static int sony_check_add_dev_list(struct sony_sc *sc)
+{
+	struct sony_sc *entry;
+	struct list_head *pos;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&sony_dev_list_lock, flags);
+
+	list_for_each(pos, &sony_device_list) {
+		entry = list_entry(pos, struct sony_sc, device_list);
+		ret = memcmp(sc->mac_address, entry->mac_address,
+				FIELD_SIZEOF(struct sony_sc, mac_address));
+		if (!ret) {
+			hid_info(sc->hdev, "Controller already connected\n");
+			return -EEXIST;
+		}
+	}
+
+	list_add(&(sc->device_list), &sony_device_list);
+
+	spin_unlock_irqrestore(&sony_dev_list_lock, flags);
+
+	return 0;
+}
+
+static void sony_remove_dev_list(struct sony_sc *sc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sony_dev_list_lock, flags);
+	list_del(&(sc->device_list));
+	spin_unlock_irqrestore(&sony_dev_list_lock, flags);
+}
+
+static int dualshock4_check_add(struct sony_sc *sc)
+{
+	int ret;
+
+	if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
+		int n;
+		unsigned int mac_addr[6];
+
+		/* HIDP stores the device MAC address in the uniq member */
+		ret = strlen(sc->hdev->uniq);
+		if (ret != 17) {
+			hid_err(sc->hdev, "Malformed controller MAC address\n");
+			return -EINVAL;
+		}
+
+		ret = sscanf(sc->hdev->uniq, "%02x:%02x:%02x:%02x:%02x:%02x",
+			&mac_addr[5], &mac_addr[4], &mac_addr[3], &mac_addr[2],
+			&mac_addr[1], &mac_addr[0]);
+
+		if (ret != 6) {
+			hid_err(sc->hdev, "Error parsing controller MAC address\n");
+			return -EINVAL;
+		}
+
+		for (n = 5; n >= 0; n--)
+			sc->mac_address[n] = (__u8)mac_addr[n];
+	} else {
+		__u8 buf[7];
+
+		/* The MAC address of a DS4 controller connected via USB can be
+		 * retrieved with feature report 0x81.
+		 */
+		ret = sc->hdev->ll_driver->raw_request(sc->hdev, 0x81,
+			buf, sizeof(buf), HID_FEATURE_REPORT,
+			HID_REQ_GET_REPORT);
+
+		if (ret != 7) {
+			hid_err(sc->hdev, "Error retrieving with controller MAC address\n");
+			return ret;
+		}
+
+		memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address));
+	}
+
+	ret = sony_check_add_dev_list(sc);
+	return ret;
+}
+
 static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	int ret;
@@ -1515,8 +1608,13 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
 		ret = sixaxis_set_operational_bt(hdev);
 	else if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) ||
-		 (sc->quirks & DUALSHOCK4_CONTROLLER_BT)) {
-		/* The Dualshock 4 touchpad supports 2 touches and has a
+		(sc->quirks & DUALSHOCK4_CONTROLLER_BT)) {
+
+		ret = dualshock4_check_add(sc);
+		if (ret)
+			goto err_stop;
+
+		 /* The Dualshock 4 touchpad supports 2 touches and has a
 		 * resolution of 1920x940.
 		 */
 		ret = sony_register_touchpad(sc, 2, 1920, 940);
@@ -1580,6 +1678,11 @@ static void sony_remove(struct hid_device *hdev)
 
 	sony_destroy_ff(hdev);
 
+	if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) ||
+	    (sc->quirks & DUALSHOCK4_CONTROLLER_BT)) {
+		sony_remove_dev_list(sc);
+	}
+
 	hid_hw_stop(hdev);
 }
 
-- 
1.8.5.3


  parent reply	other threads:[~2014-01-29 17:33 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-01-29 17:33 [PATCH 0/7] HID: sony: Add full support for the Dualshock 4 on Bluetooth Frank Praznik
2014-01-29 17:33 ` [PATCH 1/7] HID: sony: Change dualshock4_state_worker to use the low-level transport driver function Frank Praznik
2014-01-29 17:39   ` David Herrmann
2014-01-29 17:33 ` [PATCH 2/7] HID: sony: Add Bluetooth HID descriptor for Dualshock 4 Frank Praznik
2014-01-29 17:33 ` [PATCH 3/7] HID: sony: Add Bluetooth output report formatting for the " Frank Praznik
2014-01-29 17:33 ` [PATCH 4/7] HID: sony: Add offsets and battery calculations for parsing Dualshock 4 reports sent via Bluetooth Frank Praznik
2014-01-29 21:36   ` simon
2014-01-29 17:33 ` [PATCH 5/7] HID: sony: Set inital battery level to 100% to avoid false low battery warnings Frank Praznik
2014-01-29 17:33 ` [PATCH 6/7] HID: sony: Add conditionals to enable LED, rumble, battery and touchpad support on the Dualshock 4 Frank Praznik
2014-01-29 17:33 ` Frank Praznik [this message]
2014-01-29 17:42   ` [PATCH 7/7] HID: sony: Prevent devices from being connected twice David Herrmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1391016797-12842-8-git-send-email-frank.praznik@oh.rr.com \
    --to=frank.praznik@oh.rr.com \
    --cc=jkosina@suse.cz \
    --cc=linux-input@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).