跳到主要内容

USB

本章节将讲解如何在 T153MX Tina Linux 中配置 USB Host、Device 与 OTG 功能,并通过设备节点、内核日志和端到端传输验证配置结果。

文档说明
  • 原始页数: 44 页
  • 文档版本: 2.5
  • 发布日期: 2025-07-29
  • 原始文件: 查看或下载 PDF

正文以原始 PDF 为技术依据,并补充 T153MX USB 实验的连接要求、执行位置和结果判断。

目标

正确选择 USB 角色,完成内核和设备树配置,并通过一次端到端数据操作验证 T153MX USB 功能。

准备工作

硬件: T153MX 开发板、数据功能正常的 USB 线、与测试角色匹配的 U 盘或 USB 主机。确认接口供电方向,禁止两个供电端直接对接。

软件: 当前板级设备树、Kernel USB 配置、rootfs 中的 setusbconfig/ADB/MTP 工具,以及可查看串口日志的终端。

操作步骤与前置确认

  1. 确认测试的是 Host、Device 还是 OTG,三者的供电和设备角色不同。
  2. 确认命令运行在 SDK 根目录还是开发板 Linux Shell。
  3. 记录插拔前后的 dmesg,不要先清空系统日志。
  4. 检查 USB 端口是否与其他板载功能复用。

验证方法与顺序

依次检查控制器驱动、角色状态、设备枚举、设备节点和实际数据传输。只看到 USB 插入日志不代表功能完成,必须执行一次可观察的读写、ADB 连接或 MTP 传输。

T153MX 首次排查命令

以下命令在开发板 Linux Shell执行,不是在 Ubuntu 主机执行:

dmesg | grep -Ei 'usb|udc|musb|ehci|ohci'
ls -l /sys/class/udc 2>/dev/null
ls -l /sys/bus/usb/devices
ls -l /dev/bus/usb 2>/dev/null

判断顺序如下:

命令输出会随 Host、Device 或 OTG 角色变化。当前资料未确认 OmniGate 每个外露 USB 连接器的供电与复用关系,具体口位和跳帽请以对应批次原理图为准;不能仅根据 SoC 支持能力推断板级接口。

1 概述

1.1 编写目的

介绍全志USB 模块的使用方法。

1.2 适用范围

该文档适用平台如下表所示:

表1-1: 文档使用平台列表

平台内核版本
R528Linux-5.4
3Linux-5.4
T113Linux-5.4
MR527Linux-5.15
AI985Linux-5.15
MR536Linux-5.15
V821Linux-5.4
MR153Linux-5.15

1.3 相关人员

USB 驱动和应用开发人员。

2 模块介绍

USB 有主机功能和从设备功能。做主机时,能连接U 盘、USB 鼠标等USB 设备;做从设备时,具有ADB 调试等从设备功能。

芯片硬件上支持USB device/Host(OHCI/EHCI)。

2.1 相关术语介绍

术语解释
USBUniversal Serial Bus, 通用串行总线
OTGOn-The-Go
ADBAndroid Debug Bridge,Android 调试桥

HostControllerDriver,主机控制器驱动

UDCUSB Device Controller, USB 设备控制器
HCIHost Controller Interface,主机控制器接口
EHCIEnhanced Host Controller Interface,增强型主机控制器接口
OHCIOpen Host Controller Interface,开放式主机控制器接口

2.2 模块配置

2.2.1 Device Tree配置(Linux-4.9内核)

USB0 配置:

usbc0:usbc0@0 {
device_type = "usbc0";
usb_port_type = <0x2>;
usb_detect_type = <0x1>;
usb_id_gpio = <&pio PB 3 0 0 0xffffffff 0xffffffff>;
usb_det_vbus_gpio = <&pio PB 3 0 0 0xffffffff 0xffffffff>;
usb_regulator_io = "nocare";
usb_wakeup_suspend = <0>;
usb_serial_unique = <0>;
usb_serial_number = "20080411";
rndis_wceis = <1>;
status = "okay";
};
参数功能
usb_port_typeUSB 模式。0:device; 1:host; 2:OTG
usb_detect_typeUSB 检测类型。0:none; 1:vbus/id detect; 2:id/dpdm。1 是使

用GPIO 去检测,需要与usb_id_gpio 配合使用。2 是使用

PMU 去检测,需要配合det_vbus_supply 使用。
usb_detect_modeUSB ID 脚检测模式。0: 线程轮询; 1: 中断检测; 默认为0。
usb_id_gpioUSB ID 脚配置。若usb_detect_type 配置为1,这里则使用对

应gpio。若usb_detect_type 配置为2,这里则不需要配置。

usb_det_vbus_gpio USB VBUS 检测引脚配置; 一般使用对应gpio 即可;注意,如

果方案不需要检测VBUS,那么这里请填写USB ID 脚, 如果方案由PMU 检测VBUS, 那么这里请填写“axp_ctrl”。

det_vbus_supply与usb_det_vbus_gpio 类似,用于检测VBUS 是否存在。它会

指向usb_power_supply 节点。

_regulator_ioIO 的供电,如果没有则“nocare”。
usb_wakeup_suspend是否支持USB 唤醒。如果需要支持进入深度休眠后的USB 唤

醒,则置为1。

usb_serial_unique是否使用唯一序列号(由芯片chipid 得到)。
usb_serial_number如果usb_serial_unique 为0,那么使用这里的配置的值作为

序列号。

status是否启用该模块。“okay”: 启用; “disabled”: 关闭。

说明

若usb_detect_type
(即使用PMU 检测),且同时外部硬件接口为
usbtype-c 接口。需要注意使能
cc 协议识别功

能。

如果PMU 使用的是全志的AXP 芯片,那么就需要在PMU 驱动的dts 配置中,将pmu_usb_typec_used 配置成1,否则,pmu 可能无法正常检测到cc 的状态,从而otg 无法正常自动切换。配置示例:

&usbc0 {
device_type = "usbc0";
usb_port_type = <0x2>;
usb_detect_type = <0x2>;
usb_detect_mode = <0x0>;
usb_id_gpio;
usb_det_vbus_gpio = "axp_ctrl";
det_vbus_supply = <&usb_power_supply>;
usb_regulator_io = "nocare";
usb_wakeup_suspend = <0>;
usb_serial_unique = <0>;
usb_serial_number = "20080411";
status = "okay";
};
usb_power_supply:usb_power_supply {
......
pmu_usb_typec_used = <1>;
......
};

XP 芯片的配置方法,详情可以参考文档《Tina_Linux_电源管理_ 开发指南》。

如果使用的是其他PMU 芯片,需要注意使能cc 协议识别功能。

det_vbus_supply 存在的作用:

  1. 如果usb_det_vbus_gpio 设置的是axp_ctrl, 那么这里用于获取power_supply 来检测vbus 是

否存在。

  1. 卸载device 驱动时,需要获取power_supply,然后设置限流值。
有些时候,还需要对udc进行配置:
udc:udc-controller@0x05100000 {
_vbus_supply=<&usb_power_supply>;
这里det_vbus_supply同样指向usb_power_supply节点, 这里的目的是让udc获取到usb power, 并设置限流值。
udc驱动中会检测到USB接入的是PC,然后软件设置USB限流值。
如果PMU支持并开启了BC1.2协议(识别USB的类型并且硬件上自动设置限流值),那么这里就不需要配置。

无论是USB0 还是USB1, EHCI/OHCI 的配置都是类似的, 具体EHCI/OHCI 配置如下:

ehci0:ehci0-controller@0x04101000 {
drvvbus-supply = <&reg_drivevbus>;
};
ohci0:ohci0-controller@0x04101400 {
drvvbus-supply = <&reg_drivevbus>;
};

这里reg_drivevbus 主要配置对应的regulator 作为OTG_5V 供电。常见的配置有:

使用PMU自带的DRVVBUS引脚使能对应的5V输出:
regulator0: regulators@0 {
reg_drivevbus: drivevbus {
regulator-name = "axp2585-drivevbus";
};
};

使用GPIO去控制5V输出:

reg_usb0_vbus: usb0-vbus {
compatible = "regulator-fixed";
gpio = <&pio PH 12 1 2 0 0>;
regulator-name = "usb0-vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
enable-active-high;
};

USB1 配置:

usbc1:usbc1@0 {
device_type = "usbc1";
usb_regulator_io = "nocare";
usb_wakeup_suspend = <0>;
status = "okay";
};
与USB0 类似,但少了UDC 相关部分:
参数功能
usb_regulator_ioIO 的供电,如果没有则“nocare”
usb_wakeup_suspend是否支持USB 唤醒; 如果需要支持进入深度休眠后的USB 唤醒,则

置为1

status是否启用该模块。“okay”: 启用; “disabled”: 关闭

2.2.2 Device Tree配置(Linux-5.4内核)

5.4 内核下,USB 的DTS 配置有些许不同,主要是gpio 的配置存在差异。

USB0 配置:

usbc0:usbc0@0 {
device_type = "usbc0";
usb_port_type = <0x2>;
usb_detect_type = <0x1>;
usb_id_gpio = <&pio PD 21 GPIO_ACTIVE_HIGH>;
enable-active-high;
usb_det_vbus_gpio = <&pio PD 20 GPIO_ACTIVE_HIGH>;
usb_wakeup_suspend = <0>;
usb_serial_unique = <0>;
usb_serial_number = "20080411";
rndis_wceis = <1>;
status = "okay";
};

功能

usb_port_typeUSB 模式。0:device; 1:host; 2:OTG
usb_detect_typeUSB 检测类型。0:none; 1:vbus/id detect; 2:id/dpdm。1 是使

用GPIO 去检测,需要与usb_id_gpio 配合使用。2 是使用PMU 去检测,需要配合det_vbus_supply 使用。

usb_detect_modeUSB ID 脚检测模式。0: 线程轮询; 1: 中断检测; 默认为0。
usb_id_gpioUSB ID 脚配置。若usb_detect_type 配置为1,这里则使用对

应gpio。若usb_detect_type 配置为2,这里则不需要配置。

usb_det_vbus_gpioUSB VBUS 检测引脚配置; 一般使用对应gpio 即可;注意,如
果方案不需要检测VBUS,那么这里请填写USBID 脚, 如果方

案由PMU 检测VBUS, 那么这里请填写“axp_ctrl”。

det_vbus_supply与usb_det_vbus_gpio 类似,用于检测VBUS 是否存在。它会

指向usb_power_supply 节点。

usb_wakeup_suspend是否支持USB 唤醒。如果需要支持进入深度休眠后的USB 唤

醒,则置为1。

usb_serial_unique是否使用唯一序列号(由芯片chipid 得到)。
usb_serial_number如果usb_serial_unique 为0,那么使用这里的配置的值作为

序列号。

us是否启用该模块。“okay”: 启用;“disabled”:关闭。

说明

若usb_detect_type 配置成2(即使用PMU 检测),且同时外部硬件接口为usb type-c 接口。需要注意使能cc 协议识别功能。

如果PMU 使用的是全志的AXP 芯片,那么就需要在PMU 驱动的dts 配置中,将pmu_usb_typec_used 配置成1,否则,pmu 可能无法正常检测到cc 的状态,从而otg 无法正常自动切换。配置示例:

&usbc0 {
e_type="usbc0";
usb_port_type = <0x2>;
usb_detect_type = <0x2>;
usb_detect_mode = <0x0>;
usb_id_gpio;
usb_det_vbus_gpio = "axp_ctrl";
det_vbus_supply = <&usb_power_supply>;
usb_regulator_io = "nocare";
usb_wakeup_suspend = <0>;
usb_serial_unique = <0>;
usb_serial_number = "20080411";
status = "okay";
};
usb_power_supply:usb_power_supply {
......
pmu_usb_typec_used = <1>;
......
};

全志AXP 芯片的配置方法,详情可以参考文档《Tina_Linux_ 电源管理_ 开发指南》。

如果使用的是其他PMU 芯片,需要注意使能cc 协议识别功能。

有些时候,还需要对udc进行配置:
udc:udc-controller@0x05100000 {
det_vbus_supply = <&usb_power_supply>;
};
这里det_vbus_supply同样指向
usb_power_supply节点, 这里的目的是让
udc获取到usbpower, 并设置限流值。
udc驱动中会检测到USB接入的是PC,然后软件设置USB限流值。
如果PMU支持并开启了BC1.2协议(识别USB的类型并且硬件上自动设置限流值),那么这里就不需要配置。

无论是USB0 还是USB1, EHCI/OHCI 的配置都是类似的, 具体EHCI/OHCI 配置如下:

ehci0:ehci0-controller@0x04101000 {
drvvbus-supply = <&reg_drivevbus>;
};
ohci0:ohci0-controller@0x04101400 {
drvvbus-supply = <&reg_drivevbus>;
};

这里reg_drivevbus 主要配置对应的regulator 作为OTG_5V 供电。常见的配置有:

使用PMU自带的DRVVBUS引脚使能对应的5V输出:
regulator0: regulators@0 {
reg_drivevbus: drivevbus {
regulator-name = "axp2585-drivevbus";
};
};
使用GPIO去控制5V输出:
reg_usb0_vbus: usb0-vbus {
compatible = "regulator-fixed";
regulator-name = "usb0-vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-enable-ramp-delay = <1000>;
gpio = <&pio PD 19 GPIO_ACTIVE_HIGH>;
ble-active-high;
};

USB1 配置:

usbc1:usbc1@0 {
device_type = "usbc1";
usb_regulator_io = "nocare";
usb_wakeup_suspend = <0>;
status = "okay";
};

配置与USB0 类似,但少了UDC 相关部分:

参数功能
usb_regulator_ioIO 的供电,如果没有则“nocare”
usb_wakeup_suspend是否支持USB 唤醒; 如果需要支持进入深度休眠后的USB 唤醒,则

置为1

status是否启用该模块。“okay”: 启用; “disabled”: 关闭

2.2.3 Device Tree配置(Linux-5.15及之后的内核)

与Linux-5.4 的配置方法一样,可以直接参考章节《Device Tree 配置(Linux-5.4 内核)》。

2.2.4 内核配置(Linux-4.9/Linux-5.4内核)

USB device 相关配置:

Device Drivers --->[] USB support ---><> USB Gadget Support --->

USB Peripheral Controller --->
*>SoftWinnerSUNXIUSBPeripheralController

USB Host 相关配置:

Device Drivers --->[] USB support ---><> Support for Host-side USB

<*>
EHCI HCD (USB 2.0) support
<*>
OHCI HCD (USB 1.1) support
<*>
SoftWinner SUNXI USB Host Controller support
<*>
SoftWinner SUNXI USB HCI
<*>
SoftWinner SUNXI USB EHCI0
<*>
SoftWinner SUNXI USB EHCI1
<*>
SoftWinner SUNXI USB OHCI0
<*>
SoftWinner SUNXI USB OHCI1

角色管理相关配置

Device Drivers --->[] USB support ---><> SUNXI USB2.0 Dual Role Controller support ---><*> SUNXI USB2.0 Manager

其他内核配置,例如gadget 驱动配置,请参考常用功能配置章节。

2.2.5 内核配置(Linux-5.15及之后的内核)

说明

由于Linux-5.15 及之后内核的AW 外设驱动代码存放在BSP 仓库中(TinaSDK/bsp),因此内核配置也有所改动。

USB device 相关配置:

Allwinner BSP --->Device Drivers --->

USB Drivers --->USB Device Drivers --->

<*> Allwinner USB Peripheral Controller

USB Host 相关配置:

Allwinner BSP --->Device Drivers --->

USB Drivers --->USB Host Controller Drivers --->

<*> Allwinner EHCI HCD
<*> Allwinner OHCI HCD
<*> Allwinner USB Host Controller
<*> Allwinner USB HCI
<*>
Allwinner USB EHCI0
<*>
Allwinner USB EHCI1
<*>
Allwinner USB OHCI0
<*>
Allwinner USB OHCI1

USB 角色管理相关配置:

nerBSP--->

Device Drivers --->USB Drivers --->

USB Device Drivers ---><*> Allwinner USB2.0 Dual Role Controller support --->

<*> Allwinner USB2.0 Manager
<*> Allwinner USB driver debug message
<*> Allwinner USB driver use adb source

其他内核配置,例如gadget 驱动配置,请参考常用功能配置章节。

2.3 代码结构

驱动的源代码位于内核drivers/usb 目录下,如下是sunxi 平台相关源码:

USB Host:

drivers/usb/host/
├──ehci_sunxi.c
├──ohci_sunxi.c
├──sunxi_hci.c
└──sunxi_hci.h

UDC 和Manager:

drivers/usb/sunxi_usb/
├──include
│ ├──sunxi_hcd.h
│ ├──sunxi_sys_reg.h
│ ├──sunxi_udc.h
│ ├──sunxi_usb_board.h
│ ├──sunxi_usb_bsp.h
│ ├──sunxi_usb_config.h
│ ├──sunxi_usb_debug.h
│ └──sunxi_usb_typedef.h
├──Kconfig
├──Makefile
├──manager
│ ├──usbc0_platform.c
│ ├──usbc_platform.h
│ ├──usb_hcd_servers.c
│ ├──usb_hcd_servers.h
──usb_hw_scan.c
│ ├──usb_hw_scan.h
│ ├──usb_manager.c
│ ├──usb_manager.h
│ ├──usb_msg_center.c
│ └──usb_msg_center.h
├──misc
│ └──sunxi_usb_debug.c
├──udc
│ ├──sunxi_udc_board.c
│ ├──sunxi_udc_board.h
│ ├──sunxi_udc.c
│ ├──sunxi_udc_config.h
│ ├──sunxi_udc_debug.c
│ ├──sunxi_udc_debug.h
│ ├──sunxi_udc_dma.c
──sunxi_udc_dma.h

└──usbc

├──usbc.c
├──usbc_dev.c
├──usbc_i.h
└──usbc_phy.c

3 常用功能配置

3.1 配置OTG功能

OTG 功能下,需要根据USB ID 脚去进行Device, Host 模式的切换;如果需要支持NULL 模式(既不加载Device 也不加载Host 驱动), 那么还需要VBUS 状态检测引脚。

到的主要改动点:

usb_port_type配置为2,即OTG模式。
usb_id_gpio配置对应的USB ID引脚。
usb_det_vbus_gpio, 需要根据实际情况进行配置:
1.如果需要检测VBUS状态,则按下面情况进行配置:
a.由gpio引脚进行检测。直接配置对应的gpio即可。
b.由我司PMU检测。填写"axp_ctrl"
2.如果不需要检测VBUS状态(缺少NULL模式)
那么直接填写USB ID的gpio配置(也就是VBUS与ID状态一致)。

otg 功能相关的调试节点,每个芯片平台的路径可能会不一样,具体可以通过find -name otg_role确认, 下面默认以/sys/devices/platform/soc/usbc0/otg_role 这个路径举例。

方法:

拔插OTG线, 并通过下面节点查询当前USB角色:
cat /sys/devices/platform/soc/usbc0/otg_role

调试方法:

确认当前角色:
cat /sys/devices/platform/soc/usbc0/otg_role
开启角色切换调试:
echo 1 > /sys/devices/platform/soc/usbc0/hw_scan_debug
会有下面类似打印:
Id=3,role=2

role表示当前角色,0:NULL; 1:HOST; 2:DEVICE

Id值,主要看低两位,bit0表示ID, bit1表示VBUS,
例如3表示ID脚为高,VBUS脚也为高, 所以当前应该为Device模式

Id 值的所有情况:

Id 值IDVBUS模式
0x0000Host
0x0110Null
d 值IDVBUS模式
0x0201Host
0x0311Device
  • ID 脚一般情况下为高电平,只有接入OTG 线时会拉低;

  • VBUS 为1 表示micro USB 口有接入外部电源;

  • 一般不会出现Id 值为0x02 的情况,这表示接入OTG 线,但是还检测到VBUS;

  • 如果没有VBUS 检测,Id 值就只有0x00 和0x03 两种情况, 也就是说要么加载device 驱动,要

么加载host 驱动; 这会带来一些影响:usb 相关时钟一直被打开,导致有一定功耗,以及硬件射

3.2 USB Gadget功能配置

USB Gadget 支持众多功能,它们的配置方法比较类似:

  • 内核配置选中对应功能。

  • 私有gadget 功能配置。通过configfs 创建对应的gadget 功能,并设置私有属性节点。

针对部分gadget 功能,我们在setusbconfig 脚本中封装了gadget 功能配置,可供参考,请看setusbconfig章节。

3.2.1 ADB功能配置

内核相关配置:

Device Drivers --->[] USB support ---><> USB Gadget Support ---><*> USB functions configurable through configfs

[*]
Function filesystem (FunctionFS)

Device Drivers --->Character devices --->

[*] Enable TTY
[*] Unix98 PTY support

[*] Networking support --->Networking options --->

<*> Unix domain sockets
[*] TCP/IP networking

No Location

CONFIG_NET

说明

若不选上TTY 相关配置,会导致
adbshell 无法使用。若不选上网络相关配置,会导致
adbd 运行失败,应用退出。

进入系统后输入setusbconfig adb 即可切换并配置为adb 模式。

setusbconfig 中adb 相关配置解析:

设置idVendor, idProduct:
echo 0x18d1 > /sys/kernel/config/usb_gadget/g1/idVendor
echo 0xD002 > /sys/kernel/config/usb_gadget/g1/idProduct
创建adb功能:
mkdir /sys/kernel/config/usb_gadget/g1/functions/ffs.adb
建立config软链接:
ys/kernel/config/usb_gadget/g1/functions/ffs.adb//sys/kernel/config/usb_gadget/g1/configs/c.1/ffs.adb
挂载functionfs:
mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb/
设置对应的UDC控制器名称:
udc_controller=`ls /sys/class/udc`
echo $udc_controller > /sys/kernel/config/usb_gadget/g1/UDC

使用方法:需要开机启动adbd 服务, 具体请参考ADB 功能章节。

3.2.2 MTP功能配置

相关配置:

Device Drivers --->[] USB support ---><> USB Gadget Support ---><*> USB functions configurable through configfs

[*]
MTP gadget

进入系统后输入setusbconfig mtp 即可切换并配置为mtp 模式。

setusbconfig 中mtp 相关配置解析:

设置idVendor, idProduct:
echo 0x045E > /sys/kernel/config/usb_gadget/g1/idVendor
echo 0x00C9 > /sys/kernel/config/usb_gadget/g1/idProduct
创建mtp功能:
mkdir /sys/kernel/config/usb_gadget/g1/functions/mtp.gs0
建立config软链接:
ln -s /sys/kernel/config/usb_gadget/g1/functions/mtp.gs0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/mtp.gs0
设置对应的UDC控制器名称:
udc_controller=`ls /sys/class/udc`
echo $udc_controller > /sys/kernel/config/usb_gadget/g1/UDC

使用方法:需要开机启动MtpDaemon 服务, 具体请参考MTP 功能章节。

3.2.3 Mass Storage功能配置

内核相关配置:

Device Drivers --->[] USB support ---><> USB Gadget Support ---><*> USB functions configurable through configfs

[*]
Mass storage

进入系统后输入setusbconfig mass_storage 即可切换并配置为mass_storage 模式。

setusbconfig 中mass_storage 相关配置解析:

设置idVendor, idProduct:
x1f3a>/sys/kernel/config/usb_gadget/g1/idVendor
x1000>/sys/kernel/config/usb_gadget/g1/idProduct
创建mass storage功能:
mkdir /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0
建立config软链接:
ln -s /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/f1
设置对应的UDC控制器名称:
udc_controller=`ls /sys/class/udc`
echo $udc_controller > /sys/kernel/config/usb_gadget/g1/UDC

使用方法:

把要挂载的块设备写入file节点中:
dev/by-name/boot-res>/sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/file
卸载:
echo "" > /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/file

说明

  1. setusbconfig 脚本中,块设备名称默认为/dev/by-name/boot-res,需要根据实际情况将对应设备路径修改到setusbcon-

fig 脚本中。

  1. 在将块设备映射到mass storage 之前,需要确保当前块设备未被挂载,否则可能会造成文件系统异常!因此建议在运
行setusbconfig mass_stotage之前再运行一个umount /dev/by-name/boot-res。

磁盘映射PC 端成功后,还可以通过如下命令行自行配置所映射的分区(自行写脚本传参)。

echo none > /sys/kernel/config/usb_gadget/g1/UDC //disable掉udc功能
echo "/dev/sda" > /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/file //设置映射分区
ls/sys/class/udc`>/sys/kernel/config/usb_gadget/g1/UDC//
重新enableudc功能。

3.2.4 RNDIS功能配置

内核相关配置:

Device Drivers --->[*] USB support --->

<*> USB Gadget Support --->

<*> USB functions configurable through configfs
RNDIS

进入系统后输入setusbconfig rndis 即可切换并配置为rndis 模式。

setusbconfig 中rndis 相关配置解析:

设置idVendor, idProduct:
echo 0x0525 > /sys/kernel/config/usb_gadget/g1/idVendor
echo 0xa4a2 > /sys/kernel/config/usb_gadget/g1/idProduct
创建rndis功能:
mkdir /sys/kernel/config/usb_gadget/g1/functions/rndis.usb0
建立config软链接:
ln -s /sys/kernel/config/usb_gadget/g1/functions/rndis.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/rndis.usb0
设置对应的UDC控制器名称:
udc_controller=`ls /sys/class/udc`
echo $udc_controller > /sys/kernel/config/usb_gadget/g1/UDC

使用方法:

通过ifconfig命令确认是否新增了网卡设备。

如果没有可以输入下面命令开启网卡:ifconfig usb0 up

并通过ifconfig分别设置设备端以及host端网卡的ip,确保在同一个局域网内,并ping测试连通性:
设备端:
ifconfig usb0 192.168.10.5
Host端:i
genp0s20u3192.168.10.6
92.168.10.5

iperf 测试:

设备端:
iperf -c 192.168.10.6 -t 100 -i 2 -p 5004
Host端:
iperf -s 192.168.10.5 -t 100 -i 2 -p 5004
设备端的测试结果:
root@TinaLinux:/# iperf -c 192.168.10.6 -t 100 -i 2 -p 5004
------------------------------------------------------------
Client connecting to 192.168.10.6, TCP port 5004
indowsize:85.0KByte(default)
------------------------------------------------------------
[ 3] local 192.168.10.5 port 37656 connected with 192.168.10.6 port 5004
[ ID] Interval
Transfer
Bandwidth
[ 3] 0.0- 2.0 sec 19.4 MBytes 81.3 Mbits/sec

3.2.5 UAC1功能配置

内核相关配置:

Device Drivers --->[] USB support ---><> USB Gadget Support ---><*> USB functions configurable through configfs

[*]
Audio Class 1.0

进入系统后输入setusbconfig uac1 即可切换并配置为uac 模式。

setusbconfig 中uac1 相关配置解析:

设置idVendor, idProduct:
echo 0x1d61 > /sys/kernel/config/usb_gadget/g1/idVendor
echo 0x0101 > /sys/kernel/config/usb_gadget/g1/idProduct
创建uac1功能:
mkdir /sys/kernel/config/usb_gadget/g1/functions/uac1.usb0
设置UAC1私有属性节点:
设置通道数掩码,例如支持两通道:
echo 0x3 > /sys/kernel/config/usb_gadget/g1/functions/uac1.usb0/c_chmask
echo 0x3 > /sys/kernel/config/usb_gadget/g1/functions/uac1.usb0/p_chmask
注意我们默认代码UDC的endpoint中仅有一个ISO端点,所以只支持单项的同步传输,
默认会将p_chmask设置为0,也就是关闭playback通路
设置采样率:
echo 16000 > /sys/kernel/config/usb_gadget/g1/functions/uac1.usb0/p_srate
echo 48000 > /sys/kernel/config/usb_gadget/g1/functions/uac1.usb0/c_srate
建立config软链接:
ln -s /sys/kernel/config/usb_gadget/g1/functions/uac1.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/uac1.usb0

应的UDC控制器名称:

udc_controller=`ls /sys/class/udc`
echo $udc_controller > /sys/kernel/config/usb_gadget/g1/UDC

使用方法:

默认配置下,仅使能了c_chmask, 即PC端往小机端送音频数据,小机端播放出来

小机端执行setusbconfig uac1设置功能后,会在PC端枚举生成一个USB声卡, PC端选择使用该声卡进行播放
然后小机端执行下面命令:
arecord -Dhw:UAC1Gadget -f S16_LE -r 48000 -c 2 |aplay -f S16_LE -r 48000 -c 2
表示从虚拟声卡(拿到PC端送来的数据)录音,然后直接播放出来

3.2.6 HID功能配置

内核相关配置:

Device Drivers --->[] USB support ---><> USB Gadget Support ---><*> USB functions configurable through configfs

[*]
HID function

进入系统后输入setusbconfig hid 即可切换并配置为hid 模式。

setusbconfig 中hid 相关配置解析:

设置idVendor,idProduct:
echo 0x0525 > /sys/kernel/config/usb_gadget/g1/idVendor
echo 0xa4ac > /sys/kernel/config/usb_gadget/g1/idProduct
创建HID功能:
mkdir /sys/kernel/config/usb_gadget/g1/functions/hid.usb0
设置HID相关节点(根据实际HID功能进行配置,下面是模拟键盘的例子):
echo 1 > /sys/kernel/config/usb_gadget/g1/functions/hid.usb0/protocol
echo 8 > /sys/kernel/config/usb_gadget/g1/functions/hid.usb0/report_length
echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\
x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\
x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > /sys/kernel
/config/usb_gadget/g1/functions/hid.usb0/report_desc

onfig软链接:

ln -s /sys/kernel/config/usb_gadget/g1/functions/hid.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/hid.usb0
设置对应的UDC控制器名称:
udc_controller=`ls /sys/class/udc`
echo $udc_controller > /sys/kernel/config/usb_gadget/g1/UDC

使用方法:

设备端:setusbconfig hid设置gadget hid功能后,会生成/dev/hidgX节点,
其中,设置report_desc的内容用于描述hid设备,默认脚本中是一个键盘设备,因此会在Host端生成对应的/dev/input/
eventX节点,
通过该节点可以获取到对应的按键事件,例如用于检测是否能够获取到事件的简单命令:
Ubuntu(Host端):执行:sudo cat /dev/input/event16 |hexdump -C

另外,可以参考linux-x.x/Documentation/usb/gadget_hid.txt编译生成一个设备端的demo:hid_gadget_test去进行测试。

设备端执行的测试命令:
hid_gadget_test /dev/hidg0 keyboard
然后按下对应按键(串口输入字符给到hid_gadget_test然后write到hidg0节点中),观察PC端是否接受到对应消息。
最后,可以输入--quit退出测试应用

注意:

hid设备需要两个INT端点,而我们SDK一般默认只配置了一个,请参考《改UDC Endpoint配置》章节设置为两组INT端点的配

置。

3.2.7 printer功能配置

内核相关配置:

Device Drivers --->[] USB support ---><> USB Gadget Support ---><*> USB functions configurable through configfs

[*]
Printer function

进入系统后输入setusbconfig printer 即可切换并配置为printer 模式。

setusbconfig 中printer 相关配置解析:

设置idVendor,idProduct:
echo 0x0525 > /sys/kernel/config/usb_gadget/g1/idVendor
echo 0xa4a8 > /sys/kernel/config/usb_gadget/g1/idProduct
创建printer功能:
mkdir /sys/kernel/config/usb_gadget/g1/functions/printer.usb0
设置printer相关节点(根据实际进行设置,下面是例子):
echo "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;" > /sys/kernel/config/usb_gadget/g1/functions/printer.usb0/
pnp_string
echo 10 > /sys/kernel/config/usb_gadget/g1/functions/printer.usb0/q_len
建立config软链接:
ln -s /sys/kernel/config/usb_gadget/g1/functions/printer.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/printer.

usb0

设置对应的UDC控制器名称:
udc_controller=`ls /sys/class/udc`
echo $udc_controller > /sys/kernel/config/usb_gadget/g1/UDC

使用方法:

设置gadget printer功能后,会生成/dev/g_printer0节点,
然后可以参考linux-4.9/Documentation/usb/gadget_printer.txt里面的demo去进行测试。

3.2.8 多功能复合设备

场景需要同时使用多种USB 功能,同样可以通过configfs 进行配置,默认setusbconfig 脚本

中添加了adb 和mtp 功能的复合设备配置,进入系统后输入setusbconfig adb,mtp 可以进行切换。

脚本配置很简单, 把两个功能一起设置即可,其他复合设备可作参考:

[ -d /sys/kernel/config/usb_gadget/g1/functions/ffs.adb ] || {
mkdir /sys/kernel/config/usb_gadget/g1/functions/ffs.adb
}
echo "Tina ADB" > /sys/kernel/config/usb_gadget/g1/strings/0x409/product
[ -d /sys/kernel/config/usb_gadget/g1/functions/mtp.gs0 ] || {
mkdir /sys/kernel/config/usb_gadget/g1/functions/mtp.gs0
}
[ -d /dev/usb-ffs/mtp ] || {
mkdir-p/dev/usb-ffs
mkdir /dev/usb-ffs/mtp
mount -o rmode=0770,fmode=0660,uid=1024,gid=1024,no_disconnect=1 -t functionfs mtp /dev/usb-ffs/mtp/
}
ln -s /sys/kernel/config/usb_gadget/g1/functions/ffs.adb/ /sys/kernel/config/usb_gadget/g1/configs/c.1/ffs.adb
ln -s /sys/kernel/config/usb_gadget/g1/functions/$mtp_name/ /sys/kernel/config/usb_gadget/g1/configs/c.1/mtp.gs0

每个gadget 功能都对UDC 的endpoint 有要求,例如需要什么类型的ep, 多少个ep 等等,如果没有正确配置,那么gadget 驱动中申请ep 资源的时候就会失败,请根据需求改动udc ep 配置,具体请参考UDC Endponint 配置章节。

另外,对于任何USB 功能都对应有一个idVendor,idProduct,对于复合设备也一样,某些功能的

可能需要USBHost端根据id 去选择匹配驱动,否则无法正常使用的。

下面网址可以查询一些已经注册过的id:

http://www.linux-usb.org/usb.ids

3.3 修改UDC Endpoint配置

UDC 硬件上一般支持4 组(极个别芯片可支持5 组) 可配置的endpoint, 默认代码下我们配置了两组BULK ep, 一个ISO ep, 一个INT ep。

根据实际使用的gadget功能,要求的ep 传输类型也不一样,下表简单列举的部分gadget 功能要求的ep 类型、个数:

gadget 功能ep 类型个数
hidINT2, IN/OUT
accessoryBULK2, IN/OUT
loopbackBULK2, IN/OUT
mass_storageBULK2, IN/OUT
mtpBULK2,IN/OUT
INT1, IN
uac1ISOC2, IN/OUT
rndisINT1, IN
BULK2, IN/OUT
serialBULK2, IN/OUT
printerBULK2, IN/OUT
个别功能根据实际配置,要求的ep可能也有变化, 例如uac1:
如果有2个ISOC ep,那么可以同时支持录音、播放;
如果只有一个ISOC ep, 可以支持录音或者播放。

下面介绍如何修改代码支持不同类型的ep, 改动点只有两个文件:

  1. 修改drivers/usb/sunxi_usb/include/sunxi_udc.h

进行修改前,请注意:

我们芯片的udc分两种:
a. 4K FIFO, 4组ep
b.8KFIFO,5
组ep

请根据spec或者sunxi_udc.h中的宏去区分,大部分芯片都是第一种,4K FIFO, 4组ep。

修改ep_fifo 配置:

默认配置:
static const struct sw_udc_fifo ep_fifo[] = {
{ep0name,
0,
512, 0},
{ep1in_bulk_name, 512, 512, 0},
{ep1out_bulk_name, 1024, 512, 0},
{ep2in_int_name, 1536, 512, 0},
{ep2out_int_name, 2048, 512, 0},
{ep3_iso_name,
2560, 512, 0},
{ep4in_int_name, 3072, 512, 0},
{ep4out_int_name, 3584, 512, 0},
static const int ep_fifo_in[] = {0, 1, 3, 5, 6, 7};
static const int ep_fifo_out[] = {0, 2, 4, 5, 7, 8};

ep_fifo中,第一列表示ep名称;第二列表示FIFO起始地址;第三列表示ep的长度;第四列参数表示使用double buffered fifo

,配置为1则表示启用。

ep_fifo_in的配置,这里会配置所有输入方向的ep(ep0 + 4组ep)的序号,序号指的是上面ep_fifo数组的index。
例如ep_fifo_in数组中:
0表示ep0对应ep_fifo[0],即ep0;
1对应ep_fifo[1], 即ep1in-bulk;
3表示ep_fifo[3], 即ep2in-bulk;
5表示ep_fifo[5], 即ep3-iso;
6表示ep_fifo[6], 即ep4-int;
7在这里没有作用,只有某些芯片支持5组ep的才会用到这个index;i
o_out的配置方法与i
ut类似。

说明

关于double bufferd fifo,若给第三列ep 长度配置1024,则表示两个fifo 各占了512Bytes 的大小。double bufferd fifo 是会占用实际的fifo 空间的。

  1. 修改drivers/usb/sunxi_usb/udc/sunxi_udc.c

主要修改static struct sunxi_udc sunxi_udc 这个结构体里面的ep 数组。

数组需要根据sunxi_udc.h 中的ep_fifo 一一对应, 修改每个ep 时需要注意:

  • num 字段,表示第几组ep;

  • name 字段,对应的ep 名称;

  • maxpacket 字段,FIFO 大小,一般为512;

  • caps, 指定传输类型以及方向;

  • bEndpointAddress, 传输方向以及ep 序号;

  • bmAttributes, 传输类型。

下面一些修改例子:

  1. 支持ISO IN/OUT。
s/usb/sunxi_usb/include/sunxi_udc.h
改动:
#define SW_UDC_EP_ISO_FIFO_SIZE
512
static const char ep3in_iso_name[]
= "ep3in-iso";
static const char ep3out_iso_name[]
= "ep3out-iso";
static const struct sw_udc_fifo ep_fifo[] = {
{ep0name,
0,
512, 0},
{ep1in_bulk_name, 512, 512, 0},
{ep1out_bulk_name, 1024, 512, 0},
{ep2in_bulk_name, 1536, 512, 0},
{ep2out_bulk_name, 2048, 512, 0},
{ep3in_iso_name, 2560, 512, 0},
{ep3out_iso_name, 3072, 512, 0},
{ep4_int_name,
3584, 512, 0},
static const int ep_fifo_in[] = {0, 1, 3, 5, 7, 7};
static const int ep_fifo_out[] = {0, 2, 4, 6, 7, 8};
drivers/usb/sunxi_usb/udc/sunxi_udc.c改动:
主要改动了ep[5],ep[6]
.ep[5] = {
.num
= 3,
.ep = {
.name
= ep3in_iso_name,
.ops
= &sunxi_udc_ep_ops,
.maxpacket = SW_UDC_EP_ISO_FIFO_SIZE,
.maxpacket_limit = SW_UDC_EP_ISO_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
USB_EP_CAPS_DIR_IN),
},
.dev
= &sunxi_udc,
.bEndpointAddress = (USB_DIR_IN | 3),
.bmAttributes
= USB_ENDPOINT_XFER_ISOC,
},
.ep[6] = {
.num
= 3,
.ep = {
.name
= ep3out_iso_name,
.ops
= &sunxi_udc_ep_ops,
.maxpacket = SW_UDC_EP_ISO_FIFO_SIZE,
.maxpacket_limit = SW_UDC_EP_ISO_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
USB_EP_CAPS_DIR_OUT),
},
ev
=&sunxi_udc,
.bEndpointAddress = (USB_DIR_OUT | 3),
.bmAttributes
= USB_ENDPOINT_XFER_ISOC,
},
  1. 支持两个INT 传输,方向均支持。

默认代码支持了一个INT传输,所以增加一个即可,最简单的就是将ISO端点改为INT:

drivers/usb/sunxi_usb/include/sunxi_udc.h改动:
static const char ep3_int_name[]
= "ep3-int";
static const struct sw_udc_fifo ep_fifo[] = {
{ep0name,
0,
512, 0},
{ep1in_bulk_name, 512, 512, 0},
{ep1out_bulk_name, 1024, 512, 0},
{ep2in_bulk_name, 1536, 512, 0},
{ep2out_bulk_name, 2048, 512, 0},
{ep3_int_name,
2560, 1024, 0},
{ep4_int_name,
3584, 512, 0},
};
drivers/usb/sunxi_usb/udc/sunxi_udc.c改动:
主要改动了ep[5]
.ep[5] = {
.num
= 3,
.ep = {
.name
= ep3_int_name,
.ops
= &sunxi_udc_ep_ops,
.maxpacket = SW_UDC_EP_FIFO_SIZE,
maxpacket_limit=SW_UDC_EP_FIFO_SIZE,

.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,

USB_EP_CAPS_DIR_ALL),
},
.dev
= &sunxi_udc,
.bEndpointAddress = 3,
.bmAttributes
= USB_ENDPOINT_XFER_INT,
},
  1. 支持4 组BULK IN/OUT。

每个ep 都至少占用512 字节的FIFO, 如果需要支持4 组BULK, 并且IN/OUT 都需要, 那么共需要8*512=4K 的FIFO, 另外ep0 至少需要64 字节的FIFO。而我们UDC 的FIFO 实际大小是4K+64byte,是可以满足该需求的,配置方法如下所示:

代码下支持了两组BULK
现在需要多增加两组BULK。
drivers/usb/sunxi_usb/include/sunxi_udc.h改动:
static const char ep3in_bulk_name[] = "ep3in-bulk";
static const char ep3out_bulk_name[] = "ep3out-bulk";
static const char ep4in_bulk_name[] = "ep4in-bulk";
static const char ep4out_bulk_name[] = "ep4out-bulk";
static const struct sw_udc_fifo ep_fifo[] = {
{ep0name,
0,
64, 0},
{ep1in_bulk_name, 64,
512, 0},
{ep1out_bulk_name, 512+64, 512, 0},
{ep2in_bulk_name, 1024+64, 512, 0},
{ep2out_bulk_name, 1536+64, 512, 0},
{ep3in_bulk_name, 2048+64, 512, 0},
p3out_bulk_name,2560+64,512,0},
{ep4in_bulk_name, 3072+64, 512, 0},
{ep4out_bulk_name, 3584+64, 512, 0},
};
static const int ep_fifo_in[] = {0, 1, 3, 5, 7, 7};
static const int ep_fifo_out[] = {0, 2, 4, 6, 8, 8};
drivers/usb/sunxi_usb/udc/sunxi_udc.c改动:
主要改动了ep[5],ep[6],ep[7],ep[8]
.ep[5] = {
.num
= 3,
.ep = {
.name
= ep3in_bulk_name,
.ops
= &sunxi_udc_ep_ops,
.maxpacket
= SW_UDC_EP_FIFO_SIZE,
.maxpacket_limit = SW_UDC_EP_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
USB_EP_CAPS_DIR_IN),
},
.dev
= &sunxi_udc,
.bEndpointAddress = (USB_DIR_IN | 3),
.bmAttributes
= USB_ENDPOINT_XFER_BULK,
},
.ep[6] = {
.num
= 3,
.ep = {
ame=ep3out_bulk_name,
.ops
= &sunxi_udc_ep_ops,
.maxpacket
= SW_UDC_EP_FIFO_SIZE,
.maxpacket_limit = SW_UDC_EP_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
USB_EP_CAPS_DIR_OUT),
},
.dev
= &sunxi_udc,
.bEndpointAddress = (USB_DIR_OUT | 3),
.bmAttributes
= USB_ENDPOINT_XFER_BULK,
},
.ep[7] = {
.num
= 4,
.ep = {
.name
= ep4in_bulk_name,
ps=&sunxi_udc_ep_ops,
.maxpacket
= SW_UDC_EP_FIFO_SIZE,
.maxpacket_limit = SW_UDC_EP_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
USB_EP_CAPS_DIR_IN),
},
.dev
= &sunxi_udc,
.bEndpointAddress = (USB_DIR_IN | 4),
.bmAttributes
= USB_ENDPOINT_XFER_BULK,
},
.ep[8] = {
.num
= 4,
.ep = {
.name
= ep4out_bulk_name,
.ops
= &sunxi_udc_ep_ops,
.maxpacket
= SW_UDC_EP_FIFO_SIZE,
.maxpacket_limit = SW_UDC_EP_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
USB_EP_CAPS_DIR_OUT),
},
.dev
= &sunxi_udc,
.bEndpointAddress = (USB_DIR_OUT | 4),
.bmAttributes
= USB_ENDPOINT_XFER_BULK,
},

3.4 USB Host功能配置

3.4.1 U盘功能

Device Drivers --->SCSI device support ---><*> SCSI device support

<*> SCSI disk support
[*] USB support --->
<*>
USB Mass Storage support
<*>
Datafab Compact Flash Reader support
<*>
Freecom USB/ATAPI Bridge support
<*>
ISD-200 USB/ATA Bridge support
USBAT/USBAT02-basedstoragesupport
<*>
SanDisk SDDR-09 (and other SmartMedia, including DPCM) support
<*>
SanDisk SDDR-55 SmartMedia support
<*>
Lexar Jumpshot Compact Flash Reader
<*>
Olympus MAUSB-10/Fuji DPC-R1 support
<*>
Support OneTouch Button on Maxtor Hard Drives
<*>
Support for Rio Karma music player
<*>
SAT emulation on Cypress USB/ATA Bridge with ATACB
<*>
USB Attached SCSI

Enable the block layer --->Partition Types --->[*] PC BIOS (MSDOS partition tables) support

说明

若PC BIOS(MSDOS_PARTITION) 配置项没有选上,会导致不能识别U 盘在windows 端的分区。

假设
U 盘是有两个分区,但没有配置该配置项,则在
linux 端的表现为:只有/dev/sda 一个文件节点。不会生成/dev/sda/dev/
sda1 /dev/sda2 等多个文件节点。从而会使得挂载失败。

3.4.2 USB声卡

Device Drivers ---><> Sound card support --->[] USB sound devices ---><*> USB Audio/MIDI driver

3.4.3 USB网卡

Device Drivers --->[*] Network device support --->

<*> USB Network Adapters --->
在这选择对应的驱动
例如是rndis驱动:

<*> Multi-purpose USB Networking Framework

<*>
Host for RNDIS and ActiveSync devices

3.4.4 USB HID设备

Device Drivers --->HID support --->USB HID support ---><*> USB HID transport layer

3.4.5 USB 摄像头

Device Drivers ---><*> Multimedia support --->

[*] Media USB Adapters --->
USBVideoClass(UVC)
[*]
UVC input events device support

3.4.6 USB 打印机

Device Drivers --->SCSI device support ---><*> SCSI device support

<*> SCSI disk support
[*] USB support --->
<*>
USB Printer support

sb 打印机设备后,会生成对应设备节点:/dev/usb/lp0。

3.5 支持USB Standby

部分芯片可以支持USB Standby,例如外接USB 鼠标键盘,在点击鼠标时,可以唤醒系统。

软件上注意配置usb_wakeup_suspend 为1 即可。

硬件上注意vdd-usb 的电在休眠时不能关。如果用的是USB0, 那么注意OTG-5V 的电也不能掉,否则USB 外设不能正常工作。

3.6 设置USB序列号

很多时候adb devices 查看设备时,它的序列号都是20080411, 它的值就是有USB 序列号决定的。

如果要求每个设备都有自己唯一的序列号,那么可以配置芯片的chipid 转换得到序列号,并设置到USB 驱动中,修改步骤如下所示:

  1. 修改uboot 配置,增加CONFIG_SUNXI_SERIAL 配置。
增加该配置后,uboot阶段会读取chipid并转换得到serial number。
并将该serial number设置到环境变量snum中,然后启动内核时获取该变量,并增加到内核cmdline中:"androidboot.
serialno="

2.usb 配置使用唯一序列号。

修改dts, 将usbc0的usb_serial_unique改为1
usb相关驱动中会读取cmdline中"androidboot.serialno"字段获取序列号
后续gadget驱动中均会配置使用该序列号
注意,进入系统后不要再修改/sys/kernel/config/usb_gadget/g1/strings/0x409/serialnumber该节点。

验证方法:

可以通过adb devices查看序列号

3.7 测试USB速率

可以通过挂载移动硬盘,然后进行测试读写性能。

写性能:

确认移动硬盘的挂载目录,如/mnt/exUDISK/,然后执行下面命令:
time dd if=/dev/zero of=/mnt/exUDISK/test.bin bs=1MB count=1024
1024+0 records in
1024+0 records out
real
0m 36.63s
m0.00s
sys0m3.41s
所以写性能为:1024/36.63=27.95MB/s

读性能:

time dd if=/mnt/exUDISK/test.bin of=/dev/null bs=1MB count=1024
1024+0 records in
1024+0 records out
real
0m 28.99s
user
0m 0.01s
sys
0m 2.38s
所以读性能为:1024/28.99=35.33MB/s

注意,不同的U 盘、移动硬盘,受存储介质、文件系统格式影响,速率可能会存在较大差别,建

用fat32 文件系统的移动硬盘进行测试,而不使用ntfs 文件系统的移动硬盘。

说明

dd 命令在运行结束之后,其实还没真正地将文件写到硬盘上,而是单纯地把数据写/读到内存缓存当中。因此,如果需要真实反映到硬盘的读写速度。写操作需要加上参数“oflag=direct”,读操作需要加上参数“iflag=direct”。

3.8 USB功能裁剪

一般我们默认SDK 都会默认开启USB0 的OTG 功能,USB1 的Host 功能。而不同客户产品对USB功能的需求不一样,可以根据下面几个例子进行功能裁剪:

3.8.1 删除多余的usb gadget功能

实际产品仅用到有限种类的gadget 功能,可以通过make kernel_menuconfig 进入相关配置项:

Device Drivers --->

[*] USB support --->
USBGadgetSupport--->
<*> USB functions configurable through configfs
//必须要选configfs功能
[*]
Mass storage
//USB Masss Storage功能,可以理解设备模拟为U盘
[*]
Function filesystem (FunctionFS)
//ADB就是通过该ffs功能实现
[*]
MTP gadget
[*]
HID function
[*]
Printer function

实际产品可以根据情况仅选用自己需要用到的gadget 功能。

3.8.2 仅用到usb0的OTG功能

删除USB1 相关的配置

Device Drivers --->[*] USB support --->

< >
SoftWinner SUNXI USB EHCI1
< >
SoftWinner SUNXI USB OHCI1

把EHCI1,OHCI1 的配置去掉。

3.8.3 仅使用到adb功能

adb 功能需要用到USB0 的device 功能,因此可以把USB1 以及Host 相关配置都删除。

eDrivers--->

[*] USB support --->

<*> Support for Host-side USB
<*> USB Gadget Support --->
<*> USB functions configurable through configfs
//必须要选configfs功能
[*]
Function filesystem (FunctionFS)
//ADB就是通过该ffs功能实现
<*> SUNXI USB2.0 Dual Role Controller support --->

“USB Support” 配置页中仅保持上面选项,其他例如“HCI”, “USB Mass Storage” 相关配置都去掉。

3.9 Uboot阶段U盘功能

一般uboot 默认配置都没有使能USB 及U 盘功能,需要修改方案默认defconfig(例如configs/{CHIP}_defconfig):

CONFIG_USB1_VBUS_PIN="PF4"
CONFIG_USB=y
CONFIG_USB_HOST=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_CMD_USB=y

其中,USB1_VBUS_PIN 表示使能USB1 口5V 电压的gpio,如果硬件上这个5V 供电默认就上电,那么这个配置可以置空为“”。

使用的是USB0 口,那么请新增或修改CONFIG_USB0_VBUS_PIN这个配置。

测试验证步骤:

1.进入uboot命令行后,输入下面命令使能USB功能:
usb start
他会初始化USB0,USB1的Host功能(如果CONFIG_USB_MAX_CONTROLLER_COUNT为1则只初始化USB0),
如果当前接了U盘,会被扫描到,并有如下打印:
=> usb start
starting USB...
USB0: start sunxi USB-DRD...
config usb clk ok
sunxi USB-DRD init ok...
USB EHCI 1.00
ningbus0fordevices...1USBDevice(s)found
USB1: start sunxi USB1-Host...
config usb clk ok
sunxi USB1-Host init ok...
USB EHCI 1.00
scanning bus 1 for devices... 2 USB Device(s) found

scanning usb for storage devices... 1 Storage Device(s) found

另外还可以用usb tree等命令查看USB控制器信息

2.使用fat相关命令查看U盘内容
例出U盘里面的文件信息(作用如同ls):
fatls usb 0
读取U盘文件到指定内存地址中:
fatload usb 0 0x43000000 test_file

事项:

  1. 请注意确认U 盘文件系统格式, 目前仅支持fat 格式;

  2. 如果文件读取过程中出现下面timeout 打印,可尝试将common/usb_storage.c 的blk 值改小。

异常打印:

=> fatload usb 0 0x42000000 4M.bin
EHCI timed out on TD - token=0x40008d80
EHCI timed out on TD - token=0x40008d80
EHCI timed out on TD - token=0x40008d80
Error reading cluster
** Unable to read file 4M.bin **

修改办法:

原文第 33 页插图

图3-1: 修改blk 值

越小,兼容性越好,但是传输速率也会相对降下来。

出现这种现象的原因:uboot 原生代码中未对U 盘做兼容性处理,故使用U 盘读取文件时,有一些U 盘会出错,导致传输失败。

4 常见调试方法

4.1 调试节点

查看USB0 当前Role:

cat /sys/devices/platform/soc/usbc0/otg_role
cat `find /sys -name otg_role`

手动切换成Host 模式:

cat /sys/devices/platform/soc/usbc0/usb_host
或者
cat `find /sys -name usb_host`

手动切换成Device 模式:

cat /sys/devices/platform/soc/usbc0/usb_device
或者
cat `find /sys -name usb_device`

手动切换模式后,G 自动切换角色的功能就会失效;

USB1 调试节点:

卸载主机驱动
echo 0 > sys/devices/platform/soc/5200000.ehci1-controller/ehci_enable
echo 0 > sys/devices/platform/soc/5200000.ohci1-controller/ohci_enable
加载主机驱动
echo 1 > sys/devices/platform/soc/5200000.ehci1-controller/ehci_enable
echo 1 > sys/devices/platform/soc/5200000.ohci1-controller/ohci_enable

4.2 测试USB眼图

USB0 OTG Device 眼图测试:

手动切换Device模式:
cat /sys/devices/platform/soc/usbc0/usb_device
每个芯片平台的节点路径会有些差异,请通过find命令确认:
find /sys -name otg_ed_test
眼图测试命令:
echo test_pack > /sys/devices/platform/soc/5100000.udc-controller/otg_ed_test

USB0 OTG Host 眼图测试:

手动切换Host模式:
cat /sys/devices/platform/soc/usbc0/usb_host
每个芯片平台的节点路径会有些差异,请通过find命令确认(注意选择带有ehci0的路径):
find /sys -name ed_test
眼图测试命令:
echo test_pack > /sys/devices/platform/soc/5101000.ehci0-controller/ed_test

USB1 Host 眼图测试:

每个芯片平台的节点路径会有些差异,请通过find命令确认(注意选择带有ehci1的路径):
find /sys -name ed_test
眼图测试命令:
est_pack>/sys/devices/platform/soc/4201000.ehci1-controller/ed_test

5 USB相关应用工具

5.1 setusbconfig脚本

setusbconfig 脚本位于:

TinaSDK/platform/allwinner/usb/setusbconfig/

使用方法,setusbconfig 功能名, 例如:

切换成adb功能:
setusbconfig adb
切换成mtp功能:
setusbconfig mtp
切换成adb mtp复合功能:
setusbconfig adb,mtp

5.2 ADB

ADB 功能是从Android 移植过来的,设备端会运行adbd 服务,而Host 端(一般为PC) 通过adb工具进行调试,如adb shell, adb push/pull 等。

Tina SDK 中支持adbd 服务,请make menuconfig 选中对应软件包:

例如openWrt 下:

Allwinner --->USB ---><*> adbd................................................. adbd for Tina Linux

选中该软件包后,开机会默认运行adbd 服务,并且设置USB gadget 为ADB 功能。

5.2.1 ADB功能说明

5.2.1.1 adb shell功能
PC端执行adb shell,可进入控制台。
PC端执行adb shell + command, 例如adb shell ls /可以直接将结果输出到终端。
5.2.1.2 adb push/pull功能
推送文件到小机端:
ushtest.bin/mnt/UDISK/
从小机端拉取文件:
adb pull /mnt/UDISK/test.bin .
5.2.1.3 adb网络连接

修改adbd 启动脚本:

tina/package/utils/adb/adbd-configfs.init
取消下面注释
#ADB_TRANSPORT_PORT=5555

小机端与PC 在同一个局域网,并且可以ping 通。

PC端执行adb connect 192.168.1.101建立连接。
然后就可以开始执行adb shell等命令了。
5.2.1.4 adb forward功能

adb forward 功能用于数据转发,执行该命令后,应用可以通过socket 通信,实现PC 与设备之间的数据交互。

PC端执行:adb forward tcp:11111 tcp:22222
tcp:11111表示PC端监听的端口。
222表示设备端的端口。
PC端对11111端口的数据读写,都会转发到设备端22222端口
所以设备端的一些应用可以通过22222端口与PC端进行数据交互。
5.2.1.5 adb auth功能

该功能主要用于权限管理,只有经过公私钥认证后才能进行adb 通信。

使用前需要make menuconfig 选中对应功能:

Allwinner --->USB --->

<*> adbd................................................. adbd for Tina Linux
< > adbd_auth_service........................ adb auth service for Tina Linux
< > libawadbauth................................. adb auth lib for Tina Linux

默认开机就会使能该功能,执行adb 命令时会进行公私钥校验。

公钥的安装:

默认允许安装所有公钥,可以通过修改TinaSDK/platform/allwinner/usb/adbd/auth/aw_adb_auth_service.c
取消下面注释
/*aw_adbd_install_pubkey_detector(publickey_detector); */
然后在publickey_detector函数中判断是否安装公钥,返回false则不安装

安装路径:/mnt/UDISK/adb_keys

如果/mnt/UDISK/adb_keys 下面没有对应的公钥,并且不允许安装新公约,这时候adb 功能就不能使用了。

注意事项:1.Windows 下面公私钥的路径:

%USERPROFILE%\.android\adbkey
// 私钥
%USERPROFILE%\.android\adbkey.pub // 公钥

2.Ubuntu 下面公私钥的路径:

用户目录/.android/adbkey
// 私钥
用户目录/.android/adbkey.pub
// 公钥

5.2.2 ADB常见问题

  • 注意是否启动了adbd 服务
ps|grep adbd确认是否存在adbd进程,如果没有请确认:
1.是否选中adb软件包。
2.adbd启动脚本是否执行了。
可通过命令手动运行adbd服务:
/etc/init.d/adbd start
  • 如果是busybox 启动方式,需要注意挂载devpts
adb shell的过程中,需要创建虚拟终端,依赖于devpts
mount -t devpts /dev/pts /dev/pts
  • adb shell 不能使用,但是push/pull 功能正常
adb shell会用到虚拟终端,依赖部分内核配置:
CONFIG_VT_CONSOLE
CONFIG_UNIX98_PTYS
CONFIG_DEVPTS_MULTIPLE_INSTANCES
CONFIG_CONSOLE_TRANSLATIONS
  • adb 命令执行后提示close
可以通过查看adbd的打印确认问题, 串口端输入:
killall adbd
adbd &
这样adbd的打印会直接输出到串口终端
如果确认到/dev/pts/等相关字样错误打印,并且mount看到缺少devpts文件系统的信息,
那么需要挂载devpts文件系统即可解决问题:
mkdir /dev/pts
mount -t devpts none /dev/pts

5.3 MTP

MTP,全称是Media Transfer Protocol(媒体传输协议)。它是微软的一个为计算机和便携式设备之间传输图像、音乐等所定制的协议。

按照MTP 定义的规则,可以使得电脑能够获取小机端的目录信息,并且可以进行增、删、查看等操作。因此,这就要求电脑端以及小机端都需要有一个服务或者程序去发送、解析、回应数据包。

的应用分为两种角色,一个是作为Inititator,另一个作为Responder。

  • Initiator ⸺在MTP 中所有的请求都有Initiator 发起。例如,PC 请求获取小机设备的文件数

据。

  • Responder ⸺它会处理Initiator 的请求;除此之外,Responder 也会发送Event 事件。

原文第 39 页插图

图5-1: MTP 数据传输

一般Windows PC 都默认支持MTP。ubuntu 等PC 也有一些第三方包可以支持,例如libmtp,mtpfs 等。而小机端上则需要一个应用去处理PC 发送过来的请求(实际上就是按照MTP 生成的数据包),并做出回应。

Tina 参考Android MTP 系统服务,实现了自己的MTP 服务。

5.3.1 MTP服务

MtpDaemon 软件设计流程图:

原文第 40 页插图

图5-2: MtpDaemon 软件流程

  • 监测usb uevent 事件。

  • 监测fifo 看是否接受到消息,该消息主要用于更新小机端MtpDataBase(用于保存文件目录信息

的对象),详细请查阅MtpTools 章节。

  • 监测MTP 消息,该消息是从/dev/mtp_usb 节点获取。

5.3.2 MTP相关配置

5.3.2.1 menuconfig选中MtpDaemon软件包

Allwinner --->USB --->

<*> MtpDaemon................................................ Tina MTP Daemon
[*] MTP daemon compile with aio
5.3.2.2 配置挂载目录

默认配置下,只会把小机端/mnt/UDISK 挂载到PC 上,并且挂载的盘符名称为”Tina 存储设备”。如果想修改或者新增目录,可以修改下面路径的源码:

TinaSDK/platform/allwinner/usb/mtp/src/main.c

static mtp_storage_t gStorageArray[] = {
{NULL, 65537, "/mnt/UDISK", "Tina存储设备", MB(2), MB(4096)},
//{NULL, 65539, "/boot", "boot", 0, 0},
//{NULL, 65540, "/boot-res", "boot-res", 0, 0},
};
可以在该数组上添加需要的目录及相关信息,例如
{NULL, 65539, "/boot", "boot", 0, 0},
第一个参数固定填写NULL即可,MtpDaemon会在自动对这个成员赋值。
第二个参数表示Storage ID, 对每个要挂载的目录都有唯一的ID,例如上面设置的65537为/mnt/UDISK的storage ID,这个值是
一个32bit的整型数,建议从65537累加上去即可。
第三个参数表示要挂载到PC的目录,是一个绝对路径。
第四个参数表示保留空间,比如上述的是保留2MB的空间。
第五个参数表示该单个文件大小的最大值,上述例子为限制传输单个文件最大不超过4GB。

5.3.3 MtpTools

MtpDaemon 作为responder 处理并回应PC 发送过来的MTP 消息,因此在PC 上可以对小机端的目录、文件进行操作。但为了让小机端的修改能够同步到PC 上,Tina 提供了MtpTools。

MtpTools 主要通过fifo 发送消息给MtpDaemon, 然后MtpDaemon 根据该消息去更新Mtp-DataBase, 即更新用于描述目录文件信息的对象,此时PC 上只需要刷新下即可同步得到小机端的修改。

下面介绍下MtpTools 的几个命令:

MtpToolsusage:
MtpTools [function] [path]
-f, --function
function opion, contains add,remove,update,cut,copy
-t, --type
object type, FILE or DIR
-s, --spath
object src path
-d, --dpath
object dest path, specify dest path of object which will be cut or copy
-h, --help
show help
example:
MtpTools -f add -t FILE -s /mnt/UDISK/test
参数功能说明
指定要执行的动作,包含add-新增,remove-移除,update-更新,cut-剪切,

copy-复制

-t指定要操作对象的类型,文件or 目录
-s表示操作对象的源路径
-d表示操作对象的目标路径

举例说明:

新增一个名为test 的文件:

ols-fadd-tFILE-s/mnt/UDISK/test

实际上有一种比较简单的方法,就是直接更新目录信息,例如:

MtpTools -f update -t DIR -s /mnt/UDISK

这样不管该目录下就行了任何修改,全都会更新一遍。(他会遍历更新所有目录、文件信息,相对耗时多一些)。

5.3.4 MTP常见问题

机后MTP 功能没法正常使用

1.ps|grep Mtp确认MtpDaemon是否运行。
2.setusbconfig mtp切换成MTP功能。
3.确认Windows端USB驱动是否正常识别。
如果没有识别到,请打开设备管理器,找到对应"未知设备",然后右键选择更新驱动,按下面步骤手动加载驱动:
选择"浏览计算机以查找驱动程序软件" ->
"从计算机的设备驱动程序列表中选择" ->
"便携设备"
"标准MTP设备” ->
"MTP设备"
4.修改盘符名称。

默认是hostname(即TinaLinux), 可以在src/MtpServer.c中定义MODEL_NAME宏去设定其他盘符名称。

权声明

本文档及内容受著作权法保护,其著作权由珠海全志科技股份有限公司(“全志”)拥有并保留一切权利。

本文档是全志的原创作品和版权财产,未经全志书面许可,任何单位和个人不得擅自摘抄、复制、修改、发表或传播本文档内容的部分或全部,且不得以任何形式传播。

商标声明

(不完全列

举)均为珠海全志科技股份有限公司的商标或者注册商标。在本文档描述的产品中出现的其它商标,产品名称,和服务名称,均由其各自所有人拥有。

免责声明

您购买的产品、服务或特性应受您与珠海全志科技股份有限公司(“全志”)之间签署的商业合同和条款的约束。本文档中描述的全部或部分产品、服务或特性可能不在您所购买或使用的范围内。使用前请认真阅读合同条款和相关说明,并严格遵循本文档的使用说明。您将自行承担任何不当使用行为(包括但不限于如超压,超频,超温使用)造成的不利后果,全志概不负责。

本文档作为使用指导仅供参考。由于产品版本升级或其他原因,本文档内容有可能修改,如有变

恕不另行通知。全志尽全力在本文档中提供准确的信息,但并不确保内容完全没有错误,因

使用本文档而发生损害(包括但不限于间接的、偶然的、特殊的损失)或发生侵犯第三方权利事件,全志概不负责。本文档中的所有陈述、信息和建议并不构成任何明示或暗示的保证或承诺。

本文档未以明示或暗示或其他方式授予全志的任何专利或知识产权。在您实施方案或使用产品的过程中,可能需要获得第三方的权利许可。请您自行向第三方权利人获取相关的许可。全志不承担也不代为支付任何关于获取第三方许可的许可费或版税(专利税)。全志不对您所使用的第三方许可技术做出任何保证、赔偿或承担其他义务。