From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com>

This modification generates a 'uevent' to userland and adds the
'OVERCURRENT=1' environment when overcurrent event happens and
adds the 'OVERCURRENT=0' environment when returning to normal
current condition, with PORT number.

Any userland program listening to the 'uevent' interface can filter
for the presence of this environment variable to distinguish this
special 'uevent' from other 'add' or 'remove' events.

Current disadvantage: Due to the fact, the hub driver tries to enable
the port again immediately (it does not wait for user interaction)
this powerfail event gets reported twice: First time when it really
happens and second time when the external overcurrent detection device
will be reset. The second false positive report must be sorted out
by the userland application.

This patch is derived from [PATCH] Generate a uevent when an overcurrent
event happens by Juergen Beisert <jbe@@pengutronix.de> and
Michael Grzeschik <m.grzeschik@@pengutronix>.

Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.moha...@intel.com>
---
 drivers/usb/core/Kconfig |  8 ++++++++
 drivers/usb/core/hub.c   | 41 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index a99c89e..560e455 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -84,6 +84,14 @@ config USB_OTG_FSM
          Implements OTG Finite State Machine as specified in On-The-Go
          and Embedded Host Supplement to the USB Revision 2.0 Specification.
 
+config USB_OC_NOTIFICATION
+       bool "Enable Over Current Notification"
+       default n
+       help
+         Say Y here if you want to send uevent to userland for
+         over current condition on USB ports and ports coming to
+         normal state after over current condition is over.
+
 config USB_ULPI_BUS
        tristate "USB ULPI PHY interface support"
        depends on USB_SUPPORT
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 563d84e..def3200 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4891,6 +4891,16 @@ static void hub_port_connect_change(struct usb_hub *hub, 
int port1,
        usb_lock_port(port_dev);
 }
 
+#ifdef CONFIG_USB_OC_NOTIFICATION
+char oc_event[] = "OVERCURRENT=1";
+char oc_port[10];
+char *oc_envp[] = {oc_event, oc_port, NULL};
+char nc_event[] = "OVERCURRENT=0";
+char nc_port[10];
+char *nc_envp[] = {nc_event, nc_port, NULL};
+static int oc_flag;
+#endif
+
 static void port_event(struct usb_hub *hub, int port1)
                __must_hold(&port_dev->status_lock)
 {
@@ -4934,13 +4944,42 @@ static void port_event(struct usb_hub *hub, int port1)
                u16 status = 0, unused;
 
                dev_dbg(&port_dev->dev, "over-current change\n");
+#ifdef CONFIG_USB_OC_NOTIFICATION
+               if (oc_flag & BIT(port1 - 1)) {
+                       /*
+                        * Send event to userland for overcurrent condition
+                        * change at port with port number.
+                        */
+                       snprintf(oc_port, sizeof(oc_port), "NPORT=%d", port1);
+                       if (kobject_uevent_env(&hub->intfdev->kobj,
+                                               KOBJ_CHANGE, nc_envp))
+                               dev_err(&port_dev->dev,
+                                       "failed to send change OC event.\n");
+                       /* Clear port's oc_flag. */
+                       oc_flag &= ~(BIT(port1 - 1));
+               }
+#endif
                usb_clear_port_feature(hdev, port1,
                                USB_PORT_FEAT_C_OVER_CURRENT);
                msleep(100);    /* Cool down */
                hub_power_on(hub, true);
                hub_port_status(hub, port1, &status, &unused);
-               if (status & USB_PORT_STAT_OVERCURRENT)
+               if (status & USB_PORT_STAT_OVERCURRENT) {
                        dev_err(&port_dev->dev, "over-current condition\n");
+#ifdef CONFIG_USB_OC_NOTIFICATION
+                       /*
+                        * Send event to userland for overcurrent condition
+                        * with port number.
+                        */
+                       snprintf(oc_port, sizeof(oc_port), "OCPORT=%d", port1);
+                       if (kobject_uevent_env(&hub->intfdev->kobj,
+                                               KOBJ_CHANGE, oc_envp))
+                               dev_err(&port_dev->dev,
+                                       "failed to send OC event.\n");
+                       /* Set port's oc_flag. */
+                       oc_flag |= BIT(port1 - 1);
+#endif
+               }
        }
 
        if (portchange & USB_PORT_STAT_C_RESET) {
-- 
1.9.1

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to