aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Praznik <frank.praznik@oh.rr.com>2014-04-14 10:11:35 -0400
committerJiri Kosina <jkosina@suse.cz>2014-04-24 12:53:41 -0400
commit8025087acf9d2b941bae93b3e0967560e7e03e87 (patch)
tree469b78c498d5e127461638e1b944f12466a9d6c9
parent314531f18de0063131567c535af0cec3e4969c24 (diff)
HID: sony: Initialize the controller LEDs with a device ID value
Add an IDA id allocator to assign unique, sequential device ids to Sixaxis and DualShock 4 controllers. Use the device ID to initialize the Sixaxis and DualShock 4 controller LEDs to default values. The number or color of the controller is set relative to other connected Sony controllers. Set the LED class brightness values to the initial values and add the new led to the array before calling led_classdev_register so that the correct brightness value shows up in the LED sysfs entry. Use explicit module init and exit functions since the IDA allocator must be manually destroyed when the module is unloaded. Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-sony.c119
1 files changed, 114 insertions, 5 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 6ce2e3ab0693..b41356cacc14 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -33,6 +33,7 @@
33#include <linux/power_supply.h> 33#include <linux/power_supply.h>
34#include <linux/spinlock.h> 34#include <linux/spinlock.h>
35#include <linux/list.h> 35#include <linux/list.h>
36#include <linux/idr.h>
36#include <linux/input/mt.h> 37#include <linux/input/mt.h>
37 38
38#include "hid-ids.h" 39#include "hid-ids.h"
@@ -749,6 +750,7 @@ union sixaxis_output_report_01 {
749 750
750static spinlock_t sony_dev_list_lock; 751static spinlock_t sony_dev_list_lock;
751static LIST_HEAD(sony_device_list); 752static LIST_HEAD(sony_device_list);
753static DEFINE_IDA(sony_device_id_allocator);
752 754
753struct sony_sc { 755struct sony_sc {
754 spinlock_t lock; 756 spinlock_t lock;
@@ -758,6 +760,7 @@ struct sony_sc {
758 unsigned long quirks; 760 unsigned long quirks;
759 struct work_struct state_worker; 761 struct work_struct state_worker;
760 struct power_supply battery; 762 struct power_supply battery;
763 int device_id;
761 764
762#ifdef CONFIG_SONY_FF 765#ifdef CONFIG_SONY_FF
763 __u8 left; 766 __u8 left;
@@ -1078,6 +1081,52 @@ static int dualshock4_set_operational_bt(struct hid_device *hdev)
1078 HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 1081 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
1079} 1082}
1080 1083
1084static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS])
1085{
1086 static const __u8 sixaxis_leds[10][4] = {
1087 { 0x01, 0x00, 0x00, 0x00 },
1088 { 0x00, 0x01, 0x00, 0x00 },
1089 { 0x00, 0x00, 0x01, 0x00 },
1090 { 0x00, 0x00, 0x00, 0x01 },
1091 { 0x01, 0x00, 0x00, 0x01 },
1092 { 0x00, 0x01, 0x00, 0x01 },
1093 { 0x00, 0x00, 0x01, 0x01 },
1094 { 0x01, 0x00, 0x01, 0x01 },
1095 { 0x00, 0x01, 0x01, 0x01 },
1096 { 0x01, 0x01, 0x01, 0x01 }
1097 };
1098
1099 BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0]));
1100
1101 if (id < 0)
1102 return;
1103
1104 id %= 10;
1105 memcpy(values, sixaxis_leds[id], sizeof(sixaxis_leds[id]));
1106}
1107
1108static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS])
1109{
1110 /* The first 4 color/index entries match what the PS4 assigns */
1111 static const __u8 color_code[7][3] = {
1112 /* Blue */ { 0x00, 0x00, 0x01 },
1113 /* Red */ { 0x01, 0x00, 0x00 },
1114 /* Green */ { 0x00, 0x01, 0x00 },
1115 /* Pink */ { 0x02, 0x00, 0x01 },
1116 /* Orange */ { 0x02, 0x01, 0x00 },
1117 /* Teal */ { 0x00, 0x01, 0x01 },
1118 /* White */ { 0x01, 0x01, 0x01 }
1119 };
1120
1121 BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0]));
1122
1123 if (id < 0)
1124 return;
1125
1126 id %= 7;
1127 memcpy(values, color_code[id], sizeof(color_code[id]));
1128}
1129
1081static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds) 1130static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
1082{ 1131{
1083 struct list_head *report_list = 1132 struct list_head *report_list =
@@ -1191,7 +1240,7 @@ static int sony_leds_init(struct sony_sc *sc)
1191 size_t name_len; 1240 size_t name_len;
1192 const char *name_fmt; 1241 const char *name_fmt;
1193 static const char * const color_str[] = { "red", "green", "blue" }; 1242 static const char * const color_str[] = { "red", "green", "blue" };
1194 static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 }; 1243 __u8 initial_values[MAX_LEDS] = { 0 };
1195 1244
1196 BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); 1245 BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
1197 1246
@@ -1205,12 +1254,14 @@ static int sony_leds_init(struct sony_sc *sc)
1205 if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7)) 1254 if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
1206 return -ENODEV; 1255 return -ENODEV;
1207 } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { 1256 } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
1257 dualshock4_set_leds_from_id(sc->device_id, initial_values);
1208 sc->led_count = 3; 1258 sc->led_count = 3;
1209 max_brightness = 255; 1259 max_brightness = 255;
1210 use_colors = 1; 1260 use_colors = 1;
1211 name_len = 0; 1261 name_len = 0;
1212 name_fmt = "%s:%s"; 1262 name_fmt = "%s:%s";
1213 } else { 1263 } else {
1264 sixaxis_set_leds_from_id(sc->device_id, initial_values);
1214 sc->led_count = 4; 1265 sc->led_count = 4;
1215 max_brightness = 1; 1266 max_brightness = 1;
1216 use_colors = 0; 1267 use_colors = 0;
@@ -1245,19 +1296,20 @@ static int sony_leds_init(struct sony_sc *sc)
1245 else 1296 else
1246 snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); 1297 snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1);
1247 led->name = name; 1298 led->name = name;
1248 led->brightness = 0; 1299 led->brightness = initial_values[n];
1249 led->max_brightness = max_brightness; 1300 led->max_brightness = max_brightness;
1250 led->brightness_get = sony_led_get_brightness; 1301 led->brightness_get = sony_led_get_brightness;
1251 led->brightness_set = sony_led_set_brightness; 1302 led->brightness_set = sony_led_set_brightness;
1252 1303
1304 sc->leds[n] = led;
1305
1253 ret = led_classdev_register(&hdev->dev, led); 1306 ret = led_classdev_register(&hdev->dev, led);
1254 if (ret) { 1307 if (ret) {
1255 hid_err(hdev, "Failed to register LED %d\n", n); 1308 hid_err(hdev, "Failed to register LED %d\n", n);
1309 sc->leds[n] = NULL;
1256 kfree(led); 1310 kfree(led);
1257 goto error_leds; 1311 goto error_leds;
1258 } 1312 }
1259
1260 sc->leds[n] = led;
1261 } 1313 }
1262 1314
1263 return ret; 1315 return ret;
@@ -1603,6 +1655,38 @@ static int sony_check_add(struct sony_sc *sc)
1603 return sony_check_add_dev_list(sc); 1655 return sony_check_add_dev_list(sc);
1604} 1656}
1605 1657
1658static int sony_set_device_id(struct sony_sc *sc)
1659{
1660 int ret;
1661
1662 /*
1663 * Only DualShock 4 or Sixaxis controllers get an id.
1664 * All others are set to -1.
1665 */
1666 if ((sc->quirks & SIXAXIS_CONTROLLER) ||
1667 (sc->quirks & DUALSHOCK4_CONTROLLER)) {
1668 ret = ida_simple_get(&sony_device_id_allocator, 0, 0,
1669 GFP_KERNEL);
1670 if (ret < 0) {
1671 sc->device_id = -1;
1672 return ret;
1673 }
1674 sc->device_id = ret;
1675 } else {
1676 sc->device_id = -1;
1677 }
1678
1679 return 0;
1680}
1681
1682static void sony_release_device_id(struct sony_sc *sc)
1683{
1684 if (sc->device_id >= 0) {
1685 ida_simple_remove(&sony_device_id_allocator, sc->device_id);
1686 sc->device_id = -1;
1687 }
1688}
1689
1606static inline void sony_init_work(struct sony_sc *sc, 1690static inline void sony_init_work(struct sony_sc *sc,
1607 void (*worker)(struct work_struct *)) 1691 void (*worker)(struct work_struct *))
1608{ 1692{
@@ -1654,6 +1738,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
1654 return ret; 1738 return ret;
1655 } 1739 }
1656 1740
1741 ret = sony_set_device_id(sc);
1742 if (ret < 0) {
1743 hid_err(hdev, "failed to allocate the device id\n");
1744 goto err_stop;
1745 }
1746
1657 if (sc->quirks & SIXAXIS_CONTROLLER_USB) { 1747 if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
1658 /* 1748 /*
1659 * The Sony Sixaxis does not handle HID Output Reports on the 1749 * The Sony Sixaxis does not handle HID Output Reports on the
@@ -1745,6 +1835,7 @@ err_stop:
1745 sony_battery_remove(sc); 1835 sony_battery_remove(sc);
1746 sony_cancel_work_sync(sc); 1836 sony_cancel_work_sync(sc);
1747 sony_remove_dev_list(sc); 1837 sony_remove_dev_list(sc);
1838 sony_release_device_id(sc);
1748 hid_hw_stop(hdev); 1839 hid_hw_stop(hdev);
1749 return ret; 1840 return ret;
1750} 1841}
@@ -1765,6 +1856,8 @@ static void sony_remove(struct hid_device *hdev)
1765 1856
1766 sony_remove_dev_list(sc); 1857 sony_remove_dev_list(sc);
1767 1858
1859 sony_release_device_id(sc);
1860
1768 hid_hw_stop(hdev); 1861 hid_hw_stop(hdev);
1769} 1862}
1770 1863
@@ -1809,6 +1902,22 @@ static struct hid_driver sony_driver = {
1809 .report_fixup = sony_report_fixup, 1902 .report_fixup = sony_report_fixup,
1810 .raw_event = sony_raw_event 1903 .raw_event = sony_raw_event
1811}; 1904};
1812module_hid_driver(sony_driver); 1905
1906static int __init sony_init(void)
1907{
1908 dbg_hid("Sony:%s\n", __func__);
1909
1910 return hid_register_driver(&sony_driver);
1911}
1912
1913static void __exit sony_exit(void)
1914{
1915 dbg_hid("Sony:%s\n", __func__);
1916
1917 ida_destroy(&sony_device_id_allocator);
1918 hid_unregister_driver(&sony_driver);
1919}
1920module_init(sony_init);
1921module_exit(sony_exit);
1813 1922
1814MODULE_LICENSE("GPL"); 1923MODULE_LICENSE("GPL");