dev_err(hcd->self.controller,
"request interrupt %d failed\n", irqnum);
goto err_request_irq;
}
hcd->irq = irqnum;
dev_info(hcd->self.controller, "irq %d, %s 0xllx\n", irqnum,
(hcd->driver->flags & HCD_MEMORY) ?
"io mem" : "io base",
(unsigned long long)hcd->rsrc_start);
} else {
hcd->irq = -1;
if (hcd->rsrc_start)
dev_info(hcd->self.controller, "%s 0xllx\n",
(hcd->driver->flags & HCD_MEMORY) ?
"io mem" : "io base",
(unsigned long long)hcd->rsrc_start);
}
if ((retval = hcd->driver->start(hcd)) < 0) {
dev_err(hcd->self.controller, "startup error %d\n", retval);
goto err_hcd_driver_start;
}
设置root_hub的电流
rhdev->bus_mA = min(500u, hcd->power_budget);
这里就是重点的。开始注册这个root_hub
开始建立了这设备树,然后调用usb_new_device()注册这的USB设备
if ((retval = register_root_hub(hcd)) != 0)
goto err_register_root_hub;
创建总线属性文件authorized_default。
retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
if (retval < 0) {
printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
retval);
goto error_create_attr_group;
}
if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);
return retval;
error_create_attr_group:
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
mutex_unlock(&usb_bus_list_lock);
err_register_root_hub:
hcd->driver->stop(hcd);
err_hcd_driver_start:
if (hcd->irq >= 0)
free_irq(irqnum, hcd);
err_request_irq:
err_hcd_driver_setup:
hcd->self.root_hub = NULL;
usb_put_dev(rhdev);
err_allocate_root_hub:
usb_deregister_bus(&hcd->self);
err_register_bus:
hcd_buffer_destroy(hcd);
return retval;
}
下面具体分析一些hcd_buffer_create()
说到这个函数,我们可以简单分析一下整个USB系统使用的DMA内存技术
相关的函数有hcd_buffer_create()hcd_buffer_destroy()hcd_buffer_alloc()hcd_buffer_free()
这个几个函数是成对的。
static const size_t pool_max [HCD_BUFFER_POOLS] = {
32,
128,
512,
PAGE_SIZE / 2
};
int hcd_buffer_create(struct usb_hcd *hcd)
{
char name[16];
int i, size;
if (!hcd->self.controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM))
return 0;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
size = pool_max[i];
if (!size)
continue;
snprintf(name, sizeof name, "buffer-%d", size);
hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
size, size, 0);
if (!hcd->pool [i]) {
hcd_buffer_destroy(hcd);
return -ENOMEM;
}
}
return 0;
}
参数hcd 是为哪个控制器创建一致性DMA内存。dma_pool_create()创建了四个一致性DMA内存,返回的是这四个不同大小的内存池的地址,分别赋值给hcd->pool[0],hcd->pool[1],hcd->pool[2],hcd->pool[3]。
既然分配就有释放hcd_buffer_destroy()。这个函数就是干这个活得。
内存池创建了,那就有分配
hcd_buffer_alloc() 就是从刚创建的内存池中获取。
void *hcd_buffer_alloc(
struct usb_bus *bus,
size_t size,
gfp_t mem_flags,
dma_addr_t *dma
)
{
struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
if (!bus->controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM)) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
}
return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
}
先看下参数:
bus :我们之前说了,一条usb总线对应一个主机控制器。
size :需要的这个buffer多大
mem_flags :这个不用看都知道是干什么的了,gfp_t 分配内存的标志
dma :DMA总线地址,是给设备用的。调用了这个函数后这个BUFFER的总线地址就会传递给这个参数。
函数中先判断是否设备支持DMA传输,如果不支持,那么就是用PIO吧。否则进入一个for循环。判断申请的buffer是否小于内存池的大小。如果大于了,当然没法获取了。所以就只能是用另外一个函数dma_alloc_coherent()申请一致性一致性DMA内存.
最后这个返回的是一个虚拟地址,给内核空间使用的。这样设备就能和内核空间传递数据了。
过来详细的而说下usb_register_bus()
static int usb_register_bus(struct usb_bus *bus)
{
int result = -E2BIG;
int busnum;
mutex_lock(&usb_bus_list_lock);
busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
if (busnum >= USB_MAXBUS) {
printk (KERN_ERR "%s: too many buses\n", usbcore_name);
goto error_find_busnum;
}
set_bit (busnum, busmap.busmap);
bus->busnum = busnum;
list_add (&bus->bus_list, &usb_bus_list);
mutex_unlock(&usb_bus_list_lock);
usb_notify_add_bus(bus);
dev_info (bus->controller, "new USB bus registered, assigned bus "
"number %d\n", bus->busnum);
return 0;
error_find_busnum:
mutex_unlock(&usb_bus_list_lock);
return result;
}
#define USB_MAXBUS 64
struct usb_busmap {
unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];
};
static struct usb_busmap busmap;
先前简单的说了下这个函数的作用。
我们知道sizeof (unsigned long)的值是4.所以static struct usb_busmap busmap;
可以写成这样
struct usb_busmap {
unsigned long busmap [2];
};
所以busmap[2]有64位。每一位表示一条总线。假如说第5位置一了,那么USB_BUS
成员就busnum就为5.
当我们注册一条USB总线的时候,先在这个位图中找到一个第一个不为0的位赋值给busnum.并且把usb_bus的bus_list加到usb_bus_list链表头usb_notify_add_bus()的作用是在SYS文件系统上建立相关的信息。这个通知链是在USB系统初始化的时候注册的。
接下来是usb_alloc_dev()函数。这个函数很长。
usb_alloc_dev(NULL, &hcd->self, 0)
第一个参数是HULL,因为是root_hub。所以它处于金字塔的最顶端,它没有parent.第二个参数是这个设备所在的总线。第三个参数是0.一样,root_hub 忽略该位。
下面是整个函数
struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
增加hcd的也引用计数
if (!usb_get_hcd(bus_to_hcd(bus))) {
kfree(dev);
return NULL;
}
if (usb_hcd->driver->alloc_dev && parent &&
!usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
usb_put_hcd(bus_to_hcd(bus)); 增加hcd的也引用计数
kfree(dev);
return NULL;
}
device_initialize(&dev->dev);设备模型的dev初始化
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.groups = usb_device_groups;
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
第三个参数为false时不会复位这个端点。第二个参数是端点usb_host_endpoint。通过一系列的判断,完善参数一的 struct usb_host_endpoint *ep_in[16];
struct usb_host_endpoint *ep_out[16];这个两个指针数组。在这个上下文中是完善ep_out[0],ep_int[0].
usb_enable_endpoint(dev, &dev->ep0, false);
dev->can_submit = 1;
是root_hub就会运行这行
if (unlikely(!parent)) {
dev->devpath[0] = '0';
dev->route = 0;
dev->dev.parent = bus->controller;
dev_set_name(&dev->dev, "usb%d", bus->busnum);
在SYS文件系统的sys/bus/usb/ 下会出现usb1.因为只有一条总线
root_hub = 1;
} else {
设备接在root_hub运行这里
if (parent->devpath[0] == '0') {
snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
dev->route = 0;
} else {在我的板上不会运行这里,因为我没接集线器,这里运行时因为设备接在某个集线器上
snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
if (port1 < 15)
dev->route = parent->route +
(port1 << ((parent->level - 1)*4));
else
dev->route = parent->route +
(15 << ((parent->level - 1)*4));
}
dev->dev.parent = &parent->dev;
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
运行到这里,我们可以确定一些问题了。当我把设备U盘插入到ROOT_HUB上时,那么会在sys/bus/usb/usb 出现 1-1:第一个1表示总线,第二个1表示接在了root_hub的第一个端口上。
}
dev->portnum = port1;
dev->bus = bus;
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
#ifdef CONFIG_PM
mutex_init(&dev->pm_mutex);
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
INIT_WORK(&dev->autoresume, usb_autoresume_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
dev->connect_time = jiffies;
dev->active_duration = -jiffies;
#endif
if (root_hub)
dev->authorized = 1;
else {
dev->authorized = usb_hcd->authorized_default;
dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
}
return dev;
}
最后一个函数register_root_hub()。