USB学习之三 故障自恢复

来源:互联网 发布:远程桌面控制软件下载 编辑:程序博客网 时间:2024/06/06 14:24

USB支持热插拔。拔出插入之后如果文件句柄(mount和losetup)资源被释放,那么旧的设备节点会释放(sda),重新插入后会重新生成设备节点sda;而如果旧资源没被释放,那么会生成新的设备节点sdb, sdc。旧的设备节点和资源会被泄露。
usb会自恢复一些异常。但是如果USB固件出现故障,需要上下电才能恢复,linux驱动无法处理这种故障,除非对驱动进行大的整改。
USB卡如果固定插在开发板,不考虑热插拔的话,那么修改旧有的驱动,这种故障的修复变成可能。

我们考虑两种故障场景:
运行的时候USB固件跑飞了(挂死了),需要对USB固件上下电才能恢复(假设单板的EPLD固件支持对USB进行下点或者上电);
另外一种场景是USB电源线和数据线(四根线)受外界影响,出现闪断故障,导致设备断链(这样会导致旧的资源未释放,而生成新的设备)。
这两种故障场景都是标准的linux设备驱动无法处理的。
故障自恢复需要梳理初始化流程和读写流程。
先考虑第一种场景,就是读写流程
USB读写流程的关键函数是usb_stor_invoke_transport
该函数会封装qtd,内部包含CBW,DATA和CSW下发到USB控制器;触发USB控制器DMA传输。如果出现协议不可恢复故障(CRC, TIMEOUT和BAD PID),会进入Handle_Errors流程,Handle_Errors流程会复位HUB等操作,这个流程如果恢复不了,那就悲剧了。也就是说,上下电故障需要在这个流程里面添加。

usb_stor_invoke_transportHandle_Errors:    =>result = usb_stor_port_reset(us);        =>result = rc_lock = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);        =>result = usb_reset_composite_device(us->pusb_dev, us->pusb_intf);            =>ret = usb_reset_device(udev);                =>ep0_reinit(udev);                =>ret = hub_port_init(parent_hub, udev, port1, i);                    =>retval = hub_port_reset(hub, port1, udev, delay);                        =>status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_RESET);                        =>status = hub_port_wait_reset(hub, port1, udev, delay);        =>usb_unlock_device(us->pusb_dev);    =>if (result < 0)        usb_stor_report_device_reset(us);//通知上层重传        us->transport_reset(us);
原创粉丝点击