当前位置:   article > 正文

usb_host重新分析(1)_usb_host_install

usb_host_install

写在前面,最近在做Intel 的usb gadget驱动的处理,想着重新梳理一遍usb host驱动,用的是非公司的版本,所以本次就梳理一下流程,大体流程基本一致。

1:usb_init:(/driver/usb/core/usb.c)

usb驱动框架的入口函数,简单些,注册usb的子系统,注册一个总线bus_register:bus_type:usb_bus_type,主要接口流程调用usb_hub_init()用来创建hub初始化,注册一个基于usb的urb的usb_driver结构体,usb_driver的open函数hub_probe:

 1.1:注册usb总线,创建usb的文件夹属性,通过platform 的id匹配driver和device,此次匹配的一般是usb的interface的驱动,而是usb的设备驱动,里面实际匹配的是interface的id(vendor,product,class)。

struct bus_type usb_bus_type = {
    .name =        "usb",
    .match =    usb_device_match,
    .uevent =    usb_uevent,
};

usb_major_init();注册usb的子设备:包含主设备号,从设备号。

usb_hub_init(); usb_hub的初始化,(对于usb流程比较重要),详细分析流程:

https://blog.csdn.net/zuodenghuakai/article/details/83956040?spm=1001.2014.3001.5502

host和hub是不同的东西,hub是一种特殊的usb 的driver设备,它是以usb_driver去做特性适配,从这就可以看出来它是一种特殊功能的usb设备,hc是usb设备的控制器,包含host的寄存器的配置,包括端点的寄存器的配置功能,一般控制器会自带一个HUB,称为root hub(可以根据不同的片子,扩展的usb接口能力也不一样)root hub和hc控制器(可以包括2.0,3.0等不同的接口)是一一对应绑定的,其下可以扩展usb hub。

3.1:简单分析一下xhci驱动

1:module_init(xhci_hcd_init);(添加xhci的初始化信息)(xhci.c函数接口)

        retval = xhci_register_pci();   注册pci的pci接口,主要用来配置寄存器。

        retval = xhci_register_plat();注册平台驱动

此次分析的为intel的xhci的驱动器(xhic_pci.c),根据id_table去匹配pci的设备信息,调用pci_driver的probe函数(xhci_pci_probe)。

1.1:下面列出两个基本的结构体xhci_pci_driver、xhci_pci_hc_driver(用来操作hcd的驱动的钩子函数)(所以所驱动结构都比较简单,就是把不同的结构体串联起来)。

static struct pci_driver xhci_pci_driver = {
    .name =        (char *) hcd_name,
    .id_table =    pci_ids,

    .probe =    xhci_pci_probe,
    .remove =    xhci_pci_remove,
    /* suspend and resume implemented later */
};

static const struct hc_driver xhci_pci_hc_driver = { //主要对hcd的操作接口在该函数接口中实现,关于hc的寄存器的配置,在初始化的时候调用该接口函数,包含在usb_submit_urb 函数调用时,最终的寄存器的配置接口就此事从这里来的
    .description =        hcd_name,
    .product_desc =        "xHCI Host Controller",
    .hcd_priv_size =    sizeof(struct xhci_hcd *),

    /*
     * generic hardware linkage
     */
    .irq =            xhci_irq,
    .flags =        HCD_MEMORY | HCD_USB3 | HCD_SHARED,

    /*
     * basic lifecycle operations
     */
    .reset =        xhci_pci_setup,
    .start =        xhci_run,
    .stop =            xhci_stop,
    .shutdown =        xhci_shutdown,

    /*
     * managing i/o requests and associated device resources
     */
    .urb_enqueue =        xhci_urb_enqueue,  //在提交urb的时候先去分配urb_queue
    .urb_dequeue =        xhci_urb_dequeue,
    .alloc_dev =        xhci_alloc_dev,
    .free_dev =        xhci_free_dev,
    .alloc_streams =    xhci_alloc_streams,
    .free_streams =        xhci_free_streams,
    .add_endpoint =        xhci_add_endpoint,
    .drop_endpoint =    xhci_drop_endpoint,
    .endpoint_reset =    xhci_endpoint_reset,
    .check_bandwidth =    xhci_check_bandwidth,
    .reset_bandwidth =    xhci_reset_bandwidth,
    .address_device =    xhci_address_device,
    .update_hub_device =    xhci_update_hub_device,
    .reset_device =        xhci_discover_or_reset_device,
    .get_frame_number =    xhci_get_frame,

    /* Root hub support */
    .hub_control =        xhci_hub_control,
    .hub_status_data =    xhci_hub_status_data,
    .bus_suspend =        xhci_bus_suspend,
    .bus_resume =        xhci_bus_resume,
    /*
     * call back when device connected and addressed
     */
    .update_device =        xhci_update_device,
    .set_usb2_hw_lpm =    xhci_set_usb2_hardware_lpm,
    .enable_usb3_lpm_timeout =    xhci_enable_usb3_lpm_timeout,
    .disable_usb3_lpm_timeout =    xhci_disable_usb3_lpm_timeout,
    .find_raw_port_number =    xhci_find_raw_port_number,
};

