USB设备控制器(UDC)驱动指的是作为其他USB主机控制器外设的USB硬件设备上底层硬件控制器的驱动,该硬件和驱动负责将一个USB设备依附于一个USB主机控制器上。例如,当某运行Linux系统的手机作为PC的U盘时,手机中的底层USB控制器行使USB设备控制器的功能,这时运行在底层的是UDC驱动,手机要成为U盘,在UDC驱动之上需要另外一个驱动,对于USB大容量存储器而言,这个驱动为File Storage驱动,称为Function驱动。
Linux USB Gadget软件结构一文中分析Linux USB Gadget软件分为三层。这三层其中两层是与硬件无关的,分别是Gadget功能驱动层,USB设备层。一层是与硬件相关的是UDC层。每一层都提供一种关键的数据结构与函数与其他层交互。
Gadget功能驱动层: 最主要的结构是struct usb_composite_driver,这个结构在这层定义,并且实现结构中的各个函数。
USB设备层: 最主要的数据结构是struct usb_composite_dev与usb_gadget_driver。前一个代表一个USB复合设备,而后一个是Gadget驱动,与UDC层交互。
Gadet Function: 功能层的功能接口(interface)
UDC层: 最主要的数据结构是struct usb_gadget,通常包含在其他结构体中。这个结构体代表了一个USB设备控制器的所有关于USB通信的信息。
其中Gadget功能驱动层和USB设备层对应上图Gadget Function驱动; Gadet Function对应上图Gadet Function API ; UDC层对应上图UDC驱动。
int dwc3_drd_init(struct dwc3 *dwc)
{
int ret, irq;
//External Connectors是usb用于状态通知的驱动,当phy收到中断,处理完usb状态后,通过extcon驱动,广播到已监听该extcon的所有驱动
dwc->edev = dwc3_get_extcon(dwc);
if (IS_ERR(dwc->edev))
return PTR_ERR(dwc->edev);
if (device_property_read_bool(dwc->dev, "usb-role-switch")) { //如果dts里面定义了这个选项usb-role-switch
dwc3_role_switch.fwnode = dev_fwnode(dwc->dev);
/* usb role switch是一种能够或选择USB连接器角色的设备。在USB控制器是双角色的平台上,控制器
*驱动程序需要注册切换开关。在USB主机和USB设备控制器后面的连接器都是分开的,会有一个 mux,这个mux的驱动程序需要注册开关。*/
dwc->role_switch = usb_role_switch_register(dwc->dev,
&dwc3_role_switch); //注册role_switch,会生成一个%s-role-switch的节点用来控制role.
if (IS_ERR(dwc->role_switch))
return PTR_ERR(dwc->role_switch);
} else if (dwc->edev) {
dwc->edev_nb.notifier_call = dwc3_drd_notifier; //当extcon状态变化会调用这个函数,里面会设置dwc->desired_dr_role = mode;
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
&dwc->edev_nb); //注册一个通知块,以获得extcon中的任何状态更改的通知。
if (ret < 0) {
dev_err(dwc->dev, "couldn\'t register cable notifier\n");
return ret;
}
dwc3_drd_update(dwc); //获取extcon状态,里面会设置dwc->desired_dr_role = mode;
} else { //如果没有extcon,我们这里使用的是typec接口
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG;
/* use OTG block to get ID event */
irq = dwc3_otg_get_irq(dwc); //获取一个中断
if (irq < 0)
return irq;
dwc->otg_irq = irq;
/* disable all OTG IRQs */
dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
/* clear all events */
dwc3_otg_clear_events(dwc);
ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq,
dwc3_otg_thread_irq,
IRQF_SHARED, "dwc3-otg", dwc); //申请一个中断,dwc3_otg_irq是当IRQ发生时被调用的函数,后面再调用dwc3_otg_thread_irq(相当于底半部)
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
dwc->otg_irq, ret);
ret = -ENODEV;
return ret;
}
dwc3_otg_init(dwc); //主要是硬件初始化
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); //设置dwc->desired_dr_role = mode;并启动工作队列__dwc3_set_mode
}
return 0;
}
static void __dwc3_set_mode(struct work_struct *work)
{
switch (dwc->desired_dr_role) {
case DWC3_GCTL_PRTCAP_HOST: //host模式,之前已经分析过了
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dwc->dev, "failed to initialize host\n");
} else {
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
break;
case DWC3_GCTL_PRTCAP_DEVICE: //从设备模式
dwc3_event_buffers_setup(dwc);
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE); //设置phy模式
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc); //初始化gadget
if (ret)
dev_err(dwc->dev, "failed to initialize peripheral\n");
break;
case DWC3_GCTL_PRTCAP_OTG: //这里一般应该是初始化调用
dwc3_otg_init(dwc);
dwc3_otg_update(dwc, 0);
break;
default:
break;
}
}
static const struct usb_gadget_ops dwc3_gadget_ops = {
.get_frame = dwc3_gadget_get_frame,
.wakeup = dwc3_gadget_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
.pullup = dwc3_gadget_pullup, //下拉开始枚举
.udc_start = dwc3_gadget_start, //启动
.udc_stop = dwc3_gadget_stop, //停止
.udc_set_speed = dwc3_gadget_set_speed,
.get_config_params = dwc3_gadget_config_params,
};
int dwc3_gadget_init(struct dwc3 *dwc)
{
dwc->gadget.ops = &dwc3_gadget_ops; //设置操作函数
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
dwc->gadget.lpm_capable = true;
dwc->gadget.is_otg = (dwc->dr_mode == USB_DR_MODE_OTG) &&
(dwc->otg_caps.hnp_support ||
dwc->otg_caps.srp_support ||
dwc->otg_caps.adp_support); //设置模式
/*
* REVISIT: Here we should clear all pending IRQs to be
* sure we\'re starting from a well known location.
*/
ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps); //初始化usb端口,dwc->num_eps个
if (ret)
goto err3;
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); //向udc类驱动程序列表中添加一个新的gadget
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
goto err4;
}
dwc3_gadget_set_speed(&dwc->gadget, dwc->maximum_speed);
return 0;
}
static const struct usb_ep_ops dwc3_gadget_ep0_ops = { //端点0的操作函数
.enable = dwc3_gadget_ep0_enable,
.disable = dwc3_gadget_ep0_disable,
.alloc_request = dwc3_gadget_ep_alloc_request,
.free_request = dwc3_gadget_ep_free_request,
.queue = dwc3_gadget_ep0_queue,
.dequeue = dwc3_gadget_ep_dequeue,
.set_halt = dwc3_gadget_ep0_set_halt,
.set_wedge = dwc3_gadget_ep_set_wedge,
};
static const struct usb_ep_ops dwc3_gadget_ep_ops = { //除了端点0之外的端点操作函数
.enable = dwc3_gadget_ep_enable,
.disable = dwc3_gadget_ep_disable,
.alloc_request = dwc3_gadget_ep_alloc_request,
.free_request = dwc3_gadget_ep_free_request,
.queue = dwc3_gadget_ep_queue,
.dequeue = dwc3_gadget_ep_dequeue,
.set_halt = dwc3_gadget_ep_set_halt,
.set_wedge = dwc3_gadget_ep_set_wedge,
};
static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
{
dep->dwc = dwc;
dep->number = epnum;
dep->direction = direction;
dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
dwc->eps[epnum] = dep;
dep->combo_num = 0;
dep->start_cmd_status = 0;
snprintf(dep->name, sizeof(dep->name), "ep%u%s", num,
direction ? "in" : "out");
dep->endpoint.name = dep->name;
if (!(dep->number > 1)) {
dep->endpoint.desc = &dwc3_gadget_ep0_desc; //默认的描述符
dep->endpoint.comp_desc = NULL;
}
if (num == 0)
ret = dwc3_gadget_init_control_endpoint(dep); //初始化控制端点0, dep->endpoint.ops = &dwc3_gadget_ep0_ops; dwc3_gadget_ep0_ops是操作函数
else if (direction)
ret = dwc3_gadget_init_in_endpoint(dep); //初始化输入端点, dep->endpoint.ops = &dwc3_gadget_ep_ops; dwc3_gadget_ep_ops是操作函数
else
ret = dwc3_gadget_init_out_endpoint(dep); //初始化输出端点,dep->endpoint.ops = &dwc3_gadget_ep_ops; dwc3_gadget_ep_ops是操作函数
}
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
{
dev_set_name(&gadget->dev, "gadget");
INIT_WORK(&gadget->work, usb_gadget_state_work); //这个工作用于通知,sysfs_notify
gadget->dev.parent = parent;
if (release)
gadget->dev.release = release;
else
gadget->dev.release = usb_udc_nop_release;
device_initialize(&gadget->dev); //初始化设备结构
udc = kzalloc(sizeof(*udc), GFP_KERNEL); //分配usb_udc结构体
if (!udc)
goto err_put_gadget;
device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
udc->dev.groups = usb_udc_attr_groups; //创建sysfs调试节点
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
goto err_put_udc;
ret = device_add(&gadget->dev); //将usb_gadget设备添加到设备层次结构中
if (ret)
goto err_put_udc;
udc->gadget = gadget; //赋值这个usb_gadget
gadget->udc = udc;
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list); //加入到udc_list
ret = device_add(&udc->dev); //描述了一个usb设备控制器的设备,添加到设备层次结构中
if (ret)
goto err_unlist_udc;
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true;
/* pick up one of pending gadget drivers */
ret = check_pending_gadget_drivers(udc); //选择一个等待的gadget驱动,使用udc_bind_to_driver驱动绑定,后面我们会分析这个函数
if (ret)
goto err_del_udc;
mutex_unlock(&udc_lock);
return 0;
}
static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
irq = dwc->irq_gadget;
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
IRQF_SHARED, "dwc3", dwc->ev_buf); //申请中断,上半部是dwc3_interrupt,下半部是dwc3_thread_interrupt
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
goto err0;
}
dwc->gadget_driver = driver;
if (pm_runtime_active(dwc->dev))
__dwc3_gadget_start(dwc); //启动udc,主要是寄存器方面的设置,还有开始接收SETUP包,是能中断等
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
dwc3 linux usb3.0 driver架构_在路上-CSDN博客