草庐IT

Linux USB 开发指南

韦东山 2023-04-10 原文

文章目录

Linux USB 开发指南

1 前言

1.1 文档简介

介绍 USB 模块配置和调试方法。

1.2 目标读者

USB 模块开发、维护人员。

1.3 适用范围

​ 表 1-1: 适用产品列表

内核版本驱动文件
Linux-4.9drivers/usb/*
Linux-5.4drivers/usb/*

2 模块介绍

2.1 模块功能介绍

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

2.2 相关术语介绍

​ 表 2-1: 术语介绍

术语说明
USBUniversal Serial Bus, 通用串行总线
OTGOn-The-Go
ADBAndroid Debug Bridge,Android 调试桥
Gadget小配件
HCDHost Controller Driver,主机控制器驱动
UDCUSB Device Controller, USB 设备控制器
HCIHost Controller Interface,主机控制器接口
EHCIEnhanced Host Controller Interface,增强型主机控制器接口
OHCIOpen Host Controller Interface,开放式主机控制器接口

2.3 模块配置介绍

2.3.1 Device Tree 配置说明

设备树中存在的是该类芯片所有平台的模块配置,设备树文件的路径为:kernel/linux-4.9/arch/arm64(32 位平台为 arm)/boot/dts/sunxi/xxx.dtsi(xxx 为具体芯片型号,如 sun50iw10p1 等), 设备树配置如下所示:

USB0 配置

usbc0:usbc0@0 {
    device_type = "usbc0";
    compatible = "allwinner,sunxi-otg-manager";
    usb_port_type = <2>;
    usb_detect_type = <1>;
    usb_id_gpio;
    usb_det_vbus_gpio;
    usb_regulator_io = "nocare";
    usb_wakeup_suspend = <0>;
    usb_luns = <3>;
    usb_serial_unique = <0>;
    usb_serial_number = "20080411";
    rndis_wceis = <1>;
    status = "okay";
};

udc:udc-controller@0x05100000 {
    compatible = "allwinner,sunxi-udc";
    reg = <0x0 0x05100000 0x0 0x1000>,      /*udc base*/
    	  <0x0 0x00000000 0x0 0x100>,       /*sram base*/
    	  <0x0 0x05200000 0x0 0x1000>;      /*usb1 base, for common circuit*/
    interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; /*设备使用的中断*/
    clocks = <&clk_usbphy0>, <&clk_usbotg>, <&clk_usbehci1>, <&clk_usbphy1>; /*设备使用的时钟*/
    status = "okay"; /*是否使能该设备*/
};

ehci0:ehci0-controller@0x05101000 {
    compatible = "allwinner,sunxi-ehci0";
    reg = <0x0 0x05101000 0x0 0xFFF>, /*hci0 base*/
    	  <0x0 0x00000000 0x0 0x100>,
    	  <0x0 0x05100000 0x0 0x1000>,
    	  <0x0 0x07010250 0x0 0x10>,    /*prcm base, for usb standby*/
    	  <0x0 0x05200000 0x0 0x1000>;  /*usb1 base, for common circuit*/
    interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clk_usbphy0>, <&clk_usbehci0>, <&clk_usbehci1>, <&clk_usbphy1>;
    hci_ctrl_no = <0>; /*主机控制器的序列*/
    status = "okay";
};

ohci0:ohci0-controller@0x05101400 {
    compatible = "allwinner,sunxi-ohci0";
    reg = <0x0 0x05101000 0x0 0xFFF>, /*hci0 base*/
	      <0x0 0x00000000 0x0 0x100>,
          <0x0 0x05100000 0x0 0x1000>,
    	  <0x0 0x07010250 0x0 0x10>, /*prcm base, for usb standby*/
    	  <0x0 0x05200000 0x0 0x1000>;/*usb1 base, for common circuit*/
    interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clk_usbphy0>, <&clk_usbohci0>, <&clk_usbohci1>, <&clk_usbphy1>;
    hci_ctrl_no = <0>;
    status = "okay";
};

USB1 配置

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

ehci1:ehci1-controller@0x05200000 {
    compatible = "allwinner,sunxi-ehci1";
    reg = <0x0 0x05200000 0x0 0xFFF>,
          <0x0 0x00000000 0x0 0x100>,
          <0x0 0x05100000 0x0 0x1000>,
          <0x0 0x07010250 0x0 0x10>;
    interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clk_usbphy1>, <&clk_usbehci1>;
    hci_ctrl_no = <1>;
    status = "okay";
};

ohci1:ohci1-controller@0x05200400 {
    compatible = "allwinner,sunxi-ohci1";
    reg = <0x0 0x05200000 0x0 0xFFF>,
          <0x0 0x00000000 0x0 0x100>,
          <0x0 0x05100000 0x0 0x1000>,
          <0x0 0x07010250 0x0 0x10>;
    interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clk_usbphy1>, <&clk_usbohci1>, <&clk_usbohci1_12m>, <&clk_osc48md4>, 			 <&clk_hosc>, <&clk_losc>;
    hci_ctrl_no = <1>;
    status = "okay";
};

2.3.2 board.dts 配置说明

board.dts 用于保存每一个板级平台的设备信息(如 demo 板,perf1 板等),里面的配置信息会覆盖上面的 Device Tree 默认配置信息。不同 soc、版型及内核版本对应的 board.dts 具体路径如下:device/config/chips/soc/conf igs/{board}/${内核版本}/board.dts。

USB0 配置

usbc0:usbc0@0 {
    device_type = "usbc0";
    usb_port_type = <0x2>;
    usb_detect_type = <0x1>;
    usb_id_gpio = <&pio PH 8 0 0 0xffffffff 0xffffffff>;
    usb_det_vbus_gpio = "axp_ctrl"; 
    usb_regulator_io = "nocare";
    det_vbus_supply = <&usb_power_supply>;
    usb_wakeup_suspend = <0>;
    usb_luns = <3>;
    usb_serial_unique = <0>;
    usb_serial_number = "20080411";
    rndis_wceis = <1>;
    status = "okay";
};

注:(1)usb_port_type:usb0口默认的模式。
置0:devcie模式;
置1:host模式;
置2:otg模式。
(2)usb_detect_type:usb0口otg检测模式。
置0:不做检测;
置1:vbus/id检测;
置2:id/dpdm检测。
(3)usb_wakeup_suspend:standby模式。
置0:super standby模式;
置1:usb standby模式,支持远程唤醒。

udc:udc-controller@0x51000000 {
	det_vbus_supply = <&usb_power_supply>
}

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

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

说明

若使用 usb standby 模式,需注意如下:

1、IC 支持远程唤醒;

2、若条件 1 满足,相关硬件部分需严格按照《硬件设计文档》设计;

3、若条件 1、2 满足,额外添加属性 “wakeup-source;”, 启用 usb standby 功能。

USB1 配置

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

ehci1:ehci1-controller@0x05200000 {
	drvvbus-supply = <&reg_usb1_vbus>;
};

ohci1:ohci1-controller@0x05200400 {
	drvvbus-supply = <&reg_usb1_vbus>;
};

Vbus 配置

reg_usb1_vbus: usb1-vbus {
    compatible = "regulator-fixed";
    gpio = <&pio PH 10 1 2 0 1>;
    regulator-name = "usb1-vbus";
    regulator-min-microvolt = <5000000>;
    regulator-max-microvolt = <5000000>;
    regulator-enable-ramp-delay = <1000>;
    enable-active-high;
};

2.3.3 kernel menuconfig 配置说明

进入内核根目录,执行 make ARCH=arm menuconfig(64 位平台为 make ARCH=arm64 menuconfig)进入配置主界面,并按以下步骤操作:

选择 Device Drivers 选项进入下一级配置,如下图所示。

​ 图 2-1: Device Drivers 选项配置

选择 USB support 选项,进入下一级配置,如下图所示。

​ 图 2-2: USB Support 选项配置

打开如下两图的选项,如下图所示。

​ 图 2-3: USB Support 详细配置 1

​ 图 2-4: USB Support 详细配置 2

选择 USB Gadget Support,进入下一级配置,如下图所示。

​ 图 2-5: USB Gadget Support 选项配置

打开下图的选项,并在对应配置中打开所需的功能性配置, 如: 需要存储功能时, 需打开下图中的 “mass storage” 配置, 如下图所示。

​ 图 2-6: USB Gadget Support 详细配置

进入 USB Peripheral Controller,并打开下图选项:

​ 图 2-7: USB Peripheral Controller 详细配置

返回上一级,即 USB support,进入 SUNXI USB2.0 Dual Role controller support,并打开下图选项,如下图所示。

​ 图 2-8: SUNXI USB2.0 Dual Role Controller Support 详细配置

若需支持 MTP PTP 等功能需开启 TYPEC 配置返回上一级,即 USB support,进入 USB Type-C Support,并打开下图选项,如下图所示:

​ 图 2-9: USB Type-C Support 详细配置

2.4 源码结构介绍

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

Host

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

UDC 和 Manager

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

2.5 驱动框架介绍

Linux 内核提供了完整的 USB 驱动程序框架。USB 总线采用树形结构,在一条总线上只能有唯一的主机设备。Linux 内核从主机和设备两个角度观察 USB 总线结构。下图是 Linux 内核从主机和设备两个角度观察 USB 总线结构的示意图。

​ 图 2-10: USB 驱动总体结构

USB 子系统主要任务包括:

a. 注册和管理设备驱动;

b. USB 设备寻找驱动,并初始化和配置设备;

c. 内核中表现设备的树形结构;

d. 与设备交互。

2.6 Gadget 配置

Gadget 是指具有 USB 设备控制器的 USB 设备,根据具体的功能配置,连接到 PC 后可以作为 mass storage、uac 等设备。Linux 有原生 gadget 框架,通用的配置流程可参考下文。

2.6.1 打开内核配置

需在 “USB functions configurable through configfs” 下选择需要的功能。

​ 图 2-11: linux-4.x usb gadget 配置选择

2.6.2 linux-4.x/linux-5.4 USB Gadget 配置流程

Linux-4.x/Linux-5.4 使用 configfs 框架实现 composite gadget 功能。具体流程如下:

挂载 configs:

mount -t configfs none /sys/kernel/config

挂载完成之后在/sys/kernel/config 目录下就会生成 usb_gadget/目录。

建立 gadgets:

mkdir /sys/kernel/config/usb_gadget/g1

创建g1/目录之后,该目录下会生成很多配置目录,这里的g1表示 gadget 1,一个 UDC 对应一个 gadget,如果你的 SOC 上有多个 gadget,可以创建多个gx目录。

写入 gadget 的 PID、VID、序列号等信息:

echo "VID" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "PID" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
echo "manufacturer" > /sys/kernel/config/usb_gadget/g1/strings/0x409/manufacturer
echo "product" > /sys/kernel/config/usb_gadget/g1/strings/0x409/product

建立 gadget 相关配置 configurations

mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409

建立功能 functions

mkdir /sys/kernel/config/usb_gadget/g1/functions/<name>.<instance name>

:function name :任意字符串

建立功能和配置的链接

ln -s /sys/kernel/config/usb_gadget/g1/functions/<name>.<instance name> /sys/kernel/config/
usb_gadget/g1/configs/c.1

使能 gadget

echo <udc name> > UDC

常见 Gadget 功能的配置方式见附录。

2.7 端点配置

在 Gadget 配置使用过程中,可能出现端点的默认配置方式无法满足需求的情况,故需对端点进行修改满足需求。可参考现有的端点进行修改。譬如将批量端点改成中断端点,参考现有的中断端点进行修改即可。改动内容包括端点 fifo 大小,端点属性,端点方向。

2.7.1 端点 fifo 大小

以4k平台为例:
static const struct sw_udc_fifo ep_fifo[] = {
    {ep0name, 0, 512, 0},/*name, fifo_addr, fifo_size, double_fifo*/
    {ep1in_bulk_name, 512, 512, 0},
    {ep1out_bulk_name, 1024, 512, 0},
    {ep2in_bulk_name, 1536, 512, 0},
    {ep2out_bulk_name, 2048, 512, 0},
    {ep3_iso_name, 2560, 1024, 0},
    {ep4_int_name, 3584, 512, 0},
};

2.7.2 端点的属性

.ep[2] = {
    .num = 1,
    .ep = {
        .name      = ep1out_bulk_name,
        .ops       = &sunxi_udc_ep_ops,
        .maxpacket = SW_UDC_EP_FIFO_SIZE,
        .maxpacket_limit = SW_UDC_EP_FIFO_SIZE,
        .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
            USB_EP_CAPS_DIR_OUT),
    },
    .dev              = &sunxi_udc,
    .bEndpointAddress = (USB_DIR_OUT | 1),
    .bmAttributes     = USB_ENDPOINT_XFER_BULK,
},

2.7.3 定义端点的方向

/**
 * ep_fifo_in[i] = {n} i: the physic ep index, n: ep_fifo's index for the ep
 *
 * eg: ep_fifo_in[2] = {3} ===> ep2_in is in ep_fifo[3]
 * 
 * ep3_iso_name and ep4_int_name cannot be tx or rx simultaneously. 
 * 
 */
static const int ep_fifo_in[] = {0, 1, 3, 5, 6, 7};
static const int ep_fifo_out[] = {0, 2, 4, 5, 6, 8};

2.8 调试方法

2.8.1 调试节点

2.8.1.1 USB0 调试节点

查看 USB0 当前 Role

cat /sys/devices/platform/soc/usbc0/otg_role

手动切换到 Host 模式

cat /sys/devices/platform/soc/usbc0/usb_host

手动切换到 Device 模式

cat /sys/devices/platform/soc/usbc0/usb_device
2.8.1.2 USB1 调试节点

卸载主机驱动

通过下述命令找到主机驱动节点及对应路径

find -name ehci_enable
find -name ohci_enable

然后根据上述结果,按如下命令卸载主机驱动 (以 t5 平台为例)

echo 0 > sys/devices/platform/soc/5200000.ehci1-controller/ehci_enable
echo 0 > sys/devices/platform/soc/5200000.ohci1-controller/ohci_enable

加载主机驱动

通过下述命令找到主机驱动节点及对应路径

find -name ehci_enable
find -name ohci_enable

然后根据上述结果,按如下命令加载主机驱动 (以 t5 平台为例)

echo 1 > sys/devices/platform/soc/5200000.ehci1-controller/ehci_enable
echo 1 > sys/devices/platform/soc/5200000.ohci1-controller/ohci_enable

2.8.2 眼图测试

2.8.2.1 USB Device 眼图测试
获取otg_ed_test的路径path
find /sys/ -name otg_ed_test
测试眼图命令
echo test_pack > path/otg_ed_test
2.8.2.2 USB Host 眼图测试
获取ed_test的路径path
find /sys/ -name ed_test
测试眼图命令
echo test_pack > path/ed_test

3 FAQ

3.1 常见问题

3.1.1 USB 基本功能异常排查

3.1.1.1 USB Host 基本功能异常排查步骤

多找几个 USB 设备试试,排除个别 USB 设备本身的问题。

多更换几根 USB 线缆试试,排除个别 USB 线缆的问题。

多找几个 PC 主机做相同的实验,作为参考对比。若在 PC 有相同现象,则认为正常。

若硬件有多个 USB 口,尝试同样条件下测试其他 USB 口的主机功能是否正常。

样机设备 USB 口外接独立供电的 USB-HUB 设备,再将 USB 设备连接到 USB-HUB 上,确认主机功能是否正常。

确认主机驱动是否加载成功。

(1)若为 USB0 口,则可通过如下方式确认:

cat /sys/devices/platform/soc/usbc0/otg_role

(2)若为 USB1 口,可通过如下方式确认:

cat sys/devices/platform/soc/5200000.ehci1-controller/ehci_enable
cat sys/devices/platform/soc/5200000.ohci1-controller/ohci_enable

若为0,则没有加载Host驱动。

重新加载 Host 驱动,确认此时功能是否正常。

(1)若为 USB0 口,则可通过如下方式:

方式1:重新插拔OTG线。
方式2:手动切换到Host模式。

(2)若为 USB1 口,则可通过卸载驱动、再加载驱动。

对比 SDK 代码与最新发布的代码或者补丁, 确认代码是否更新到最新。

同样条件下,分别打印出功能异常板子和功能正常板子的相关寄存器,并进行对比,确认是否有不同之处。

出现异常时,测试 USB 高速眼图是否正常。

若眼图测试未通过,可尝试调节眼图参数。

3.1.1.2 USB Device 基本功能异常排查步骤

多换几个 PC 主机做相同的测试,排除个别 PC 的问题。

多更换几根 USB 线缆做相同的测试,排除个别 USB 线缆的问题。

确认 Device 驱动是否加载成功,可通过如下方式:

(1)通过 Log。

[ 104.732695]  insmod_device_driver
[ 104.732695] 
device_chose finished!

(2)通过节点查看当前 Role。

重新加载 Device 驱动,确认此时功能是否恢复正常。

(1)重新插拔 USB 线。

(2)手动切换到 Device 模式。

对比 SDK 代码与最新发布的代码或者补丁, 确认代码是否更新到最新。

同样条件下,分别打印出功能异常板子和功能正常板子的相关寄存器,并进行对比,确认是否有异常。

出现异常时,确认 USB 高速眼图是否正常。

3.1.2 配置其他 gadget 功能前关闭 adb 功能时却报异常的解决办法

问题产生的原因是:仅执行./etc/adb_conf.sh stop 只是强制杀死 adb 守护进程,但 adb 功能链接仍存,当配置其他 gadget 功能时,便会复合 adb 链接导致异常,故在需要配置其他 gadget 功能时,除了强制杀死 adb 守护进程还须移除 adb 功能链接,在小机中操作步骤如下:

1、./etc/adb_conf.sh stop
2、umount /sys/kernel/config
3、rm -fr /sys/kernel/config/usb_gadget/g1/configs/c.1/ffs.adb

执行以上操作,正常关闭 adb 后,根据需要的 gadget 功能,参考【附录】章节进行配置即可。

4 附录

4.1 Linux-4.x/Linux-5.4 Gadget 配置示例

4.1.1 小机做 mass storage

dd if=/dev/zero of=/dev/a.bin bs=1M count=100
mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x18d1" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x0001" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0
echo /dev/a.bin > /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/file
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/ /sys/kernel/config/
usb_gadget/g1/configs/c.1/
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

说明

如果需要增加 lun,在 functions/mass_storage.usb0 下:

mkdir lun.1

mkdir lun.2

4.1.2 小机做 cdrom

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x1f3a" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0xa4ac" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0
echo 1 > /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/cdrom
echo /tmp/phoenixcard.iso > /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/
lun.0/file
ln -s /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/ /sys/kernel/config/
usb_gadget/g1/configs/c.1/mass_storage.usb0
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

说明

/tmp/phoenixcard.iso 根据实际情况更改。

4.1.4 小机做 UAC2

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x1d61" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x0101" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/uac2.usb0
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/uac2.usb0/ /sys/kernel/config/usb_gadget/
g1/configs/c.1/
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

4.1.5 小机做 UVC

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x1f3a" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x100d" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0
mkdir -p /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p
echo 1280 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/wWidth
echo 720 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/
wHeight
echo 333333 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/
dwFrameInterval
echo 333333 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/
dwDefaultFrameInterval
echo 442368000 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p
/dwMinBitRate
echo 442368000 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p
/dwMaxBitRate
echo 1843200 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/
dwMaxVideoFrameBufferSize
mkdir /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/header/h
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/streaming/header/h/
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/header/h/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/streaming/class/fs
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/header/h/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/streaming/class/hs
mkdir /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/control/header/h
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/control/header/h/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/control/class/fs/
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/control/header/h/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/control/class/ss/
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/ /sys/kernel/config/usb_gadget/g1
/configs/c.1/
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

4.1.6 小机做 HID

mount -t configfs none /sys/kernel/config/
mkdir /sys/kernel/config/usb_gadget/g1
echo 0x0525 >/sys/kernel/config/usb_gadget/g1/idVendor
echo 0xa4ac >/sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/hid.usb0
echo 512 >/sys/kernel/config/usb_gadget/g1/functions/hid.usb0/report_length
echo -ne <report_desc> >/sys/kernel/config/usb_gadget/g1/functions/hid.usb0/report_desc
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 >/sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 >/sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/hid.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

说明

report_desc 根据需求自定义。

4.1.7 小机做 rndis

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x1f3a" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x200a" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/rndis.usb0
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/rndis.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/rndis.usb0
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

4.1.8 小机做 acm

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x1f3a" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x0007" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/acm.usb0
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/acm.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/acm.usb0
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

4.1.9 小机做 adb

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x18d1" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x0002" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
echo "20080411" > /sys/kernel/config/usb_gadget/g1/strings/0x409/serialnumber
echo "Android" > /sys/kernel/config/usb_gadget/g1/strings/0x409/manufacturer
mkdir /sys/kernel/config/usb_gadget/g1/functions/ffs.adb
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/ffs.adb/ /sys/kernel/config/usb_gadget/g1/
configs/c.1/ffs.adb
mkdir /dev/usb-ffs
mkdir /dev/usb-ffs/adb
mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb/
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

4.1.10 小机做 mass storage+adb

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x18d1" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x0003" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
echo "20080411" > /sys/kernel/config/usb_gadget/g1/strings/0x409/serialnumber
echo "Android" > /sys/kernel/config/usb_gadget/g1/strings/0x409/manufacturer
mkdir /sys/kernel/config/usb_gadget/g1/functions/ffs.adb
mkdir /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0
echo ${BLOCK_PATH} > /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/file
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/ /sys/kernel/config/
usb_gadget/g1/configs/c.1/mass_storage.usb0
ln -s /sys/kernel/config/usb_gadget/g1/functions/ffs.adb/ /sys/kernel/config/usb_gadget/g1/
configs/c.1/ffs.adb
mkdir /dev/usb-ffs
mkdir /dev/usb-ffs/adb
mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb/
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

4.1.11 小机做 uvc+uac1

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x1f3a" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x100d" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/uac1.usb0
mkdir /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0
mkdir -p /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p
echo 1280 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/wWidth
echo 720 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/wHeight
echo 333333 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/dwFrameInterval
echo 333333 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/dwDefaultFrameInterval
echo 442368000 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/dwMinBitRate
echo 442368000 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/dwMaxBitRate
echo 1843200 > /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/720p/dwMaxVideoFrameBufferSize
mkdir /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/header/h
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/mjpeg/m/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/streaming/header/h/
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/header/h/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/streaming/class/fs
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/streaming/header/h/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/streaming/class/hs
mkdir /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/control/header/h
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/control/header/h/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/control/class/fs/
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/control/header/h/ /sys/kernel/
config/usb_gadget/g1/functions/uvc.usb0/control/class/ss/
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/uvc.usb0/ /sys/kernel/config/usb_gadget/g1
/configs/c.1/
ln -s /sys/kernel/config/usb_gadget/g1/functions/uac1.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

4.1.12 小机做 hid+cdrom

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x1f3a" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0xa4ac" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 > /sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/hid.usb0
mkdir /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0
echo 512 >/sys/kernel/config/usb_gadget/g1/functions/hid.usb0/report_length
echo -ne <report_desc> >/sys/kernel/config/usb_gadget/g1/functions/hid.usb0/report_desc
ln -s /sys/kernel/config/usb_gadget/g1/functions/hid.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/hid.usb0
echo 1 > /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/cdrom
echo /tmp/phoenixcard.iso > /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/lun.0/file
ln -s /sys/kernel/config/usb_gadget/g1/functions/mass_storage.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/mass_storage.usb0
ls /sys/class/udc/ | xargs echo > /sys/kernel/config/usb_gadget/g1/UDC

4.1.13 小机做 rndis+adb

mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo "0x18d1" > /sys/kernel/config/usb_gadget/g1/idVendor
echo "0x0010" > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
mkdir /sys/kernel/config/usb_gadget/g1/functions/ffs.adb
mkdir /sys/kernel/config/usb_gadget/g1/functions/rndis.usb0
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
echo 0xc0 >/sys/kernel/config/usb_gadget/g1/configs/c.1/bmAttributes
echo 500 >/sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
ln -s /sys/kernel/config/usb_gadget/g1/functions/rndis.usb0/ /sys/kernel/config/usb_gadget/g1/configs/c.1/rndis.usb0
ln -s /sys/kernel/config/usb_gadget/g1/functions/ffs.adb/ /sys/kernel/config/usb_gadget/g1/configs/c.1/ffs.adb
mkdir /dev/usb-ffs
mkdir /dev/usb-ffs/adb
mount -o uid=2000,gid=2000 -t functionfs adb /dev/usb-ffs/adb/
ls/sys/class/udc/|xargs echo>/sys/kernel/config/usb_gadget/g1/UDC

有关Linux USB 开发指南的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  3. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  4. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  5. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  8. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  9. ruby-on-rails - environment.rb 中设置的常量在开发模式中消失 - 2

    了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl

  10. ruby - Rails 开发服务器、PDFKit 和多线程 - 2

    我有一个使用PDFKit呈现网页的pdf版本的Rails应用程序。我使用Thin作为开发服务器。问题是当我处于开发模式时。当我使用“bundleexecrailss”启动我的服务器并尝试呈现任何PDF时,整个过程会陷入僵局,因为当您呈现PDF时,会向服务器请求一些额外的资源,如图像和css,看起来只有一个线程.如何配置Rails开发服务器以运行多个工作线程?非常感谢。 最佳答案 我找到的最简单的解决方案是unicorn.geminstallunicorn创建一个unicorn.conf:worker_processes3然后使用它:

随机推荐