USB重定向协议

概述

本文档描述的协议是单个usb设备的隧道化传输,不是整个集线器。最典型的使用场景是usb设备插在client端,使usb设备在guest虚拟机内部显示和使用,就好象usb设备直接插在虚拟机上一样。所描述的协议假定有可靠的双向传输通信,例如tcp套接字。协议中的所有整数都是通过管道以最低有效字节优先的顺序发送的。通过管道发送的所有结构都是打包的(没有填充字节)。
定义:

  • usb-device:usb设备,通过隧道传输。
  • usb-guest:连接到usb设备并使用它的实体(guest),就像直接连接到它一样。
  • usb-host:使usb-device可供usb-guest使用的实体(client)。

基本包结构/通信

在usb-guest和usb-host之间交换的每个数据包都以usb_redir_header开头,后跟可选的数据包类型指定的头部,加上可选的附加数据。
每个包都以usb_redir_header开始,结构如下:

struct usb_redir_header {
    uint32_t type;
    uint32_t length;
    uint32_t id;
}
//或者如果两端都有usb_redir_cap_64bits_ids 能力:
struct usb_redir_header {
    uint32_t type;
    uint32_t length;
    uint64_t id;
}

type: 数据包的类型id,来自于type的枚举类型
length: 可选的数据包类型指定的头部加上可选的数据的长度。
id: 一个唯一的值,usb-guest发送包时产生,usb-host响应包返回。usb-guest使用id来匹配请求和响应。

有两种类型的数据包

  1. 控制包 control packets
  2. 数据包 data packets

控制包在usb-host内同步处理,它会将请求传递给host os,然后等待响应。在这期间,usb-host将停止处理更多的包。 对于数据包,usb-host将其和request一起传递给主机操作系统,让usb-host进程知道何时有来自usb-device的响应。

请注意,只有在受控制包影响的设备/接口/端点上没有数据包待处理时,才应将控制包发送到usb-host。 任何待处理的数据包都将被丢弃,任何活动的iso流/分配的bulk流将被停止/free-ed。

Packet type list

//control packets
usb_redir_hello
usb_redir_device_connect
usb_redir_device_disconnect
usb_redir_reset
usb_redir_interface_info
usb_redir_ep_info
usb_redir_set_configuration
usb_redir_get_configuration
usb_redir_configuration_status
usb_redir_set_alt_setting
usb_redir_get_alt_setting
usb_redir_alt_setting_status
usb_redir_start_iso_stream
usb_redir_stop_iso_stream
usb_redir_iso_stream_status
usb_redir_start_interrupt_receiving
usb_redir_stop_interrupt_receiving
usb_redir_interrupt_receiving_status
usb_redir_alloc_bulk_streams
usb_redir_free_bulk_streams
usb_redir_bulk_streams_status
usb_redir_cancel_data_packet
usb_redir_filter_reject
usb_redir_filter_filter
usb_redir_device_disconnect_ack
usb_redir_start_bulk_receiving
usb_redir_stop_bulk_receiving
usb_redir_bulk_receiving_status

//data packets
usb_redir_control_packet
usb_redir_bulk_packet
usb_redir_iso_packet
usb_redir_interrupt_packet
usb_redir_buffered_bulk_packet

Status code list

许多usb-host回复都有一个状态字段,该字段可以具有以下值:

enum {
    usb_redir_success,
    usb_redir_cancelled,    /* The transfer was cancelled */
    usb_redir_inval,        /* Invalid packet type / length / ep, etc. */
    usb_redir_ioerror,      /* IO error */
    usb_redir_stall,        /* Stalled */
    usb_redir_timeout,      /* Request timed out */
    usb_redir_babble,       /* The device has "babbled" */
};

请注意,在将来的版本中,可能还有其他状态代码来指示新的/其他错误条件。 因此,任何未知状态值都应该被解释为错误

usb_redir_hello

usb_redir_header.type = usb_redir_hello
usb_redir_header.length = <see description>
usb_redir_header.id =0 //(always as this is an unsolicited(主动提供) packet)

struct usb_redir_hello_header {
    char     version[64];
    uint32_t capabilities[0];
}

没有包类型特定的附加数据。
一旦建立连接,双方就发送这种类型的包。 该数据包必须是双方发送的第一个数据包! 该包包含:

  • version:一个以0结尾的自由格式的版本字符串,对于日志记录非常有用,不应该被解析! 建议格式:“qemu 0.13”,“usb-redir-daemon 0.1”等
  • 功能:用于通知功能的可变长度数组。

请注意,由于在收到usb_redir_hello数据包之前不知道对方的能力,因此hello数据包始终具有32位id字段!
length字段的值取决于capabilities数组的大小。 值为64 + capabilities-array-size * sizeof(uint32_t)。
Currently the following capabilities are defined:

enum {
    /* Supports USB 3 bulk streams */
    usb_redir_cap_bulk_streams, 
    /* The device_connect packet has the device_version_bcd field */
    usb_redir_cap_connect_device_version,
    /* Supports usb_redir_filter_reject and usb_redir_filter_filter pkts */
    usb_redir_cap_filter,
    /* Supports the usb_redir_device_disconnect_ack packet */
    usb_redir_cap_device_disconnect_ack,
    /* The ep_info packet has the max_packet_size field */
    usb_redir_cap_ep_info_max_packet_size,
    /* Supports 64 bits ids in usb_redir_header */
    usb_redir_cap_64bits_ids,
    /* Supports 32 bits length in usb_redir_bulk_packet_header */
    usb_redir_cap_32bits_bulk_length,
    /* Supports bulk receiving / buffered bulk input */
    usb_redir_cap_bulk_receiving,
};

usb_redir_device_connect

usb_redir_header.type = usb_redir_device_connect
usb_redir_header.length = sizeof(usb_redir_device_connect_header)
usb_redir_header.id  = 0 // (always as this is an unsolicited packet)

enum {
    usb_redir_speed_low,
    usb_redir_speed_full,
    usb_redir_speed_high,
    usb_redir_speed_super,
    usb_redir_speed_unknown = 255
}

struct usb_redir_device_connect_header {
    uint8_t speed;
    uint8_t device_class;
    uint8_t device_subclass;
    uint8_t device_protocol;
    uint16_t vendor_id;
    uint16_t product_id;
    uint16_t device_version_bcd;
}

No packet type specific additional data.

当设备可用时,该数据包由usb-host发送(usb-host可能等待设备插入)。
只有当双方都具有usb_redir_cap_connect_device_version功能时,才应发送(并在接收时预期)device_version_bcd字段。 如果不是这种情况,数据包的长度将减少2个字节!
请注意,usb-host可以重新使用现有连接用于新的/重新插入的设备,在这种情况下,可以在usb_redir_device_disconnect消息之后发送该数据包以通知usb-guest新设备可用。
注意usbredir-host 在发送usb_redir_device_connect_info之前,必须在发送usb_redir_interface_info之后接着发送usb_redir_ep_info

usb_redir_device_disconnect

usb_redir_header.type =  usb_redir_device_disconnect
usb_redir_header.length = 0
usb_redir_header.id = 0// (always as this is an unsolicited packet)

No packet type specific header.
No packet type specific additional data.
该数据包可以由usb-host发送,以指示设备已断开连接(拔掉插头)。 请注意,在某些平台上,usb-host可能不会意识到设备已断开连接,直到一个usb包发送给设备。

usb_redir_reset

usb_redir_header.type  = usb_redir_reset
usb_redir_header.length = 0

No packet type specific header. No packet type specific additional data.

这个数据包可以由usb-guest发送,以便重置usb设备。 请注意,出现问题后,usb-host可能无法在重置后重新连接到设备! 如果发生这种情况,usb-host将发送usb_redir_device_disconnect数据包。

