Rockchip RK3399 - USB调试
----------------------------------------------------------------------------------------------------------------------------
开发板 :NanoPC-T4
开发板
eMMC
:16GB
LPDDR3
:4GB
显示屏 :15.6
英寸HDMI
接口显示屏
u-boot
:2023.04
linux
:6.3
----------------------------------------------------------------------------------------------------------------------------
一、设备树
设备树配置参考文档:
Documentation/devicetree/bindings/usb/generic-ehci.yaml
; (USB
控制器的通用属性配置说明)Documentation/devicetree/bindings/usb/generic-ohci.yaml
; (USB
控制器的通用属性配置说明)Documentation/devicetree/bindings/usb/generic-xhci.yaml
; (USB
控制器的通用属性配置说明)Documentation/devicetree/bindings/usb/fcs,fusb302.yaml
;Documentation/devicetree/bindings/usb/rockchip,rk3399-dwc3.yaml
;(适用于RK3399
)Documentation/devicetree/bindings/usb/usb-uhci.txt
;Documentation/devicetree/bindings/usb/usb-xhci.yaml
;Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
;Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml
;Documentation/devicetree/bindings/phy/rockchip-usb-phy.yaml
;
1.1 USB2.0 Host Type-A
NanoPC-T4
开发板支持两个USB2.0 Host Type-A
接口,对应的USB
控制器为USB2.0 HOST(EHCI&OHCI)
、对应的USB PHY
为USB2.0 HOST PHY
;
因此对应的设备树配置,包括USB2.0 HOST(EHCI&OHCI)
控制器设备树配置和USB2.0 HOST PHY
设备树配置。
1.1.1 控制器配置
(1) USB2.0 HOST0
控制器设备节点usb_host0_ehci
、usb_host0_ohci
定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
usb_host0_ehci: usb@fe380000 {
compatible = "generic-ehci";
reg = <0x0 0xfe380000 0x0 0x20000>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
<&u2phy0>;
phys = <&u2phy0_host>;
phy-names = "usb";
status = "disabled";
};
usb_host0_ohci: usb@fe3a0000 {
compatible = "generic-ohci";
reg = <0x0 0xfe3a0000 0x0 0x20000>;
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
<&u2phy0>;
phys = <&u2phy0_host>;
phy-names = "usb";
status = "disabled";
};
在USB
控制器设备节点中,通过phys
属性关联对应的USB PHY
。
phys = <&u2phy0_host>;
这表明这两个USB
控制器都用了u2phy0_host
这个USB PHY
.
这两个USB
控制器就是我们之前介绍的是EHCI
和OHCI
,OHCI
支持USB1.0
和USB1.1
,EHCI
支持USB2.0
。
(2) USB2.0 HOST1
控制器设备节点usb_host1_ehci
、usb_host1_ohci
定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
usb_host1_ehci: usb@fe3c0000 {
compatible = "generic-ehci";
reg = <0x0 0xfe3c0000 0x0 0x20000>;
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>,
<&u2phy1>;
phys = <&u2phy1_host>;
phy-names = "usb";
status = "disabled";
};
usb_host1_ohci: usb@fe3e0000 {
compatible = "generic-ohci";
reg = <0x0 0xfe3e0000 0x0 0x20000>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>,
<&u2phy1>;
phys = <&u2phy1_host>;
phy-names = "usb";
status = "disabled";
};
1.1.2 PHY
配置
USB2.0 PHY
包含两个端口,以USB2.0 PHY0
为例,包含的两个端口设备节点为u2phy0_host
、u2phy0_otg
;
(1) USB2.0 HOST PHY0
设备节点u2phy0_host
定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
u2phy0: usb2phy@e450 {
compatible = "rockchip,rk3399-usb2phy";
reg = <0xe450 0x10>;
clocks = <&cru SCLK_USB2PHY0_REF>;
clock-names = "phyclk";
#clock-cells = <0>;
clock-output-names = "clk_usbphy0_480m";
status = "disabled";
u2phy0_host: host-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "linestate";
status = "disabled";
};
u2phy0_otg: otg-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "otg-bvalid", "otg-id",
"linestate";
status = "disabled";
};
};
(2) USB2.0 HOST PHY1
设备节点u2phy1_host
定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
u2phy1: usb2phy@e460 {
compatible = "rockchip,rk3399-usb2phy";
reg = <0xe460 0x10>;
clocks = <&cru SCLK_USB2PHY1_REF>;
clock-names = "phyclk";
#clock-cells = <0>;
clock-output-names = "clk_usbphy1_480m";
status = "disabled";
u2phy1_host: host-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "linestate";
status = "disabled";
};
u2phy1_otg: otg-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "otg-bvalid", "otg-id",
"linestate";
status = "disabled";
};
};
1.1.3 电源配置
(1) USB2.0 PHY
芯片三路电源依次为VCCA0V9_S3
、VCCA1V8_S3
、VCC3V3_S3
;
VCCA0V9_S3
、VCCA1V8_S3
这两路由PMIC_SLEEP_H
(连接RK3399
的GPIO1_A5/AP_PWROFF
,这个应该是处理器睡眠引脚,处理器工作时电源有效)引脚控制的;
VCC3V3_S3
由RK808
电源管理芯片第7号引脚VSWOUT
提供,因此需要配置其电源输出为3.3V
;
在arch/arm64/boot/dts/rockchip/rk3399-evb.dts
配置vcc3v3_s3
设备节点;
&i2c0 {
......
rk808: pmic@1b {
......
regulators {
......
vcc3v3_s3: SWITCH_REG1 {
regulator-always-on;
regulator-boot-on;
regulator-name = "vcc3v3_s3";
regulator-state-mem {
regulator-off-in-suspend;
};
};
......
};
};
};
完整的rk808
设备节点配置参考:rk808
驱动配置。
(2) USB2.0 Host Type-A
接口电源VCC5V0_HOST0
由RT9724GQW
提供的,其输入端为VCC5V0_SYS
。
在arch/arm64/boot/dts/rockchip/rk3399-evb.dts
配置vcc5v0_host
;
vcc5v0_sys: vcc5v0-sys {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_sys";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
};
vcc5v0_host: vcc5v0-host-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_host";
regulator-always-on;
regulator-boot-on;
vin-supply = <&vcc5v0_sys>;
};
1.1.4 使能
下面介绍的都是配置在arch/arm64/boot/dts/rockchip/rk3399-evb.dts
文件。
(1) 为了同时支持USB1.0
、USB1.1
和USB2.0
,就需要同时用到EHCI
和OHCI
,因此需要把这两个USB
控制器都打开:
&usb_host0_ehci {
status = "okay";
};
&usb_host0_ohci {
status = "okay";
};
&usb_host1_ehci {
status = "okay";
};
&usb_host1_ohci {
status = "okay";
};
(2) 使能USB2.0 HOST PHY0
,同时配置USB2.0 HOST PHY0 phy-supply
属性,用于控制USB
电源VBUS
;
&u2phy0 {
status = "okay";
};
&u2phy0_host {
phy-supply = <&vcc5v0_host>;
status = "okay";
};
(3) 使能USB2.0 HOST PHY1
,同时配置USB2.0 HOST PHY1 phy-supply
属性,用于控制USB
电源VBUS
;
&u2phy1 {
status = "okay";
};
&u2phy1_host {
phy-supply = <&vcc5v0_host>;
status = "okay";
};
1.2 USB3.0 Host Type-A
NanoPC-T4
开发板支持1个USB3.0 Host Type-A
接口,对应的USB
控制器为USB3.0 OTG1(DWC3/xHCI)
、对应的USB PHY
为USB3.0 Type-C PHY1
和USB2.0 OTG PHY1
;
因此对应的设备树配置,包括USB3.0 OTG1(DWC3/xHCI)
控制器设备树配置和USB3.0 Type-C PHY1
、USB2.0 OTG PHY1
设备树配置。
1.2.1 控制器配置
(1) USB3.0 OTG1(DWC3/xHCI)
控制器设备节点usbdrd3_1
,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
usbdrd3_1: usb@fe900000 {
compatible = "rockchip,rk3399-dwc3";
#address-cells = <2>;
#size-cells = <2>;
ranges;
clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>,
<&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_RKSOC_AXI_PERF>,
<&cru ACLK_USB3>, <&cru ACLK_USB3_GRF>;
clock-names = "ref_clk", "suspend_clk",
"bus_clk", "aclk_usb3_rksoc_axi_perf",
"aclk_usb3", "grf_clk";
resets = <&cru SRST_A_USB3_OTG1>;
reset-names = "usb3-otg";
status = "disabled";
usbdrd_dwc3_1: usb@fe900000 {
compatible = "snps,dwc3";
reg = <0x0 0xfe900000 0x0 0x100000>;
interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru SCLK_USB3OTG1_REF>, <&cru ACLK_USB3OTG1>,
<&cru SCLK_USB3OTG1_SUSPEND>;
clock-names = "ref", "bus_early", "suspend";
dr_mode = "otg";
phys = <&u2phy1_otg>, <&tcphy1_usb3>;
phy-names = "usb2-phy", "usb3-phy";
phy_type = "utmi_wide";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis_u2_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
power-domains = <&power RK3399_PD_USB3>;
status = "disabled";
};
};
1.2.2 PHY
配置
(1) USB3.0 Type-C PHY1
设备节点tcphy1_usb3
,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
tcphy1: phy@ff800000 {
compatible = "rockchip,rk3399-typec-phy";
reg = <0x0 0xff800000 0x0 0x40000>;
clocks = <&cru SCLK_UPHY1_TCPDCORE>,
<&cru SCLK_UPHY1_TCPDPHY_REF>;
clock-names = "tcpdcore", "tcpdphy-ref";
assigned-clocks = <&cru SCLK_UPHY1_TCPDCORE>;
assigned-clock-rates = <50000000>;
power-domains = <&power RK3399_PD_TCPD1>;
resets = <&cru SRST_UPHY1>,
<&cru SRST_UPHY1_PIPE_L00>,
<&cru SRST_P_UPHY1_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
rockchip,grf = <&grf>;
status = "disabled";
tcphy1_dp: dp-port {
#phy-cells = <0>;
};
tcphy1_usb3: usb3-port {
#phy-cells = <0>;
};
};
(2) USB2.0 OTG PHY1
设备节点u2phy1_otg
,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
u2phy1: usb2phy@e460 {
compatible = "rockchip,rk3399-usb2phy";
reg = <0xe460 0x10>;
clocks = <&cru SCLK_USB2PHY1_REF>;
clock-names = "phyclk";
#clock-cells = <0>;
clock-output-names = "clk_usbphy1_480m";
status = "disabled";
u2phy1_host: host-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "linestate";
status = "disabled";
};
u2phy1_otg: otg-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "otg-bvalid", "otg-id",
"linestate";
status = "disabled";
};
};
1.2.3 电源配置
(1) USB2.0 PHY1
芯片三路电源依次为VCCA0V9_S3
、VCCA1V8_S3
、VCC3V3_S3
, 这个配置上面已经介绍了,不再重复介绍。
(2) USB3.0 Type-C PHY1
芯片三路电源和USB2.0 PHY1
芯片三路电源一样。
(3) USB3.0 Host Type-A
接口电源VCC5V0_HOST2
由RT9724GQW
提供的,其输入端为VCC5V0_SYS
。
在arch/arm64/boot/dts/rockchip/rk3399-evb.dts
配置vcc5v2_host
;
vcc5v0_sys: vcc5v0-sys {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_sys";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
};
vcc5v2_host: vcc5v2-host-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc5v2_host";
regulator-always-on;
regulator-boot-on;
vin-supply = <&vcc5v0_sys>;
};
1.2.4 使能
下面介绍的都是配置在arch/arm64/boot/dts/rockchip/rk3399-evb.dts
文件。
(1) 使能usbdrd3_1
:
/* Configurate and Enable USB3.0 OTG Controller */
&usbdrd3_1 {
status = "okay";
};
&usbdrd_dwc3_1 {
/* 配置dr_mode为host,表示只支持Host only mode */
dr_mode = "host";
status = "okay";
};
(2) 使能tcphy1_usb3
;
/* Enable USB3.0 PHY */
&tcphy1 {
status = "okay";
};
&tcphy1_usb3{
status = "okay";
};
(3) 使能u2phy1_otg
,同时配置USB2.0 OTG PHY1 phy-supply
属性,用于控制USB
电源VBUS
;
/* Enable USB2.0 PHY */
&u2phy1 {
status = "okay";
};
&u2phy1_otg {
phy-supply = <&vcc5v2_host>;
status = "okay";
};
1.2.5 总结
USB3.0 Host Type-A
接口设备树配置的注意点如下:
- 对应的
fusb
节点不要配置,因为USB3.0 Host Type-A
接口不需要fusb302
芯片; - 对应的
USB
控制器子节点(usbdrd_dwc3
)和PHY
的节点(tcphy
和u2phy
)都要删除extcon
属性; - 对应的
USB
控制器子节点(usbdrd_dwc3
)的dr_mode
属性要配置为host
;
1.3 USB3.0 Type-C
NanoPC-T4
开发板支持1个USB3.0 Type-C
接口,对应的USB
控制器为USB3.0 OTG0(DWC3/xHCI)
、对应的USB PHY
为USB3.0 Type-C PHY0
和USB2.0 OTG PHY0
;
因此对应的设备树配置,包括USB3.0 OTG0(DWC3/xHCI)
控制器设备树配置和USB3.0 Type-C PHY0
、USB2.0 OTG PHY0
设备树配置。
1.3.1 控制器配置
(1) USB3.0 OTG0(DWC3/xHCI)
控制器设备节点usbdrd3_0
,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
usbdrd3_0: usb@fe800000 {
compatible = "rockchip,rk3399-dwc3";
#address-cells = <2>;
#size-cells = <2>;
ranges;
clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
<&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_RKSOC_AXI_PERF>,
<&cru ACLK_USB3>, <&cru ACLK_USB3_GRF>;
clock-names = "ref_clk", "suspend_clk",
"bus_clk", "aclk_usb3_rksoc_axi_perf",
"aclk_usb3", "grf_clk";
resets = <&cru SRST_A_USB3_OTG0>;
reset-names = "usb3-otg";
status = "disabled";
usbdrd_dwc3_0: usb@fe800000 {
compatible = "snps,dwc3";
reg = <0x0 0xfe800000 0x0 0x100000>;
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru SCLK_USB3OTG0_REF>, <&cru ACLK_USB3OTG0>,
<&cru SCLK_USB3OTG0_SUSPEND>;
clock-names = "ref", "bus_early", "suspend";
dr_mode = "otg";
phys = <&u2phy0_otg>, <&tcphy0_usb3>;
phy-names = "usb2-phy", "usb3-phy";
phy_type = "utmi_wide";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis_u2_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,dis-tx-ipgap-linecheck-quirk;
power-domains = <&power RK3399_PD_USB3>;
status = "disabled";
};
};
1.3.2 PHY
配置
(1) USB3.0 Type-C PHY0
设备节点tcphy0_usb3
,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
tcphy0: phy@ff7c0000 {
compatible = "rockchip,rk3399-typec-phy";
reg = <0x0 0xff7c0000 0x0 0x40000>;
clocks = <&cru SCLK_UPHY0_TCPDCORE>,
<&cru SCLK_UPHY0_TCPDPHY_REF>;
clock-names = "tcpdcore", "tcpdphy-ref";
assigned-clocks = <&cru SCLK_UPHY0_TCPDCORE>;
assigned-clock-rates = <50000000>;
power-domains = <&power RK3399_PD_TCPD0>;
resets = <&cru SRST_UPHY0>,
<&cru SRST_UPHY0_PIPE_L00>,
<&cru SRST_P_UPHY0_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
rockchip,grf = <&grf>;
status = "disabled";
tcphy0_dp: dp-port {
#phy-cells = <0>;
};
tcphy0_usb3: usb3-port {
#phy-cells = <0>;
};
};
(2) USB2.0 OTG PHY0
设备节点u2phy0_otg
,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi
;
u2phy0: usb2phy@e450 {
compatible = "rockchip,rk3399-usb2phy";
reg = <0xe450 0x10>;
clocks = <&cru SCLK_USB2PHY0_REF>;
clock-names = "phyclk";
#clock-cells = <0>;
clock-output-names = "clk_usbphy0_480m";
status = "disabled";
u2phy0_host: host-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "linestate";
status = "disabled";
};
u2phy0_otg: otg-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "otg-bvalid", "otg-id",
"linestate";
status = "disabled";
};
};
1.3.3 电源配置
(1) USB2.0 PHY0
芯片三路电源依次为VCCA0V9_S3
、VCCA1V8_S3
、VCC3V3_S3
, 这个配置上面已经介绍了,不再重复介绍。
(2) USB3.0 Type-C PHY0
芯片三路电源和USB2.0 PHY0
芯片三路电源一样。
(3) USB3.0 Type-C
接口电源VBUS_TYPEC
由RT9724GQW
提供的,其输入端为VCC5V0_SYS
。由GPIO4_D2
引脚使能,高电平有效;
在arch/arm64/boot/dts/rockchip/rk3399-evb.dts
配置vbus_typec
;
vcc5v0_sys: vcc5v0-sys {
compatible = "regulator-fixed";
regulator-name = "vcc5v0_sys";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
};
vbus_typec: vbus-typec {
compatible = "regulator-fixed";
enable-active-high;
gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&vbus_typec_en>;
regulator-name = "vbus_typec";
vin-supply = <&vcc5v0_sys>;
};
由于vbus_typec
节点配置了default
状态对应的引脚配置节点为vbus_typec_en
,因此需要在pinctrl
节点下增加引脚配置节点vbus_typec_en
,这个节点在fusb
配置中介绍。
1.3.4 fusb302
配置
在arch/arm64/boot/dts/rockchip/rk3399-evb.dts
配置:
&i2c4 {
clock-frequency = <400000>;
i2c-scl-rising-time-ns = <160>;
i2c-scl-falling-time-ns = <30>;
status = "okay";
fusb0: typec-portc@22 {
compatible = "fcs,fusb302";
reg = <0x22>;
interrupt-parent = <&gpio1>;
interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&fusb0_int>;
vbus-supply = <&vbus_typec>;
status = "okay";
};
};
&pinctrl {
fusb30x {
fusb0_int: fusb0-int {
rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
};
vbus_typec_en: vbus-typec-en {
rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
......
}
其中GPIO1_A2
连接了fusb302
的中断引脚,低电平触发。
fusb0
设备节点匹配的驱动程序是drivers/usb/typec/tcpm/fusb302.c
,这里fusb0
设备节点配置的可能有问题,因此后面测试的时候无法自动识别是接入了USB
主机或USB
设备。这里我就不去追究如何配置了,具体可以参考:
Documentation/devicetree/bindings/usb/fcs,fusb302.yaml
;Documentation/devicetree/bindings/connector/usb-connector.yaml
;- 《
Rockchip RK3588
- 移植uboot 2017.09 & linux 6.1
(友善之家脚本方式)》。
如果你使用的是linux 4.19
,更改设备节点fusb0
如下:
&i2c4 {
.....
fusb0: fusb30x@22 {
compatible = "fairchild,fusb302";
reg = <0x22>;
pinctrl-names = "default";
pinctrl-0 = <&fusb0_int>;
int-n-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; /* 中断引脚GPIO1_A2配置 */
vbus-5v-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; /* VBUS使能引脚GPIO4_D2配置 */
status = "okay";
};
};
fusb0
设备节点匹配的驱动程序是drivers/mfd/fusb302.c
。
1.3.5 使能
下面介绍的都是配置在arch/arm64/boot/dts/rockchip/rk3399-evb.dts
文件。
(1) 使能usbdrd3_0
:
通过dr_mode
属性设置USB
控制器的模式,一共有三种模式:otg
(同时支持主机/设备)、host
(主机)、peripheral
(设备);这里配置为otg
;
/* Configurate and Enable USB3.0 OTG Controller notifier */
&usbdrd3_0 {
status = "okay";
};
&usbdrd_dwc3_0 {
/* 配置dr_mode为otg */
dr_mode = "otg";
status = "okay";
};
需要注意的是由于我们使用的是linux 6.3
内核,内核没有支持驱动drivers/mfd/fusb302.c
,导致不会为fusb302
驱动注册extcon
设备,因此不要在usbdrd3_0
设备节点配置extcon
属性,不然将会由于找不到extcon
,导致usbdrd3_0
无法正常工作;并且出现类似如下错误:
[ 24.692156] platform ff7c0000.phy: deferred probe pending
[ 24.692188] platform fe800000.usb: deferred probe pending
如果你使用的是linux 4.19
的内核,由于内核支持驱动drivers/mfd/fusb302.c
,因此在usbdrd3_0
节点配置extcon
属性;
&usbdrd3_0 {
status = "okay";
/* 配置extcon属性,用于接收fusb302驱动的UFP/DFP */
extcon = <&fusb0>;
};
(2) 使能tcphy0_usb3
;
/* Enable USB3.0 PHY */
&tcphy0 {
status = "okay";
};
&tcphy0_usb3{
status = "okay";
};
同上,如果是linux 4.19
的内核,需要在tcphy0
节点配置extcon
属性。
(3) 使能u2phy0_otg
,同时配置USB2.0 OTG PHY0 phy-supply
属性,用于控制USB
电源VBUS
;
/* Enable USB2.0 PHY */
&u2phy0 {
status = "okay";
};
&u2phy0_otg {
phy-supply = <&vbus_typec>;
status = "okay";
};
同上,如果是linux 4.19
的内核,需要在u2phy0
节点配置extcon
属性。
1.3.6 总结
USB3.0 Type-C
设备树配置的注意点如下:
- 对应的
fusb
节点需要配置,因为USB3.0 Type-C
需要fusb302
芯片; - 对应的
USB
控制器子节点(usbdrd_dwc3
)和PHY
的节点(tcphy
和u2phy
)都要配置extcon
属性; - 对应的
USB
控制器子节点(usbdrd_dwc3
)的dr_mode
属性要配置为otg
;
二、 配置内核
2.1 配置USB PHY
在linux
内核根目录下执行make menuconfig
配置以下选项:
Device Drivers --->
PHY Subsystem --->
<*> Rockchip INNO USB2PHY Driver
<*> Rockchip TYPEC PHY Driver
USB2.0 PHY
使用的是Innosilicon IP
,应选择Rockchip INNO USB2PHY Driver
,驱动位于drivers/phy/rockchip/phy-rockchip-inno-usb2.c
;
USB3.0 Type-C PHY
使用的是Type-C
[Vendor: Cadence
],应选择Rockchip TYPEC PHY Driver
,驱动位于drivers/phy/rockchip/phy-rockchip-typec.c
;
2.2 配置USB
控制器
在linux
内核根目录下执行make menuconfig
配置以下选项:
Device Drivers --->
[*] USB support --->
<*> xHCI HCD (USB 3.0) support
-*- Generic xHCI driver for a platform device
<*> EHCI HCD (USB 2.0) support
-*- Root Hub Transaction Translators
[*] Improved Transaction Translator scheduling
<*> Generic EHCI driver for a platform device
<*> OHCI HCD (USB 1.1) support
<*> Generic OHCI driver for a platform device
<*> USB support -->
[*] USB announce new devices(输出识别的每个usb设备的基本信息,比如idVendor、idProduct、制造商、产品、和序列号等)
OHCI HCD (USB 1.1)
选择OHCI Driver
配置;
EHCI HCD (USB 2.0)
选择EHCI Driver
配置;
xHCI HCD (USB 3.0)
选择xHCI Driver
配置。
2.3 配置USB OTG
默认情况下dw3
是双角色(即同时支持Host
和Device
模式,可以动态切换):
Device Drivers --->
[*] USB support --->
<*> DesignWare USB2 DRD Core Support
DWC2 Mode Selection (Dual Role mode)
<*> DesignWare USB3 DRD Core Support
DWC3 Mode Selection (Dual Role mode)
RK3399 USB3.0 OTG
使用Synopsys
方案,即xHCI
扩展的DWC3
控制器,因此需要配置DesignWare USB3 DRD Core Support
。
2.4 配置USB Gadget
由于我们将USB3.0 Type-C
接口配置为了USB OTG
,作为USB device
(丛机)使用,因此我们可以将开发板模拟成一个存储设备、或者声卡、鼠标等设备,然后可以通过开发板上的USB3.0 Type-C
接口将PC
和开发板连接在一起。
在linux
内核根目录下执行make menuconfig
配置以下选项:
File systems --->
Pseudo filesystems --->
/* 配置CONFIG_CONFIGFS_FS,为用户空间提供访问配置内核驱动的configfs文件系统 */
-*- Userspace-driven configuration filesystem
Device Drivers --->
[*] USB support --->
<*> USB Gadget Support --->
/* 配置了CONFIG_USB_CONFIGFS、同时会自动配置CONFIG_USB_LIBCOMPOSITE(生成libcomposite.ko,提供USB Gadget Composite框架) */
/* 需要注意的是CONFIG_USB_CONFIGFS配置成了模块,下面的usb_f_xxx.ko也会编译成模块,因为他们依赖于libcomposite.ko */
/* 这里之所以都选择为模块的形式,是为了调试方便,有些模块,比如U盘加载时还需要提供介质,就是说加载模块时还需要参数,否则加载不上 */
<M> USB Gadget functions configurable through configfs
[*] Generic serial bulk in/out /* usb_f_serial.ko */
[*] Abstract Control Model (CDC ACM) /* usb_f_acm.ko */
[*] Object Exchange Model (CDC OBEX) /* usb_f_obex.ko */
[*] Network Control Model (CDC NCM) /* usb_f_ncm.ko */
[*] Ethernet Control Model (CDC ECM) /* usb_f_ecm.ko */
[*] Ethernet Control Model (CDC ECM) subset /* usb_f_ecm_subset.ko */
[*] RNDIS /* usb_f_rndis.ko */
[*] Ethernet Emulation Model (EEM) /* usb_f_eem.ko */
[*] Mass storage (大容量存储功能) /* usb_f_mass_storage.ko */
[ ] Loopback and sourcesink function (for testing)
/* 文件系统功能(FunctionFS)可以让用户在用户空间中创建USB复合功能,就像GadgetFS可以让用户在用户空间中创建USB设备一样 */
[*] Function filesystem (FunctionFS) /* usb_f_fs.ko */
[*] Audio Class 1.0 (音频功能 1.0) /* usb_f_uac1.ko */
[*] Audio Class 1.0 (legacy implementation) /* usb_f_uac1_legacy.ko */
[*] Audio Class 2.0 (音频功能 2.0) /* usb_f_uac2.ko */
[ ] MIDI function
[*] HID function (HID功能) /* usb_f_hid.ko */
[*] USB Webcam functio (USB摄像头功能) /* usb_f_uvc.ko */
[ ] Printer function
USB Gadget precomposed configurations ---> /* USB Gadget预配置(位于drivers/usb/gadget/legacy) */
<M> Audio Gadget (音频设备) /* g_audio.ko */
< > Ethernet Gadget (with CDC Ethernet support) (网络设备)
< > Network Control Model (NCM) support
<M> Gadget Filesystem /* 配置CONFIG_USB_GADGETFS */
<M> Function Filesystem /* 配置CONFIG_USB_FUNCTIONFS */
<M> Mass Storage Gadget (大容量存储设备) /* g_mass_storage.ko */
< > Serial Gadget (with CDC ACM and CDC OBEX support) (串口设备)
< > MIDI Gadget
< > Printer Gadget (打印机)
< > CDC Composite Device (Ethernet and ACM)
< > CDC Composite Device (ACM and mass storage)
< > Multifunction Composite Gadget
<M> HID Gadget (hid设备) /* g_hid.ko */
< > EHCI Debug Device Gadget
< > USB Webcam Gadget (USB摄像头)
<*> USB Raw Gadget (生成设备节点/dev/raw-gadget)
USB Gadget
驱动主要包括两大块:
-
USB Gadget functions
:各种USB
子类设备功能接口驱动,位于drivers/usb/gadget/function
目录下,里面给出了对应的sample
。其作用是配置USB
子类协议的接口描述以及其它子类协议,比如uvc
协议,hid
等;比如我们配置了大容量存储设备驱动,编译完之后,就会在function
目录下生成usb_f_mass_storage.ko
; -
USB Gadget Legacy
:整个gadget
设备驱动的入口,位于drivers/usb/gadget/legacy
目录下,这个目录下的驱动目前已经过时了,不再建议使用了,以后的linux
版本或许会消失:里面给出了常用的USB
类设备的驱动sample
,其作用就是配置USB
设备描述符信息,提供一个usb_composite_driver
, 然后注册到composite
层;比如我们配置了大容量存储设备驱动,编译完之后,就会在legacy
目录下生成g_mass_storage.ko
;
有关USB Gadget
驱动更加具体内容参考《一文搞懂 USB
设备端驱动框架》。
下面我们介绍几个Gadget
设备驱动:
Mass Storage Gadget
用于模拟大容量存储设备;需要注意:linux
下的SD
卡、eMMC
文件系统一般是ext4
,在windows
下不识别;所以如果做实验,可以使用FAT
格式的存储器,比如U
盘;或者是NFTS
格式的移动硬盘;因此我们还需要配置内核支持exFAT
/NFTS
文件系统;
File systems
<*> FUSE (Filesystem in Userspace) support
DOS/FAT/EXFAT/NT Filesystems --->
< > MSDOS fs support
<*> VFAT (Windows-95) fs support
(437) Default codepage for FAT
(iso8859-1) Default iocharset for FAT
[*] Enable FAT UTF-8 option by default
<*> exFAT filesystem support
(utf8) Default iocharset for exFAT (NEW)
<*> NTFS file system support
[ ] NTFS debugging support
[*] NTFS write support
<*> NTFS Read-Write file system support
[*] 64 bits per NTFS clusters
[*] activate support of external compressions lzx/xpress
[*] NTFS POSIX Access Control Lists
-
Audio Gadget
:用于模拟声卡;USB
声卡就是USB
接口的外置声卡,一般电脑都自带了声卡,但是内部自带的声卡效果相对来说比较差,不能满足很多HIFI
玩家的需求,USB
声卡通过USB
接口来传递音频数据。具体的ADC
和DAC
过程由声卡完成,摆脱了电脑主板体积的限制,外置USB
声卡就可以做的很好。NanoPC-T4
开发板搭载了音频解码芯片,因此可以将NanoPC-T4
开发板作为一个外置USB
声卡。该驱动程序它会自动使用默认音频解码器来播放来自主机机器的音频。 -
HID Gadget
:用于模拟人机接口设备,包括键盘、鼠标、操纵杆、扫描仪、数字化板、触摸屏等。 -
Gadget Filesystem
:USB GadgetFS
提供了一种基于文件系统的API
,允许用户程序实现单个配置的USB
设备,包括端点I/O
和不涉及枚举的控制请求。所有硬件支持的端点、传输速度和传输类型都可以通过read
和write
调用进行访问; -
Function Filesystem
:USB FunctionFS
允许用户在用户空间中创建USB
组合功能,就像GadgetFS
允许用户在用户空间中创建USB
设备一样。这允许创建组合设备,其中一些功能在内核空间中实现(例如Ethernet
、串口或大容量存储),而其他功能在用户空间中实现;
2.5 配置USB
外设
根据开发板硬件情况,配置支持各种USB
设备。
2.5.1 配置大容量存储设备
移动硬盘属于SCSI
设备,所以在配置USB
模块之前需要配置SCSI
选项;
Device Drivers --->
SCSI device support --->
<*> SCSI device support
[*] legacy /proc/scsi/ support
*** SCSI support type (disk, tape, CD-ROM) ***
<*> SCSI disk support
< > SCSI tape support
< > SCSI CDROM support
<*> SCSI generic support
[*] /dev/bsg support (SG v4)
<*> SCSI media changer support
[*] Verbose SCSI error reporting (kernel size +=75K)
[*] SCSI logging facility
[*] Asynchronous SCSI scanning
SCSI Transports --->
[*] SCSI low-level drivers --->
[ ] SCSI Device Handlers ----
配置完SCSI Device Support
后,可以在USB Support
中找到如下选项,选上即可
Device Driver --->
[*] USB support --->
<*> USB Mass Storage support
2.5.2 配置USB
转串口
(1) 支持USB 3G Modem
USB 3G Modem
使用的是USB
转串口,使用时需要选上如下选项:
Device Driver --->
[*] USB support --->
<*> USB Serial Converter support --->
<*> USB driver for GSM and CDMA modems
此外,USB 3G Modem
还需要使能PPP
拨号的相关配置项:
Device Driver --->
[*] Network device support --->
<*> PPP (point-to-point protocol) support
<*> PPP BSD-Compress compression
<*> PPP Deflate compression
[*] PPP filtering
<*> PPP MPPE compression (encryption)
[*] PPP multilink support
<*> PPP over Ethernet
<*> PPP over L2TP
<*> PPP on L2TP Access Concentrator
<*> PPP on PPTP Network Server
<*> PPP support for async serial ports
<*> PPP support for sync tty ports
(2) 支持PL2303
如果要使用PL2303
输出数据到串口,需要选择如下选项,同时需要禁用 USB driver for GSM and CDMA modems
,否则,PL2303
可能会被误识别为USB 3G modem
;
Device Driver --->
[*] USB support --->
<*> USB Serial Converter support --->
<*> USB Prolific 2303 Single Port Serial Driver
(3) 支持USB GPS
如果要支持USB GPS
,如u-blox 6-GPS Receiver
设备,需要选择如下选项:
Device Drivers --->
[*] USB support --->
[*] USB Modem (CDC ACM) support
2.5.3 配置HID
在内核中,配置USB
键盘、鼠标、触摸屏驱动有多种方式,我们采用其中一种即可。
(1) 通用HID
驱动程序
如果要使用USB
接口的keyboards
(键盘)、mice
(鼠标)、joysticks
(摇杆)、graphic tablets
(绘图板)等其他的HID
设备,那么就需要配置USB HID Transport layer
(USB
人机接口设备传输层)。
USB HID transport layer
此选项对应配置项就是CONFIG_USB_HID
,也就是通用HID
驱动程序。
Device Drivers --->
[*] HID bus support
-*- HID bus core support
<*> Generic HID driver
USB HID support --->
<*> USB HID transport layer
[ ] PID device support
[*] /dev/hiddev raw HID device support
USB HID Transport Layer
是USB
协议栈中的一个组件,用于支持 HID
类型的设备与计算机之间的通信。USB HID
传输层负责解析来自HID
设备的数据,并将其转换为适当的格式,以便应用程序可以理解和使用。
通用HID
驱动程序在内核源码的drivers/hid/usbhid/
目录下,如下所示:
[root@rk3399 linux-6.3]# ls drivers/hid/usbhid/
built-in.a hid-core.o hiddev.o hid-pidff.o Makefile usbhid.h usbmouse.c
hid-core.c hiddev.c hid-pidff.c Kconfig modules.order usbkbd.c
在drivers/hid/usbhid/Makefile
:
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the USB input drivers
#
usbhid-y := hid-core.o
usbhid-$(CONFIG_USB_HIDDEV) += hiddev.o
usbhid-$(CONFIG_HID_PID) += hid-pidff.o
obj-$(CONFIG_USB_HID) += usbhid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o
如上面Makefile
所示,根据Kconfig
文件里CONFIG_USB_HID=y
或者m
,通用HID
驱动程序可以编译进内核,也可以编译成usbhid.ko
模块,usbhid.ko
可以由hid-core.c+hiddev.c+hid-pidff.c
组成。
当我们把USB
接口的鼠标/键盘接入到设备上时,在/dev/input
目录下会生成event*
设备,用evtest
工具打开/dev/input/event*
设备,移动鼠标和点击左/右键或者敲击键盘时会显示出相应的鼠标/键盘事件。
在某些嵌入式设备上,如果不想为USB
鼠标、键盘使用通用的HID
驱动程序,而更喜欢在其有限的Boot Protocol
模式下使用鼠标/键盘时,可以使用usbmouse.c/usbkbd.c
作为鼠标和键盘驱动程序。
关于USB
鼠标我们之前有单独的文章介绍:linux
驱动移植-usb
鼠标接口驱动。
关于USB
键盘我们之前有单独的文章介绍:linux
驱动移植-usb
键盘接口驱动。
(2) Generic input layer
实际上在linux
中还有一个通用输入层子系统,用于处理和管理各种输入设备,例如键盘、鼠标、触摸屏和游戏手柄等。通用输入层提供了一个统一的接口,使应用程序可以以一致的方式与不同类型的输入设备进行交互,配置如下:
Device Drivers --->
Input device support
-*- Generic input layer (needed for keyboard, mouse, ...)
那他们之间有什么区别呢?
区别在于:
-
Generic Input Layer
是Linux
内核的一个通用输入设备管理层,它与各种输入设备进行交互,并将输入数据传递给应用程序; -
USB HID Transport Layer
则是USB
协议栈中的一个特定组件,专门用于处理HID
设备的通信和数据传输;
通用输入层可以与各种输入设备一起使用(不仅限于USB HID
设备),而USB HID
传输层则专注于USB HID
设备的通信协议。针对于USB
输入设备,我们配置USB HID transport layer
即可。
2.5.4 配置USB
摄像头
Device Drivers -->
--- Multimedia support
[ ] Filter media drivers (取消选择)
Media core support --->
<*> Video4Linux core (NEW)
[*] Media Controller API (NEW)
Media drivers --->
[*] Media USB Adapters(启用usb总线的媒体驱动程序,drivers/media/usb)
<*> USB Video Class(UVC)(我们的摄像头支持UVC,选择这个驱动即可)
[*] UVC input events device supports(NEW)
<> GSPCA based webcams --> (GSPCA 是一个法国程序员在业余时间制作的一个万能USB 摄像头驱动程序,在此可以选择对应类型USB摄像头的支持)
<> SONIX Bayer USB Camer Driver (NEW)
<> OV772x/OV965x/... 系列摄像头支持
<> ....
[*] Media platform devices (NEW) --->
[*]V4L platform devices
关于USB
摄像头我们之前有单独的文章介绍:linux
驱动移植-usb
摄像头uvc
驱动。
2.5.5 配置USB
音频
Device Driver --->
<*> Sound card support --->
<*> Advanced Linux Sound Architecture --->
[*] USB sound devices --->
[*] USB Audio/MIDI driver
2.5.6 配置USB HUB
如果要支持USB HUB
,请将Disable external hubs
配置选项去掉;
Device Drivers --->
[*] USB support --->
[ ] Disable external hubs
其它有可能用到的USB
设备还有很多,如GPS
,Printer
等,有可能需要Vendor
定制的驱动,也有可能
是标准的 设备类驱动,如需支持这类设备,可直接在网络上搜索linux
对该设备支持要做的工作。
2.6 配置extcon
2.6.1 linux 6.3
配置
配置Fairchild FUSB302 Type-C chip driver
驱动,将drivers/usb/typec/tcpm/fusb302.c
编译到内核;
Device Driver --->
-*- External Connector Class (extcon) support --->
<*> USB support --->
<*> USB Type-C Support --->
[*] USB Type-C Port Controller Manager --->
[*] Fairchild FUSB302 Type-C chip driver
2.6.2 linux 4.19
配置
如果你使用的是linux 4.19
内核,则配置Fairchild fusb302 Support
驱动,将drivers/mfd/fusb302.c
编译到内核;
Device Driver --->
<*> Fairchild fusb302 Support
drivers/mfd/fusb302.c
驱动通过注册extcon
设备来识别是接入了USB
主机或USB
设备。
drivers/mfd/fusb302.c
的probe
函数:
点击查看代码
static int fusb30x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct fusb30x_chip *chip;
struct PD_CAP_INFO *pd_cap_info;
int ret;
char *string[2];
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
if (fusb30x_port_used == 0xff)
return -1;
chip->port_num = fusb30x_port_used++;
fusb30x_port_info[chip->port_num] = chip;
chip->dev = &client->dev;
chip->regmap = devm_regmap_init_i2c(client, &fusb302_regmap_config);
if (IS_ERR(chip->regmap)) {
dev_err(&client->dev, "Failed to allocate regmap!\n");
return PTR_ERR(chip->regmap);
}
ret = fusb_initialize_gpio(chip);
if (ret)
return ret;
fusb_initialize_timer(chip);
chip->fusb30x_wq = create_workqueue("fusb302_wq");
INIT_WORK(&chip->work, fusb302_work_func);
chip->role = ROLE_MODE_NONE;
chip->try_role = ROLE_MODE_NONE;
if (!of_property_read_string(chip->dev->of_node, "fusb302,role",
(const char **)&string[0])) {
if (!strcmp(string[0], "ROLE_MODE_DRP"))
chip->role = ROLE_MODE_DRP;
else if (!strcmp(string[0], "ROLE_MODE_DFP"))
chip->role = ROLE_MODE_DFP;
else if (!strcmp(string[0], "ROLE_MODE_UFP"))
chip->role = ROLE_MODE_UFP;
}
if (chip->role == ROLE_MODE_NONE) {
dev_warn(chip->dev,
"Can't get property of role, set role to default DRP\n");
chip->role = ROLE_MODE_DRP;
string[0] = "ROLE_MODE_DRP";
}
if (!of_property_read_string(chip->dev->of_node, "fusb302,try_role",
(const char **)&string[1])) {
if (!strcmp(string[1], "ROLE_MODE_DFP"))
chip->try_role = ROLE_MODE_DFP;
else if (!strcmp(string[1], "ROLE_MODE_UFP"))
chip->try_role = ROLE_MODE_UFP;
}
if (chip->try_role == ROLE_MODE_NONE)
string[1] = "ROLE_MODE_NONE";
chip->vconn_supported = true;
tcpm_init(chip);
tcpm_set_rx_enable(chip, 0);
chip->conn_state = unattached;
tcpm_set_cc(chip, chip->role);
chip->n_caps_used = 1;
chip->source_power_supply[0] = 0x64;
chip->source_max_current[0] = 0x96;
pd_cap_info = &chip->pd_cap_info;
pd_cap_info->dual_role_power = 1;
pd_cap_info->data_role_swap = 1;
pd_cap_info->externally_powered = 1;
pd_cap_info->usb_suspend_support = 0;
pd_cap_info->usb_communications_cap = 0;
pd_cap_info->supply_type = 0;
pd_cap_info->peak_current = 0;
chip->extcon = devm_extcon_dev_allocate(&client->dev, fusb302_cable);
if (IS_ERR(chip->extcon)) {
dev_err(&client->dev, "allocat extcon failed\n");
return PTR_ERR(chip->extcon);
}
ret = devm_extcon_dev_register(&client->dev, chip->extcon);
if (ret) {
dev_err(&client->dev, "failed to register extcon: %d\n",
ret);
return ret;
}
ret = extcon_set_property_capability(chip->extcon, EXTCON_USB,
EXTCON_PROP_USB_TYPEC_POLARITY);
if (ret) {
dev_err(&client->dev,
"failed to set USB property capability: %d\n",
ret);
return ret;
}
ret = extcon_set_property_capability(chip->extcon, EXTCON_USB_HOST,
EXTCON_PROP_USB_TYPEC_POLARITY);
if (ret) {
dev_err(&client->dev,
"failed to set USB_HOST property capability: %d\n",
ret);
return ret;
}
ret = extcon_set_property_capability(chip->extcon, EXTCON_DISP_DP,
EXTCON_PROP_USB_TYPEC_POLARITY);
if (ret) {
dev_err(&client->dev,
"failed to set DISP_DP property capability: %d\n",
ret);
return ret;
}
ret = extcon_set_property_capability(chip->extcon, EXTCON_USB,
EXTCON_PROP_USB_SS);
if (ret) {
dev_err(&client->dev,
"failed to set USB USB_SS property capability: %d\n",
ret);
return ret;
}
ret = extcon_set_property_capability(chip->extcon, EXTCON_USB_HOST,
EXTCON_PROP_USB_SS);
if (ret) {
dev_err(&client->dev,
"failed to set USB_HOST USB_SS property capability: %d\n",
ret);
return ret;
}
ret = extcon_set_property_capability(chip->extcon, EXTCON_DISP_DP,
EXTCON_PROP_USB_SS);
if (ret) {
dev_err(&client->dev,
"failed to set DISP_DP USB_SS property capability: %d\n",
ret);
return ret;
}
ret = extcon_set_property_capability(chip->extcon, EXTCON_CHG_USB_FAST,
EXTCON_PROP_USB_TYPEC_POLARITY);
if (ret) {
dev_err(&client->dev,
"failed to set USB_PD property capability: %d\n", ret);
return ret;
}
i2c_set_clientdata(client, chip);
spin_lock_init(&chip->irq_lock);
chip->enable_irq = 1;
chip->gpio_int_irq = gpiod_to_irq(chip->gpio_int);
if (chip->gpio_int_irq < 0) {
dev_err(&client->dev,
"Unable to request IRQ for INT_N GPIO! %d\n",
ret);
ret = chip->gpio_int_irq;
goto IRQ_ERR;
}
ret = devm_request_threaded_irq(&client->dev,
chip->gpio_int_irq,
NULL,
cc_interrupt_handler,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
client->name,
chip);
if (ret) {
dev_err(&client->dev, "irq request failed\n");
goto IRQ_ERR;
}
dev_info(chip->dev,
"port %d probe success with role %s, try_role %s\n",
chip->port_num, string[0], string[1]);
chip->input = devm_input_allocate_device(&client->dev);
if (!chip->input) {
dev_err(chip->dev, "Can't allocate input dev\n");
ret = -ENOMEM;
goto IRQ_ERR;
}
chip->input->name = "Typec_Headphone";
chip->input->phys = "fusb302/typec";
input_set_capability(chip->input, EV_SW, SW_HEADPHONE_INSERT);
ret = input_register_device(chip->input);
if (ret) {
dev_err(chip->dev, "Can't register input device: %d\n", ret);
goto IRQ_ERR;
}
return 0;
IRQ_ERR:
destroy_workqueue(chip->fusb30x_wq);
return ret;
}
2.7 保存配置
配置完内核之后记得保存配置:
存档:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# mv rk3399_defconfig ./arch/arm64/configs/
重新配置内核(如果不想重新编译内核,可以存档一份到.config
):
root@zhengyang:/work/sambashare/rk3399/linux-6.3# make rk3399_defconfig
2.8 烧录内核
2.8.1 编译内核
在linux
内核根目录下执行如下命令进行编译内核:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# make -j8
u-boot-2023.04
路径下的mkimage
工具拷贝过来,然后在命令行使用mkimage
工具编译即可:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# cp ../u-boot-2023.04/tools/mkimage ./
root@zhengyang:/work/sambashare/rk3399/linux-6.3# ./mkimage -f kernel.its kernel.itb
2.8.2 通过tftp
烧录内核
给开发板上电,同时连接上网线,进入uboot
命令行。我们将内核拷贝到tftp
文件目录:
root@zhengyang:/work/sambashare/rk3399/linux-6.3# cp kernel.itb /work/tftpboot/
接着给开发板上电。通过uboot
命令行将kernel.itb
下到内存地址0x10000000
处:
=> tftp 0x10000000 kernel.itb
通过mmc write
命令将内核镜像烧录到eMMC
第0x8000
个扇区处:
=> mmc erase 0x8000 0xA000
=> mmc write 0x10000000 0x8000 0xA000
2.8.3 启动内核
我们重新启动开发板,我们会看到与USB
相关的日志:
[ 1.829924] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[ 1.830411] ehci-platform fe380000.usb: EHCI Host Controller
[ 1.830442] ohci-platform fe3a0000.usb: Generic Platform OHCI controller
[ 1.830485] ohci-platform fe3a0000.usb: new USB bus registered, assigned bus number 1
[ 1.830590] ehci-platform fe3c0000.usb: EHCI Host Controller
[ 1.830609] ohci-platform fe3e0000.usb: Generic Platform OHCI controller
[ 1.830621] ehci-platform fe3c0000.usb: new USB bus registered, assigned bus number 2
[ 1.830638] ohci-platform fe3e0000.usb: new USB bus registered, assigned bus number 3
[ 1.830658] ohci-platform fe3a0000.usb: irq 53, io mem 0xfe3a0000
[ 1.830761] ehci-platform fe3c0000.usb: irq 52, io mem 0xfe3c0000
[ 1.830789] ohci-platform fe3e0000.usb: irq 54, io mem 0xfe3e0000
[ 1.836166] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 4
[ 1.842483] ehci-platform fe380000.usb: new USB bus registered, assigned bus number 5
[ 1.850092] xhci-hcd xhci-hcd.0.auto: hcc params 0x0220fe64 hci version 0x110 quirks 0x0000000002010010
[ 1.853065] ehci-platform fe3c0000.usb: USB 2.0 started, EHCI 1.00
[ 1.853516] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.03
[ 1.853532] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 1.853544] usb usb2: Product: EHCI Host Controller
[ 1.853553] usb usb2: Manufacturer: Linux 6.3.0 ehci_hcd
[ 1.853562] usb usb2: SerialNumber: fe3c0000.usb
[ 1.854382] hub 2-0:1.0: USB hub found
[ 1.854450] hub 2-0:1.0: 1 port detected
[ 1.858836] ehci-platform fe380000.usb: irq 51, io mem 0xfe380000
[ 1.865071] xhci-hcd xhci-hcd.0.auto: irq 49, io mem 0xfe800000
[ 1.885063] ehci-platform fe380000.usb: USB 2.0 started, EHCI 1.00
[ 1.890257] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[ 1.897120] usb usb5: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.03
[ 2.023756] usb usb5: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 2.031870] usb usb5: Product: EHCI Host Controller
[ 2.037347] usb usb5: Manufacturer: Linux 6.3.0 ehci_hcd
[ 2.043306] usb usb5: SerialNumber: fe380000.usb
[ 2.049117] hub 5-0:1.0: USB hub found
[ 2.053375] hub 5-0:1.0: 1 port detected
[ 2.058339] usb usb1: New USB device found, idVendor=1d6b, idProduct=0001, bcdDevice= 6.03
[ 2.067630] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 2.075719] usb usb1: Product: Generic Platform OHCI controller
[ 2.082361] usb usb1: Manufacturer: Linux 6.3.0 ohci_hcd
[ 2.088316] usb usb1: SerialNumber: fe3a0000.usb
[ 2.094011] hub 1-0:1.0: USB hub found
[ 2.098273] hub 1-0:1.0: 1 port detected
[ 2.103093] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 6
[ 2.103266] usb usb3: New USB device found, idVendor=1d6b, idProduct=0001, bcdDevice= 6.03
[ 2.111691] xhci-hcd xhci-hcd.0.auto: Host supports USB 3.0 SuperSpeed
[ 2.120951] usb usb3: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 2.136415] usb usb3: Product: Generic Platform OHCI controller
[ 2.143068] usb usb3: Manufacturer: Linux 6.3.0 ohci_hcd
[ 2.149052] usb usb3: SerialNumber: fe3e0000.usb
[ 2.154791] hub 3-0:1.0: USB hub found
[ 2.159046] hub 3-0:1.0: 1 port detected
[ 2.164005] usb usb4: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.03
[ 2.173296] usb usb4: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 2.181386] usb usb4: Product: xHCI Host Controller
[ 2.186857] usb usb4: Manufacturer: Linux 6.3.0 xhci-hcd
[ 2.192813] usb usb4: SerialNumber: xhci-hcd.0.auto
[ 2.198818] hub 4-0:1.0: USB hub found
[ 2.203079] hub 4-0:1.0: 1 port detected
[ 2.207872] usb usb6: We don't know the algorithms for LPM for this host, disabling LPM.
[ 2.217093] usb usb6: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 6.03
[ 2.226375] usb usb6: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 2.234485] usb usb6: Product: xHCI Host Controller
[ 2.239956] usb usb6: Manufacturer: Linux 6.3.0 xhci-hcd
[ 2.245911] usb usb6: SerialNumber: xhci-hcd.0.auto
[ 2.251953] hub 6-0:1.0: USB hub found
[ 2.256206] hub 6-0:1.0: 1 port detected
[ 2.261191] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[ 2.267479] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 7
[ 2.276205] xhci-hcd xhci-hcd.1.auto: hcc params 0x0220fe64 hci version 0x110 quirks 0x0000000002010010
[ 2.286876] xhci-hcd xhci-hcd.1.auto: irq 50, io mem 0xfe900000
[ 2.293711] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[ 2.299883] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 8
[ 2.308563] xhci-hcd xhci-hcd.1.auto: Host supports USB 3.0 SuperSpeed
[ 2.316043] usb usb7: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.03
[ 2.325407] usb usb7: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 2.333513] usb usb7: Product: xHCI Host Controller
[ 2.338977] usb usb7: Manufacturer: Linux 6.3.0 xhci-hcd
[ 2.345017] usb usb7: SerialNumber: xhci-hcd.1.auto
[ 2.351075] hub 7-0:1.0: USB hub found
[ 2.355332] hub 7-0:1.0: 1 port detected
[ 2.360123] usb usb8: We don't know the algorithms for LPM for this host, disabling LPM.
[ 2.369320] usb usb8: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 6.03
[ 2.378593] usb usb8: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 2.386698] usb usb8: Product: xHCI Host Controller
[ 2.392169] usb usb8: Manufacturer: Linux 6.3.0 xhci-hcd
[ 2.398123] usb usb8: SerialNumber: xhci-hcd.1.auto
[ 2.404138] hub 8-0:1.0: USB hub found
[ 2.408398] hub 8-0:1.0: 1 port detected
[ 2.414435] usbcore: registered new interface driver usb-storage
[ 2.421325] usbcore: registered new interface driver pl2303
[ 2.427613] usbserial: USB Serial support registered for pl2303
[ 3.598344] usbcore: registered new interface driver uvcvideo
[ 3.718570] usbcore: registered new interface driver usbhid
[ 3.730651] usbhid: USB HID core driver
[ 3.744550] usbcore: registered new interface driver snd-usb-audio
从上面日志上可以看到总共注册了8个USB
总线,编号依次从1~8。每个USB
总线上对应一个USB
控制器,一共有8个USB
控制器;
-
ohci-platform fe3a0000.usb
:USB
总线编号为1,对应设备节点usb_host0_ohci
,对应开发板上接口为USBH2
; -
ehci-platform fe3c0000.usb
:USB
总线编号为2,对应设备节点usb_host1_ehci
,对应开发板上接口为USBH3
; -
ohci-platform fe3e0000.usb
:USB
总线编号为3,对应设备节点usb_host1_ohci
,对应开发板上接口为USBH3
; -
xhci-hcd xhci-hcd.0.auto(fe800000.usb)
:USB
总线编号为4,对应设备节点usbdrd3_0
,对应开发板上接口为Type-C/DP
; -
ehci-platform fe380000.usb
:USB
总线编号为5,对应设备节点usb_host0_ehci
,对应开发板上接口为USBH2
; -
xhci-hcd xhci-hcd.0.auto(fe800000.usb)
:USB
总线编号为6,对应设备节点usbdrd3_0
,对应开发板上接口为Type-C/DP
; -
xhci-hcd xhci-hcd.1.auto(fe900000.usb)
:USB
总线编号为7,对应设备节点usbdrd3_1
,对应开发板上接口为CON5
; -
xhci-hcd xhci-hcd.1.auto(fe900000.usb)
:USB
总线编号为8,对应设备节点usbdrd3_1
,对应开发板上接口为CON5
;
三、测试USB
设备
我们接下来在开发板USB2.0 Host Type-A
、USB3.0 Host Type-A
接口插入不同的USB
设备进行测试。
3.1 测试USB
鼠标
我们将USB
鼠标接到开发板其中一个USB2.0 Host Type-A
接口(对应开发板上的USBH3
), 我们可以在内核日志中,找到USB
鼠标信息的日志:
[ 1457.916575] usb 3-1: new full-speed USB device number 2 using ohci-platform
[ 1458.149684] usb 3-1: New USB device found, idVendor=046d, idProduct=c52b, bcdDevice=24.11
[ 1458.149723] usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 1458.149740] usb 3-1: Product: USB Receiver
[ 1458.149754] usb 3-1: Manufacturer: Logitech
[ 1458.161331] input: Logitech USB Receiver as /devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.0/0003:046D:C52B.0001/input/input1
[ 1458.221766] hid-generic 0003:046D:C52B.0001: input: USB HID v1.11 Keyboard [Logitech USB Receiver] on usb-fe3e0000.usb-1/input0
[ 1458.230238] input: Logitech USB Receiver Mouse as /devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.1/0003:046D:C52B.0002/input/input2
[ 1458.230914] input: Logitech USB Receiver Consumer Control as /devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.1/0003:046D:C52B.0002/input/input3
[ 1458.289373] input: Logitech USB Receiver System Control as /devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.1/0003:046D:C52B.0002/input/input4
[ 1458.290293] hid-generic 0003:046D:C52B.0002: input,hiddev96: USB HID v1.11 Mouse [Logitech USB Receiver] on usb-fe3e0000.usb-1/input1
[ 1458.297793] hid-generic 0003:046D:C52B.0003: hiddev97: USB HID v1.11 Device [Logitech USB Receiver] on usb-fe3e0000.usb-1/input2
此时可以在ubuntu
桌面系统测试鼠标,可以发现是可以正常使用的。
USB
鼠标工作在全速模式下,OHCI
控制器,USB1.1
通信协议,使用的USB
总线编号为3,设备编号为2。
日志开头表示的是:"驱动模块的名字: + 具体的信息",其中:
input:
描述的是将鼠标作为输入设备注册到内核,对应事件类输入设备节点/dev/input/event2
、/dev/input/event3
、/dev/input/event4
;hid-generic 0003:046D:C52B.xxxx
:鼠标匹配的驱动是hid-generic
驱动,这里可以看到注册了两个hid
设备节点:hiddev96
,hiddev97
。
3.2 测试USB
键盘
(1) 我们将USB
键盘接到开发板另一个USB2.0 Host Type-A
接口(对应开发板上的USBH2
),在内核日志中,找到USB
键盘信息的日志:
[ 1619.954338] usb 1-1: new low-speed USB device number 2 using ohci-platform
[ 1620.183564] usb 1-1: New USB device found, idVendor=1a2c, idProduct=4d7e, bcdDevice= 1.10
[ 1620.183603] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 1620.183620] usb 1-1: Product: USB Keyboard
[ 1620.183634] usb 1-1: Manufacturer: SEMICO
[ 1620.193197] input: SEMICO USB Keyboard as /devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.0/0003:1A2C:4D7E.0004/input/input6
[ 1620.251611] hid-generic 0003:1A2C:4D7E.0004: input: USB HID v1.10 Keyboard [SEMICO USB Keyboard] on usb-fe3a0000.usb-1/input0
[ 1620.263525] input: SEMICO USB Keyboard Consumer Control as /devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.1/0003:1A2C:4D7E.0005/input/input7
[ 1620.323415] input: SEMICO USB Keyboard System Control as /devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.1/0003:1A2C:4D7E.0005/input/input8
[ 1620.324115] input: SEMICO USB Keyboard as /devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.1/0003:1A2C:4D7E.0005/input/input10
[ 1620.324871] hid-generic 0003:1A2C:4D7E.0005: input,hiddev98: USB HID v1.10 Keyboard [SEMICO USB Keyboard] on usb-fe3a0000.usb-1/input1
此时可以在ubuntu
桌面系统测试键盘,可以发现是可以正常使用的。
USB
键盘工作在低速模式下,OHCI
控制器,USB1.0
通信协议,使用的USB
总线编号为1,设备编号为2。
这里可以看到注册了1个hid
设备节点:hiddev98
。
(2) 拔掉USB
键盘,尝试将USB
键盘接到USB3.0 Host Type-A
接口(对应开发板上的CON5
),在内核日志中,找到USB
键盘信息的日志:
[ 1665.652164] usb 1-1: USB disconnect, device number 2
[ 1678.668389] usb 7-1: new low-speed USB device number 2 using xhci-hcd
[ 1678.822673] usb 7-1: New USB device found, idVendor=1a2c, idProduct=4d7e, bcdDevice= 1.10
[ 1678.822713] usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 1678.822729] usb 7-1: Product: USB Keyboard
[ 1678.822743] usb 7-1: Manufacturer: SEMICO
[ 1678.850429] input: SEMICO USB Keyboard as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.0/0003:1A2C:4D7E.0006/input/input11
[ 1678.909715] hid-generic 0003:1A2C:4D7E.0006: input: USB HID v1.10 Keyboard [SEMICO USB Keyboard] on usb-xhci-hcd.1.auto-1/input0
[ 1678.921243] input: SEMICO USB Keyboard Consumer Control as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.1/0003:1A2C:4D7E.0007/input/input12
[ 1678.981216] input: SEMICO USB Keyboard System Control as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.1/0003:1A2C:4D7E.0007/input/input13
[ 1678.981907] input: SEMICO USB Keyboard as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.1/0003:1A2C:4D7E.0007/input/input15
[ 1678.982716] hid-generic 0003:1A2C:4D7E.0007: input,hiddev98: USB HID v1.10 Keyboard [SEMICO USB Keyboard] on usb-xhci-hcd.1.auto-1/input1
此时可以在ubuntu
桌面系统测试键盘,可以发现是可以正常使用的。
USB
键盘工作在低速模式下,xHCI
控制器,USB1.0
通信协议,使用的USB
总线编号为7,设备编号为2。
3.3 测试USB
摄像头
我们将USB
摄像头接到开发板的USB3.0 Host Type-A
接口(对应开发板上的CON5
),在内核日志中,找到USB
摄像头信息的日志:
[ 2305.074204] usb 7-1: USB disconnect, device number 2
[ 2323.296616] usb 7-1: new high-speed USB device number 3 using xhci-hcd
[ 2323.483982] usb 7-1: New USB device found, idVendor=0c45, idProduct=6340, bcdDevice= 0.00
[ 2323.484022] usb 7-1: New USB device strings: Mfr=2, Product=1, SerialNumber=0
[ 2323.484038] usb 7-1: Product: USB 2.0 Camera
[ 2323.484052] usb 7-1: Manufacturer: Sonix Technology Co., Ltd.
[ 2323.495745] usb 7-1: Found UVC 1.00 device USB 2.0 Camera (0c45:6340)
[ 2323.519918] input: USB 2.0 Camera: USB Camera as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.0/input/input16
USB
键盘工作在高速模式下,xHCI
控制器,USB2.0
通信协议,使用的USB
总线编号为7,设备编号为2。
从上面的信息可以看到这里,已经识别到了我们的USB
摄像头,VID=0c45
、PID=6340
。
安装应用程序茄子:
root@rk3399:/# sudo apt-get install cheese
在ubuntu
输入cheese
命令捕捉视频:
root@rk3399:/# cheese
如图所示:
3.4 测试移动硬盘
准备好一个移动硬盘,注意移动硬盘要为NFTS
格式的!NTFS
和exFAT
由于版权问题所以在Linux
下支持的不完善,操作的话可能会有问题,比如只能读,不能写或者无法识别等。
准备好以后将移动硬盘插入到开发板USB3.0 Host Type-A
接口(对应开发板上的CON5
),在内核日志中,找到移动硬盘信息的日志:
[ 3341.772611] usb 7-1: USB disconnect, device number 3
[ 3393.909693] usb 8-1: new SuperSpeed USB device number 2 using xhci-hcd
[ 3393.932045] usb 8-1: New USB device found, idVendor=0480, idProduct=b200, bcdDevice= 1.00
[ 3393.932085] usb 8-1: New USB device strings: Mfr=2, Product=3, SerialNumber=1
[ 3393.932102] usb 8-1: Product: External USB 3.0
[ 3393.932115] usb 8-1: Manufacturer: TOSHIBA
[ 3393.932129] usb 8-1: SerialNumber: 2018010302552D
[ 3393.936501] usb-storage 8-1:1.0: USB Mass Storage device detected
[ 3393.937468] scsi host0: usb-storage 8-1:1.0
[ 3394.970703] scsi 0:0:0:0: Direct-Access TOSHIBA External USB 3.0 0 PQ: 0 ANSI: 6
[ 3394.972008] sd 0:0:0:0: Attached scsi generic sg0 type 0
[ 3394.973469] sd 0:0:0:0: [sda] Spinning up disk...
[ 3395.993613] ...ready
[ 3398.068783] sd 0:0:0:0: [sda] 1953525168 512-byte logical blocks: (1.00 TB/932 GiB)
[ 3398.069873] sd 0:0:0:0: [sda] Write Protect is off
[ 3398.069891] sd 0:0:0:0: [sda] Mode Sense: 43 00 00 00
[ 3398.071119] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 3398.114863] sda: sda1 sda2 sda3 sda4 < sda5 >
[ 3398.116779] sd 0:0:0:0: [sda] Attached SCSI disk
移动硬盘工作在超高速模式下,xHCI
控制器,USB3.0
通信协议,使用的USB
总线编号为8,设备编号为2。
可以看出,系统检测到移动硬盘插入,大小为1TB
,对应的设备文件为/dev/sda
和/dev/sda1~5
,大家可以查看一下/dev
目录下有没有sda
和sda1~5
这6个文件;
root@rk3399:/# ll /dev/sda*
brw-rw---- 1 root disk 8, 0 Sep 16 15:28 /dev/sda
brw-rw---- 1 root disk 8, 1 Sep 16 15:28 /dev/sda1
brw-rw---- 1 root disk 8, 2 Sep 16 15:28 /dev/sda2
brw-rw---- 1 root disk 8, 3 Sep 16 15:28 /dev/sda3
brw-rw---- 1 root disk 8, 4 Sep 16 15:28 /dev/sda4
brw-rw---- 1 root disk 8, 5 Sep 16 15:28 /dev/sda5
其中:
/dev/sda
:是整个移动硬盘;/dev/sda1~5
: 是移动硬盘的第1个到第5个分区,这是是由于我在PC
上已经将移动硬盘分了5个分区;
(1) 要想访问移动硬盘我们需要先对移动硬盘进行挂载,理论上挂载到任意一个目录下都可以.
测试发现ubuntu系统会自动将移动硬盘下的各个分区挂载到/media/root
下;
root@rk3399:/media/root# df -T
Filesystem Type 1K-blocks Used Available Use% Mounted on
/dev/root ext4 14801956 4998424 9143588 36% /
devtmpfs devtmpfs 1950140 0 1950140 0% /dev
tmpfs tmpfs 1972572 0 1972572 0% /dev/shm
tmpfs tmpfs 394516 1760 392756 1% /run
tmpfs tmpfs 5120 4 5116 1% /run/lock
tmpfs tmpfs 1972572 0 1972572 0% /sys/fs/cgroup
tmpfs tmpfs 394512 16 394496 1% /run/user/0
/dev/sda3 fuseblk 209715196 14878708 194836488 8% /media/root/小白PE工具盘1
/dev/sda5 fuseblk 347613180 14758876 332854304 5% /media/root/小白PE工具盘
/dev/sda2 fuseblk 209715196 42328260 167386936 21% /media/root/程序
/dev/sda1 fuseblk 209715196 13973916 195741280 7% /media/root/学业
(2) 这里我创建一个/mnt/usb_disk
目录,然后将移动硬盘第一个分区挂载到/mnt/usb_disk
目录下,命令如下:
root@rk3399:/# mkdir -p /mnt/usb_disk
root@rk3399:/# mount /dev/sda1 /mnt/usb_disk/ -t ntfs -o iocharset=utf8
其中:
-t ntfs
:指定挂载所使用的文件系统类型,这里设置为ntfs
,也就是NTFS
文件系统;-o iocharset=utf8
:设置硬盘编码格式为utf8
,否则的话移动硬盘里面的中文会显示乱码;
如果挂载的时候出现如下错误:
root@rk3399:/# mount /dev/sda1 /mnt/usb_disk/ -t ntfs -o iocharset=utf8
Mount is denied because the NTFS volume is already exclusively opened.
The volume may be already mounted, or another software may use it which
could be identified for example by the help of the 'fuser' command.
通过错误语句的输出可以知道NTFS
卷被拒绝是因为已经执行打开,可能已经被挂载或者有应用程序正在使用它,可以使用fuser
命令显示正在使用指定的file
,file system
或者socket
的进程信息。
如fuser -m -u /dev/sda1
使用-m -u
显示正在使用/dev/sda1
的进程PID
以及用户名称,如我输入上述命令后显示的情况:
root@rk3399:/# fuser -m -u /dev/sda1
/dev/sda1: 5168(root)
root@rk3399:/# kill 5168
表明是PID
为5168的进程正在使用它,可以使用kill
命令杀死该进程,此时在使用mount
命令就不会出错了。
挂载成功以后进入到/mnt/usb_disk
目录下,输入ls
命令查看移动硬盘文件;
root@rk3399:/# cd /mnt/usb_disk/
root@rk3399:/mnt/usb_disk# ll
total 60
drwxrwxrwx 1 root root 8192 Jun 22 2021 '$RECYCLE.BIN'/
drwxrwxrwx 1 root root 12288 Jun 22 2021 ./
drwxr-xr-x 3 root root 4096 Sep 16 15:37 ../
drwxrwxrwx 1 root root 4096 Jun 22 2021 1.led/
drwxrwxrwx 1 root root 4096 Jun 22 2021 3.myboot/
drwxrwxrwx 1 root root 4096 Jun 22 2021 4.mmu/
drwxrwxrwx 1 root root 4096 Jun 22 2021 5.nadflash/
drwxrwxrwx 1 root root 8192 Jun 22 2021 6.interupt/
drwxrwxrwx 1 root root 4096 Jun 22 2021 7.uart/
drwxrwxrwx 1 root root 4096 Jun 22 2021 8.do_bootm_linux/
drwxrwxrwx 1 root root 4096 Dec 22 2021 'System Volume Information'/
至此移动硬盘就能正常读写操作了,直接对/mnt/usb_disk
目录进行操作就行了。如果要拔出移动硬盘要执行一个sync
命令进行同步,然后在使用unmount
进行移动硬盘卸载,命令如下所示:
root@rk3399:/mnt/usb_disk# sync
root@rk3399:/mnt/usb_disk# cd /
root@rk3399:/# umount /mnt/usb_disk
3.5 测试Type-C
触摸屏
现在我手里有一个NanoPC-T4
开发板,同时还有一个15.6
英寸HDMI
接口显示屏,并且该显示屏支持Type-C
十点触摸。
(1) 配置USB3.0 OTG0
的工作模式为Host
(主机),这种做法只会临时有效:
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
otg
root@rk3399:/lib/modules/6.3.0# echo host > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
host
如果想永久有效,可以通过修改设备树dr-mode = host
将工作配置为Host
(主机);具体可以参考:《Rockchip RK3399 - USB
触摸屏接口驱动》。
(2) 这里我们通过Type-C
线(两端都是Type-C
接口)将开发板USB3.0 Type-C
接口(对应开发板上的Type-C/DP
)与触摸屏的Type-C
接口连接起来。内核输出日志信息:
[ 2358.710215] usb 4-1: new full-speed USB device number 2 using xhci-hcd
[ 2358.862485] usb 4-1: New USB device found, idVendor=222a, idProduct=0001, bcdDevice= 1.00
[ 2358.862525] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2358.862542] usb 4-1: Product: SingWon-CTP-V1.18A
[ 2358.862555] usb 4-1: Manufacturer: UsbHID
[ 2358.862569] usb 4-1: SerialNumber: 6F6A099B1133
[ 2358.899245] input: UsbHID SingWon-CTP-V1.18A as /devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb4/4-1/4-1:1.0/0003:222A:0001.0003/input/input6
[ 2358.899571] hid-generic 0003:222A:0001.0003: input: USB HID v1.11 Device [UsbHID SingWon-CTP-V1.18A] on usb-xhci-hcd.0.auto-1/input0
[ 2358.903930] input: UsbHID SingWon-CTP-V1.18A as /devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb4/4-1/4-1:1.1/0003:222A:0001.0004/input/input7
[ 2358.966870] hid-generic 0003:222A:0001.0004: input: USB HID v1.12 Keyboard [UsbHID SingWon-CTP-V1.18A] on usb-xhci-hcd.0.auto-1/input1
此时可以在ubuntu
桌面系统测试触摸屏,可以发现触摸屏可以正常实用。
USB
触摸屏工作在全速模式下,xHCI
控制器,USB1.1
通信协议,使用的USB
总线编号为4,设备编号为2。
3.6 测试USB
4口HUB
集线器
这里我们将USB
4口HUB
集线器里连接到开发板USB3.0 Host Type-A
接口(对应开发板上的CON5
)。内核输出日志信息:
[ 232.825153] usb 7-1: new high-speed USB device number 4 using xhci-hcd
[ 232.975149] usb 7-1: New USB device found, idVendor=14cd, idProduct=8601, bcdDevice= 0.00
[ 232.975188] usb 7-1: New USB device strings: Mfr=1, Product=3, SerialNumber=0
[ 232.975204] usb 7-1: Product: USB 2.0 Hub
[ 232.975218] usb 7-1: Manufacturer: USB Device
[ 233.011052] hub 7-1:1.0: USB hub found
[ 233.011213] hub 7-1:1.0: 4 ports detected
USB
键盘工作在高速模式下,xHCI
控制器,USB2.0
通信协议,使用的USB
总线编号为7,设备编号为4。
从上面的信息可以看到这里,已经识别到了我们的USB
4口HUB
集线器,VID=14cd
、PID=8601
,并且有4个端口。
我们尝试在将USB
鼠标插入HUB
其中一个端口,内核输出日志信息:
[ 450.823397] usb 7-1.1: new full-speed USB device number 5 using xhci-hcd
[ 450.928638] usb 7-1.1: New USB device found, idVendor=046d, idProduct=c52b, bcdDevice=24.11
[ 450.928677] usb 7-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 450.928694] usb 7-1.1: Product: USB Receiver
[ 450.928707] usb 7-1.1: Manufacturer: Logitech
[ 451.031478] input: Logitech USB Receiver as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1.1/7-1.1:1.0/0003:046D:C52B.0006/input/input11
[ 451.092719] hid-generic 0003:046D:C52B.0006: input: USB HID v1.11 Keyboard [Logitech USB Receiver] on usb-xhci-hcd.1.auto-1.1/input0
[ 451.099030] input: Logitech USB Receiver Mouse as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1.1/7-1.1:1.1/0003:046D:C52B.0007/input/input12
[ 451.099733] input: Logitech USB Receiver Consumer Control as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1.1/7-1.1:1.1/0003:046D:C52B.0007/input/input13
[ 451.160075] input: Logitech USB Receiver System Control as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1.1/7-1.1:1.1/0003:046D:C52B.0007/input/input14
[ 451.160547] hid-generic 0003:046D:C52B.0007: input,hiddev97: USB HID v1.11 Mouse [Logitech USB Receiver] on usb-xhci-hcd.1.auto-1.1/input1
[ 451.165557] hid-generic 0003:046D:C52B.0008: hiddev98: USB HID v1.11 Device [Logitech USB Receiver] on usb-xhci-hcd.1.auto-1.1/input2
此时可以在ubuntu
桌面系统测试鼠标,可以发现是可以正常使用的。
USB
鼠标工作在全速模式下,xHCI
控制器,USB1.1
通信协议,使用的USB
总线编号为7,设备编号为5。
四、 模拟USB
设备
本节的目标是将我们的开发板设置成从设备,从而实现和PC
的通信,既然是将开发板模拟成从设备,首先想到的就是USB3.0 OTG控制器
,我们需要工作模式dr-mode
配置成otg
或者peripheral
。
然后我们还需要实现一个USB Gadget
驱动,实现方法有多种,这里我们介绍其中的两种:
- 使用内核中提供的
USB Gadget
驱动,即我们在USB Gadget precomposed configurations
中配置的驱动; - 使用内核提供的
USB Gadget Configfs
,它提供了一种用户配置USB Gadget
的方式,通过configfs
可以动态的创建和配置USB Gadaget
从设备,而无需修改内核源代码或重新编译内核;
注意:使用内核提供的USB Gadget Configfs
,必须配置CONFIG_CONFIGFS_FS
和CONFIG_USB_LIBCOMPOSITE
的宏,前者为用户空间提供访问配置内核驱动的configfs
文件系统,后者提供USB Gadget Composite
框架;
4.1 模拟存储设备
我们需要按照前面的内核配置将USB Gadget precomposed configurations
---> Mass Storage Gadget
驱动编译成模块。使用的时候直接输入命令加载驱动即可。
(1) 配置好以后重新linux
内核,会得到三个.ko
驱动文件:
drivers/usb/gadget/libcomposite.ko
drivers/usb/gadget/function/usb_f_mass_storage.ko
drivers/usb/gadget/legacy/g_mass_storage.ko
(2) 重新烧录内核,启动开发板。将上述三个.ko
模块拷贝到开发板/lib/modules/6.3.0
(如果没有该目录,自行创建),命令如下:
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/modules.builtin /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/modules.order /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/libcomposite.ko /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/function/usb_f_mass_storage.ko /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/legacy/g_mass_storage.ko /lib/modules/6.3.0
(3) 在开发板插入一个移动硬盘到我们的USB3.0 Host Type-A
接口,并使用Type-C
连接线,并按照之前介绍的将/dev/sda1
分区挂载到/mnt/usb_disk
目录下;
root@rk3399:/# mount /dev/sda1 /mnt/usb_disk/ -t ntfs -o iocharset=utf8
最后将开发板USB3.0 Type-C
接口与PC
连接起来。
(4) 配置USB3.0 OTG0
的工作模式为Device
(设备),这种做法只会临时有效:
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
otg
root@rk3399:/lib/modules/6.3.0# echo device > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
device
如果想永久有效,可以通过修改设备树dr-mode = peripheral
将工作配置为Device
(设备);
(5) 需要在加载模块之前建立该模块的依赖关系,也即必须用depmod
来更新一下/lib/modules/linux-6.3/modules.dep
文件;
root@rk3399:/lib/modules/6.3.0# cd /lib/modules/6.3.0
root@rk3399:/lib/modules/6.3.0# depmod -a
root@rk3399:/lib/modules/6.3.0# modprobe libcomposite
root@rk3399:/lib/modules/6.3.0# modprobe usb_f_mass_storage
root@rk3399:/lib/modules/6.3.0# modprobe g_mass_storage file=/dev/sda1 removable=1
modprobe
和insmode
的区别在于modprobe
可以动态加载依赖的驱动,而insmode
必须一个一个加载。加载g_mass_storage
的时候使用file
参数指定使用的大容量存储设备对应的/dev/sda1
。同时内核会输出如下日志:
[ 390.786425] Mass Storage Function, version: 2009/09/11
[ 390.786459] LUN: removable file: (no medium)
[ 390.786724] LUN: removable file: /dev/sda1
[ 390.786743] Number of LUNs=1
[ 390.786975] g_mass_storage gadget.0: Mass Storage Gadget, version: 2009/09/11
[ 390.786995] g_mass_storage gadget.0: userspace failed to provide iSerialNumber
[ 390.787005] g_mass_storage gadget.0: g_mass_storage ready
通过命令可以查看我们已经加载的驱动:
root@rk3399:/lib/modules/6.3.0# lsmod
Module Size Used by
#### 下面是我们刚才加载的 ######
g_mass_storage 16384 0
usb_f_mass_storage 69632 2 g_mass_storage
libcomposite 81920 2 usb_f_mass_storage,g_mass_storage
#### 下面是wifi相关的,忽略即可 #####
brcmfmac_wcc 16384 0
brcmfmac 348160 1 brcmfmac_wcc
cfg80211 901120 1 brcmfmac
brcmutil 24576 1 brcmfmac
如果加载成功的话PC
就会出现一个移动硬盘,如下图所示:
(6) 我们可以直接在电脑上对这个移动硬盘进行读写操作,实际上操作的就是我们的移动硬盘,操作完成以后要退出的话执行如下命令:
root@rk3399:/lib/modules/6.3.0# rmmod g_mass_storage
4.2 模拟声卡
我们需要按照前面的内核配置将USB Gadget precomposed configurations
---> Audio Gadget
驱动编译成模块。使用的时候直接输入命令加载驱动即可。
(1) 配置好以后重新linux
内核,会得到5个.ko
驱动文件:
drivers/usb/gadget/libcomposite.ko
drivers/usb/gadget/function/usb_f_uac1.ko
drivers/usb/gadget/function/u_audio.ko
drivers/usb/gadget/legacy/g_audio.ko
(2) 重新烧录内核,启动开发板。将上述5个.ko
模块拷贝到开发板/lib/modules/6.3.0
(如果没有该目录,自行创建),命令如下:
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/modules.builtin /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/modules.order /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/libcomposite.ko /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/function/usb_f_uac1.ko /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/function/u_audio.ko /lib/modules/6.3.0
root@rk3399:/lib# scp -r root@192.168.0.200:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/legacy/g_audio.ko /lib/modules/6.3.0
(3) 首先按照我们之前声卡驱动移植章节介绍的,保证声卡可以正常播放。
使用Type-C
连接线,将开发板USB3.0 Type-C
接口与PC
连接起来。
(4) 配置USB3.0 OTG0
的工作模式为Device
(设备),这种做法只会临时有效:
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
otg
root@rk3399:/lib/modules/6.3.0# echo device > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
device
如果想永久有效,可以通过修改设备树dr-mode = peripheral
将工作配置为Device
(设备);
(5) 需要在加载模块之前建立该模块的依赖关系,也即必须用depmod
来更新一下/lib/modules/linux-6.3/modules.dep
文件;
root@rk3399:~# cd /lib/modules/6.3.0
root@rk3399:/lib/modules/6.3.0# depmod -a
root@rk3399:/lib/modules/6.3.0# modprobe libcomposite
root@rk3399:/lib/modules/6.3.0# modprobe u_audio
root@rk3399:/lib/modules/6.3.0# modprobe usb_f_uac1
root@rk3399:/lib/modules/6.3.0# modprobe g_audio
modprobe
和insmode
的区别在于modprobe
可以动态加载依赖的驱动,而insmode
必须一个一个加载。内核会输出如下日志:
[ 1863.468513] g_audio gadget.0: Linux USB Audio Gadget, version: Feb 2, 2012
[ 1863.468535] g_audio gadget.0: g_audio ready
通过命令可以查看我们已经加载的驱动:
root@rk3399:/lib/modules/6.3.0# lsmod
Module Size Used by
#### 下面是我们刚才加载的 ######
g_audio 16384 0
usb_f_uac1 36864 0
u_audio 32768 2 usb_f_uac1,usb_f_uac2
libcomposite 81920 5 usb_f_uac1,u_audio,g_audio,usb_f_mass_storage,usb_f_uac2
#### 下面是wifi相关的,忽略即可 #####
brcmfmac_wcc 16384 0
brcmfmac 348160 1 brcmfmac_wcc
cfg80211 901120 1 brcmfmac
brcmutil 24576 1 brcmfmac
加载完成以后稍等一会虚拟出一个USB
声卡,打开电脑的设备管理器,选择声音、视频和游戏控制器,会出现有一个名为Source/Sink
设备,如下图所示:
选择该设备,并通过PC
播放音乐,不过这里我测试始终没有声音输出,具体原因还不太清除;
(6) 移除驱动:
root@rk3399:/lib/modules/6.3.0# rmmod g_audio
4.3 configfs
模拟U
盘
这里我们USB Gadget Configfs
来模拟一个大容量存储设备。
4.3.1 挂载configfs
首先需要挂载configfs
到/sys/kernel/config
目录下:
root@rk3399:/# mount -t configfs none /sys/kernel/config
创建g1
文件夹,创建完g1
之后,会在该目录下生成很多配置目录;
root@rk3399:/# cd /sys/kernel/config/usb_gadget
root@rk3399:/sys/kernel/config/usb_gadget# mkdir -p g1
root@rk3399:/sys/kernel/config/usb_gadget# ll g1/
-rw-r--r-- 1 root root 4096 Sep 17 22:16 UDC
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bDeviceClass
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bDeviceProtocol
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bDeviceSubClass
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bMaxPacketSize0
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bcdDevice
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bcdUSB
drwxr-xr-x 2 root root 0 Sep 17 22:16 configs/
drwxr-xr-x 2 root root 0 Sep 17 22:16 functions/
-rw-r--r-- 1 root root 4096 Sep 17 22:16 idProduct
-rw-r--r-- 1 root root 4096 Sep 17 22:16 idVendor
-rw-r--r-- 1 root root 4096 Sep 17 22:16 max_speed
drwxr-xr-x 2 root root 0 Sep 17 22:16 os_desc/
drwxr-xr-x 2 root root 0 Sep 17 22:16 strings/
drwxr-xr-x 2 root root 0 Sep 17 22:16 webusb/
这里的g1
表示gadget 1
,一个UDC
对应一个gadget
,如果SoC
上有多个gadget
,可以创建多个gx
目录。
4.3.2 加载功能接口(function
)驱动
configfs
开启gadget
驱动测试前,需要加载usb_f_mass_storage
驱动程序:
root@rk3399:/lib/modules/6.3.0# cd /lib/modules/6.3.0
root@rk3399:/lib/modules/6.3.0# depmod -a
root@rk3399:/lib/modules/6.3.0# modprobe libcomposite
root@rk3399:/lib/modules/6.3.0# modprobe usb_f_mass_storage
root@rk3399:/lib/modules/6.3.0# cd /sys/kernel/config/usb_gadget/g1
4.3.4 配置g1
(1) 设置USB
协议版本;
echo 0x0200 > bcdUSB
(2) 配置PID
和VID
;
echo 0x1a2c > idVendor
echo 0x4d7e > idProduct
(3) 创建并配置string
字目录:
mkdir strings/0x409
echo "0" > strings/0x409/serialnumber
echo "SEMICO" > strings/0x409/manufacturer
echo "USB Keyboard" > strings/0x409/product
上面的配置信息大部分都是从USB
键盘设备信息中拷贝过来的。
(4) 创建一个USB
配置实例:
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
(5) 定义配置描述符使用的字符串;
echo "mass_storage" > configs/c.1/strings/0x409/configuration
这里的mass_storage
的名字不能随便起,需要根据modprobe
的function
驱动usb_f_mass_storage.ko
来决定,否则会出现错误。
(6) 创建一个接口(一个接口对应一种功能,一般而言一个USB
设备可能存在多个接口),需要注意的是,如果存在多个接口的话,扩展名必须用数字编号:
mkdir functions/mass_storage.0
(7) 配置U
盘参数
先生成一个FAT32
格式的img
,并挂载到
mkdir -p /var/sdcard;
cd /var/sdcard;
mkdir sda;
dd if=/dev/zero of=/var/sdcard/disk.img bs=1M count=20;
mkdosfs -F 32 disk.img
mount -t vfat -o sync /var/sdcard/disk.img /var/sdcard/sda
cd /sys/kernel/config/usb_gadget/g1
接着配置U
盘参数;
echo "/var/sdcard/disk.img" > functions/mass_storage.0/lun.0/file
echo 1 > functions/mass_storage.0/lun.0/removable
echo 0 > functions/mass_storage.0/lun.0/nofua
(8) 绑定接口到配置c.1
ln -s functions/mass_storage.0 configs/c.1
(9) 配置USB3.0 OTG0
的工作模式为Device
(设备):
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
otg
root@rk3399:/lib/modules/6.3.0# echo device > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
device
(10) 查看当前的UDC
,可见开发板上有1个UDC
,fe800000.usb
root@rk3399:/config# ll /sys/class/udc/
lrwxrwxrwx 1 root root 0 Sep 17 23:37 fe800000.usb -> '../../devices/platform/usb@fe800000/fe800000.usb/udc/fe800000.usb'/
配置当前gadget
对应的USB OTG
控制器, 执行如下命令;
echo fe800000.usb > UDC
上述步骤写成脚本,即可加载U
盘驱动。
4.3.5 验证
使用Type-C
连接线,将开发板USB3.0 Type-C
接口与PC
连接起来。
4.3.6 卸载U
盘
当执行如下命令时,相当于模拟U
盘拔掉,PC
磁盘符消失;
echo "" > UDC
4.3.7 总结
这种方式比legacy
方式要先进,USB
设备属性修改(如序列号、PID
/VID
、interface
等)、插拔模拟等等都很方便在用户态修改,你只需要在configfs
文件系统下创建一下文件/文件夹或者使用echo
命令修改文件内容即可。
更重要的是,这种方法,很方便地实现“复合设备”。USB
复合设备是只有一个设备描述符,一个配置描述符,同时有多个接口描述符(代表多种功能),譬如一个键鼠设备,既有键盘又有鼠标。
4. 4 configfs
模拟鼠标键盘
用户可以使用configfs
尝试实现更多的复合设备进行测试,但USB
的端点数量是有限的USB2.0
协议指定只用4bit表示端点号,所以最大端点数是16对IN
/OUT
端点(包含默认端点0)。端点资源有限,所以不可能复合任意多个设备。
4.4.1 hid_keyboard_mouse
脚本
下面我们创建一个复合键鼠设备,然后编写hid_keyboard_mouse.sh
脚本,文件存放在开发板ubuntu
系统/shell/hid
路径下;
#!/bin/bash
gadget=g1
do_start(){
has_mount=$(mount -l | grep /sys/kernel/config)
if [[ -z $has_mount ]];then
mount -t configfs none /sys/kernel/config
fi
cd /sys/kernel/config/usb_gadget
# 当我们创建完这个文件夹之后,系统自动的在这个文件夹中创建usb相关的内容 ,这些内容需要由创建者自己填写
if [[ ! -d ${gadget} ]]; then
mkdir ${gadget}
fi
cd ${gadget}
cd /lib/modules/6.3.0
depmod -a
modprobe libcomposite
modprobe usb_f_hid #需要先将usb_f_hid.ko驱动拷贝过来
cd /sys/kernel/config/usb_gadget/${gadget}
#设置USB协议版本USB2.0
echo 0x0200 > bcdUSB
#定义产品的VendorID和ProductID
echo "0x0525" > idVendor
echo "0xa4ac" > idProduct
#实例化"英语"ID:
mkdir strings/0x409
#将开发商、产品和序列号字符串写入内核
echo "76543210" > strings/0x409/serialnumber
echo "mkelehk" > strings/0x409/manufacturer
echo "keyboard_mouse" > strings/0x409/product
#创建一个USB配置实例
if [[ ! -d configs/c.1 ]]; then
mkdir configs/c.1
fi
#定义配置描述符使用的字符串
if [[ ! -d configs/c.1/strings/0x409 ]]; then
mkdir configs/c.1/strings/0x409
fi
echo "hid" > configs/c.1/strings/0x409/configuration
#创建两个接口
mkdir functions/hid.0 #键盘
mkdir functions/hid.1 #鼠标
#接口0,模拟键盘
echo 1 > functions/hid.0/subclass #启动设备符
echo 1 > functions/hid.0/protocol #键盘协议
echo 8 > functions/hid.0/report_length #标识该hid设备每次发送的报表长度为8字节
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 > functions/hid.0/report_desc #配置hid描述符
#接口1,模拟键盘鼠标
echo 1 > functions/hid.1/subclass #启动设备符
echo 2 > functions/hid.1/protocol #鼠标协议
echo 4 > functions/hid.1/report_length # 相对值是4
echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x05\\x15\\x00\\x25\\x01\\x95\\x05\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x03\\x81\\x01\\x05\\x01\\x09\\x30\\x09\\x31\\x09\\x38\\x15\\x81\\x25\\x7F\\x75\\x08\\x95\\x03\\x81\\x06\\xc0\\xc0 > functions/hid.1/report_desc
#捆绑接口到配置config.1
ln -s functions/hid.0 configs/c.1
ln -s functions/hid.1 configs/c.1
#配置USB3.0 OTG0的工作模式为Device(设备):
echo device > /sys/kernel/debug/usb/fe800000.usb/mode
echo "sleep 3s"
sleep 3s
#将gadget驱动注册到UDC上,插上USB线到电脑上,电脑就会枚举USB设备。
echo fe800000.usb > UDC
}
do_stop() {
cd /sys/kernel/config/usb_gadget/${gadaget}
echo "" > UDC
rmmod usb_f_hid.ko
rmmod libcomposite.ko
}
case $1 in
start)
echo "Start hid gadget "
do_start
;;
stop)
echo "Stop hid gadget"
do_stop
;;
*)
echo "Usage: $0 (stop | start)"
;;
esac
对于鼠标设备,我们配置:
subclass
:接口子类,配置为1,表示启动设备;protocol
:接口协议,配置为2,鼠标协议;report_length
:报告长度配置为4,即表示鼠标发送的数据长度为4个字节,关于每个字节的含义可以参考:linux
驱动移植-USB
鼠标接口驱动;
对于键盘设备,我们配置:
subclass
:接口子类,配置为1,表示启动设备;protocol
:接口协议,配置为1,键盘协议;report_length
:报告长度配置为8,即表示键盘发送的数据长度为8个字节,关于每个字节的含义可以参考:linux
驱动移植-USB
键盘接口驱动 。
(1) 此外,对于鼠标、键盘设备,我们还配置了HID
报告描述符;HID
报告描述符(Report Descriptor
)是HID
设备中的一个描述符,它是比较复杂的一个描述符。
报告描述符,是描述一个报告以及报告里面的数据是用来干什么用的?
- 通过它,
USB HOST
可以分析出报告里面的数据所表示的意思。它通过控制输入端点0
返回,主机使用获取报告描述符命令来获取报告描述符,注意这个请求是发送到接口的,而不是到设备; - 一个报告描述符可以描述多个报告,不同的报告通过报告
ID
来识别,报告ID
在报告最前面,即第一个字节。当报告描述符中没有规定报告ID
时,报告中就没有ID
字段,开始就是数据; - 更详细的说明请参看
USB HID
协议,该协议可从Http://www.usb.org
下载;
关于如何编写HID
报告描述符强烈推荐这篇文章:HID
报告描述符教程 手把手教你编写HID
报告描述符。
(2) 我们如果想要查看一个HID
设备的报告描述,应该怎么做呢?
查看/sys/kernel/debug/hid/
目录下包含046D:C52B
的文件名;
root@rk3399:/shell/hid# ls /sys/kernel/debug/hid/ | grep "046D:C52B"
0003:046D:C52B.0016
0003:046D:C52B.0017
0003:046D:C52B.0018
其中:
0003
描述的是hid
类设备,对于hid
类设备,接口描述符的bInterfaceClass
字段值固定为0x03
;046D
为USB
鼠标的idVendor
;C52B
为USB
鼠标的idProduct
;0016/0017/0018
:具体含义还不是特别清楚;
这里我们选择其中一个查看报告描述符:
root@rk3399:/shell/hid# cat /sys/kernel/debug/hid/0003\:046D\:C52B.0017/rdesc
05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 10 15 00 25 01 95 10 75 01 81 02 05 01 16 01 f8 26 ff 07 75 0c 95 02 09 30 09 31 81 06 15 81 25 7f 75 08 95 01 09 38 81 06 05 0c 0a 38 02 95 01 81 06 c0 c0 05 0c 09 01 a1 01 85 03 75 10 95 02 15 01 26 ff 02 19 01 2a ff 02 81 00 c0 05 01 09 80 a1 01 85 04 75 02 95 01 15 01 25 03 09 82 09 81 09 83 81 60 75 06 81 03 c0 06 bc ff 09 88 a1 01 85 08 19 01 29 ff 15 01 26 ff 00 75 08 95 01 81 00 c0
其中部分数据表示的含义:
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
......
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
我们使用的鼠标的报告描述符还是比较复杂的,这里就不具体解读了。
更多内容可以参考内核:
Documentation/usb/gadget_configfs.rst
;Documentation/usb/gadget_hid.rst
;HID
报告及报告描述简介;
(3) 在开发板ubuntu
系统运行命令模拟鼠标和键盘:
root@rk3399:/shell/hid# bash hid_keyboard_mouse.sh start
Start hid gadget
sleep 3s
此时会在/dev
目录下生成了设备节点/dev/hidg0
、/dev/hidg1
;
root@rk3399:/shell# ll /dev/hidg*
crw------- 1 root root 510, 0 Sep 18 23:03 /dev/hidg0
crw------- 1 root root 510, 1 Sep 18 23:03 /dev/hidg1
如果需卸载鼠标和键盘,执行如下命令:
root@rk3399:/shell/hid# bash hid_keyboard_mouse.sh stop
4.4.2 编写应用程序
然后我们通过设备节点/dev/hidg0
、/dev/hidg1
,就可以模拟鼠标、键盘实现与PC
的通信。
编写测试应用程序hid_gadget_control.c
,文件存放在ubuntu
宿主机/work/sambashare/rk3399/drivers/2.hid
路径下;
/* hid_gadget_test */
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_LEN 512
struct options {
const char *opt;
unsigned char val;
};
// 描述特殊按键,存储在BYTE0字节
static struct options kmod[] = {
{.opt = "--left-ctrl", .val = 0x01},
{.opt = "--right-ctrl", .val = 0x10},
{.opt = "--left-shift", .val = 0x02},
{.opt = "--right-shift", .val = 0x20},
{.opt = "--left-alt", .val = 0x04},
{.opt = "--right-alt", .val = 0x40},
{.opt = "--left-meta", .val = 0x08},
{.opt = "--right-meta", .val = 0x80},
{.opt = NULL}
};
// 描述普通按键,存储在BYTE2~BYTE7字节
static struct options kval[] = {
{.opt = "--return", .val = 0x28},
{.opt = "--esc", .val = 0x29},
{.opt = "--bckspc", .val = 0x2a},
{.opt = "--tab", .val = 0x2b},
{.opt = "--spacebar", .val = 0x2c},
{.opt = "--caps-lock", .val = 0x39},
{.opt = "--f1", .val = 0x3a},
{.opt = "--f2", .val = 0x3b},
{.opt = "--f3", .val = 0x3c},
{.opt = "--f4", .val = 0x3d},
{.opt = "--f5", .val = 0x3e},
{.opt = "--f6", .val = 0x3f},
{.opt = "--f7", .val = 0x40},
{.opt = "--f8", .val = 0x41},
{.opt = "--f9", .val = 0x42},
{.opt = "--f10", .val = 0x43},
{.opt = "--f11", .val = 0x44},
{.opt = "--f12", .val = 0x45},
{.opt = "--insert", .val = 0x49},
{.opt = "--home", .val = 0x4a},
{.opt = "--pageup", .val = 0x4b},
{.opt = "--del", .val = 0x4c},
{.opt = "--end", .val = 0x4d},
{.opt = "--pagedown", .val = 0x4e},
{.opt = "--right", .val = 0x4f},
{.opt = "--left", .val = 0x50},
{.opt = "--down", .val = 0x51},
{.opt = "--kp-enter", .val = 0x58},
{.opt = "--up", .val = 0x52},
{.opt = "--num-lock", .val = 0x53},
{.opt = NULL}
};
int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
{
char *tok = strtok(buf, " ");
int key = 0;
int i = 0;
for (; tok != NULL; tok = strtok(NULL, " ")) {
if (strcmp(tok, "--quit") == 0)
return -1;
if (strcmp(tok, "--hold") == 0) {
*hold = 1;
continue;
}
if (key < 6) {
for (i = 0; kval[i].opt != NULL; i++)
if (strcmp(tok, kval[i].opt) == 0) {
report[2 + key++] = kval[i].val;
break;
}
if (kval[i].opt != NULL)
continue;
}
if (key < 6)
if (islower(tok[0])) {
report[2 + key++] = (tok[0] - ('a' - 0x04));
continue;
}
for (i = 0; kmod[i].opt != NULL; i++)
if (strcmp(tok, kmod[i].opt) == 0) {
report[0] = report[0] | kmod[i].val;
break;
}
if (kmod[i].opt != NULL)
continue;
if (key < 6)
fprintf(stderr, "unknown option: %s\n", tok);
}
return 8;
}
// 描述鼠标按下/松开,存在在BYTE0
static struct options mmod[] = {
{.opt = "--b1", .val = 0x01}, // 左键按下
{.opt = "--b2", .val = 0x02}, // 右键按下
{.opt = "--b3", .val = 0x04}, // 中键按下
{.opt = NULL}
};
int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
{
char *tok = strtok(buf, " ");
int mvt = 0;
int i = 0;
for (; tok != NULL; tok = strtok(NULL, " ")) {
if (strcmp(tok, "--quit") == 0)
return -1;
if (strcmp(tok, "--hold") == 0) {
*hold = 1;
continue;
}
for (i = 0; mmod[i].opt != NULL; i++)
if (strcmp(tok, mmod[i].opt) == 0) {
report[0] = report[0] | mmod[i].val;
break;
}
if (mmod[i].opt != NULL)
continue;
if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
errno = 0;
report[1 + mvt++] = (char)strtol(tok, NULL, 0);
if (errno != 0) {
fprintf(stderr, "Bad value:'%s'\n", tok);
report[1 + mvt--] = 0;
}
continue;
}
fprintf(stderr, "unknown option: %s\n", tok);
}
return 3;
}
static struct options jmod[] = {
{.opt = "--b1", .val = 0x10},
{.opt = "--b2", .val = 0x20},
{.opt = "--b3", .val = 0x40},
{.opt = "--b4", .val = 0x80},
{.opt = "--hat1", .val = 0x00},
{.opt = "--hat2", .val = 0x01},
{.opt = "--hat3", .val = 0x02},
{.opt = "--hat4", .val = 0x03},
{.opt = "--hatneutral", .val = 0x04},
{.opt = NULL}
};
int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
{
char *tok = strtok(buf, " ");
int mvt = 0;
int i = 0;
*hold = 1;
/* set default hat position: neutral */
report[3] = 0x04;
for (; tok != NULL; tok = strtok(NULL, " ")) {
if (strcmp(tok, "--quit") == 0)
return -1;
for (i = 0; jmod[i].opt != NULL; i++)
if (strcmp(tok, jmod[i].opt) == 0) {
report[3] = (report[3] & 0xF0) | jmod[i].val;
break;
}
if (jmod[i].opt != NULL)
continue;
if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
errno = 0;
report[mvt++] = (char)strtol(tok, NULL, 0);
if (errno != 0) {
fprintf(stderr, "Bad value:'%s'\n", tok);
report[mvt--] = 0;
}
continue;
}
fprintf(stderr, "unknown option: %s\n", tok);
}
return 4;
}
void print_options(char c)
{
int i = 0;
if (c == 'k') {
printf(" keyboard options:\n"
" --hold\n");
for (i = 0; kmod[i].opt != NULL; i++)
printf("\t\t%s\n", kmod[i].opt);
printf("\n keyboard values:\n"
" [a-z] or\n");
for (i = 0; kval[i].opt != NULL; i++)
printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
printf("\n");
} else if (c == 'm') {
printf(" mouse options:\n"
" --hold\n");
for (i = 0; mmod[i].opt != NULL; i++)
printf("\t\t%s\n", mmod[i].opt);
printf("\n mouse values:\n"
" Two signed numbers\n"
"--quit to close\n");
} else {
printf(" joystick options:\n");
for (i = 0; jmod[i].opt != NULL; i++)
printf("\t\t%s\n", jmod[i].opt);
printf("\n joystick values:\n"
" three signed numbers\n"
"--quit to close\n");
}
}
int main(int argc, const char *argv[])
{
const char *filename = NULL;
int fd = 0;
char buf[BUF_LEN];
int cmd_len;
char report[8];
int to_send = 8;
int hold = 0;
fd_set rfds;
int retval, i;
if (argc < 3) {
fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
argv[0]);
return 1;
}
if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
return 2;
filename = argv[1];
if ((fd = open(filename, O_RDWR, 0666)) == -1) {
perror(filename);
return 3;
}
print_options(argv[2][0]);
while (42) {
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
FD_SET(fd, &rfds);
retval = select(fd + 1, &rfds, NULL, NULL, NULL);
if (retval == -1 && errno == EINTR)
continue;
if (retval < 0) {
perror("select()");
return 4;
}
if (FD_ISSET(fd, &rfds)) {
cmd_len = read(fd, buf, BUF_LEN - 1);
printf("recv report:");
for (i = 0; i < cmd_len; i++)
printf(" %02x", buf[i]);
printf("\n");
}
if (FD_ISSET(STDIN_FILENO, &rfds)) {
memset(report, 0x0, sizeof(report));
cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
if (cmd_len == 0)
break;
buf[cmd_len - 1] = '\0';
hold = 0;
memset(report, 0x0, sizeof(report));
if (argv[2][0] == 'k')
to_send = keyboard_fill_report(report, buf, &hold);
else if (argv[2][0] == 'm')
to_send = mouse_fill_report(report, buf, &hold);
else
to_send = joystick_fill_report(report, buf, &hold);
if (to_send == -1)
break;
if (write(fd, report, to_send) != to_send) {
perror(filename);
return 5;
}
if (!hold) {
memset(report, 0x0, sizeof(report));
if (write(fd, report, to_send) != to_send) {
perror(filename);
return 6;
}
}
}
}
close(fd);
return 0;
}
编写Makefile
文件:
all:
arm-linux-gcc -march=armv8-a -o hid_gadget_control hid_gadget_control.c
clean:
rm -rf *.o hid_gadget_control
在ubuntu
宿主机下编译:
root@zhengyang:/work/sambashare/rk3399/drivers/2.hid# make
arm-linux-gcc -march=armv8-a -o hid_gadget_control hid_gadget_control.c
root@zhengyang:/work/sambashare/rk3399/drivers/2.hid# ll
-rwxr-xr-x 1 root root 79000 Sep 18 22:39 hid_gadget_control*
-rwxrw-rw- 1 root root 10526 Sep 18 22:37 hid_gadget_control.c*
-rwxrw-rw- 1 root root 3286 Sep 18 22:34 hid_keyboard_mouse.sh*
-rwxrw-rw- 1 root root 118 Sep 18 22:39 Makefile*
将编译后的hid_gadget_control
拷贝到开发板ubuntu
系统/shell/hid
路径;
root@rk3399:/shell/hid# scp root@192.168.0.200:/work/sambashare/rk3399/drivers/2.hid/hid_gadget_control ./
使用hid_gadget_control
程序时,需要指定一个hidgX
设备,并设置设备类型(键盘/鼠标/游戏手柄)。
4.4.3 测试键盘
(1) 使用Type-C
连接线,将开发板USB3.0 Type-C
接口与PC
连接起来。
在开发板ubuntu
桌面环境打开一个终端输入如下命令(开发板需要先连接好键盘):
root@rk3399:/shell/hid# ./hid_gadget_control /dev/hidg0 keyboard
./hid_gadget_control: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./hid_gadget_control)
检查版本:
root@rk3399:/shell/hid# strings /lib/aarch64-linux-gnu/libc.so.6 | grep GLIBC_
GLIBC_2.17
GLIBC_2.18
GLIBC_2.22
GLIBC_2.23
GLIBC_2.24
GLIBC_2.25
GLIBC_2.26
GLIBC_2.27
GLIBC_2.28
GLIBC_2.29
GLIBC_2.30
GLIBC_PRIVATE
最高版本只到2.30,由于使用的系统为ubuntu20.04
,已经升级到了系统版本的最高版本了。
解决方案:添加一个高级版本系统的源,直接升级libc6
。编辑源:
root@rk3399:/shell/hid# vi /etc/apt/sources.list
添加高版本的源:
deb https://mirrors.ustc.edu.cn/ubuntu-ports/ jammy main restricted universe mulltiverse
deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ jammy main main restricted universe multiverse
运行升级(可能时间比较长稍等一会):
root@rk3399:/shell/hid#sudo apt update
root@rk3399:/shell/hid#sudo apt install libc6
root@rk3399:/shell/hid# strings /lib/aarch64-linux-gnu/libc.so.6 | grep GLIBC_2.34
GLIBC_2.34
(2) 在开发板ubuntu
桌面环境打开一个终端输入如下命令(开发板需要先连接好键盘):
进入hid_gadget_control
的提示符后,可以输入任意组合的选项和值。可用的选项和值在程序启动时列出。
在键盘模式下,可以发送最多六个值。例如,通过开发板连接的键盘键入以下内容:g i s t r --left-shift
,然后按回车键;
对应的报告将由HID gadget
发送,此时在PC
端window
系统聚焦的输入框可以得到键盘输入的内容:
另一个有趣的示例是大写锁定键测试。键入 --caps-lock
并按回车键。然后,设备将发送一个报告,你应该会收到主机的响应,对应于大写锁定键的LED
状态:
--caps-lock
recv report: 03
4.4.4 测试鼠标
(1) 这里我们做个好玩的实验,使用Type-C
连接线将开发板USB3.0 Type-C
接口与开发板上的USB2.0 Host Type-A
接口(对应开发板上的USBH3
)连接起来;内核日志信息如下:
[ 4162.448207] usb 2-1: new high-speed USB device number 2 using ehci-platform
[ 4162.607147] usb 2-1: New USB device found, idVendor=0525, idProduct=a4ac, bcdDevice= 6.03
[ 4162.607187] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 4162.607204] usb 2-1: Product: keyboard_mouse
[ 4162.607218] usb 2-1: Manufacturer: mkelehk
[ 4162.607231] usb 2-1: SerialNumber: 76543210
[ 4162.613199] input: mkelehk keyboard_mouse as /devices/platform/fe3c0000.usb/usb2/2-1/2-1:1.0/0003:0525:A4AC.000A/input/input15
[ 4162.673625] hid-generic 0003:0525:A4AC.000A: input: USB HID v1.01 Keyboard [mkelehk keyboard_mouse] on usb-fe3c0000.usb-1/input0
[ 4162.676744] input: mkelehk keyboard_mouse as /devices/platform/fe3c0000.usb/usb2/2-1/2-1:1.1/0003:0525:A4AC.000B/input/input16
[ 4162.677172] hid-generic 0003:0525:A4AC.000B: input: USB HID v1.01 Mouse [mkelehk keyboard_mouse] on usb-fe3c0000.usb-1/input1
USB
鼠标工作在高速模式下,eHCI
控制器,USB2.0
通信协议,使用的USB
总线编号为2,设备编号为2。
其中Product
=keyboard_mouse
,Manufacturer=mkelehk
,SerialNumber=76543210
、idVendor=0525
、idProduct=a4ac
,这个就是我们在hid_keyboard_mouse.sh
脚本下配置的。
在连接Type-C
连接线之后,/dev/event
下多了两个设备节点文件event9
、event10
。
(2) 将鼠标移动到开发板ubuntu
桌面系统的正中间,并打开一个开发板终端(非桌面终端)输入如下命令:
root@rk3399:/shell/hid# ./hid_gadget_control /dev/hidg1 mouse
mouse options:
--hold
--b1
--b2
--b3
mouse values:
Two signed numbers
--quit to close
200 210 # 鼠标向左上移动
-200 210 # 鼠标向右上移动
200 -210 # 鼠标向左下移动
-200 -210 # 鼠标向右下移动
0 0 --b1 # 鼠标左键点击
0 0 --b2 # 鼠标右键点击
0 0 --b3 # 鼠标中键点击
进入hid_gadget_control
的提示符后,可以输入任意组合的选项和值。可用的选项和值在程序启动时列出。
此时效果就是开发板ubuntu
桌面的鼠标会移动,并触发点击事件。
需要注意的是:这里我也尝试了使用Type-C
连接线将开发板USB3.0 Type-C
接口与PC
连接起来,但是并没有上面所说的效果。
4.5 configs
模拟触摸屏
这一节我们尝试使用configfs
模拟触摸屏。
4.5.1 hid_touch
脚本
下面我们创建一个触摸屏设备,然后编写hid_touch.sh
脚本,文件存放在开发板ubuntu
系统/shell/hid
路径下;
#!/bin/bash
gadget=g2
do_start(){
has_mount=$(mount -l | grep /sys/kernel/config)
if [[ -z $has_mount ]];then
mount -t configfs none /sys/kernel/config
fi
cd /sys/kernel/config/usb_gadget
# 当我们创建完这个文件夹之后,系统自动的在这个文件夹中创建usb相关的内容 ,这些内容需要由创建者自己填写
if [[ ! -d ${gadget} ]]; then
mkdir ${gadget}
fi
cd ${gadget}
cd /lib/modules/6.3.0
depmod -a
modprobe libcomposite
modprobe usb_f_hid
cd /sys/kernel/config/usb_gadget/${gadget}
#设置USB协议版本USB2.0
echo 0x0200 > bcdUSB
#定义产品的VendorID和ProductID
echo "0x0525" > idVendor
echo "0xa4ac" > idProduct
#实例化"英语"ID:
mkdir strings/0x409
#将开发商、产品和序列号字符串写入内核
echo "76543210" > strings/0x409/serialnumber
echo "mkelehk" > strings/0x409/manufacturer
echo "touch_screen" > strings/0x409/product
#创建一个USB配置实例
if [[ ! -d configs/c.1 ]]; then
mkdir configs/c.1
fi
#定义配置描述符使用的字符串
if [[ ! -d configs/c.1/strings/0x409 ]]; then
mkdir configs/c.1/strings/0x409
fi
echo "hid" > configs/c.1/strings/0x409/configuration
#创建接口
mkdir functions/hid.0
#触摸屏接口 配置hid描述符
echo 0 > functions/hid.0/subclass
echo 0 > functions/hid.0/protocol
echo 5 > functions/hid.0/report_length #标识该hid设备每次发送的报表长度为5字节
echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x05\\x15\\x00\\x25\\x01\\x95\\x05\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x03\\x81\\x01\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x00\\x26\\xff\\x7f\\x35\\x00\\x46\\xff\\x7f\\x75\\x10\\x95\\x02\\x81\\x02\\xc0\\xc0 > functions/hid.0/report_desc
#捆绑接口到配置config.1
ln -s functions/hid.0 configs/c.1
#配置USB3.0 OTG0的工作模式为Device(设备):
echo device > /sys/kernel/debug/usb/fe800000.usb/mode
echo "sleep 3s"
sleep 3s
#将gadget驱动注册到UDC上,插上USB线到电脑上,电脑就会枚举USB设备。
echo fe800000.usb > UDC
}
do_stop() {
cd /sys/kernel/config/usb_gadget/${gadaget}
echo "" > UDC
rmmod usb_f_hid.ko
rmmod libcomposite.ko
}
case $1 in
start)
echo "Start hid gadget "
do_start
;;
stop)
echo "Stop hid gadget"
do_stop
;;
*)
echo "Usage: $0 (stop | start)"
;;
esac
对于触摸屏设备,我们配置:
subclass
:接口子类,配置为0,表示No Subclass
;protocol
:接口协议,配置为0;report_length
:报告长度配置为5,触摸屏与鼠标的不同点是鼠标的上报值是相对坐标,触摸屏是绝对坐标,鼠标xy轴分别需要一个字节,而触摸屏一般为16bit即两个字节;
HID
设备支持多种协议。接口描述符的bInterfaceProtocol
成员(接口协议)只有在bInterfaceSubClass
(接口子类)支持启动接口时才有意义,否则为0。
在开发板ubuntu
系统运行命令模拟触摸屏:
root@rk3399:/shell/hid# bash hid_touch.sh start
Start hid gadget
sleep 3s
此时会在/dev
目录下生成了设备节点/dev/hidg0
(这里实验时我重启了开发板,所以编号是0);
root@rk3399:/shell/hid# ll /dev/hidg*
crw------- 1 root root 510, 0 Sep 19 23:41 /dev/hidg0
如果需卸载触摸屏,执行如下命令:
root@rk3399:/shell/hid# bash hid_touch.sh stop
4.5.2 编写应用程序
编写测试应用程序hid_touch_control.c
,文件存放在ubuntu
宿主机/work/sambashare/rk3399/drivers/2.hid
路径下;
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
/**
* 触摸屏每次发送5字节报告
* report[0]的D0就是左键,D1就是右键,D2就是中键
* report[1]为X轴低字节
* report[2]为X轴高字节
* report[3]为Y轴低字节
* report[4]为Y轴高字节,
*/
/**
* @brief 将焦点移动到指定位置
*
* @param fd 文件描述符
* @param x x轴坐标
* @param y y轴坐标
*/
void move_To(int fd ,int x, int y)
{
char report[5]={0,0,0,0,0};
report[0] = 0x00;
report[1] = x & 0xFF;
report[2] = (x >> 8) & 0xFF;
report[3] = y & 0xFF;
report[4] = (y >> 8) & 0xFF;
// 写入失败
if (write(fd, report, 5) != 5) {
perror("move_To error");
return;
}
usleep(50000);
}
/**
* @brief 函数功能:画线段的函数。
*
*@param fd 文件描述符
* @param x x轴坐标
* @param y y轴坐标
*/
void line_to(int fd, int x, int y)
{
char report[5]={0,0,0,0,0};
report[0] = 0x01; //左键按下
report[1] = x & 0xFF;
report[2] = (x >> 8) & 0xFF;
report[3] = y & 0xFF;
report[4] = (y >> 8) & 0xFF;
if (write(fd, report, 5) != 5) {
perror("line_to error");
return;
}
usleep(50000);
}
int main(int argc, char const *argv[])
{
const char *filename = NULL;
int fd = 0;
if (argc != 3)
{
fprintf(stderr, "Usage: %s devname a/l\n",
argv[0]);
return 1;
}
filename = argv[1];
if ((fd = open(filename, O_RDWR, 0666)) == -1) {
perror(filename);
return 1;
}
if(argv[2][0] == 'a')
{
printf("Draw Tri-angle begin\n");
move_To(fd, 8888, 8888); //移动到(8888,8888)
line_to(fd, 8888, 8888); //开始画线
line_to(fd, 12000, 12000); //画线到(12000,12000)
move_To(fd, 12000, 12000); //松开鼠标左键
move_To(fd, 12000, 12000); //移动到(12000,12000)
line_to(fd, 12000, 12000); //开始画线
line_to(fd ,8888, 12000); //画线到(8888,12000)
move_To(fd, 8888, 12000); //松开鼠标左键
move_To(fd, 8888, 12000); //移动到(8888,12000)
line_to(fd, 8888, 12000); //开始画线
line_to(fd ,8888, 8888); //画线到(8888,8888)
move_To(fd, 8888, 8888); //松开鼠标左键
printf("Draw Tri-angle end\n");
}
if(argv[2][0] == 'l'){
printf("Draw line begin\n");
move_To(fd, 10000, 10000); // 移动到(10000,10000)
line_to(fd, 10000, 10000); // 开始画线
line_to(fd, 20000, 10000); // 画线到(20000,10000)
move_To(fd, 20000, 10000); // 松开鼠标左键
printf("Draw line end\n");
}
close(fd);
return 0;
}
在ubuntu
宿主机下编译:
root@zhengyang:/work/sambashare/rk3399/drivers/2.hid# arm-linux-gcc -march=armv8-a -o hid_touch_control hid_touch_control.c
将编后的hid_touch_control
拷贝到开发板ubuntu
系统/shell/hid
路径;
root@rk3399:/shell/hid# scp root@192.168.0.200:/work/sambashare/rk3399/drivers/2.hid/hid_touch_control ./
使用hid_touch_control
程序时,需要指定触摸屏设备节点/devhidgX
,并设置操作类型(a
/l
)。
4.5.3 测试触摸屏
(1) 这里我们和鼠标测试一样,使用Type-C
连接线将开发板USB3.0 Type-C
接口与开发板上的USB2.0 Host Type-A
接口(对应开发板上的USBH3
)连接起来;内核日志信息如下:
[ 212.726544] usb 2-1: new high-speed USB device number 3 using ehci-platform
[ 212.885619] usb 2-1: New USB device found, idVendor=0525, idProduct=a4ac, bcdDevice= 6.03
[ 212.885658] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 212.885675] usb 2-1: Product: touch_screen
[ 212.885696] usb 2-1: Manufacturer: mkelehk
[ 212.885709] usb 2-1: SerialNumber: 76543210
[ 212.890175] input: mkelehk touch_screen as /devices/platform/fe3c0000.usb/usb2/2-1/2-1:1.0/0003:0525:A4AC.0009/input/input16
[ 212.890947] hid-generic 0003:0525:A4AC.0009: input: USB HID v1.01 Mouse [mkelehk touch_screen] on usb-fe3c0000.usb-1/input0
USB
触摸屏工作在高速模式下,eHCI
控制器,USB2.0
通信协议,使用的USB
总线编号为2,设备编号为3。
其中Product
=touch_screen
,Manufacturer=mkelehk
,SerialNumber=76543210
、idVendor=0525
、idProduct=a4ac
,这个就是我们在hid_touch.sh
脚本下配置的。
(2) 在开发板ubuntu
桌面安装画图软件,并运行程序;
root@rk3399:/shell/hid# sudo apt install -y kolourpaint
root@rk3399:/shell/hid# kolourpaint
我们将画布调到最大,并且选择左侧的Line
;
(3) 打开一个开发板终端(非桌面终端)输入如下命令:
root@rk3399:/shell/hid# ./hid_touch_control /dev/hidg0 a
Draw Tri-angle begin
Draw Tri-angle end
root@rk3399:/shell/hid# ./hid_touch_control /dev/hidg0 l
Draw line begin
Draw line end
最终得到如下图:
五、调试接口
5.1 sysfs
5.1.1 USB
设备
所有USB
设备可以在/sys/bus/usb/devices
下找到;
root@rk3399:/# ll /sys/bus/usb/devices
total 0
drwxr-xr-x 2 root root 0 Mar 15 2023 ./
drwxr-xr-x 4 root root 0 Mar 15 2023 ../
lrwxrwxrwx 1 root root 0 Mar 15 2023 1-0:1.0 -> ../../../devices/platform/fe3a0000.usb/usb1/1-0:1.0/
lrwxrwxrwx 1 root root 0 Sep 16 21:50 1-1 -> ../../../devices/platform/fe3a0000.usb/usb1/1-1/
lrwxrwxrwx 1 root root 0 Sep 16 21:50 1-1:1.0 -> ../../../devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.0/
lrwxrwxrwx 1 root root 0 Sep 16 21:50 1-1:1.1 -> ../../../devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.1/
lrwxrwxrwx 1 root root 0 Mar 15 2023 2-0:1.0 -> ../../../devices/platform/fe3c0000.usb/usb2/2-0:1.0/
lrwxrwxrwx 1 root root 0 Mar 15 2023 3-0:1.0 -> ../../../devices/platform/fe3e0000.usb/usb3/3-0:1.0/
lrwxrwxrwx 1 root root 0 Sep 16 21:31 3-1 -> ../../../devices/platform/fe3e0000.usb/usb3/3-1/
lrwxrwxrwx 1 root root 0 Sep 16 21:31 3-1:1.0 -> ../../../devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.0/
lrwxrwxrwx 1 root root 0 Sep 16 21:31 3-1:1.1 -> ../../../devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.1/
lrwxrwxrwx 1 root root 0 Sep 16 21:31 3-1:1.2 -> ../../../devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.2/
lrwxrwxrwx 1 root root 0 Mar 15 2023 4-0:1.0 -> '../../../devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb4/4-0:1.0'/
lrwxrwxrwx 1 root root 0 Mar 15 2023 5-0:1.0 -> ../../../devices/platform/fe380000.usb/usb5/5-0:1.0/
lrwxrwxrwx 1 root root 0 Mar 15 2023 6-0:1.0 -> '../../../devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb6/6-0:1.0'/
lrwxrwxrwx 1 root root 0 Mar 15 2023 7-0:1.0 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-0:1.0'/
lrwxrwxrwx 1 root root 0 Mar 15 2023 8-0:1.0 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb8/8-0:1.0'/
lrwxrwxrwx 1 root root 0 Sep 16 22:03 8-1 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb8/8-1'/
lrwxrwxrwx 1 root root 0 Sep 16 22:03 8-1:1.0 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb8/8-1/8-1:1.0'/
lrwxrwxrwx 1 root root 0 Mar 15 2023 usb1 -> ../../../devices/platform/fe3a0000.usb/usb1/
lrwxrwxrwx 1 root root 0 Mar 15 2023 usb2 -> ../../../devices/platform/fe3c0000.usb/usb2/
lrwxrwxrwx 1 root root 0 Mar 15 2023 usb3 -> ../../../devices/platform/fe3e0000.usb/usb3/
lrwxrwxrwx 1 root root 0 Mar 15 2023 usb4 -> '../../../devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb4'/
lrwxrwxrwx 1 root root 0 Mar 15 2023 usb5 -> ../../../devices/platform/fe380000.usb/usb5/
lrwxrwxrwx 1 root root 0 Mar 15 2023 usb6 -> '../../../devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb6'/
lrwxrwxrwx 1 root root 0 Mar 15 2023 usb7 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7'/
lrwxrwxrwx 1 root root 0 Mar 15 2023 usb8 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb8'/
如上图所示,可以看到大量的USB
设备。取名规则如下:
bus-port[.port]:configuration.interface
其中:
bus
:表示USB
控制器所连接的总线编号;从1开始编号;port
:表示总线上的硬件端口号;从0开始编号;比如1-0
是根hub
自身信息,当hub
上有插入设备时,就会出现1-1
了。port
:如果总线上的硬件端口连接的设备是一个HUB
,那么该port
表示连接在hub
上的硬件端口号;从1开始编号;configuration
:表示设备的配置值;从1开始编号;interface
:表示设备的接口号;从0开始编号;
比如1-1:1.1
具有以下含义:
1-1
:表示连接到第一个USB
控制器的编号为1的硬件端口;1.1
:表示设备的第一个配置(configuration
)编号为1接口(interface
)。
7-1.2:1.0
具有以下含义:
7-1.2
:表示连接到第7个USB
控制器的编号为1的硬件端口连接了一个hub
,hub
编号为2的硬件端口上连接了一个设备;1.0
:表示设备的第一个配置(configuration
)编号为0接口(interface
)。
5.1.2 USB
设备信息
我们可以查看USB
设备PID
和VID
:
root@rk3399:/sys/bus/usb/devices# ls
1-0:1.0 1-1:1.0 2-0:1.0 3-1 3-1:1.1 4-0:1.0 6-0:1.0 8-0:1.0 8-1:1.0 usb2 usb4 usb6 usb8
1-1 1-1:1.1 3-0:1.0 3-1:1.0 3-1:1.2 5-0:1.0 7-0:1.0 8-1 usb1 usb3 usb5 usb7
root@rk3399:/sys/bus/usb/devices# ls 8-1/id*
8-1/idProduct 8-1/idVendor
root@rk3399:/sys/bus/usb/devices# cat 8-1/idVendor
0480
root@rk3399:/sys/bus/usb/devices# cat 8-1/idProduct
b200
root@rk3399:/sys/bus/usb/devices# cat 8-1/manufacturer
TOSHIBA
root@rk3399:/sys/bus/usb/devices# cat 8-1/product
External USB 3.0
root@rk3399:/sys/bus/usb/devices# cat 8-1/version
3.00
VID=0480
、PID=b200
对应的使我们移动硬盘。
1个USB
设备可能会有多个接口,比如:
root@rk3399:/sys/bus/usb/devices# ls 1-1/1-1\:1.
1-1:1.0/ 1-1:1.1/
目录1-1
存放的是USB
设备信息,1-1:1.0
、1-1:1.1
目录下存放的相应接口的信息。
5. 2 debugfs
USB
调试信息位于/sys/kernel/debug/usb
;
root@rk3399:~# ll /sys/kernel/debug/usb
-r--r--r-- 1 root root 0 Jan 1 1970 devices
drwxr-xr-x 4 root root 0 Jan 1 1970 ehci/
drwxr-xr-x 2 root root 0 Jan 1 1970 fe800000.usb/
drwxr-xr-x 2 root root 0 Jan 1 1970 fe900000.usb/
drwxr-xr-x 2 root root 0 Jan 1 1970 fusb302-4-0022/
drwxr-xr-x 4 root root 0 Jan 1 1970 ohci/
drwxr-xr-x 2 root root 0 Jan 1 1970 tcpm-4-0022/
drwxr-xr-x 2 root root 0 Jan 1 1970 uvcvideo/
drwxr-xr-x 4 root root 0 Jan 1 1970 xhci/
其中:
devices
:该文件列出了当前系统中已连接的USB设备的详细信息;ehci
:该目录包含EHCI
主机控制器接口的调试信息;fe800000.usb
:该目录包含与fe800000.usb
控制器相关的调试信息;fe900000.usb
:该目录包含与fe900000.usb
控制器相关的调试信息。fusb302-4-0022
:该目录包含与fusb302-4-0022
设备相关的调试信息,4为I2C
总线编号,0022为I2C
设备地址;ohci
:该目录包含OHCI
主机控制器接口的调试信息;tcpm-4-0022
:该目录包含与tcpm-4-0022
设备相关的调试信息,4为I2C
总线编号,0022为I2C
设备地址;uvcvideo
:该目录包含与uvcvideo
(USB Video Class
,USB
视频类)驱动程序相关的调试信息;xhci
:该目录包含XHCI
主机控制器的调试信息;
5.2.1 查看工作模式
以USB3.0 OTG0(DWC3/xHCI)
控制器为例,对应设备节点usbdrd3_0: usb@fe800000
:
root@rk3399:~# ll /sys/kernel/debug/usb/fe800000.usb/
-rw-r--r-- 1 root root 0 Jan 1 1970 link_state
-rw-r--r-- 1 root root 0 Jan 1 1970 lsp_dump
-rw-r--r-- 1 root root 0 Jan 1 1970 mode
-r--r--r-- 1 root root 0 Jan 1 1970 regdump
-rw-r--r-- 1 root root 0 Jan 1 1970 testmode
其中:
link_state
:打印DWC3
的链路状态;regdump
:打印DWC3
控制器的寄存器状态信息;mode
:打印DWC3
的工作模式;testmode
:设置DWC3
进HighSpeed
的测试模式,用于眼图测试;
我们可以查看USB3.0 OTG0
、USB3.0 OTG1
控制器的工作模式:
root@rk3399:~# cat /sys/kernel/debug/usb/fe800000.usb/mode # OTG0 对应开发板Type-C/DP接口
otg
root@rk3399:~# cat /sys/kernel/debug/usb/fe900000.usb/mode # OTG1 对应开发板CON5接口
host
5.2.2 查看xhci
root@rk3399:/# ll /sys/kernel/debug/usb/xhci/
drwxr-xr-x 6 root root 0 Jan 1 1970 xhci-hcd.0.auto/
drwxr-xr-x 6 root root 0 Jan 1 1970 xhci-hcd.1.auto/
root@rk3399:/# ll /sys/kernel/debug/usb/xhci/xhci-hcd.0.auto/
drwxr-xr-x 2 root root 0 Jan 1 1970 command-ring/
drwxr-xr-x 2 root root 0 Jan 1 1970 devices/
drwxr-xr-x 2 root root 0 Jan 1 1970 event-ring/
drwxr-xr-x 4 root root 0 Jan 1 1970 ports/
-r--r--r-- 1 root root 0 Jan 1 1970 reg-cap
-r--r--r-- 1 root root 0 Jan 1 1970 reg-ext-dbc:00
-r--r--r-- 1 root root 0 Jan 1 1970 reg-ext-legsup:00
-r--r--r-- 1 root root 0 Jan 1 1970 reg-ext-protocol:00
-r--r--r-- 1 root root 0 Jan 1 1970 reg-ext-protocol:01
-r--r--r-- 1 root root 0 Jan 1 1970 reg-op
-r--r--r-- 1 root root 0 Jan 1 1970 reg-runtime
5.2.3 查看ehci
root@rk3399:/# ll /sys/kernel/debug/usb/ehci/
drwxr-xr-x 2 root root 0 Jan 1 1970 fe380000.usb/
drwxr-xr-x 2 root root 0 Jan 1 1970 fe3c0000.usb/
root@rk3399:/# ll /sys/kernel/debug/usb/ehci/fe380000.usb/
-r--r--r-- 1 root root 0 Jan 1 1970 async
-r--r--r-- 1 root root 0 Jan 1 1970 bandwidth
-r--r--r-- 1 root root 0 Jan 1 1970 periodic
-r--r--r-- 1 root root 0 Jan 1 1970 registers
5.2.4 查看fusb302-4-0022
root@rk3399:/# ll /sys/kernel/debug/usb/fusb302-4-0022/
-r--r--r-- 1 root root 0 Jan 1 1970 log
root@rk3399:/# cat /sys/kernel/debug/usb/fusb302-4-0022/log
[ 3.588457] sw reset
[ 3.589715] fusb302 device ID: 0x81
[ 3.591218] pd := off
[ 3.591222] vbus is already Off
[ 3.591225] charge is already Off
[ 3.591228] vconn is already Off
[ 3.591588] pd header := Sink, Device
[ 3.591658] cc1=Open, cc2=Open
[ 3.593266] pd := off
[ 3.593278] vbus is already Off
[ 3.593283] charge is already Off
[ 3.593288] vconn is already Off
[ 3.593623] pd header := Sink, Device
[ 3.593646] cc := Open
[ 3.696903] start drp toggling
[ 3.697640] IRQ: 0x80, a: 0x00, b: 0x00, status0: 0x83
[ 3.697650] IRQ: VBUS_OK, vbus=On
[ 3.698289] IRQ: 0x80, a: 0x00, b: 0x00, status0: 0x83
[ 3.698298] IRQ: VBUS_OK, vbus=On
5.2.5 查看tcpm-4-0022
root@rk3399:/# ll /sys/kernel/debug/usb/tcpm-4-0022/
-r--r--r-- 1 root root 0 Jan 1 1970 log
root@rk3399:/# cat /sys/kernel/debug/usb/tcpm-4-0022/log
[ 3.589722] Setting usb_comm capable false
[ 3.591231] Setting voltage/current limit 0 mV 0 mA
[ 3.591241] polarity 0
[ 3.591297] Requesting mux state 0, usb-role 0, orientation 0
[ 3.591601] state change INVALID_STATE -> SNK_UNATTACHED [rev1 NONE_AMS]
[ 3.591661] CC1: 0 -> 0, CC2: 0 -> 0 [state SNK_UNATTACHED, polarity 0, disconnected]
[ 3.591669] 4-0022: registered
[ 3.591681] Setting usb_comm capable false
[ 3.593293] Setting voltage/current limit 0 mV 0 mA
[ 3.593312] polarity 0
[ 3.593318] Requesting mux state 0, usb-role 0, orientation 0
[ 3.593641] cc:=0
[ 3.595138] pending state change PORT_RESET -> PORT_RESET_WAIT_OFF @ 100 ms [rev1 NONE_AMS]
[ 3.695257] state change PORT_RESET -> PORT_RESET_WAIT_OFF [delayed 100 ms]
[ 3.695272] state change PORT_RESET_WAIT_OFF -> SNK_UNATTACHED [rev1 NONE_AMS]
[ 3.695282] Start toggling
[ 3.697687] VBUS
5.3 更改USB3.0 OTG
工作模式
我们使用的开发板USB3.0 Type-C PHY1
、USB2.0 OTG PHY1
物理接口被设计为USB3.0 Host Type-A
,即VBUS
被配置为了常供电,所以只能作为主设备为从设备供电,usbdrd_dwc3_1
的dr_mode
属性只能配置为host
。
如果你的开发板USB3.0 Type-C PHY1
、USB2.0 OTG PHY1
物理接口被设计为USB3.0 OTG Type-A
的话,就可以尝试将USB3.0 OTG1
控制器工作模式也设置为otg
(同时支持主机/设备)。
不过Rockchip
官方手册介绍中描述到:USB Gadget driver
内核架构(可能只针对低版本内核比如4.19
)只支持一个USB
控制器配置为otg
,所以如果你有兴趣的话,可以测试一下看看能不能同时将USB3.0 OTG0
、USB3.0 OTG1
控制器都配置为otg
模式,具体流程参考下面。
5.3.1 修改usbdrd_dwc3_1
设备节点
修改arch/arm64/boot/dts/rockchip/rk3399-evb.dts
设备节点usbdrd_dwc3_1
设备节点:
&usbdrd_dwc3_1 {
/* 配置dr_mode为otg */
dr_mode = "otg";
status = "okay";
};
如果VBUS
为常供电(也即系统开机后,VBUS
一直为高),则不需要配置vbus-supply
属性,但需要增加如下的属性,否则,会出现 USB
无法正常连接的情况。这里应修改对应的u2phy1_otg
节点:
&u2phy1_otg {
rockchip,vbus-always-on;
/* phy-supply = <&vcc5v2_host>; */
status = "okay";
};
5.3.2 测试
重新编译内核并烧录,查看USB3.0 OTG0
、USB3.0 OTG1
控制器的工作模式;
root@rk3399:~# cat /sys/kernel/debug/usb/fe800000.usb/mode # OTG0 对应开发板Type-C/DP接口
otg
root@rk3399:~# cat /sys/kernel/debug/usb/fe900000.usb/mode # OTG1 对应开发板CON5接口
otg
更改工作模式为Host
(主机),这种做法只会临时有效:
root@rk3399:/lib/modules/6.3.0# echo host > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# echo host > /sys/kernel/debug/usb/fe900000.usb/mode
然后将开发板CON5
、Type-C/DP
这两个接口接上USB
设备测试。
参考文章
[2] RK3399 Android7.1 USB
模块中的控制器和PHY
[3] RK3399ANDROID7.1 USB TYPE-A
的配置
[4] USB gadget configfs
的原理及单片机实现
[5] Rockchip_Developer_Guide_USB_CN.pdf
[6] Rockchip_RK3399_Developer_Guide_USB_DTS_CN.pdf
[7] RK
平台如何配置USB
功能
[11] linux usb gadget hid
模拟鼠标键盘configfs
[13] usb hid gadget
驱动
[14 ] RK3399
驱动开发 | 18 - 使用usb3.0
作为device
模拟u
盘
[15] linux driver probe deferral
机制
[17] 6.61、USB
如何模拟HID
设备
[18] USB
总线-Linux
内核USB3.0
设备控制器之dwc3 gadget
驱动初始化过程分析(五)
[19] 基于rk3308
实现 linux usb slave hid
设备模拟键盘,鼠标等
[20] zynq
下usb gadget
模拟网口、U
盘、串口(转)
[21] RK3399
模拟成鼠标触摸屏
[22] raw-gadget-USB Raw Gadget-Linux USB Gadget
子系统的底层接口
[23] xairy/raw-gadge
[24] USB Support