Re: [PATCH 7/7] HID: sony: Prevent devices from being connected twice

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi

On Wed, Jan 29, 2014 at 6:33 PM, Frank Praznik <frank.praznik@xxxxxxxxx> wrote:
> 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@xxxxxxxxx>
>
> ---
>  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]);

Don't do this. UNIQ is a way to provide unique identifiers for
devices, but it's not guaranteed to stay the same.
Is it not possible to use the same FEATURE_REPORT as with USB?

Thanks
David

> +
> +               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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux