Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34472d37 authored by David Herrmann's avatar David Herrmann Committed by Jiri Kosina
Browse files

HID: wiimote: add Motion Plus extension module



Add parsers for motion plus data so we can hotplug motion plus extensions
and make use of them. This is mostly the same as the old static motion
plus parser.

Signed-off-by: default avatarDavid Herrmann <dh.herrmann@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 9d6f9ecb
Loading
Loading
Loading
Loading
+144 −0
Original line number Original line Diff line number Diff line
@@ -1475,11 +1475,155 @@ static const struct wiimod_ops wiimod_bboard = {


/*
/*
 * Motion Plus
 * Motion Plus
 * The Motion Plus extension provides rotation sensors (gyro) as a small
 * extension device for Wii Remotes. Many devices have them built-in so
 * you cannot see them from the outside.
 * Motion Plus extensions are special because they are on a separate extension
 * port and allow other extensions to be used simultaneously. This is all
 * handled by the Wiimote Core so we don't have to deal with it.
 */
 */


static void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext)
{
	__s32 x, y, z;

	/*        |   8    7    6    5    4    3 |  2  |  1  |
	 *   -----+------------------------------+-----+-----+
	 *    1   |               Yaw Speed <7:0>            |
	 *    2   |              Roll Speed <7:0>            |
	 *    3   |             Pitch Speed <7:0>            |
	 *   -----+------------------------------+-----+-----+
	 *    4   |       Yaw Speed <13:8>       | Yaw |Pitch|
	 *   -----+------------------------------+-----+-----+
	 *    5   |      Roll Speed <13:8>       |Roll | Ext |
	 *   -----+------------------------------+-----+-----+
	 *    6   |     Pitch Speed <13:8>       |  1  |  0  |
	 *   -----+------------------------------+-----+-----+
	 * The single bits Yaw, Roll, Pitch in the lower right corner specify
	 * whether the wiimote is rotating fast (0) or slow (1). Speed for slow
	 * roation is 440 deg/s and for fast rotation 2000 deg/s. To get a
	 * linear scale we multiply by 2000/440 = ~4.5454 which is 18 for fast
	 * and 9 for slow.
	 * If the wiimote is not rotating the sensor reports 2^13 = 8192.
	 * Ext specifies whether an extension is connected to the motionp.
	 * which is parsed by wiimote-core.
	 */

	x = ext[0];
	y = ext[1];
	z = ext[2];

	x |= (((__u16)ext[3]) << 6) & 0xff00;
	y |= (((__u16)ext[4]) << 6) & 0xff00;
	z |= (((__u16)ext[5]) << 6) & 0xff00;

	x -= 8192;
	y -= 8192;
	z -= 8192;

	if (!(ext[3] & 0x02))
		x *= 18;
	else
		x *= 9;
	if (!(ext[4] & 0x02))
		y *= 18;
	else
		y *= 9;
	if (!(ext[3] & 0x01))
		z *= 18;
	else
		z *= 9;

	input_report_abs(wdata->mp, ABS_RX, x);
	input_report_abs(wdata->mp, ABS_RY, y);
	input_report_abs(wdata->mp, ABS_RZ, z);
	input_sync(wdata->mp);
}

static int wiimod_mp_open(struct input_dev *dev)
{
	struct wiimote_data *wdata = input_get_drvdata(dev);
	unsigned long flags;

	spin_lock_irqsave(&wdata->state.lock, flags);
	wdata->state.flags |= WIIPROTO_FLAG_MP_USED;
	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
	__wiimote_schedule(wdata);
	spin_unlock_irqrestore(&wdata->state.lock, flags);

	return 0;
}

static void wiimod_mp_close(struct input_dev *dev)
{
	struct wiimote_data *wdata = input_get_drvdata(dev);
	unsigned long flags;

	spin_lock_irqsave(&wdata->state.lock, flags);
	wdata->state.flags &= ~WIIPROTO_FLAG_MP_USED;
	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
	__wiimote_schedule(wdata);
	spin_unlock_irqrestore(&wdata->state.lock, flags);
}

static int wiimod_mp_probe(const struct wiimod_ops *ops,
			   struct wiimote_data *wdata)
{
	int ret;

	wdata->mp = input_allocate_device();
	if (!wdata->mp)
		return -ENOMEM;

	input_set_drvdata(wdata->mp, wdata);
	wdata->mp->open = wiimod_mp_open;
	wdata->mp->close = wiimod_mp_close;
	wdata->mp->dev.parent = &wdata->hdev->dev;
	wdata->mp->id.bustype = wdata->hdev->bus;
	wdata->mp->id.vendor = wdata->hdev->vendor;
	wdata->mp->id.product = wdata->hdev->product;
	wdata->mp->id.version = wdata->hdev->version;
	wdata->mp->name = WIIMOTE_NAME " Motion Plus";

	set_bit(EV_ABS, wdata->mp->evbit);
	set_bit(ABS_RX, wdata->mp->absbit);
	set_bit(ABS_RY, wdata->mp->absbit);
	set_bit(ABS_RZ, wdata->mp->absbit);
	input_set_abs_params(wdata->mp,
			     ABS_RX, -16000, 16000, 4, 8);
	input_set_abs_params(wdata->mp,
			     ABS_RY, -16000, 16000, 4, 8);
	input_set_abs_params(wdata->mp,
			     ABS_RZ, -16000, 16000, 4, 8);

	ret = input_register_device(wdata->mp);
	if (ret)
		goto err_free;

	return 0;

err_free:
	input_free_device(wdata->mp);
	wdata->mp = NULL;
	return ret;
}

static void wiimod_mp_remove(const struct wiimod_ops *ops,
			     struct wiimote_data *wdata)
{
	if (!wdata->mp)
		return;

	input_unregister_device(wdata->mp);
	wdata->mp = NULL;
}

const struct wiimod_ops wiimod_mp = {
const struct wiimod_ops wiimod_mp = {
	.flags = 0,
	.flags = 0,
	.arg = 0,
	.arg = 0,
	.probe = wiimod_mp_probe,
	.remove = wiimod_mp_remove,
	.in_mp = wiimod_mp_in_mp,
};
};


/* module table */
/* module table */
+1 −0
Original line number Original line Diff line number Diff line
@@ -139,6 +139,7 @@ struct wiimote_data {
	struct input_dev *accel;
	struct input_dev *accel;
	struct input_dev *ir;
	struct input_dev *ir;
	struct power_supply battery;
	struct power_supply battery;
	struct input_dev *mp;
	struct timer_list timer;
	struct timer_list timer;
	struct wiimote_ext *ext;
	struct wiimote_ext *ext;
	struct wiimote_debug *debug;
	struct wiimote_debug *debug;