Skip to content

Instantly share code, notes, and snippets.

@azsde
Forked from Gadgetoid/README.md
Created February 20, 2023 09:35
Show Gist options
  • Save azsde/ae72a2799948c2ed968752c828fc389e to your computer and use it in GitHub Desktop.
Save azsde/ae72a2799948c2ed968752c828fc389e to your computer and use it in GitHub Desktop.
Raspberry Pi Zero / Windows 10 automatic RNDIS driver install for composite gadgets

Preface

I owe my very rapid learning journey in the world of ConfigFs to several key sources which aren't necessarily relevant to this result, but I feel deserve a mention anyway.

The Result

One of the biggest and most repeated issues with the Pi Zero and OTG USB is that a composite gadget including RNDIS Ethernet for Ethernet-over-USB support in Windows will not automatically install drivers and, furthermore, is a heinous pain to install drivers for. My original idea was to develop and sign drivers to solve this problem- I still plan to do that, because the solution presented here is a hack - but it turned out signing inf files is really waaay more complex than it has any right to be.

So, using the resources above, plus some others (probably) which I've forgotten, and lots, and lots and lots of trial and error I finally accidentally hit upon a method to trick Windows 10 - repeatably I believe - into installing RNDIS drivers for a composite gadget.

The Technique

The technique is ridiculously simple;

  • Set up an RNDIS gadget using a VID/PID of a known good device that's compatible with composite RNDIS
  • Set bDeviceClass and bDeviceSubClass to 0x02 for a valid gadget
  • Set up the "os_desc" node with Windows magic (I don't think this is 100% necessary, but voodoo is voodoo!
  • Link only the RNDIS function to the config
  • Attach the USB gaget to the device
  • Wait some time for Windows to detect/install drivers- 5sec seems plenty as it happens, some experimentation required here
  • Detach the USB gadget
  • Link the rest of your functions- Mass Storage, Serial ACM, etc ( So far only tested with these )
  • Set bDeviceClass to 0x00
  • Re-attach the USB gadget
  • Now it should show up - in Windows 10 at least - as a composite gadget with functional RNDIS, Serial and Mass Storage. Yay!

Changelog

2017-11-05 - 00:26 - Tweaked to better support OSX. Still no RNDIS funcionality in 10.12, but Mass Storage and Serial seem to work

#!/bin/bash
# TODO: Figure out how to get ECM to work here
# without breaking Windows support
# Currently OSX supports Mass Storage + Serial but *not* RNDIS (at least not 10.12 anyway)
# Windows 10 and Linux seem to support everything
# Windows 8, 7 and below are untested
if [ ! -d /sys/kernel/config/usb_gadget ]; then
modprobe libcomposite
fi
if [ -d /sys/kernel/config/usb_gadget/g1 ]; then
exit 0
fi
ID_VENDOR="0x1d6b"
ID_PRODUCT="0x0104"
SERIAL="$(grep Serial /proc/cpuinfo | sed 's/Serial\s*: 0000\(\w*\)/\1/')"
MAC="$(echo ${SERIAL} | sed 's/\(\w\w\)/:\1/g' | cut -b 2-)"
MAC_HOST="12$(echo ${MAC} | cut -b 3-)"
MAC_DEV="02$(echo ${MAC} | cut -b 3-)"
cd /sys/kernel/config/usb_gadget/
mkdir g1
cd g1
echo "0x0200" > bcdUSB
echo "0x02" > bDeviceClass
echo "0x00" > bDeviceSubClass
echo "0x3066" > bcdDevice
echo $ID_VENDOR > idVendor
echo $ID_PRODUCT > idProduct
# Windows extensions to force config
echo "1" > os_desc/use
echo "0xcd" > os_desc/b_vendor_code
echo "MSFT100" > os_desc/qw_sign
mkdir strings/0x409
echo "9112473" > strings/0x409/serialnumber
echo "Pimoroni Ltd." > strings/0x409/manufacturer
echo "PiratePython" > strings/0x409/product
# Config #1 for OSX / Linux
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "CDC 2xACM+Mass Storage+RNDIS" > configs/c.1/strings/0x409/configuration
mkdir functions/acm.GS0
mkdir functions/acm.GS1
#mkdir functions/ecm.usb0 # OSX/Linux
mkdir functions/rndis.usb0 # Flippin' Windows
mkdir functions/mass_storage.piratepython
echo "/dev/mmcblk0p1" > functions/mass_storage.piratepython/lun.0/file
echo 0 > functions/mass_storage.piratepython/stall
echo 0 > functions/mass_storage.piratepython/lun.0/cdrom
echo 0 > functions/mass_storage.piratepython/lun.0/nofua
echo 1 > functions/mass_storage.piratepython/lun.0/removable
echo "PiratePython" > functions/mass_storage.piratepython/lun.0/inquiry_string
echo "RNDIS" > functions/rndis.usb0/os_desc/interface.rndis/compatible_id
echo "5162001" > functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id
echo $MAC_HOST > functions/rndis.usb0/host_addr
echo $MAC_DEV > functions/rndis.usb0/dev_addr
# Set up the rndis device only first
ln -s functions/rndis.usb0 configs/c.1
# Tell Windows to use config #2
ln -s configs/c.1 os_desc
# Show Windows the RNDIS device with
# bDeviceClass 0x02
# bDeviceSubClass 0x02
echo "20980000.usb" > UDC
# Give it time to install
sleep 5
# Yank it back
echo "" > UDC
# Sneak in all the extra goodies
ln -s functions/acm.GS0 configs/c.1
ln -s functions/acm.GS1 configs/c.1
ln -s functions/mass_storage.piratepython configs/c.1
# Reset bDeviceClass to 0x00
# This is essential to make it work in Windows 10
# Basically forces it to use device information
# in the descriptors versus assuming a particular class.
echo "0x00" > bDeviceClass
# Re-attach the gadget
echo "20980000.usb" > UDC
# BOOM!
ifconfig usb0 up 10.0.99.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment