uboot usb设备驱动

文章目录

    • DTS中定义
    • usb driver
    • bind
    • fastboot
    • fastboot命令处理
    • fastboot触发

介绍usb device设备驱动

uboot在init_dm中会扫描dtb和代码中driver进行匹配,匹配成功就调用driver驱动进行bind
以dwc3为例进行介绍

DTS中定义

usb0: usb0@ff9d0000 {
	#address-cells = <2>;
	#size-cells = <2>;
	status = "disabled";
	compatible = "xlnx,zynqmp-dwc3"; //匹配的compatible 
	reg = <0x0 0xff9d0000 0x0 0x100>;
	clock-names = "bus_clk", "ref_clk";
	power-domains = <&pd_usb0>;
	ranges;
	nvmem-cells = <&soc_revision>;
	nvmem-cell-names = "soc_revision";

	dwc3_0: dwc3@fe200000 {
		compatible = "snps,dwc3";
		status = "disabled";
		reg = <0x0 0xfe200000 0x0 0x40000>;
		interrupt-parent = <&gic>;
		interrupts = <0 65 4>, <0 69 4>;
		#stream-id-cells = <1>;
		iommus = <&smmu 0x860>;
		snps,quirk-frame-length-adjustment = <0x20>;
		snps,refclk_fladj;
		snps,enable_guctl1_resume_quirk;
		snps,enable_guctl1_ipd_quirk;
		snps,xhci-stream-quirk;
		/* dma-coherent; */
	};
};

usb1: usb1@ff9e0000 {
	#address-cells = <2>;
	#size-cells = <2>;
	status = "disabled";
	compatible = "xlnx,zynqmp-dwc3";
	reg = <0x0 0xff9e0000 0x0 0x100>;
	clock-names = "bus_clk", "ref_clk";
	power-domains = <&pd_usb1>;
	ranges;
	nvmem-cells = <&soc_revision>;
	nvmem-cell-names = "soc_revision";

	dwc3_1: dwc3@fe300000 {
		compatible = "snps,dwc3";
		status = "disabled";
		reg = <0x0 0xfe300000 0x0 0x40000>;
		interrupt-parent = <&gic>;
		interrupts = <0 70 4>, <0 74 4>;
		#stream-id-cells = <1>;
		iommus = <&smmu 0x861>;
		snps,quirk-frame-length-adjustment = <0x20>;
		snps,refclk_fladj;
		snps,enable_guctl1_resume_quirk;
		snps,enable_guctl1_ipd_quirk;
		snps,xhci-stream-quirk;
		/* dma-coherent; */
	};
};

usb driver

drivers\usb\dwc3\dwc3-generic.c

用于match的compatible 
static const struct udevice_id dwc3_generic_ids[] = {
	{ .compatible = "xlnx,zynqmp-dwc3" },
	{ }
};

定义了driver
U_BOOT_DRIVER(dwc3_generic_wrapper) = {
	.name	= "dwc3-generic-wrapper",
	.id	= UCLASS_MISC,
	.of_match = dwc3_generic_ids,
	.bind = dwc3_generic_bind,
};

bind

compatible = “xlnx,zynqmp-dwc3” ,dts和driver匹配成功,定义driver->bind,即dwc3_generic_bind

static int dwc3_generic_bind(struct udevice *parent)
{
	const void *fdt = gd->fdt_blob;
	int node;
	int ret;

	遍历dts中usb device,一个soc可能包含多个usb控制器
	for (node = fdt_first_subnode(fdt, parent->of_offset); node > 0;
	     node = fdt_next_subnode(fdt, node)) {
		const char *name = fdt_get_name(fdt, node, NULL);
		enum usb_dr_mode dr_mode;
		struct udevice *dev;

		debug("%s: subnode name: %s\n", __func__, name);
		if (strncmp(name, "dwc3@", 4))
			continue;

		dr_mode = usb_get_dr_mode(node);
		//usb 控制器模式,device模式或主机模式
		switch (dr_mode) {
		case USB_DR_MODE_PERIPHERAL://device模式
		case USB_DR_MODE_OTG://otg模式
			
			//进一步进行device和driver匹配,驱动name为 "dwc3-generic-peripheral",
			ret = device_bind_driver_to_node(parent,
							 "dwc3-generic-peripheral",
							 name, node, &dev);
			
			break;
		case USB_DR_MODE_HOST:
			debug("%s: dr_mode: HOST\n", __func__);
			ret = device_bind_driver_to_node(parent,
							 "dwc3-generic-host",
							 name, node, &dev);
			
			break;
		default:
			break;
		};
	}

	return 0;
}

