usb host分析

1:usb入口函数:usb_init

参考文档:

https://blog.csdn.net/chenliang0224/article/details/79692045

注册一个总线bus_register:bus_type:usb_bus_type

调用usb_hub_init()用来创建hub初始化,注册一个基于usb的urb的usb_driver结构体,usb_driver的open函数hub_probe:

hub_probe中调用hub_configure函数。

每当设备连接到usb接口时,usb总线在查询hub状态信息会触发hub的中断hub_irq,利用kick_khubd将hub结构通过event_list添加到khubd的队列hub_event_list,然后唤醒khudb,进入hub_e_vents函数,处理khudb事件队列,从khubd的hub_event_list中的每个usb_hub数据结构。

创建一个hub_thread线程,调用hub_events();调用hub_port_connect_change(物理逻辑更改就调用该函数)

usb_alloc_dev()然后对每个函数调用usb的设备构造函数hub_port_init(复位usb3.0得到设备描述符),

检查设备的运行速度check_highspeed()

usb_new_device()创建一个新的device设备。

 Hub_probe流程图:

 关于usb_host的驱动:(ehci)

usb_register_device_driver(&usb_generic_driver, THIS_MODULE); 注册一个设备驱动:usb_generic_driver

usb_device_driver:定义一个usb设备驱动 

ehci设备注册:

static struct platform_device hiusb_ehci_platdev = {
    .name = "hiusb-ehci", //匹配设备驱动
    .id = 0,
    .dev = {
        .platform_data     = NULL,
        .dma_mask          = &usb_dmamask,
        .coherent_dma_mask = DMA_BIT_MASK(32),
        .release           = usb_ehci_platdev_release,
    },
    .num_resources = ARRAY_SIZE(hiusb_ehci_res),
    .resource      = hiusb_ehci_res,
};

设备资源:

static struct resource hiusb_ehci_res[] = {
    [0] = {
        .start = CONFIG_HIUSB_EHCI_IOBASE,
        .end   = CONFIG_HIUSB_EHCI_IOBASE
            + CONFIG_HIUSB_EHCI_IOSIZE - 1,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = CONFIG_HIUSB_EHCI_IRQNUM,
        .end   = CONFIG_HIUSB_EHCI_IRQNUM,
        .flags = IORESOURCE_IRQ,
    },
};

平台驱动注册:

static struct platform_driver hiusb_ehci_hcd_driver = {
    .probe         = hiusb_ehci_hcd_drv_probe,
    .remove        = hiusb_ehci_hcd_drv_remove,
    .shutdown      = usb_hcd_platform_shutdown,
    .driver = {
        .name  = "hiusb-ehci",
        .owner = THIS_MODULE,
        .pm    = HIUSB_EHCI_PMOPS,
    }
};

平台设备和平台驱动通过hiusb-ehci匹配,匹配成功调用平台驱动的hiusb_ehci_hcd_drv_probe函数

平台探测函数

static int hiusb_ehci_hcd_drv_probe(struct platform_device *pdev)
{
    struct usb_hcd *hcd;
    struct ehci_hcd *ehci;
    struct resource *res;
    int ret;

    if (usb_disabled())
        return -ENODEV;

    if (pdev->resource[1].flags != IORESOURCE_IRQ) {
        pr_debug("resource[1] is not IORESOURCE_IRQ");
        return -ENOMEM;
    }
    hcd = usb_create_hcd(&hiusb_ehci_hc_driver, &pdev->dev, "hiusb-ehci");
    if (!hcd)
        return -ENOMEM;

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    hcd->rsrc_start = res->start;
    hcd->rsrc_len = resource_size(res);

    if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
        pr_debug("request_mem_region failed");
        ret = -EBUSY;
        goto err1;
    }

    hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
    if (!hcd->regs) {
        pr_debug("ioremap failed");
        ret = -ENOMEM;
        goto err2;
    }

    hiusb_start_hcd();

    ehci = hcd_to_ehci(hcd);
    ehci->caps = hcd->regs;
    ehci->regs = hcd->regs +
        HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));

    /* cache this readonly data; minimize chip reads */
    ehci->hcs_params = readl(&ehci->caps->hcs_params);

    ret = usb_add_hcd(hcd, pdev->resource[1].start,
              IRQF_DISABLED | IRQF_SHARED);
    if (ret == 0) {
        platform_set_drvdata(pdev, hcd);
        return ret;
    }

    hiusb_stop_hcd();
    iounmap(hcd->regs);
err2:
    release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
    usb_put_hcd(hcd);
    return ret;
}

探测函数通过usb_create_hcd调用了ehci的主机控制驱动:

static const struct hc_driver hiusb_ehci_hc_driver = {
    .description        = hcd_name, //hcd主机控制器名称
    .product_desc        = "HIUSB EHCI",
    .hcd_priv_size        = sizeof(struct ehci_hcd), //hcd主机控制器大小

    /*
     * generic hardware linkage
     */
    .irq            = ehci_irq,//ehci的硬件中断
    .flags            = HCD_MEMORY | HCD_USB2, //usb2.0

    /*
     * basic lifecycle operations
     *
     * FIXME -- ehci_init() doesn't do enough here.
     * See ehci-ppc-soc for a complete implementation.
     */
    .reset            = hiusb_ehci_setup, //复位主机
    .start            = ehci_run,   //启动主机控制器
    .stop            = ehci_stop,
    .shutdown        = ehci_shutdown,

    /*
     * managing i/o requests and associated device resources
     */
    .urb_enqueue        = ehci_urb_enqueue,  //urb请求队列
    .urb_dequeue        = ehci_urb_dequeue, //释放队列
    .endpoint_disable    = ehci_endpoint_disable, //端点禁止
    .endpoint_reset        = ehci_endpoint_reset,

    /*
     * scheduling support
     */
    .get_frame_number    = ehci_get_frame,

    /*
     * root hub support
     */
    .hub_status_data    = ehci_hub_status_data, //获取hub状态
    .hub_control        = ehci_hub_control,
    .bus_suspend        = ehci_bus_suspend,
    .bus_resume        = ehci_bus_resume,
    .relinquish_port    = ehci_relinquish_port,
    .port_handed_over    = ehci_port_handed_over,

    .clear_tt_buffer_complete    = ehci_clear_tt_buffer_complete,
};

usb_create_hcd:usb主机控制器创建(hcd.c)

struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
        struct device *dev, const char *bus_name,
        struct usb_hcd *primary_hcd)
{
    struct usb_hcd *hcd;

    hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
    if (!hcd) {
        dev_dbg (dev, "hcd alloc failed\n");
        return NULL;
    }
    if (primary_hcd == NULL) {
        hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
                GFP_KERNEL);
        if (!hcd->bandwidth_mutex) {
            kfree(hcd);
            dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
            return NULL;
        }
        mutex_init(hcd->bandwidth_mutex);
        dev_set_drvdata(dev, hcd);
    } else {
        hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
        hcd->primary_hcd = primary_hcd;
        primary_hcd->primary_hcd = primary_hcd;
        hcd->shared_hcd = primary_hcd;
        primary_hcd->shared_hcd = hcd;
    }

    kref_init(&hcd->kref);

  1.     usb_bus_init(&hcd->self); //usb_hcd作为一个总线初始化

    hcd->self.controller = dev;
    hcd->self.bus_name = bus_name;
    hcd->self.uses_dma = (dev->dma_mask != NULL);

    init_timer(&hcd->rh_timer);
    hcd->rh_timer.function = rh_timer_func;
    hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_USB_SUSPEND
    INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif

    hcd->driver = driver;//usb_hcd主机控制器绑定主机控制器驱动driver
    hcd->speed = driver->flags & HCD_MASK;
    hcd->product_desc = (driver->product_desc) ? driver->product_desc :
            "USB Host Controller";
    return hcd;
}

a> struct usb_hcd usb主机控制器

b> struct hc_driver 主机控制器驱动

