本文共 20043 字,大约阅读时间需要 66 分钟。
面向对象, 并不一定需要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 <> retval = usb_add_gadget_udc(dev, &ci->gadget); 2 4724 ./kernel-4.14/drivers/usb/dwc2/gadget.c < > ret = usb_add_gadget_udc(dev, &hsotg->gadget); 3 3298 ./kernel-4.14/drivers/usb/dwc3/gadget.c < > ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); 4 1943 ./kernel-4.14/drivers/usb/gadget/udc/at91_udc.c < > retval = usb_add_gadget_udc(dev, &udc->gadget); 5 2380 ./kernel-4.14/drivers/usb/gadget/udc/atmel_usba_udc.c < > ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget); 6 2412 ./kernel-4.14/drivers/usb/gadget/udc/bcm63xx_udc.c < > rc = usb_add_gadget_udc(dev, &udc->gadget); 7 552 ./kernel-4.14/drivers/usb/gadget/udc/bdc/bdc_udc.c < > ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget); 8 1078 ./kernel-4.14/drivers/usb/gadget/udc/dummy_hcd.c < > rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); 9 1178 ./kernel-4.14/drivers/usb/gadget/udc/fotg210-udc.c < > ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget); 10 1478 ./kernel-4.14/drivers/usb/gadget/udc/fusb300_udc.c < >
可以看到, 有很多具体的UDC控制器, 和该具体的产品及内核配置有关。 如果内部有集成dwc2, dwc3, chipidea等多种控制器, 你当然可以通过make menuconfig使能他们, 或者编译成ko, 加载具体的驱动模块。
综上, 用户可以于程序运行时选在加载的gadget驱动及控制器模块, 程序进项相应的绑定/匹配, 并最终能使用该驱动。
这就是一种多态的思想。。
ok, 摘录两篇lwn.net的文章, 后续继续学些。
转载地址:http://wpcrj.baihongyu.com/