usb_redir_interface_info

usb_redir_header.type  =   usb_redir_interface_info
usb_redir_header.length = sizeof(usb_redir_interface_info_header)
usb_redir_header.id  =  0 //(always as this is an unsolicited packet)

struct usb_redir_interface_info_header {
    uint32_t interface_count;
    uint8_t interface[32];
    uint8_t interface_class[32];
    uint8_t interface_subclass[32];
    uint8_t interface_protocol[32];
}

No packet type specific additional data.
该数据包由usb-host发送,以通知usb-guest有关设备接口的信息。 它包含interface_count个接口的接口编号,类和协议信息。 这在(成功的)初始连接,set_config和set_alt_setting时发送。

usb_redir_ep_info

usb_redir_header.type    =   usb_redir_ep_info
usb_redir_header.length =  sizeof(usb_redir_ep_info_header)
usb_redir_header.id =     0 //(always as this is an unsolicited packet)

enum {
    /* Note these 4 match the usb spec! */
    usb_redir_type_control,
    usb_redir_type_iso,
    usb_redir_type_bulk,
    usb_redir_type_interrupt,
    usb_redir_type_invalid = 255
}

struct usb_redir_ep_info_header {
    uint8_t type[32];
    uint8_t interval[32];
    uint8_t interface[32];
    uint16_t max_packet_size[32];
}

No packet type specific additional data.

这个数据包由usb-host发送,让usb-guest知道所有可能端点所属的端点类型,间隔和接口,先是0-15 out,然后是0-15 in。这会在 初始化连接,set_configset_alt_setting时发送
只有当双方都具有usb_redir_cap_ep_info_max_packet_size功能时,才应发送max_packet_size字段(并在接收时预期)。 如果不是这种情况,数据包的长度将减少64个字节!

usb_redir_set_configuration

usb_redir_header.type =   usb_redir_set_configuration
usb_redir_header.length= sizeof(usb_redir_set_configuration_header)

struct usb_redir_set_configuration_header {
    uint8_t configuration;
}

No packet type specific additional data.
usb-guest可以发送此数据包以设置(更改)usb设备的活动配置。

usb_redir_get_configuration

usb_redir_header.type:    usb_redir_get_configuration
usb_redir_header.length:  0

No packet type specific header.
No packet type specific additional data.
usb-guest可以发送此数据包以获取(查询)usb设备的活动配置。

usb_redir_configuration_status

usb_redir_header.type:    usb_redir_configuration_status
usb_redir_header.length:  sizeof(usb_redir_configuration_status_header)

struct usb_redir_configuration_status_header {
    uint8_t status;
    uint8_t configuration;
}

No packet type specific additional data.
这是由usb-host发送的,用于响应usb_redir_set_configuration/usb_redir_get_configuration数据包。 它会报告状态代码,如果命令成功,还会返回 resulting/active 配置。 请注意,在成功的usb_redir_set_configuration命令之后,usbredir-host必须首先发送usb_redir_ep_info,然后发送usb_redir_interface_info,然后再发送usb_redir_configuration_status,以确保usb-guest在开始使用新配置时具有新信息。

usb_redir_set_alt_setting

usb_redir_header.type:    usb_redir_set_alt_setting
usb_redir_header.length:  sizeof(usb_redir_set_alt_setting_header)

struct usb_redir_set_alt_setting_header {
    uint8_t interface;
    uint8_t alt;
}

No packet type specific additional data.
usb-guest可以发送此数据包,以将接口<interface>的alt_setting设置(更改)为<alt>

usb_redir_get_alt_setting

usb_redir_header.type:    usb_redir_get_alt_setting
usb_redir_header.length:  sizeof(usb_redir_get_alt_setting_header)

struct usb_redir_get_alt_setting_header {
    uint8_t interface;
}

