Skip to content

Commit 08072dd

Browse files
David HerrmannJiri Kosina
authored andcommitted
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 <[email protected]> Tested-by: Rafael Brune <[email protected]> Signed-off-by: David Herrmann <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 0abda6f commit 08072dd

File tree

3 files changed

+128
-9
lines changed

3 files changed

+128
-9
lines changed

Documentation/ABI/testing/sysfs-driver-hid-wiimote

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,21 @@ Description: This attribute is only provided if the device was detected as a
5757
Calibration data is already applied by the kernel to all input
5858
values but may be used by user-space to perform other
5959
transformations.
60+
61+
What: /sys/bus/hid/drivers/wiimote/<dev>/pro_calib
62+
Date: October 2013
63+
KernelVersion: 3.13
64+
Contact: David Herrmann <[email protected]>
65+
Description: This attribute is only provided if the device was detected as a
66+
pro-controller. It provides a single line with 4 calibration
67+
values for all 4 analog sticks. Format is: "x1:y1 x2:y2". Data
68+
is prefixed with a +/-. Each value is a signed 16bit number.
69+
Data is encoded as decimal numbers and specifies the offsets of
70+
the analog sticks of the pro-controller.
71+
Calibration data is already applied by the kernel to all input
72+
values but may be used by user-space to perform other
73+
transformations.
74+
Calibration data is detected by the kernel during device setup.
75+
You can write "scan\n" into this file to re-trigger calibration.
76+
You can also write data directly in the form "x1:y1 x2:y2" to
77+
set the calibration values manually.

drivers/hid/hid-wiimote-modules.c

Lines changed: 108 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,10 +1655,39 @@ static void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext)
16551655
ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8);
16561656
ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8);
16571657

1658-
input_report_abs(wdata->extension.input, ABS_X, lx - 0x800);
1659-
input_report_abs(wdata->extension.input, ABS_Y, 0x800 - ly);
1660-
input_report_abs(wdata->extension.input, ABS_RX, rx - 0x800);
1661-
input_report_abs(wdata->extension.input, ABS_RY, 0x800 - ry);
1658+
/* zero-point offsets */
1659+
lx -= 0x800;
1660+
ly = 0x800 - ly;
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);
16621691

16631692
input_report_key(wdata->extension.input,
16641693
wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT],
@@ -1766,12 +1795,70 @@ static int wiimod_pro_play(struct input_dev *dev, void *data,
17661795
return 0;
17671796
}
17681797

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+
17691847
static int wiimod_pro_probe(const struct wiimod_ops *ops,
17701848
struct wiimote_data *wdata)
17711849
{
17721850
int ret, i;
1851+
unsigned long flags;
17731852

17741853
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);
17751862

17761863
wdata->extension.input = input_allocate_device();
17771864
if (!wdata->extension.input)
@@ -1786,6 +1873,13 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
17861873
goto err_free;
17871874
}
17881875

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+
17891883
wdata->extension.input->open = wiimod_pro_open;
17901884
wdata->extension.input->close = wiimod_pro_close;
17911885
wdata->extension.input->dev.parent = &wdata->hdev->dev;
@@ -1806,20 +1900,23 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
18061900
set_bit(ABS_RX, wdata->extension.input->absbit);
18071901
set_bit(ABS_RY, wdata->extension.input->absbit);
18081902
input_set_abs_params(wdata->extension.input,
1809-
ABS_X, -0x800, 0x800, 2, 4);
1903+
ABS_X, -0x400, 0x400, 4, 100);
18101904
input_set_abs_params(wdata->extension.input,
1811-
ABS_Y, -0x800, 0x800, 2, 4);
1905+
ABS_Y, -0x400, 0x400, 4, 100);
18121906
input_set_abs_params(wdata->extension.input,
1813-
ABS_RX, -0x800, 0x800, 2, 4);
1907+
ABS_RX, -0x400, 0x400, 4, 100);
18141908
input_set_abs_params(wdata->extension.input,
1815-
ABS_RY, -0x800, 0x800, 2, 4);
1909+
ABS_RY, -0x400, 0x400, 4, 100);
18161910

18171911
ret = input_register_device(wdata->extension.input);
18181912
if (ret)
1819-
goto err_free;
1913+
goto err_file;
18201914

18211915
return 0;
18221916

1917+
err_file:
1918+
device_remove_file(&wdata->hdev->dev,
1919+
&dev_attr_pro_calib);
18231920
err_free:
18241921
input_free_device(wdata->extension.input);
18251922
wdata->extension.input = NULL;
@@ -1837,6 +1934,8 @@ static void wiimod_pro_remove(const struct wiimod_ops *ops,
18371934
input_unregister_device(wdata->extension.input);
18381935
wdata->extension.input = NULL;
18391936
cancel_work_sync(&wdata->rumble_worker);
1937+
device_remove_file(&wdata->hdev->dev,
1938+
&dev_attr_pro_calib);
18401939

18411940
spin_lock_irqsave(&wdata->state.lock, flags);
18421941
wiiproto_req_rumble(wdata, 0);

drivers/hid/hid-wiimote.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#define WIIPROTO_FLAG_DRM_LOCKED 0x8000
4747
#define WIIPROTO_FLAG_BUILTIN_MP 0x010000
4848
#define WIIPROTO_FLAG_NO_MP 0x020000
49+
#define WIIPROTO_FLAG_PRO_CALIB_DONE 0x040000
4950

5051
#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
5152
WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
@@ -135,6 +136,7 @@ struct wiimote_state {
135136

136137
/* calibration/cache data */
137138
__u16 calib_bboard[4][3];
139+
__s16 calib_pro_sticks[4];
138140
__u8 cache_rumble;
139141
};
140142

0 commit comments

Comments
 (0)