c> struct usb_bus self 总线

d> struct usb_device *rhdev 设备

usb主机控制器添加
int usb_add_hcd(struct usb_hcd *hcd,
        unsigned int irqnum, unsigned long irqflags)
{
    int retval;
    struct usb_device *rhdev;

    dev_info(hcd->self.controller, "%s\n", hcd->product_desc);

    /* Keep old behaviour if authorized_default is not in [0, 1]. */
    if (authorized_default < 0 || authorized_default > 1)
        hcd->authorized_default = hcd->wireless? 0 : 1;
    else
        hcd->authorized_default = authorized_default;
    set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

    /* HC is in reset state, but accessible.  Now do the one-time init,
     * bottom up so that hcds can customize the root hubs before khubd
     * starts talking to them.  (Note, bus id is assigned early too.)
     */
    if ((retval = hcd_buffer_create(hcd)) != 0) { //分配一个dma池:具体dma的分配可以查看该函数
        dev_dbg(hcd->self.controller, "pool alloc failed\n");
        return retval;
    }

    if ((retval = usb_register_bus(&hcd->self)) < 0)//注册一个usb_bus
        goto err_register_bus;

    if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { //分配一个dev设备
        dev_err(hcd->self.controller, "unable to allocate root hub\n");
        retval = -ENOMEM;
        goto err_allocate_root_hub;
    }
    hcd->self.root_hub = rhdev;

    switch (hcd->speed) {
    case HCD_USB11:
        rhdev->speed = USB_SPEED_FULL;
        break;
    case HCD_USB2:
        rhdev->speed = USB_SPEED_HIGH;
        break;
    case HCD_USB3:
        rhdev->speed = USB_SPEED_SUPER;
        break;
    default:
        retval = -EINVAL;
        goto err_set_rh_speed;
    }

    /* wakeup flag init defaults to "everything works" for root hubs,
     * but drivers can override it in reset() if needed, along with
     * recording the overall controller's system wakeup capability.
     */
    device_set_wakeup_capable(&rhdev->dev, 1);

    /* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
     * registered.  But since the controller can die at any time,
     * let's initialize the flag before touching the hardware.
     */
    set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);

    /* "reset" is misnamed; its role is now one-time init. the controller
     * should already have been reset (and boot firmware kicked off etc).
     */
    if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
        dev_err(hcd->self.controller, "can't setup\n");
        goto err_hcd_driver_setup;
    }
    hcd->rh_pollable = 1;

    /* NOTE: root hub and controller capabilities may not be the same */
    if (device_can_wakeup(hcd->self.controller)
            && device_can_wakeup(&hcd->self.root_hub->dev))
        dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");

    /* enable irqs just before we start the controller,
     * if the BIOS provides legacy PCI irqs.
     */
    if (usb_hcd_is_primary_hcd(hcd) && irqnum) {
        retval = usb_hcd_request_irqs(hcd, irqnum, irqflags);
        if (retval)
            goto err_request_irq;
    }

    hcd->state = HC_STATE_RUNNING;
    retval = hcd->driver->start(hcd);
    if (retval < 0) {
        dev_err(hcd->self.controller, "startup error %d\n", retval);
        goto err_hcd_driver_start;
    }

    /* starting here, usbcore will pay attention to this root hub */
    if ((retval = register_root_hub(hcd)) != 0)
        goto err_register_root_hub;

    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(hcd))
        usb_hcd_poll_rh_status(hcd);

    /*
     * Host controllers don't generate their own wakeup requests;
     * they only forward requests from the root hub.  Therefore
     * controllers should always be enabled for remote wakeup.
     */
    device_wakeup_enable(hcd->self.controller);
    return retval;

error_create_attr_group:
    clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
    if (HC_IS_RUNNING(hcd->state))
        hcd->state = HC_STATE_QUIESCING;
    spin_lock_irq(&hcd_root_hub_lock);
    hcd->rh_registered = 0;
    spin_unlock_irq(&hcd_root_hub_lock);