No packet type specific additional data.
usb-guest可以发送此数据包以获取(查询)usb设备接口的活动alt_setting。

usb_redir_alt_setting_status

usb_redir_header.type:    usb_redir_alt_setting_status
usb_redir_header.length:  sizeof(usb_redir_alt_setting_status_header)

struct usb_redir_alt_setting_status_header {
    uint8_t status;
    uint8_t interface;
    uint8_t alt;
}

No packet type specific additional data.
这是由usb-host发送的,用于响应usb_redir_set_alt_setting / usb_redir_get_alt_setting数据包。 它会报告状态代码,受影响的接口以及如果成功还包括该接口的结果/活动alt_setting。

请注意,在成功的usb_redir_set_alt_setting命令之后,usbredir-host必须首先发送usb_redir_ep_info,然后发送usb_redir_interface_info,然后再发送usb_redir_alt_setting_status,以确保usb-guest在开始使用新的alt设置时具有新信息

usb_redir_start_iso_stream

usb_redir_header.type:    usb_redir_start_iso_stream
usb_redir_header.length:  sizeof(usb_redir_start_iso_stream_header)

struct usb_redir_start_iso_stream_header {
    uint8_t endpoint;
    uint8_t pkts_per_urb;
    uint8_t no_urbs;
}

No packet type specific additional data.
usb-guest可以发送此数据包,以便在usb-device的指定端点上启动iso流。
此功能分配 no_urbs 个urb,每个urb有pkts_per_urb个iso数据包/帧。 对于iso输入端点,这些urb将立即提交给设备,对于iso输出端点,usb-host将等待它收到(pkts_per_urb * no_urbs / 2)数据包以填充其缓冲区,然后再提交第一个urb。

usb_redir_stop_iso_stream

usb_redir_header.type:    usb_redir_stop_iso_stream
usb_redir_header.length:  sizeof(struct usb_redir_start_iso_stream_header)

struct usb_redir_stop_iso_stream_header {
    uint8_t endpoint;
}

No packet type specific additional data.
usb-guest可以发送此数据包以停止指定端点上的iso流。 这将取消所有待处理的urb,刷新usb-host的缓冲区并释放所有相关资源。 请注意,usb-guest仍然可以在发送之后从端点中的isoc接收isoc数据包,因为某些数据包可能已经在传输管道内。

usb_redir_iso_stream_status

usb_redir_header.type:    usb_redir_iso_stream_status
usb_redir_header.length:  sizeof(usb_redir_iso_stream_status_header)

struct usb_redir_iso_stream_status_header {
    uint8_t status;
    uint8_t endpoint;
}

No packet type specific additional data.
该数据包由usb-host发送,以响应usb_redir_start_iso_streamusb_redir_stop_iso_stream数据包。 请注意,对于输出iso流的启动,成功状态仅指示已成功分配所有缓冲区,在缓冲足够的数据包之前不会启动实际流。
请注意,如果iso输出流发生错误,也可以通过usb-host主动发送,请参阅usb_redir_iso_packet
为了允许usb-guest检测到流是否被阻止,如果流由于usb_redir_stop_iso_stream之外的任何原因而被停止,usb-host将总是报告为usb_redir_stall状态,

usb_redir_start_interrupt_receiving

usb_redir_header.type:    usb_redir_start_interrupt_receiving
usb_redir_header.length:  sizeof(usb_redir_start_interrupt_receiving_header)

struct usb_redir_start_interrupt_receiving_header {
    uint8_t endpoint;
}

usb-guest可以发送此数据包以开始从usb设备的指定端点接收中断。
此功能仅用于input中断端点。 需要及时轮询输入中断端点,否则数据可能会丢失。 因此,对于输入中断端点,usb-host负责提交和重新提交urb。
收到此数据包后,usb-host将使用描述符中的interval和maxPacketSize启动到端点的中断传输。 当此传输完成时,usb-host将向usb-guest发送usb_redir_interrupt_packet,并将重新提交urb。

usb_redir_stop_interrupt_receiving

usb_redir_header.type:    usb_redir_stop_interrupt_receiving
usb_redir_header.length:  sizeof(struct usb_redir_start_interrupt_receiving_header)

struct usb_redir_stop_interrupt_receiving_header {
    uint8_t endpoint;
}

No packet type specific additional data.
usb-guest可以发送此数据包以停止指定端点上的中断接收。 这将取消待处理的urb。 请注意,usb-guest在发送之后仍然可以接收usb_redir_interrupt_packet-s,因为一些数据包可能已经在传输管道内。

usb_redir_interrupt_receiving_status

usb_redir_header.type:    usb_redir_interrupt_receiving_status
usb_redir_header.length:  sizeof(usb_redir_interrupt_receiving_status_header)

struct usb_redir_interrupt_receiving_status_header {
    uint8_t status;
    uint8_t endpoint;
}

No packet type specific additional data.
该数据包由usb-host发送,以响应usb_redir_start_interrupt_receivingusb_redir_stop_interrupt_receiving数据包。
请注意,如果重新提交中断urb时出错,也可以由usb-host主动发送。
为了允许usb-guest检测到流是否被阻止,如果流由于usb_redir_stop_interrupt_receiving之外的任何原因而被停止,则usb-host将始终报告为usb_redir_stall状态。

usb_redir_alloc_bulk_streams

usb_redir_header.type:    usb_redir_alloc_bulk_streams
usb_redir_header.length:  sizeof(usb_redir_alloc_bulk_streams_header)

struct usb_redir_alloc_bulk_streams_header {
    uint8_t endpoint;
    uint8_t no_streams;
}

No packet type specific additional data.
这个数据包可以由usb-guest发送到usb-host,以请求usb-host分配ID,这样usb-guest就可以使用最多no_streams流ID。

usb_redir_free_bulk_streams

usb_redir_header.type:    usb_redir_free_bulk_streams
usb_redir_header.length:  sizeof(usb_redir_free_bulk_streams_header)

struct usb_redir_free_bulk_streams_header {
    uint8_t endpoint;
}

No packet type specific additional data.
这个数据包可以由usb-guest发送到usb-host,以释放在端点上之前分配的任何bulk流。

usb_redir_bulk_streams_status

usb_redir_header.type:    usb_redir_bulk_streams_status
usb_redir_header.length:  sizeof(usb_redir_bulk_streams_status_header)

struct usb_redir_bulk_streams_status_header {
    uint8_t status;
    uint8_t endpoint;
    uint8_t no_streams;
}

No packet type specific additional data.

该数据包由usb-host发送,以响应usb_redir_alloc_bulk_streamsusb_redir_free_bulk_streams数据包。 请注意,响应usb_redir_alloc_bulk_streams是成功状态时,由于主机控制器/设备限制,no_streams可能会少于请求。 响应usb_redir_alloc_bulk_streams是成功状态时,usb-guest可以使用流ID 1到no_streams。

usb_redir_start_bulk_receiving

usb_redir_header.type:    usb_redir_start_bulk_receiving
usb_redir_header.length:  sizeof(usb_redir_start_bulk_receiving_header)

struct usb_redir_start_bulk_receiving_header {
    uint32_t stream_id;
    uint32_t bytes_per_transfer;
    uint8_t endpoint;  
    uint8_t no_transfers;
}

No packet type specific additional data.
usb-guest发送这个包启动从bulk端点读取缓存的数据。
收到此数据包后,usb-host将提交no_transfers个transfer中的bulk(每一个transfer中含有bytes_per_transfer字节)到usb-device的指定端点。 一旦一个transfer完成,usb-host将向usb-guest发送带有接收到的数据的usb_redir_buffered_bulk_packet,并立即重新提交已完成的transfer。
注意bytes_per_transfer必须是端点max_packet_size的倍数。
请注意,此数据包只应发送到具有usb_redir_cap_bulk_receiving功能的usb-hosts。

usb_redir_stop_bulk_receiving

usb_redir_header.type:    usb_redir_stop_bulk_receiving
usb_redir_header.length:  sizeof(usb_redir_stop_bulk_receiving_header)

struct usb_redir_stop_bulk_receiving_header {
    uint32_t stream_id;
    uint8_t endpoint;
}

No packet type specific additional data.
usb-guest可以发送此数据包以停止指定端点上的bulk接收。 这将取消所有待处理的transfer。 请注意,usb-guest在发送之后仍然可以接收usb_redir_bulk_packet-s,因为一些数据包可能已经在传输管道内。
请注意,此数据包只应发送到具有usb_redir_cap_bulk_receiving功能的usb-hosts。

usb_redir_bulk_receiving_status

usb_redir_header.type:    usb_redir_bulk_receiving_status
usb_redir_header.length:  sizeof(usb_redir_bulk_receiving_status_header)

struct usb_redir_bulk_receiving_status_header {
    uint32_t stream_id;
    uint8_t endpoint;
    uint8_t status;
}

No packet type specific additional data.
该数据包由usb-host发送,以响应usb_redir_start_bulk_receivingusb_redir_stop_bulk_receiving数据包。
请注意,如果重新提交bulk transfer时出错,也可以由usb-host主动发送。
为了允许usb-guest检测到流是否被阻止,如果流由于usb_redir_stop_interrupt_receiving之外的任何原因而被停止,则usb-host将始终报告为usb_redir_stall状态。
请注意,此数据包只应发送给具有usb_redir_cap_bulk_receiving功能的usb-guests。

usb_redir_cancel_data_packet

usb_redir_header.type:    usb_redir_cancel_data_packet
usb_redir_header.id       <id of packet to cancel>
usb_redir_header.length:  0

No packet type specific header.
No packet type specific additional data.
usb-guest可以发送此数据包以取消先前发送的数据包,id应设置为usb-guest希望取消的数据包使用的id。
请注意,usb-guest将总是收到一个具有相同类型相同ID的数据包,usb-guest可以通过查看返回数据包的状态字段检查数据包是否正常完成(在取消数据包由usb-host处理之前)或者是被取消。

usb_redir_filter_reject

usb_redir_header.type:    usb_redir_filter_reject
usb_redir_header.length:  0
usb_redir_header.id:      0 (always as this is an unsolicited packet)

No packet type specific header.
No packet type specific additional data.
这个数据包是在usb-guest收到usb-redir_device_connectusb_redir_interface_info数据包并被设备过滤器拒绝后由usb-guest发送的。 此数据包只应发送到具有usb_redir_cap_filter功能的usb-hosts。

usb_redir_filter_filter

usb_redir_header.type:    usb_redir_filter_filter
usb_redir_header.length:  string-length + 1 (for 0 termination)
usb_redir_header.id:      0 (always as this is an unsolicited packet)

No packet type specific header.
附加数据包含一个C风格的usredirfilter字符串。
可以在hello数据包之后直接发送此数据包,以通知对方过滤器已就位且某些设备可能被拒绝。
usredirfilter由一个或多个规则组成,其中字符串形式的每个规则都具有以下格式: <类>,<厂商>,<产品>,<版本>,<允许> 值可以是十进制格式,也可以是以0x预先固定的十六进制格式,值-1可以用于允许任何值。 过滤器的所有规则都是连续的,用“|”分隔 形成单个usredirfilter字符串的字符: <规则1> | <规则2> | <规则3> 如果设备不匹配任何规则,则过滤的结果是拒绝,设备将被拒绝。 有关过滤的更多信息,请参阅usbredirfilter.h 该数据包只应发送给具有`usb_redir_cap_filter`功能的对等体。

usb_redir_device_disconnect_ack

usb_redir_header.type:    usb_redir_device_disconnect_ack
usb_redir_header.length:  0
usb_redir_header.id:      0 (as the id of the device_disconnect is always 0)

No packet type specific header.
No packet type specific additional data.
在处理usb-host发送的usb_redir_device_disconnect数据包之后,usb-guest会发送此数据包。 这让想要重新使用现有连接的usb-host知道usb-guest已经看到断开连接并且不会再发送用于已断开连接设备的数据包。 如果没有这个,那么usb-host可能会有一个可用的新设备,但它仍在接收旧设备的数据包,因为usb-guest尚未看到断开连接。
请注意,只有双方都具有usb_redir_cap_device_disconnect_ack功能时才会发送此数据包。

usb_redir_control_packet

usb_redir_header.type:    usb_redir_control_packet
usb_redir_header.length:  sizeof(usb_redir_control_packet_header) [+ length]

struct usb_redir_control_packet_header {
    uint8_t endpoint;
    uint8_t request;
    uint8_t requesttype;
    uint8_t status;
    uint16_t value;
    uint16_t index;
    uint16_t length;
}

附加数据包含要发送/接收的控制消息数据。
这种类型的数据包可以由usb-guest发送到usb-host,以启动usb设备上的控制传输。 端点,请求,请求类型,值和索引对于USB控制消息具有其标准含义。 status字段仅用于usb-host的响应。
length是usb-guest发送/期望读取的数据量(在USB_DIR_IN情况下)。 请注意,长度应仅在一个方向上添加到usb_redir_header.length(并且实际数据包长度应匹配)。
当usb-device处理了控制消息时,usb-host将usb_redir_control_packet发送回usb-guest,所有字段都保持不变,除了状态字段和长度更新以匹配实际结果。

usb_redir_bulk_packet

usb_redir_header.type:    usb_redir_bulk_packet
usb_redir_header.length:  sizeof(usb_redir_bulk_packet_header) [+ length]

struct usb_redir_bulk_packet_header {
    uint8_t endpoint;
    uint8_t status;
    uint16_t length;
    uint32_t stream_id;
    uint16_t length_high; /* High 16 bits of the packet length */
}

附加数据包含要发送/接收的bulk msg数据。
这种类型的数据包可以由usb-guest发送到usb-host,以便在usb设备上启动一个bulk传输。 endpoint和stream_id对usb bulk消息有其标准含义。 status字段仅用于usb-host的响应。 length是usb-guest发送/期望读取的数据量(取决于端点的方向)。
length_high包含16位高位长度以允许大于65535字节的数据包,仅在双方都具有usb_redir_cap_32bits_bulk_length能力时发送/接收。
当usb-device处理bulk消息时,usb-host将usb_redir_bulk_packet发送回usb-guest,更新状态字段和长度以匹配实际结果。
请注意,就像usb_redir_control_packet一样,此数据包只在一个方向上有额外的数据,具体取决于端点的方向。
注意请参阅usb_redir_buffered_bulk_packet以获取从bulk端点接收数据的替代方法。

usb_redir_iso_packet

usb_redir_header.type:    usb_redir_iso_packet
usb_redir_header.length:  sizeof(usb_redir_iso_packet_header) + length

struct usb_redir_iso_packet_header {
    uint8_t endpoint;
    uint8_t status;
    uint16_t length;
}

附加数据包含要发送/接收的iso msg数据。
一旦使用usb_redir_start_iso_stream启动iso流,就应该持续发送此类型的数据包(以端点间隔速度),它们发送的方向取决于端点方向。
状态字段仅对从usb-host发送到usb-guest的数据包有意义(对于iso输入端点)。由于缓冲,不可能及时通知usb-guest关于iso输出包的传输错误。 usb-host自身将尝试清除任何错误条件。如果它失败了,它将向usb-guest发送usb_redir_iso_stream_status,表明iso流存在问题。
由于usb-host会在iso输入端点上启动流后连续发送usb_redir_iso_packet,因此usb-host无法将usb_redir_header.id设置为相应接收的数据包的id。所以对于usb_redir_iso_packet来说,usb-host只是以id为0开始,并且每个数据包都会递增。请注意,当usb-host从stall状态中恢复时,id将从0重新开始!

usb_redir_interrupt_packet

usb_redir_header.type:    usb_redir_interrupt_packet
usb_redir_header.length:  sizeof(usb_redir_interrupt_packet_header) [+ length]

struct usb_redir_interrupt_packet_header {
    uint8_t endpoint;
    uint8_t status;
    uint16_t length;
}

附加数据包含要发送/接收的中断msg数据。
中断端点的处理根据端点是输入还是输出端点而显著不同。

输入端点

需要及时轮询输入中断端点,否则数据可能会丢失。 因此,对于输入中断端点,usb-host负责提交和重新提交urb,usb-guest可以使用usb_redir_start_interrupt_receiving / usb_redir_stop_interrupt_receiving数据包启动/停止接收中断数据包。 请注意,对于输入中断端点,usb_redir_interrupt_packet-s仅在一个方向上发送,从usb-host发送到usb-guest!
由于usb_redir_interrupt_packet是在中断接收开始后由usb-host主动发送的,所以usb-host不能将usb_redir_header.id设置为相应接收数据包的id。 因此,对于usb_redir_interrupt_packet,usb-host只是以id为0开始,并将每个数据包递增。 请注意,当usb-host从停顿中恢复时,id将从0重新开始!

输出端点

对于中断输出端点,使用同样用于control和bulk transfers的普通异步机制:
usb-guest将usb_redir_interrupt_packet发送到usb-host。 当usb-device处理了中断消息时,usb-host将usb_redir_interrupt_packet发送回usb-guest,更新状态字段和长度以匹配实际结果。 当从usb-guest发送到usb-host时,此数据包仅包含其他数据(要输出的数据)。
请注意,由于与iso数据不同,通常中断数据没有流的概念,缓冲对输出中断数据包没有意义,而是尽快交付。
尽管是尽快交付,但很可能无法满足应用于中断输出传输的时间限制。 其后果因设备而异。

usb_redir_buffered_bulk_packet

usb_redir_header.type:    usb_redir_bulk_packet
usb_redir_header.length:  sizeof(usb_redir_bulk_packet_header) + length
usb_redir_header.id:      starts at 0, incremented by 1 per send packet

struct usb_redir_buffered_bulk_packet_header {
    uint32_t stream_id;
    uint32_t length;
    uint8_t endpoint;
    uint8_t status;
}

附加数据包含收到的bulk msg数据。
buffered bulk模式适用于bulk输入端点,其中数据具有流式特性(不是命令响应协议的一部分)。如果数据读取速度不够快,这些端点的输入缓冲区可能会溢出。因此,在buffered bulk模式下,usb-host负责提交和重新提交bulk传输。 usb-guest可以使用usb_redir_start_bulk_receiving / usb_redir_stop_bulk_receiving数据包开始/停止接收buffered bulk数据。
请注意,usb_redir_buffered_bulk_packet-s仅从一个方向发送,从usb-host发送到usb-guest!
由于usb-redir_buffered_bulk_packet-s在bulk 接收开始后由usb-host主动发送,因此usb-host无法将usb_redir_header.id设置为相应接收的数据包的id。因此,对于usb_redir_buffered_bulk_packet-s,usb-host只需以id为0开始,并将每个数据包递增。请注意,当usb-host从stall状态中恢复时,id将从0重新开始!
应该使用buffered bulk模式的典型示例是 usb 端点到串行转换器中的bulk。
注意buffered bulk模式只能在双方都具有usb_redir_cap_bulk_receiving功能时使用。