raspberrypi / linux

Kernel source tree for Raspberry Pi-provided kernel builds. Issues unrelated to the linux kernel should be posted on the community forum at https://forums.raspberrypi.com/
Other
11k stars 4.95k forks source link

RPi zero Support for USB Gadget Mode (pi shows up as keyboard, disk, net, camera etc) #1212

Closed hh closed 8 years ago

hh commented 8 years ago

Having a $5 usb gadget that could function as a combination of anything in https://github.com/torvalds/linux/tree/master/drivers/usb/gadget/function would be pretty grand.

Think about your phone, how it works to connect a micro-B to charge and connect to it as a gadget to your computer, then when you connect a micro-A cable you plug mice, keyboard, and thumb drives into your phone.

As a usb host, you can plug a phone into it (just like you do your dekstop or laptop) and flash it. Format a usb drive, or bootstrap embedded devices like intel edison.

As a usb gadet, you can plug it into a computer and have it show up as a usb keyboard, disk, network, and other interesting things. (send some keystrokes to hit F12, and boot to a usb installation disk).

I'm looking to see if we can't get the RPi zero to function as both.

It looks like it may have worked at one point: https://github.com/raspberrypi/linux/issues/881#issuecomment-161411866

I just wanted to gauge the interest.

imbens commented 8 years ago

That would also allow you to code on the Pi Zero with only a single cable (for power and network) to a PC.

harjoc commented 8 years ago

Apparently the data pins on the port used for power aren't connnected to the SoC:

http://raspberrypi.stackexchange.com/questions/8587/can-you-transfer-data-through-the-microusb

hh commented 8 years ago

I'm not talking about using the port that is for power only.

This is specifically for the second usb micro port on the RPi zero that does have the data pins connected (you usually use an OTG cable to connect to it in host mode). I'm wanting to use that same port in gadget mode.

hh commented 8 years ago

It looks like the RPi can be powered over that second port (the one we want to use in gadget mode). So @imbens idea for allowing us to code with a single cable seems valid.

hh commented 8 years ago

For most OTG supported ports, it depends on what you plug into it that decides if the port is in host mode or gadget mode. We just need to get confirmation that the RPi zero port is wired the same way for the port that has it's usb data pins connected (not the one dedicated to power).

"A device with a micro-A plug inserted becomes an OTG A-device, and a device with a micro-B plug inserted becomes a B-device. The type of plug inserted is detected by the state of the pin ID ."

The RPi zero USB_OTGID pin should be grounded by the cable when using a micro-A / OTG cable and is hopefully left floating otherwise. That way we can the more common micro-B cable for providing power and connecting the usb data pins to a computer.

Here is a RPi zero mechanical diagram, that shows the two usb micro ports for the RPi zero in bottom right:

image

I couldn't find wiring schematics for RPi zero, so I pulled these from the RPi A

This is the usb micro port used for power: (no data pins)

image

This is the RPi-A USB-A port (note that the USB_OTGID pin on the usb controller is grounded). On the RPi zero, this connector is a micro-b port, and shouldn't have the USB_OTGID pin grounded, as that is usually done by the cable to distinguish between OTG/Host mode and usb gadget mode.

image

I suspect that if we connect a normal usb A to Micro-B cable that doesn't ground out the USB_OTGID pin on the RPi zero, that we can accomplish the correct physical connections without any modifications, but we may need the kernel changes mentioned in this comment on #881

hh commented 8 years ago

@ladyada provides a really nice picture of the port in questions:

RPi zero photo from ladyada

We want to use the USB micro port on the left, not the POWER IN port on the right.

lurch commented 8 years ago

I agree it would be great to see this working.

I don't have a PiZero myself yet, and this doesn't directly relate to the linux driver mentioned here (so apologies if this is slightly off-topic) but I experimented earlier in the year (or maybe it was last year) and was able to get https://github.com/raspberrypi/tools/tree/master/usbboot to work with a Raspberry Pi Model A, when either no SD card was inserted, or when start.elf (I think - or maybe it was bootcode.bin) was renamed. I.e. if I logged into the Model A over the serial terminal, renamed /boot/start.elf on the SD card, ran rpiboot on my PC and used the serial terminal to reboot the Pi, then I was able to access the Model A's SD card on the PC as a MassStorageDevice.

lurch commented 8 years ago

I've just been playing around in GIMP with the lovely hi-res images from https://learn.adafruit.com/introducing-the-raspberry-pi-zero by following the traces across the top and bottom sides of the PCB :-) It looks like the USB_OTGID pin connects from the MicroUSB to the SOC, and also connects to PP40 on the underside of the board. And the 5V from the "PWR IN" MicroUSB port is connected to the 5V on the "USB" MicroUSB port via the black component with a yellow circle on it - which might be a zero-ohm resistor?

