USB Gadget 子系统详解:OTG 口模拟各类 USB 外设

USB Gadget 子系统详解:OTG 口模拟各类 USB 外设

1. 前言

很多开发者在使用 LubanCat 开发板时,会注意到板子上有一个 OTG(On-The-Go)口。这个口不仅仅是用来烧录固件或连接 USB 设备的——它还有一个非常强大的能力:让开发板模拟成各种 USB 外设,被 PC 或其他 USB Host 识别。

重要前提:只有 OTG 口才能模拟 USB 外设,普通 USB-A 口不行。 原因在于硬件层面——USB 控制器分为 Host-only 和 Dual-Role(OTG)两种,普通 USB-A 口背后的 EHCI/xHCI 控制器只支持 Host 模式,硬件上没有 Device 模式的端点和寄存器;只有 OTG 口背后的 DWC3 控制器支持双角色切换,才能加载 Gadget 驱动模拟外设。详见下方 第 8 节 的设备树分析。

本文将深度剖析 kernel-6.1/drivers/usb/gadget/ 目录的完整结构,详细介绍 Linux 内核提供的所有 USB Gadget 功能,让你了解开发板到底能模拟哪些 USB 设备。

2. 什么是 USB Gadget?

2.1 USB 的两种角色

USB 协议中定义了两种角色:

角色说明硬件接口典型设备
USB Host主控端,发起所有通信Type-A 口PC、手机(OTG模式下)
USB Device/Gadget从设备,响应 Host 请求Type-B / Micro-B / Type-CU盘、摄像头、键盘

USB Gadget 就是让 Linux 设备充当 USB Device 角色的框架。 通过 OTG 口,开发板可以在 Host 和 Device 两种角色之间切换。

2.2 Gadget 框架的三层架构

┌─────────────────────────────────────────────────────────────────┐
│  用户空间 / configfs 配置层                                       │
│  /config/usb_gadget/g1/functions/...                             │
├─────────────────────────────────────────────────────────────────┤
│  Function 层(可模拟的 USB 设备类型)                              │
│  f_mass_storage / f_hid / f_uvc / f_acm / f_rndis / ...        │
├─────────────────────────────────────────────────────────────────┤
│  Composite 框架层(组合多个 Function)                             │
│  composite.c / configfs.c / epautoconf.c                        │
├─────────────────────────────────────────────────────────────────┤
│  UDC 层(USB Device Controller 硬件驱动)                         │
│  dwc3 / dwc2 / fsl_udc / ...                                    │
├─────────────────────────────────────────────────────────────────┤
│  USB 硬件控制器 (DWC3 on RK3588)                                 │
└─────────────────────────────────────────────────────────────────┘

3. 目录结构总览

源码位置:kernel-6.1/drivers/usb/gadget/

drivers/usb/gadget/
├── composite.c          ← Composite 框架核心(组合多个 Function)
├── config.c             ← USB Configuration 管理
├── configfs.c           ← configfs 接口(用户空间配置 Gadget)
├── configfs.h
├── epautoconf.c         ← 端点自动配置
├── functions.c          ← Function 注册管理
├── u_f.c / u_f.h        ← 通用工具函数
├── u_os_desc.h          ← OS 描述符支持
├── usbstring.c          ← USB 字符串描述符处理
├── Kconfig              ← 内核配置选项
├── Makefile
│
├── function/            ← ★ Function 驱动(每种模拟设备一个)★
│   ├── f_mass_storage.c    → U盘
│   ├── f_hid.c             → 键盘/鼠标
│   ├── f_uvc.c             → USB 摄像头
│   ├── f_acm.c             → 虚拟串口
│   ├── f_rndis.c           → Windows 网卡
│   ├── f_ecm.c             → Linux/Mac 网卡
│   ├── f_ncm.c             → 高速网卡
│   ├── f_uac1.c            → USB 音频 1.0
│   ├── f_uac2.c            → USB 音频 2.0
│   ├── f_midi.c            → MIDI 乐器
│   ├── f_printer.c         → USB 打印机
│   ├── f_serial.c          → 通用串口
│   ├── f_eem.c             → 简化网卡
│   ├── f_subset.c          → 最简网卡
│   ├── f_obex.c            → OBEX 交换
│   ├── f_phonet.c          → Nokia 电话协议
│   ├── f_fs.c              → FunctionFS(用户空间自定义)
│   ├── f_loopback.c        → 回环测试
│   ├── f_sourcesink.c      → 源/汇测试
│   └── f_tcm.c             → SCSI 存储目标
│
├── legacy/              ← 预组合的完整 Gadget 驱动
│   ├── mass_storage.c      → g_mass_storage(纯U盘)
│   ├── ether.c             → g_ether(纯网卡)
│   ├── serial.c            → g_serial(纯串口)
│   ├── hid.c               → g_hid(纯HID)
│   ├── audio.c             → g_audio(纯音频)
│   ├── webcam.c            → g_webcam(纯摄像头)
│   ├── printer.c           → g_printer(纯打印机)
│   ├── midi.c              → g_midi(纯MIDI)
│   ├── multi.c             → g_multi(多功能组合)
│   ├── acm_ms.c            → g_acm_ms(串口+U盘)
│   ├── ncm.c               → g_ncm(NCM网卡)
│   ├── zero.c              → g_zero(测试用)
│   ├── raw_gadget.c        → raw_gadget(底层测试)
│   └── ...
│
└── udc/                 ← USB Device Controller 硬件驱动
    ├── core.c              → UDC 核心框架
    ├── ...(各平台 UDC 驱动)
    └── dummy_hcd.c         → 虚拟 HCD(测试用)

4. 可模拟的 USB 设备类型详解

4.1 USB 存储类(Mass Storage)

源码: function/f_mass_storage.c

模拟设备: U盘、移动硬盘、光驱

原理: 将开发板上的一个文件或块设备(如 SD 卡分区、eMMC 分区)通过 USB Mass Storage 协议暴露给 Host,Host 会将其识别为一个可移动磁盘。

Kconfig: CONFIG_USB_F_MASS_STORAGE

典型用途:

  • 将开发板的 SD 卡共享给 PC 访问
  • 制作 USB 启动盘
  • 嵌入式设备固件升级(将固件分区暴露为U盘)
# 示例:将 /dev/mmcblk1p1 共享为 U盘
echo /dev/mmcblk1p1 > /config/usb_gadget/g1/functions/mass_storage.0/lun.0/file

还有一个更高级的存储 Gadget:f_tcm.c,基于 Linux 内核的 TCM(Target Core Module)框架,支持 UAS(USB Attached SCSI)协议,性能更好,支持 USB 3.0 流。

4.2 USB 人机接口类(HID)

源码: function/f_hid.c

模拟设备: USB 键盘、USB 鼠标、USB 游戏手柄、USB 触摸屏

原理: HID 是 USB 协议中最简单的设备类之一。Gadget 端注册一个 /dev/hidgX 设备节点,用户空间向其写入 HID 报告描述符对应的数据,Host 就会将其解释为键盘按键、鼠标移动等。

Kconfig: CONFIG_USB_F_HID

典型用途:

  • 开发板模拟键盘自动输入字符
  • 开发板模拟鼠标控制 PC
  • 自定义 HID 设备(如 USB 按钮、旋钮)
  • BadUSB 安全研究
# 示例:模拟键盘,向 Host 发送 "Hello"
echo -n "Hello" > /dev/hidg0

4.3 USB 摄像头类(UVC)

源码: function/f_uvc.c

模拟设备: USB 摄像头/网络摄像头

原理: 通过 UVC(USB Video Class)协议,将开发板采集的视频帧通过 USB 发送给 Host。Host 端的 UVC 驱动会自动识别,创建 /dev/videoX 节点。详见 0204 文档

Kconfig: CONFIG_USB_F_UVC

典型用途:

  • 将 MIPI CSI 摄像头的画面通过 USB 传给 PC
  • 将开发板屏幕内容作为 USB 摄像头输出
  • 远程监控/视频会议
  • 机器视觉系统(开发板处理图像后通过 UVC 输出)

4.4 USB 串口类(CDC ACM / Serial)

源码: function/f_acm.cfunction/f_serial.c

模拟设备: USB 虚拟串口(COM 口)

原理: CDC ACM(Abstract Control Model)是 USB 通信设备类的一种,模拟标准串口。Host 端会加载 cdc-acm 驱动,创建 /dev/ttyACMx 设备节点。

Kconfig: CONFIG_USB_F_ACMCONFIG_USB_F_SERIAL

两者区别:

特性f_acm (CDC ACM)f_serial (Generic Serial)
协议标准 CDC ACM简单 Bulk 传输
Host 驱动cdc-acm(系统自带)需要专用驱动
控制信号支持 DTR/RTS/CTS 等
兼容性Windows/Linux/Mac 通用仅 Linux

典型用途:

  • 开发板通过 USB 给 PC 提供串口控制台
  • 两个 Linux 设备之间通过 USB 串口通信
  • 嵌入式设备固件调试

4.5 USB 网络类(RNDIS / ECM / NCM / EEM)

这是最复杂的一类,有多种协议可选:

4.5.1 RNDIS(Remote NDIS)

源码: function/f_rndis.c

模拟设备: USB 网卡(Windows 兼容)

Kconfig: CONFIG_USB_F_RNDIS

特点: 微软私有协议,Windows XP 及以上系统原生支持,无需安装驱动。是与 Windows 通信的首选。

4.5.2 CDC ECM(Ethernet Control Model)

源码: function/f_ecm.c

模拟设备: USB 网卡(Linux/Mac 兼容)

Kconfig: CONFIG_USB_F_ECM

特点: 标准 CDC 协议,Linux 和 macOS 原生支持,Windows 不支持。

4.5.3 CDC NCM(Network Control Model)

源码: function/f_ncm.c

模拟设备: 高速 USB 网卡

Kconfig: CONFIG_USB_F_NCM

特点: ECM 的升级版,支持将多个以太网帧打包到一个 USB 传输中,性能最好。4G/5G 模块常用此协议。

4.5.4 CDC EEM(Ethernet Emulation Model)

源码: function/f_eem.c

模拟设备: 简化 USB 网卡

Kconfig: CONFIG_USB_F_EEM

特点: 比 ECM 更简单,对硬件要求更低。

4.5.5 CDC Subset(最小以太网)

源码: function/f_subset.c

模拟设备: 最简 USB 网卡

Kconfig: CONFIG_USB_F_SUBSET

特点: 最精简的以太网实现,适用于硬件能力有限的控制器。

网络类协议对比:

协议WindowsLinuxmacOS性能复杂度
RNDIS原生支持需 rndis_host不支持
ECM不支持原生支持原生支持
NCMWin10+原生支持原生支持
EEM不支持原生支持不支持
Subset不支持原生支持不支持最低

典型用途:

  • 开发板通过 USB 共享网络给 PC(USB 网络共享)
  • 开发板通过 USB 连接 PC 进行 SSH/FTP 等网络操作
  • Android 手机的 USB 网络共享(USB Tethering)

4.6 USB 音频类(UAC 1.0 / 2.0)

源码: function/f_uac1.cfunction/f_uac2.c

模拟设备: USB 声卡/USB 音频设备

Kconfig: CONFIG_USB_F_UAC1CONFIG_USB_F_UAC2

两者区别:

特性UAC 1.0 (f_uac1)UAC 2.0 (f_uac2)
最大采样率96kHz384kHz
最大位深24-bit32-bit
通道数有限更多
虚拟 ALSA 声卡
需要硬件 codec否(虚拟)否(虚拟)

另外还有一个 f_uac1_legacy.c,它需要真实的音频编解码器硬件配合。

典型用途:

  • 开发板作为 USB 声卡,PC 通过它播放/录制音频
  • USB 音频流传输
  • 专业音频设备

4.7 USB MIDI 类

源码: function/f_midi.c

模拟设备: USB MIDI 乐器/控制器

Kconfig: CONFIG_USB_F_MIDI

典型用途:

  • 开发板模拟 MIDI 键盘/控制器
  • 连接音乐制作软件
  • MIDI 信号路由/转换

4.8 USB 打印机类

源码: function/f_printer.c

模拟设备: USB 打印机

Kconfig: CONFIG_USB_F_PRINTER

原理: 注册 /dev/g_printerX 设备节点,Host 发送的打印数据会写入该节点,用户空间程序读取并处理。

典型用途:

  • 模拟 USB 打印机接收打印任务
  • 测试 Host 端打印机驱动
  • 打印任务拦截/转发

4.9 USB OBEX 类

源码: function/f_obex.c

模拟设备: OBEX 文件交换设备

Kconfig: CONFIG_USB_F_OBEX

典型用途:

  • 类似蓝牙 OBEX 的文件传输
  • 手机与 PC 之间的文件交换

4.10 USB Phonet 类

源码: function/f_phonet.c

模拟设备: Nokia Phonet 蜂窝调制解调器

Kconfig: CONFIG_USB_F_PHONET

说明: 专用于 Nokia N900 等老款手机的蜂窝调制解调器通信协议,目前很少使用。

4.11 FunctionFS(用户空间自定义)

源码: function/f_fs.c

模拟设备: 任意 USB 设备(由用户空间定义)

Kconfig: CONFIG_USB_F_FS

原理: FunctionFS 提供了一个文件系统接口(/dev/usb-ffs/),允许用户空间程序直接实现 USB 设备的描述符和数据处理逻辑,无需编写内核驱动。

典型用途:

  • Android ADB(Android Debug Bridge)
  • MTP(Media Transfer Protocol,媒体传输协议)
  • 任何需要在用户空间实现的 USB 协议
# FunctionFS 目录结构
/dev/usb-ffs/adb/
├── ep0          ← 控制端点(描述符读写)
├── ep1          ← Bulk IN 端点
└── ep2          ← Bulk OUT 端点

4.12 测试用 Gadget

Gadget Zero(回环/源汇测试)

源码: function/f_loopback.cfunction/f_sourcesink.c

用途: 用于测试 USB 控制器硬件和驱动的正确性。Host 端使用 usbtest 驱动配合测试。

  • f_loopback.c:将收到的数据原样回传(Loopback)
  • f_sourcesink.c:一端产生数据(Source),另一端消耗数据(Sink)
Raw Gadget

源码: legacy/raw_gadget.c

用途: 提供最底层的 USB Gadget 访问接口,允许用户空间完全控制 USB 通信过程。用于 USB 协议安全研究、Fuzzing 测试。

5. Legacy 预组合 Gadget 驱动

legacy/ 目录下的驱动是将多个 Function 组合在一起的"开箱即用"方案:

模块名源码组合内容用途
g_mass_storagemass_storage.cMass Storage纯 U盘
g_etherether.cRNDIS + ECM + EEM + Subset纯网卡
g_serialserial.cACM + Serial + OBEX纯串口
g_hidhid.cHID纯 HID 设备
g_audioaudio.cUAC 1.0/2.0纯音频
g_webcamwebcam.cUVC + UAC纯摄像头
g_printerprinter.cPrinter纯打印机
g_midigmidi.cMIDI纯 MIDI
g_ncmncm.cNCMNCM 网卡
g_multimulti.cRNDIS + ACM + Mass Storage多功能组合
g_acm_msacm_ms.cACM + Mass Storage串口+U盘
g_zerozero.cLoopback + SourceSink测试用

现代推荐: 使用 configfs 方式动态配置,而不是加载 legacy 模块。configfs 允许在运行时自由组合多个 Function,更灵活。

6. configfs 动态配置方式

6.1 基本流程

# 1. 挂载 configfs
mount -t configfs none /config
mkdir -p /config/usb_gadget/g1

# 2. 设置 USB VID/PID
echo 0x1d6b > /config/usb_gadget/g1/idVendor   # Linux Foundation
echo 0x0104 > /config/usb_gadget/g1/idProduct   # Multifunction Composite Gadget

# 3. 创建 Function 实例(可创建多个)
mkdir /config/usb_gadget/g1/functions/acm.usb0      # 串口
mkdir /config/usb_gadget/g1/functions/rndis.usb0     # 网卡
mkdir /config/usb_gadget/g1/functions/mass_storage.0 # U盘

# 4. 配置 U盘后端
echo /dev/mmcblk1p1 > /config/usb_gadget/g1/functions/mass_storage.0/lun.0/file

# 5. 创建 Configuration 并绑定 Function
mkdir /config/usb_gadget/g1/configs/c.1
ln -s /config/usb_gadget/g1/functions/acm.usb0      /config/usb_gadget/g1/configs/c.1/
ln -s /config/usb_gadget/g1/functions/rndis.usb0     /config/usb_gadget/g1/configs/c.1/
ln -s /config/usb_gadget/g1/functions/mass_storage.0 /config/usb_gadget/g1/configs/c.1/

# 6. 绑定到 UDC(USB Device Controller)
echo <udc_name> > /config/usb_gadget/g1/UDC

6.2 查看可用的 UDC

ls /sys/class/udc/
# RK3588 上通常显示:fe8a0000.usb 或类似名称

7. 与 RK3588 硬件的关系

RK3588 芯片内部集成了 DesignWare DWC3 USB 3.0 控制器,支持 Host/Device/OTG 三种模式。Linux 内核中对应的驱动在 drivers/usb/dwc3/ 目录下。

RK3588 USB OTG 口
    │
    ├── 硬件:DWC3 USB 3.0 控制器
    │
    ├── 内核驱动:drivers/usb/dwc3/
    │
    ├── Gadget 框架:drivers/usb/gadget/
    │   ├── composite.c    → 组合框架
    │   ├── function/      → 各种 Function 驱动
    │   └── configfs.c     → 用户空间配置接口
    │
    └── 用户空间工具:
        ├── configfs 直接配置
        ├── libusbgx(USB Gadget 扩展库)
        └── gt(Gadget 工具)

8. LubanCat 设备树中的 OTG 配置分析

8.1 RK3588/RK3588S 的 USB 控制器全貌

通过分析设备树源码,RK3588 芯片共有 4 个 USB 控制器,但只有 2 个 DWC3 控制器支持 OTG/Device 模式:

控制器设备树节点类型dr_mode支持 Gadget用途
DWC3_0usbdrd_dwc3_0DWC3otgOTG 口(Type-C)
DWC3_1usbdrd_dwc3_1DWC3host否(默认)USB 3.0 Type-A 口
EHCI_0/OHCI_0usb_host0EHCI/OHCIhostUSB 2.0 Type-A 口
EHCI_1/OHCI_1usb_host1EHCI/OHCIhostUSB 2.0 Type-A 口

关键区别:

  • DWC3 控制器snps,dwc3):支持 Host/Device/OTG 三种模式,通过 dr_mode 属性切换
  • EHCI/OHCI 控制器:硬件上只支持 Host 模式,无法用于 Gadget

8.2 基础 dtsi 中的默认配置

rk3588s.dtsi:2577 中,DWC3_0 的默认配置:

usbdrd_dwc3_0: usb@fc000000 {
    compatible = "snps,dwc3";
    dr_mode = "otg";                    ← 默认为 OTG 模式
    phys = <&u2phy0_otg>, <&usbdp_phy0_u3>;
    phy-names = "usb2-phy", "usb3-phy";
    status = "disabled";                ← 默认禁用,需要板级 DTS 启用
};

rk3588.dtsi:102 中,DWC3_1 的默认配置:

usbdrd_dwc3_1: usb@fc400000 {
    compatible = "snps,dwc3";
    dr_mode = "host";                   ← 默认为 Host 模式
    phys = <&u2phy1_otg>, <&usbdp_phy1_u3>;
    status = "disabled";
};

8.3 LubanCat 各板型的 OTG 启用情况

分析各板型 DTS 文件中对 usbdrd_dwc3_0 的配置:

板型DTS 文件DWC3_0 dr_modeOTG 启用
LubanCat 4rk3588s-lubancat-4.dts:1368otg
LubanCat 4IOrk3588s-lubancat-4io.dts:1477otg
LubanCat 5rk3588-lubancat-5.dts:1385otg
LubanCat 5IOrk3588-lubancat-5io.dts:1411otg
LubanCat 5IOIrk3588-lubancat-5ioi.dtsotg
LubanCat 5-v2rk3588-lubancat-5-v2.dtsotg
genericrk3588-lubancat-generic.dts未配置(需手动启用)

rk3588s-lubancat-4io.dts:1472 为例:

/* USB3.0 OTG0 Controller  */
&usbdrd3_0 {
    status = "okay";                    ← 启用 DWC3_0 控制器
};

&usbdrd_dwc3_0 {
    dr_mode = "otg";                    ← 设置为 OTG 模式
    usb-role-switch;                    ← 启用角色自动切换
    status = "okay";

    port {
        dwc3_0_role_switch: endpoint@0 {
            remote-endpoint = <&usbc0_role_sw>;  ← 连接 Type-C 控制器
        };
    };
};

8.4 LubanCat 的 USB 接口总结

LubanCat 开发板(以 LubanCat 4IO 为例)
    │
    ├── USB 3.0 Type-C 口(OTG)
    │   ├── 控制器:DWC3_0 (usbdrd_dwc3_0)
    │   ├── dr_mode = "otg"
    │   ├── 支持 Host + Device 双角色
    │   ├── ★ 可以加载 Gadget 驱动,模拟 USB 外设 ★
    │   └── UDC 名称:通过 ls /sys/class/udc/ 查看
    │
    ├── USB 3.0 Type-A 口
    │   ├── 控制器:DWC3_1 (usbdrd_dwc3_1)
    │   ├── dr_mode = "host"
    │   └── 仅支持 Host(接U盘/摄像头等)
    │
    └── USB 2.0 Type-A 口(如有)
        ├── 控制器:EHCI/OHCI
        └── 仅支持 Host

结论:LubanCat 各板型只有 Type-C(OTG)口支持 Gadget 模式,可以模拟 USB 外设。其他 USB-A 口只能作为 Host 使用。

9. 总结

┌──────────────────────────────────────────────────────────────────┐
│                    USB Gadget 可模拟的设备总览                     │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  存储类     │ f_mass_storage → U盘/移动硬盘/光驱                  │
│            │ f_tcm          → 高速 SCSI 存储(UAS)               │
│                                                                  │
│  人机接口   │ f_hid          → 键盘/鼠标/游戏手柄/触摸屏           │
│                                                                  │
│  视频类     │ f_uvc          → USB 摄像头                         │
│                                                                  │
│  串口类     │ f_acm          → CDC ACM 虚拟串口                   │
│            │ f_serial       → 通用串口                            │
│                                                                  │
│  网络类     │ f_rndis        → Windows 网卡                       │
│            │ f_ecm          → Linux/Mac 网卡                     │
│            │ f_ncm          → 高速网卡(4G/5G)                   │
│            │ f_eem          → 简化网卡                            │
│            │ f_subset       → 最简网卡                            │
│                                                                  │
│  音频类     │ f_uac1         → USB 音频 1.0                       │
│            │ f_uac2         → USB 音频 2.0(高清)                │
│            │ f_midi         → MIDI 乐器接口                       │
│                                                                  │
│  打印类     │ f_printer      → USB 打印机                         │
│                                                                  │
│  其他       │ f_fs           → FunctionFS(用户空间自定义)        │
│            │ f_obex         → OBEX 文件交换                       │
│            │ f_phonet       → Nokia 蜂窝调制解调器                 │
│            │ f_loopback     → 回环测试                            │
│            │ f_sourcesink   → 源/汇测试                           │
│                                                                  │
│  总计:21 个 Function 驱动,12 个预组合 Legacy 驱动                │
└──────────────────────────────────────────────────────────────────┘

回答你的问题:是的,drivers/usb/gadget/ 目录就是专门用于让 USB OTG 口模拟各种 USB 外设的。 Linux 内核提供了 21 种 Function 驱动,可以模拟 U盘、网卡、摄像头、串口、声卡、键盘鼠标、打印机、MIDI 乐器等几乎所有标准 USB 设备类型。通过 configfs 还可以将多个 Function 组合在一起,让开发板同时模拟多种设备(如同时当 U盘 + 网卡 + 串口)。

但请注意:只有 OTG 口(Type-C)才能使用这些 Gadget 功能。 LubanCat 各板型的 Type-C 口背后是 DWC3 控制器,支持 dr_mode = "otg",可以切换为 Device 模式;而普通 USB-A 口背后的 EHCI/xHCI 控制器只支持 Host 模式,无法用于 Gadget。在使用前,请确认你的设备树中已正确启用 OTG 控制器(status = "okay"dr_mode = "otg")。

10. 参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值