1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
18903: pkg/tinyusb: add tinyUSB netdev driver r=dylad a=gschorcht

### Contribution description

This PR adds the tinyUSB netdev driver.

The tinyUSB netdev driver is part of the tinyUSB package and is enabled by module `tinyusb_netdev`. It is available for boards that provide the `tinyusb_device` feature.

**Please note** Since the tinyUSB package is distinct from (and incompatible with) the USB stack provided around USBUS in RIOT (see USB), the tinyUSB netdev driver cannot be used together with with any USBUS device class.

The tinyUSB netdev driver uses Ethernet over USB and supports the following protocols:
- CDC ECM (Ethernet Control Model)
- CDC NCM (Network Control Model)
- RNDIS (Microsoft Remote NDIS)

While Linux and macOS support all these protocols, Microsoft Windows only supports the RNDIS protocol and since Windows version 11 also the CDC NCM protocol. macOS supports the RNDIS protocol since version 10.15 (Catalina).

Which protocol is used is selected by the corresponding pseudomodules `tinyusb_class_net_cdc_ecm`, `tinyusb_class_net_cdc_ncm` and `tinyusb_class_net_rndis`.

The CDC ECM protocol (`tinyusb_class_net_cdc_ecm`) and the RNDIS protocol (`tinyusb_class_net_rndis`) can be used simultaneously to support all operating systems, for example :
```
USEMODULE='tinyusb_netdev tinyusb_class_net_rndis tinyusb_class_net_cdc_ecm' \
BOARD=... make -C ... flash
 ```
In this case, the CDC ECM protocol is the default protocol and the RNDIS protocol the alternative protocol defined as second device configuration. The CDC NCM protocol cannot be used together with the CDC ECM or the RNDIS protocol.

This PR includes PR #18983 for now to be compilable. 

Comparison with USBUS CDC ECM (`nucleo-f767zi` board):
```
   text	   data	    bss	    dec	    hex	filename
  65916	    596	  18728	  85240	  14cf8	tests_pkg_tinyusb_netdev.elf
```
```
   text	   data	    bss	    dec	    hex	filename
  63120	    544	  15444	  79108	  13504	tests_usbus_cdc_ecm.elf

```

### Testing procedure

Use a board that is supported by tinyUSB. Compile and flash the test application for each protocol:

1. RNDIS
    ```
    BOARD=... make -j8 -C tests/pkg_tinyusb_netdev flash
    ```
2. CDC ECM
    ```
    CLASS=tinyusb_class_net_cdc_ecm BOARD=... make -j8 -C tests/pkg_tinyusb_netdev flash
    ```
3. CDC NCM
    ```
    CLASS=tinyusb_class_net_cdc_ncm BOARD=... make -j8 -C tests/pkg_tinyusb_netdev flash
    ```
For each test, a network interface should be added on the host. Use command `ifconfig` on USB device and on the host and check that both have a link local address. In syslog there should be an output like the following:
<details>

```
Nov 13 18:14:46 gunny8 kernel: [4611465.480025] usb 1-2.2: new full-speed USB device number 28 using xhci_hcd
Nov 13 18:14:47 gunny8 kernel: [4611465.581641] usb 1-2.2: New USB device found, idVendor=1209, idProduct=7d01, bcdDevice= 1.00
Nov 13 18:14:47 gunny8 kernel: [4611465.581646] usb 1-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Nov 13 18:14:47 gunny8 kernel: [4611465.581650] usb 1-2.2: Product: nucleo-f767zi
Nov 13 18:14:47 gunny8 kernel: [4611465.581653] usb 1-2.2: Manufacturer: RIOT-os.org
Nov 13 18:14:47 gunny8 kernel: [4611465.581654] usb 1-2.2: SerialNumber: 6591620BCB270283
Nov 13 18:14:47 gunny8 vmnetBridge: RTM_NEWLINK: name:usb0 index:508 flags:0x00001002
Nov 13 18:14:47 gunny8 vmnet-natd: RTM_NEWLINK: name:usb0 index:508 flags:0x00001002
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.1066] manager: (usb0): new Ethernet device (/org/freedesktop/NetworkManager/Devices/528)
Nov 13 18:14:47 gunny8 kernel: [4611465.594604] rndis_host 1-2.2:1.0 usb0: register 'rndis_host' at usb-0000:00:14.0-2.2, RNDIS device, fa:db:7c:1b:58:80
Nov 13 18:14:47 gunny8 mtp-probe: checking bus 1, device 28: "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2"
Nov 13 18:14:47 gunny8 mtp-probe: bus: 1, device: 28 was not an MTP device
Nov 13 18:14:47 gunny8 systemd-udevd[17796]: link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.
Nov 13 18:14:47 gunny8 vmnet-natd: RTM_NEWLINK: name:usb0 index:508 flags:0x00001002
Nov 13 18:14:47 gunny8 kernel: [4611465.643852] rndis_host 1-2.2:1.0 enp0s20f0u2u2: renamed from usb0
Nov 13 18:14:47 gunny8 vmnetBridge: RTM_NEWLINK: name:usb0 index:508 flags:0x00001002
Nov 13 18:14:47 gunny8 vmnet-natd: RTM_NEWLINK: name:enp0s20f0u2u2 index:508 flags:0x00001002
Nov 13 18:14:47 gunny8 vmnetBridge: RTM_NEWLINK: name:enp0s20f0u2u2 index:508 flags:0x00001002
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.1833] device (usb0): interface index 508 renamed iface from 'usb0' to 'enp0s20f0u2u2'
Nov 13 18:14:47 gunny8 upowerd[2845]: unhandled action 'bind' on /sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2/1-2.2:1.1
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2037] device (enp0s20f0u2u2): state change: unmanaged -> unavailable (reason 'managed', sys-iface-state: 'external')
Nov 13 18:14:47 gunny8 vmnet-natd: RTM_NEWLINK: name:enp0s20f0u2u2 index:508 flags:0x00011043
Nov 13 18:14:47 gunny8 vmnetBridge: RTM_NEWLINK: name:enp0s20f0u2u2 index:508 flags:0x00011043
Nov 13 18:14:47 gunny8 vmnetBridge: Adding interface enp0s20f0u2u2 index:508
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2075] device (enp0s20f0u2u2): carrier: link connected
Nov 13 18:14:47 gunny8 upowerd[2845]: unhandled action 'bind' on /sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2/1-2.2:1.0
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2129] settings: (enp0s20f0u2u2): created default wired connection 'Kabelgebundene Verbindung 2'
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <warn>  [1668359687.2142] device (enp0s20f0u2u2): connectivity: "/proc/sys/net/ipv4/conf/enp0s20f0u2u2/rp_filter" is set to "1". This might break connectivity checking for IPv4 on this device
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2151] device (enp0s20f0u2u2): state change: unavailable -> disconnected (reason 'none', sys-iface-state: 'managed')
Nov 13 18:14:47 gunny8 vmnetBridge: RTM_NEWLINK: name:enp0s20f0u2u2 index:508 flags:0x00011043
Nov 13 18:14:47 gunny8 vmnet-natd: RTM_NEWLINK: name:enp0s20f0u2u2 index:508 flags:0x00011043
Nov 13 18:14:47 gunny8 upowerd[2845]: unhandled action 'bind' on /sys/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2
Nov 13 18:14:47 gunny8 systemd-udevd[17796]: link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2403] policy: auto-activating connection 'Kabelgebundene Verbindung 2' (0b1ae45e-c76e-3efb-a2cd-138ca2b2a59c)
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2414] device (enp0s20f0u2u2): Activation: starting connection 'Kabelgebundene Verbindung 2' (0b1ae45e-c76e-3efb-a2cd-138ca2b2a59c)
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2419] device (enp0s20f0u2u2): state change: disconnected -> prepare (reason 'none', sys-iface-state: 'managed')
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2429] device (enp0s20f0u2u2): state change: prepare -> config (reason 'none', sys-iface-state: 'managed')
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2440] device (enp0s20f0u2u2): state change: config -> ip-config (reason 'none', sys-iface-state: 'managed')
Nov 13 18:14:47 gunny8 NetworkManager[24229]: <info>  [1668359687.2445] dhcp4 (enp0s20f0u2u2): activation: beginning transaction (timeout in 45 seconds)
Nov 13 18:14:47 gunny8 vmnetBridge: RTM_NEWLINK: name:enp0s20f0u2u2 index:508 flags:0x00011043
Nov 13 18:14:47 gunny8 vmnet-natd: RTM_NEWLINK: name:enp0s20f0u2u2 index:508 flags:0x00011043
Nov 13 18:14:47 gunny8 avahi-daemon[1464]: Joining mDNS multicast group on interface enp0s20f0u2u2.IPv6 with address fe80::dba4:adb8:9ffe:d93e.
Nov 13 18:14:47 gunny8 avahi-daemon[1464]: New relevant interface enp0s20f0u2u2.IPv6 for mDNS.
Nov 13 18:14:47 gunny8 avahi-daemon[1464]: Registering new address record for fe80::dba4:adb8:9ffe:d93e on enp0s20f0u2u2.*.
Nov 13 18:14:47 gunny8 kernel: [4611465.895046] userif-1: sent link down event.
Nov 13 18:14:47 gunny8 kernel: [4611465.895052] userif-1: sent link up event.
```

</details>

Ping from and to the host.

### Issues/PRs references

Depends on PR https://github.com/RIOT-OS/RIOT/pull/18983

Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
This commit is contained in:
bors[bot] 2023-02-03 09:32:29 +00:00 committed by GitHub
commit 0fb6a09598
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 915 additions and 38 deletions

View File

@ -36,6 +36,7 @@ rsource "$(RIOTCPU)/stm32/periph/Kconfig.eth"
rsource "sx126x/Kconfig"
rsource "sx127x/Kconfig"
rsource "sx1280/Kconfig"
rsource "$(RIOTPKG)/tinyusb/netdev/Kconfig"
rsource "tja1042/Kconfig"
rsource "w5100/Kconfig"
endmenu # Network Device Drivers

View File

@ -332,6 +332,7 @@ typedef enum {
NETDEV_ESP_ETH,
NETDEV_ESP_WIFI,
NETDEV_CDC_ECM,
NETDEV_TINYUSB,
/* add more if needed */
} netdev_type_t;
/** @} */

View File

@ -126,6 +126,9 @@ config MODULE_TINYUSB_HOST
help
Select to enable tinyUSB host stack
config MODULE_TINYUSB_LIB_NETWORKING
bool
config MODULE_TINYUSB_PORTABLE_ESPRESSIF
bool
help
@ -170,13 +173,7 @@ menu "Device Classes"
bool "Musical Instrument Digital Interface (MIDI)"
depends on MODULE_TINYUSB_DEVICE
config MODULE_TINYUSB_CLASS_NET_ECM_RNDIS
bool "Network with RNDIS, Ethernet Control Model (ECM)"
depends on MODULE_TINYUSB_DEVICE
config MODULE_TINYUSB_CLASS_NET_NCM
bool "Network with Network Control Model (NCM)"
depends on MODULE_TINYUSB_DEVICE
rsource "Kconfig.net"
config MODULE_TINYUSB_CLASS_USBTMC
bool "Test and Measurement Class (USBTMC)"

60
pkg/tinyusb/Kconfig.net Normal file
View File

@ -0,0 +1,60 @@
# Copyright (c) 2022 Gunar Schorcht
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_TINYUSB_CLASS_NET
bool "Network Device Class"
depends on MODULE_TINYUSB_DEVICE
if MODULE_TINYUSB_CLASS_NET
config MODULE_TINYUSB_CLASS_NET_CDC_ECM
bool "CDC ECM network device"
default y
config MODULE_TINYUSB_CLASS_NET_CDC_NCM
bool "CDC NCM network device"
config MODULE_TINYUSB_CLASS_NET_RNDIS
bool "RNDIS network device"
select MODULE_TINYUSB_LIB_NETWORKING
config TUSBD_NET_NUMOF
int
default 1
if TUSBD_NET_NUMOF > 0
config TUSBD_NET_NOTIF_EP_SIZE
int "Net Notification endpoint size [byte]"
default 64
config TUSBD_NET_FS_EP_SIZE
int "Net Full-Speed endpoint size [byte]"
default 64
config TUSBD_NET_HS_EP_SIZE
int "Net High-Speed endpoint size [byte]"
default 512
config TUSBD_NET_MTU_SIZE
int "MTU size [byte]"
default 1514
config TUSBD_NET_DESC_STRING
string "Class descriptor string"
default "TinyUSB Net"
config TUSBD_NET_CUSTOM_MAC
bool "Use custom MAC address string"
config TUSBD_NET_MAC_STRING
string "MAC address string"
depends on TUSBD_ECM_CUSTOM_MAC
default "0123456789ab"
endif # TUSBD_NET_NUMOF > 0
endif # MODULE_TINYUSB_CLASS_NET

View File

@ -8,10 +8,11 @@ PKG_LICENSE=MIT
include $(RIOTBASE)/pkg/pkg.mk
PSRC = $(PKG_SOURCE_DIR)/src
PLIB = $(PKG_SOURCE_DIR)/lib
.PHONY: all
all: $(filter tinyusb_% stdio_tinyusb_cdc_acm,$(USEMODULE))
all: $(filter tinyusb_% stdio_tinyusb_cdc_acm,$(filter-out tinyusb_class_net_%,$(USEMODULE)))
$(QQ)"$(MAKE)" -C $(PSRC) -f $(RIOTBASE)/Makefile.base MODULE=tinyusb
stdio_tinyusb_cdc_acm:
@ -26,6 +27,9 @@ tinyusb_dfu:
tinyusb_hw:
$(QQ)"$(MAKE)" -C $(RIOTPKG)/$(PKG_NAME)/hw
tinyusb_netdev:
$(QQ)"$(MAKE)" -C $(RIOTPKG)/$(PKG_NAME)/netdev
tinyusb_class_audio:
$(QQ)"$(MAKE)" -C $(PSRC)/class/audio -f $(RIOTBASE)/Makefile.base MODULE=$@
@ -50,10 +54,7 @@ tinyusb_class_midi:
tinyusb_class_msc:
$(QQ)"$(MAKE)" -C $(PSRC)/class/msc -f $(RIOTBASE)/Makefile.base MODULE=$@
tinyusb_class_net_ecm_rndis:
$(QQ)"$(MAKE)" -C $(PSRC)/class/net -f $(RIOTBASE)/Makefile.base MODULE=$@
tinyusb_class_net_ncm:
tinyusb_class_net:
$(QQ)"$(MAKE)" -C $(PSRC)/class/net -f $(RIOTBASE)/Makefile.base MODULE=$@
tinyusb_class_usbtmc:
@ -74,6 +75,9 @@ tinyusb_device:
tinyusb_host:
$(QQ)"$(MAKE)" -C $(PSRC)/host -f $(RIOTBASE)/Makefile.base MODULE=$@
tinyusb_lib_networking:
$(QQ)"$(MAKE)" -C $(PLIB)/networking -f $(RIOTPKG)/$(PKG_NAME)/Makefile.lib_networking
tinyusb_portable_espressif:
$(QQ)"$(MAKE)" -C $(PSRC)/portable/espressif/esp32sx -f $(RIOTBASE)/Makefile.base MODULE=$@

View File

@ -30,6 +30,24 @@ ifneq (,$(filter tinyusb_dfu,$(USEMODULE)))
endif
endif
ifneq (,$(filter tinyusb_class_net_%,$(USEMODULE)))
USEMODULE += tinyusb_class_net
endif
ifneq (,$(filter tinyusb_netdev,$(USEMODULE)))
USEMODULE += luid
USEMODULE += netdev_eth
USEMODULE += tinyusb_device
ifeq (,$(filter tinyusb_class_net_%,$(USEMODULE)))
# default to CDC ECM
USEMODULE += tinyusb_class_net_cdc_ecm
endif
endif
ifneq (,$(filter tinyusb_class_net_rndis,$(USEMODULE)))
USEMODULE += tinyusb_lib_networking
endif
ifeq (,$(filter tinyusb_class_%,$(USEMODULE)))
$(error At least one tinyusb_class_* module has to be enabled)
endif
@ -60,10 +78,7 @@ endif
ifneq (,$(filter tinyusb_class_midi,$(USEMODULE)))
USEMODULE += tinyusb_device
endif
ifneq (,$(filter tinyusb_class_net_ecm_rndis,$(USEMODULE)))
USEMODULE += tinyusb_device
endif
ifneq (,$(filter tinyusb_class_net_ncm,$(USEMODULE)))
ifneq (,$(filter tinyusb_class_net,$(USEMODULE)))
USEMODULE += tinyusb_device
endif
ifneq (,$(filter tinyusb_class_usbtmc,$(USEMODULE)))

View File

@ -1,3 +1,7 @@
PSEUDOMODULES += tinyusb_class_net_cdc_ecm
PSEUDOMODULES += tinyusb_class_net_cdc_ncm
PSEUDOMODULES += tinyusb_class_net_rndis
INCLUDES += -I$(RIOTBASE)/pkg/tinyusb/contrib
INCLUDES += -I$(RIOTBASE)/pkg/tinyusb/contrib/include
INCLUDES += -I$(RIOTBASE)/pkg/tinyusb/hw/include
@ -30,10 +34,14 @@ else
$(error CPU $(CPU) or CPU family $(CPU_FAM) not supported)
endif
ifneq (,$(filter tinyusb_class_net_ecm_rndis,$(USEMODULE)))
ifneq (,$(filter tinyusb_class_net tinyusb_lib_networking,$(USEMODULE)))
INCLUDES += -I$(PKGDIRBASE)/tinyusb/lib/networking
endif
ifneq (,$(filter tinyusb_dfu,$(USEMODULE)))
INCLUDES += -I$(RIOTBASE)/pkg/tinyusb/dfu/include
endif
ifneq (,$(filter tinyusb_netdev,$(USEMODULE)))
INCLUDES += -I$(RIOTBASE)/pkg/tinyusb/netdev/include
endif

View File

@ -0,0 +1,5 @@
MODULE = tinyusb_lib_networking
SRC = rndis_reports.c
include $(RIOTBASE)/Makefile.base

View File

@ -46,6 +46,10 @@
extern "C" {
#endif
#if MODULE_TINYUSB_CLASS_NET_RNDIS
#define SIZEOF_ETH_HDR 14
#endif
/**
* @brief Initialize the tinyUSB stack including used peripherals and start the tinyUSB thread
*

View File

@ -56,6 +56,10 @@ enum {
#if CONFIG_TUSBD_MSC_NUMOF
TUSBD_ITF_MSC, /**< MSC interface */
#endif
#if CONFIG_TUSBD_NET_NUMOF
TUSBD_ITF_NET, /**< NET Notification interface */
TUSBD_ITF_NET_DATA, /**< NET Data interface */
#endif
#if CONFIG_TUSBD_VENDOR_NUMOF
TUSBD_ITF_VENDOR, /**< Vendor interface */
#endif
@ -87,6 +91,11 @@ enum {
TUSBD_EP_MSC_OUT = TUSBD_ITF_MSC + 0x01, /**< MSC EP OUT */
TUSBD_EP_MSC_IN = TUSBD_ITF_MSC + 0x81, /**< MSC EP IN */
#endif
#if CONFIG_TUSBD_NET_NUMOF
TUSBD_EP_NET_NOTIF = TUSBD_ITF_NET + 0x81, /**< NET Notification EP IN */
TUSBD_EP_NET_OUT = TUSBD_ITF_NET_DATA + 0x01, /**< NET Data EP OUT */
TUSBD_EP_NET_IN = TUSBD_ITF_NET_DATA + 0x81, /**< NET Data EP IN */
#endif
#if CONFIG_TUSBD_VENDOR_NUMOF
TUSBD_EP_VENDOR_OUT = TUSBD_ITF_VENDOR + 0x01, /**< Vendor EP OUT */
TUSBD_EP_VENDOR_IN = TUSBD_ITF_VENDOR + 0x81, /**< Vendor EP IN */
@ -123,6 +132,20 @@ enum {
#if CONFIG_TUSBD_MSC_NUMOF
TUSBD_STR_IDX_MSC,
#endif
#if CONFIG_TUSBD_NET_NUMOF
#if CONFIG_TUSBD_NET_CDC_ECM
TUSBD_STR_IDX_NET_CDC_ECM,
#endif /* CONFIG_TUSBD_NET_CDC_ECM */
#if CONFIG_TUSBD_NET_CDC_NCM
TUSBD_STR_IDX_NET_CDC_NCM,
#endif /* CONFIG_TUSBD_NET_CDC_NCM */
#if CONFIG_TUSBD_NET_RNDIS
TUSBD_STR_IDX_NET_RNDIS,
#endif /* CONFIG_TUSBD_NET_RNDIS */
TUSBD_STR_IDX_NET_MAC,
#endif /* CONFIG_TUSBD_NET_NUMOF */
#if CONFIG_TUSBD_VENDOR_NUMOF
TUSBD_STR_IDX_VENDOR,
#endif
@ -134,22 +157,46 @@ enum {
#define CONFIG_TUSBD_DFU_ALT_NUMOF 2
#if !defined(TUSBD_DESC_TOTAL_LEN)
#if CONFIG_TUSBD_NET_CDC_ECM
#define TUSBD_DESC_NET_LEN TUD_CDC_ECM_DESC_LEN
#elif CONFIG_TUSBD_NET_CDC_NCM
#define TUSBD_DESC_NET_LEN TUD_CDC_NCM_DESC_LEN
#elif CONFIG_TUSBD_NET_RNDIS
#define TUSBD_DESC_NET_LEN TUD_RNDIS_DESC_LEN
#else
#define TUSBD_DESC_NET_LEN 0
#endif
#define TUSBD_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + \
(CONFIG_TUSBD_CDC_NUMOF * TUD_CDC_DESC_LEN) + \
(CONFIG_TUSBD_DFU_NUMOF * TUD_DFU_DESC_LEN(CONFIG_TUSBD_DFU_ALT_NUMOF)) + \
(CONFIG_TUSBD_DFU_RT_NUMOF * TUD_DFU_RT_DESC_LEN) + \
(CONFIG_TUSBD_HID_NUMOF * TUD_HID_INOUT_DESC_LEN) + \
(CONFIG_TUSBD_MSC_NUMOF * TUD_MSC_DESC_LEN) + \
(CONFIG_TUSBD_VENDOR_NUMOF * TUD_VENDOR_DESC_LEN))
(CONFIG_TUSBD_VENDOR_NUMOF * TUD_VENDOR_DESC_LEN) + \
TUSBD_DESC_NET_LEN)
#endif /* !defined(TUSBD_DESC_TOTAL_LEN) */
/* If CDC ECM and RNDIS are used simultaneously, an alternative configuration
* descriptor is required. In this case, the main configuration descriptor
* contains the CDC ECM interface descriptor and the alternative configuration
* descriptor contains the RNDIS interface descriptor. */
#if CONFIG_TUSBD_NET_CDC_ECM && CONFIG_TUSBD_NET_RNDIS
#define TUSBD_DESC_ALT_NET_LEN TUD_RNDIS_DESC_LEN
#define TUSBD_DESC_ALT_TOTAL_LEN (TUD_CONFIG_DESC_LEN + \
(CONFIG_TUSBD_CDC_NUMOF * TUD_CDC_DESC_LEN) + \
(CONFIG_TUSBD_DFU_NUMOF * TUD_DFU_DESC_LEN(CONFIG_TUSBD_DFU_ALT_NUMOF)) + \
(CONFIG_TUSBD_DFU_RT_NUMOF * TUD_DFU_RT_DESC_LEN) + \
(CONFIG_TUSBD_HID_NUMOF * TUD_HID_INOUT_DESC_LEN) + \
(CONFIG_TUSBD_MSC_NUMOF * TUD_MSC_DESC_LEN) + \
(CONFIG_TUSBD_VENDOR_NUMOF * TUD_VENDOR_DESC_LEN))
(CONFIG_TUSBD_VENDOR_NUMOF * TUD_VENDOR_DESC_LEN) + \
TUSBD_DESC_ALT_NET_LEN)
#endif /* CONFIG_TUSBD_NET_CDC_ECM && CONFIG_TUSBD_NET_RNDIS */
#endif /* !defined(CONFIG_TUSBD_USE_CUSTOM_DESC) */

View File

@ -40,8 +40,16 @@
#endif
#include "tinyusb.h"
#if MODULE_TINYUSB_CLASS_NET
#include "net/ethernet.h"
#endif
#if !DOXYGEN
#if MODULE_TINYUSB_CLASS_NET_CDC_NCM && (MODULE_TINYUSB_CLASS_NET_CDC_ECM || MODULE_TINYUSB_CLASS_NET_RNDIS)
#error "CDC NCM device class cannot be used together with CDC ECM or RNDIS device class"
#endif
#ifndef CONFIG_TUSBD_AUDIO_NUMOF
#if MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_CLASS_AUDIO
#define CONFIG_TUSBD_AUDIO_NUMOF 1
@ -82,14 +90,6 @@
#endif
#endif
#ifndef CONFIG_TUSBD_ECM_NUMOF
#if MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_CLASS_ECM
#define CONFIG_TUSBD_ECM_NUMOF 1
#else
#define CONFIG_TUSBD_ECM_NUMOF 0
#endif
#endif
#ifndef CONFIG_TUSBD_HID_NUMOF
#if MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_CLASS_HID
#define CONFIG_TUSBD_HID_NUMOF 1
@ -114,14 +114,6 @@
#endif
#endif
#ifndef CONFIG_TUSBD_NCM_NUMOF
#if MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_CLASS_NCM
#define CONFIG_TUSBD_NCM_NUMOF 1
#else
#define CONFIG_TUSBD_NCM_NUMOF 0
#endif
#endif
#ifndef CONFIG_TUSBD_USBTMC_NUMOF
#if MODULE_TINYUSB_DEVICE && MODULE_TINYUSB_CLASS_USBTMC
#define CONFIG_TUSBD_USBTMC_NUMOF 1
@ -272,6 +264,14 @@
#define CONFIG_TUSBD_MSC_HS_EP_SIZE CONFIG_TUSBD_HS_EP_SIZE
#endif
#ifndef CONFIG_TUSBD_NET_FS_EP_SIZE
#define CONFIG_TUSBD_NET_FS_EP_SIZE CONFIG_TUSBD_FS_EP_SIZE
#endif
#ifndef CONFIG_TUSBD_NET_HS_EP_SIZE
#define CONFIG_TUSBD_NET_HS_EP_SIZE CONFIG_TUSBD_HS_EP_SIZE
#endif
#ifndef CONFIG_TUSBD_VENDOR_FS_EP_SIZE
#define CONFIG_TUSBD_VENDOR_FS_EP_SIZE CONFIG_TUSBD_FS_EP_SIZE
#endif
@ -280,6 +280,38 @@
#define CONFIG_TUSBD_VENDOR_HS_EP_SIZE CONFIG_TUSBD_HS_EP_SIZE
#endif
#ifndef CONFIG_TUSBD_NET_NOTIF_EP_SIZE
#define CONFIG_TUSBD_NET_NOTIF_EP_SIZE 64
#endif
#ifndef CONFIG_TUSBD_NET_MTU_SIZE
#define CONFIG_TUSBD_NET_MTU_SIZE ETHERNET_FRAME_LEN
#endif
#if MODULE_TINYUSB_CLASS_NET_CDC_ECM
#define CONFIG_TUSBD_NET_CDC_ECM 1
#else
#define CONFIG_TUSBD_NET_CDC_ECM 0
#endif
#if MODULE_TINYUSB_CLASS_NET_CDC_NCM
#define CONFIG_TUSBD_NET_CDC_NCM 1
#else
#define CONFIG_TUSBD_NET_CDC_NCM 0
#endif
#if MODULE_TINYUSB_CLASS_NET_RNDIS
#define CONFIG_TUSBD_NET_RNDIS 1
#else
#define CONFIG_TUSBD_NET_RNDIS 0
#endif
#if CONFIG_TUSBD_NET_CDC_ECM || CONFIG_TUSBD_NET_CDC_NCM || CONFIG_TUSBD_NET_RNDIS
#define CONFIG_TUSBD_NET_NUMOF 1
#else
#define CONFIG_TUSBD_NET_NUMOF 0
#endif
#ifndef CONFIG_TUSBH_ENUM_SIZE
#define CONFIG_TUSBH_ENUM_SIZE 256
#endif
@ -333,6 +365,7 @@
#define CFG_TUD_AUDIO CONFIG_TUSBD_AUDIO_NUMOF
#define CFG_TUD_BTH CONFIG_TUSBD_BTH_NUMOF
#define CFG_TUD_CDC CONFIG_TUSBD_CDC_NUMOF
#define CFG_TUD_ECM_RNDIS (CONFIG_TUSBD_NET_CDC_ECM || CONFIG_TUSBD_NET_RNDIS)
#define CFG_TUD_DFU CONFIG_TUSBD_DFU_NUMOF
#define CFG_TUD_DFU_RUNTIME CONFIG_TUSBD_DFU_RT_NUMOF
#define CFG_TUD_HID CONFIG_TUSBD_HID_NUMOF
@ -408,6 +441,12 @@
: CONFIG_TUSBD_MSC_FS_EP_SIZE)
/** @} */
/**
* @name Typical required NET device class configurations
* @{
*/
#define CFG_TUD_NET_MTU CONFIG_TUSBD_NET_MTU_SIZE
/**
* @name Typical required HID host class configurations
* @{

View File

@ -30,6 +30,8 @@
#include "tusb.h"
#include "usb.h"
#include "net/ethernet.h"
#ifdef MODULE_TINYUSB_DFU
#include "riotboot/usb_dfu.h"
#endif
@ -45,13 +47,12 @@
#if (MODULE_TINYUSB_CLASS_AUDIO || \
MODULE_TINYUSB_CLASS_BTH || \
MODULE_TINYUSB_CLASS_MIDI || \
MODULE_TINYUSB_CLASS_NET_ECM_RNDIS || \
MODULE_TINYUSB_CLASS_NET_NCM || \
MODULE_TINYUSB_CLASS_USBTMC || \
MODULE_TINYUSB_CLASS_VIDEO || \
(CONFIG_TUSBD_CDC_NUMOF > 2) || \
(CONFIG_TUSBD_DFU_NUMOF > 1) || \
(CONFIG_TUSBD_DFU_RT_NUMOF > 1) || \
(CONFIG_TUSBD_NET_NUMOF > 1) || \
(CONFIG_TUSBD_HID_NUMOF > 2) || \
(CONFIG_TUSBD_MSC_NUMOF > 1) || \
(CONFIG_TUSBD_VENDOR_NUMOF > 1))
@ -59,7 +60,13 @@
of device class interfaces. Custom descriptors have to be implemented.
#endif
/* If CDC ECM and RNDIS are used simultaneously, an alternative configuration
* descriptor is required. */
#if CONFIG_TUSBD_NET_CDC_ECM && CONFIG_TUSBD_NET_RNDIS
#define _TUD_CONFIG_DESC_NUMOF 2
#else
#define _TUD_CONFIG_DESC_NUMOF 1
#endif
enum {
_TUD_CONFIG_DESC_ID = 0,
@ -266,6 +273,39 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id,
speed ? CONFIG_TUSBD_MSC_HS_EP_SIZE \
: CONFIG_TUSBD_MSC_FS_EP_SIZE)
#define _TUD_CDC_ECM_DESC(speed) \
/* Interface number, Description string index, MAC address string index,
* EP notification address and size, EP Data Out & In, EP size, MTU size. */ \
TUD_CDC_ECM_DESCRIPTOR(TUSBD_ITF_NET, \
TUSBD_STR_IDX_NET_CDC_ECM, TUSBD_STR_IDX_NET_MAC, \
TUSBD_EP_NET_NOTIF, \
CONFIG_TUSBD_NET_NOTIF_EP_SIZE, \
TUSBD_EP_NET_OUT, TUSBD_EP_NET_IN, \
speed ? CONFIG_TUSBD_NET_HS_EP_SIZE \
: CONFIG_TUSBD_NET_FS_EP_SIZE, \
CONFIG_TUSBD_NET_MTU_SIZE)
#define _TUD_CDC_NCM_DESC(speed) \
/* Interface number, Description string index, MAC address string index,
* EP notification address and size, EP Data Out & In, EP size, MTU size. */ \
TUD_CDC_NCM_DESCRIPTOR(TUSBD_ITF_NET, \
TUSBD_STR_IDX_NET_CDC_NCM, TUSBD_STR_IDX_NET_MAC, \
TUSBD_EP_NET_NOTIF, \
CONFIG_TUSBD_NET_NOTIF_EP_SIZE, \
TUSBD_EP_NET_OUT, TUSBD_EP_NET_IN, \
speed ? CONFIG_TUSBD_NET_HS_EP_SIZE \
: CONFIG_TUSBD_NET_FS_EP_SIZE, \
CONFIG_TUSBD_NET_MTU_SIZE)
#define _TUD_RNDIS_DESC(speed) \
/* Interface number, Description string index, EP notification address and
* size, EP Data Out & In, EP size */ \
TUD_RNDIS_DESCRIPTOR(TUSBD_ITF_NET, TUSBD_STR_IDX_NET_RNDIS, \
TUSBD_EP_NET_NOTIF, 8, TUSBD_EP_NET_OUT, \
TUSBD_EP_NET_IN, \
speed ? CONFIG_TUSBD_NET_HS_EP_SIZE \
: CONFIG_TUSBD_NET_FS_EP_SIZE)
#define _TUD_VENDOR_DESC(speed) \
/* Interface number, string index, EP Out & In address, EP size */ \
TUD_VENDOR_DESCRIPTOR(TUSBD_ITF_VENDOR, TUSBD_STR_IDX_VENDOR, \
@ -298,6 +338,13 @@ uint8_t const tusb_desc_fs_config[] = {
#if CONFIG_TUSBD_MSC_NUMOF
_TUD_MSC_DESC(_tusb_speed_fs),
#endif
#if CONFIG_TUSBD_NET_CDC_ECM
_TUD_CDC_ECM_DESC(_tusb_speed_fs),
#elif CONFIG_TUSBD_NET_CDC_NCM
_TUD_CDC_NCM_DESC(_tusb_speed_fs),
#elif CONFIG_TUSBD_NET_RNDIS
_TUD_RNDIS_DESC(_tusb_speed_fs),
#endif
#if CONFIG_TUSBD_VENDOR_NUMOF
_TUD_VENDOR_DESC(_tusb_speed_fs),
#endif
@ -328,6 +375,11 @@ uint8_t const tusb_desc_fs_config_alt[] = {
#if CONFIG_TUSBD_MSC_NUMOF
_TUD_MSC_DESC(_tusb_speed_fs),
#endif
/* The alternative configuration descriptor is only required if CDC ECM and
* RDNIS are used simultaneously. In this case, the main configuration
* descriptor contains the CDC ECM interface descriptor and the alternative
* configuration descriptor contains the RNDIS interface descriptor. */
_TUD_RNDIS_DESC(_tusb_speed_fs),
#if CONFIG_TUSBD_VENDOR_NUMOF
_TUD_VENDOR_DESC(_tusb_speed_fs),
#endif
@ -363,6 +415,13 @@ uint8_t const tusb_desc_hs_config[] = {
#if CONFIG_TUSBD_MSC_NUMOF
_TUD_MSC_DESC(_tusb_speed_hs),
#endif
#if CONFIG_TUSBD_NET_CDC_ECM
_TUD_CDC_ECM_DESC(_tusb_speed_hs),
#elif CONFIG_TUSBD_NET_CDC_NCM
_TUD_CDC_NCM_DESC(_tusb_speed_hs),
#elif CONFIG_TUSBD_NET_RNDIS
_TUD_RNDIS_DESC(_tusb_speed_hs),
#endif
#if CONFIG_TUSBD_VENDOR_NUMOF
_TUD_VENDOR_DESC(_tusb_speed_hs),
#endif
@ -393,6 +452,11 @@ uint8_t const tusb_desc_hs_config_alt[] = {
#if CONFIG_TUSBD_MSC_NUMOF
_TUD_MSC_DESC(_tusb_speed_hs),
#endif
/* The alternative configuration descriptor is only required if CDC ECM and
* RDNIS are used simultaneously. In this case, the main configuration
* descriptor contains the CDC ECM interface descriptor and the alternative
* configuration descriptor contains the RNDIS interface descriptor. */
_TUD_RNDIS_DESC(_tusb_speed_hs),
#if CONFIG_TUSBD_VENDOR_NUMOF
_TUD_VENDOR_DESC(_tusb_speed_hs),
#endif
@ -535,6 +599,14 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
#define CONFIG_TUSBD_CDC_1_STRING "TinyUSB CDC1"
#endif
#ifndef CONFIG_TUSBD_CDC_ECM_STRING
#define CONFIG_TUSBD_CDC_ECM_STRING "TinyUSB CDC ECM"
#endif
#ifndef CONFIG_TUSBD_CDC_NCM_STRING
#define CONFIG_TUSBD_CDC_NCM_STRING "TinyUSB CDC NCM"
#endif
#ifndef CONFIG_TUSBD_DFU_0_STRING
#define CONFIG_TUSBD_DFU_0_STRING USB_DFU_MODE_SLOT0_NAME
#endif
@ -559,6 +631,14 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
#define CONFIG_TUSBD_MSC_STRING "TinyUSB MSC"
#endif
#ifndef CONFIG_TUSBD_NET_DESC_STRING
#define CONFIG_TUSBD_NET_DESC_STRING "TinyUSB Net"
#endif
#ifndef CONFIG_TUSBD_RNDIS_STRING
#define CONFIG_TUSBD_RNDIS_STRING "TinyUSB RNDIS"
#endif
#ifndef CONFIG_TUSBD_VENDOR_STRING
#define CONFIG_TUSBD_VENDOR_STRING "TinyUSB Vendor"
#endif
@ -602,6 +682,23 @@ char const* tusb_string_desc_array[] = {
#if CONFIG_TUSBD_VENDOR_NUMOF
CONFIG_TUSBD_VENDOR_STRING, /* Vendor Interface */
#endif
#if CONFIG_TUSBD_NET_NUMOF
#if CONFIG_TUSBD_NET_CDC_ECM
CONFIG_TUSBD_CDC_ECM_STRING, /* CDC ECM Interface */
#endif /* CONFIG_TUSBD_NET_CDC_ECM */
#if CONFIG_TUSBD_NET_CDC_NCM
CONFIG_TUSBD_CDC_NCM_STRING, /* CDC NCM Interface */
#endif /* CONFIG_TUSBD_NET_CDC_NCM */
#if CONFIG_TUSBD_NET_RNDIS
CONFIG_TUSBD_RNDIS_STRING, /* RNDIS Interface */
#endif /* CONFIG_TUSBD_NET_RNDIS */
#ifdef CONFIG_TUSBD_NET_CUSTOM_MAC
CONFIG_TUSBD_NET_MAC_STRING, /* NET Interface MAC address */
#else
NULL,
#endif /* CONFIG_TUSBD_NET_CUSTOM_MAC */
#endif /* CONFIG_TUSBD_NET_NUMOF */
};
static uint16_t _desc_str[32];
@ -645,6 +742,21 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
}
str = _serial_str;
}
#if CONFIG_TUSBD_NET_NUMOF
else if ((index == TUSBD_STR_IDX_NET_MAC) &&
(tusb_string_desc_array[index] == NULL)) {
/* generated MAC address string is used */
static char mac_str[(ETHERNET_ADDR_LEN << 1) + 1] = { };
if (strlen(mac_str) == 0) {
/* generate the serial string if it is not yet generated */
uint8_t luid_buf[ETHERNET_ADDR_LEN];
luid_get_eui48((eui48_t*)luid_buf);
fmt_bytes_hex(mac_str, luid_buf, sizeof(luid_buf));
mac_str[(ETHERNET_ADDR_LEN << 1)] = 0;
}
str = mac_str;
}
#endif
else {
str = tusb_string_desc_array[index];
}
@ -667,4 +779,26 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
return _desc_str;
}
#if !CONFIG_TUSBD_RNDIS
__attribute__((weak))
void rndis_class_set_handler(uint8_t *data, int size)
{
(void)data;
(void)size;
}
__attribute__((weak))
void tud_network_init_cb(void)
{
printf("tud_network_init_cb");
}
__attribute__((weak))
bool tud_network_recv_cb(const uint8_t *src, uint16_t size)
{
printf("tud_network_init_cb %p %u", src, size);
return true;
}
#endif
#endif /* !defined(CONFIG_TUSBD_USE_CUSTOM_DESC) */

View File

@ -5,7 +5,7 @@
* @author Gunar Schorcht <gunar@schorcht.net>
* @see https://github.com/hathach/tinyusb
*
* # TinyUSB
* # TinyUSB {#pkg_tinyusb}
*
* tinyUSB is an open-source cross-platform USB Host/Device stack for
* embedded systems.
@ -94,6 +94,7 @@
* - up to two interfaces of the Generic In/Out HID class,
* - up to one DFU interface
* - up to one MSC device interface and,
* - up to one Net device interface with CDC ECM, CDC NCM and RNDIS protocol, and
* - up to one interface of the Vendor device class.
*
* Any other combination, either a different number of these device class

View File

@ -0,0 +1,16 @@
# Copyright (c) 2022 Gunar Schorcht
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config MODULE_TINYUSB_NETDEV
bool "TinyUSB Network Device Driver"
depends on HAS_TINYUSB_DEVICE
depends on TEST_KCONFIG
select MODULE_LUID
select MODULE_NETDEV_ETH
select MODULE_TINYUSB_CLASS_NET
select MODULE_TINYUSB_DEVICE
select PACKAGE_TINYUSB

View File

@ -0,0 +1,3 @@
MODULE = tinyusb_netdev
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2022 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup pkg_tinyusb_netdev TinyUSB netdev driver
* @ingroup pkg_tinyusb
* @ingroup drivers_netdev
* @brief TinyUSB netdev driver for CDC ECM, CDC NCM and RNDIS protocol
*
* The tinyUSB netdev driver is part of the \ref pkg_tinyusb "tinyUSB package"
* and is enabled by module `tinyusb_netdev`. It is available for boards that
* provide the `tinyusb_device` feature.
*
* @note Since the tinyUSB package is distinct from (and incompatible with)
* the USB stack provided around USBUS in RIOT (see USB), the tinyUSB netdev
* driver cannot be used together with with any USBUS device class.
*
* The tinyUSB netdev driver uses Ethernet over USB and supports the following
* protocols:
*
* - CDC ECM (Ethernet Control Model)
* - CDC NCM (Network Control Model)
* - RNDIS (Microsoft Remote NDIS)
*
* While Linux and macOS support all these protocols, Microsoft Windows
* only supports the RNDIS protocol and since Windows version 11 also the
* CDC NCM protocol. macOS supports the RNDIS protocol since version 10.15
* (Catalina).
*
* Which protocol is used is selected by the corresponding
* pseudomodules `tinyusb_class_net_cdc_ecm`, `tinyusb_class_net_cdc_ncm`
* and `tinyusb_class_net_rndis`.
*
* The CDC ECM protocol (`tinyusb_class_net_cdc_ecm`) and the RNDIS protocol
* (`tinyusb_class_net_rndis`) can be used simultaneously to support all
* operating systems, for example :
* ```
* USEMODULE='tinyusb_netdev tinyusb_class_net_rndis tinyusb_class_net_cdc_ecm' \
* BOARD=... make -C ... flash
* ```
* In this case, the CDC ECM protocol is the default protocol and the RNDIS
* protocol the alternative protocol defined as second device configuration.
*
* The CDC NCM protocol cannot be used together with the CDC ECM or the RNDIS
* protocol.
*
* @{
* @file
* @brief TinyUSB netdev driver for CDC ECM, CDC NCM and RNDIS protocol
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef TINYUSB_NETDEV_H
#define TINYUSB_NETDEV_H
#include "net/ethernet.h"
#include "net/netdev.h"
#include "mutex.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Device descriptor for tinyUSB CDC ECM network devices
*/
typedef struct {
netdev_t netdev; /**< netdev parent struct */
uint8_t mac_addr[ETHERNET_ADDR_LEN]; /**< device MAC address */
uint8_t mac_host[ETHERNET_ADDR_LEN]; /**< host MAC address */
uint16_t rx_len; /**< number of bytes received */
uint16_t tx_len; /**< number of bytes in transmit buffer */
const uint8_t *rx_buf; /**< receive buffer in tinyUSB stack */
uint8_t tx_buf[ETHERNET_MAX_LEN]; /**< transmit buffer */
mutex_t lock; /**< device is already in use */
} tinyusb_netdev_t;
#ifdef __cplusplus
}
#endif
#endif /* TINYUSB_NETDEV_H */
/** @} */

View File

@ -0,0 +1,257 @@
/*
* Copyright (C) 2022 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup pkg_tinyusb
* @{
* @file TinyUSB Netdev implementation for CDC Ethernet Control Model
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#define USB_H_USER_IS_RIOT_INTERNAL
#include "kernel_defines.h"
#include "iolist.h"
#include "net/eui_provider.h"
#include "net/netdev/eth.h"
#include "od.h"
#include "device/usbd.h"
#include "class/net/net_device.h"
#include "tinyusb_netdev.h"
#define ENABLE_DEBUG_HEXDUMP 0
#define ENABLE_DEBUG 0
#include "debug.h"
/* The symbol is needed by the tinyUSB stack but not used and shall be removed
* later on, see: https://github.com/hathach/tinyusb/issues/718 */
const uint8_t tud_network_mac_address[6] = { 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
static const netdev_driver_t _tusb_driver;
tinyusb_netdev_t tinyusb_netdev;
void tinyusb_netdev_setup(tinyusb_netdev_t *dev)
{
DEBUG("[tinyusb_netdev] %s: %p\n", __func__, dev);
mutex_init(&dev->lock);
dev->netdev.driver = &_tusb_driver;
dev->rx_len = 0;
dev->tx_len = 0;
netdev_register(&dev->netdev, NETDEV_TINYUSB, 0);
}
static int _send(netdev_t *netdev, const iolist_t *iolist)
{
DEBUG("[tinyusb_netdev] %s: %p %p\n", __func__, netdev, iolist);
tinyusb_netdev_t *dev = (tinyusb_netdev_t *)netdev;
assert(dev == &tinyusb_netdev);
assert(iolist);
if (!tud_ready()) {
return -EBUSY;
}
mutex_lock(&dev->lock);
dev->tx_len = 0;
/* load packet data into TX buffer */
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
if (dev->tx_len + iol->iol_len > ETHERNET_MAX_LEN) {
mutex_unlock(&dev->lock);
return -EOVERFLOW;
}
if (iol->iol_len) {
memcpy (dev->tx_buf + dev->tx_len, iol->iol_base, iol->iol_len);
dev->tx_len += iol->iol_len;
}
}
if (IS_ACTIVE(ENABLE_DEBUG)) {
printf("[tinyusb_netdev] %s: send %d byte from %p\n",
__func__, dev->tx_len, dev->tx_buf);
if (IS_ACTIVE(ENABLE_DEBUG_HEXDUMP) && IS_USED(MODULE_OD)) {
od_hex_dump(dev->tx_buf, dev->tx_len, OD_WIDTH_DEFAULT);
}
}
mutex_unlock(&dev->lock);
/* if the network driver can accept another packet, trigger the send */
if (tud_network_can_xmit(dev->tx_len))
{
tud_network_xmit(dev->tx_buf, dev->tx_len);
return 0;
}
return -EBUSY;
}
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
{
(void)info;
DEBUG("[tinyusb_netdev] %s: %p %p %u %p\n", __func__, netdev, buf, len, info);
tinyusb_netdev_t *dev = (tinyusb_netdev_t *)netdev;
assert(dev == &tinyusb_netdev);
mutex_lock(&dev->lock);
int size = dev->rx_len;
if (!buf) {
/* get the size of the frame; if len > 0 then also drop the frame */
if (len > 0) {
/* drop frame requested */
dev->rx_len = 0;
}
mutex_unlock(&dev->lock);
return size;
}
if (dev->rx_len > len) {
/* buffer is smaller than the number of received bytes */
DEBUG("[tinyusb_netdev] %s: Not enough space in receive buffer for %d bytes\n",
__func__, dev->rx_len);
mutex_unlock(&dev->lock);
return -ENOBUFS;
}
if (IS_ACTIVE(ENABLE_DEBUG)) {
printf ("[tinyusb_netdev] %s: received %d byte\n", __func__, dev->rx_len);
if (IS_ACTIVE(ENABLE_DEBUG) && IS_USED(MODULE_OD)) {
od_hex_dump(dev->rx_buf, dev->rx_len, OD_WIDTH_DEFAULT);
}
}
/* copy received date and reset the receive length */
memcpy(buf, dev->rx_buf, dev->rx_len);
dev->rx_len = 0;
mutex_unlock(&dev->lock);
/* indicate that receiving the frame has been finished */
tud_network_recv_renew();
return size;
}
static int _init(netdev_t *netdev)
{
DEBUG("[tinyusb_netdev] %s: %p\n", __func__, netdev);
tinyusb_netdev_t *dev = (tinyusb_netdev_t *)netdev;
assert(dev == &tinyusb_netdev);
netdev_eui48_get(netdev, (eui48_t*)&dev->mac_addr);
netdev->event_callback(netdev, NETDEV_EVENT_LINK_UP);
return 0;
}
static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
{
DEBUG("[tinyusb_netdev] %s: %p %u %p %u\n",
__func__, netdev, opt, value, max_len);
tinyusb_netdev_t *dev = (tinyusb_netdev_t *)netdev;
assert(dev == &tinyusb_netdev);
(void)max_len;
switch (opt) {
case NETOPT_ADDRESS:
assert(max_len >= ETHERNET_ADDR_LEN);
memcpy(value, dev->mac_addr, ETHERNET_ADDR_LEN);
return ETHERNET_ADDR_LEN;
default:
return netdev_eth_get(netdev, opt, value, max_len);
}
}
static int _set(netdev_t *netdev, netopt_t opt,
const void *value, size_t len)
{
DEBUG("[tinyusb_netdev] %s: %p %u %p %u\n",
__func__, netdev, opt, value, len);
tinyusb_netdev_t *dev = (tinyusb_netdev_t *)netdev;
assert(dev == &tinyusb_netdev);
switch (opt) {
case NETOPT_ADDRESS:
assert(len == ETHERNET_ADDR_LEN);
memcpy(dev->mac_addr, value, ETHERNET_ADDR_LEN);
return ETHERNET_ADDR_LEN;
default:
return netdev_eth_set(&dev->netdev, opt, value, len);
}
}
static void _isr(netdev_t *netdev)
{
tinyusb_netdev_t *dev = (tinyusb_netdev_t *)netdev;
assert(dev == &tinyusb_netdev);
if (dev->rx_len) {
dev->netdev.event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
}
}
static const netdev_driver_t _tusb_driver = {
.send = _send,
.recv = _recv,
.init = _init,
.isr = _isr,
.get = _get,
.set = _set,
};
void tud_network_init_cb(void)
{
DEBUG("[tinyusb_netdev] %s\n", __func__);
tinyusb_netdev.rx_len = 0;
tinyusb_netdev.tx_len = 0;
}
bool tud_network_recv_cb(const uint8_t *src, uint16_t size)
{
DEBUG("[tinyusb_netdev] %s: %p %u\n", __func__, src, size);
/* if the previous packet is not handled just return with false */
if (tinyusb_netdev.rx_len) {
return false;
}
assert(size <= ETHERNET_MAX_LEN);
if (size)
{
tinyusb_netdev.rx_buf = src;
tinyusb_netdev.rx_len = size;
}
netdev_trigger_event_isr(&tinyusb_netdev.netdev);
return true;
}
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg)
{
DEBUG("[tinyusb_netdev] %s: %p %p %u\n", __func__, dst, ref, arg);
memcpy(dst, ref, arg);
return arg;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2019 Koen Zandberg
* 2022 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
/**
* @ingroup sys_auto_init_gnrc_netif
* @{
*
* @file
* @brief Auto initialization for tinyUSB CDC ECM module
*
* @author Koen Zandberg <koen@bergzand.net>
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#define USB_H_USER_IS_RIOT_INTERNAL
#include "include/init_devs.h"
#include "log.h"
#include "net/gnrc/netif/ethernet.h"
#include "tinyusb_netdev.h"
/**
* @brief global cdc ecm object, declared in the usb auto init file
*/
extern tinyusb_netdev_t tinyusb_netdev;
/**
* @brief Define stack parameters for the MAC layer thread
* @{
*/
#define TUSB_NETDEV_STACKSIZE (GNRC_NETIF_STACKSIZE_DEFAULT)
#ifndef TUSB_NETDEV_PRIO
#define TUSB_NETDEV_PRIO (GNRC_NETIF_PRIO)
#endif
/**
* @brief Stacks for the MAC layer threads
*/
static char _netdev_eth_stack[TUSB_NETDEV_STACKSIZE];
static gnrc_netif_t _netif;
extern void tinyusb_netdev_setup(tinyusb_netdev_t *dev);
void auto_init_tinyusb_netdev(void)
{
LOG_DEBUG("[auto_init_netif] initializing tinyUSB netdev #0\n");
tinyusb_netdev_setup(&tinyusb_netdev);
/* initialize netdev<->gnrc adapter state */
gnrc_netif_ethernet_create(&_netif, _netdev_eth_stack,
TUSB_NETDEV_STACKSIZE, TUSB_NETDEV_PRIO,
"tinyusb_netdev", &tinyusb_netdev.netdev);
}
/** @} */

View File

@ -171,4 +171,10 @@ void gnrc_netif_init_devs(void)
extern void auto_init_sx126x(void);
auto_init_sx126x();
}
if (IS_USED(MODULE_TINYUSB_NETDEV)) {
extern void auto_init_tinyusb_netdev(void);
auto_init_tinyusb_netdev();
}
}

View File

@ -0,0 +1,21 @@
BOARD ?= samr21-xpro
include ../Makefile.tests_common
USB_VID ?= $(USB_VID_TESTING)
USB_PID ?= $(USB_PID_TESTING)
CLASS ?= tinyusb_class_net_rndis
USEPKG += tinyusb
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_icmpv6_echo
USEMODULE += shell
USEMODULE += shell_cmds_default
USEMODULE += ps
USEMODULE += tinyusb_netdev
USEMODULE += $(CLASS)
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,3 @@
BOARD_INSUFFICIENT_MEMORY := \
stm32f7508-dk \
#

View File

@ -0,0 +1,54 @@
Overview
========
This test application can be used to check the implementation of the tinyUSB
netdev driver. The implementation of the tinyUSB netdev driver uses Ethernet
over USB and supports the following protocols:
- CDC ECM (Ethernet Control Model)
- CDC NCM (Network Control Model)
- RNDIS (Microsoft Remote NDIS)
While Linux and macOS support all these protocols, Microsoft Windows only
supports RNDIS and since Windows version 11 also CDC NCM. Which protocol is
used is selected by the corresponding pseudomodules `tinyusb_class_net_cdc_ecm`,
`tinyusb_class_net_cdc_ncm` and `tinyusb_class_net_rndis`.
Configuration
=============
The test application use the protocol defined by the CLASS variable, which
defaults to the RNDIS protocol (`tinyusb_class_net_rndis`). This can be
changed by setting this variable in the make command line, for example:
```
CLASS=tinyusb_class_net_cdc_ecm BOARD=... make -C tests/pkg_tinyusb_netdev flash
```
The CDC ECM protocol (`tinyusb_class_net_cdc_ecm`) and the RNDIS protocol
(`tinyusb_class_net_rndis`) can be used simultaneously to support all operating
systems, for example :
```
CLASS='tinyusb_class_net_rndis tinyusb_class_net_cdc_ecm' \
BOARD=... make -C tests/pkg_tinyusb_netdev flash
```
In this case, the CDC ECM protocol is the default protocol and the RNDIS
protocol the alternative protocol defined as second device configuration.
The CDC NCM protocol cannot be used together with the CDC ECM or the RNDIS
protocol
Expected result
===============
Use the network related shell commands to verify the network link between the
board under test and the host computer. Ping to the link local address from and
to the host computer must work.
On the host computer, using tools such as `ethtool` must show the USB CDC ECM
interface as link detected:
```
# ethtool enp0s20u9u4
Settings for enp0s20u9u4:
Current message level: 0x00000007 (7)
drv probe link
Link detected: yes
```

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2019 Koen Zandberg <koen@bergzand.net>
* 2022 Gunar Schorcht <gunar@schorcht.net>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for the tinyUSB netdev
*
* @author Koen Zandberg <koen@bergzand.net>
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
#include <stdio.h>
#include "shell.h"
#include "msg.h"
#define MAIN_QUEUE_SIZE (8U)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
int main(void)
{
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
puts("Test application for the tinyUSB net device interface\n");
puts("This test pulls in parts of the GNRC network stack, use the\n"
"provided shell commands (i.e. ifconfig, ping) to interact with\n"
"the tinyUSB based network interface.\n");
/* start shell */
puts("Starting the shell now...");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should be never reached */
return 0;
}