aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFrank Praznik <frank.praznik@oh.rr.com>2014-11-12 14:10:09 -0500
committerJiri Kosina <jkosina@suse.cz>2014-11-19 04:23:54 -0500
commit9b2b5c9a790743ccb2516f1a86671d5df9c6c5cd (patch)
tree3401b3ff86f562eb38989039fa0c9dd6a2e57d8c /drivers
parent6b07974af9698225766d42175470b1a5d7bf9f48 (diff)
HID: sony: Use kernel allocated buffers for HID reports
Replace stack buffers with kernel allocated buffers for sending and receiving HID reports to prevent issues with DMA transfers on certain hardware. Output report buffers are allocated at initialization time to avoid excessive calls to kmalloc and kfree. Link: https://bugzilla.kernel.org/show_bug.cgi?id=87991 Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com> Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/hid-sony.c147
1 files changed, 113 insertions, 34 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index bc4269e559f1..b6e610289e9d 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -798,6 +798,12 @@ union sixaxis_output_report_01 {
798 __u8 buf[36]; 798 __u8 buf[36];
799}; 799};
800 800
801#define DS4_REPORT_0x02_SIZE 37
802#define DS4_REPORT_0x05_SIZE 32
803#define DS4_REPORT_0x11_SIZE 78
804#define DS4_REPORT_0x81_SIZE 7
805#define SIXAXIS_REPORT_0xF2_SIZE 18
806
801static spinlock_t sony_dev_list_lock; 807static spinlock_t sony_dev_list_lock;
802static LIST_HEAD(sony_device_list); 808static LIST_HEAD(sony_device_list);
803static DEFINE_IDA(sony_device_id_allocator); 809static DEFINE_IDA(sony_device_id_allocator);
@@ -811,6 +817,7 @@ struct sony_sc {
811 struct work_struct state_worker; 817 struct work_struct state_worker;
812 struct power_supply battery; 818 struct power_supply battery;
813 int device_id; 819 int device_id;
820 __u8 *output_report_dmabuf;
814 821
815#ifdef CONFIG_SONY_FF 822#ifdef CONFIG_SONY_FF
816 __u8 left; 823 __u8 left;
@@ -1142,9 +1149,20 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
1142 1149
1143static int sixaxis_set_operational_bt(struct hid_device *hdev) 1150static int sixaxis_set_operational_bt(struct hid_device *hdev)
1144{ 1151{
1145 unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; 1152 static const __u8 report[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
1146 return hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf), 1153 __u8 *buf;
1154 int ret;
1155
1156 buf = kmemdup(report, sizeof(report), GFP_KERNEL);
1157 if (!buf)
1158 return -ENOMEM;
1159
1160 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(report),
1147 HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 1161 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
1162
1163 kfree(buf);
1164
1165 return ret;
1148} 1166}
1149 1167
1150/* 1168/*
@@ -1153,10 +1171,19 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
1153 */ 1171 */
1154static int dualshock4_set_operational_bt(struct hid_device *hdev) 1172static int dualshock4_set_operational_bt(struct hid_device *hdev)
1155{ 1173{
1156 __u8 buf[37] = { 0 }; 1174 __u8 *buf;
1175 int ret;
1157 1176
1158 return hid_hw_raw_request(hdev, 0x02, buf, sizeof(buf), 1177 buf = kmalloc(DS4_REPORT_0x02_SIZE, GFP_KERNEL);
1178 if (!buf)
1179 return -ENOMEM;
1180
1181 ret = hid_hw_raw_request(hdev, 0x02, buf, DS4_REPORT_0x02_SIZE,
1159 HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 1182 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
1183
1184 kfree(buf);
1185
1186 return ret;
1160} 1187}
1161 1188
1162static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS]) 1189static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS])
@@ -1471,9 +1498,7 @@ error_leds:
1471 1498
1472static void sixaxis_state_worker(struct work_struct *work) 1499static void sixaxis_state_worker(struct work_struct *work)
1473{ 1500{
1474 struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); 1501 static const union sixaxis_output_report_01 default_report = {
1475 int n;
1476 union sixaxis_output_report_01 report = {
1477 .buf = { 1502 .buf = {
1478 0x01, 1503 0x01,
1479 0x00, 0xff, 0x00, 0xff, 0x00, 1504 0x00, 0xff, 0x00, 0xff, 0x00,
@@ -1485,20 +1510,27 @@ static void sixaxis_state_worker(struct work_struct *work)
1485 0x00, 0x00, 0x00, 0x00, 0x00 1510 0x00, 0x00, 0x00, 0x00, 0x00
1486 } 1511 }
1487 }; 1512 };
1513 struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
1514 struct sixaxis_output_report *report =
1515 (struct sixaxis_output_report *)sc->output_report_dmabuf;
1516 int n;
1517
1518 /* Initialize the report with default values */
1519 memcpy(report, &default_report, sizeof(struct sixaxis_output_report));
1488 1520
1489#ifdef CONFIG_SONY_FF 1521#ifdef CONFIG_SONY_FF
1490 report.data.rumble.right_motor_on = sc->right ? 1 : 0; 1522 report->rumble.right_motor_on = sc->right ? 1 : 0;
1491 report.data.rumble.left_motor_force = sc->left; 1523 report->rumble.left_motor_force = sc->left;
1492#endif 1524#endif
1493 1525
1494 report.data.leds_bitmap |= sc->led_state[0] << 1; 1526 report->leds_bitmap |= sc->led_state[0] << 1;
1495 report.data.leds_bitmap |= sc->led_state[1] << 2; 1527 report->leds_bitmap |= sc->led_state[1] << 2;
1496 report.data.leds_bitmap |= sc->led_state[2] << 3; 1528 report->leds_bitmap |= sc->led_state[2] << 3;
1497 report.data.leds_bitmap |= sc->led_state[3] << 4; 1529 report->leds_bitmap |= sc->led_state[3] << 4;
1498 1530
1499 /* Set flag for all leds off, required for 3rd party INTEC controller */ 1531 /* Set flag for all leds off, required for 3rd party INTEC controller */
1500 if ((report.data.leds_bitmap & 0x1E) == 0) 1532 if ((report->leds_bitmap & 0x1E) == 0)
1501 report.data.leds_bitmap |= 0x20; 1533 report->leds_bitmap |= 0x20;
1502 1534
1503 /* 1535 /*
1504 * The LEDs in the report are indexed in reverse order to their 1536 * The LEDs in the report are indexed in reverse order to their
@@ -1511,28 +1543,30 @@ static void sixaxis_state_worker(struct work_struct *work)
1511 */ 1543 */
1512 for (n = 0; n < 4; n++) { 1544 for (n = 0; n < 4; n++) {
1513 if (sc->led_delay_on[n] || sc->led_delay_off[n]) { 1545 if (sc->led_delay_on[n] || sc->led_delay_off[n]) {
1514 report.data.led[3 - n].duty_off = sc->led_delay_off[n]; 1546 report->led[3 - n].duty_off = sc->led_delay_off[n];
1515 report.data.led[3 - n].duty_on = sc->led_delay_on[n]; 1547 report->led[3 - n].duty_on = sc->led_delay_on[n];
1516 } 1548 }
1517 } 1549 }
1518 1550
1519 hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf, 1551 hid_hw_raw_request(sc->hdev, report->report_id, (__u8 *)report,
1520 sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); 1552 sizeof(struct sixaxis_output_report),
1553 HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
1521} 1554}
1522 1555
1523static void dualshock4_state_worker(struct work_struct *work) 1556static void dualshock4_state_worker(struct work_struct *work)
1524{ 1557{
1525 struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); 1558 struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
1526 struct hid_device *hdev = sc->hdev; 1559 struct hid_device *hdev = sc->hdev;
1560 __u8 *buf = sc->output_report_dmabuf;
1527 int offset; 1561 int offset;
1528 1562
1529 __u8 buf[78] = { 0 };
1530
1531 if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { 1563 if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
1564 memset(buf, 0, DS4_REPORT_0x05_SIZE);
1532 buf[0] = 0x05; 1565 buf[0] = 0x05;
1533 buf[1] = 0xFF; 1566 buf[1] = 0xFF;
1534 offset = 4; 1567 offset = 4;
1535 } else { 1568 } else {
1569 memset(buf, 0, DS4_REPORT_0x11_SIZE);
1536 buf[0] = 0x11; 1570 buf[0] = 0x11;
1537 buf[1] = 0xB0; 1571 buf[1] = 0xB0;
1538 buf[3] = 0x0F; 1572 buf[3] = 0x0F;
@@ -1560,12 +1594,33 @@ static void dualshock4_state_worker(struct work_struct *work)
1560 buf[offset++] = sc->led_delay_off[3]; 1594 buf[offset++] = sc->led_delay_off[3];
1561 1595
1562 if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) 1596 if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
1563 hid_hw_output_report(hdev, buf, 32); 1597 hid_hw_output_report(hdev, buf, DS4_REPORT_0x05_SIZE);
1564 else 1598 else
1565 hid_hw_raw_request(hdev, 0x11, buf, 78, 1599 hid_hw_raw_request(hdev, 0x11, buf, DS4_REPORT_0x11_SIZE,
1566 HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); 1600 HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
1567} 1601}
1568 1602
1603static int sony_allocate_output_report(struct sony_sc *sc)
1604{
1605 if (sc->quirks & SIXAXIS_CONTROLLER)
1606 sc->output_report_dmabuf =
1607 kmalloc(sizeof(union sixaxis_output_report_01),
1608 GFP_KERNEL);
1609 else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT)
1610 sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x11_SIZE,
1611 GFP_KERNEL);
1612 else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
1613 sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x05_SIZE,
1614 GFP_KERNEL);
1615 else
1616 return 0;
1617
1618 if (!sc->output_report_dmabuf)
1619 return -ENOMEM;
1620
1621 return 0;
1622}
1623
1569#ifdef CONFIG_SONY_FF 1624#ifdef CONFIG_SONY_FF
1570static int sony_play_effect(struct input_dev *dev, void *data, 1625static int sony_play_effect(struct input_dev *dev, void *data,
1571 struct ff_effect *effect) 1626 struct ff_effect *effect)
@@ -1754,6 +1809,7 @@ static int sony_get_bt_devaddr(struct sony_sc *sc)
1754 1809
1755static int sony_check_add(struct sony_sc *sc) 1810static int sony_check_add(struct sony_sc *sc)
1756{ 1811{
1812 __u8 *buf = NULL;
1757 int n, ret; 1813 int n, ret;
1758 1814
1759 if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) || 1815 if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) ||
@@ -1769,36 +1825,44 @@ static int sony_check_add(struct sony_sc *sc)
1769 return 0; 1825 return 0;
1770 } 1826 }
1771 } else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { 1827 } else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
1772 __u8 buf[7]; 1828 buf = kmalloc(DS4_REPORT_0x81_SIZE, GFP_KERNEL);
1829 if (!buf)
1830 return -ENOMEM;
1773 1831
1774 /* 1832 /*
1775 * The MAC address of a DS4 controller connected via USB can be 1833 * The MAC address of a DS4 controller connected via USB can be
1776 * retrieved with feature report 0x81. The address begins at 1834 * retrieved with feature report 0x81. The address begins at
1777 * offset 1. 1835 * offset 1.
1778 */ 1836 */
1779 ret = hid_hw_raw_request(sc->hdev, 0x81, buf, sizeof(buf), 1837 ret = hid_hw_raw_request(sc->hdev, 0x81, buf,
1780 HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 1838 DS4_REPORT_0x81_SIZE, HID_FEATURE_REPORT,
1839 HID_REQ_GET_REPORT);
1781 1840
1782 if (ret != 7) { 1841 if (ret != DS4_REPORT_0x81_SIZE) {
1783 hid_err(sc->hdev, "failed to retrieve feature report 0x81 with the DualShock 4 MAC address\n"); 1842 hid_err(sc->hdev, "failed to retrieve feature report 0x81 with the DualShock 4 MAC address\n");
1784 return ret < 0 ? ret : -EINVAL; 1843 ret = ret < 0 ? ret : -EINVAL;
1844 goto out_free;
1785 } 1845 }
1786 1846
1787 memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address)); 1847 memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address));
1788 } else if (sc->quirks & SIXAXIS_CONTROLLER_USB) { 1848 } else if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
1789 __u8 buf[18]; 1849 buf = kmalloc(SIXAXIS_REPORT_0xF2_SIZE, GFP_KERNEL);
1850 if (!buf)
1851 return -ENOMEM;
1790 1852
1791 /* 1853 /*
1792 * The MAC address of a Sixaxis controller connected via USB can 1854 * The MAC address of a Sixaxis controller connected via USB can
1793 * be retrieved with feature report 0xf2. The address begins at 1855 * be retrieved with feature report 0xf2. The address begins at
1794 * offset 4. 1856 * offset 4.
1795 */ 1857 */
1796 ret = hid_hw_raw_request(sc->hdev, 0xf2, buf, sizeof(buf), 1858 ret = hid_hw_raw_request(sc->hdev, 0xf2, buf,
1797 HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 1859 SIXAXIS_REPORT_0xF2_SIZE, HID_FEATURE_REPORT,
1860 HID_REQ_GET_REPORT);
1798 1861
1799 if (ret != 18) { 1862 if (ret != SIXAXIS_REPORT_0xF2_SIZE) {
1800 hid_err(sc->hdev, "failed to retrieve feature report 0xf2 with the Sixaxis MAC address\n"); 1863 hid_err(sc->hdev, "failed to retrieve feature report 0xf2 with the Sixaxis MAC address\n");
1801 return ret < 0 ? ret : -EINVAL; 1864 ret = ret < 0 ? ret : -EINVAL;
1865 goto out_free;
1802 } 1866 }
1803 1867
1804 /* 1868 /*
@@ -1811,7 +1875,13 @@ static int sony_check_add(struct sony_sc *sc)
1811 return 0; 1875 return 0;
1812 } 1876 }
1813 1877
1814 return sony_check_add_dev_list(sc); 1878 ret = sony_check_add_dev_list(sc);
1879
1880out_free:
1881
1882 kfree(buf);
1883
1884 return ret;
1815} 1885}
1816 1886
1817static int sony_set_device_id(struct sony_sc *sc) 1887static int sony_set_device_id(struct sony_sc *sc)
@@ -1895,6 +1965,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
1895 return ret; 1965 return ret;
1896 } 1966 }
1897 1967
1968 ret = sony_allocate_output_report(sc);
1969 if (ret < 0) {
1970 hid_err(hdev, "failed to allocate the output report buffer\n");
1971 goto err_stop;
1972 }
1973
1898 ret = sony_set_device_id(sc); 1974 ret = sony_set_device_id(sc);
1899 if (ret < 0) { 1975 if (ret < 0) {
1900 hid_err(hdev, "failed to allocate the device id\n"); 1976 hid_err(hdev, "failed to allocate the device id\n");
@@ -1984,6 +2060,7 @@ err_stop:
1984 if (sc->quirks & SONY_BATTERY_SUPPORT) 2060 if (sc->quirks & SONY_BATTERY_SUPPORT)
1985 sony_battery_remove(sc); 2061 sony_battery_remove(sc);
1986 sony_cancel_work_sync(sc); 2062 sony_cancel_work_sync(sc);
2063 kfree(sc->output_report_dmabuf);
1987 sony_remove_dev_list(sc); 2064 sony_remove_dev_list(sc);
1988 sony_release_device_id(sc); 2065 sony_release_device_id(sc);
1989 hid_hw_stop(hdev); 2066 hid_hw_stop(hdev);
@@ -2004,6 +2081,8 @@ static void sony_remove(struct hid_device *hdev)
2004 2081
2005 sony_cancel_work_sync(sc); 2082 sony_cancel_work_sync(sc);
2006 2083
2084 kfree(sc->output_report_dmabuf);
2085
2007 sony_remove_dev_list(sc); 2086 sony_remove_dev_list(sc);
2008 2087
2009 sony_release_device_id(sc); 2088 sony_release_device_id(sc);