Open zwhitchcox opened 3 years ago
Have you found a solution for this? Thanks!
I have run into the same issue a few days ago ... but still after hours of research I couldn't get it working :(
I'm fixing it now but I need some information from RPi devs.
@pelwell I'm sorry to bother you, but it seems that dwc2
has a problem with correctly determining the capabilities of the controller (or maybe not). dwc2
considers that the flag hw->hibernation = !!(hwcfg4 & GHWCFG4_HIBER)
is 0
on RPi. Is it correct? I tried to force the parameter p->power = DWC2_POWER_DOWN_PARAM_HIBERNATION
here and apparently everything works, I was able to wakeup the host (with some other improvements, but the key point was this flag). Is it really 0
or is it actually supported on broadcom and it's lying?
PS: Maybe related with #3151
I used the USB protocol analyzer to make sure that it works. Yes, the host really switch the interface in suspend and then using dwc2_gadget_exit_hibernation(*, 1, 0)
, host immediately wakeups. On the other hand, do I understand correctly the purpose of this function that it should be called by RPi if RPi wants to wakeup the host? The description says that it is initiated by the host, but it has a rem_wakeup parameter that indicates if it is initiated by the device (RPi).
I also found that this code is sufficient to make wakeup work with echo 1 > /sys/devices/platform/soc/fe980000.usb/udc/fe980000.usb/srp
. This works in a similar way in dwc3
.
The second question is related to this: should I send a wakeup signal using dwc2_hsotg_wakeup and then wait for this event to be processed using dwc2_gadget_exit_hibernation as a callback?
static int dwc2_hsotg_wakeup(struct usb_gadget *gadget)
{
struct dwc2_hsotg *hsotg = to_hsotg(gadget);
struct dwc2_dregs_backup *dr = &hsotg->dr_backup;
u32 dctl;
unsigned long flags;
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_writel(hsotg, dr->dctl | DCTL_RMTWKUPSIG, DCTL);
mdelay(12);
dctl = dwc2_readl(hsotg, DCTL);
dctl &= ~DCTL_RMTWKUPSIG;
dwc2_writel(hsotg, dctl, DCTL);
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
}
static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
.get_frame = dwc2_hsotg_gadget_getframe,
.set_selfpowered = dwc2_hsotg_set_selfpowered,
.udc_start = dwc2_hsotg_udc_start,
.udc_stop = dwc2_hsotg_udc_stop,
.pullup = dwc2_hsotg_pullup,
.vbus_session = dwc2_hsotg_vbus_session,
.vbus_draw = dwc2_hsotg_vbus_draw,
.wakeup = dwc2_hsotg_wakeup, // <------------------------------------------------
};
Can not understand what you described. Don't know how to help as well. Sorry!
Interesting results. If I force the hibernate flag, then everything is fine for a while, but after 15 minutes the kernel starts to freeze. I probably shouldn't do this.
The second approach - my naive implementation of dwc2_hsotg_wakeup()
- gives an interesting effect. It is able to wake up the host, but after that the hid gadget stops working until I reconnect the USB (but it can still send wakeup signal). I suppose this is due to the fact that I do not reset some other flags.
Okay, I'm stupid. dr->dctl has invalid value in dwc2_hsotg_wakeup()
when hibernation=0 (not forced to 1). I'll try to use dwc2_set_bit/dwc2_cleat_bit
later.
But the question remains why the kernel freezes when hibernation=1.
dwc2_set_bit/dwc2_cleat_bit
is not working. Same result.
I doubt it will be easy to obtain from Broadcom the Verilog that makes up the DWC OTG controller to discover definitively which features have been enabled, but it shouldn't be necessary. The purpose of the HWCFG<n>
registers is to record those settings in a way that can be interrogated by the driver, and they are likely to have been populated automatically by the configuration software that came with the IP from the supplier.
Until you demonstrate that hibernation works properly I see no reason to not believe that it doesn't.
@pelwell I think so. My experiments show that this partially works, but eventually leads to a freeze. It seems that either this feature is partially implemented in IP (but not enough to work), or in the case of RPi, something special is required to work properly.
What confuses me is that even without forcing this value, suspend works correctly. That is, I see how the host puts the port to suspend state, then wakes it up (I use a second keyboard for this), and the RPi USB gadget continues to work perfectly again, no matter how many times this cycle occurs.
Do I understand correctly that in the case of RPi, suspend is implemented in hardware and it does not require additional processing from the driver?
I don't know.
Okay, anyway, thanks for the information. I will continue to investigate and maybe find out something.
Here's a workaround that works for me (on a pi zero w) : https://github.com/karn862/linux/commit/bbb6ccfac814f23930512ec05c0393ac1f593291. I'm calling a modified version of the dwc2_gadget_exit_hibernate function to exit the usb suspend state instead (since we're not hibernated).
I hope this can be helpful in finding a real fix, or at least be a temporary solution for anyone else missing this feature.
I've bought the pi zero w for the sole purpose of using the remote wakeup, so this is good enough for me. I haven't done any extensive testing, but it survives multiple suspend - wakeup sequences, and i can still inject keys in the hidg device afterwards.
Here's a workaround that works for me (on a pi zero w) : karn862@bbb6ccf. I'm calling a modified version of the dwc2_gadget_exit_hibernate function to exit the usb suspend state instead (since we're not hibernated).
I'm still getting the "echo: write error: Resource temporarily unavailable" message, but can confirm the workaround works for me too! I'm now able to "remote-wakeup" and unlock my host system (iPad Pro 2021) with the RPi zero. Thank you very much.
Very little information on this subject on the internet. Aside from this thread I found this post in Japanese http://www.dt8.jp/cgi-bin/adiary/adiary.cgi/0583. Looking at the Google Translate version, it seems the person was able to solve the problem.
They modified two files which I've replicated to my own fork here https://github.com/jlian/linux/compare/raspberrypi:linux:rpi-5.15.y...patch-1. Most importantly, they add dwc2_hsotg_wakeup
in gadget.c
just like above from @mdevaev and it looks very similar.
static int dwc2_hsotg_wakeup(struct usb_gadget *gadget)
{
u32 dctl;
struct dwc2_dregs_backup *dr;
struct dwc2_hsotg *dev;
unsigned long flags;
dev = container_of(gadget, struct dwc2_hsotg, gadget);
dr = &dev->dr_backup;
spin_lock_irqsave(&dev->lock, flags);
udelay(10);
/* Start Remote Wakeup Signaling */
dwc2_writel(dr->dctl | DCTL_RMTWKUPSIG, dev->regs + DCTL);
mdelay(12);
dctl = dwc2_readl(dev->regs + DCTL);
dctl &= ~DCTL_RMTWKUPSIG;
dwc2_writel(dctl, dev->regs + DCTL);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
I can't speak Japanese, don't understand most of this, nor have I tried this myself (looks like I'll have compile the kernel?). But I thought this information might be helpful to folks on this thread 😅.
@jlian It will not work :) In 5.15 dwc2 started performing clock gating and it broke the patch. The good news is that I figured out how to fix it the right way: https://github.com/pikvm/packages/blob/master/packages/linux-rpi-pikvm/1003-remote-wakeup.patch
Oh wow, I'm glad that I made the comment to learn about the actual fix!
@mdevaev is this also fixed in the upstream Linux kernel? Do you have any pointers on how I might apply your patch if I'm using https://github.com/homebridge/homebridge-raspbian-image?
This patch is suitable for upstream 5.15. But I haven't used homebridge since I'm building kernels for Arch.
@mdevaev I applied your patch, compiled the kernel, and put onto my Raspberry Pi 4 (notes https://github.com/jlian/linux-kernel-cross-compile). Unfortunately it didn't seem to fix it for me. I'm pretty (?) sure that I did the patching/compilation correctly, but it's my first time doing so and I'm not even sure how to check that my Pi is using the patched kernel or not.
Below command writes "whatup" if the computer is awake. With a sleeping computer it errors out like before.
pi@homebridge:~ $ echo -ne "\0\0\x1a\x0b\x04\x17\x18\x13" > /dev/hidg0 && echo -ne "\0\0\0\0\0\0\0\0" > /dev/hidg0
-bash: echo: write error: Resource temporarily unavailable
EDIT: I also did echo 0xa0 > configs/c.1/bmAttributes
following this post https://www.rmedgar.com/blog/using-rpi-zero-as-keyboard-setup-and-device-definition/ and still it doesn't fix it. I checked that it's applied by
pi@homebridge:~ $ cat /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
0xa0
You need to enable wakeup_on_write
in the driver:
echo 1 > /sys/kernel/config/usb_gadget/GADGET/functions/hid.usb0/wakeup_on_write
Whoa! It worked! Thanks so much @mdevaev ! I hope the patch gets included in the official kernel soon 🥇
Ur welcome. I haven't sent it yet as it slightly duplicates the existing code. When I have time, I will try to put it in order. The good news is that I will be maintaining it in my repository anyway.
@mdevaev - a bit off-topic reply here, but: awesome project - a KVM from a Raspberry Pi!
Thanks)
Hey guys, thanks for the great solution. Can this be applied to Pi zero?
Patch - yes. PiKVM - you need zero2 at least.
Patch - yes. PiKVM - you need zero2 at least.
Thanks! What I want is connecting pi 0 to usb and acts as a keyboard. Then connect to wifi. I would like to connect it through ssh and wake up my computer. Can you tell me whether this is able to work? :)
Yea, why not.
Awesome! Unluckily, zero 2 wifi is out of stock everywhere..... I returned mine because it didn't work when I found this thread one year ago
@mdevaev GIve us a poke when your final patch makes it upstream and we'll back-port it.
@pelwell okay!
You need to enable
wakeup_on_write
in the driver:echo 1 > /sys/kernel/config/usb_gadget/GADGET/functions/hid.usb0/wakeup_on_write
Hello, I'm trying to apply this after having recompiled Linux with the patch, but I have a message error saying that device or ressource is busy... any idea where I'm doing wrong ? Thanks a lot !
My bad I did it the wrong way (trying to change the value after configuration is just a bad idea ^^).
It works 100% (when you don't forgot the right bmAttributes)
Is there any other way to wake up the host via gadget mode besides this patch? I'd be fine with having to check whether the write was successful and then sending the signal if it wasn't. There really isn't much documentation on this specific topic out there.
No. You need to affect the USB at a low level, this is impossible without a patch.
I struggled with this for a month with my zero and it never worked so, this is way off topic, but if the goal is to wake up the computer rather than to do it with an rpi at all cost there is a solution. Since this solution requires a zero2, some $$ need to be spent. An alternative is to spend $ on a pico w. Circuitpython version 9 includes wakeup support. I have it running using mosquitto_sub on the pico to triger the hid functions. Then I just publish a message from where I am working and the machine connected to the pico wakes up. I have two of them so I just change the topic to the machine name and the one I want wakes up. I have a short powershell script that prompts for machine name and runs the pub command. I can post the code if mentioning a pico in this thread doesn't offend anyone
I built some utility tool to build and deploy modified kernel
I built some utility tool to build and deploy modified kernel
Can i build it on raspbian for rpi4 , like how do i do it do i need to run it like normal and burn it into sdcard or what ?
Describe the bug A raspberry pi Zero in HID gadget mode cannot wake host computer.
To reproduce Enable
dwc2
driver and reboot:Load modules:
Add keyboard to ConfigFS:
Now, output keys to
/dev/hidg0
When you are plugged in to a host computer that is on, it will output the keys. That works fine.
Next suspend the host computer, and try the same thing:
You get an error:
Per the kernel gadget documentation, this the
remote wakeup
functionality is supposed to be handled by the kernel gadget driver.Expected behaviour When you send keys to the host computer, the gadget driver should send the
wakeup
signal to the host computer, instead of just failing.Actual behaviour As mentioned previously, you can't write to the file
System
raspinfo
``` System Information ------------------ Raspberry Pi Zero W Rev 1.1 PRETTY_NAME="Raspbian GNU/Linux 10 (buster)" NAME="Raspbian GNU/Linux" VERSION_ID="10" VERSION="10 (buster)" Raspberry Pi reference 2020-08-20 Generated using pi-gen, https://github.com/RPi-Distro/pi-gen, 9a3a10bf1019ebb2d59053564dc6b90068bad27d, stage2 Linux raspberrypi 5.4.51+ #1333 Mon Aug 10 16:38:02 BST 2020 armv6l GNU/Linux Revision : 9000c1 Serial : 0000000050a70373 Model : Raspberry Pi Zero W Rev 1.1 Throttled flag : throttled=0x0 Camera : supported=0 detected=0 Videocore information --------------------- Aug 19 2020 17:40:36 Copyright (c) 2012 Broadcom version e90cba19a98a0d1f2ef086b9cafcbca00778f094 (clean) (release) (start_cd) alloc failures: 0 compactions: 0 legacy block fails: 0 Filesystem information ---------------------- Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 30485636 7499856 21715764 26% / devtmpfs 212620 0 212620 0% /dev tmpfs 245632 0 245632 0% /dev/shm tmpfs 245632 6548 239084 3% /run tmpfs 5120 4 5116 1% /run/lock tmpfs 245632 0 245632 0% /sys/fs/cgroup /dev/mmcblk0p1 258095 54603 203492 22% /boot tmpfs 49124 0 49124 0% /run/user/1000 /dev/mapper/loop0p1 40862 6016 34846 15% /mnt/loop0p1 /dev/mapper/loop0p2 1353296 585912 677068 47% /mnt/loop0p2 /dev/mapper/loop0p3 3003 29 2689 2% /mnt/loop0p3 Filename Type Size Used Priority /var/swap file 102396 4352 -2 Package version information --------------------------- raspberrypi-ui-mods: Installed: (none) raspberrypi-sys-mods: Installed: 20200812 openbox: Installed: (none) lxpanel: Installed: (none) pcmanfm: Installed: (none) rpd-plym-splash: Installed: (none) Networking Information ---------------------- lo: flags=73