device_bind_driver_to_node–》device_bind–》device_bind_common:匹配了device和驱动,调用uclass-bind和driver bind。

"dwc3-generic-peripheral"驱动

U_BOOT_DRIVER(dwc3_generic_peripheral) = {
	.name	= "dwc3-generic-peripheral",
	.id	= UCLASS_USB_DEV_GENERIC,
	.ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata,
	.probe = dwc3_generic_peripheral_probe,
	.remove = dwc3_generic_peripheral_remove,
	.bind = dwc3_generic_peripheral_bind,
	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
	.priv_auto_alloc_size = sizeof(struct dwc3),
	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
};

dwc3_generic_peripheral_bind–》device_probe–》dev->drv->probe》dwc3_generic_peripheral_probe
调用了dwc3_generic_peripheral_probe–》dwc3_init进行dwc3初始化

–》dwc3_core_init_mode–》dwc3_gadget_init–》usb_add_gadget_udc
初始了gadget功能,并向udc core注册。
具体初始化过程不再描述。
完成了底层usb device和驱动初始化,上层抽象功能在进行初始化,比如,网络,鼠标等等。

fastboot

以fastboot为例,分析function驱动初始注册。
f_fastboot.c
DECLARE_GADGET_BIND_CALLBACK(usb_dnl_fastboot, fastboot_add);
声明定义了g_dnl_bind_callback 结构的fastboot function功能。

/*
 * @usb_fname: unescaped USB function name
 * @callback_ptr: bind callback, one per function name
 */
#define DECLARE_GADGET_BIND_CALLBACK(usb_fname, callback_ptr) \
	ll_entry_declare(struct g_dnl_bind_callback, \
			__usb_function_name_##usb_fname, \
			g_dnl_bind_callbacks) = { \
				.usb_function_name = #usb_fname, \
				.fptr = callback_ptr \
			}

typedef int (*g_dnl_bind_callback_f)(struct usb_configuration *);

/* used in Gadget downloader callback linker list */
struct g_dnl_bind_callback {
	const char *usb_function_name;
	g_dnl_bind_callback_f fptr;
};

do_fastboot中调用注册了fastboot驱动,

do_fastboot--g_dnl_register("usb_dnl_fastboot");--》
g_dnl_driver.name = name;
usb_composite_register(&g_dnl_driver);--》
composite = driver;
usb_gadget_register_driver(&composite_driver);
--》usb_gadget_probe_driver
找到一个udc,前面usb初始化已经向usb core注册了udc
list_for_each_entry(udc, &udc_list, list) {
		/* For now we take the first one */
		if (!udc->driver)
			goto found;
	}
	ret = udc_bind_to_driver(udc, driver);
	---》
	driver->bind(udc->gadget); 回调g_dnl_bind
	usb_gadget_udc_start(udc); 开启usb func功能,触发usb device和usb host交互
	usb_gadget_connect(udc->gadget);

g_dnl_bind–》g_dnl_config_register

一些usb 设备的config
	config->label = name;
	config->bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER;
	config->bConfigurationValue = CONFIGURATION_NUMBER;
	config->iConfiguration = STRING_USBDOWN;
	config->bind = g_dnl_do_config;
usb_add_config--》config->bind(config);--》 g_dnl_do_config
static int g_dnl_do_config(struct usb_configuration *c)
{
	const char *s = c->cdev->driver->name;
	struct g_dnl_bind_callback *callback = g_dnl_bind_callback_first();

	for (; callback != g_dnl_bind_callback_end(); callback++)
		if (!strcmp(s, callback->usb_function_name))
			return callback->fptr(c); //回调所有dnl类型的function功能
	return -ENODEV;
}
--》fastboot_add进行functiong功能注册
以上过程就是function对应设备接口,配置和端点注册过程
static inline int usb_gadget_udc_start(struct usb_udc *udc)
{
	return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
}

