dwc3控制器是怎么处理otg

news2024/11/25 1:01:53

概念

在OTG中,初始主机设备称为A设备,外设称为B设备。可用电缆的连接方式来决定初始角色。两用设备使用新型Mini-AB插座,从而使Mini-A插头、Mini-B插头和Mini-AB插座增添了第5个引脚(ID),以用于识别不同的电缆端点。Mini-A插头中的ID引脚接地,Mini-B插头中的ID引脚浮空。当OTG设备检测到接地的ID引脚时,表示默认的是A设备(主机),而检测到ID引脚浮空的设备则认为是B设备(外设)。系统一旦连接后,OTG的角色还可以更换,以采用新的HNP协议。而SRP允许B设备请求A设备打开VBUS电源并启动一次对话。

设备树

我们直接看支持otg的dwc3是怎么处理otg的,从设备开始看驱动,usb3_0的这个节点一般就是厂商自己定义的,主要包括中断,一般用于vbus检测,usb的插拔情况;dwc3_0这个子节点就是通用的dwc3核心,主要包括中断,一般用于id脚的检测,来判断当前是设备还是主机;如果dr_mode设置了模式,就会用固定的模式去初始化控制器

usb3phy: usb3phy@c0030000 {
        compatible = "usb3-phy";
        reg = <0xc0030000 0x1000>;
        clocks = <&soc_clocks CLK_USB>;
        clock-names = "usb_clk";
        status = "disabled";
};
usb3_0: usb3-0 {
        compatible = "arch,dwc3";
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;
        interrupts = <53>;
        clocks = <&soc_clocks CLK_USB>;
        clock-names = "usb_clk";
        status = "disabled";
        usb_dwc3_0: dwc31@c0000000 {
                compatible = "snps,dwc3";
                reg = <0xc0000000 0x11000>;
                interrupts = <44>;
                usb-phy = <&usb3phy>;
                maximum-speed = "super-speed";
                dr_mode = "peripheral";
                phy_type = "utmi";
                lpm-qos = <PM_QOS_CPUIDLE_BLOCK_AXI>;
                snps,dis_u3_susphy_quirk;
                /* allow-suspend; */
                status = "okay";
        };
};

驱动框架

设备树跟驱动match后,会执行dwc3_probe;主要是一些初始化操作,如果设置了dr_mode为peripheral,就调用dwc_gadget_init去初始化设备控制器;dr_mode为host,就调用dwc3_host_init去初始化为主机控制器;如果dr_mode为otg,就根据id的情况去初始化为主机或设备

dwc3_probe
    dwc3_get_dr_mode
    dwc3_core_init
    dwc3_debugfs_init
    dwc3_core_init_mode//根据模式进入一种
        dwc3_gadget_init
            dwc->gadget.ops	= &dwc3_gadget_ops;//初始化设备控制器操作函数
            dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
                dep->endpoint.ops = &dwc3_gadget_ep_ops;
            usb_add_gadget_udc(dwc->dev, &dwc->gadget);//注册设备控制器
        dwc3_host_init
            xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
            platform_device_add(xhci)//初始化xhci平台设备;用于匹配到usb_xhci_driver-----其probe来初始化主机控制器,填充操作函数xhci_hc_driver,并注册主机控制器
        dwc3_drd_init
            request_threaded_irq(dwc->otg_irq, dwc3_otg_irq,dwc3_otg_thread_irq,IRQF_SHARED, "dwc3-otg", dwc);
                dwc3_set_mode
                    __dwc3_set_mode
                        dwc3_otg_update//根据模式进入一种
                            dwc3_host_init
                            dwc3_gadget_init

主机控制器的初始化

上面的代码分析到:dwc3_host_init会通过 platform_device_add(xhci)//初始化xhci平台设备;用于匹配到usb_xhci_driver-----其probe来初始化主机控制器,填充操作函数xhci_hc_driver,并注册主机控制器

drivers/usb/host/xhci-plat.c中的usb_xhci_driver通过name(xhci-hcd)匹配上;xhci_init_driver将通用的xhci_hc_driver,赋值给xhci_plat_hc_driver;过程跟ehci_init_driver一致

static int xhci_plat_probe(struct platform_device *pdev)
{
	const struct xhci_plat_priv *priv_match;
	const struct hc_driver	*driver;
	struct device		*sysdev, *tmpdev;
	struct xhci_hcd		*xhci;
	struct resource         *res;
	struct usb_hcd		*hcd;
	int			ret;
	int			irq;
	struct xhci_plat_priv	*priv = NULL;


	if (usb_disabled())
		return -ENODEV;

	driver = &xhci_plat_hc_driver;

	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		return irq;

	/*
	 * sysdev must point to a device that is known to the system firmware
	 * or PCI hardware. We handle these three cases here:
	 * 1. xhci_plat comes from firmware
	 * 2. xhci_plat is child of a device from firmware (dwc3-plat)
	 * 3. xhci_plat is grandchild of a pci device (dwc3-pci)
	 */
	for (sysdev = &pdev->dev; sysdev; sysdev = sysdev->parent) {
		if (is_of_node(sysdev->fwnode) ||
			is_acpi_device_node(sysdev->fwnode))
			break;
#ifdef CONFIG_PCI
		else if (sysdev->bus == &pci_bus_type)
			break;
#endif
	}

	if (!sysdev)
		sysdev = &pdev->dev;

	/* Try to set 64-bit DMA first */
	if (WARN_ON(!sysdev->dma_mask))
		/* Platform did not initialize dma_mask */
		ret = dma_coerce_mask_and_coherent(sysdev,
						   DMA_BIT_MASK(64));
	else
		ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));

	/* If seting 64-bit DMA mask fails, fall back to 32-bit DMA mask */
	if (ret) {
		ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32));
		if (ret)
			return ret;
	}

	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);
	pm_runtime_get_noresume(&pdev->dev);

	hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
			       dev_name(&pdev->dev), NULL);
	if (!hcd) {
		ret = -ENOMEM;
		goto disable_runtime;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(hcd->regs)) {
		ret = PTR_ERR(hcd->regs);
		goto put_hcd;
	}

	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);

	xhci = hcd_to_xhci(hcd);

	/*
	 * Not all platforms have clks so it is not an error if the
	 * clock do not exist.
	 */
	xhci->reg_clk = devm_clk_get_optional(&pdev->dev, "reg");
	if (IS_ERR(xhci->reg_clk)) {
		ret = PTR_ERR(xhci->reg_clk);
		goto put_hcd;
	}

	ret = clk_prepare_enable(xhci->reg_clk);
	if (ret)
		goto put_hcd;

	xhci->clk = devm_clk_get_optional(&pdev->dev, NULL);
	if (IS_ERR(xhci->clk)) {
		ret = PTR_ERR(xhci->clk);
		goto disable_reg_clk;
	}

	ret = clk_prepare_enable(xhci->clk);
	if (ret)
		goto disable_reg_clk;

	priv_match = of_device_get_match_data(&pdev->dev);
	if (priv_match) {
		priv = hcd_to_xhci_priv(hcd);
		/* Just copy data for now */
		if (priv_match)
			*priv = *priv_match;
	}

	device_wakeup_enable(hcd->self.controller);

	xhci->main_hcd = hcd;
	xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
			dev_name(&pdev->dev), hcd);
	if (!xhci->shared_hcd) {
		ret = -ENOMEM;
		goto disable_clk;
	}

	/* imod_interval is the interrupt moderation value in nanoseconds. */
	xhci->imod_interval = 40000;

	/* Iterate over all parent nodes for finding quirks */
	for (tmpdev = &pdev->dev; tmpdev; tmpdev = tmpdev->parent) {

		if (device_property_read_bool(tmpdev, "usb2-lpm-disable"))
			xhci->quirks |= XHCI_HW_LPM_DISABLE;

		if (device_property_read_bool(tmpdev, "usb3-lpm-capable"))
			xhci->quirks |= XHCI_LPM_SUPPORT;

		if (device_property_read_bool(tmpdev, "quirk-broken-port-ped"))
			xhci->quirks |= XHCI_BROKEN_PORT_PED;

		device_property_read_u32(tmpdev, "imod-interval-ns",
					 &xhci->imod_interval);
	}

	hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
	if (IS_ERR(hcd->usb_phy)) {
		ret = PTR_ERR(hcd->usb_phy);
		if (ret == -EPROBE_DEFER)
			goto put_usb3_hcd;
		hcd->usb_phy = NULL;
	} else {
		ret = usb_phy_init(hcd->usb_phy);
		if (ret)
			goto put_usb3_hcd;
	}

	hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
	xhci->shared_hcd->tpl_support = hcd->tpl_support;

	if (priv) {
		ret = xhci_priv_plat_setup(hcd);
		if (ret)
			goto disable_usb_phy;
	}

	if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)))
		hcd->skip_phy_initialization = 1;

	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
	if (ret)
		goto disable_usb_phy;

	if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
		xhci->shared_hcd->can_do_streams = 1;

	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
	if (ret)
		goto dealloc_usb2_hcd;

	device_enable_async_suspend(&pdev->dev);
	pm_runtime_put_noidle(&pdev->dev);

	/*
	 * Prevent runtime pm from being on as default, users should enable
	 * runtime pm using power/control in sysfs.
	 */
	pm_runtime_forbid(&pdev->dev);

	return 0;
....
}
static struct platform_driver usb_xhci_driver = {
	.probe	= xhci_plat_probe,
	.remove	= xhci_plat_remove,
	.shutdown = usb_hcd_platform_shutdown,
	.driver	= {
		.name = "xhci-hcd",
		.pm = &xhci_plat_pm_ops,
		.of_match_table = of_match_ptr(usb_xhci_of_match),
		.acpi_match_table = ACPI_PTR(usb_xhci_acpi_match),
	},
};
MODULE_ALIAS("platform:xhci-hcd");

static int __init xhci_plat_init(void)
{
	xhci_init_driver(&xhci_plat_hc_driver, &xhci_plat_overrides);
	return platform_driver_register(&usb_xhci_driver);
}
module_init(xhci_plat_init);

static void __exit xhci_plat_exit(void)
{
	platform_driver_unregister(&usb_xhci_driver);
}
module_exit(xhci_plat_exit);

dwc3_core_init_mode

dwc3_core_init_mode根据设备树获得的模式,初始化控制器为对应模式,初始化控制器的操作函数:主机有主机的操作函数;设备有设备的操作函数

static int dwc3_core_init_mode(struct dwc3 *dwc)
{
        struct device *dev = dwc->dev;
        int ret;

        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
                dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);

                if (dwc->usb2_phy)
                        otg_set_vbus(dwc->usb2_phy->otg, false);
                phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
                phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);

                ret = dwc3_gadget_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "failed to initialize gadget\n");
                        return ret;
                }
                break;
        case USB_DR_MODE_HOST:
                dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);

                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);

                ret = dwc3_host_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "failed to initialize host\n");
                        return ret;
                }
                break;
        case USB_DR_MODE_OTG:
                INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
                ret = dwc3_drd_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
                                dev_err(dev, "failed to initialize dual-role\n");
                        return ret;
                }
                break;
        default:
                dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
                return -EINVAL;
        }

        return 0;
}

OTG模式

注册中断

一般是通过id脚注册中断:use OTG block to get ID event

int dwc3_drd_init(struct dwc3 *dwc)
{
        int ret, irq;

        dwc->edev = dwc3_get_extcon(dwc);
        if (IS_ERR(dwc->edev))
                return PTR_ERR(dwc->edev);

        if (ROLE_SWITCH &&
            device_property_read_bool(dwc->dev, "usb-role-switch")) {
                ret = dwc3_setup_role_switch(dwc);
                if (ret < 0)
                        return ret;
        } else if (dwc->edev) {
                dwc->edev_nb.notifier_call = dwc3_drd_notifier;
                ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
                                               &dwc->edev_nb);
                if (ret < 0) {
                        dev_err(dwc->dev, "couldn't register cable notifier\n");
                        return ret;
                }

                dwc3_drd_update(dwc);
        } else {
                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);
                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);
        }

        return 0;
}

中断处理

根据id脚的状态,判断是做主机还是设备

static irqreturn_t dwc3_otg_irq(int irq, void *_dwc)
{
        u32 reg;
        struct dwc3 *dwc = _dwc;
        irqreturn_t ret = IRQ_NONE;

        reg = dwc3_readl(dwc->regs, DWC3_OEVT);
        if (reg) {
                /* ignore non OTG events, we can't disable them in OEVTEN */
                if (!(reg & DWC3_OTG_ALL_EVENTS)) {
                        dwc3_writel(dwc->regs, DWC3_OEVT, reg);
                        return IRQ_NONE;
                }

                if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST &&
                    !(reg & DWC3_OEVT_DEVICEMODE))
                        dwc->otg_restart_host = 1;
                dwc3_writel(dwc->regs, DWC3_OEVT, reg);
                ret = IRQ_WAKE_THREAD;
        }

        return ret;
}

可以看作中断下半部,来通过dwc3_set_mode将控制器初始化为主机或者设备

static irqreturn_t dwc3_otg_thread_irq(int irq, void *_dwc)
{
        struct dwc3 *dwc = _dwc;

        spin_lock(&dwc->lock);
        if (dwc->otg_restart_host) {
                dwc3_otg_host_init(dwc);
                dwc->otg_restart_host = 0;
        }

        spin_unlock(&dwc->lock);

        dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);

        return IRQ_HANDLED;
}


void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
        unsigned long flags;

        spin_lock_irqsave(&dwc->lock, flags);
        dwc->desired_dr_role = mode;
        spin_unlock_irqrestore(&dwc->lock, flags);

        queue_work(system_freezable_wq, &dwc->drd_work);
}

设置模式

模式设置的是设备或者主机,就直接调用dwc3_gadget_init或者dwc3_host_init初始化控制器;如果是otg模式,就要根据dwc3_otg_update去判断id脚的情况来更新为设备或者主机

static void __dwc3_set_mode(struct work_struct *work)
{
        struct dwc3 *dwc = work_to_dwc(work);
        unsigned long flags;
        int ret;
        u32 reg;

        if (dwc->dr_mode != USB_DR_MODE_OTG)
                return;

        if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
                dwc3_otg_update(dwc, 0);

        if (!dwc->desired_dr_role)
                return;

        if (dwc->desired_dr_role == dwc->current_dr_role)
                return;

        if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
                return;

        switch (dwc->current_dr_role) {
        case DWC3_GCTL_PRTCAP_HOST:
                dwc3_host_exit(dwc);
                break;
        case DWC3_GCTL_PRTCAP_DEVICE:
                dwc3_gadget_exit(dwc);
                dwc3_event_buffers_cleanup(dwc);
                break;
        case DWC3_GCTL_PRTCAP_OTG:
                dwc3_otg_exit(dwc);
                spin_lock_irqsave(&dwc->lock, flags);
                dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE;
                spin_unlock_irqrestore(&dwc->lock, flags);
                dwc3_otg_update(dwc, 1);
                break;
        default:
                break;
        }

        spin_lock_irqsave(&dwc->lock, flags);

        dwc3_set_prtcap(dwc, dwc->desired_dr_role);

        spin_unlock_irqrestore(&dwc->lock, flags);

        switch (dwc->desired_dr_role) {
        case DWC3_GCTL_PRTCAP_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);
                        if (dwc->dis_split_quirk) {
                                reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
                                reg |= DWC3_GUCTL3_SPLITDISABLE;
                                dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
                                dwc3_save_controller_regs(DWC3_GUCTL3, reg);
                        }
                }
                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_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);

                ret = dwc3_gadget_init(dwc);
                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;
        }
}

更新模式

ignore_idstatus为0,就回去读id相关寄存器,获取id脚的状态desired_otg_role;为高就是DWC3_OTG_ROLE_DEVICE,为低就是DWC3_OTG_ROLE_HOST;跟current_otg_role一样就返回,不一样就关掉当前的控制器,初始化为desired_otg_role的控制器模式

void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
{
	int ret;
	u32 reg;
	int id;
	unsigned long flags;

	if (dwc->dr_mode != USB_DR_MODE_OTG)
		return;

	/* don't do anything if debug user changed role to not OTG */
	if (dwc->current_dr_role != DWC3_GCTL_PRTCAP_OTG)
		return;

	if (!ignore_idstatus) {
		reg = dwc3_readl(dwc->regs, DWC3_OSTS);
		id = !!(reg & DWC3_OSTS_CONIDSTS);

		dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE :
					DWC3_OTG_ROLE_HOST;
	}

	if (dwc->desired_otg_role == dwc->current_otg_role)
		return;

	switch (dwc->current_otg_role) {
	case DWC3_OTG_ROLE_HOST:
		dwc3_host_exit(dwc);
		spin_lock_irqsave(&dwc->lock, flags);
		dwc3_otg_host_exit(dwc);
		spin_unlock_irqrestore(&dwc->lock, flags);
		break;
	case DWC3_OTG_ROLE_DEVICE:
		dwc3_gadget_exit(dwc);
		spin_lock_irqsave(&dwc->lock, flags);
		dwc3_event_buffers_cleanup(dwc);
		dwc3_otg_device_exit(dwc);
		spin_unlock_irqrestore(&dwc->lock, flags);
		break;
	default:
		break;
	}

	spin_lock_irqsave(&dwc->lock, flags);

	dwc->current_otg_role = dwc->desired_otg_role;

	spin_unlock_irqrestore(&dwc->lock, flags);

	switch (dwc->desired_otg_role) {
	case DWC3_OTG_ROLE_HOST:
		spin_lock_irqsave(&dwc->lock, flags);
		dwc3_otgregs_init(dwc);
		dwc3_otg_host_init(dwc);
		spin_unlock_irqrestore(&dwc->lock, flags);
		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);
			if (dwc->usb2_generic_phy)
				phy_set_mode(dwc->usb2_generic_phy,
					     PHY_MODE_USB_HOST);
		}
		break;
	case DWC3_OTG_ROLE_DEVICE:
		spin_lock_irqsave(&dwc->lock, flags);
		dwc3_otgregs_init(dwc);
		dwc3_otg_device_init(dwc);
		dwc3_event_buffers_setup(dwc);
		spin_unlock_irqrestore(&dwc->lock, flags);

		if (dwc->usb2_phy)
			otg_set_vbus(dwc->usb2_phy->otg, false);
		if (dwc->usb2_generic_phy)
			phy_set_mode(dwc->usb2_generic_phy,
				     PHY_MODE_USB_DEVICE);
		ret = dwc3_gadget_init(dwc);
		if (ret)
			dev_err(dwc->dev, "failed to initialize peripheral\n");
		break;
	default:
		break;
	}
}

debugfs

drivers/usb/dwc3/debugfs.c通过应用层写模式到属性文件中,也能直接切换模式

static ssize_t dwc3_mode_write(struct file *file,
                const char __user *ubuf, size_t count, loff_t *ppos)
{
        struct seq_file         *s = file->private_data;
        struct dwc3             *dwc = s->private;
        u32                     mode = 0;
        char                    buf[32];

        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
                return -EFAULT;

        if (!strncmp(buf, "host", 4))
                mode = DWC3_GCTL_PRTCAP_HOST;

        if (!strncmp(buf, "device", 6))
                mode = DWC3_GCTL_PRTCAP_DEVICE;

        if (!strncmp(buf, "otg", 3))
                mode = DWC3_GCTL_PRTCAP_OTG;

        dwc3_set_mode(dwc, mode);

        return count;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1626746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么从回收站恢复已删除的文件?(5种恢复方法)

回收站是电脑操作系统中的一个特殊目录&#xff0c;用于存储被删除但尚未完全清除的文件和文件夹。当用户删除文件或文件夹时&#xff0c;它们并不立即从硬盘驱动器中移除&#xff0c;而是被移动到回收站。这样设计的目的是为了给用户一个“第二次机会”&#xff0c;如果他们意…

python-excel自动化-openpyxl

openpyxl学习笔记 创建或打开表格存储和遍历数据设置单元格风格过滤器和排序更改工作表的背景颜色合并单元格冻结窗口数字格式公式图像图表条形图折线图散点图 创建或打开表格 # 创建 import datetime from openpyxl import Workbook # 实例化 wb Workbook() # 激活 work…

融合卷积和注意力机制:有效整合它们优势的方法概述

卷积与注意力机制的结合 1. 介绍2. 模型学习偏差及其后果2.1 全连接层2.2 卷积层2.3 自注意力层 3. 融合卷积与注意力的学习方法3.1 Squeeze-and-Excitation网络3.2 卷积块注意力模块3.3 相对自注意力3.4 注意力增强卷积网络3.5 使用变换器进行端到端目标检测3.6 CvT&#xff1…

ssm083化妆品配方及工艺管理系统的设计与实现+jsp

化妆品配方及工艺管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本化妆品配方及工艺管理系统就是在这样的大环境下诞生&#xff0c;其可…

自动评论轻松增粉!抖音新技能来了

在如今这个信息爆炸&#xff0c;流量至上的时代&#xff0c;如何快速吸引新粉丝并保持互动性成为了许多内容创作者的心头大患。想象一下&#xff0c;如果你有一款神奇的工具&#xff0c;能让你在抖音上自动互动&#xff0c;轻松吸引关注&#xff0c;岂不是美哉&#xff1f;今天…

Spring Cloud Alibaba Sentinel 使用

初识Sentinel Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址&#xff1a; home | Sentinel 需要了解的概念 簇点链路 在学习 Sentinel 的使用之前&#xff0c;我们有必要首先了解一下簇点链路。当请求进入微服务时&#xff0c;首先会访Controller、Service、Ma…

原生js实现一个简化版的h函数

原生js实现一个简化版的h函数 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&…

ChatGPT智能对话和MidjourneyAI画画系统源码运营版+完整教程

今天给大家带来一款可以帮你赚米的AI智能系统。这款系统将AI智能会话及AI画画功能合二为一&#xff0c;对接了大名鼎鼎的ChatGPT接口及Midjourney两个王牌接口。另外后台还集成了国内外几十个AI大模型及AI绘画接口&#xff08;输入文字就可以快速生成高清图片&#xff09;&…

PHP 函数的命名空间是否会影响执行顺序?

在 php 中&#xff0c;函数命名空间一般不会影响执行顺序。执行顺序通常由文件顺序或函数调用顺序决定。即使函数位于不同的命名空间中&#xff0c;只要它们在同一文件中&#xff0c;它们就会按照定义顺序执行。 PHP 函数命名空间是否会影响执行顺序&#xff1f; 简介 在 PHP…

AI 边缘计算平台 - 嘉楠堪智 CanMV K230 开箱

CanMV-K230 开发板采用的是嘉楠科技 Kendryte 系列 AIoT 芯片中的最新一代 SoC 芯片 K230。该芯片采用全新的多异构单元加速计算架构&#xff0c;最新高性能 RISC-V CPU 内置双核玄铁 C908 CPU, 主频高达 1.6GHz&#xff1b;是全球首款支持 RISC-V Vector 1.0 标准的商用 SoC&a…

某翻译平台翻译接口逆向之webpack学习

逆向网址 aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tLw 逆向链接 aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tLyMv 逆向接口 aHR0cHM6Ly9kaWN0LnlvdWRhby5jb20vd2VidHJhbnNsYXRl 逆向过程 请求方式 POST 逆向参数 sign c168e4cb76169e90f82d28118dbd24d2 接口请求结果解密 过程分析 根据XHR…

Transformer模型详解01-Word Embedding

文章目录 前言Transformer 整体结构Transformer 的输入单词 Embedding原理CBOW 模型one-hot构建 CBOW 训练数据集构建 CBOW 神经网络训练 CBOW 神经网络 Skip-gram 模型one-hot构建 Skip-gram训练数据集训练 Skip-gram神经网络 Word2Vec实例数据训练保存和加载 前言 Transform…

Jammy@Jetson Orin - Tensorflow Keras Get Started: 000 setup for tutorial

JammyJetson Orin - Tensorflow & Keras Get Started: 000 setup for tutorial 1. 源由2. 搭建环境2.1 安装IDE环境2.2 安装numpy2.3 安装keras2.4 安装JAX2.5 安装tensorflow2.6 安装PyTorch2.7 安装nbdiff 3. 测试DEMO3.1 numpy版本兼容问题3.2 karas API - model.compil…

全国省级金融发展水平数据集(2000-2022年)

01、数据简介 金融发展水平是一个国家或地区经济实力和国际竞争力的重要体现。它反映了金融体系的成熟程度和发展水平&#xff0c;是衡量一个国家或地区经济发展质量的重要指标。金融发展水平的提高&#xff0c;意味着金融体系能够更好地服务实体经济&#xff0c;推动经济增长…

数据结构-二叉树-堆(二)

一、建堆的时间复杂度问题 1、除了向上调整建堆&#xff0c;我们还可以向下调整建堆。不能在根上直接开始向下调整。这里的条件就是左右子树必须都是大堆或者小堆。我们可以倒着往前走&#xff0c;可以从最后一个叶子开始调整。但是从叶子开始调整没有意义。所以我们可以从倒数…

【C++杂货铺】多态

目录 &#x1f308;前言&#x1f308; &#x1f4c1;多态的概念 &#x1f4c1; 多态的定义及实现 &#x1f4c2; 多态的构成条件 &#x1f4c2; 虚函数 &#x1f4c2; 虚函数重写 &#x1f4c2; C11 override 和 final &#x1f4c2; 重载&#xff0c;覆盖&#xff08;重写…

VBA技术资料MF145:清空回收站

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

六、项目发布-- 3. Node.js+express 编写书城首页API

前面那些准备工作做完之后&#xff0c;现在我们就具体来用Node.js来写一个简单的API 基本API编写&#xff1a; 建个后端文件夹&#xff0c;放到vscode打开 我们之前的代码都是前端代码&#xff0c;现在我们来做一个后端的代码。新建一个新的文件夹叫node_new_book&#xff0…

二 SSM整合实操

SSM整合实操 一 依赖管理 数据库准备 mysql8.0.33 CREATE DATABASE mybatis-example;USE mybatis-example;CREATE TABLE t_emp(emp_id INT AUTO_INCREMENT,emp_name CHAR(100),emp_salary DOUBLE(10,5),PRIMARY KEY(emp_id) );INSERT INTO t_emp(emp_name,emp_salary) VALUE…

数字旅游:通过科技赋能,创新旅游服务模式,提供智能化、个性化的旅游服务,满足游客多元化、个性化的旅游需求

目录 一、数字旅游的概念与内涵 二、科技赋能数字旅游的创新实践 1、大数据技术的应用 2、人工智能技术的应用 3、物联网技术的应用 4、云计算技术的应用 三、智能化、个性化旅游服务的实现路径 1、提升旅游服务的智能化水平 2、实现旅游服务的个性化定制 四、数字旅…