Linux那些事儿之我是EHCI(4) data structure of ehci driver and device

来源:互联网 发布:淘宝王者荣耀充值原理 编辑:程序博客网 时间:2024/04/29 21:49

阿扁"辞职"了,kde4发布了,更让我激动的是,英雄志过两天又有更新了,这部连载长达8年的小说,终于要进入精彩的大结局。卢云的命运究竟如何?观海云远,四个性格理念完全不同的人,谁是好,谁是坏,谁是对,谁是错?何谓正道?

接着上回说,usb_hcd_pci_probe这个函数在"我是UHCI"中也有讨论,不过我想按照我的思路写下去。 

     46 /**
     47  * usb_hcd_pci_probe - initialize PCI-based HCDs
     48  * @dev: USB Host Controller being probed
     49  * @id: pci hotplug id connecting controller to HCD framework
     50  * Context: !in_interrupt()
     51  *
     52  * Allocates basic PCI resources for this USB host controller, and
     53  * then invokes the start() method for the HCD associated with it
     54  * through the hotplug entry's driver_data.
     55  *
     56  * Store this function in the HCD's struct pci_driver as probe().
     57  
*/

     
58 int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
     
59 {
     
60         struct hc_driver        *driver;
     
61         struct usb_hcd          *hcd;
     
62         int                     retval;
     
63
     
64         if (usb_disabled())
     
65                 return -ENODEV;
     
66
     
67         if (!id || !(driver = (struct hc_driver *) id->driver_data))
     
68                 return -EINVAL;
     
69
     
70         if (pci_enable_device (dev) < 0)
     
71                 return -ENODEV;
     
72         dev->current_state = PCI_D0;
     
73         dev->dev.power.power_state = PMSG_ON;
     
74
     
75         if (!dev->irq) {
     
76                 dev_err (&dev->dev,
     
77                         "Found HC with no IRQ.  Check BIOS/PCI %s setup! ",
     
78                         pci_name(dev));
     
79                 retval = -ENODEV;
     
80                 goto err1;
     
81         }

     
82
     
83         hcd = usb_create_hcd (driver, &dev->dev, pci_name(dev));
     
84         if (!hcd) {
     
85                 retval = -ENOMEM;
     
86                 goto err1;
     
87         }

     
88
     
89         if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI
     90                 hcd->rsrc_start = pci_resource_start (dev, 0);
     
91                 hcd->rsrc_len = pci_resource_len (dev, 0);
     
92                 if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len,
     
93                                 driver->description)) {
     
94                         dev_dbg (&dev->dev, "controller already in use ");
     
95                         retval = -EBUSY;
     
96                         goto err2;
     
97                 }

     
98                 hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len);
     
99                 if (hcd->regs == NULL) {
    
100                         dev_dbg (&dev->dev, "error mapping memory ");
    
101                         retval = -EFAULT;
    
102                         goto err3;
    
103                 }

    
104
    
105         }
 else {                                // UHCI
    106                 int     region;
    
107
    
108                 for (region = 0; region < PCI_ROM_RESOURCE; region++{
    
109                         if (!(pci_resource_flags (dev, region) &
    
110                                         IORESOURCE_IO))
    
111                                 continue;
    
112
    
113                         hcd->rsrc_start = pci_resource_start (dev, region);
    
114                         hcd->rsrc_len = pci_resource_len (dev, region);
    
115                         if (request_region (hcd->rsrc_start, hcd->rsrc_len,
    
116                                         driver->description))
    
117                                 break;
    
118                 }

    
119                 if (region == PCI_ROM_RESOURCE) {
    
120                         dev_dbg (&dev->dev, "no i/o regions available ");
    
121                         retval = -EBUSY;
    
122                         goto err1;
    
123                 }

    
124         }

    
125
    
126         pci_set_master (dev);
    
127
    
128         retval = usb_add_hcd (hcd, dev->irq, IRQF_SHARED);
    
129         if (retval != 0)
    
130                 goto err4;
    
131         return retval;
    
132
    
133  err4:
    
134         if (driver->flags & HCD_MEMORY) {
    
135                 iounmap (hcd->regs);
    
136  err3:
    
137                 release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
    
138         }
 else
    
139                 release_region (hcd->rsrc_start, hcd->rsrc_len);
    
140  err2:
    
141         usb_put_hcd (hcd);
    
142  err1:
    
143         pci_disable_device (dev);
    
144         dev_err (&dev->dev, "init %s fail, %d ", pci_name(dev), retval);
    
145         return retval;
    
146 }

 

