USB——usb root hub注册 - awokezhou/LinuxPage GitHub Wiki
usb root hub 注册
在usb host controller driver 初始化文章中,通过对其hcd添加过程进行分析,发现添加过程做了很多事情,大概有这么几件事情比较重要
-
为root hub数据结构分配内存空间
-
初始化root hub的0号端点
-
设置root hub的父设备为hcd,并将hcd->self->root_hub指针指向root hub设备,以关联hcd和root hub
-
hcd reset
-
注册hcd的中断服务例程
-
hcd start
-
注册root hub
这几件事情的执行顺序和逻辑如下图所示

以下对root hub的注册过程进行详细分析,搞清楚root hub注册过程中代码的执行逻辑,以及root hub在系统运行过程中的作用
register_root_hub函数分析
root hub注册函数的入口是register_root_hub(),代码如下
static int register_root_hub(struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
struct usb_device *usb_dev = hcd->self.root_hub;
const int devnum = 1;
int retval;
usb_dev->devnum = devnum;
usb_dev->bus->devnum_next = devnum + 1;
memset (&usb_dev->bus->devmap.devicemap, 0,
sizeof usb_dev->bus->devmap.devicemap);
set_bit (devnum, usb_dev->bus->devmap.devicemap);
usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
mutex_lock(&usb_bus_list_lock);
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
if (retval != sizeof usb_dev->descriptor) {
mutex_unlock(&usb_bus_list_lock);
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
retval = usb_new_device (usb_dev);
if (retval) {
dev_err (parent_dev, "can't register root hub for %s, %d\n",
dev_name(&usb_dev->dev), retval);
}
mutex_unlock(&usb_bus_list_lock);
if (retval == 0) {
spin_lock_irq (&hcd_root_hub_lock);
hcd->rh_registered = 1;
spin_unlock_irq (&hcd_root_hub_lock);
/* Did the HC die before the root hub was registered? */
if (hcd->state == HC_STATE_HALT)
usb_hc_died (hcd); /* This time clean up */
}
return retval;
}
指针usb_dev指向hcd->self->root_hub,前面分析过,就是root hub设备。指定root hub的设备号为1,总线的下一个设备号为2,猜测如果总线上有其他设备添加上来,设备号就依次加1去分配。这里对一个数据结构devmap进行了初始化,这个结构代表什么含义呢?该结构的定义为
/* USB device number allocation bitmap */
struct usb_devmap {
unsigned long devicemap[128 / (8*sizeof(unsigned long))];
};
定义看起来很奇怪,定义了一个数组,但是数组的长度是多少呢?
假设unsigned long占4个字节,那么数组的每个成员占4个字节,共有128/(84)=4个成员,所有成员共44=16个字节,也就是128bit;
假设unsigned long占8个字节,那么数组的每个成员占8个字节,共有128/(88)=2个成员,所有成员共82=16个字节,也就是128bit。
所以这里其实是定义了128个bit位,这128个bit位代表的是总线上的所有usb设备,因为USB标准规定在一条usb总线上最多可以存在128个设备,devmap就是用来对设备进行一些记录的。代码中调用了set_bit()对devmap进行了设置,因为devnum的值是1,所以现在devmap的值是0x1,也就是最低位为1。这样的操作说明在usb驱动中,并没有把usb host controller设备当作usb总线上的成员,而根集线器是usb总线上的第一个成员。
调用usb_set_device_state()将root hub的状态设置为USB_STATE_ADDRESS。设置0号端点的最大包大小为64字节。然后调用usb_get_device_descriptor()获取设备描述信息,这里关于设备信息获取的部分,因为其实现比较复杂,后续会专门写一篇文章来分析,现在暂且不深入研究。
然后调用了usb_new_device(),下面进入这个函数
usb_new_device
int usb_new_device(struct usb_device *udev)
{
int err;
/* Increment the parent's count of unsuspended children */
if (udev->parent)
usb_autoresume_device(udev->parent);
usb_detect_quirks(udev);
err = usb_enumerate_device(udev); /* Read descriptors */
if (err < 0)
goto fail;
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
udev->devnum, udev->bus->busnum,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* Tell the world! */
announce_device(udev);
/* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device
* notifier chain (used by usbfs and possibly others).
*/
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
usb_stop_pm(udev);
return err;
}
首先判断了其usb父设备是否存在,以前分析过root hub没有父usb设备,只有父device设备是hcd,所以这个判断后的函数不会执行。下一步调用了usb_enumerate_device()函数,我们来看看
static int usb_enumerate_device(struct usb_device *udev)
{
int err;
if (udev->config == NULL) {
err = usb_get_configuration(udev);
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
}
if (udev->wusb == 1 && udev->authorized == 0) {
udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
}
else {
/* read the standard strings and cache them if present */
udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
udev->manufacturer = usb_cache_string(udev,
udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
}
err = usb_enumerate_device_otg(udev);
fail:
return err;
}
第一步判断root hub的config指针是否为空,如果为空执行usb_get_configuration()。因为root hub结构体分配后并没有对config指针赋值过,所以肯定为空。进入usb_get_configuration()函数看看
int usb_get_configuration(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
int ncfg = dev->descriptor.bNumConfigurations;
int result = 0;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
cfgno = 0;
if (dev->authorized == 0) /* Not really an error */
goto out_not_authorized;
result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
if (ncfg < 1) {
dev_err(ddev, "no configurations\n");
return -EINVAL;
}
length = ncfg * sizeof(struct usb_host_config);
dev->config = kzalloc(length, GFP_KERNEL);
if (!dev->config)
goto err2;
length = ncfg * sizeof(char *);
dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
if (!dev->rawdescriptors)
goto err2;
buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
if (!buffer)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
result = 0;
for (; cfgno < ncfg; cfgno++) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s: %d\n", cfgno, "start", result);
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
} else if (result < 4) {
dev_err(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno,
USB_DT_CONFIG_SIZE, result);
result = -EINVAL;
goto err;
}
length = max((int) le16_to_cpu(desc->wTotalLength),
USB_DT_CONFIG_SIZE);
/* Now that we know the length, get the whole thing */
bigbuffer = kmalloc(length, GFP_KERNEL);
if (!bigbuffer) {
result = -ENOMEM;
goto err;
}
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
bigbuffer, length);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "all");
kfree(bigbuffer);
goto err;
}
if (result < length) {
dev_warn(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno, length, result);
length = result;
}
dev->rawdescriptors[cfgno] = bigbuffer;
result = usb_parse_configuration(&dev->dev, cfgno,
&dev->config[cfgno], bigbuffer, length);
if (result < 0) {
++cfgno;
goto err;
}
}
result = 0;
err:
kfree(buffer);
out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)
dev_err(ddev, "out of memory\n");
return result;
}
首先判断authorized是否为0,因为在root hub分配过程中对authorized成员有过赋值,且值为1,所以该条件满足。然后经过了一些简单的判断后,调用kzalloc()为config成员分配内存空间,然后循环设备的所有配置,获取配置描述信息,并用rawdescriptors[]数组指针记录。这里的获取配置描述信息同上面的获取设备描述符信息,先不深究,只用知道是通过一个通道从设备端读出来的就行了。下一步对于每一个配置,调用了usb_parse_configuration()函数,对配置进行解析,后面代码先不进行分析了。主要就是读取接口和端点的信息,然后对root hub相关结构体进行赋值和空间分配。
最重要的步骤来了,调用了device_add()向系统注册设备,调用usb_create_ep_devs()注册端点设备。注意注册的设备是root hub的device设备,前面分析usb core初始化的时候说过,hub驱动注册过的,此时注册了root hub设备,那么驱动的probe函数会被调用。
root hub probe
首先会被调用的接口是usb_probe_interface(),代码如下
static int usb_probe_interface(struct device *dev)
{
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;
dev_dbg(dev, "%s\n", __func__);
intf->needs_binding = 0;
if (usb_device_is_owned(udev))
return -ENODEV;
if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n");
return -ENODEV;
}
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
if (id) {
dev_dbg(dev, "%s - got id\n", __func__);
error = usb_autoresume_device(udev);
if (error)
return error;
/* Interface "power state" doesn't correspond to any hardware
* state whatsoever. We use it to record when it's bound to
* a driver that may start I/0: it's not frozen/quiesced.
*/
mark_active(intf);
intf->condition = USB_INTERFACE_BINDING;
/* The interface should always appear to be in use
* unless the driver suports autosuspend.
*/
atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);
/* Carry out a deferred switch to altsetting 0 */
if (intf->needs_altsetting0) {
error = usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
if (error < 0)
goto err;
intf->needs_altsetting0 = 0;
}
error = driver->probe(intf, id);
if (error)
goto err;
intf->condition = USB_INTERFACE_BOUND;
usb_autosuspend_device(udev);
}
return error;
err:
mark_quiesced(intf);
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);
usb_autosuspend_device(udev);
return error;
}