安裝好 gadget 驅(qū)動(dòng)程序后(比如 modprobe g_zero), 它只是構(gòu)造好了各類描述符。在設(shè)備的枚舉過程會(huì)讀取描述符。
使用 OTG 線連接電腦和開發(fā)板時(shí),電腦軟件會(huì)執(zhí)行如下操作:
- 使用控制傳輸,讀取設(shè)備信息(設(shè)備描述符):第一次讀取時(shí),它只需要得到 8 字節(jié)數(shù)據(jù),因?yàn)榈?8 個(gè)數(shù)據(jù)表示端點(diǎn) 0 能傳輸?shù)淖畲髷?shù)據(jù)長度。
- Host 分配地址給設(shè)備,然后把新地址發(fā)給設(shè)備。
- 使用新地址,重新讀取設(shè)備描述符,設(shè)備描述符長度是 18
- 讀取配置描述符:它傳入的長度是 255,想一次性把當(dāng)前配置描述符、它下面的接口描述符、端點(diǎn)描述符全部讀出來。
- 讀取字符描述符。
上述過程里,設(shè)備方都是接收到 Host 發(fā)給 endpoint 0 的數(shù)據(jù),然后做出回應(yīng)。不同的 Gadget 設(shè)備,在返回描述符給主機(jī)時(shí),這些操作都是一樣的,只是回應(yīng)的數(shù)據(jù)不同而已。源碼分析的起點(diǎn)都是某個(gè)中斷函數(shù):
4.1 IMX6ULL 的核心函數(shù)
IMX6ULL 芯片中 USB 控制器型號(hào)是 chipidea,在Linux-4.9.88driversusbchipideacore.c
中注冊(cè)了中斷函數(shù):
ci_hdrc_probe
ret = devm_request_irq(dev, ci- >irq, ci_irq, IRQF_SHARED,
ci- >platdata- >name, ci);
發(fā)生中斷后,對(duì)于 endpoint 0 的數(shù)據(jù)處理流程如下:
// 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);
函數(shù)isr_setup_packet_handler
就是處理 endpoint 0 接收到的控制傳輸?shù)年P(guān)鍵。
4.2 STM32MP157的核心函數(shù)
STM32MP157 芯片中 USB 控制器型號(hào)是 dwc2,在Linux-5.4driversusbdwc2gadget.c
中注冊(cè)了中斷函數(shù):
dwc2_gadget_init
ret = devm_request_irq(hsotg- >dev, hsotg- >irq, dwc2_hsotg_irq,
IRQF_SHARED, dev_name(hsotg- >dev), hsotg);
發(fā)生中斷后,函數(shù)dwc2_hsotg_irq
被調(diào)用,它處理 endpoint 中斷有兩種方法:
- 使用 DMA 時(shí):調(diào)用
dwc2_hsotg_epint
來處理 - 不使用 DMA 時(shí):調(diào)用
dwc2_hsotg_handle_rx
來處理
以dwc2_hsotg_epint
為例進(jìn)行分析,對(duì)于 endpoint 0 的數(shù)據(jù)處理流程如下:
// 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);
}
函數(shù)dwc2_hsotg_epint
中,對(duì)于 endpoint 0 的處理如下:
// Linux-5.4driversusbdwc2gadget.c
dwc2_hsotg_epint
if (idx == 0 && !hs_ep- >req)
dwc2_hsotg_enqueue_setup(hsotg);
函數(shù)dwc2_hsotg_enqueue_setup
被調(diào)用時(shí),Gadget 設(shè)備已經(jīng)收到了 SETUP 令牌包,但是還沒收到 DATA0 令牌包。dwc2_hsotg_enqueue_setup
的作用是,設(shè)置、啟動(dòng)一個(gè) request,核心在于設(shè)置了 request 的 complete 函數(shù)(當(dāng) SETTUP 事務(wù)完成后這個(gè)函數(shù)被調(diào)用):
當(dāng)控制傳輸?shù)?setup事務(wù)"完成時(shí),函數(shù)dwc2_hsotg_complete_setup
被調(diào)用。
4.3 如何處理控制傳輸
無論是 MX6ULL 的函數(shù)isr_setup_packet_handler
,還是 STM32M157 的函數(shù)dwc2_hsotg_complete_setup
,它們都是在 Gadget 設(shè)備收到"SETUP事務(wù)"后才被調(diào)用。接收完"SETUP事務(wù)"后,就可以從里面知道這個(gè)控制傳輸想做什么(req.bRequest 是什么),然后就可以處理它了。
怎么處理呢?可以分為 3 層:
- UDC 驅(qū)動(dòng)程序:類似"設(shè)置地址"的控制傳輸,在底層的 UDC 驅(qū)動(dòng)程序里就可以處理,
- 這類請(qǐng)求有:
USB_REQ_SET_ADDRESS USB_REQ_SET_FEATURE // 有一些請(qǐng)求可能需要上報(bào)改 gadget driver USB_REQ_CLEAR_FEATURE // 有一些請(qǐng)求可能需要上報(bào)改 gadget driver USB_REQ_GET_STATUS // 有一些請(qǐng)求可能需要上報(bào)改 gadget driver
- 驅(qū)動(dòng)程序位置
IMX6ULL: Linux-4.9.88driversusbchipideaudc.c, 函數(shù) isr_setup_packet_handler STM32MP157: Linux-5.4driversusbdwc2gadget.c, 函數(shù) dwc2_hsotg_complete_setup
- 這類請(qǐng)求有:
- gadget driver:涉及描述符的操作
- 這類請(qǐng)求有:
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 驅(qū)動(dòng)無法處理的話, gadget driver 來處理 USB_REQ_CLEAR_FEATURE // 底層 UDC 驅(qū)動(dòng)無法處理的話, gadget driver 來處理 USB_REQ_SET_FEATURE // 底層 UDC 驅(qū)動(dòng)無法處理的話, gadget driver 來處理
- 驅(qū)動(dòng)程序位置
文件:driversusbgadgetcomposite.c 函數(shù):composite_setup
- 這類請(qǐng)求有:
- usb_configuration 或 usb_function 的處理:這是二選一的。大部分設(shè)備使用控制傳輸實(shí)現(xiàn)標(biāo)準(zhǔn)的 USB 請(qǐng)求,但是也可以用控制傳輸來進(jìn)行實(shí)現(xiàn)相關(guān)的請(qǐng)求,對(duì)于這些非標(biāo)準(zhǔn)的請(qǐng)求,就需要上層驅(qū)動(dòng)來處理。
-
嵌入式
+關(guān)注
關(guān)注
5087文章
19145瀏覽量
306136 -
Linux
+關(guān)注
關(guān)注
87文章
11320瀏覽量
209851 -
框架
+關(guān)注
關(guān)注
0文章
403瀏覽量
17511
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論