64行,usb_disabled()判断内核有没有开启支持usb,要是这都不支持,一切都免谈。

70行,pci_enable_device()这是对ehci三类接口中的pci configuration space进行操作,设置其中某个寄存器的值,使设备处于工作状态。调用pci_read_config_word()pci_write_config_word来读写pci配置空间的寄存器。pci_enable_device -> pci_enable_device_bars -> do_pci_enable_device ...  原理不难,只要对照spec可以看懂。

7273是电源管理的内容。75判断设备的中断号是否为空。
83usb_create_hcd() 创建一个usb_hcd机构体。
 
   1480 /**
   1481  * usb_create_hcd - create and initialize an HCD structure
   1482  * @driver: HC driver that will use this hcd
   1483  * @dev: device for this HC, stored in hcd->self.controller
   1484  * @bus_name: value to store in hcd->self.bus_name
   1485  * Context: !in_interrupt()
   1486  *
   1487  * Allocate a struct usb_hcd, with extra space at the end for the
   1488  * HC driver's private data.  Initialize the generic members of the
   1489  * hcd structure.
   1490  *
   1491  * If memory is unavailable, returns NULL.
   1492  
*/

   
1493 struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
   
1494                 struct device *dev, char *bus_name)
   
1495 {
   
1496         struct usb_hcd *hcd;
   
1497
   
1498         hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
   
1499         if (!hcd) {
   
1500                 dev_dbg (dev, "hcd alloc failed ");
   
1501                 return NULL;
   
1502         }

   
1503         dev_set_drvdata(dev, hcd);
   
1504         kref_init(&hcd->kref);
   
1505
   
1506         usb_bus_init(&hcd->self);
   
1507         hcd->self.controller = dev;
   
1508         hcd->self.bus_name = bus_name;
   
1509         hcd->self.uses_dma = (dev->dma_mask != NULL);
   
1510
   
1511         init_timer(&hcd->rh_timer);
   
1512         hcd->rh_timer.function = rh_timer_func;
   
1513         hcd->rh_timer.data = (unsigned long) hcd;
   
1514 #ifdef CONFIG_PM
   
1515         INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
   
1516 #endif
   
1517
   
1518         hcd->driver = driver;
   
1519         hcd->product_desc = (driver->product_desc) ? driver->product_desc :
   
1520                         "USB Host Controller";
   
1521
   
1522         return hcd;
   
1523 }

 
一下子出现了很多数据结构,现在有必要捋一捋它们之间的关系。
(1)描述驱动的数据结构
 
ehci主控器的驱动程序需要包括些什么东西?站在pci总线的角度来说,ehci是一个pci的设备,驱动程序里面必须提供操作ehci设备,比如开启(start),关闭(stop),重启(reset),中断的函数。另外,站在usb控制器的角度来说,驱动程序里面还要与底层usb系统交互的函数,如插入/删除urb(rb_enqueue, urb_dequeue)。
 
pci_driver ehci_pci_driver{
           .........
           .id_table = pci_ids,       ------------>driver_data = (unsigned long) &ehci_pci_hc_driver,
          .probe = usb_hcd_pci_probe
 
}
hc_driver ehci_pci_hc_driver{
        ........
       .hcd_priv_size = sizeof(struct ehci_hcd),
 
       .irq =   ehci_irq,
       .reset =  ehci_pci_setup,
       .start =  ehci_run,
       .stop =   ehci_stop,
       .shutdown =  ehci_shutdown,
 
       .urb_enqueue =  ehci_urb_enqueue,
       .urb_dequeue =  ehci_urb_dequeue,
}
(2)描述设备的数据结构
 
usb_hcd{
        ........
        usb_bus .self
       .hcd_priv = ehci_hcd
}
 
usb_hcd交大人甲有过论述:linux那些事儿 之 戏说USB(28)设备的生命线 (七) http://blog.csdn.net/fudan_abc/archive/2007/10/18/1831459.aspx
 
usb_hcd注释上说USB Host Controller Driver,但我更愿意认为它是一个描述一个usb主控制器设备的数据结构。usb_hcd描述了usb主控制器共有的属性,usb_hcd.hcd_priv指向了特定的主控制器数据结构,它描述各自特有的属性。对ehci,是ehci_hcd,对uhci,是uhci_hcd。usb_hcd的成员usb_bus self 是HCD bus-glue layer,usb主控器与总线之间粘合剂。
这样,1498就好理解了。1506行usb_bus_init初始化usb_hcd.self。 1511-1513初始化 root harbor 计时器。然后就有返回到usb_hcd_pci_probe()