struct usb_driver

/**
 	struct usb_driver -确认到usbcore的接口驱动
 name:USB驱动之间,驱动的名字必须是独特的,并且和模块的名称通常一样
 probe:为了查看驱动是否能够管理设备上的一个独特的接口,如果能,probe返回0,并且
 使用usb_set_intfdata()整合驱动特性的数据与接口,同样肯呢过使用use usb_set_interface()
 去确定合适的altsetting。如果不能管理接口,返回-ENODEV。若IO错误出现,返回一个
 负值。
 disconnect:如果接口不能被访问就调用这个函数,常常因为设备没有连接或者驱动
 模块没有加载。
 unlocked_ioctl:若驱动想访问用户空间澹(通过usbfs文件系统)就会调用这个函数。
 这个函数能使设备暴露信息到用户空间而不用去管其他的
 suspend:系统禁用设备时会调用这个函数
 resume:系统重新调用设备时会调用这个函数
 reset_resume:当挂起的设备被复位而不是重新调用的时候调用这个函数
 pre_reset:当设备复位要复位时,被usb_reset_device()调用,这个例程直到驱动没有
 对设备没有活动的URBS才能返回,并且没有URBS被递交
 post_reset:设备复位后,被usb_reset_device()函数调用
 id_table:USB驱动使用ID table支持热插拔。输出参数到MODULE_DEVICE_TABLE().
 这是必须配置的,除非你的驱动probe函数永远不会调用
 dynids:用来保持设备id的链表
 drvwrap:驱动模型核心结构体的封装。
 no_dynamic_id:如果配置成1,USB核心将不会允许动态id被加入到驱动(通过阻止系统
 文件的创建)
 supports_autosuspend:如果配置成0,USB核心不会允许自动挂起驱动
 soft_unbind:如果配置成1,USB核心在调用驱动断开连接函数前不会杀手URBS和
 禁止使能端点。
 disable_hub_initiated_lpm:如果配置成0,当理想时间超时,USB核心不会允许HUBS
<think>我们正在分析`usb_serial_resume`函数,它是USB串口驱动中与`usb_serial_suspend`相对应的恢复函数。当系统从休眠状态唤醒时,USB核心会调用此函数来恢复USB串口设备的功能。 ### 一、`usb_serial_resume`函数的核心作用 1. **设备状态恢复** 当系统从休眠状态唤醒时,该函数负责: - 重新激活USB串口设备 - 恢复挂起前的串口配置(如波特率、数据位等) - 重新提交URB(USB Request Block)以恢复数据传输[^1] 2. **关联系统电源管理** 作为USB设备驱动的一部分,通过`.resume`回调函数注册到USB核心子系统: ```c static struct usb_driver usb_serial_driver = { .suspend = usb_serial_suspend, .resume = usb_serial_resume, // 唤醒回调 }; ``` 当系统触发唤醒流程时,USB核心层会遍历所有USB设备并调用其驱动的`resume`回调[^1]。 3. **处理挂起失败场景** 如果设备在挂起过程中失败(如`serial->type->suspend`返回错误),`resume`函数需要能够处理异常状态并尝试恢复设备[^1]。 --- ### 二、函数实现原理详解 #### 1. 基本流程 ```mermaid graph TD A[系统PM框架调用] --> B[USB核心层遍历设备] B --> C{是否匹配USB串口设备?} C -- 是 --> D[调用usb_serial_resume] D --> E[恢复设备特定状态] E --> F[重新提交URB请求] F --> G[清除挂起标志] G --> H[返回成功代码] ``` #### 2. 关键操作源码解析(以Linux内核为例) ```c // drivers/usb/serial/usb-serial.c int usb_serial_resume(struct usb_interface *intf) { struct usb_serial *serial = usb_get_intfdata(intf); int rv = 0; /* 1. 调用设备特定的恢复函数(如果存在) */ if (serial->type->resume) { rv = serial->type->resume(serial); if (rv < 0) { dev_err(&intf->dev, "resume error %d\n", rv); return rv; } } /* 2. 重新提交URB请求 */ for (int i = 0; i < serial->num_ports; i++) { struct usb_serial_port *port = serial->port[i]; // 清除URB的“中毒”状态,允许重新提交 usb_serial_port_unpoison_urbs(port); // 重新提交读URB(如果端口已打开) if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) usb_serial_port_resume(port); } /* 3. 清除挂起标志 */ serial->suspending = 0; return 0; } ``` #### 3. 技术要点 - **设备定制化恢复**:调用`serial->type->resume()`允许特定串口芯片(如FTDI、CP210x)实现额外的恢复逻辑,例如重新配置波特率寄存器[^1]。 - **URB重新提交**:通过`usb_serial_port_unpoison_urbs()`清除URB的“中毒”状态(在挂起时设置),使URB能够重新提交[^2]。 - **端口状态检查**:使用`test_bit(ASYNCB_INITIALIZED, ...)`确保只在已初始化的端口上重新提交URB,避免无效操作。 --- ### 三、与挂起函数的协同机制 挂起与恢复过程的对称性: | 操作阶段 | `usb_serial_suspend` | `usb_serial_resume` | |-------------------|-----------------------------------|-----------------------------------| | **设备状态** | 设置`suspending=1` | 清除`suspending=0` | | **URB管理** | `usb_serial_port_poison_urbs()` | `usb_serial_port_unpoison_urbs()`| | **设备特定逻辑** | 调用`type->suspend()` | 调用`type->resume()` | > 注:若挂起过程中`type->suspend()`失败,恢复函数需具备容错能力(如跳过部分操作)[^1]。 --- ### 四、复合设备中的恢复流程 在引用[3][^3]提到的**Legacy复合设备**(如`g_serial.ko`)中,恢复流程同样通过标准USB串口框架触发: ```c // drivers/usb/gadget/function/f_serial.c static void f_serial_resume(struct usb_function *f) { struct f_serial *serial = func_to_serial(f); /* 调用底层串口驱动的恢复逻辑 */ if (serial->serial_port->ops->resume) serial->serial_port->ops->resume(serial->serial_port); } ``` 此时`usb_serial_resume`最终仍会通过`serial->type->resume()`调用到设备特定恢复函数[^3][^5]。 --- ### 五、典型问题与调试 1. **唤醒后数据丢失** - **原因**:URB重新提交失败(如USB主机控制器未就绪) - **解决方案**:检查`usb_submit_urb()`返回值,确保端口已正确初始化 2. **调试建议** - 启用动态调试:`echo 'module usbserial +p' > /sys/kernel/debug/dynamic_debug/control` - 监控URB状态:`cat /sys/kernel/debug/usb/urbs/<device>/<endpoint>` --- §§相关问题§§ 1. USB串口设备在唤醒后如何重新建立数据传输? 2. 为什么某些USB转串口芯片需要额外的`resume`回调实现? 3. 如何验证USB串口驱动的唤醒功能是否正常工作?</think>### `usb_serial_resume` 函数功能分析 #### 一、核心作用 1. **设备状态恢复** 当系统从休眠状态唤醒时,该函数负责: - 重新激活USB串口设备 - 恢复挂起前的串口配置(如波特率、数据位等) - 重新提交URB(USB Request Block)以恢复数据传输[^1] ```c for (i = 0; i < serial->num_ports; ++i) usb_serial_port_unpoison_urbs(serial->port[i]); // 关键恢复操作 ``` 2. **与挂起函数的对称性** 作为`usb_serial_suspend`的逆操作: ```mermaid graph LR A[系统休眠] --> B[usb_serial_suspend] C[系统唤醒] --> D[usb_serial_resume] B -->|设置suspending=1| E[挂起设备] D -->|设置suspending=0| F[激活设备] ``` 3. **设备特定恢复逻辑** 通过`serial->type->resume()`回调执行芯片级恢复操作: ```c if (serial->type->resume) rv = serial->type->resume(serial); // 执行设备特定恢复 ``` 例如FTDI芯片需重新配置波特率寄存器[^1] --- #### 二、关键实现机制 ##### 1. URB生命周期管理 | 操作阶段 | 函数 | 作用 | |---------------|-------------------------------|--------------------------| | 挂起时 | `usb_serial_port_poison_urbs` | 标记URB为"中毒"状态 | | 唤醒时 | `usb_serial_port_unpoison_urbs` | 清除"中毒"标记 | | 恢复传输 | `usb_submit_urb` | 重新提交URB到USB核心[^2] ##### 2. 接口状态恢复 通过`struct usb_interface`的成员恢复设备状态: ```c struct usb_serial *serial = usb_get_intfdata(intf); // 恢复cur_altsetting指向的当前接口设置[^2][^4] struct usb_host_interface *cur = intf->cur_altsetting; ``` ##### 3. 端点描述符恢复 重新激活接口关联的端点: ```c struct usb_host_endpoint *ep = cur->endpoint; // 获取端点数组[^3] for (i = 0; i < cur->desc.bNumEndpoints; i++) { usb_enable_endpoint(ep[i]); // 激活端点 } ``` --- #### 三、复合设备处理 对于引用[3][^3][^5]提到的**Legacy复合设备**: 1. 通过`usb_function`结构体恢复功能描述符 ```c // 参考g_serial驱动实现 static struct usb_function_instance *serial_alloc_inst(void) { struct f_serial_opts *opts; opts->func_inst.set_inst_name = serial_set_inst_name; // 名称恢复 } ``` 2. 重新提交类特定描述符(如CDC ACM的`usb_cdc_header_desc`) --- #### 四、典型问题与调试 1. **唤醒失败常见原因** - 设备特定`resume()`未正确恢复寄存器 - URB重新提交时资源分配失败 - USB主机控制器未就绪 2. **调试方法** ```bash # 监控USB事件 dmesg | grep "usb.*resume" # 检查接口状态 lsusb -v -d <vid>:<pid> | grep -i interface ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值