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
11.01k stars 4.95k forks source link

Libcomposite's g_ether + g_webcam on Buster Lite, Stretch Lite and Jessie Lite in Pi Zero W do not work #3965

Open jasonmnemonic opened 3 years ago

jasonmnemonic commented 3 years ago

Hi.

I am quite new to this reporting but can help to investigate. I believe this is a kernel bug and not sure has this ever worked before. I am not sure if this is related to https://github.com/raspberrypi/linux/issues/3862 or/and https://github.com/raspberrypi/linux/issues/2076. I can try to help resolve or fix it as a team if I could get guidance on this.

So, I have a Pi Zero W with a Pi Camera. I have been looking at making the Pi as a UVC gadget using https://github.com/climberhunt/uvc-gadget and with ConfigFS or g_webcam non-modular approach (not sure what is this method called) but I mostly experiment and use ConfigFS method.

I have also read about the possibility of configuring gadgets on Linux kernel where I can make multi-gadgets device so I can make USB webcam + storage or RNDIS ethernet + storage but not webcam + RNDIS ethernet on the Pi Zero W with all the lite OS. So here is the matrix of what is successful on the Zero W and libcomposite.

When it fails, what I get is, on Windows 10, I can ping the Pi via USB cable ethernet and that part works. Device Manager sees no errors (no exclamations) for UVC Camera and RNDIS Network Adapter entries. When using the Win10 Camera App to stream, I get this error (something like this): 0xa00f4271 (0x800703e3)

Then I look at the Pi logs and see something like below:

configfs-gadget gadget: uvc_function_bind dwc2 20980000.usb: bound driver configfs-gadget IPv6: ADDRCONF(NETDEV_UP): usb0: link is not ready dwc2 20980000.usb: new device is high-speed dwc2 20980000.usb: new device is high-speed dwc2 20980000.usb: new address 1 configfs-gadget gadget: high-speed config #1: c configfs-gadget gadget: uvc_function_set_alt(2, 0) configfs-gadget gadget: reset UVC Control configfs-gadget gadget: uvc_function_set_alt(3, 0) IPv6: ADDRCONF(NETDEV_CHANGE): usb0: link becomes ready configfs-gadget gadget: uvc_function_set_alt(3, 0) configfs-gadget gadget: uvc_function_set_alt(3, 0) dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep ceadd390 ep0, 1) dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep ceadd390 ep0, 1) random: crng init done dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep ceadd390 ep0, 1) dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep ceadd390 ep0, 1) dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep ceadd390 ep0, 1) dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep ceadd390 ep0, 1) Bluetooth: Core ver 2.22

The dwc2_hsotg_ep_sethalt is where I am stuck and currently my path on this trail.

I have tried with all of these Raspberry Pi OSes.

and I get same behaviour. Standalone USB webcam, it works but anything webcam with RNDIS ethernet gadget fails.

Help please, anyone?

Thank you! :-)

tuyenld commented 3 years ago

@jasonmnemonic I have same issue on Window 7.

Does the Pi Zero W OTG ever worked for USB webcam + RNDIS ethernet?

I tested, it works on Linux but not work on Window.

Mario Cao commentd on StackOverflow

The RNDIS IAD interface must be the first and second of the composite device. Although the problem is solved, it still puzzles me.

If I installed UVC, then RNDIS > only UVC works, can't start RNDIS (code 10) If I installed RNDIS, then UVC -> only RNDIS works, camera application shows nothing.

jasonmnemonic commented 3 years ago

@tuyenld Hi Tuyen, thanks for the reply.

Correct me if I am wrong; I assume your test on Linux works which is for either UVC then RNDIS, or RNDIS then UVC? And it is just Windows that is having issue.

Out of interest, on Mario Cao's comment, he said to

The RNDIS IAD interface must be the first and second of the composite device.

How does one do that in ConfigFS? I think I may have done this but just counter-checking. Do you repeat the same thing twice? It is because, I cannot see how copy and paste the same config twice will not lead to other errors unless you copy and paste twice where the second one uses C.2? If you understand, could you please clarify with an example? I think if one were to do the same as Mario's suggestion, they will experience what we experience as well that is RNDIS and UVC working but camera does not upstream.

I have found some other ConfigFS which I think I used that form where RNDIS is C.1 and then add os_desc which is that second config. When I do that, I get this case

If I installed RNDIS, then UVC -> only RNDIS works, camera application shows nothing.

tuyenld commented 3 years ago

Hi @jasonmnemonic I am working on showmewebcam which used uvc-gadget.

Here is my working config on Linux, I used single configuration (i.e. only c.1)

# cat /opt/uvc-webcam/multi-gadget.sh 
#!/bin/sh
#
# Thank to 
#   wismna: http://github.com/wismna/raspberry-pi/hackpi
#   RoganDawes: https://github.com/RoganDawes/P4wnP1

# https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/enumeration-of-the-composite-parent-device
# https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-common-class-generic-parent-driver

# OS="$1"
OS_CONFIG="Linux"
MAC_HOST="48:6f:73:74:50:43" # "Mac address for host PC"
MAC_SELF="42:61:64:55:53:42" # "MAC address for PiCam"
CONFIG=/sys/kernel/config/usb_gadget/piwebcam

mkdir -p "$CONFIG"
cd "$CONFIG" || exit 1

# 0x04b3 = 1203
# {
#     "name": "IBM Corporation",
#     "field_vid": "1203"
# },
OS_CONFIG=$(echo $OS_CONFIG | tr '[A-Z]' '[a-z]')
case $OS_CONFIG in
  window)
    # wismna hack for Window
    # IBM Corporation RNDIS Driver will be loaded
    echo 0x04b3 > idVendor
    echo 0x4010 > idProduct
    ;;
  *)
    echo 0x1d6b > idVendor   # Linux Foundation
    echo 0x0104 > idProduct  # Multifunction Composite Gadget
    ;;

esac

echo 0x0100 > bcdDevice
echo 0x0200 > bcdUSB

# Mandatory for Multiple Gadgets 
echo 0xEF > bDeviceClass
echo 0x02 > bDeviceSubClass
echo 0x01 > bDeviceProtocol
echo 0x40 > bMaxPacketSize0

mkdir -p strings/0x409
mkdir -p configs/c.1/strings/0x409
echo 100000000d2386db         > strings/0x409/serialnumber
echo "Show-me Webcam Project" > strings/0x409/manufacturer
echo "Piwebcam "              > strings/0x409/product
echo 250                      > configs/c.1/MaxPower
echo "Piwebcam"               > configs/c.1/strings/0x409/configuration

config_frame () {
  FORMAT=$1
  NAME=$2
  WIDTH=$3
  HEIGHT=$4

  FRAMEDIR="functions/uvc.usb0/streaming/$FORMAT/$NAME/${HEIGHT}p"

  mkdir -p "$FRAMEDIR"

  echo "$WIDTH"                    > "$FRAMEDIR"/wWidth
  echo "$HEIGHT"                   > "$FRAMEDIR"/wHeight
  echo 333333                      > "$FRAMEDIR"/dwDefaultFrameInterval
  echo $(($WIDTH * $HEIGHT * 80))  > "$FRAMEDIR"/dwMinBitRate
  echo $(($WIDTH * $HEIGHT * 160)) > "$FRAMEDIR"/dwMaxBitRate
  echo $(($WIDTH * $HEIGHT * 2))   > "$FRAMEDIR"/dwMaxVideoFrameBufferSize
  cat <<EOF > "$FRAMEDIR"/dwFrameInterval
333333
400000
666666
EOF
}

config_uvc () {
  mkdir -p functions/uvc.usb0/control/header/h

  config_frame mjpeg m  640  360
  config_frame mjpeg m  640  480
  config_frame mjpeg m  800  600
  config_frame mjpeg m 1024  768
  config_frame mjpeg m 1280  720
  config_frame mjpeg m 1280  960
  config_frame mjpeg m 1440 1080
  config_frame mjpeg m 1536  864
  config_frame mjpeg m 1600  900
  config_frame mjpeg m 1600 1200
  config_frame mjpeg m 1920 1080

  mkdir -p functions/uvc.usb0/streaming/header/h
  ln -s functions/uvc.usb0/streaming/mjpeg/m  functions/uvc.usb0/streaming/header/h
  ln -s functions/uvc.usb0/streaming/header/h functions/uvc.usb0/streaming/class/fs
  ln -s functions/uvc.usb0/streaming/header/h functions/uvc.usb0/streaming/class/hs
  ln -s functions/uvc.usb0/control/header/h   functions/uvc.usb0/control/class/fs

  ln -s functions/uvc.usb0 configs/c.1/uvc.usb0
}

config_acm(){
  mkdir -p functions/acm.usb0
  ln -s functions/acm.usb0 configs/c.1/acm.usb0
}

# Ethernet Adapter
#-------------------------------------------
config_rndis () {
  mkdir -p functions/rndis.usb0
  echo $MAC_HOST > functions/rndis.usb0/host_addr
  echo $MAC_SELF > functions/rndis.usb0/dev_addr

  mkdir -p os_desc
  echo "0x80"     > configs/c.1/bmAttributes
  echo "1"        > os_desc/use
  echo "0xbc"     > os_desc/b_vendor_code
  echo "MSFT100"  > os_desc/qw_sign

  mkdir -p functions/rndis.usb0/os_desc/interface.rndis
  echo "RNDIS"    > functions/rndis.usb0/os_desc/interface.rndis/compatible_id
  echo "5162001"  > functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id

  ln -s functions/rndis.usb0 configs/c.1/
  ln -s configs/c.1/ os_desc
}

config_ecm () {
  mkdir -p functions/ecm.usb0
  echo $MAC_HOST > functions/ecm.usb0/host_addr
  echo $MAC_SELF > functions/ecm.usb0/dev_addr
  ln -s functions/ecm.usb0 configs/c.1/
}

config_uvc
case $OS_CONFIG in
  window)
    config_rndis
    ;;
  linux)
    config_rndis
    ;;
  macos)
    config_ecm
    ;;
  *)
    ;;
esac

config_acm

udevadm settle -t 5 || :
ls /sys/class/udc > UDC

case $OS_CONFIG in
  window | linux | macos)
    ifconfig usb0 10.0.0.1 netmask 255.255.255.252 up
    ;;
  *)
    ;;
esac

Proof: image

To use on Window, I change

OS_CONFIG="Window"

If I installed UVC, then RNDIS > only UVC works, can't start RNDIS (code 10) If I installed RNDIS, then UVC -> only RNDIS works, camera application shows nothing.

The order installation I mentioned are these lines:

config_uvc
case $OS_CONFIG in
  window)
    config_rndis
    ;;
  linux)
    config_rndis
    ;;
  macos)
    config_ecm
    ;;
  *)
    ;;
esac

config_acm

According to Microsoft

The bus driver also reports a compatible identifier (ID) of USB\COMPOSITE, if the device meets the following requirements:

  • The device class field of the device descriptor (bDeviceClass) must contain a value of zero, or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol) fields of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively, as explained in USB Interface Association Descriptor.
  • The device must have multiple interfaces.
  • The device must have a single configuration.

So, I don't think multiple configurations will work.

tuyenld commented 3 years ago

I don't have MacOs to test, but it seems MacOs has no built-in RNDIS support.

jasonmnemonic commented 3 years ago

@tuyenld thanks for getting back to me and the fast reply. Sorry that I did not manage to reply sooner. I wanted to but real-world got to me :-(

Anyway, my ConfigFS is similarly to yours, just that I have RNDIS first then UVC and like you no Device Manager errors but no streaming. The alternative is the Code10 error on the RNDIS driver. Interestingly, you mentioned it works in Linux with both UVC and RNDIS which I assume the order matters not.

The bus driver also reports a compatible identifier (ID) of USB\COMPOSITE, if the device meets the following requirements:

  • The device class field of the device descriptor (bDeviceClass) must contain a value of zero, or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol) fields of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively, as explained in USB Interface Association Descriptor.
  • The device must have multiple interfaces.
  • The device must have a single configuration.

So, I don't think multiple configurations will work.

This part I sort of understand (not entirely as I am lost at the multiple interfaces as I cannot mapped to what an interface is in ConfigFS); basically Windows only support C.1 configuration and nothing else. So no C.2 and above. Having said that, I think I just answered my own question about what is an interface but still in a confused state; see below.

The part of Mario Cao at Stackoverflow when he mentions the first and second interfaces to be loaded must be the RNDIS; I think this is the:

ln -s functions/rndis.usb0 configs/c.1/ ln -s configs/c.1/os_desc

My understanding is as follows; not sure how those interfaces are RNDIS IADs but maybe they come in pairs? The first configures the RNDIS device and the second allows Win10 to help install the correct plug and play driver to avoid Code10.

My conclusion on Mac is like yours (I have not tested it) but Mac only does ECM, Linux does both(?) and Windows only RNDIS.

If I got any above wrong, please correct me so we do not confused anyone else.

It could be a bug with libcomposite since it works in Linux and not Windows or a different bug in libcomposite's UVC since the uvc-gadget is just a different app that does upstreaming from one video source to another video sink. But this is just my guess.