Uboot Beaglebone Black Usb驱动分析
在驱动开发中,USB驱动是比较难以理解的部分,也是令驱动开发者比较头疼的,不仅是因为USB包括host端和设备端;USB的协议类型也非常多:数据传输的协议,控制协议,主控制器协议,设备相关的协议,硬件接口的协议。
还要注意的是,设备端还包括多种设备,主要分为五大类:显示器、通信设备(串口一类)、人机输入(键鼠)、音频设备、海量储存(U盘)。
每一种设备的通信协议都不一样,比如海量存储设备,它的通信协议有四个规范:CBI传输、Bulk-Only传输、ATA命令块、UFI命令规范。
而USB的所有系统实现中,UBoot的实现是最为简单易懂的,这点我相信进行过驱动开发的同学都能体会。不仅是因为UBoot的设备树管理简单,而且实现方式基本都是polling,不会用到中断,理解起来方便很多。这里用BBB板子作为示例
首先是初始化,BBB的USB初始化并不包含在board.c文件中,也就是说并不是上电后就自动初始化USB。这点和UBoot的其他很多板子都不一样。而是要利用usb的shell命令进行初始化:在uboot命令行下输入usb回车;如下图所示:
可以看到利用usb start命令可以实现usb的初始化,看下usb start源码实现:
在common/cmd_usb.c中:
static void do_usb_start(void)
{
bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start");
if (usb_init() < 0)
return;
/* Driver model will probe the devices as they are found */
#ifndef CONFIG_DM_USB
#ifdef CONFIG_USB_STORAGE
/* try to recognize storage devices immediately */
usb_stor_curr_dev = usb_stor_scan(1);
#endif
#endif
#ifdef CONFIG_USB_HOST_ETHER
# ifdef CONFIG_DM_ETH
# ifndef CONFIG_DM_USB
# error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
# endif
# else
/* try to recognize ethernet devices immediately */
usb_ether_curr_dev = usb_host_eth_scan(1);
# endif
#endif
#ifdef CONFIG_USB_KEYBOARD
drv_usb_kbd_init();
#endif
}
进入该函数首先调用usb_init函数,该函数在common/usb.c中:
int usb_init(void)
{
void *ctrl;
struct usb_device *dev;
int i, start_index = 0;
int controllers_initialized = 0;
int ret;
dev_index = 0;
asynch_allowed = 1;
usb_hub_reset();
/* first make all devices unknown */
for (i = 0; i < USB_MAX_DEVICE; i++) {
memset(&usb_dev[i], 0, sizeof(struct usb_device));
usb_dev[i].devnum = -1;
}
/* init low_level USB */
for (i = 0; i < CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
/* init low_level USB */
printf("USB%d: ", i);
ret = usb_lowlevel_init(i, USB_INIT_HOST, &ctrl);
if (ret == -ENODEV) { /* No such device. */
puts("Port not available.\n");
controllers_initialized++;
continue;
}
if (ret) { /* Other error. */
puts("lowlevel init failed\n");
continue;
}
/*
* lowlevel init is OK, now scan the bus for devices
* i.e. search HUBs and configure them
*/
controllers_initialized++;
start_index = dev_index;
printf("scanning bus %d for devices... ", i);
ret = usb_alloc_new_device(ctrl, &dev);
if (ret)
break;
/*
* device 0 is always present
* (root hub, so let it analyze)
*/
ret = usb_new_device(dev);
if (ret)
usb_free_device(dev->controller);
if (start_index == dev_index) {
puts("No USB Device found\n");
continue;
} else {
printf("%d USB Device(s) found\n",
dev_index - start_index);
}
usb_started = 1;
}
debug("scan end\n");
/* if we were not able to find at least one working bus, bail out */
if (controllers_initialized == 0)
puts("USB error: all controllers failed lowlevel init\n");
return usb_started ? 0 : -ENODEV;
}
在usb_init函数中会调用usb_lowlevel_init函数,该函数实现了的是ehci的初始化,也就是调用了ehci_hcd_init函数,该函数的具体实现在每个班子的board.c中,这里不做过多分析。
返回到do_usb_start函数中,调用完usb_init函数后,会进行各种设备的检测:
#ifdef CONFIG_USB_STORAGE
如果定义了CONFIG_USB_STORAGE宏定义,那么会调用usb_stor_scan函数对usb海量数据存储设备进行检测,也就是对u盘进行检测:
看看该函数的实现:
在common/usb_storage.c中:
int usb_stor_scan(int mode)
{
unsigned char i;
if (mode == 1)
printf(" scanning usb for storage devices... ");
usb_disable_asynch(1); /* asynch transfer not allowed */
usb_stor_reset();
for (i = 0; i < USB_MAX_DEVICE; i++) {
struct usb_device *dev;
dev = usb_get_dev_index(i); /* get device */
debug("i=%d\n", i);
if (usb_stor_probe_device(dev))
break;
} /* for */
usb_disable_asynch(0); /* asynch transfer allowed */
printf("%d Storage Device(s) found\n", usb_max_devs);
if (usb_max_devs > 0)
return 0;
return -1;
}
该函数中首先调用usb_disable_asynch函数禁用异步传输,然后reset stor设备,然后就是最重要的usb_stor_probe_device函数,也就是探测storage设备:
该函数也在同一个文件中:
static int usb_stor_probe_device(struct usb_device *dev)
{
if (dev == NULL)
return -ENOENT; /* no more devices available */
debug("\n\nProbing for storage\n");
if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
/* OK, it's a storage device. Iterate over its LUNs
* and populate `usb_dev_desc'.
*/
int lun, max_lun, start = usb_max_devs;
max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
for (lun = 0;
lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
lun++) {
struct block_dev_desc *blkdev;
blkdev = &usb_dev_desc[usb_max_devs];
memset(blkdev, '\0', sizeof(block_dev_desc_t));
blkdev->if_type = IF_TYPE_USB;
blkdev->dev = usb_max_devs;
blkdev->part_type = PART_TYPE_UNKNOWN;
blkdev->target = 0xff;
blkdev->type = DEV_TYPE_UNKNOWN;
blkdev->block_read = usb_stor_read;
blkdev->block_write = usb_stor_write;
blkdev->lun = lun;
blkdev->priv = dev;
if (usb_stor_get_info(dev, &usb_stor[start],
&usb_dev_desc[usb_max_devs]) ==
1) {
usb_max_devs++;
debug("%s: Found device %p\n", __func__, dev);
}
}
}
/* if storage device */
if (usb_max_devs == USB_MAX_STOR_DEV) {
printf("max USB Storage Device reached: %d stopping\n",
usb_max_devs);
return -ENOSPC;
}
return 0;
}
这样就实现了usb中大容量设备的检测;然后回到do_usb_start函数,如果定义了CONFIG_USB_HOST_ETHER,那么会调用usb_host_eth_scan函数对usb 网卡设备进行检测,同理如果定义了CONFIG_USB_KEYBOARD,会调用drv_usb_kbd_init函数对人体标准输入设备进行初始化。
全部检测完成后会在shell输出检测结果:
同样,调用usb的其他命令也会执行相应函数,都在cmd_usb.c文件中。不做展开。
posted on 2017-02-26 21:21 sichenzhao 阅读(605) 评论(0) 编辑 收藏 举报