Linux裝置驅動子系統終極彈 – USB

來源:互聯網
上載者:User

0. 預備理論

1. USB Core

2. USB Hub

3. USB OTG

4. USB Host

5. USB Gadget

6. USB Mass Storage

USB博大精深,不是一兩篇博文能夠解釋清楚的。想要深入研究USB的話,USB協議(外加Host和OTG協議)是必要的知識,另外,國內有本fudan_abc的<<USB那些事>>也寫的很好很詳細,唯一美中不足的就是寫得太詳細了反而感覺思路架構不是很清晰了,本人學識還淺,想簡單地把USB在Linux裡的結構架構大致整理下,其中重點解析下USB Core和Hub。

0. 預備理論

說實話,讀USB2.0協議還是蠻痛苦的,它僅僅是一個協議,一個在USB世界裡制定的遊戲規則,就像法律條文一樣,它並不是為了學習者而寫的,可讀性很差。這裡總結以下幾個重點基本點。

0.1 拓撲結構 (ch4.1.1)

 

 

  • 之所以要規定這個樹形拓撲結構是為了避免環形串連。
  • 一條USB匯流排有且只有一個USB Host,對應一個RootHub
  • USB裝置分為兩類,Hub和Functions,Hub通過連接埠Port串連更多USB裝置,Functions即USB外接從裝置。
  • 層次最多7層,且第7層不能有Hub,只能有functions。
  • Compound Device - 一個Hub上接多個裝置群組成一個小裝置。
  • Composite Device - 一個USB外接裝置具有多個複用功能。

0.2 機械效能 (ch5)

  • 串連件connector,就是裝置上的那個串連口。
  • 插頭plug,就是USB電纜線兩頭的插口。
  • Mini-AB, Micro-AB指的是支援A和B兩類插頭的串連件。

0.3 電氣效能 (ch6)

  • VBUS  -  +5V電源供電。
  • D+ D- -  用於資料轉送的電纜線。
  • 低速 low-speed  10-100Kb/s      應用於滑鼠和鍵盤等
  • 全速 full-speed   500Kb-10Mb/s 應用於音頻和麥克等
  • 高速 high-speed 25-400Mb/s     應用於儲存和視頻等  (USB3.0比之塊10倍)

 0.4 四大描述符 (ch9.5)

  協議規定了USB的四個描述符descriptor - 裝置device,配置configure,介面interface,端點endpoint。

  終端下輸入命令  # ls /sys/bus/usb/devices

    usb1
    1-0:1.0
    usb2
    2-0:1.0   // USB匯流排(RootHub) No.2,USB port連接埠號碼No.0,配置號No.1,介面號No.0。

  • 區別port和endpoint,port之於hub,endpoint是每個USB裝置用於資料轉送所必需的端點。
  • 裝置device>配置configure>介面interface>設定setting>端點endpoint。
  • 裝置可以有多個配置,配置可以有一個或多個介面,介面可以有一個或多個設定。
  • 一個介面對應一個驅動,介面是端點的集合。

  0.5 啟動流程 (ch9.1,9.2)

 

  • attached->powered->default->address->configured
  • 啟動流程與其他裝置比如SD卡相比,最大的不同在於Hub,主機Host通過Hub狀態的變化判斷USB外接裝置的有無。
  • USB外接裝置插入和拔出整個實現過程稱為匯流排枚舉Bus Enumeration。

   0.6 資料流傳輸 (ch5)

  • endpoint分零端點和非零端點,零端點作為預設的控制方法用於初始化和操控USB邏輯裝置。
  • 資料流傳輸分 control/bulk/interrupt/isochronous data transfer。

 0.7 資料包 (ch8)

  • 資料包分Token, Data, Handshake, Special,四種包有自己的資料群組織方式。
  • Token令牌包只能由主機傳送給裝置,分IN, OUT, SOF和SETUP。
  • SETUP包實現主機向裝置發出的請求request,也要滿足特定的格式。(ch9.3,9.4)

1. USB Core

   先囉嗦幾句,回答一個困擾我很久的問題,讀Linux源碼究竟要讀到什麼程度?這是個永恒的話題,每個同道中人都有自己的看法。以筆者之見,如何閱讀源碼主要取決於自己的職業定位,是研發還是開發,是為Linux社區作貢獻還是用已有的方案開發?我想大多數驅動工程師屬於後者,那麼,面對已經很完善的核心層源碼,還有必要看嗎,或者有必要去深入研究嗎?我認為既然我們已經站在了巨人的肩膀上,至少要知道這寬闊的肩膀是如何煉成的,它所存在的價值以及如何去使用它。

  既然如此,那USB核心層到底是什麼,它都默默地做了些什麼,我們要如何使用它?這裡主要有兩個重點,USB匯流排和urb。

1.1 USB子系統結構

協議裡說,HCD提供主控制器驅動的硬體抽象,它只對USB Core一個負責,USB Core將使用者的請求映射到相關的HCD,使用者不能直接存取HCD。換句話說,USB Core就是HCD與USB裝置唯一的橋樑。

1.2 USB子系統的初始化

USB core源碼位於./drivers/usb/core,其中的Makefile摘要如下,

usbcore這個模組代表的不是某一個裝置,而是所有USB裝置賴以生存的模組,它就是USB子系統。

./drivers/usb/core/usb.c裡實現了初始化,虛擬碼如下,

usbcore註冊了USB匯流排,USB檔案系統,USB Hub以及USB的裝置驅動usb generic driver等。

1.3 USB匯流排

  註冊USB匯流排通過bus_register(&usb_bus_type);

struct bus_type usb_bus_type = {
 .name =  "usb",
 .match = usb_device_match,   // 這是個很重要的函數,用來匹配USB裝置和驅動。
 .uevent = usb_uevent,
 .pm =  &usb_bus_pm_ops,
};
下面總結下USB裝置和驅動匹配的全過程,

-> step 1 - usb device driver

USB子系統初始化的時候就會註冊usb_generic_driver, 它的結構體類型是usb_device_driver,它是USB世界裡唯一的一個USB裝置驅動,區別於struct usb_driver USB驅動。

  • USB裝置驅動(usb device driver)就只有一個,即usb_generice_driver這個對象,所有USB裝置都要綁定到usb_generic_driver上,它的使命可以概括為:為USB裝置選擇一個合適的配置,讓裝置進入configured狀態。
  • USB驅動(usb driver)就是USB裝置的介面驅動程式,比如adb驅動程式,u盤驅動程式,滑鼠驅動程式等等。

-> step 2 - usb driver

 

 Linux啟動時註冊USB驅動,在xxx_init()裡通過usb_register()將USB驅動提交個裝置模型,添加到USB匯流排的驅動鏈表裡。

 -> step 3 - usb device

USB裝置串連在Hub上,Hub檢測到有裝置串連進來,為裝置分配一個struct usb_device結構體對象,並將裝置添加到USB匯流排的裝置列表裡。

  -> step 4 - usb interface

 

 USB裝置各個配置的詳細資料在USB core裡的漫漫旅途中已經被擷取並存放在相關的幾個成員裡。

 usb_generic_driver得到了USB裝置的詳細資料,然後把準備好的介面送給裝置模型,Linux裝置模型將介面添加到裝置鏈表裡,然後去輪詢USB匯流排另外一條驅動鏈表,針對每個找到的驅動去調用USB匯流排的match函數,完成匹配。

 1.4 USB Request Block (urb)

 USB主機與裝置間的通訊以資料包(packet)的形式傳遞,Linux的思想就是把這些遵循協議的資料都封裝成資料區塊(block)作統一調度,USB的資料區塊就是urb,結構體struct urb,定義在<linux/usb.h>,其中的成員unsigned char *setup_packet指標指向SETUP資料包。下面總結下使用urb完成一次完整的USB通訊需要經曆的過程,

-> step 1 - usb_alloc_urb()

建立urb,並指定USB裝置的目的端點。

-> step 2 - usb_control_msg()

將urb提交給USB core, USB core將它交給HCD主機控制器驅動。

-> step 3 - usb_parse_configuration()

HCD解析urb,拿到資料與USB裝置通訊。

-> step 4

HCD把urb的所有權交還給驅動程式。

協議層裡最重要的函數就是usb_control/bulk/interrupt_msg(),這裡就簡單地理一條線索,

usb_control_msg() => usb_internal_control_msg() => usb_start_wait_urb() => usb_submit_urb() => usb_hcd_submit_urb => hcd->driver->urb_enqueue() HCD主控制器驅動根據具體平台實現USB資料通訊。

 2. USB Hub

 Hub集線器用來串連更多USB裝置,硬體上實現了USB裝置的匯流排枚舉過程,軟體上實現了USB裝置與介面在USB匯流排上的匹配。

 下面總結下USB Hub在Linux USB核心層裡的實現機制,

 USB子系統初始化時,usb_hub_init()開啟一個名為"khubd"的核心線程,

核心線程khubd從Linux啟動後就自始至終為USB Hub服務,沒有Hub事件時khubd進入睡眠,有USB Hub事件觸發時將會經由hud_irq() => hub_activate() => kick_khubd() 最終喚醒khubd,將事件加入hub_event_list列表,並執行hub_events()。hub_events()會不停地輪詢hub_events_list列表去完成hub觸發的事件,直到這個列表為空白時退出結束,回到wait_event_xxx繼續等待。

處理hub事件的全過程大致可分為兩步,

  • 第一步 判斷連接埠狀態的變化

通過hub_port_status()得到hub連接埠的狀態。

源碼裡類似像hub_port_status(), hub_hub_status()等功能函數,都調用了核心層的usb_control_msg()去實現主控制器與USB裝置間的通訊。

  • 第二步 處理連接埠的變化

hub_port_connect_change()是核心函數,以連接埠發現有新的USB裝置插入為例,USB Hub為USB裝置做了以下幾步重要的工作,注意這裡所謂的USB裝置是指插入USB Hub的外接USB裝置(包括Hub和Functions),接下來Hub都在為USB裝置服務。

1) usb_alloc_dev() 為USB裝置申請一個sturct usb_device結構。

2) usb_set_device_state() 設定USB裝置狀態為上電狀態。(硬體上裝置已進入powered狀態)。

3) choose_address() 為USB裝置選擇一個地址,利用一個輪詢演算法為裝置從0-127裡選擇一個地址號。

4) hub_port_init() 連接埠初始化,實質就是擷取裝置描述符device descriptor。

5) usb_get_status() 這個有點特殊,它是專門給Hub又外接Hub而準備的。

6) usb_new_device() 這時USB裝置已經進入了Configured狀態,調用device_add()在USB匯流排上尋找驅動,若匹配成功,則載入對應的驅動程式。

 

3. USB OTG

  引入OTG的概念是為了讓裝置可以充當主從兩個角色,主裝置即HCD,從裝置即UDC,也就是Gadget。這裡就簡單梳理下協議和源碼。

3.1 協議

1) Protocol

 OTG的傳輸協議有三類 - ADP,SRP,HNP。

  • ADP(Attach Detection Protocol) 當USB匯流排上沒有供電時,ADP允許OTG裝置或USB裝置決定串連狀態。
  • SRP(Session Request Protocol) 允許從裝置也可以控制主裝置。
  • HNP(Host Negotiation Protocol) 允許兩個裝置互換主從角色。 

2) Device role

  協議定義兩種角色,OTG A-device和OTG B-device,A-device為電源提供者,B-device為電源消費者,預設配置下,A-device作為主裝置,B-device作為從裝置,之後可以通過HNP互換。

3) OTG micro plug

  協議上說"An OTG product must have a single Micro-AB receptacle and no other USB receptacles."這句話有點問題。。。應該還包括mini-AB receptacle,以下所有micro都可以是mini。

  OTG電纜一端為micro-A plug,另一端為micro-B plug。

  OTG加了第5個pin腳,名為ID-pin,micro-A plug的ID-pin接地,micro-B plug的ID-pin懸空。

  OTG裝置被接上micro-A plug後被稱為micro-A device,被接上micro-B plug後被稱為micro-B device。

3.2 源碼淺析

  OTG控制器整合在CPU內,Linux下的源碼驅動由各家開發平台提供,位於./drivers/usb/otg/下。

  以Freescale平台為例,主要的思路就是,當有OTG線插入OTG裝置時產生中斷,中斷處理函數上半部通過讀取OTG控制器寄存器相應值判斷OTG裝置屬於Host(HCD)還是Gadget(UDC),下半部通過工作隊列由回呼函數類似host->resume()或gadget->resume()重啟Host或Gadget控制器,resume()具體的實現過程在HCD或UDC相關驅動裡實現。

 

4. USB Host

  USB主控制器(HCD)同樣整合在CPU內,由開發平台廠商提供驅動,源碼位於./drivers/usb/host/下。

  主控制器主要有四類:EHCI, FHCI, OHCI, UHCI, 它們各自的寄存器介面協議不同,嵌入式裝置多為EHCI。

  該驅動的結構體類型為struct hc_driver,其中的成員(*urb_enqueue)最為重要,它是主控制器HCD將資料包urb傳向USB裝置的核心實現函數,之前已經提到,協議層裡最主要的函數usb_control_msg()最終就會回調主控制器的(*urb_enqueue)。

usb_control_msg() => usb_internal_control_msg() => usb_start_wait_urb() => usb_submit_urb() => usb_hcd_submit_urb => hcd->driver->urb_enqueue()

 

5. USB Gadget

  當年寫過一篇Gadget...http://blog.csdn.net/qianjin0703/archive/2011/01/15/6141763.aspx

  Gadget源碼位於./drivers/usb/gadget/下,涉及的驅動程式和資料結構相對較多。

  驅動主要有,

  • 平台相關的Gadget控制器驅動
  • 平台無關的複用裝置驅動composite.c
  • android平台的複用裝置驅動android.c
  • adb驅動f_adb.c,隨身碟驅動f_mass_storage.c等一些複用的USB驅動

  資料結構主要有,

  • struct usb_gadget 裡面主要有(*ops)和struct usb_ep *ep0。
  • struct usb_gadget_driver 其中的(*bind)綁定複用裝置驅動,(*setup)完成USB枚舉操作。
  • struct usb_compostie_driver 其中的(*bind)綁定比如android複用裝置驅動。
  • struct usb_request USB資料請求包,類似urb。
  • struct usb_configuration 就是這個gadget裝置具有的配置,其中的struct usb_function *interface[]數組記錄著它所擁有的USB介面/功能/驅動。
  • struct usb_function 其中的(*bind)綁定相關的USB介面,(*setup)完成USB枚舉操作。

  整體架構可概括為,(mv_gadget為gadget控制器的資料)

 

6. USB Mass Storage

  全世界只有一個Linux 隨身碟驅動,位於./drivers/usb/storage/usb.c,虛擬碼如下,這裡需要注意的是,在進行隨身碟驅動的初始化probe之前,USB core和hub已經對這個隨身碟做了兩大工作,即

1) 完成了USB裝置的枚舉,此時隨身碟已經進入configured狀態,隨身碟資料存放在struct usb_interface。

2) 完成了USB匯流排上裝置和驅動的匹配,這時匯流排上已經找到了介面對應的驅動即隨身碟驅動。

  • 土黃色部分由SCSI子系統封裝實現最終的隨身碟驅動註冊。
  • usb_stor_scan_thread 掃描隨身碟的線程,等待5秒,如果5秒內不拔出就由SCSI進行全盤掃描,
  • usb_stor_contro_thread 一個核心的線程,具體參看《USB那些事》...

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.