1. 程式人生 > >Linux那些事兒之我是Hub(17)八大重量級函式閃亮登場(一)

Linux那些事兒之我是Hub(17)八大重量級函式閃亮登場(一)

還有人記得1996年那部史詩般的電視劇<<英雄無悔>>?那年我初二.這部戲讓我認識了濮存昕,也是這部戲確立了濮存昕少婦殺手的地位,後來大肆那年濮存昕去過復旦,宣傳艾滋病方面的知識,儘管那時候我正在求職的路上遭遇種種挫折,但還是抽出了時間去五教看了聽了他的講座,完了之後他還即興了一段朗誦.我覺得他身上那種健康的形象是我喜歡的,因為這種積極向上的東西我太缺了.

<<英雄無悔>>裡面濮存昕扮演的公安局長高天有一句最經典的話:世上註定會有撐船人和坐船人,而他應該是那個執著的撐船仔.其實hubusb世界裡扮演的又何嘗不是這種角色呢?我們來看這個迴圈,

這是Hub驅動中最核心的程式碼,然而這段程式碼卻自始至終是在為別的裝置服務.

在這個迴圈中,主要涉及這麼八個重量級函式,先點明它們的角色分工.

第一個函式,usb_alloc_dev(),為一個struct usb_device結構體指標,申請記憶體,這個結構體指標可不是為hub準備的,它正是為了hub這個埠所接的裝置而申請的,別忘了我們此時此刻的上下文,之所以進入到了這個迴圈,是因為我們的Hub檢測到某個埠有裝置連線了進來,所以我們作為Hub驅動當然就義不容辭的要為該裝置做點什麼.

第二個函式,usb_set_device_state(),這個函式用來設定裝置的狀態,struct usb_device

結構體中,有一個成員,enum usb_device_state state,這一刻,會把這個裝置的狀態設定為USB_STATE_POWERED,即上電狀態.

第三個函式,choose_address(),為裝置選擇一個地址.一會咱們會用例項來看看效果.

第四個函式,hub_port_init(),不多說了,這個就是埠初始化,主要就是前面說的獲取裝置的描述符.

第五個函式,usb_get_status(),這個函式是專門為hub準備的,不是為當前的這個hub,而是說當前hub的這個埠上連線的如果又是hub,那麼和連線普通裝置當然不一樣.

第六個函式,check_highspeed(),

不同速度的裝置當然待遇不一樣.

第七個函式,usb_new_device().尋找驅動程式,呼叫驅動程式的probe,跟蹤這個函式就能一直跟蹤到裝置驅動程式的probe()函式的呼叫.

第八個函式,hub_power_remaining(),別忘了,電源管理將是hub驅動永恆的話題.

Ok,下面就讓我們來認真的逐個看一看這八大函式.

usb_alloc_dev(),drivers/usb/core/usb.c:

226 /**

227* usb_alloc_dev - usb device constructor (usbcore-internal)

228* @parent: hub to which device is connected; null to allocate a root hub

229* @bus: bus used to access the device

230* @port1: one-based index of port; ignored for root hubs

231* Context: !in_interrupt()

232*

233* Only hub drivers (including virtual root hub drivers for host

234* controllers) should ever call this.

235*

236* This call may not be used in a non-sleeping context.

237*/

238 struct usb_device *

239 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)

240 {

241struct usb_device *dev;

242

243 dev = kzalloc(sizeof(*dev), GFP_KERNEL);

244if (!dev)

245return NULL;

246

247if (!usb_get_hcd(bus_to_hcd(bus))) {

248kfree(dev);

249return NULL;

250}

251

252device_initialize(&dev->dev);

253dev->dev.bus = &usb_bus_type;

254dev->dev.type = &usb_device_type;

255dev->dev.dma_mask = bus->controller->dma_mask;

256dev->state = USB_STATE_ATTACHED;

257

258INIT_LIST_HEAD(&dev->ep0.urb_list);

259dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;

260dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;

261/* ep0 maxpacket comes later, from device descriptor */

262dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;

263

264/* Save readable and stable topology id, distinguishing devices

265* by location for diagnostics, tools, driver model, etc.The

266* string is a path along hub ports, from the root.Each device's

267* dev->devpath will be stable until USB is re-cabled, and hubs

268* are often labeled with these port numbers.The bus_id isn't

269* as stable:bus->busnum changes easily from modprobe order,

270* cardbus or pci hotplugging, and so on.

271*/

272if (unlikely(!parent)) {

273dev->devpath[0] = '0';

274

275dev->dev.parent = bus->controller;

276sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);

277} else {

278/* match any labeling on the hubs; it's one-based */

279if (parent->devpath[0] == '0')

280snprintf(dev->devpath, sizeof dev->devpath,

281"%d", port1);

282else

283snprintf(dev->devpath, sizeof dev->devpath,

284"%s.%d", parent->devpath, port1);

285

286dev->dev.parent = &parent->dev;

287sprintf(&dev->dev.bus_id[0], "%d-%s",

288bus->busnum, dev->devpath);

289

290/* hub driver sets up TT records */

291}

292

293dev->portnum = port1;

294dev->bus = bus;

295dev->parent = parent;

296INIT_LIST_HEAD(&dev->filelist);

297

298 #ifdefCONFIG_PM

299mutex_init(&dev->pm_mutex);

300INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);

301dev->autosuspend_delay = usb_autosuspend_delay * HZ;

302 #endif

303return dev;

304 }

首先是申請記憶體,申請一個struct usb_device結構體指標的記憶體,這個指標就是dev,bus就是匯流排,這裡傳遞進來的兩個實參我們看到,一個是hdev,一個是hdve->bus,hdev自然很明確,就是hub所對應的那個struct usb_device指標,它的bus當然更加明確,一個主機控制器就對應一條匯流排,那麼不管我們在哪裡說,都是那條匯流排.busstruct usb_bus結構體指標,bus_to_hcd()得到的就是該匯流排對應的主機控制器,江湖上的人都知道,主機控制器就是代表一條匯流排.主機控制器由一個結構體struct usb_hcd表示,struct usb_hcd定義於drivers/usb/core/hcd.c,它有一個成員,struct usb_bus self.那麼這裡bus_to_hcd()就是得到該bus所屬於的那個struct usb_hcd所對應的指標,usb_get_hcd()是增加引用計數,具體怎麼實現咱們在裝置模型裡面有過交待.這裡很顯然,因為這個主機控制器的總線上多了一個裝置,當然得為主機控制器增加引用計數,只要有裝置在,主機控制器的資料結構就得在,否則系統肯定掛了.這裡如果usb_get_hcd()失敗了那就沒啥好說的了,釋放記憶體吧,哪涼快去哪待著.

然後device_initialize(&dev->dev),初始化裝置,第一個devstruct usb_device結構體指標,而第二個devstruct device結構體,這是裝置模型裡面一個最最基本的結構體,使用它必然要先初始化,device_initialize就是核心提供給咱們的初始化函式.

接下來,關於struct device結構體,我們迫不得已必須講兩句了,熟悉2.6裝置模型的兄弟們一