Commit 0f398230 authored by Frank Praznik's avatar Frank Praznik Committed by Jiri Kosina

HID: sony: Relax duplicate checking for USB-only devices

Some USB-only devices which masquerade as Sixaxis controllers report the
same generic Bluetooth address for all hardware when queried via the HID
report. This causes these devices to be wrongly rejected as duplicates
when more than one is connected at once.

This introduces a connection type comparison when checking for duplicates
and only rejects the newly connected device if the existing matching
device is connected using a different connection protocol.

The results of the connection type comparison are also used when
registering power supply info as the device Bluetooth address is used
as the unique identifier string.  In cases where more than one valid
device has the same Bluetooth address the device ID is now appended
to the power supply name string to avoid name collisions when
registering the power supply information.
Signed-off-by: default avatarFrank Praznik <frank.praznik@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 884316de
...@@ -65,6 +65,8 @@ ...@@ -65,6 +65,8 @@
MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER) MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER)
#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ #define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\
MOTION_CONTROLLER) MOTION_CONTROLLER)
#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\
MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT)
#define MAX_LEDS 4 #define MAX_LEDS 4
...@@ -2039,8 +2041,11 @@ static int sony_battery_get_property(struct power_supply *psy, ...@@ -2039,8 +2041,11 @@ static int sony_battery_get_property(struct power_supply *psy,
return ret; return ret;
} }
static int sony_battery_probe(struct sony_sc *sc) static int sony_battery_probe(struct sony_sc *sc, int append_dev_id)
{ {
const char *battery_str_fmt = append_dev_id ?
"sony_controller_battery_%pMR_%i" :
"sony_controller_battery_%pMR";
struct power_supply_config psy_cfg = { .drv_data = sc, }; struct power_supply_config psy_cfg = { .drv_data = sc, };
struct hid_device *hdev = sc->hdev; struct hid_device *hdev = sc->hdev;
int ret; int ret;
...@@ -2056,9 +2061,8 @@ static int sony_battery_probe(struct sony_sc *sc) ...@@ -2056,9 +2061,8 @@ static int sony_battery_probe(struct sony_sc *sc)
sc->battery_desc.get_property = sony_battery_get_property; sc->battery_desc.get_property = sony_battery_get_property;
sc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; sc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
sc->battery_desc.use_for_apm = 0; sc->battery_desc.use_for_apm = 0;
sc->battery_desc.name = kasprintf(GFP_KERNEL, sc->battery_desc.name = kasprintf(GFP_KERNEL, battery_str_fmt,
"sony_controller_battery_%pMR", sc->mac_address, sc->device_id);
sc->mac_address);
if (!sc->battery_desc.name) if (!sc->battery_desc.name)
return -ENOMEM; return -ENOMEM;
...@@ -2094,7 +2098,21 @@ static void sony_battery_remove(struct sony_sc *sc) ...@@ -2094,7 +2098,21 @@ static void sony_battery_remove(struct sony_sc *sc)
* it will show up as two devices. A global list of connected controllers and * 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 * their MAC addresses is maintained to ensure that a device is only connected
* once. * once.
*
* Some USB-only devices masquerade as Sixaxis controllers and all have the
* same dummy Bluetooth address, so a comparison of the connection type is
* required. Devices are only rejected in the case where two devices have
* matching Bluetooth addresses on different bus types.
*/ */
static inline int sony_compare_connection_type(struct sony_sc *sc0,
struct sony_sc *sc1)
{
const int sc0_not_bt = !(sc0->quirks & SONY_BT_DEVICE);
const int sc1_not_bt = !(sc1->quirks & SONY_BT_DEVICE);
return sc0_not_bt == sc1_not_bt;
}
static int sony_check_add_dev_list(struct sony_sc *sc) static int sony_check_add_dev_list(struct sony_sc *sc)
{ {
struct sony_sc *entry; struct sony_sc *entry;
...@@ -2107,9 +2125,14 @@ static int sony_check_add_dev_list(struct sony_sc *sc) ...@@ -2107,9 +2125,14 @@ static int sony_check_add_dev_list(struct sony_sc *sc)
ret = memcmp(sc->mac_address, entry->mac_address, ret = memcmp(sc->mac_address, entry->mac_address,
sizeof(sc->mac_address)); sizeof(sc->mac_address));
if (!ret) { if (!ret) {
if (sony_compare_connection_type(sc, entry)) {
ret = 1;
} else {
ret = -EEXIST; ret = -EEXIST;
hid_info(sc->hdev, "controller with MAC address %pMR already connected\n", hid_info(sc->hdev,
"controller with MAC address %pMR already connected\n",
sc->mac_address); sc->mac_address);
}
goto unlock; goto unlock;
} }
} }
...@@ -2285,6 +2308,7 @@ static inline void sony_cancel_work_sync(struct sony_sc *sc) ...@@ -2285,6 +2308,7 @@ static inline void sony_cancel_work_sync(struct sony_sc *sc)
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;
int append_dev_id;
unsigned long quirks = id->driver_data; unsigned long quirks = id->driver_data;
struct sony_sc *sc; struct sony_sc *sc;
unsigned int connect_mask = HID_CONNECT_DEFAULT; unsigned int connect_mask = HID_CONNECT_DEFAULT;
...@@ -2379,7 +2403,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -2379,7 +2403,7 @@ 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_check_add(sc); ret = append_dev_id = sony_check_add(sc);
if (ret < 0) if (ret < 0)
goto err_stop; goto err_stop;
...@@ -2390,7 +2414,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -2390,7 +2414,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
} }
if (sc->quirks & SONY_BATTERY_SUPPORT) { if (sc->quirks & SONY_BATTERY_SUPPORT) {
ret = sony_battery_probe(sc); ret = sony_battery_probe(sc, append_dev_id);
if (ret < 0) if (ret < 0)
goto err_stop; goto err_stop;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment