Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
UVC ConfigFS Gadget configuration tool
#!/bin/sh
set -e
#set -x
CONFIGFS="/sys/kernel/config"
GADGET="$CONFIGFS/usb_gadget"
VID="0x0525"
PID="0xa4a2"
SERIAL="0123456789"
MANUF=$(hostname)
PRODUCT="UVC Gadget"
USBFILE=/root/usbstorage.img
BOARD=$(strings /proc/device-tree/model)
case $BOARD in
"Renesas Salvator-X board based on r8a7795 ES1.x")
UDC_USB2=e6590000.usb
UDC_USB3=ee020000.usb
UDC_ROLE2=/sys/devices/platform/soc/ee080200.usb-phy/role
UDC_ROLE2=/dev/null #Not needed - always peripheral
UDC_ROLE3=/sys/devices/platform/soc/ee020000.usb/role
UDC=$UDC_USB2
UDC_ROLE=$UDC_ROLE2
;;
"TI OMAP4 PandaBoard-ES")
UDC=`ls /sys/class/udc` # Should be musb-hdrc.0.auto
UDC_ROLE=/dev/null # Not needed - peripheral enabled
;;
*)
UDC=`ls /sys/class/udc` # will identify the 'first' UDC
UDC_ROLE=/dev/null # Not generic
;;
esac
echo "Detecting platform:"
echo " board : $BOARD"
echo " udc : $UDC"
create_msd() {
# Example usage:
# create_msd <target config> <function name> <image file>
# create_msd configs/c.1 mass_storage.0 /root/backing.img
CONFIG=$1
FUNCTION=$2
BACKING_STORE=$3
if [ ! -f $BACKING_STORE ]
then
echo "\tCreating backing file"
dd if=/dev/zero of=$BACKING_STORE bs=1M count=32 > /dev/null 2>&1
mkfs.ext4 $USBFILE > /dev/null 2>&1
echo "\tOK"
fi
echo "\tCreating MSD gadget functionality"
mkdir functions/$FUNCTION
echo 1 > functions/$FUNCTION/stall
echo $BACKING_STORE > functions/$FUNCTION/lun.0/file
echo 1 > functions/$FUNCTION/lun.0/removable
echo 0 > functions/$FUNCTION/lun.0/cdrom
ln -s functions/$FUNCTION configs/c.1
echo "\tOK"
}
delete_msd() {
# Example usage:
# delete_msd <target config> <function name>
# delete_msd config/c.1 uvc.0
CONFIG=$1
FUNCTION=$2
echo "Removing Mass Storage interface : $FUNCTION"
rm -f $CONFIG/$FUNCTION
rmdir functions/$FUNCTION
echo "OK"
}
create_uvc() {
# Example usage:
# create_uvc <target config> <function name>
# create_uvc config/c.1 uvc.0
CONFIG=$1
FUNCTION=$2
echo " Creating UVC gadget functionality : $FUNCTION"
mkdir functions/$FUNCTION
mkdir -p functions/$FUNCTION/streaming/uncompressed/u/360p
cat <<EOF > functions/$FUNCTION/streaming/uncompressed/u/360p/dwFrameInterval
666666
1000000
5000000
EOF
mkdir functions/$FUNCTION/streaming/header/h
cd functions/$FUNCTION/streaming/header/h
ln -s ../../uncompressed/u
cd ../../class/fs
ln -s ../../header/h
cd ../../class/hs
ln -s ../../header/h
cd ../../../control
mkdir header/h
ln -s header/h class/fs
ln -s header/h class/ss
cd ../../../
echo 2048 > functions/$FUNCTION/streaming_maxpacket
ln -s functions/$FUNCTION configs/c.1
}
delete_uvc() {
# Example usage:
# delete_uvc <target config> <function name>
# delete_uvc config/c.1 uvc.0
CONFIG=$1
FUNCTION=$2
echo " Deleting UVC gadget functionality : $FUNCTION"
rm $CONFIG/$FUNCTION
rm functions/$FUNCTION/control/class/*/h
rm functions/$FUNCTION/streaming/class/*/h
rm functions/$FUNCTION/streaming/header/h/u
rmdir functions/$FUNCTION/streaming/uncompressed/u/360p
rmdir functions/$FUNCTION/streaming/uncompressed/u
rmdir functions/$FUNCTION/streaming/header/h
rmdir functions/$FUNCTION/control/header/h
rmdir functions/$FUNCTION
}
case "$1" in
start)
echo "Creating the USB gadget"
#echo "Loading composite module"
#modprobe libcomposite
echo "Creating gadget directory g1"
mkdir -p $GADGET/g1
cd $GADGET/g1
if [ $? -ne 0 ]; then
echo "Error creating usb gadget in configfs"
exit 1;
else
echo "OK"
fi
echo "Setting Vendor and Product ID's"
echo $VID > idVendor
echo $PID > idProduct
echo "OK"
echo "Setting English strings"
mkdir -p strings/0x409
echo $SERIAL > strings/0x409/serialnumber
echo $MANUF > strings/0x409/manufacturer
echo $PRODUCT > strings/0x409/product
echo "OK"
echo "Creating Config"
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "Creating functions..."
#create_msd configs/c.1 mass_storage.0 $USBFILE
create_uvc configs/c.1 uvc.0
echo "OK"
echo "Binding USB Device Controller"
echo $UDC > UDC
echo peripheral > $UDC_ROLE
cat $UDC_ROLE
echo "OK"
;;
stop)
echo "Stopping the USB gadget"
set +e # Ignore all errors here on a best effort
cd $GADGET/g1
if [ $? -ne 0 ]; then
echo "Error: no configfs gadget found"
exit 1;
fi
echo "Unbinding USB Device Controller"
grep $UDC UDC && echo "" > UDC
echo "OK"
delete_uvc configs/c.1 uvc.0
#delete_msd configs/c.1 mass_storage.0
echo "Clearing English strings"
rmdir strings/0x409
echo "OK"
echo "Cleaning up configuration"
rmdir configs/c.1/strings/0x409
rmdir configs/c.1
echo "OK"
echo "Removing gadget directory"
cd $GADGET
rmdir g1
cd /
echo "OK"
#echo "Disable composite USB gadgets"
#modprobe -r libcomposite
#echo "OK"
;;
*)
echo "Usage : $0 {start|stop}"
esac
@ikester

This comment has been minimized.

Copy link

@ikester ikester commented Apr 26, 2020

Hi! I'm not sure if you've used this script recently.

I'm trying it now on a Pi Zero W with the latest version of Buster (Linux raspberrypi 4.19.97+ #1294 Thu Jan 30 13:10:54 GMT 2020 armv6l GNU/Linux) but I'm getting this error on the line that is doing echo $UDC > UDC, right after "Binding USB Device Controller":

echo: echo: I/O error

If I try writing to /sys/kernel/config/usb_gadget/g1/UDC manually (after creating the parent dir g1) as root I still get a permissions error.

I don't think the UVC device is getting configured completely. Any idea why this line may be failing with a recent version or Raspbian? Is that line absolutely necessary for the device to work?

@kbingham

This comment has been minimized.

Copy link
Owner Author

@kbingham kbingham commented Apr 26, 2020

Hi, I'm afraid I haven't used it at all lately, and I haven't used it on a raspberry pi - so it might have some differences.

I would like to see uvc-gadget working on the RPi0 though so I'd be keen to help you get this going, and I can try to bring up the UDC on my RPi0 too.

I believe binding is important, so I suspect if it's not allowing it to be bound, perhaps it's already bound to another gadget function?

@ikester

This comment has been minimized.

Copy link

@ikester ikester commented Apr 26, 2020

Thanks for the reply. I figured out that it wasn't binding because I was loading g_ether first. Once I removed that and connected to the Pi through WiFi I was able to get the script to create the ConfigFS and bind properly. However, I cannot get the uvc-gadget binaries to work. They start and bind to the device, but the buffers are not allocated and it doesn't register on the host.

If I use the old g_webcam driver (it's as simple as running sudo modprobe g_webcam, instead of the configfs approach) I'm able to get this binary to stream a synthetic pattern to a Mac:
https://github.com/wlhe/uvc-gadget

Using uvc-gadget -d

But that same application does not work with the configfs method. I suspect I might need to find some additional configuration/function values to create a proper tree for the RPi Zero.

@kbingham

This comment has been minimized.

Copy link
Owner Author

@kbingham kbingham commented Apr 26, 2020

Ah ok - so some progress. Indeed there are two methods to configure. The g_webcam is quite simple and doesn't allow much configuration, but shows that the device is functional. I'm sure I remember coding the uvc-gadget to detect and support the old g_webcam and still work - but we really did focus on the configfs route, so I wouldn't be surprised if the current uvc-gadget master only really works with configfs methods.

Have you got any logs that show the errors you experience? Perhaps worth moving to e-mail to help debug: - feel free to send details to kieran.bingham@ideasonboard.com, and I'll try to take a look during the week, or next.

@ikester

This comment has been minimized.

Copy link

@ikester ikester commented Apr 26, 2020

Thanks for offering to follow-up. That's very generous. I'll write you an email with some more detail. The upstream uvc-gadget only supports streaming from another video device to the virtual one (i.e. from /dev/video10 to /dev/video0). Since I'm trying to make a video loopback device, I'm trying to use some of the forks (like the one mentioned above) that include some patches and enhancements, like sending a test pattern.

Thanks again!

@johnelliott

This comment has been minimized.

Copy link

@johnelliott johnelliott commented May 4, 2020

@ikester I am also hoping to do the same thing with my pi zero w

@teafella

This comment has been minimized.

Copy link

@teafella teafella commented May 6, 2020

EDIT: Found this thread on the raspi forums. It appears discussion about this has moved there.

@Learner379

This comment has been minimized.

Copy link

@Learner379 Learner379 commented Jan 20, 2021

HI @kbingham @ikester,

I am also trying to configure my RK3399 board as a webcam gadget. I tried both g_webcam and configfs ways to create the gadget and am able to do so. But when I start streaming from the host side, uvc-gadget test application is being killed with below errors.

Log snippet:
uvc-gadget prints:130|console:/ # uvc_gadget -u /dev/video12 -v /dev/video10                    
V4L2 device is UVC Camera (046d:081b) on bus usb-xhci-hcd.12.auto-1
V4L2: Getting current format: YUYV 640x360
V4L2: Setting format to: YUYV 640x360
V4L2: Getting current format: YUYV 640x360
v4l2 open succeeded, file descriptor = 3
uvc_open:837
uvc device is dwc3-gadget on bus gadget
uvc open succeeded, file descriptor = 4
V4L2: Buffer 0 mapped at address 0xe8da6000.
V4L2: Buffer 1 mapped at address 0xe8d35000.
V4L2: 2 buffers allocated.
control request (req 86 cs 02)
control request (req 86 cs 02)
streaming request (req 87 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 81 cs 01)
control request (req 87 cs 02)
control request (req 82 cs 02)
control request (req 83 cs 02)
control request (req 84 cs 02)
control request (req 87 cs 02)
control request (req 84 cs 02)
control request (req 81 cs 02)
control request (req 81 cs 02)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 82 cs 01)
streaming request (req 83 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 81 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 82 cs 01)
streaming request (req 83 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 81 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 82 cs 01)
streaming request (req 83 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 81 cs 01)
streaming request (req 01 cs 02)
setting commit control, length = 26
UVC: 2 buffers allocated.
V4L2: Starting video stream.
UVC: Starting video stream.
UVC: Stopping video stream.
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 82 cs 01)
streaming request (req 83 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 81 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 82 cs 01)
streaming request (req 83 cs 01)
streaming request (req 01 cs 01)
setting probe control, length = 26
streaming request (req 81 cs 01)
streaming request (req 01 cs 02)
setting commit control, length = 26
UVC: 2 buffers allocated.
V4L2: Starting video stream.
UVC: Starting video stream.
select timeout
UVC: Stopping video stream.
console:/ #

dmesg errors:
console:/ # dmesg:
[  202.023545] VS request cancelled.
[  202.023561] VS request cancelled.
[  202.023567] VS request cancelled.
[  202.023573] VS request cancelled.
[  202.030850] dwc3 fe800000.dwc3: request 0000000000000000 was not queued to ep2in
[  202.030981] dwc3 fe800000.dwc3: request 0000000000000000 was not queued to ep2in
[  202.031177] dwc3 fe800000.dwc3: request 0000000000000000 was not queued to ep2in
[  202.031381] dwc3 fe800000.dwc3: request 0000000000000000 was not queued to ep2in

Any help would be greatly appreciated. Please let me know if you need any other information.

Thanks

@Gladsonba

This comment has been minimized.

Copy link

@Gladsonba Gladsonba commented Feb 26, 2021

Hello @kbingham,

We are using zynq Ultrascale + MPSoC with custom board.
Our board has 2 USB ports(Host 2.0 and device 3.0), 2 SDI(one input and another output).
Kernel version on board is 4.19.0 and In host PC 5.4.0-58-generic.
Final project according to customers requirement is Streaming 1080p video taking input from SDI and taking output from USB(device).
Currently We are trying with connecting C922 Pro Stream Webcam to USB(host) port.This creates /dev/video0 node.
Then modprobe g_webcam. This creates /dev/video1.
Using the application https://github.com/wlhe/uvc-gadget. At host side /dev/video0 is created.
And when I try to stream via logitech webcam to custom webcam. USB disconnection occurs at host side.
host

When I try to display using application such as guvcview, at the device side, getting below attached log.
I need some more input so that I canmove forward with this project.

Host side log :
376489.240082] usb 4-5: new SuperSpeed Gen 1 USB device number 90 using xhci_hcd
[376489.261079] usb 4-5: New USB device found, idVendor=1d6b, idProduct=0102, bcdDevice= 4.19
[376489.261081] usb 4-5: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[376489.261082] usb 4-5: Product: Webcam gadget
[376489.261083] usb 4-5: Manufacturer: Linux Foundation
[376489.282666] uvcvideo: Found UVC 1.00 device Webcam gadget (1d6b:0102)
[376489.294595] input: Webcam gadget: UVC Camera as /devices/pci0000:00/0000:00:14.0/usb4/4-5/4-5:1.0/input/input95
[376507.027915] usb 4-5: USB disconnect, device number 90
[12020.033391] uvcvideo: Failed to resubmit video URB (-19).
[12020.033396] uvcvideo: Failed to resubmit video URB (-19).
[12020.033397] uvcvideo: Failed to resubmit video URB (-19).
[12020.033399] uvcvideo: Failed to resubmit video URB (-19).
[12020.033401] uvcvideo: Failed to resubmit video URB (-19).
[12020.033403] xhci_hcd 0000:00:14.0: WARN Event TRB for slot 25 ep 4 with no TDs queued?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment