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

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

HID: wiimote: add sysfs extension/device-type attrs



Two new attributes, "extension" and "devtype" now allow user-space to read
the extension type and device type. As device detection is asynchronous,
we send a CHANGED event after it is done. This also allows user-space to
wait for a device to settle before opening its input event devices.

The "extension" device is compatible with the old "extension" sysfs field
(which was registered by the static extension support code).

Signed-off-by: default avatarDavid Herrmann <dh.herrmann@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent d76f89e1
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ Description: Make it possible to set/get current led state. Reading from it
What:		/sys/bus/hid/drivers/wiimote/<dev>/extension
Date:		August 2011
KernelVersion:	3.2
Contact:	David Herrmann <dh.herrmann@googlemail.com>
Contact:	David Herrmann <dh.herrmann@gmail.com>
Description:	This file contains the currently connected and initialized
		extensions. It can be one of: none, motionp, nunchuck, classic,
		motionp+nunchuck, motionp+classic
@@ -20,3 +20,25 @@ Description: This file contains the currently connected and initialized
		the official Nintendo Nunchuck extension and classic is the
		Nintendo Classic Controller extension. The motionp extension can
		be combined with the other two.
		Starting with kernel-version 3.11 Motion Plus hotplugging is
		supported and if detected, it's no longer reported as static
		extension. You will get uevent notifications for the motion-plus
		device then.

What:		/sys/bus/hid/drivers/wiimote/<dev>/devtype
Date:		May 2013
KernelVersion:	3.11
Contact:	David Herrmann <dh.herrmann@gmail.com>
Description:	While a device is initialized by the wiimote driver, we perform
		a device detection and signal a "change" uevent after it is
		done. This file shows the detected device type. "pending" means
		that the detection is still ongoing, "unknown" means, that the
		device couldn't be detected or loaded. "generic" means, that the
		device couldn't be detected but supports basic Wii Remote
		features and can be used.
		Other strings for each device-type are available and may be
		added if new device-specific detections are added.
		Currently supported are:
			gen10: First Wii Remote generation
			gen20: Second Wii Remote Plus generation (builtin MP)
			balanceboard: Wii Balance Board
+105 −1
Original line number Diff line number Diff line
@@ -1166,11 +1166,18 @@ static void wiimote_init_worker(struct work_struct *work)
{
	struct wiimote_data *wdata = container_of(work, struct wiimote_data,
						  init_worker);
	bool changed = false;

	if (wdata->state.devtype == WIIMOTE_DEV_PENDING)
	if (wdata->state.devtype == WIIMOTE_DEV_PENDING) {
		wiimote_init_detect(wdata);
		changed = true;
	}

	if (!wiimote_init_check(wdata))
		wiimote_init_hotplug(wdata);

	if (changed)
		kobject_uevent(&wdata->hdev->dev.kobj, KOBJ_CHANGE);
}

void __wiimote_schedule(struct wiimote_data *wdata)
@@ -1591,6 +1598,84 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
	return 0;
}

static ssize_t wiimote_ext_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	struct wiimote_data *wdata = dev_to_wii(dev);
	__u8 type;
	unsigned long flags;

	spin_lock_irqsave(&wdata->state.lock, flags);
	type = wdata->state.exttype;
	spin_unlock_irqrestore(&wdata->state.lock, flags);

	switch (type) {
	case WIIMOTE_EXT_NONE:
		return sprintf(buf, "none\n");
	case WIIMOTE_EXT_NUNCHUK:
		return sprintf(buf, "nunchuk\n");
	case WIIMOTE_EXT_CLASSIC_CONTROLLER:
		return sprintf(buf, "classic\n");
	case WIIMOTE_EXT_BALANCE_BOARD:
		return sprintf(buf, "balanceboard\n");
	case WIIMOTE_EXT_UNKNOWN:
		/* fallthrough */
	default:
		return sprintf(buf, "unknown\n");
	}
}

static ssize_t wiimote_ext_store(struct device *dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{
	struct wiimote_data *wdata = dev_to_wii(dev);

	if (!strcmp(buf, "scan")) {
		wiimote_schedule(wdata);
	} else {
		return -EINVAL;
	}

	return strnlen(buf, PAGE_SIZE);
}

static DEVICE_ATTR(extension, S_IRUGO | S_IWUSR | S_IWGRP, wiimote_ext_show,
		   wiimote_ext_store);

static ssize_t wiimote_dev_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	struct wiimote_data *wdata = dev_to_wii(dev);
	__u8 type;
	unsigned long flags;

	spin_lock_irqsave(&wdata->state.lock, flags);
	type = wdata->state.devtype;
	spin_unlock_irqrestore(&wdata->state.lock, flags);

	switch (type) {
	case WIIMOTE_DEV_GENERIC:
		return sprintf(buf, "generic\n");
	case WIIMOTE_DEV_GEN10:
		return sprintf(buf, "gen10\n");
	case WIIMOTE_DEV_GEN20:
		return sprintf(buf, "gen20\n");
	case WIIMOTE_DEV_BALANCE_BOARD:
		return sprintf(buf, "balanceboard\n");
	case WIIMOTE_DEV_PENDING:
		return sprintf(buf, "pending\n");
	case WIIMOTE_DEV_UNKNOWN:
		/* fallthrough */
	default:
		return sprintf(buf, "unknown\n");
	}
}

static DEVICE_ATTR(devtype, S_IRUGO, wiimote_dev_show, NULL);

static struct wiimote_data *wiimote_create(struct hid_device *hdev)
{
	struct wiimote_data *wdata;
@@ -1631,6 +1716,9 @@ static void wiimote_destroy(struct wiimote_data *wdata)
	cancel_work_sync(&wdata->init_worker);
	del_timer_sync(&wdata->timer);

	device_remove_file(&wdata->hdev->dev, &dev_attr_devtype);
	device_remove_file(&wdata->hdev->dev, &dev_attr_extension);

	wiimote_mp_unload(wdata);
	wiimote_ext_unload(wdata);
	wiimote_modules_unload(wdata);
@@ -1673,6 +1761,18 @@ static int wiimote_hid_probe(struct hid_device *hdev,
		goto err_stop;
	}

	ret = device_create_file(&hdev->dev, &dev_attr_extension);
	if (ret) {
		hid_err(hdev, "cannot create sysfs attribute\n");
		goto err_close;
	}

	ret = device_create_file(&hdev->dev, &dev_attr_devtype);
	if (ret) {
		hid_err(hdev, "cannot create sysfs attribute\n");
		goto err_ext;
	}

	ret = wiidebug_init(wdata);
	if (ret)
		goto err_free;
@@ -1688,6 +1788,10 @@ static int wiimote_hid_probe(struct hid_device *hdev,
	wiimote_destroy(wdata);
	return ret;

err_ext:
	device_remove_file(&wdata->hdev->dev, &dev_attr_extension);
err_close:
	hid_hw_close(hdev);
err_stop:
	hid_hw_stop(hdev);
err: