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

Commit 201af55d authored by Jon Flatley's avatar Jon Flatley Committed by Greg Kroah-Hartman
Browse files

usb: core: added uevent for over-current



After commit 1cbd53c8 ("usb: core: introduce per-port over-current
counters") usb ports expose a sysfs value 'over_current_count'
to user space. This value on its own is not very useful as it requires
manual polling.

As a solution, fire a udev event from the usb hub device that specifies
the values 'OVER_CURRENT_PORT' and 'OVER_CURRENT_COUNT' that indicate
the path of the usb port where the over-current event occurred and the
value of 'over_current_count' in sysfs. Additionally, call
sysfs_notify() so the sysfs value supports poll().

Signed-off-by: default avatarJon Flatley <jflat@chromium.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ea3b4d55
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -219,7 +219,14 @@ Description:
		ports and report them to the kernel. This attribute is to expose
		the number of over-current situation occurred on a specific port
		to user space. This file will contain an unsigned 32 bit value
		which wraps to 0 after its maximum is reached.
		which wraps to 0 after its maximum is reached. This file supports
		poll() for monitoring changes to this value in user space.

		Any time this value changes the corresponding hub device will send a
		udev event with the following attributes:

		OVER_CURRENT_PORT=/sys/bus/usb/devices/.../(hub interface)/portX
		OVER_CURRENT_COUNT=[current value of this sysfs attribute]

What:		/sys/bus/usb/devices/.../(hub interface)/portX/usb3_lpm_permit
Date:		November 2015
+36 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/pm_qos.h>
#include <linux/kobject.h>

#include <linux/uaccess.h>
#include <asm/byteorder.h>
@@ -5147,6 +5148,40 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
	usb_lock_port(port_dev);
}

/* Handle notifying userspace about hub over-current events */
static void port_over_current_notify(struct usb_port *port_dev)
{
	static char *envp[] = { NULL, NULL, NULL };
	struct device *hub_dev;
	char *port_dev_path;

	sysfs_notify(&port_dev->dev.kobj, NULL, "over_current_count");

	hub_dev = port_dev->dev.parent;

	if (!hub_dev)
		return;

	port_dev_path = kobject_get_path(&port_dev->dev.kobj, GFP_KERNEL);
	if (!port_dev_path)
		return;

	envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path);
	if (!envp[0])
		return;

	envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u",
			port_dev->over_current_count);
	if (!envp[1])
		goto exit;

	kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp);

	kfree(envp[1]);
exit:
	kfree(envp[0]);
}

static void port_event(struct usb_hub *hub, int port1)
		__must_hold(&port_dev->status_lock)
{
@@ -5189,6 +5224,7 @@ static void port_event(struct usb_hub *hub, int port1)
	if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
		u16 status = 0, unused;
		port_dev->over_current_count++;
		port_over_current_notify(port_dev);

		dev_dbg(&port_dev->dev, "over-current change #%u\n",
			port_dev->over_current_count);