Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Jan 2020 03:23:17 +0000
From:      <Shichun.Ma@dell.com>
To:        <hps@selasky.org>, <freebsd-usb@freebsd.org>
Cc:        <Jason_YH_Yang@wistron.com>
Subject:   Re: USB keyboard/mouse wake up from S3
Message-ID:  <1579231397567.62223@Dell.com>
In-Reply-To: <685f991f-6cb6-3f27-65d8-38181e4cfa8e@selasky.org>
References:  <1578625588784.46788@Dell.com> <47257477-bace-a9c5-69f5-7a0eb7af3947@selasky.org> <1578648297338.92657@Dell.com>, <685f991f-6cb6-3f27-65d8-38181e4cfa8e@selasky.org>

index | next in thread | previous in thread | raw e-mail

[-- Attachment #1 --]

HPS,

Here is my patch to enable USB wakeup under XHCI, I tested USB mouse/keyboard can wake up system from S3.

Thanks & Regards,

Shichun Ma
Software Engineer
Dell | Cloud Client Computing
office +86 10 82862579,  Mobile +86 13241851528
shichun_ma@dell.com



________________________________________
From: Hans Petter Selasky <hps@selasky.org>
Sent: Friday, January 10, 2020 5:41 PM
To: Ma, Horse; freebsd-usb@freebsd.org
Subject: Re: USB keyboard/mouse wake up from S3

[EXTERNAL EMAIL]

On 2020-01-10 10:24, Shichun.Ma@dell.com wrote:
> The USB wake up can still even device is detached.
> Before system enter to S3 and when detach the USB device, we can enable device's remote wake up feature.
> it can still send out the resume signal to host if it connected from hardware.
>

I think we don't do that currently. Would need a patch in the USB core.
Only during normal USB suspend / resume, not host suspend / resume.

--HPS

[-- Attachment #2 --]
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 508ad45f6d9..a448787214a 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -3255,12 +3255,31 @@ acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate)
 	if (bootverbose)
 	    device_printf(dev, "wake_prep disabled wake for %s (S%d)\n",
 		acpi_name(handle), sstate);
-    } else if (dev && (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) != 0) {
+    } else if (dev && (((acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) != 0) ||
+		       (strstr(acpi_name(handle), "XHC")))) { //hard code XHCI as wake up signal, any susggestion on the setting?
 	acpi_pwr_wake_enable(handle, 1);
 	acpi_SetInteger(handle, "_PSW", 1);
-	if (bootverbose)
+	if (1 || bootverbose)
 	    device_printf(dev, "wake_prep enabled for %s (S%d)\n",
 		acpi_name(handle), sstate);
+	ACPI_OBJECT argl[3];
+	ACPI_OBJECT_LIST args = {3, argl};
+
+	acpi_pwr_wake_enable(handle, 1);
+
+	argl[0].Type = ACPI_TYPE_INTEGER;
+	argl[0].Integer.Value = 1;
+
+	argl[1].Type = ACPI_TYPE_INTEGER;
+	argl[1].Integer.Value = sstate;
+
+	argl[2].Type = ACPI_TYPE_INTEGER;
+	argl[2].Integer.Value = 3;
+	if (AcpiEvaluateObject(handle, "_DSW", &args, NULL))
+		device_printf(dev, "ACPI: AcpiEvaluateObject _DSW Failed\n");
+	acpi_SetInteger(handle, "_PSW", 1);
+	//AcpiEnableGpe(prw.gpe_handle, prw.gpe_bit);
+	AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, ACPI_GPE_ENABLE);
     }
 
     return (0);
diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c
index 3887e0423b6..3694296dc15 100644
--- a/sys/dev/usb/controller/usb_controller.c
+++ b/sys/dev/usb/controller/usb_controller.c
@@ -452,6 +452,30 @@ usb_bus_detach(struct usb_proc_msg *pm)
 	bus->bdev = NULL;
 }
 
+static void
+usb_suspend_all(struct usb_bus *bus)
+{
+	int max_depth = 0, i, j;
+	struct usb_device *udev;
+
+	for (i = 0; i < bus->devices_max; i++) {
+		udev = bus->devices[i];
+		if (!udev)
+			continue;
+		if (max_depth < udev->depth)
+			max_depth = udev->depth;
+	}
+
+	for (i = max_depth; i > 0; i--) {
+		for (j = 0; j < bus->devices_max; j++) {
+			udev = bus->devices[j];
+			if (udev && (udev->depth == i) &&
+			    usb_peer_can_wakeup(udev))
+				usb_suspend_dev(udev);
+		}
+	}
+}
+
 /*------------------------------------------------------------------------*
  *	usb_bus_suspend
  *
@@ -483,7 +507,7 @@ usb_bus_suspend(struct usb_proc_msg *pm)
 	 * subsequently. At resume all USB devices will be
 	 * re-connected again.
 	 */
-
+	usb_suspend_all(bus);
 	bus_generic_shutdown(bus->bdev);
 
 	do_unlock = usbd_enum_lock(udev);
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index 8d60ba212de..659babb7af1 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -79,6 +79,7 @@
 #include <dev/usb/usb_util.h>
 
 #include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_pci.h>
 #include <dev/usb/usb_bus.h>
 #endif			/* USB_GLOBAL_INCLUDE_FILE */
 
@@ -695,11 +696,13 @@ xhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
 {
 	struct xhci_softc *sc = XHCI_BUS2SC(bus);
 
+	//xhci_dump_regs(sc);
+
 	switch (state) {
 	case USB_HW_POWER_SUSPEND:
 		DPRINTF("Stopping the XHCI\n");
 		xhci_halt_controller(sc);
-		xhci_reset_controller(sc);
+		//xhci_reset_controller(sc);
 		break;
 	case USB_HW_POWER_SHUTDOWN:
 		DPRINTF("Stopping the XHCI\n");
diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c
index 186d383e35f..53310548e72 100644
--- a/sys/dev/usb/usb_hub.c
+++ b/sys/dev/usb/usb_hub.c
@@ -2927,3 +2927,47 @@ usbd_start_set_config(struct usb_device *udev, uint8_t index)
 	}
 	return (USB_ERR_PENDING_REQUESTS);
 }
+
+int
+usb_suspend_dev(struct usb_device *udev)
+{
+	int err;
+	struct usb_port_status ps;
+
+	err = usbd_req_set_device_feature(udev,
+	    NULL, UF_DEVICE_REMOTE_WAKEUP);
+	if (err) {
+		DPRINTFN(0, "Setting remote wakeup failed, err %d\n", err);
+		return err;
+	}
+	usb_pause_mtx(NULL, USB_MS_TO_TICKS(10));
+	if (usb_device_20_compatible(udev)) {
+		err = usbd_req_set_port_feature(udev->parent_hub,
+		    NULL, udev->port_no, UHF_PORT_SUSPEND);
+		if (err) {
+			DPRINTFN(0, "Suspending port failed\n");
+			return err;
+		}
+	} else {
+		err = usbd_req_set_port_link_state(udev->parent_hub,
+		    NULL, udev->port_no, UPS_PORT_LS_U3);
+		if (err) {
+			DPRINTFN(0, "Suspending port failed\n");
+			return err;
+		}
+	}
+
+	err = usbd_req_get_port_status(udev->parent_hub, NULL, &ps,
+					  udev->port_no);
+	if (UGETW(ps.wPortChange)) {
+		err = usbd_req_clear_port_feature(udev->parent_hub, NULL,
+					udev->port_no, UHF_C_PORT_CONNECTION);
+	}
+	err = usbd_req_get_port_status(udev->parent_hub, NULL, &ps,
+					  udev->port_no);
+	if (!err)
+		DPRINTFN(0, "port %d, %x:%x, err %x:\n", udev->port_no,
+			UGETW(ps.wPortChange), UGETW(ps.wPortStatus), err);
+
+	return 0;
+}
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 0a393844511..8bbbdc26849 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -708,5 +708,6 @@ void	*usb_fifo_softc(struct usb_fifo *fifo);
 void	usb_fifo_set_close_zlp(struct usb_fifo *, uint8_t);
 void	usb_fifo_set_write_defrag(struct usb_fifo *, uint8_t);
 void	usb_fifo_free(struct usb_fifo *f);
+int	usb_suspend_dev(struct usb_device *udev);
 #endif /* _KERNEL */
 #endif /* _USB_USBDI_H_ */
home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1579231397567.62223>