macmpi commented 8 years ago

Any chance we could then use Chromecast Ethernet Adapter (https://store.google.com/product/ethernet_adapter_for_chromecast) to both charge & get RJ45 socket in one cable then? That would be great solution for RPi zero Usure it would require additional driver though: can't tell which chipset it is using.

lurch commented 8 years ago

Any chance we could then use Chromecast Ethernet Adapter

Interesting idea. I did a bit of googling and found https://productforums.google.com/forum/#!topic/chromecast/xo_NDh5CZA8 which says "the Chromecast kernel includes only one driver (asix.ko / USB_NET_AX8817X)" so that's obviously the driver needed for the official chromecast adaptor, and the asix.ko driver is already well supported on Linux.

macmpi commented 8 years ago

Well, that's what I initially thought but there might be some more subtle consideration on that adapter. I used AX8817X dongles and Y OTG cable to charge/ethernet both Chromecast and some Android tablets, all sharing the same well known driver indeed. I then bought the Chromecast Ethernet Adapter for the same, but it does only work with Chromecast for some mysterious reason...(other chipset, wierd cabling? ...) Would love to see it working with Pi Zero, as it would provide elegant solution for that tiny board. I hope this effort will bring it closer: I do not intend to hijack the thread more with this.

procount commented 8 years ago

Anyone seen this post from Dom about gadget mode on the PiZero on the forum? https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=127003&p=850028&hilit=pi+zero+gadget#p850028 It provides a bit of insight about what is necessary.

hh commented 8 years ago

From Dom's post:

On Pi Zero the OTG line is used and makes the linux driver choose
host/gadget mode. However as most people want host mode, and
non-OTG cables make the Pi Zero boot in gadget mode, we ignore this.

Looks like at some point it was decided to force the port into host mode, because the original Pi only had a host port. Would it make sense at this point to just revert this commit globally:

gusbcfg.b.force_host_mode = 1

to

gusbcfg.b.force_host_mode = 0

Anyone want to compile and test this?

Yes, in theory USB OTG and using the Pi Zero as a host or gadget is possible
(just as it is on model A and CM). Not sure if anyone has got that working?

I'm still trying to get one to test with.

However that is not sufficient. The USB driver hasn't been tested in gadget mode
by us for about 3 years, and certainly some of the FIQ stuff doesn't work with gadget
mode. Some some hacking would be needed (starting with disabling the fiq) to make
this work. Volunteers are welcome!

Looking forward to some momentum here.

lurch commented 8 years ago

Would it make sense at this point to just revert this commit globally:

Based on @popcornmix 's commit comment of "Force host mode to fix incorrect compute module boards" and looking at the compute module schematics it sounds like some (lots?) of people have made modules for the CM to plug into, and I'm guessing they forgot to ground the USB_OTGID pin but they actually wanted the USB to be in host mode, so the driver was modified to always only support host mode (since due to the FIQ stuff it currently doesn't support gadget mode anyway); which saves people having to create another iteration of their CM host PCBs, or always using a custom-compiled kernel.

Well that's my best guess anyway ;-)

notro commented 8 years ago

The mainline dwc2 driver which does work on the Pi in host mode, has otg mode as well. Maybe worth trying. I haven't got an A or Zero so I can't try it myself.

This config change:

CONFIG_USB_DWC2=y

which also enables this:

CONFIG_USB_DWC2_HOST=y

coupled with this overlay

/dts-v1/;
/plugin/;

/{
    compatible = "brcm,bcm2835";

    fragment@0 {
        target = <&usb>;
        __overlay__ {
            compatible = "brcm,bcm2835-usb";
            reg = <0x7e980000 0x10000>;
            interrupts = <1 9>;
        };
    };
};

will switch to using the dwc2 driver in host mode.

Enabling CONFIG_USB_GADGET seems to be necessary to to enable otg mode in the dwc2 driver. From drivers/usb/dwc2/Kconfig:

choice
        bool "DWC2 Mode Selection"
        default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET)
        default USB_DWC2_HOST if (USB && !USB_GADGET)
        default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET)

The next step seems to be to set the dr_mode DT property to otg (see binding doc).

The reason we are currently using dwc_otg instead of dwc2, is that it can use a non-maskable fiq interrupt to increase throughput, but lowered throughput probably isn't such an issue in otg mode.

https://www.kernel.org/doc/Documentation/devicetree/bindings/usb/dwc2.txt http://lxr.free-electrons.com/source/drivers/usb/dwc2/

toddtreece commented 8 years ago

@notro thanks for the info!

i'm pretty new to working with device trees, but i thought i would give it a shot. i tried it with USB_DWC2_DUAL_ROLE enabled, but i am still not having any luck. i'm not sure what to use for the clocks parameter. this is the overlay i compiled and enabled:

/dts-v1/;
/plugin/;

/{
    compatible = "brcm,bcm2835";

    fragment@0 {
        target = <&usb>;
        #address-cells = <1>;
        #size-cells = <1>;
        __overlay__ {
            compatible = "brcm,bcm2835-usb";
            reg = <0x7e980000 0x10000>;
            interrupts = <1 9>;
            dr_mode = "otg";
            clocks = <&clk_core>;
            clock-names = "otg";
        };
    };
};

the pi would boot, but it won't show up on my OS X machine as a device.

notro commented 8 years ago

Do you get anything related to usb in the kernel log: dmesg

notro commented 8 years ago

You also need to enable the gadget drivers you want (I have never done this before): http://lxr.free-electrons.com/source/drivers/usb/gadget/Kconfig (also try enabling the debug options)

http://www.linux-usb.org/gadget/ https://www.kernel.org/doc/Documentation/usb/ (gadget_*.txt)

toddtreece commented 8 years ago

i think the issue is here:

Dec 16 20:27:16 raspberrypi kernel: [    2.022050] dwc2 20980000.usb: Mode Mismatch Interrupt: currently in Device mode

here's the full log from that boot: https://gist.github.com/toddtreece/88965370a4d84877edf7

ED6E0F17 commented 8 years ago

Thanks for the tip about device tree. The upstream driver seems to be working in host mode, but I get a warning about insufficient fifo memory.

dmesg.txt

notro commented 8 years ago

@ED6E0F17 you get the warning in otg mode, right? Enabling DEBUG will print the fifo sizes used. @P33M can probably tell if they're valid or not.

drivers/usb/dwc2/gadget.c#L3566

int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
{
...
    /* Dump fifo information */
    dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n",
                        hsotg->g_np_g_tx_fifo_sz);
    dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz);
    for (i = 0; i < MAX_EPS_CHANNELS; i++)
        dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i,
                        hsotg->g_tx_fifo_sz[i]);

A similar error on rockchip was solved like this: https://github.com/torvalds/linux/commit/ec32bd9fcadc26d8a184c9a09ec3fe29e097c175

ladyada commented 8 years ago

just poking in to say im gonna try compiling this too, cuz why not :) im working off of https://github.com/raspberrypi/linux/tree/rpi-4.4.y, will edit/post with whatever i find!

ladyada commented 8 years ago

@ED6E0F17 hey i tried just the default arch/arm/rpi_defconfig in the 4.4.0-rc5 branch and couldnt get the kernel to boot, just rainbowscreen. im compiling for the zero (BCM2708) and saw you're compiling for BCM2709 - but are you using the default defconfig?

ED6E0F17 commented 8 years ago

@notro - that looks like the right fix for fifo sizes. The warning occurs on loading the driver, but it is coming from the gadget driver.

@ladyada - I am working from a heavily modified config, but from defconfig you will need to enable the Upstream driver, and disable the Downstream driver, and also patch the device tree.

DT patch: patch.txt

My rpi-4.4 config: config.txt

notro commented 8 years ago

I have used otg mode on a B+ with some intrumentation to look at the fifo sizes. The board never comes fully up, but I do get the numbers. @P33M can you have a look?

[    0.000000] Linux version 4.4.0-rc5+ (pi@raspi2) (gcc version 4.8.3 20140106 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2014.01 - Linaro GCC 2013.11) ) #3 PREEMPT Fri Dec 18 20:36:34 CET 2015

[    2.359432] dwc2 20980000.usb: NonPeriodic TXFIFO size: 1024
[    2.365268] dwc2 20980000.usb: RXFIFO size: 2048
[    2.370075] dwc2 20980000.usb: Periodic TXFIFO 0 size: 0
[    2.375530] dwc2 20980000.usb: Periodic TXFIFO 1 size: 256
[    2.381208] dwc2 20980000.usb: Periodic TXFIFO 2 size: 256
[    2.386891] dwc2 20980000.usb: Periodic TXFIFO 3 size: 256
[    2.392518] dwc2 20980000.usb: Periodic TXFIFO 4 size: 256
[    2.398183] dwc2 20980000.usb: Periodic TXFIFO 5 size: 768
[    2.403813] dwc2 20980000.usb: Periodic TXFIFO 6 size: 768
[    2.409482] dwc2 20980000.usb: Periodic TXFIFO 7 size: 768
[    2.419758] dwc2 20980000.usb: Periodic TXFIFO 8 size: 768
[    2.430063] dwc2 20980000.usb: Periodic TXFIFO 9 size: 0
[    2.440137] dwc2 20980000.usb: Periodic TXFIFO10 size: 0
[    2.450151] dwc2 20980000.usb: Periodic TXFIFO11 size: 0
[    2.460074] dwc2 20980000.usb: Periodic TXFIFO12 size: 0
[    2.469798] dwc2 20980000.usb: Periodic TXFIFO13 size: 0
[    2.479572] dwc2 20980000.usb: Periodic TXFIFO14 size: 0
[    2.489276] dwc2 20980000.usb: Periodic TXFIFO15 size: 0
[    2.536754] dwc2 20980000.usb: resetting core
[    2.545373] dwc2 20980000.usb: reset successful

(the 4080 number is hsotg->fifo_mem)
[    2.554109] dwc2 20980000.usb: EPs: 8, dedicated fifos, 4080 entries in SPRAM
[    2.565613] dwc2 20980000.usb: GRXFSIZ=0x00001000, GNPTXFSIZ=0x00201000

[    2.576598] dwc2_hsotg_init_fifo(): hsotg->fifo_mem=4080 (0xff0)

(addr = hsotg->g_rx_fifo_sz + hsotg->g_np_g_tx_fifo_sz == 2048 + 1024 == 3072)

[    2.586691] addr=3072 (0xc00), hsotg->g_tx_fifo_sz[1]=256
[    2.596327] addr=3328 (0xd00), hsotg->g_tx_fifo_sz[2]=256
[    2.605928] addr=3584 (0xe00), hsotg->g_tx_fifo_sz[3]=256

[    2.615489] ------------[ cut here ]------------
[    2.624272] WARNING: CPU: 0 PID: 1 at drivers/usb/dwc2/gadget.c:215 dwc2_hsotg_init_fifo+0x1a8/0x23c()
[    2.637788] insufficient fifo memory
[    2.641291] Modules linked in:
[    2.652782] CPU: 0 PID: 1 Comm: swapper Not tainted 4.4.0-rc5+ #3
[    2.663120] Hardware name: BCM2708

[    2.733156] [<c045bea4>] (dwc2_hsotg_init_fifo) from [<c045bfe4>] (dwc2_hsotg_init+0xac/0x110)
[    2.746312] [<c045bfe4>] (dwc2_hsotg_init) from [<c045f91c>] (dwc2_gadget_init+0x3c0/0x890)
[    2.759225] [<c045f91c>] (dwc2_gadget_init) from [<c0451604>] (dwc2_driver_probe+0x254/0x2e4)
[    2.772314] [<c0451604>] (dwc2_driver_probe) from [<c03b3008>] (platform_drv_probe+0x44/0x7c)

[    2.944490] ---[ end trace bf843f4c4ca2ef38 ]---

[    2.954026] addr=3840 (0xf00), hsotg->g_tx_fifo_sz[4]=256
[    2.964436] addr=4096 (0x1000), hsotg->g_tx_fifo_sz[5]=768
[    2.974923] addr=4864 (0x1300), hsotg->g_tx_fifo_sz[6]=768
[    2.985261] addr=5632 (0x1600), hsotg->g_tx_fifo_sz[7]=768
[    2.995696] addr=6400 (0x1900), hsotg->g_tx_fifo_sz[8]=768
toddtreece commented 8 years ago

@notro i just realized i was tweaking bcmrpi_defconfig to test dwc2. should i be using bcm2835_defconfig?

notro commented 8 years ago

No, we're using bcmrpi_defconfig.

toddtreece commented 8 years ago

@notro ok. thanks

ED6E0F17 commented 8 years ago

@notro : I don`t know if the gadget fifos should sum to 1024 or 4096, but it is coming up in gadget mode on model A with this device tree : dtpatch.txt

I need to make up a cable before I test further.

notro commented 8 years ago

I don`t know if the gadget fifos should sum to 1024 or 4096

4080 it seeems.

The driver gets the number of entries here:

static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
{
    cfg = dwc2_readl(hsotg->regs + GHWCFG3);
    hsotg->fifo_mem = (cfg >> GHWCFG3_DFIFO_DEPTH_SHIFT);

    dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n",
         hsotg->num_of_eps,
         hsotg->dedicated_fifos ? "dedicated" : "shared",
         hsotg->fifo_mem);

which is 4080:

dwc2 20980000.usb: EPs: 8, dedicated fifos, 4080 entries in SPRAM

Set up hw fifos:

static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
{

    /* set RX/NPTX FIFO sizes */
    dwc2_writel(hsotg->g_rx_fifo_sz, hsotg->regs + GRXFSIZ);
    dwc2_writel((hsotg->g_rx_fifo_sz << FIFOSIZE_STARTADDR_SHIFT) |
        (hsotg->g_np_g_tx_fifo_sz << FIFOSIZE_DEPTH_SHIFT),
        hsotg->regs + GNPTXFSIZ);

    /* start at the end of the GNPTXFSIZ, rounded up */
    addr = hsotg->g_rx_fifo_sz + hsotg->g_np_g_tx_fifo_sz;

    /*
     * Configure fifos sizes from provided configuration and assign
     * them to endpoints dynamically according to maxpacket size value of
     * given endpoint.
     */
    for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) {
        if (!hsotg->g_tx_fifo_sz[ep])
            continue;
        val = addr;
        val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT;
        WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem,
              "insufficient fifo memory");
        addr += hsotg->g_tx_fifo_sz[ep];

        dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep));
    }

fifo_mem (4080) is used for the overflow check.

I found these numbers in the BCM2835 datasheet:

Total Data FIFO RAM Depth 4096

Largest Rx Data FIFO Depth 4096

Largest Non-periodic Tx Data FIFO Depth 4096

Largest Device Mode IN Endpoint Tx FIFOn Depth (n = 0 to 15) when using dynamic FIFO sizing
0=32
1..5=512
6,7=768
ED6E0F17 commented 8 years ago

With debug logging enabled I get two obvious errors: "cannot get otg clock", which is something that should be set in the device tree; and "dwc2_hsotg_complete_setup: failed -104"

log highlights:

debuglog.txt

Dave-0 commented 8 years ago

I've got this to work on a Pi Zero using ED6E0F17's device tree patch and selecting gadget only mode. I tried duel mode first but couldn't get that to work.

My kernel config is below:

config.txt

I'm using the serial gadget and I can run a terminal session over the connection. I've not done extensive testing but it seems stable. I'll post again when I've done more testing.

Dave-0 commented 8 years ago

One thing to add: I changed config.txt for my testing. This seems to be important because with the default raspbian one it hangs at "Uncompressing Linux... done, booting the kernel.".

config.txt

Dave-0 commented 8 years ago

I've tried this with dual mode again and got it to work this time, I must have made a mistake somewhere the first time. It switches between host and gadget mode correctly depending on the cable type.

martinbrook commented 8 years ago

Great, could you confirm which kernel branch you are using and which dt patch, I see two in the tread.

Dave-0 commented 8 years ago

@martinbrook: I'm using the 4.4.y branch and the dtpatch is this one.

ladyada commented 8 years ago

@ED6E0F17 @notro heya thanks for the help! turns out i was missing the mkknlimg step >.< got everything working and have a kernel with gaddet modules and a tutorial here https://learn.adafruit.com/turning-your-raspberry-pi-zero-into-a-usb-gadget/ i'll update the kernel-o-matic and make a set of .deb files for easier install some time later this week

merry xmas!

gbaman commented 8 years ago

@ED6E0F17 @notro Can also confirm have also been able to get this working, @Dave-0's post over on the forums was a great help too.

@ladyada Looks like I wasn't the only one working over Christmas Eve on this, my write is here.

Now over course, the big question is can we get this working with normal USB within the same kernels, without having to break it? Something like being able to enable/disable the mode from the cmdline.txt file? (not my idea, @ghollingworth's idea).
That would then mean, users could enable it from another computer by editing the fat32 partition, opening up a huge range of possibilities!

notro commented 8 years ago

I have a Zero now and got it working with g_serial. I'm trying g_multi and do get a usb drive, but the serial and ethernet device isn't supported by windows and since I got Windows 8, it won't install the unsigned Documentation/usb/linux-cdc-acm.inf and Documentation/usb/linux.inf "drivers". I need to reboot and disable this restraint, but have too many things running on my machine to just do a reboot now.

Regarding getting it to work with normal kernels, this isn't a problem, dwc2 and dwc_otg can coexist. We can use a Device Tree overlay to enable dwc2 instead of dwc_otg:

/dts-v1/;
/plugin/;

/{
    compatible = "brcm,bcm2708";

    fragment@0 {
        target = <&usb>;
        #address-cells = <1>;
        #size-cells = <1>;
        __overlay__ {
            compatible = "brcm,bcm2835-usb";
            reg = <0x7e980000 0x10000>;
            interrupts = <1 9>;
            dr_mode = "otg";
            g-np-tx-fifo-size = <32>;
            g-rx-fifo-size = <256>;
            g-tx-fifo-size = <256 128 128 64 64 64 32>;
        };
    };
};

dwc2 can probably be built as a module as well to save memory for those that don't use it.

But maybe an even better idea than an overlay is to give the Zero a dtb of it's own and make dwc2 the default. Currently it uses the B+ dtb:

~$ sudo vcdbg log msg
001289.085: Loading 'bcm2708-rpi-b-plus.dtb' from SD card

I haven't tried dwc2 in host mode on Zero yet, but it did work on B+. A DT overlay can be made to enable dwc_otg for those that need the extra performance.

Adding to this, Raspian could get a systemd service that when it detects that usb is in device/peripheral mode, loads the g_serial module and fires up a console on it.

This way we can just download a regular raspian image put it on the Zero, connect it to a computer and get a usb serial console. And if a keyboard is connected instead, the dwc2 driver acts in host mode as normal and no module is loaded (I wonder if hotswapping between device/host mode is supported by dwc2).

On top of this, raspi-config could have an option to enable loading of g_multi module instead and provide an usb drive that has the necessary signed inf files (Windows) to get serial and ethernet working at the same time.

tdicola commented 8 years ago

You might check out the Beaglebone Black's support repo too, here's where they have a systemd service that sets up the BBB as a USB device using g_multi: https://github.com/beagleboard/meta-beagleboard/tree/b5c709b2b6bd3bf236df923fa8f245a00fbb1b60/meta-beagleboard-extras/recipes-support/usb-gadget/gadget-init I haven't looked too deeply into it but it might be handy to do something similar on the Pi.

gbaman commented 8 years ago

Even on Mac OS I am getting issues with g_multi. Am getting mass storage and serial working fine, but not ethernet. So problems with it aren't just with Windows. I do though get all 3 working fine when connecting it to a Linux machine. With g_cdc am able to get ethernet and serial fine on both Mac OS and Linux, although again not on Windows.

@notro some interesting ideas, am inclined to agree with you about using dwc2 for both if we can get away with it, I doubt anyone will be attaching anything that requires a whole lot of performance to the Pi Zero, although having the option to solely use dwc_otg would be important.

Also, I have just been testing... I enabled the dwc2 for both both host and gadget. I then booted up the Pi zero and enabled g_ether. I am able to quite happily use a keyboard, then switch over the cable to one plugged into another computer and up pops my ethernet interface, then switch back again by physically unplugging one to the computer and replugging in the keyboard and keyboard works again? So, it looks like it can quite easily auto detect and switch automatically. So perhaps, no need for any fancy scripts, it looks like it may just work (famous last words).

ladyada commented 8 years ago

@gbaman funny, i didn't have time till today to wrap up the tutorial! while the kids are asleep the elves work on crafting kernel packages :) your writeup looks great

notro commented 8 years ago

while the kids are asleep the elves work on crafting kernel packages :)

Haha, yes the elves are working their best magic at night with it's peace and quiet :-) I'm sure that many with a Zero will be happy to have those kernels packages to play with for the Christmas holidays.

Thanks @tdicola I suspected those guys to have a good solution. This is the yocto repo version: http://git.yoctoproject.org/cgit/cgit.cgi/meta-ti/tree/recipes-ti/beagleboard/gadget-init Looks like they're using a dhcp server to provide the connected host with an ip address. I can't find anything for serial though.

The file I use for my backing store (g_multi) shows up here:

~$ cat /sys/devices/platform/soc/20980000.usb/gadget/lun0/file
/home/pi/fat32.img
~$ cat /sys/devices/platform/soc/20980000.usb/gadget/net/usb0/address
92:0c:4a:56:0f:2e

Maybe something somewhere in sysfs shows whether the controller is in host or peripheral mode.

@gbaman so hotswapping works, thats cool.

hh commented 8 years ago

Nice work everyone!

I was hoping to not use one big module, but to configure functions dynamically using libcomposite and configfs. I use the following on my Beagebone Black to dynamically decide what to use at runtime rather than precompile a monolithic gadget module:

From: https://github.com/ii/boot-scripts/blob/configfs/boot/am335x_evm.sh#L144

        modprobe libcomposite
        cd /sys/kernel/config/usb_gadget

        # New gagdet
        mkdir -p ii
        cd ii

        # http://pid.codes/1209/cafe/
        echo 0xCAFE > idProduct
        echo 0x1209 > idVendor
        mkdir -p strings/0x409
        echo 01 > strings/0x409/serialnumber
        echo ii > strings/0x409/manufacturer
        echo iiGadget > strings/0x409/product

        # our first config
        mkdir -p configs/c.1
        mkdir -p configs/c.1/strings/0x409
        echo "iiKeyboardDiskNet" > configs/c.1/strings/0x409/configuration
        echo 500 > configs/c.1/MaxPower

        # Undocumented but available via http://www.spinics.net/lists/linux-usb/msg110976.html

        #+c_chmask - capture channel mask
        #+c_srate - capture sampling rate
        #+c_ssize - capture sample size (bytes)
        #+p_chmask - playback channel mask
        #+p_srate - playback sampling rate
        #+p_ssize - playback sample size (bytes)
        mkdir -p functions/uac2.0
        ln -sf functions/uac2.0 configs/c.1

        # our first function, a hid device (keyboard, mouse, joystick)
        # should create /dev/hidg0
        mkdir -p functions/hid.usb0
        echo 1 > functions/hid.usb0/protocol
        echo 1 > functions/hid.usb0/subclass
        echo 8 > functions/hid.usb0/report_length
        echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc
        ln -sf functions/hid.usb0 configs/c.1

        # https://wiki.tizen.org/wiki/USB/Linux_USB_Layers/Configfs_Composite_Gadget/Usage_eq._to_g_serial.ko
        # on host 'screen /dev/ttyACM0 115200
        # on device... probably want to run at getty
        mkdir -p functions/acm.tty1 #ttyACMX / ttyGSX ?
        ln -sf functions/acm.tty1 configs/c.1

        # https://wiki.tizen.org/wiki/USB/Linux_USB_Layers/Configfs_Composite_Gadget/Usage_eq._to_g_mass_storage.ko
        mkdir -p functions/mass_storage.0
        echo /root/lun0.img > functions/mass_storage.0/lun.0/file
        mkdir -p functions/mass_storage.0/lun.1
        echo /root/lun1.img > functions/mass_storage.0/lun.1/file
        ln -sf functions/mass_storage.0 configs/c.1

        mkdir -p functions/ecm.0
        ln -sf functions/ecm.0 configs/c.1
        #mkdir -p functions/rndis.0
        #ln -sf functions/rndis.0 configs/c.1

        # # ls /sys/class/udc/ #=> musb-hdrc.0.auto
        echo musb-hdrc.0.auto > UDC

I have some more fully fleshed out versions with more features, but don't yet have access to a Pi Zero (waiting for them to get back in stock).

notro commented 8 years ago

Hot swapping does indeed work!

After boot without anything connected to the usb data connector:

sudo modprobe g_serial
sudo systemctl start getty@ttyGS0.service

Then I connect it to my computer and get a login screen and can log in (COM port shows up as: ELMO GMAS). Disconnect computer and connect a keyboard, working fine. Disconnect keyboard and connect computer, login screen waiting for me!

notro commented 8 years ago

Have anyone been able to do this on rpi-4.1.y? I get this error:

[    7.463269] dwc2 20980000.usb: no platform data or transceiver defined

I have made a proposal for rpi-4.4.y #1239

Dave-0 commented 8 years ago

@notro: I got the same error when I tried it. I think it needs something in the DTB for the USB PHY but I don't know what.

ED6E0F17 commented 8 years ago

This patch claims that we cannot change the gadget fifo sizes, and so need to read the preset values from the hardware, before setting the device tree values in linux-4.4:

https://www.spinics.net/lists/linux-usb/msg134539.html

NicoHood commented 8 years ago

I tried both tutorials. The one from @ladyada and the one from @gbaman (with a full image!). Both of the corrupt my sd card after rebooting with the new kernel. I get errors like this:

