RootHub感应设备的插拔

来源:互联网 发布:哪下载软件安全 编辑:程序博客网 时间:2024/04/30 05:26

其实,RootHub的中断传输 是使用定时器来实现的。下面仔细欣赏。
这里写图片描述

首先你要明白的是: xHC控制器有两个RootHub,
一个是RootHub2.0的。 (遇到的开发板中它引出8个port.这些port对应寄存器为PORTSC0~7),
一个是RootHub3.0的。(引出7个port,PORTSC8~13),
那么就对应了两条bus总线了,但是这两条总线对应这同一个控制器xhc
这里写图片描述
port 状态变化 这块 很复杂,在后面会慢慢道来。往下看吧。

int usb_submit_urb(struct urb *urb, gfp_t mem_flags){    .... //先跳过,后面详细分析。    return usb_hcd_submit_urb(urb, mem_flags);}int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags){        if (is_root_hub(urb->dev))  //RootHub        {            status = rh_urb_enqueue(hcd, urb);        } else {            //非RootHub的先跳过。        }}static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb){    if (usb_endpoint_xfer_int(&urb->ep->desc))  //中断传输    {        return rh_queue_status (hcd, urb);    }       if (usb_endpoint_xfer_control(&urb->ep->desc))//控制传输    {        return rh_call_control (hcd, urb);    }       return -EINVAL;}static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb){    int     retval;    unsigned long   flags;    unsigned    len = 1 + (urb->dev->maxchild / 8);    spin_lock_irqsave (&hcd_root_hub_lock, flags);    /**        如果roothub已经在处理中断传输或者是非法的urb    */    if (hcd->status_urb || urb->transfer_buffer_length < len)     {        dev_dbg (hcd->self.controller, "not queuing rh status urb\n");        retval = -EINVAL;        goto done;    }    /**        将urb添加到endpoint的urb队列上。    */    retval = usb_hcd_link_urb_to_ep(hcd, urb);    if (retval)    {        goto done;    }    hcd->status_urb = urb;    urb->hcpriv = hcd;      /**        支持新的轮询方式。        问:            那么他是再什么时候被赋值的呢?            int xhci_run(struct usb_hcd *hcd)            {                u32 temp;                u64 temp_64;                int ret;                struct xhci_hcd *xhci = hcd_to_xhci(hcd);                hcd->uses_new_polling = 1;         //支持新的轮询方式。                if (!usb_hcd_is_primary_hcd(hcd))  //RootHub 3.0                {                    return xhci_run_finished(xhci);                }                ...            }            看,他是在xhci_run()中被赋值的。那么,xhci_run()函数又是在什么时候被调用的?            往下看。            xhci_register_pci()            {                return pci_register_driver(&xhci_pci_driver);            }            static struct pci_driver xhci_pci_driver =             {                .name =     (char *) hcd_name,                .id_table = pci_ids,                .probe =    xhci_pci_probe,                .remove =   xhci_pci_remove,            };    /*        看他的porbe()函数。        注册了两个roothub。        一个是3.0的        一个是2.0的        但是 2.0的必须现注册.(为什么是2.0的要先注册?)    */        static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)        {            ...            /**                注册2.0的roothub . 必须先注册 2.0的 roothub.            */            retval = usb_hcd_pci_probe(dev, id);            /**                这个函数中会初始化定时器,并设定定时器到期执行的函数。                看,在xhci_register_pci()函数完成的时候 定时器轮询roothub就已经准备好了                init_timer(&hcd->rh_timer);                hcd->rh_timer.function = rh_timer_func;                hcd->rh_timer.data = (unsigned long) hcd;                这个rh_timer_func()在下面详细分析。            */            xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev,pci_name(dev), hcd);            ....             retval = usb_add_hcd(xhci->shared_hcd, dev->irq,IRQF_SHARED);               }        int usb_add_hcd(struct usb_hcd *hcd,unsigned int irqnum, unsigned long irqflags)        {            ...            ...             /*               调用reset( )函数              */             if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0)             {                dev_err(hcd->self.controller, "can't setup: %d\n", retval);                goto err_hcd_driver_setup;            }            /*                设置可轮询            */              hcd->rh_pollable = 1;            /*                注册了irq,也就使能了中断。            */              if (usb_hcd_is_primary_hcd(hcd) && irqnum)             {                retval = usb_hcd_request_irqs(hcd, irqnum, irqflags);                if (retval)                {                    goto err_request_irq;                }               }            /*                调用start函数。 这里的start函数就是xhci_run()函数。            */              retval = hcd->driver->start(hcd);            /*                注册RootHub            */              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)  //如果不支持新的轮询方式。    {        mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));    }else if (HCD_POLL_PENDING(hcd))    {        mod_timer(&hcd->rh_timer, jiffies);    }       retval = 0; done:    spin_unlock_irqrestore (&hcd_root_hub_lock, flags);    return retval;}

这里写图片描述

从头开始说把。
这里写图片描述

这个probe函数只要做了一下事情:

一 调用usb_hcd_pci_probe()注册roothub2.0,
USB core must know to register the USB 2.0 roothub first
上面是内核中的注释, 说注册3.0的RootHub之前,必须要先注册2.0的RootHub。

二 :调用usb_create_shared_hcd()创建和初始化一个HCD structure。
在这个函数中 它初始化了一个定时器,这个定时器的到期执行函数 会 轮询RootHub。
下面是一幅图:
这里写图片描述
下面好好的说说这个函数!

0 0