4. UAC1.0控制端点与中断端点
在 UAC1.0 协议中,音频功能的控制与状态反馈分别由 控制端点 (Endpoint 0, 默认控制管道) 和 中断端点 (Interrupt Endpoint) 承载。控制端点负责主机下发或查询音频属性(如音量、静音、采样率),中断端点则用于设备主动向主机上报状态变化(如音量旋钮被转动、插拔检测)。理解这两类传输的请求格式、数据流向和时序约束,是实现稳定 USB 声卡驱动的核心。
4.1 控制传输请求:Set/Get 与 Cur/Min/Max/Res
UAC1.0 的控制请求通过标准的 USB 控制传输(Setup + Data + Status 阶段)完成。请求格式遵循 Audio Class-Specific Request 规范,其 Setup 包结构如下:
| 字段 | 偏移 (字节) | 长度 (位) | 说明 |
|---|---|---|---|
| bmRequestType | 0 | 8 | 方向 (Host→Dev=0x21, Dev→Host=0xA1) + 类型 (Class=001) + 接收者 (Interface=00001) |
| bRequest | 1 | 8 | SET_CUR=0x01, GET_CUR=0x81, GET_MIN=0x82, GET_MAX=0x83, GET_RES=0x84 |
| wValue | 2 | 16 | 高字节: 控制选择子 (CS), 低字节: 实体ID (Entity ID) |
| wIndex | 4 | 16 | 高字节: 接口号 (Interface), 低字节: 终端/功能单元ID |
| wLength | 6 | 16 | 数据阶段传输的字节数 (取决于控制参数类型) |
CS 决定了具体操作哪个属性。例如:
- MUTE_CONTROL (CS=0x01): 静音开关,数据为 1 字节 (0=静音, 1=非静音)
- VOLUME_CONTROL (CS=0x02): 音量,数据为 2 字节 (有符号 16 位, 单位 dB/256)
- SAMPLING_FREQ_CONTROL (CS=0x01 for Clock Source): 采样率,数据为 3 字节 (24 位整数, 单位 Hz)
4.2 控制请求的典型流程:以音量调节为例
主机通过 SET_CUR 设置音量,通过 GET_CUR 读取当前音量。设备端驱动需在控制端点 0 的请求处理函数中解析 wValue 和 wIndex,定位到对应的 Feature Unit,然后执行硬件寄存器读写。
/* 伪代码:UAC1.0 音量 SET_CUR 处理 */
int uac1_feature_unit_set_cur(struct usb_device *udev,
u8 entity_id, u8 channel,
s16 volume) {
struct usb_ctrlrequest req;
req.bRequestType = 0x21; // Host to Device, Class, Interface
req.bRequest = 0x01; // SET_CUR
req.wValue = cpu_to_le16((0x02 << 8) | entity_id); // CS=VOLUME_CONTROL
req.wIndex = cpu_to_le16((iface_num << 8) | channel);
req.wLength = cpu_to_le16(2); // 2 bytes volume data
return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
req.bRequest, req.bRequestType,
req.wValue, req.wIndex,
&volume, 2, 1000);
}
4.3 中断端点:状态反馈的异步通道
UAC1.0 要求音频接口必须包含一个 中断端点 (Interrupt IN Endpoint),用于设备主动向主机报告音频功能的状态变化。典型场景包括:
- 音量旋钮/编码器:用户旋转硬件旋钮时,设备通过中断端点发送新的音量值。
- 静音按钮:硬件静音开关状态变化。
- 自动增益控制 (AGC) 状态:AGC 使能/失活或增益值变化。
- 时钟源锁定状态:外部时钟源失锁或重新锁定。
中断端点的传输数据格式为 UAC1.0 Status Interrupt Packet,长度固定为 6 字节:
| 字节偏移 | 字段 | 说明 |
|---|---|---|
| 0 | bStatusType | 0x01 = 中断由控制变化触发 (Cur变化) |
| 1 | bOriginator | 产生中断的实体 ID (Feature Unit ID 或 Terminal ID) |
| 2 | bControlSelector | 发生变化的控制选择子 (如 0x02=音量, 0x01=静音) |
| 3 | bAttribute | 0x00 = 当前值 (Cur) 变化 |
| 4-5 | wValue | 变化后的新值 (与对应控制的数据类型一致) |
4.4 中断端点的工作机制与驱动实现
设备端驱动需在初始化时注册中断端点的 URB,并提交一个 周期性中断传输。主机端通过轮询中断端点(通常每 1~8 帧,即 1~8 ms)获取状态更新。当设备无状态变化时,中断端点应返回 NAK;当有事件发生时,设备在中断端点上返回有效数据包。
/* 伪代码:中断端点 URB 提交与回调 */
static void uac1_interrupt_complete(struct urb *urb) {
struct uac1_status_packet *pkt = urb->transfer_buffer;
if (urb->status == 0 && pkt->bStatusType == 0x01) {
// 解析状态变化
u8 entity = pkt->bOriginator;
u8 cs = pkt->bControlSelector;
u16 new_val = le16_to_cpu(pkt->wValue);
// 通知上层应用或更新内部状态
audio_driver_notify_change(entity, cs, new_val);
}
// 重新提交 URB 以继续监听
usb_submit_urb(urb, GFP_ATOMIC);
}
int uac1_init_interrupt_endpoint(struct usb_device *udev,
struct usb_endpoint_descriptor *ep) {
struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
unsigned char *buf = kmalloc(6, GFP_KERNEL);
usb_fill_int_urb(urb, udev,
usb_rcvintpipe(udev, ep->bEndpointAddress),
buf, 6,
uac1_interrupt_complete, NULL,
ep->bInterval); // 轮询间隔 (帧数)
return usb_submit_urb(urb, GFP_KERNEL);
}
- 中断端点必须配置为 IN 方向,且最大包长通常为 6 字节。
- 如果硬件不支持主动中断,驱动应返回 NAK 或空包,不要返回错误 STALL,否则主机可能认为端点出错。
- 中断 URB 的回调中必须重新提交 URB,否则只能收到一次状态变化。
4.5 控制与中断的协同:状态同步流程
下图展示了主机通过控制端点查询/设置音频属性,以及设备通过中断端点主动上报状态变化的完整交互流程:
4.6 中断端点的 bInterval 与实时性权衡
中断端点的轮询间隔由描述符中的 bInterval 字段决定。对于全速 (Full Speed) 设备,bInterval 表示帧数 (1 帧 = 1 ms);对于高速 (High Speed) 设备,bInterval 表示微帧数 (1 微帧 = 125 μs)。
| bInterval 值 | 全速 (FS) 轮询间隔 | 高速 (HS) 轮询间隔 | 适用场景 |
|---|---|---|---|
| 1 | 1 ms | 125 μs | 高实时性要求 (如专业音频控制台) |
| 4 | 4 ms | 500 μs | 普通消费级声卡 |
| 8 | 8 ms | 1 ms | 低功耗/低优先级状态反馈 |
4.7 常见问题与调试方法
- 控制请求返回 STALL:检查 wValue 中的 CS 和实体 ID 是否匹配描述符中的定义;确认 Feature Unit 的 bmControls 位图是否声明支持该控制。
- 中断端点无数据:使用
usbmon或lsusb -v确认中断端点描述符的 bEndpointAddress 和 wMaxPacketSize 是否正确;检查硬件是否真正产生了中断事件。 - 音量值反向:UAC1.0 音量使用有符号数,+1 dB 对应 0x0100,-1 dB 对应 0xFF00。注意符号扩展和硬件寄存器映射。
- 中断 URB 提交失败:确认中断端点未在
usb_set_interface后被重置;检查 URB 的interval参数是否与描述符一致。
lsusb -v -d [vid:pid] | grep -A 10 "Audio Control" — 查看音频控制接口描述符usbmon -i 1 -t -s 0 — 实时监控 USB 控制传输和中断传输cat /sys/kernel/debug/usb/usbmon/1t — 查看 USB 监控文本输出