安装好 gadget 驱动程序后(比如 modprobe g_zero), 它只是构造好了各类描述符。在设备的枚举过程会读取描述符。
使用 OTG 线连接电脑和开发板时,电脑软件会执行如下操作:
上述过程里,设备方都是接收到 Host 发给 endpoint 0 的数据,然后做出回应。不同的 Gadget 设备,在返回描述符给主机时,这些操作都是一样的,只是回应的数据不同而已。源码分析的起点都是某个中断函数:
IMX6ULL 芯片中 USB 控制器型号是 chipidea,在Linux-4.9.88driversusbchipideacore.c
中注册了中断函数:
ci_hdrc_probe
ret = devm_request_irq(dev, ci- >irq, ci_irq, IRQF_SHARED,
ci- >platdata- >name, ci);
发生中断后,对于 endpoint 0 的数据处理流程如下:
// Linux-4.9.88driversusbchipideacore.c
ci_irq
/* Handle device/host interrupt */
if (ci- >role != CI_ROLE_END)
ret = ci_role(ci)- >irq(ci); // udc_irq
// Linux-4.9.88driversusbchipideaudc.c
udc_irq
if (USBi_UI & intr)
// Linux-4.9.88driversusbchipideaudc.c
isr_tr_complete_handler(ci);
/* Only handle setup packet below */
if (i == 0 &&
hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(0)))
// Linux-4.9.88driversusbchipideaudc.c
isr_setup_packet_handler(ci);
函数isr_setup_packet_handler
就是处理 endpoint 0 接收到的控制传输的关键。
STM32MP157 芯片中 USB 控制器型号是 dwc2,在Linux-5.4driversusbdwc2gadget.c
中注册了中断函数:
dwc2_gadget_init
ret = devm_request_irq(hsotg- >dev, hsotg- >irq, dwc2_hsotg_irq,
IRQF_SHARED, dev_name(hsotg- >dev), hsotg);
发生中断后,函数dwc2_hsotg_irq
被调用,它处理 endpoint 中断有两种方法:
dwc2_hsotg_epint
来处理dwc2_hsotg_handle_rx
来处理以dwc2_hsotg_epint
为例进行分析,对于 endpoint 0 的数据处理流程如下:
// Linux-5.4driversusbdwc2gadget.c
dwc2_hsotg_irq
// 处理endpoint中断
for (ep = 0; ep < hsotg- >num_of_eps && daint_out; ep++, daint_out > >= 1) {
if (daint_out & 1)
dwc2_hsotg_epint(hsotg, ep, 0);
}
for (ep = 0; ep < hsotg- >num_of_eps && daint_in; ep++, daint_in > >= 1) {
if (daint_in & 1)
dwc2_hsotg_epint(hsotg, ep, 1);
}
函数dwc2_hsotg_epint
中,对于 endpoint 0 的处理如下:
// Linux-5.4driversusbdwc2gadget.c
dwc2_hsotg_epint
if (idx == 0 && !hs_ep- >req)
dwc2_hsotg_enqueue_setup(hsotg);
函数dwc2_hsotg_enqueue_setup
被调用时,Gadget 设备已经收到了 SETUP 令牌包,但是还没收到 DATA0 令牌包。dwc2_hsotg_enqueue_setup
的作用是,设置、启动一个 request,核心在于设置了 request 的 complete 函数(当 SETTUP 事务完成后这个函数被调用):
当控制传输的"setup事务"完成时,函数dwc2_hsotg_complete_setup
被调用。
无论是 MX6ULL 的函数isr_setup_packet_handler
,还是 STM32M157 的函数dwc2_hsotg_complete_setup
,它们都是在 Gadget 设备收到"SETUP事务"后才被调用。接收完"SETUP事务"后,就可以从里面知道这个控制传输想做什么(req.bRequest 是什么),然后就可以处理它了。
怎么处理呢?可以分为 3 层:
USB_REQ_SET_ADDRESS
USB_REQ_SET_FEATURE // 有一些请求可能需要上报改 gadget driver
USB_REQ_CLEAR_FEATURE // 有一些请求可能需要上报改 gadget driver
USB_REQ_GET_STATUS // 有一些请求可能需要上报改 gadget driver
IMX6ULL: Linux-4.9.88driversusbchipideaudc.c, 函数 isr_setup_packet_handler
STM32MP157: Linux-5.4driversusbdwc2gadget.c, 函数 dwc2_hsotg_complete_setup
USB_REQ_GET_DESCRIPTOR
USB_REQ_SET_CONFIGURATION
USB_REQ_GET_CONFIGURATION
USB_REQ_SET_INTERFACE
USB_REQ_GET_INTERFACE
USB_REQ_GET_STATUS // 底层 UDC 驱动无法处理的话, gadget driver 来处理
USB_REQ_CLEAR_FEATURE // 底层 UDC 驱动无法处理的话, gadget driver 来处理
USB_REQ_SET_FEATURE // 底层 UDC 驱动无法处理的话, gadget driver 来处理
文件:driversusbgadgetcomposite.c
函数:composite_setup
全部0条评论
快来发表一下你的评论吧 !