fastboot_add功能添加

static int fastboot_add(struct usb_configuration *c)
{
	struct f_fastboot *f_fb = fastboot_func;
	int status;

	debug("%s: cdev: 0x%p\n", __func__, c->cdev);

	if (!f_fb) {
		f_fb = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_fb));
		if (!f_fb)
			return -ENOMEM;

		fastboot_func = f_fb;
		memset(f_fb, 0, sizeof(*f_fb));
	}

	f_fb->usb_function.name = "f_fastboot";
	f_fb->usb_function.bind = fastboot_bind;
	f_fb->usb_function.unbind = fastboot_unbind;
	f_fb->usb_function.set_alt = fastboot_set_alt;
	f_fb->usb_function.disable = fastboot_disable;
	f_fb->usb_function.strings = fastboot_strings;

	status = usb_add_function(c, &f_fb->usb_function);

	return status;
}

在接口配置设置时回调f_fb->usb_function.set_alt = fastboot_set_alt;
fastboot_set_alt中配置了端点回调函数,并且使能了端点。
f_fb->out_req->complete = rx_handler_command; 从host接收到usb包,回调函数
f_fb->in_req->complete = fastboot_complete; 发送一个usb包,回调函数

fastboot命令处理

rx_handler_command中解析接收到usb数据,并匹配是否含有定义的fastboot协议命令

static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
{
	char *cmdbuf = req->buf;
	void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL;
	int i;


    匹配命令
	for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) {
		if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) {
			func_cb = cmd_dispatch_info[i].cb;
			break;
		}
	}

	
	
		if (req->actual < req->length) {
			u8 *buf = (u8 *)req->buf;
			buf[req->actual] = 0;
			func_cb(ep, req); //处理命令

	}

	*cmdbuf = '\0';
	req->actual = 0;
	usb_ep_queue(ep, req, 0);
}
static const struct cmd_dispatch_info cmd_dispatch_info[] = {
	{
		.cmd = "reboot",
		.cb = cb_reboot,
	}, {
		.cmd = "getvar:",
		.cb = cb_getvar,
	}, {
		.cmd = "download:",
		.cb = cb_download,
	}, {
		.cmd = "boot",
		.cb = cb_boot,
	}, {
		.cmd = "continue",
		.cb = cb_continue,
	},
#ifdef CONFIG_FASTBOOT_FLASH
	{
		.cmd = "flash",
		.cb = cb_flash,
	}, {
		.cmd = "erase",
		.cb = cb_erase,
	},
#endif
	{
		.cmd = "oem",
		.cb = cb_oem,
	},
};

fastboot触发

上一节分析了fastboot功能的注册。
命令fastboot触发fastboot功能进行初始化注册,并继续后续处理。

U_BOOT_CMD(
	fastboot, 2, 1, do_fastboot,
	"use USB Fastboot protocol",
	"\n"
	"    - run as a fastboot usb device"
);
static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
	int controller_index;
	char *usb_controller;
	int ret;

	if (argc < 2)
		return CMD_RET_USAGE;

	usb_controller = argv[1];
	controller_index = simple_strtoul(usb_controller, NULL, 0);

	ret = board_usb_init(controller_index, USB_INIT_DEVICE);
	if (ret) {
		error("USB init failed: %d", ret);
		return CMD_RET_FAILURE;
	}

	g_dnl_clear_detach();
	ret = g_dnl_register("usb_dnl_fastboot");
	if (ret)
		return ret;

	if (!g_dnl_board_usb_cable_connected()) {
		puts("\rUSB cable not detected.\n" \
		     "Command exit.\n");
		ret = CMD_RET_FAILURE;
		goto exit;
	}

   前面注册usb fastboot驱动
   下面是和host交互命令处理
	while (1) {
		if (g_dnl_detach())
			break;
		if (ctrlc())
			break;
		usb_gadget_handle_interrupts(controller_index); 中断处理,处理event buf,回调上面的out_req->complete和in_req->complete
	}

	ret = CMD_RET_SUCCESS;


	return ret;
}

你可能感兴趣的:(uboot)