33
33
#include <linux/leds.h>
34
34
#include <linux/power_supply.h>
35
35
#include <linux/spinlock.h>
36
+ #include <linux/list.h>
36
37
#include <linux/input/mt.h>
37
38
38
39
#include "hid-ids.h"
@@ -717,8 +718,12 @@ static enum power_supply_property sony_battery_props[] = {
717
718
POWER_SUPPLY_PROP_STATUS ,
718
719
};
719
720
721
+ static spinlock_t sony_dev_list_lock ;
722
+ static LIST_HEAD (sony_device_list );
723
+
720
724
struct sony_sc {
721
725
spinlock_t lock ;
726
+ struct list_head list_node ;
722
727
struct hid_device * hdev ;
723
728
struct led_classdev * leds [MAX_LEDS ];
724
729
unsigned long quirks ;
@@ -730,6 +735,7 @@ struct sony_sc {
730
735
__u8 right ;
731
736
#endif
732
737
738
+ __u8 mac_address [6 ];
733
739
__u8 worker_initialized ;
734
740
__u8 cable_state ;
735
741
__u8 battery_charging ;
@@ -1489,6 +1495,133 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
1489
1495
return 0 ;
1490
1496
}
1491
1497
1498
+ /*
1499
+ * If a controller is plugged in via USB while already connected via Bluetooth
1500
+ * it will show up as two devices. A global list of connected controllers and
1501
+ * their MAC addresses is maintained to ensure that a device is only connected
1502
+ * once.
1503
+ */
1504
+ static int sony_check_add_dev_list (struct sony_sc * sc )
1505
+ {
1506
+ struct sony_sc * entry ;
1507
+ unsigned long flags ;
1508
+ int ret ;
1509
+
1510
+ spin_lock_irqsave (& sony_dev_list_lock , flags );
1511
+
1512
+ list_for_each_entry (entry , & sony_device_list , list_node ) {
1513
+ ret = memcmp (sc -> mac_address , entry -> mac_address ,
1514
+ sizeof (sc -> mac_address ));
1515
+ if (!ret ) {
1516
+ ret = - EEXIST ;
1517
+ hid_info (sc -> hdev , "controller with MAC address %pMR already connected\n" ,
1518
+ sc -> mac_address );
1519
+ goto unlock ;
1520
+ }
1521
+ }
1522
+
1523
+ ret = 0 ;
1524
+ list_add (& (sc -> list_node ), & sony_device_list );
1525
+
1526
+ unlock :
1527
+ spin_unlock_irqrestore (& sony_dev_list_lock , flags );
1528
+ return ret ;
1529
+ }
1530
+
1531
+ static void sony_remove_dev_list (struct sony_sc * sc )
1532
+ {
1533
+ unsigned long flags ;
1534
+
1535
+ if (sc -> list_node .next ) {
1536
+ spin_lock_irqsave (& sony_dev_list_lock , flags );
1537
+ list_del (& (sc -> list_node ));
1538
+ spin_unlock_irqrestore (& sony_dev_list_lock , flags );
1539
+ }
1540
+ }
1541
+
1542
+ static int sony_get_bt_devaddr (struct sony_sc * sc )
1543
+ {
1544
+ int ret ;
1545
+
1546
+ /* HIDP stores the device MAC address as a string in the uniq field. */
1547
+ ret = strlen (sc -> hdev -> uniq );
1548
+ if (ret != 17 )
1549
+ return - EINVAL ;
1550
+
1551
+ ret = sscanf (sc -> hdev -> uniq ,
1552
+ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx" ,
1553
+ & sc -> mac_address [5 ], & sc -> mac_address [4 ], & sc -> mac_address [3 ],
1554
+ & sc -> mac_address [2 ], & sc -> mac_address [1 ], & sc -> mac_address [0 ]);
1555
+
1556
+ if (ret != 6 )
1557
+ return - EINVAL ;
1558
+
1559
+ return 0 ;
1560
+ }
1561
+
1562
+ static int sony_check_add (struct sony_sc * sc )
1563
+ {
1564
+ int n , ret ;
1565
+
1566
+ if ((sc -> quirks & DUALSHOCK4_CONTROLLER_BT ) ||
1567
+ (sc -> quirks & SIXAXIS_CONTROLLER_BT )) {
1568
+ /*
1569
+ * sony_get_bt_devaddr() attempts to parse the Bluetooth MAC
1570
+ * address from the uniq string where HIDP stores it.
1571
+ * As uniq cannot be guaranteed to be a MAC address in all cases
1572
+ * a failure of this function should not prevent the connection.
1573
+ */
1574
+ if (sony_get_bt_devaddr (sc ) < 0 ) {
1575
+ hid_warn (sc -> hdev , "UNIQ does not contain a MAC address; duplicate check skipped\n" );
1576
+ return 0 ;
1577
+ }
1578
+ } else if (sc -> quirks & DUALSHOCK4_CONTROLLER_USB ) {
1579
+ __u8 buf [7 ];
1580
+
1581
+ /*
1582
+ * The MAC address of a DS4 controller connected via USB can be
1583
+ * retrieved with feature report 0x81. The address begins at
1584
+ * offset 1.
1585
+ */
1586
+ ret = hid_hw_raw_request (sc -> hdev , 0x81 , buf , sizeof (buf ),
1587
+ HID_FEATURE_REPORT , HID_REQ_GET_REPORT );
1588
+
1589
+ if (ret != 7 ) {
1590
+ hid_err (sc -> hdev , "failed to retrieve feature report 0x81 with the DualShock 4 MAC address\n" );
1591
+ return ret < 0 ? ret : - EINVAL ;
1592
+ }
1593
+
1594
+ memcpy (sc -> mac_address , & buf [1 ], sizeof (sc -> mac_address ));
1595
+ } else if (sc -> quirks & SIXAXIS_CONTROLLER_USB ) {
1596
+ __u8 buf [18 ];
1597
+
1598
+ /*
1599
+ * The MAC address of a Sixaxis controller connected via USB can
1600
+ * be retrieved with feature report 0xf2. The address begins at
1601
+ * offset 4.
1602
+ */
1603
+ ret = hid_hw_raw_request (sc -> hdev , 0xf2 , buf , sizeof (buf ),
1604
+ HID_FEATURE_REPORT , HID_REQ_GET_REPORT );
1605
+
1606
+ if (ret != 18 ) {
1607
+ hid_err (sc -> hdev , "failed to retrieve feature report 0xf2 with the Sixaxis MAC address\n" );
1608
+ return ret < 0 ? ret : - EINVAL ;
1609
+ }
1610
+
1611
+ /*
1612
+ * The Sixaxis device MAC in the report is big-endian and must
1613
+ * be byte-swapped.
1614
+ */
1615
+ for (n = 0 ; n < 6 ; n ++ )
1616
+ sc -> mac_address [5 - n ] = buf [4 + n ];
1617
+ } else {
1618
+ return 0 ;
1619
+ }
1620
+
1621
+ return sony_check_add_dev_list (sc );
1622
+ }
1623
+
1624
+
1492
1625
static int sony_probe (struct hid_device * hdev , const struct hid_device_id * id )
1493
1626
{
1494
1627
int ret ;
@@ -1556,6 +1689,10 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
1556
1689
ret = 0 ;
1557
1690
}
1558
1691
1692
+ if (ret < 0 )
1693
+ goto err_stop ;
1694
+
1695
+ ret = sony_check_add (sc );
1559
1696
if (ret < 0 )
1560
1697
goto err_stop ;
1561
1698
@@ -1594,6 +1731,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
1594
1731
sony_battery_remove (sc );
1595
1732
if (sc -> worker_initialized )
1596
1733
cancel_work_sync (& sc -> state_worker );
1734
+ sony_remove_dev_list (sc );
1597
1735
hid_hw_stop (hdev );
1598
1736
return ret ;
1599
1737
}
@@ -1613,6 +1751,8 @@ static void sony_remove(struct hid_device *hdev)
1613
1751
if (sc -> worker_initialized )
1614
1752
cancel_work_sync (& sc -> state_worker );
1615
1753
1754
+ sony_remove_dev_list (sc );
1755
+
1616
1756
hid_hw_stop (hdev );
1617
1757
}
1618
1758
0 commit comments