Linux 內核面向對象思想及實現

面向對象, 並不一定需要C++, JAVA語言才能實現。 C語言也能實現, 比如Linux內核。

 

C語言實現面向對象的思想, 

1. 封裝,  將數據和方法都封裝在數據結構中, 其中方法可以使用函數指針來實現。

2. 繼承, 

3. 多態, 即具體的函數調非編譯器決定, 而是程序運行期間決定, 即所謂的晚綁定(Late Binding)。

    即封裝中的函數指針,  可根據具體的實際對象選擇函數調用。

    

    看些代碼, 比如常見的比如platform_driver,

  1671 static struct platform_driver dwc3_driver = {                                                                                                                    
  1672 ›   .probe› ›   = dwc3_probe,                                                                                                                                    
  1673 ›   .remove››   = dwc3_remove,                                                                                                                                   
  1674 ›   .driver››   = {                                                                                                                                              
  1675 ›   ›   .name›  = "usb",                                                                                                                                         
  1676 ›   ›   .of_match_table›= of_match_ptr(of_dwc3_match),                                                                                                           
  1677 ›   ›   .acpi_match_table = ACPI_PTR(dwc3_acpi_match),                                                                                                           
  1678 ›   ›   .pm›= &dwc3_dev_pm_ops,                                                                                                                                  
  1679 ›   },                                                                                                                                                           
  1680 };                                                                                                                                                               
  1681                                                                                                                                                                  
  1682 module_platform_driver(dwc3_driver); 

該dwc3_driver驅動註冊成ko模式, 當該ko加載時, 內核會調用probe函數, 即dwc3_probe函數, 

驅動卸載時,  會調用dwc3_remove函數。

有點類和封裝的味道...


dwc3_probe函數會去做某些初始化, 如dwc3_core_init_mode->dwc3_gadget_init, 並初始選一些gadget操作集。

  3267 ›   dwc->gadget.ops››   ›   = &dwc3_gadget_ops;                                                                                                                  
  3268 ›   dwc->gadget.speed›  ›   = USB_SPEED_UNKNOWN;                                                                                                                 
  3269 ›   dwc->gadget.sg_supported›   = true;                                                                                                                          
  3270 ›   dwc->gadget.name›   ›   = "dwc3-gadget";                                                                                                                     
  3271 ›   dwc->gadget.is_otg› ›   = dwc->dr_mode == USB_DR_MODE_OTG;  

  2074 static const struct usb_gadget_ops dwc3_gadget_ops = {                                                                                                           
  2075 ›   .get_frame› ›   = dwc3_gadget_get_frame,                                                                                                                     
  2076 ›   .wakeup››   ›   = dwc3_gadget_wakeup,                                                                                                                        
  2077 ›   .set_selfpowered›   = dwc3_gadget_set_selfpowered,                                                                                                           
  2078 ›   .pullup››   ›   = dwc3_gadget_pullup,                                                                                                                        
  2079 ›   .udc_start› ›   = dwc3_gadget_start,                                                                                                                         
  2080 ›   .udc_stop›  ›   = dwc3_gadget_stop,                                                                                                                          
  2081 ›   .udc_set_speed› ›   = dwc3_gadget_set_speed,                                                                                                                 
  2082 }; 

ok, 此處dwc3_gadet_ops即爲dwc3這個具體udc控制器的一些行爲,  比如啓動,  關閉, 上拉, 設置速度,  喚醒, 設置自供電模式, get_frame等。

而這些行爲都是所有UDC控制器需要實現的功能, 即所有usb控制器抽象出來的一種行爲。 故UDC算是父類, dwc3控制器算個具體的子類, 該子類封裝了它的屬性及行爲。

我們看下udc_start行爲的流程, 即udc core框架如何調用udc_start的。

一種usb composite複合設備的流程如下:

usb_gadget_probe_driver->udc_bind_to_driver->usb_gadget_udc_start->udc->gadget->ops->udc_start(udc->gadget, udc->driver); -> dwc3_gadget_start

1038 /**                                                                                                                                                                
1039  * usb_gadget_udc_start - tells usb device controller to start up                                                                                                  
1040  * @udc: The UDC to be started                                                                                                                                     
1041  *                                                                                                                                                                 
1042  * This call is issued by the UDC Class driver when it's about                                                                                                     
1043  * to register a gadget driver to the device controller, before                                                                                                    
1044  * calling gadget driver's bind() method.                                                                                                                          
1045  *                                                                                                                                                                 
1046  * It allows the controller to be powered off until strictly                                                                                                       
1047  * necessary to have it powered on.                                                                                                                                
1048  *                                                                                                                                                                 
1049  * Returns zero on success, else negative errno.                                                                                                                   
1050  */                                                                                                                                                                
1051 static inline int usb_gadget_udc_start(struct usb_udc *udc)                                                                                                        
1052 {                                                                                                                                                                  
1053 ›   return udc->gadget->ops->udc_start(udc->gadget, udc->driver);                                                                                                  
1054 }        

看下udc_bind_to_driver函數, 

1317 static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)  

參數分別爲, udc指針和gadget_driver指針,  即綁定具體的udc控制器和當前的gadget驅動。

這裏udc控制器是dwc3, gadget驅動就是具體的function驅動, 如g_zero, g_serial, g_dnl(fastboot)等等。

 


看下udc_bind_to_driver綁定的流程。

1352 int usb_gadget_probe_driver(struct usb_gadget_driver *driver)                                                                                                      
1353 {                                                                                                                                                                  
1354 ›   struct usb_udc› ›   *udc = NULL;                                                                                                                               
1355 ›   int››   ›   ret = -ENODEV;                                                                                                                                     
1356                                                                                                                                                                    
1357 ›   if (!driver || !driver->bind || !driver->setup)                                                                                                                
1358 ›   ›   return -EINVAL;                                                                                                                                            
1359                                                                                                                                                                    
1360 ›   mutex_lock(&udc_lock);                                                                                                                                         
1361 ›   if (driver->udc_name) {                                                                                                                                        
1362 ›   ›   list_for_each_entry(udc, &udc_list, list) {                                                                                                                
1363 ›   ›   ›   ret = strcmp(driver->udc_name, dev_name(&udc->dev));                                                                                                   
1364 ›   ›   ›   if (!ret)                                                                                                                                              
1365 ›   ›   ›   ›   break;                                                                                                                                             
1366 ›   ›   }                                                                                                                                                          
1367 ›   ›   if (ret)                                                                                                                                                   
1368 ›   ›   ›   ret = -ENODEV;                                                                                                                                         
1369 ›   ›   else if (udc->driver)                                                                                                                                      
1370 ›   ›   ›   ret = -EBUSY;                                                                                                                                          
1371 ›   ›   else                                                                                                                                                       
1372 ›   ›   ›   goto found;                                                                                                                                            
1373 ›   } else {                                                                                                                                                       
1374 ›   ›   list_for_each_entry(udc, &udc_list, list) {                                                                                                                
1375 ›   ›   ›   /* For now we take the first one */                                                                                                                    
1376 ›   ›   ›   if (!udc->driver)                                                                                                                                      
1377 ›   ›   ›   ›   goto found;                                                                                                                                        
1378 ›   ›   }                                                                                                                                                          
1379 ›   }                                                                                                                                                              
1380                                                                                                                                                                    
1381 ›   if (!driver->match_existing_only) {                                                                                                                            
1382 ›   ›   list_add_tail(&driver->pending, &gadget_driver_pending_list);                                                                                              
1383 ›   ›   pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",                                                              
1384 ›   ›   ›   driver->function);                                                                                                                                     
1385 ›   ›   ret = 0;                                                                                                                                                   
1386 ›   }                                                                                                                                                              
1387                                                                                                                                                                    
1388 ›   mutex_unlock(&udc_lock);                                                                                                                                       
1389 ›   return ret;                                                                                                                                                    
1390 found:                                                                                                                                                             
1391 ›   ret = udc_bind_to_driver(udc, driver);                                                                                                                         
1392 ›   mutex_unlock(&udc_lock);                                                                                                                                       
1393 ›   return ret;                                                                                                                                                    
1394 }                                                                                                                                                                  
1395 EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); 

可以看到, 是遍歷udc_list, 並根據名稱進行匹配, 匹配到空閒的udc,  綁定該udc和驅動。(由於usb端點硬件資源的限制, 通常一個時間只能使能一種usb gadget驅動。 例如安卓手機, 同一時間只能選擇MTP, PTP, ADB等其中一種。 所以對於想同時使用多種功能的需求, 需使用composite複合設備,  如g_multi那種多功能複合設備。)

 


繼續看下什麼時機調用該綁定的操作。

其中一種複合設備流程如下:

module_usb_composite_driver->usb_composite_probe->usb_gadget_probe_driver->udc_bind_to_driver

查看g_zero驅動(zero.c)

416 static struct usb_composite_driver zero_driver = {                                                                                                                  
417 ›   .name›  ›   = "zero",                                                                                                                                           
418 ›   .dev›   ›   = &device_desc,                                                                                                                                     
419 ›   .strings›   = dev_strings,                                                                                                                                      
420 ›   .max_speed› = USB_SPEED_SUPER,                                                                                                                                  
421 ›   .bind›  ›   = zero_bind,                                                                                                                                        
422 ›   .unbind››   = zero_unbind,                                                                                                                                      
423 ›   .suspend›   = zero_suspend,                                                                                                                                     
424 ›   .resume››   = zero_resume,                                                                                                                                      
425 };                                                                                                                                                                  
426                                                                                                                                                                     
427 module_usb_composite_driver(zero_driver); 

即ko加載的時機就是綁定的時機。

modprobe g_zero後,  內核就會綁定一個可用的udc控制器和g_zero驅動, 配置並開啓udc控制器, 拉高相應D+/D- 引腳。使主機端能識別到usb設備插入, 併發起枚舉。


關於系統udc控制器, 我們在代碼中找下udc_list列表的維護。

可以找到相應的list_add_tail(&udc->list, &udc_list); 處。

調用順序爲:

usb_add_gadget_udc->usb_add_gadget_udc_release->list_add_tail(&udc->list, &udc_list); 

cscope搜索下usb_add_gadget_udc的調用。

Cscope tag: usb_add_gadget_udc                                                                                                                                          
   #   line  filename / context / line                                                                                                                                  
   1   1929  ./kernel-4.14/drivers/usb/chipidea/udc.c <<udc_start>>                                           
             retval = usb_add_gadget_udc(dev, &ci->gadget);                                                                                                             
   2   4724  ./kernel-4.14/drivers/usb/dwc2/gadget.c <<dwc2_gadget_init>>                                     
             ret = usb_add_gadget_udc(dev, &hsotg->gadget);                                                                                                             
   3   3298  ./kernel-4.14/drivers/usb/dwc3/gadget.c <<dwc3_gadget_init>>                                     
             ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);                                                                                                          
   4   1943  ./kernel-4.14/drivers/usb/gadget/udc/at91_udc.c <<at91udc_probe>>                                
             retval = usb_add_gadget_udc(dev, &udc->gadget);                                                                                                            
   5   2380  ./kernel-4.14/drivers/usb/gadget/udc/atmel_usba_udc.c <<usba_udc_probe>>                         
             ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);                                                                                                        
   6   2412  ./kernel-4.14/drivers/usb/gadget/udc/bcm63xx_udc.c <<bcm63xx_udc_probe>>                         
             rc = usb_add_gadget_udc(dev, &udc->gadget);                                                                                                                
   7    552  ./kernel-4.14/drivers/usb/gadget/udc/bdc/bdc_udc.c <<bdc_udc_init>>                              
             ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget);                                                                                                          
   8   1078  ./kernel-4.14/drivers/usb/gadget/udc/dummy_hcd.c <<dummy_udc_probe>>                             
             rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);                                                                                                         
   9   1178  ./kernel-4.14/drivers/usb/gadget/udc/fotg210-udc.c <<fotg210_udc_probe>>                         
             ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget);                                                                                                    
  10   1478  ./kernel-4.14/drivers/usb/gadget/udc/fusb300_udc.c <<fusb300_probe>>      

可以看到, 有很多具體的UDC控制器, 和該具體的產品及內核配置有關。 如果內部有集成dwc2, dwc3, chipidea等多種控制器, 你當然可以通過make menuconfig使能他們, 或者編譯成ko, 加載具體的驅動模塊。

 


綜上, 用戶可以於程序運行時選在加載的gadget驅動及控制器模塊, 程序進項相應的綁定/匹配,  並最終能使用該驅動。

這就是一種多態的思想。。


ok, 摘錄兩篇lwn.net的文章, 後續繼續學些。

https://lwn.net/Articles/444910/

https://lwn.net/Articles/446317/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章