1.2:xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) xhci的probe函数,probe的主要功能是在不同状态下调用usb_add_hcd函数接口。

retval = usb_hcd_pci_probe(dev, id);//创建ucd,创建地址映射。

    xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev,pci_name(dev), hcd)主要是注册了 定时器的   hcd->rh_timer.function = rh_timer_func;,这个轮询定时器比较重要,关系到usb插入后,如何通知给hub,最终调用函数usb_hcd_poll_rh_status会一直使用定时器调用自己,如果读取到hub有变化,而且有提交的urb,就返回。,

        hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev))创建和填充hcd结构体

usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);添加hcd(函数比较重要,拎出来)。

1.2.1:usb_add_hcd (把里面的重要函数功能放出来,这里把大多数分支流程都删除)

int usb_add_hcd(struct usb_hcd *hcd,unsigned int irqnum, unsigned long irqflags){
    int retval;
    struct usb_device *rhdev;
    set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
    if ((retval = hcd_buffer_create(hcd)) != 0) {
        dev_dbg(hcd->self.controller, "pool alloc failed\n");
        return retval;
    }

    if ((retval = usb_register_bus(&hcd->self)) < 0)
        goto err_register_bus;

    if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
        dev_err(hcd->self.controller, "unable to allocate root hub\n");
        retval = -ENOMEM;
        goto err_allocate_root_hub;
    }
    hcd->self.root_hub = rhdev; //root hub的dev信息是从hcd中读取出来, struct usb_device ,用来分析usb_device结构体的填充过程

    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);
    set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
    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");
    if (usb_hcd_is_primary_hcd(hcd) && irqnum) {

//xHCI规范说我们可以得到一个中断,如果HC在某种情况出现了错误,我们可能会从事件环中获取坏数据。这个中断不是用来探测插入了设备的。申请中断,中断处理函数usb_hcd_irq,实际调用xhci_irq
        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)//注册一个root hub
        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))

//如果驱动请求roothub中断传输,会用一个定时器轮询;否则由驱动在事件发生时调用
        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;

1.2.2:usb_hcd_poll_rh_status(hcd);

该函数在大名鼎鼎的函数接口usb_submit_urb 中也会重启启动

void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
{
    struct urb    *urb;
    int        length;
    unsigned long    flags;
    char        buffer[6];    /* Any root hubs with > 31 ports? */

    length = hcd->driver->hub_status_data(hcd, buffer); //通过hcd得到设备驱动的状态
    if (length > 0) {
        spin_lock_irqsave(&hcd_root_hub_lock, flags);
        urb = hcd->status_urb;
        if (urb) {//如果已经提交了获取状态的urb, 将状态值拷贝进入urb。
            clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
            hcd->status_urb = NULL;
            urb->actual_length = length;
            memcpy(urb->transfer_buffer, buffer, length);

            usb_hcd_unlink_urb_from_ep(hcd, urb);
            spin_unlock(&hcd_root_hub_lock);
            usb_hcd_giveback_urb(hcd, urb, 0);
            spin_lock(&hcd_root_hub_lock);
        } else {//若此时没有已经提交的urb,则设置poll_pending标志
            length = 0;
            set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
        }
        spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
    }
    if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) :
            (length == 0 && hcd->status_urb != NULL))
        mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); //开启轮询定时器
}        }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/246994
推荐阅读
相关标签
  

闽ICP备14008679号