#ifdef CONFIG_USB_SUSPEND
    cancel_work_sync(&hcd->wakeup_work);
#endif
    mutex_lock(&usb_bus_list_lock);
    usb_disconnect(&rhdev);        /* Sets rhdev to NULL */
    mutex_unlock(&usb_bus_list_lock);
err_register_root_hub:
    hcd->rh_pollable = 0;
    clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
    del_timer_sync(&hcd->rh_timer);
    hcd->driver->stop(hcd);
    hcd->state = HC_STATE_HALT;
    clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
    del_timer_sync(&hcd->rh_timer);
err_hcd_driver_start:
    if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0)
        free_irq(irqnum, hcd);
err_request_irq:
err_hcd_driver_setup:
err_set_rh_speed:
    usb_put_dev(hcd->self.root_hub);
err_allocate_root_hub:
    usb_deregister_bus(&hcd->self);
err_register_bus:
    hcd_buffer_destroy(hcd);
    return retval;
}

usb_alloc_dev()分配一个dev设备:

struct usb_device *usb_alloc_dev(struct usb_device *parent,
                 struct usb_bus *bus, unsigned port1)

parent表示hub设备被连接,如果为空,则创建一个root的hub

创建dma池

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

usb_hcd_request_irqs():申请一个hcd中断定时器

在usb_add_hcd创建usb_hcd_request_irqs:用来创建和调用中断(中断的创建)

static int usb_hcd_request_irqs(struct usb_hcd *hcd,
        unsigned int irqnum, unsigned long irqflags)
{
    int retval;

    if (hcd->driver->irq) {

        /* IRQF_DISABLED doesn't work as advertised when used together
         * with IRQF_SHARED. As usb_hcd_irq() will always disable
         * interrupts we can remove it here.
         */
        if (irqflags & IRQF_SHARED)
            irqflags &= ~IRQF_DISABLED;

        snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
                hcd->driver->description, hcd->self.busnum);
        retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
                hcd->irq_descr, hcd);
        if (retval != 0) {
            dev_err(hcd->self.controller,
                    "request interrupt %d failed\n",
                    irqnum);
            return retval;
        }
        hcd->irq = irqnum;
        dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum,
                (hcd->driver->flags & HCD_MEMORY) ?
                    "io mem" : "io base",
                    (unsigned long long)hcd->rsrc_start);
    } else {
        hcd->irq = 0;
        if (hcd->rsrc_start)
            dev_info(hcd->self.controller, "%s 0x%08llx\n",
                    (hcd->driver->flags & HCD_MEMORY) ?
                    "io mem" : "io base",
                    (unsigned long long)hcd->rsrc_start);
    }
    return 0;
}

注册一个root的hub分配器register_root_hub():中的函数创建和流程

在register_root_hub()中创建usb_get_device_descriptor()

创建一个usb设备:usb_new_device()

//在usb_new_device中调用usb_enumerate_device()函数中枚举设置

获取usb的配置信息usb_get_configuration,给usb设备分配一个编号,获取设备描述符usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE),因为不知道设备描述符的里面有多少配置,配置有多少个接口,所以这里直接读取USB_DT_DEVICE_SIZE,而这个字节长度恰好对应设备描述符的基金额狗踢长度。

读取配置参数usb_parse_configuration

解析接口信息:usb_parse_interface

解析端点函数usb_parse_endpoint

端点的主要 工作:根据不同的usb,传输不同的字节数,

在通过如下函数输出控制信息功能:announce_device

通过platform总线完成ehci设备和驱动的匹配探测函数,完成主机控制器,和寄存器资源分配,分配一个hcd主机控制器(是否使用dma池),增加主句控制器到usb 总线上,注册一个跟hub,期间包含最重要的部分,在获取接口信息时分两次读取,第一次读取固定长度的接口信息,第二次根据第一个的描述符里面的信息长度读取整个接口信息,根据借口信息解析端点,最后将该主机控制器的根hub注册到usb总线上。

猜你喜欢

转载自blog.csdn.net/zuodenghuakai/article/details/83903405