[   14.284755] mmc0: timeout waiting for hardware interrupt.
[   14.295918] mmc0: cmd op 18 arg 0x34268 flags 0xb5 - resp 00000900 00000000 00000000 00000000, err 0
[   14.310769] mmc0: data blocks 8 blksz 200 - err 0
[   14.321232] mmc0: stop op 12 arg 0x0 flags 0x95 - resp 00000000 00000000 00000000 00000000, err 0
[   14.335825] mmc0: =========== REGISTER DUMP ===========
[   14.346718] mmc0: SDCMD  0x00004052
[   14.355949] mmc0: SDARG  0x00034268
[   14.365073] mmc0: SDTOUT 0x017d7840
[   14.374172] mmc0: SDCDIV 0x00000006
[   14.383229] mmc0: SDRSP0 0x00000900
[   14.392172] mmc0: SDRSP1 0x00001269
[   14.401119] mmc0: SDRSP2 0xffffffff
[   14.409883] mmc0: SDRSP3 0x0002c01f
[   14.418726] mmc0: SDHSTS 0x00000080
[   14.427403] mmc0: SDVDD  0x00000001
[   14.436182] mmc0: SDEDM  0x00010801
[   14.444799] mmc0: SDHCFG 0x0000040e
[   14.453526] mmc0: SDHBCT 0x00000200
[   14.462065] mmc0: SDHBLC 0x00000008
[   14.470658] mmc0: ===========================================
[   14.481623] mmcblk0: error -110 transferring data, sector 213608, nr 8, cmd response 0x900, card status 0xb00

[...]

[   97.030895] 9ec0: dafb8800 dafb8800 dae87338 24590411 dafc9f2c dafc9ee0 c046f018 c046e308
[   97.045067] 9ee0: 00000000 daf613a0 dafc8000 00000000 dafc9f14 dafc9f00 c02fd414 daf85400
[   97.059296] 9f00: 00000000 dafb8804 dafc8000 00000000 24590411 00000001 dae87338 daf613a0
[   97.073589] 9f20: dafc9f64 dafc9f30 c0470b78 c046ef20 c0470a90 dafb880c 00000000 daf5b180
[   97.087946] 9f40: 00000000 dafb8804 c0470a90 00000000 00000000 00000000 dafc9fac dafc9f68
[   97.102268] 9f60: c003ff58 c0470a9c 00000000 00000000 c003fe78 dafb8804 00000000 dafc9f7c
[   97.116656] 9f80: dafc9f7c 00000000 dafc9f88 dafc9f88 daf5b180 c003fe78 00000000 00000000
[   97.131143] 9fa0: 00000000 dafc9fb0 c000f808 c003fe84 00000000 00000000 00000000 00000000
[   97.145787] 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[   97.160453] 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
[   97.175143] [<c047722c>] (bcm2835_sdhost_dumpregs) from [<c0478178>] (bcm2835_sdhost_finish_command+0x434/0x468)
[   97.191984] [<c0478178>] (bcm2835_sdhost_finish_command) from [<c0478ed0>] (bcm2835_sdhost_request+0x1d0/0x274)
[   97.208840] [<c0478ed0>] (bcm2835_sdhost_request) from [<c045d53c>] (__mmc_start_request+0x50/0xe0)
[   97.224726] [<c045d53c>] (__mmc_start_request) from [<c045d6cc>] (mmc_start_request+0x100/0x134)
[   97.240441] [<c045d6cc>] (mmc_start_request) from [<c045e648>] (mmc_start_req+0x300/0x450)
[   97.255640] [<c045e648>] (mmc_start_req) from [<c046e3d4>] (mmc_blk_issue_rw_rq+0xd8/0xc18)
[   97.270823] [<c046e3d4>] (mmc_blk_issue_rw_rq) from [<c046f018>] (mmc_blk_issue_rq+0x104/0x550)
[   97.286254] [<c046f018>] (mmc_blk_issue_rq) from [<c0470b78>] (mmc_queue_thread+0xe8/0x18c)
[   97.301245] [<c0470b78>] (mmc_queue_thread) from [<c003ff58>] (kthread+0xe0/0xfc)
[   97.315242] [<c003ff58>] (kthread) from [<c000f808>] (ret_from_fork+0x14/0x2c)
[   97.328950] Code: e1a00004 e59f22c4 ebffffc6 e59430d4 (e593c008) 
[   97.341783] ---[ end trace 4613cbd2c24ee84c ]---
[  138.934782] random: nonblocking pool is initialized

I had this before with my sd card (its too fast), but that seemed to be fixed with the current raspbian image. The new kernel however seems to break it again.

I did not get the chance to even load a module, so the new kernel itself just causes problems. I am willing to test and help, but I do not really know why this now happens with the other kernel.

pelwell commented 8 years ago

The latest rpi-update kernel uses the sdhost driver by default. A few people have reported problems with certain SD card varieties, and these are being investigated. What type of SD card do you have? Be as specific as you can.

Until this problem is resolved you can configure your Pi to use the old mmc driver by adding:

dtoverlay=mmc

to your config.txt.