aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wood <simon@mungewell.org>2015-11-19 18:42:13 -0500
committerJiri Kosina <jkosina@suse.cz>2015-11-20 04:29:59 -0500
commit7f4b49fef6ffb5021c01a915c21b3221fd521e81 (patch)
treeed23590c09c25e70d8f251ed95df291d4d0fa1d8
parent7bfd2927adcacac2930a2709a9bcc1231e5bba1c (diff)
HID: hid-logitech-hidpp: Add range sysfs for Logitech G920
The G920 can adjust the amount of 'turn' it permits, this patch adds a sysfs file 'range' to control this. Signed-off-by: Simon Wood <simon@mungewell.org> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-logitech-hidpp.c140
1 files changed, 139 insertions, 1 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 98b8f096d7ee..fc553e3f948d 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -1295,6 +1295,133 @@ static int k400_connect(struct hid_device *hdev, bool connected)
1295 return k400_disable_tap_to_click(hidpp); 1295 return k400_disable_tap_to_click(hidpp);
1296} 1296}
1297 1297
1298/* ------------------------------------------------------------------------- */
1299/* Logitech G920 Driving Force Racing Wheel for Xbox One */
1300/* ------------------------------------------------------------------------- */
1301
1302#define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123
1303
1304/* Using session ID = 1 */
1305#define CMD_G920_FORCE_GET_APERTURE 0x51
1306#define CMD_G920_FORCE_SET_APERTURE 0x61
1307
1308struct g920_private_data {
1309 u8 force_feature;
1310 u16 range;
1311};
1312
1313#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
1314
1315static ssize_t g920_range_show(struct device *dev, struct device_attribute *attr,
1316 char *buf)
1317{
1318 struct hid_device *hid = to_hid_device(dev);
1319 struct hidpp_device *hidpp = hid_get_drvdata(hid);
1320 struct g920_private_data *pdata;
1321
1322 pdata = hidpp->private_data;
1323 if (!pdata) {
1324 hid_err(hid, "Private driver data not found!\n");
1325 return -EINVAL;
1326 }
1327
1328 return scnprintf(buf, PAGE_SIZE, "%u\n", pdata->range);
1329}
1330
1331static ssize_t g920_range_store(struct device *dev, struct device_attribute *attr,
1332 const char *buf, size_t count)
1333{
1334 struct hid_device *hid = to_hid_device(dev);
1335 struct hidpp_device *hidpp = hid_get_drvdata(hid);
1336 struct g920_private_data *pdata;
1337 struct hidpp_report response;
1338 u8 params[2];
1339 int ret;
1340 u16 range = simple_strtoul(buf, NULL, 10);
1341
1342 pdata = hidpp->private_data;
1343 if (!pdata) {
1344 hid_err(hid, "Private driver data not found!\n");
1345 return -EINVAL;
1346 }
1347
1348 if (range < 180)
1349 range = 180;
1350 else if (range > 900)
1351 range = 900;
1352
1353 params[0] = range >> 8;
1354 params[1] = range & 0x00FF;
1355
1356 ret = hidpp_send_fap_command_sync(hidpp, pdata->force_feature,
1357 CMD_G920_FORCE_SET_APERTURE, params, 2, &response);
1358 if (ret)
1359 return ret;
1360
1361 pdata->range = range;
1362 return count;
1363}
1364
1365static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, g920_range_show, g920_range_store);
1366
1367static int g920_allocate(struct hid_device *hdev)
1368{
1369 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
1370 struct g920_private_data *pdata;
1371
1372 pdata = devm_kzalloc(&hdev->dev, sizeof(struct g920_private_data),
1373 GFP_KERNEL);
1374 if (!pdata)
1375 return -ENOMEM;
1376
1377 hidpp->private_data = pdata;
1378
1379 return 0;
1380}
1381
1382static int g920_get_config(struct hidpp_device *hidpp)
1383{
1384 struct g920_private_data *pdata = hidpp->private_data;
1385 struct hidpp_report response;
1386 u8 feature_type;
1387 u8 feature_index;
1388 int ret;
1389
1390 pdata = hidpp->private_data;
1391 if (!pdata) {
1392 hid_err(hidpp->hid_dev, "Private driver data not found!\n");
1393 return -EINVAL;
1394 }
1395
1396 /* Find feature and store for later use */
1397 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK,
1398 &feature_index, &feature_type);
1399 if (ret)
1400 return ret;
1401
1402 pdata->force_feature = feature_index;
1403
1404 /* Read current Range */
1405 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1406 CMD_G920_FORCE_GET_APERTURE, NULL, 0, &response);
1407 if (ret > 0) {
1408 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1409 __func__, ret);
1410 return -EPROTO;
1411 }
1412 if (ret)
1413 return ret;
1414
1415 pdata->range = get_unaligned_be16(&response.fap.params[0]);
1416
1417 /* Create sysfs interface */
1418 ret = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range);
1419 if (ret)
1420 hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d\n", ret);
1421
1422 return 0;
1423}
1424
1298/* -------------------------------------------------------------------------- */ 1425/* -------------------------------------------------------------------------- */
1299/* Generic HID++ devices */ 1426/* Generic HID++ devices */
1300/* -------------------------------------------------------------------------- */ 1427/* -------------------------------------------------------------------------- */
@@ -1595,6 +1722,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
1595 ret = k400_allocate(hdev); 1722 ret = k400_allocate(hdev);
1596 if (ret) 1723 if (ret)
1597 goto allocate_fail; 1724 goto allocate_fail;
1725 } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
1726 ret = g920_allocate(hdev);
1727 if (ret)
1728 goto allocate_fail;
1598 } 1729 }
1599 1730
1600 INIT_WORK(&hidpp->work, delayed_work_cb); 1731 INIT_WORK(&hidpp->work, delayed_work_cb);
@@ -1648,6 +1779,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
1648 ret = wtp_get_config(hidpp); 1779 ret = wtp_get_config(hidpp);
1649 if (ret) 1780 if (ret)
1650 goto hid_hw_open_failed; 1781 goto hid_hw_open_failed;
1782 } else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
1783 ret = g920_get_config(hidpp);
1784 if (ret)
1785 goto hid_hw_open_failed;
1651 } 1786 }
1652 1787
1653 /* Block incoming packets */ 1788 /* Block incoming packets */
@@ -1673,6 +1808,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
1673hid_hw_open_failed: 1808hid_hw_open_failed:
1674 hid_device_io_stop(hdev); 1809 hid_device_io_stop(hdev);
1675 if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { 1810 if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
1811 device_remove_file(&hdev->dev, &dev_attr_range);
1676 hid_hw_close(hdev); 1812 hid_hw_close(hdev);
1677 hid_hw_stop(hdev); 1813 hid_hw_stop(hdev);
1678 } 1814 }
@@ -1689,8 +1825,10 @@ static void hidpp_remove(struct hid_device *hdev)
1689{ 1825{
1690 struct hidpp_device *hidpp = hid_get_drvdata(hdev); 1826 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
1691 1827
1692 if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) 1828 if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
1829 device_remove_file(&hdev->dev, &dev_attr_range);
1693 hid_hw_close(hdev); 1830 hid_hw_close(hdev);
1831 }
1694 hid_hw_stop(hdev); 1832 hid_hw_stop(hdev);
1695 cancel_work_sync(&hidpp->work); 1833 cancel_work_sync(&hidpp->work);
1696 mutex_destroy(&hidpp->send_mutex); 1834 mutex_destroy(&hidpp->send_mutex);