写在前面
买了很多Linux开发板但是从来没有好好的进行过Linux开发(驱动,应用等)的系统学习。趁着暑假这几天的空闲,捡起一块来进行Linux的系统性学习,在这作为一个记录来记录学习过程和遇到的一些问题。
使用的开发板是旺仔的平地铲D1S开发板,使用芯片为全志Allwinner的F133B,提供的SDK的Linux版本为5.4。前期根据旺仔提供的教程进行开发学习。后续如果使用别的开发板也写在这里吧。
USB的RNDIS开发
RNDIS(Remote NDIS)是一种通过USB接口虚拟出以太网设备的技术,本质是TCP/IP over USB。它能让USB设备模拟成网卡,使Windows或Linux主机直接通过USB访问4G/5G网络,无需额外硬件。使用RNDIS的话就可以实现一根USB线替代网线,使用USB连接开发板和上位机就可以实现网络连接,进一步使用SSH,非常之方便。
D1S开发板的基础信息:
Linux Kernel : 5.4
UDC : 4100000.udc-controller
ConfigFS : /sys/kernel/config
Gadget : g1
Config : configs/b.1
ADB : FunctionFS + adbd
RNDIS : rndis.usb0
SSH Server : Dropbear
已经确认的内核配置:
CONFIG_USB_GADGET=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_RNDIS=y
并且没有使用传统 g_ether:
# CONFIG_USB_ETH is not set
# CONFIG_USB_ETH_RNDIS is not set
上述是D1S开发板的内核固件默认配置,对于其它的开发板,需要在内核编译前确认几项配置:
Device Drivers
-> USB support
-> USB Gadget Support
<*> USB Gadget functions configurable through configfs
[*] Ethernet Control Model (CDC ECM)
[*] RNDIS
也就是完整的设置组合为:
CONFIG_USB_SUPPORT=y
CONFIG_USB_GADGET=y
CONFIG_USB_LIBCOMPOSITE=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_ECM=y
CONFIG_USB_CONFIGFS_RNDIS=y
#再加上:
CONFIG_NET=y
#以及SOC的USB:
CONFIG_USB_xxx_UDC=y
这样在内核上就支持了,然后就是系统上的设置。 当然,也可以先验证一下内核的部分:
zcat /proc/config.gz | grep -E \
"CONFIG_USB_GADGET|CONFIG_USB_CONFIGFS|CONFIG_USB_CONFIGFS_RNDIS|CONFIG_USB_CONFIGFS_ECM"
确保:
CONFIG_USB_GADGET=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_ECM=y
随后:
ls /sys/class/udc/
应该有:
4100000.udc-controller
这里前面的数字不是那么重要,只要有这个控制器存在就行,然后后续开始后续的工作:
检查内核和UDC
首先查看内核配置:
zcat /proc/config.gz | grep -E \
"CONFIG_USB_GADGET|CONFIG_USB_CONFIGFS|CONFIG_USB_CONFIGFS_RNDIS|CONFIG_USB_CONFIGFS_F_FS|CONFIG_USB_ETH"
至少应该有:
CONFIG_USB_GADGET=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_RNDIS=y
如果未来还需要ADB的功能则需要:
CONFIG_USB_CONFIGFS_F_FS=y
最好不要有:
CONFIG_USB_ETH=y
CONFIG_USB_ETH_RNDIS=y
然后检查UDC:
ls /sys/class/udc/
会看到:
4100000.udc-controller
检查configfs:
mount | grep configfs
如果没有输出:
mount -t configfs none /sys/kernel/config
手动配置RNDIS
创建Gadget:
mkdir -p /sys/kernel/config/usb_gadget/g1
#创建之后
cd /sys/kernel/config/usb_gadget/g1
设置VID/PID
echo 0x1d6b > idVendor
echo 0x0105 > idProduct
保持device class默认
echo 0x00 > bDeviceClass
echo 0x00 > bDeviceSubClass
echo 0x00 > bDeviceProtocol
设置USB字符串
mkdir -p strings/0x409
echo "1587636487" > strings/0x409/serialnumber
echo "wangzai" > strings/0x409/manufacturer
echo "wangzai USB Ethernet" > strings/0x409/product
创建configuration
mkdir -p configs/b.1/strings/0x409
echo "RNDIS" > configs/b.1/strings/0x409/configuration
创建RNDIS function
mkdir -p functions/rndis.usb0
这时看到
using random self ethernet address
using random host ethernet address
是正常的,随后固定MAC
echo "02:00:00:00:00:01" > functions/rndis.usb0/dev_addr
echo "02:00:00:00:00:02" > functions/rndis.usb0/host_addr
配 Microsoft OS Descriptor
echo 1 > os_desc/use
echo 0xcd > os_desc/b_vendor_code
echo "MSFT100" > os_desc/qw_sign
echo "RNDIS" > functions/rndis.usb0/os_desc/interface.rndis/compatible_id
echo "5162001" > functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id
把 RNDIS 加入 configuration
ln -s functions/rndis.usb0 configs/b.1/rndis.usb0
再关联OS Descriptor:
ln -s configs/b.1 os_desc/b.1
最后绑定UDC(使用实际的USB)
echo 4100000.udc-controller > UDC
检查:
cat UDC
应该为:
4100000.udc-controller
随后开始配置usb0 首先查看接口:
ip link show usb0
应该有:
inet 192.168.7.2/24
link/ether 02:00:00:00:00:01
如果没有则配置:
ip addr flush dev usb0
ip addr add 192.168.7.2/24 dev usb0
ip link set usb0 up
然后回到查看接口,应该看到有ip地址
windows端操作
此时,用usb将上位机和开发板连接,设备管理器,网络适配器中应该看到:
Remote NDIS Compatible Device
打开网络设置
Win + R
ncpa.cpl
找到对应的 USB 以太网接口,IPv4 设置
IP:192.168.7.1
掩码:255.255.255.0
网关:留空
DNS:留空
然后进行Ping测试连通
ping 192.168.7.2
固化为开机自启动
首先创建
/etc/init.d/S100usrndis
执行:最好是串口执行:
cat > /etc/init.d/S100usrndis <<'EOF'
#!/bin/sh
GADGET="/sys/kernel/config/usb_gadget/g1"
CONFIG="${GADGET}/configs/b.1"
FUNC="${GADGET}/functions/rndis.usb0"
UDC_NAME="4100000.udc-controller"
start()
{
echo "Starting USB RNDIS..."
if ! grep -q " /sys/kernel/config configfs " /proc/mounts; then
mount -t configfs none /sys/kernel/config || return 1
fi
mkdir -p "${GADGET}"
echo 0x1d6b > "${GADGET}/idVendor"
echo 0x0105 > "${GADGET}/idProduct"
echo 0x00 > "${GADGET}/bDeviceClass"
echo 0x00 > "${GADGET}/bDeviceSubClass"
echo 0x00 > "${GADGET}/bDeviceProtocol"
mkdir -p "${GADGET}/strings/0x409"
echo "1587636487" > "${GADGET}/strings/0x409/serialnumber"
echo "wangzai" > "${GADGET}/strings/0x409/manufacturer"
echo "wangzai USB Ethernet" > "${GADGET}/strings/0x409/product"
mkdir -p "${CONFIG}/strings/0x409"
echo "RNDIS" > "${CONFIG}/strings/0x409/configuration"
mkdir -p "${FUNC}"
echo "02:00:00:00:00:01" > "${FUNC}/dev_addr"
echo "02:00:00:00:00:02" > "${FUNC}/host_addr"
echo 1 > "${GADGET}/os_desc/use"
echo 0xcd > "${GADGET}/os_desc/b_vendor_code"
echo "MSFT100" > "${GADGET}/os_desc/qw_sign"
echo "RNDIS" > "${FUNC}/os_desc/interface.rndis/compatible_id"
echo "5162001" > "${FUNC}/os_desc/interface.rndis/sub_compatible_id"
if [ ! -e "${CONFIG}/rndis.usb0" ]; then
ln -s "${FUNC}" "${CONFIG}/rndis.usb0"
fi
if [ ! -e "${GADGET}/os_desc/b.1" ]; then
ln -s "${CONFIG}" "${GADGET}/os_desc/b.1"
fi
echo "${UDC_NAME}" > "${GADGET}/UDC
sleep 1
ip addr flush dev usb0 2>/dev/null
ip addr add 192.168.7.2/24 dev usb0
ip link set usb0 up
echo "USB RNDIS started."
}
stop()
{
echo "Stopping USB RNDIS..."
if [ -e "${GADGET}/UDC" ]; then
echo "" > "${GADGET}/UDC" 2>/dev/null
fi
sleep 1
ip link set usb0 down 2>/dev/null
ip addr flush dev usb0 2>/dev/null
echo "USB RNDIS stopped."
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 2
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
EOF
写完后立即检查,因为串口粘贴容易丢字符:
grep -n "UDC" /etc/init.d/S100usrndis
正确的一行应该是:
echo "${UDC_NAME}" > "${GADGET}/UDC"
然后给文件以权限
chmod +x /etc/init.d/S100usrndis
检查语法
sh -n /etc/init.d/S100usrndis
手动启动脚本:
/etc/init.d/S100usrndis start
检查
cat /sys/kernel/config/usb_gadget/g1/UDC
ip addr show usb0
Windows上测试:
ping 192.168.7.2
参考资料
Linux内核程序的开发
Linux内核程序可以选择作为动态模块加载,这样每次编译内核程序不用替换开发板的内核固件,比较方便。
动态模块开发相关
首先要确保Linux的内核支持动态模块,主要确认的是Kernel Configuration里:
[*]Enable loadable module support
...
[*]Module unloading
将上述内容保存并编译后烧录新的固件到开发板中即可,目前使用的开发板默认配置是开启的。
Comments