diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2013-10-28 12:49:20 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-10-30 09:13:29 -0400 |
commit | 08072dde333c2f09114a01b0bd32be52ecce195b (patch) | |
tree | 9f6841827abd53f5445052951ff2b1a64a925bb8 /drivers/hid | |
parent | 0abda6fa81dced031e3df31ac29bfb253549c2d1 (diff) |
HID: wiimote: add pro-controller analog stick calibration
The analog sticks of the pro-controller might report slightly off values.
To guarantee a uniform setup, we now calibrate analog-stick values during
pro-controller setup.
Unfortunately, the pro-controller fails during normal EEPROM reads and I
couldn't figure out whether there are any calibration values stored on the
device. Therefore, we now use the first values reported by the device (iff
they are not _way_ off, which would indicate movement) to initialize the
calibration values. To allow users to change this calibration data, we
provide a pro_calib sysfs attribute.
We also change the "flat" values so user-space correctly smoothes our
data. It makes slightly off zero-positions less visible while still
guaranteeing highly precise movement reports. Note that the pro controller
reports zero-positions in a quite huge range (at least: -100 to +100).
Reported-by: Rafael Brune <mail@rbrune.de>
Tested-by: Rafael Brune <mail@rbrune.de>
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-wiimote-modules.c | 117 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote.h | 2 |
2 files changed, 110 insertions, 9 deletions
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c index e30567af42ed..6b61f01e01e7 100644 --- a/drivers/hid/hid-wiimote-modules.c +++ b/drivers/hid/hid-wiimote-modules.c | |||
@@ -1655,10 +1655,39 @@ static void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext) | |||
1655 | ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8); | 1655 | ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8); |
1656 | ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8); | 1656 | ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8); |
1657 | 1657 | ||
1658 | input_report_abs(wdata->extension.input, ABS_X, lx - 0x800); | 1658 | /* zero-point offsets */ |
1659 | input_report_abs(wdata->extension.input, ABS_Y, 0x800 - ly); | 1659 | lx -= 0x800; |
1660 | input_report_abs(wdata->extension.input, ABS_RX, rx - 0x800); | 1660 | ly = 0x800 - ly; |
1661 | input_report_abs(wdata->extension.input, ABS_RY, 0x800 - ry); | 1661 | rx -= 0x800; |
1662 | ry = 0x800 - ry; | ||
1663 | |||
1664 | /* Trivial automatic calibration. We don't know any calibration data | ||
1665 | * in the EEPROM so we must use the first report to calibrate the | ||
1666 | * null-position of the analog sticks. Users can retrigger calibration | ||
1667 | * via sysfs, or set it explicitly. If data is off more than abs(500), | ||
1668 | * we skip calibration as the sticks are likely to be moved already. */ | ||
1669 | if (!(wdata->state.flags & WIIPROTO_FLAG_PRO_CALIB_DONE)) { | ||
1670 | wdata->state.flags |= WIIPROTO_FLAG_PRO_CALIB_DONE; | ||
1671 | if (abs(lx) < 500) | ||
1672 | wdata->state.calib_pro_sticks[0] = -lx; | ||
1673 | if (abs(ly) < 500) | ||
1674 | wdata->state.calib_pro_sticks[1] = -ly; | ||
1675 | if (abs(rx) < 500) | ||
1676 | wdata->state.calib_pro_sticks[2] = -rx; | ||
1677 | if (abs(ry) < 500) | ||
1678 | wdata->state.calib_pro_sticks[3] = -ry; | ||
1679 | } | ||
1680 | |||
1681 | /* apply calibration data */ | ||
1682 | lx += wdata->state.calib_pro_sticks[0]; | ||
1683 | ly += wdata->state.calib_pro_sticks[1]; | ||
1684 | rx += wdata->state.calib_pro_sticks[2]; | ||
1685 | ry += wdata->state.calib_pro_sticks[3]; | ||
1686 | |||
1687 | input_report_abs(wdata->extension.input, ABS_X, lx); | ||
1688 | input_report_abs(wdata->extension.input, ABS_Y, ly); | ||
1689 | input_report_abs(wdata->extension.input, ABS_RX, rx); | ||
1690 | input_report_abs(wdata->extension.input, ABS_RY, ry); | ||
1662 | 1691 | ||
1663 | input_report_key(wdata->extension.input, | 1692 | input_report_key(wdata->extension.input, |
1664 | wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT], | 1693 | wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT], |
@@ -1766,12 +1795,70 @@ static int wiimod_pro_play(struct input_dev *dev, void *data, | |||
1766 | return 0; | 1795 | return 0; |
1767 | } | 1796 | } |
1768 | 1797 | ||
1798 | static ssize_t wiimod_pro_calib_show(struct device *dev, | ||
1799 | struct device_attribute *attr, | ||
1800 | char *out) | ||
1801 | { | ||
1802 | struct wiimote_data *wdata = dev_to_wii(dev); | ||
1803 | int r; | ||
1804 | |||
1805 | r = 0; | ||
1806 | r += sprintf(&out[r], "%+06hd:", wdata->state.calib_pro_sticks[0]); | ||
1807 | r += sprintf(&out[r], "%+06hd ", wdata->state.calib_pro_sticks[1]); | ||
1808 | r += sprintf(&out[r], "%+06hd:", wdata->state.calib_pro_sticks[2]); | ||
1809 | r += sprintf(&out[r], "%+06hd\n", wdata->state.calib_pro_sticks[3]); | ||
1810 | |||
1811 | return r; | ||
1812 | } | ||
1813 | |||
1814 | static ssize_t wiimod_pro_calib_store(struct device *dev, | ||
1815 | struct device_attribute *attr, | ||
1816 | const char *buf, size_t count) | ||
1817 | { | ||
1818 | struct wiimote_data *wdata = dev_to_wii(dev); | ||
1819 | int r; | ||
1820 | s16 x1, y1, x2, y2; | ||
1821 | |||
1822 | if (!strncmp(buf, "scan\n", 5)) { | ||
1823 | spin_lock_irq(&wdata->state.lock); | ||
1824 | wdata->state.flags &= ~WIIPROTO_FLAG_PRO_CALIB_DONE; | ||
1825 | spin_unlock_irq(&wdata->state.lock); | ||
1826 | } else { | ||
1827 | r = sscanf(buf, "%hd:%hd %hd:%hd", &x1, &y1, &x2, &y2); | ||
1828 | if (r != 4) | ||
1829 | return -EINVAL; | ||
1830 | |||
1831 | spin_lock_irq(&wdata->state.lock); | ||
1832 | wdata->state.flags |= WIIPROTO_FLAG_PRO_CALIB_DONE; | ||
1833 | spin_unlock_irq(&wdata->state.lock); | ||
1834 | |||
1835 | wdata->state.calib_pro_sticks[0] = x1; | ||
1836 | wdata->state.calib_pro_sticks[1] = y1; | ||
1837 | wdata->state.calib_pro_sticks[2] = x2; | ||
1838 | wdata->state.calib_pro_sticks[3] = y2; | ||
1839 | } | ||
1840 | |||
1841 | return strnlen(buf, PAGE_SIZE); | ||
1842 | } | ||
1843 | |||
1844 | static DEVICE_ATTR(pro_calib, S_IRUGO|S_IWUSR|S_IWGRP, wiimod_pro_calib_show, | ||
1845 | wiimod_pro_calib_store); | ||
1846 | |||
1769 | static int wiimod_pro_probe(const struct wiimod_ops *ops, | 1847 | static int wiimod_pro_probe(const struct wiimod_ops *ops, |
1770 | struct wiimote_data *wdata) | 1848 | struct wiimote_data *wdata) |
1771 | { | 1849 | { |
1772 | int ret, i; | 1850 | int ret, i; |
1851 | unsigned long flags; | ||
1773 | 1852 | ||
1774 | INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker); | 1853 | INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker); |
1854 | wdata->state.calib_pro_sticks[0] = 0; | ||
1855 | wdata->state.calib_pro_sticks[1] = 0; | ||
1856 | wdata->state.calib_pro_sticks[2] = 0; | ||
1857 | wdata->state.calib_pro_sticks[3] = 0; | ||
1858 | |||
1859 | spin_lock_irqsave(&wdata->state.lock, flags); | ||
1860 | wdata->state.flags &= ~WIIPROTO_FLAG_PRO_CALIB_DONE; | ||
1861 | spin_unlock_irqrestore(&wdata->state.lock, flags); | ||
1775 | 1862 | ||
1776 | wdata->extension.input = input_allocate_device(); | 1863 | wdata->extension.input = input_allocate_device(); |
1777 | if (!wdata->extension.input) | 1864 | if (!wdata->extension.input) |
@@ -1786,6 +1873,13 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops, | |||
1786 | goto err_free; | 1873 | goto err_free; |
1787 | } | 1874 | } |
1788 | 1875 | ||
1876 | ret = device_create_file(&wdata->hdev->dev, | ||
1877 | &dev_attr_pro_calib); | ||
1878 | if (ret) { | ||
1879 | hid_err(wdata->hdev, "cannot create sysfs attribute\n"); | ||
1880 | goto err_free; | ||
1881 | } | ||
1882 | |||
1789 | wdata->extension.input->open = wiimod_pro_open; | 1883 | wdata->extension.input->open = wiimod_pro_open; |
1790 | wdata->extension.input->close = wiimod_pro_close; | 1884 | wdata->extension.input->close = wiimod_pro_close; |
1791 | wdata->extension.input->dev.parent = &wdata->hdev->dev; | 1885 | wdata->extension.input->dev.parent = &wdata->hdev->dev; |
@@ -1806,20 +1900,23 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops, | |||
1806 | set_bit(ABS_RX, wdata->extension.input->absbit); | 1900 | set_bit(ABS_RX, wdata->extension.input->absbit); |
1807 | set_bit(ABS_RY, wdata->extension.input->absbit); | 1901 | set_bit(ABS_RY, wdata->extension.input->absbit); |
1808 | input_set_abs_params(wdata->extension.input, | 1902 | input_set_abs_params(wdata->extension.input, |
1809 | ABS_X, -0x800, 0x800, 2, 4); | 1903 | ABS_X, -0x400, 0x400, 4, 100); |
1810 | input_set_abs_params(wdata->extension.input, | 1904 | input_set_abs_params(wdata->extension.input, |
1811 | ABS_Y, -0x800, 0x800, 2, 4); | 1905 | ABS_Y, -0x400, 0x400, 4, 100); |
1812 | input_set_abs_params(wdata->extension.input, | 1906 | input_set_abs_params(wdata->extension.input, |
1813 | ABS_RX, -0x800, 0x800, 2, 4); | 1907 | ABS_RX, -0x400, 0x400, 4, 100); |
1814 | input_set_abs_params(wdata->extension.input, | 1908 | input_set_abs_params(wdata->extension.input, |
1815 | ABS_RY, -0x800, 0x800, 2, 4); | 1909 | ABS_RY, -0x400, 0x400, 4, 100); |
1816 | 1910 | ||
1817 | ret = input_register_device(wdata->extension.input); | 1911 | ret = input_register_device(wdata->extension.input); |
1818 | if (ret) | 1912 | if (ret) |
1819 | goto err_free; | 1913 | goto err_file; |
1820 | 1914 | ||
1821 | return 0; | 1915 | return 0; |
1822 | 1916 | ||
1917 | err_file: | ||
1918 | device_remove_file(&wdata->hdev->dev, | ||
1919 | &dev_attr_pro_calib); | ||
1823 | err_free: | 1920 | err_free: |
1824 | input_free_device(wdata->extension.input); | 1921 | input_free_device(wdata->extension.input); |
1825 | wdata->extension.input = NULL; | 1922 | wdata->extension.input = NULL; |
@@ -1837,6 +1934,8 @@ static void wiimod_pro_remove(const struct wiimod_ops *ops, | |||
1837 | input_unregister_device(wdata->extension.input); | 1934 | input_unregister_device(wdata->extension.input); |
1838 | wdata->extension.input = NULL; | 1935 | wdata->extension.input = NULL; |
1839 | cancel_work_sync(&wdata->rumble_worker); | 1936 | cancel_work_sync(&wdata->rumble_worker); |
1937 | device_remove_file(&wdata->hdev->dev, | ||
1938 | &dev_attr_pro_calib); | ||
1840 | 1939 | ||
1841 | spin_lock_irqsave(&wdata->state.lock, flags); | 1940 | spin_lock_irqsave(&wdata->state.lock, flags); |
1842 | wiiproto_req_rumble(wdata, 0); | 1941 | wiiproto_req_rumble(wdata, 0); |
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h index 75db0c400037..03065f1917fc 100644 --- a/drivers/hid/hid-wiimote.h +++ b/drivers/hid/hid-wiimote.h | |||
@@ -46,6 +46,7 @@ | |||
46 | #define WIIPROTO_FLAG_DRM_LOCKED 0x8000 | 46 | #define WIIPROTO_FLAG_DRM_LOCKED 0x8000 |
47 | #define WIIPROTO_FLAG_BUILTIN_MP 0x010000 | 47 | #define WIIPROTO_FLAG_BUILTIN_MP 0x010000 |
48 | #define WIIPROTO_FLAG_NO_MP 0x020000 | 48 | #define WIIPROTO_FLAG_NO_MP 0x020000 |
49 | #define WIIPROTO_FLAG_PRO_CALIB_DONE 0x040000 | ||
49 | 50 | ||
50 | #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ | 51 | #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ |
51 | WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) | 52 | WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) |
@@ -135,6 +136,7 @@ struct wiimote_state { | |||
135 | 136 | ||
136 | /* calibration/cache data */ | 137 | /* calibration/cache data */ |
137 | __u16 calib_bboard[4][3]; | 138 | __u16 calib_bboard[4][3]; |
139 | __s16 calib_pro_sticks[4]; | ||
138 | __u8 cache_rumble; | 140 | __u8 cache_rumble; |
139 | }; | 141 | }; |
140 | 142 | ||