Linux那些事儿 之 戏说USB(32)驱动的生命线(四)
生活随笔
收集整理的這篇文章主要介紹了
Linux那些事儿 之 戏说USB(32)驱动的生命线(四)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
設備自從有了Address,拿到了各種描述符,就在那兒看usb_generic_driver忙活了,不過還算沒白忙,設備總算是幸福的進入Configured了。
Address有點像你合幾代人之力辛辛苦苦才弄到的一套新房子,你還得想辦法去裝修它,Configured就像是已經裝修好的,下面咱就看看usb_generic_driver又對設備做了些什么。
109行,nintf就是配置里接口的數目,那么這個for循環顯然就是在對配置里的每個接口做處理。
114行,這里要明白的是,cp里的兩個數組interface和intf_cache,一個是沒有初始化的,一個是已經動過手術很飽滿的。正像前面提到的,這里需要為interface動手術,拿intf_cache的內容去充實它。
120行,獲得這個接口的0號設置。咱們已經知道,因為某些廠商有特殊的癖好,導致了struct usb_host_config結構里的數組interface并不一定是按照接口號的順序存儲的,你必須使用usb_ifnum_to_if 來獲得指定接口號對應的struct usb_interface結構體。現在咱們需要再多知道一點,接口里的altsetting數組也不一定是按照設置編號來順序存儲的,你必須使用usb_altnum_to_altsetting()來獲得接口里的指定設置。它在drivers/usb/core/usb.c里定義()
132行,指定剛剛拿到的設置為當前要使用的設置。
133行,前邊兒遇到過device和endpoint的disable函數,這里遇到個interface的enable函數,同樣在message.c里定義
這個函數同樣也是靠一個for循環來解決問題,輪詢前面獲得的那個接口設置使用到的每個端點,調用message.c里的usb_enable_endpoint()將它們統統enable。
現在看看為什么兩個if語句里都出現有is_control。控制傳輸使用的是message管道,message管道必須對應兩個相同號碼的端點,一個用來in,一個用來out。這里使用兩個if,而不是if-else組合,目的就是塞進去一個is_control,表示只要是控制端點,就將它的端點號對應的IN和OUT兩個方向上的toggle位還有ep_int和ep_out都給初始化了。當然,所謂的控制端點一般也就是指端點0。
endpoint的enable函數要比disable函數清爽的多,disable的時候還要深入到HCD的腹地去撤銷掛在它上面的各個urb,而enable的時候就是簡單設置一下toggle位還有那兩個數組就好了,要知道它的urb隊列urb_list是早在從設備那里獲取配置描述符并去解析那一大堆數據的時候就初始化好了的。enable之后,接口里的各個端點便都處于了欣欣向榮的可用狀態,你就可以在驅動里向指定的端點提交urb了。當然,到目前這個時候接口還仍然是接口,驅動(接口驅動)還仍然是驅動,它們中間還缺少那根著名的紅線。
然后看看跟在usb_enable_interface()后面的那幾行,接口所屬的總線類型仍然為usb_bus_type,設備類型變為usb_if_device_type,dma_mask被設置為你的設備的dma_mask,而你設備的dma_mask很早以前就被設置為了host controller的dma_mask。
142行,device_initialize在初始化設備struct usb_device結構體的時候遇到過一次,這里初始化接口的時候又遇到了。
148行,for循環結束了,new_interfaces的歷史使命也就結束了。我想你應該會明白的是,這里的kfree釋放的只是new_interfaces指針數組的內存,而不包括它里面各個指針所指向的內存,至于那些數據,都已經在前面被賦給配置里的interface數組了。
179行,獲得配置的字符串描述符,怎么獲得?先飄過去把剩下的說了再說它。
194行,這個for循環結束,usb_set_configuration()的三個階段也就算結束了,設備和大美女usb_generic_driver上上下下忙活了這么久也都很累了,接下來就該接口和接口驅動去忙活了。
這個for循環將前面那個for循環準備好的每個接口送給設備模型,Linux設備模型會根據總線類型usb_bus_type將接口添加到usb總線的那條有名的設備鏈表里,然后去輪詢usb總線的另外一條有名的驅動鏈表,針對每個找到的驅動去調用usb總線的match函數,也就是usb_device_match,去為接口尋找另一個匹配的半圓。你說這個時候設備和接口兩條路它應該走哪條?它的類型已經設置成usb_if_device_type了,設備那條路把門兒的根本就不會讓它進,所以它必須得去走接口那條路。
Address有點像你合幾代人之力辛辛苦苦才弄到的一套新房子,你還得想辦法去裝修它,Configured就像是已經裝修好的,下面咱就看看usb_generic_driver又對設備做了些什么。
109行,nintf就是配置里接口的數目,那么這個for循環顯然就是在對配置里的每個接口做處理。
114行,這里要明白的是,cp里的兩個數組interface和intf_cache,一個是沒有初始化的,一個是已經動過手術很飽滿的。正像前面提到的,這里需要為interface動手術,拿intf_cache的內容去充實它。
120行,獲得這個接口的0號設置。咱們已經知道,因為某些廠商有特殊的癖好,導致了struct usb_host_config結構里的數組interface并不一定是按照接口號的順序存儲的,你必須使用usb_ifnum_to_if 來獲得指定接口號對應的struct usb_interface結構體。現在咱們需要再多知道一點,接口里的altsetting數組也不一定是按照設置編號來順序存儲的,你必須使用usb_altnum_to_altsetting()來獲得接口里的指定設置。它在drivers/usb/core/usb.c里定義()
struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,unsigned int altnum)
{int i;for (i = 0; i < intf->num_altsetting; i++) {if (intf->altsetting[i].desc.bAlternateSetting == altnum)return &intf->altsetting[i];}return NULL;
}這個函數依靠一個for循環來解決問題,就是輪詢接口里的每個設置,比較它們的編號與你指定的編號是不是一樣。原理簡單,操作也簡單,有點不簡單的是前面調用它的時候為什么指定編號0,也就是獲得0號設置。這還要歸咎于spec里說了這么一句,接口的默認設置總是0號設置,所以這里的目的就是獲得接口的默認設置,如果沒有拿到設置0,接下來就在128行拿altsetting數組里的第一項來充數。
132行,指定剛剛拿到的設置為當前要使用的設置。
133行,前邊兒遇到過device和endpoint的disable函數,這里遇到個interface的enable函數,同樣在message.c里定義
這個函數同樣也是靠一個for循環來解決問題,輪詢前面獲得的那個接口設置使用到的每個端點,調用message.c里的usb_enable_endpoint()將它們統統enable。
void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep,bool reset_ep)
{int epnum = usb_endpoint_num(&ep->desc);int is_out = usb_endpoint_dir_out(&ep->desc);int is_control = usb_endpoint_xfer_control(&ep->desc);if (reset_ep)usb_hcd_reset_endpoint(dev, ep);if (is_out || is_control)dev->ep_out[epnum] = ep;if (!is_out || is_control)dev->ep_in[epnum] = ep;ep->enabled = 1;
}這個函數的前邊兒幾行沒什么好說的,分別獲得端點地址,端點號,還有是不是控制端點。稍微有那么點嚼頭兒的是后面的兩個if,它們分別根據端點的方向來初始化設備的ep_in和ep_out數組。
現在看看為什么兩個if語句里都出現有is_control。控制傳輸使用的是message管道,message管道必須對應兩個相同號碼的端點,一個用來in,一個用來out。這里使用兩個if,而不是if-else組合,目的就是塞進去一個is_control,表示只要是控制端點,就將它的端點號對應的IN和OUT兩個方向上的toggle位還有ep_int和ep_out都給初始化了。當然,所謂的控制端點一般也就是指端點0。
endpoint的enable函數要比disable函數清爽的多,disable的時候還要深入到HCD的腹地去撤銷掛在它上面的各個urb,而enable的時候就是簡單設置一下toggle位還有那兩個數組就好了,要知道它的urb隊列urb_list是早在從設備那里獲取配置描述符并去解析那一大堆數據的時候就初始化好了的。enable之后,接口里的各個端點便都處于了欣欣向榮的可用狀態,你就可以在驅動里向指定的端點提交urb了。當然,到目前這個時候接口還仍然是接口,驅動(接口驅動)還仍然是驅動,它們中間還缺少那根著名的紅線。
然后看看跟在usb_enable_interface()后面的那幾行,接口所屬的總線類型仍然為usb_bus_type,設備類型變為usb_if_device_type,dma_mask被設置為你的設備的dma_mask,而你設備的dma_mask很早以前就被設置為了host controller的dma_mask。
142行,device_initialize在初始化設備struct usb_device結構體的時候遇到過一次,這里初始化接口的時候又遇到了。
148行,for循環結束了,new_interfaces的歷史使命也就結束了。我想你應該會明白的是,這里的kfree釋放的只是new_interfaces指針數組的內存,而不包括它里面各個指針所指向的內存,至于那些數據,都已經在前面被賦給配置里的interface數組了。
179行,獲得配置的字符串描述符,怎么獲得?先飄過去把剩下的說了再說它。
194行,這個for循環結束,usb_set_configuration()的三個階段也就算結束了,設備和大美女usb_generic_driver上上下下忙活了這么久也都很累了,接下來就該接口和接口驅動去忙活了。
這個for循環將前面那個for循環準備好的每個接口送給設備模型,Linux設備模型會根據總線類型usb_bus_type將接口添加到usb總線的那條有名的設備鏈表里,然后去輪詢usb總線的另外一條有名的驅動鏈表,針對每個找到的驅動去調用usb總線的match函數,也就是usb_device_match,去為接口尋找另一個匹配的半圓。你說這個時候設備和接口兩條路它應該走哪條?它的類型已經設置成usb_if_device_type了,設備那條路把門兒的根本就不會讓它進,所以它必須得去走接口那條路。
總結
以上是生活随笔為你收集整理的Linux那些事儿 之 戏说USB(32)驱动的生命线(四)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux那些事儿 之 戏说USB(31
- 下一篇: Linux那些事儿 之 戏说USB(33