面向對象, 並不一定需要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的文章, 後續繼續學些。