- Linux那些事儿之我是USB
- 肖林甫 肖季东 任桥伟
- 2977字
- 2020-08-27 00:52:23
27.设备的生命线(八)
这个世界上不需要努力就能得到的东西只有一样,那就是年龄。所以要不怕苦不怕累,看完struct usb_bus函数,回到struct usb_hcd函数,继续努力地往下看。
64行,kref,USB主机控制器的引用计数。struct usb_hcd也有自己专用的引用计数函数,在hcd.c文件中。
1526 static void hcd_release (struct kref *kref) 1527 { 1528 struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); 1529 1530 kfree(hcd); 1531 } 1532 1533 struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd) 1534 { 1535 if (hcd) 1536 kref_get (&hcd->kref); 1537 return hcd; 1538 } 1539 EXPORT_SYMBOL (usb_get_hcd); 1540 1541 void usb_put_hcd (struct usb_hcd *hcd) 1542 { 1543 if (hcd) 1544 kref_put (&hcd->kref, hcd_release); 1545 } 1546 EXPORT_SYMBOL (usb_put_hcd);
66行,product_desc,主机控制器的产品描述字符串,对于UHCI,它为“UHCI Host Controller”,对于EHCI,它为“EHCI Host Controller”。
67行,irq_descr[24],这里面保存的是“ehci-hcd:usb1”之类的字符串,也就是驱动的名称再加上总线编号。
71行到73行,电源管理。
78行,driver,每个主机控制器驱动都有一个struct hc_driver结构体。查看它在hcd.h中的定义。
149 struct hc_driver { 150 const char *description; /* "ehci-hcd" etc */ 151 const char *product_desc; /* product/vendor string */ 152 size_t hcd_priv_size; /* size of private data */ 153 154 /* irq handler */ 155 irqreturn_t (*irq) (struct usb_hcd *hcd); 156 157 int flags; 158 #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ 159 #define HCD_USB11 0x0010 /* USB 1.1 */ 160 #define HCD_USB2 0x0020 /* USB 2.0 */ 161 162 /* called to init HCD and root hub */ 163 int (*reset) (struct usb_hcd *hcd); 164 int (*start) (struct usb_hcd *hcd); 165 166 /* NOTE: these suspend/resume calls relate to the HC as 167 * a whole, not just the root hub; they're for PCI bus glue. 168 */ 169 /* called after suspending the hub, before entering D3 etc */ 170 int (*suspend) (struct usb_hcd *hcd, pm_message_t message); 171 172 /* called after entering D0 (etc), before resuming the hub */ 173 int (*resume) (struct usb_hcd *hcd); 174 175 /* cleanly make HCD stop writing memory and doing I/O */ 176 void (*stop) (struct usb_hcd *hcd); 177 178 /* shutdown HCD */ 179 void (*shutdown) (struct usb_hcd *hcd); 180 181 /* return current frame number */ 182 int (*get_frame_number) (struct usb_hcd *hcd); 183 184 /* manage i/o requests, device state */ 185 int (*urb_enqueue) (struct usb_hcd *hcd, 186 struct usb_host_endpoint *ep, 187 struct urb *urb, 188 gfp_t mem_flags); 189 int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); 190 191 /* hw synch, freeing endpoint resources that urb_dequeue can't */ 192 void (*endpoint_disable)(struct usb_hcd *hcd, 193 struct usb_host_endpoint *ep); 194 195 /* root hub support */ 196 int (*hub_status_data) (struct usb_hcd *hcd, char *buf); 197 int (*hub_control) (struct usb_hcd *hcd, 198 u16 typeReq, u16 wValue, u16 wIndex, 199 char *buf, u16 wLength); 200 int (*bus_suspend)(struct usb_hcd *); 201 int (*bus_resume)(struct usb_hcd *); 202 int (*start_port_reset)(struct usb_hcd *, unsigned port_num); 203 void (*hub_irq_enable)(struct usb_hcd *); 204 /* Needed only if port-change IRQs are level-triggered */ 205 };
与usb_driver和pci_driver一样,所有的“xxx_driver”都有一堆函数指针,具体的主机控制器驱动就靠它们,这里只说函数指针之外的东西。
description直白点儿说就是驱动的大名,比如对于UHCI,它是“uhci_hcd”,对于EHCI,它就是“ehci_hcd”。product_desc和struct usb_hcd里的是一样。hcd_priv_size还是有点儿意思的,每个主机控制器驱动都会有一个私有结构体,藏在struct usb_hcd最后的那个变长数组里,这个“变”也是相对的,在创建usb_hcd时也得知道它能变多长,不然谁知道要申请多少内存,这个长度就hcd_priv_size。
81行,flags,属于HCD的一些标志,可用值就在82行和83行。它们什么意思?书到用时方恨少,flags到用时才可知。
69行,70行,85行到91行,这几行都是专为root hub服务的。一个主机控制器对应一个Root Hub,即使在嵌入式系统里,硬件上主机控制器没有集成Root Hub,软件上也需要虚拟一个出来,也就是所谓的Virtual Root Hub。
它位置是特殊的,但需要提供的功能和其他Hub是没有什么差别的,仅仅是在和主机控制器的软硬件接口上有一些特别的规定。Root Hub再怎么特别也始终是一个Hub,是一个USB设备,也不能脱离USB这个大家庭,也要向组织注册,也要有自己的设备生命线。
92行,wireless,无线USB。
94行到97行这几行都是与主机控制器的“娘家”PCI有关的,说到PCI就不得不说到如图1.20.1所示的那张著名的表。
图1.20.1 PCI配置寄存器
在这张表里中断号等很多有用的东西都在里面准备好了。94行的irq就躲在上面表儿里的倒数第四个Byte,HCD可以直接拿来用,根本就不用再去申请。接下来的regs,rsrc_start,rsrc_len就与中间的Base Address0~5脱不开关系了,牵涉到所谓的I/O内存和I/O端口,下面简单介绍一下。
大家都知道CPU是众人瞩目的焦点,但是它也不可能一个人完成工作,计算机运转是一个集体项目,CPU也需要跟各种外设配合交流,它需要访问外设里的寄存器或者内存。
CPU的差别主要表现在空间的差别。一些CPU芯片有两个空间,即I/O空间和内存空间,提供有专门访问外设I/O端口的指令;而另外一些CPU只有一个空间,即内存空间。外设的I/O端口可以映射在I/O空间也可以映射到内存空间,CPU通过访问这两个空间来访问外设,I/O空间有I/O空间访问的接口,内存空间有内存空间访问的接口。当然一些外设不但有寄存器,还有内存,也就是I/O内存,比如EHCI/OHCI,它们需要映射到内存空间。但是不管映射到哪个空间,访问I/O端口还是I/O内存,CPU必须知道它们映射后的地址,不然没有办法配合交流。
在图1.20.1中,中间的那些基地址就是保存PCI设备中I/O内存或I/O端口的首尾位置还有长度。驱动使用时要首先把它们给读出来,如果要映射到I/O空间,则要根据读到的值向系统申请I/O端口资源,如果要映射到内存空间,除了要申请内存资源,还要使用ioremap等进行映射。
96行的rsrc_start和97行的rsrc_len保存的就是从表里读出来的主机控制器的I/O端口或内存的首地址和长度,95行的regs保存的是调用ioremap_nocache映射后的内存地址。
98行,power_budget,能够提供的电流。
101行,*pool [HCD_BUFFER_POOLS],几个dma池。因为HCD_BUFFER_POOLS在100行定义为4,所以这里就表示每个主机控制器可以有4个dma池。
我们知道主机控制器是可以进行DMA传输的,再回到前面讲的struct urb,它有两个成员,transfer_dma和setup_dma,前面只是说可以使用usb_buffer_alloc分配好DMA缓冲区给它们,然后再告诉HCD urb已经有了,HCD就可以不用再进行复杂的DMA映射了。但并没有提到这个获取的DMA缓冲区是从哪里来的。这里所说的DMA池子里来的了。
像创建或销毁线程、数据库连接时比较消耗资源,可以先建一个池子预先创建好一批线程放里面,用时就从里面取出来,不用时就再放里面。
当然,DMA池还有其他的作用。一般来说DMA映射获得的都是以页为单位的内存,urb不需要这么大的,如果需要比较小的DMA缓冲区,就离不开DMA池了。还是查看主机控制器的这几个池子在buffer.c文件中是怎么创建的。
52 int hcd_buffer_create(struct usb_hcd *hcd) 53 { 54 char name[16]; 55 int i, size; 56 57 if (!hcd->self.controller->dma_mask) 58 return 0; 59 60 for (i = 0; i < HCD_BUFFER_POOLS; i++) { 61 if (!(size = pool_max [i])) 62 continue; 63 snprintf(name, sizeof name, "buffer-%d", size); 64 hcd->pool[i] = dma_pool_create(name, hcd->self.controller, 65 size, size, 0); 66 if (!hcd->pool [i]) { 67 hcd_buffer_destroy(hcd); 68 return -ENOMEM; 69 } 70 } 71 return 0; 72 }
这里首先要判断这个主机控制器支持不支持DAM,如果不支持的话再创建DMA池就是纯粹无稽之谈了。如果主机控制器支持DMA,就逐个使用dma_pool_alloc来创建DMA池,如果创建失败了,就调用同一个文件中的hcd_buffer_destroy来将已经创建成功的池子给销毁掉。
82 void hcd_buffer_destroy(struct usb_hcd *hcd) 83 { 84 int i; 85 86 for (i = 0; i < HCD_BUFFER_POOLS; i++) { 87 struct dma_pool *pool = hcd->pool[i]; 88 if (pool) { 89 dma_pool_destroy(pool); 90 hcd->pool[i] = NULL; 91 } 92 } 93 }
这里调用的dma_pool_destroy和dma_pool_alloc。每个DMA池子都要找到四个函数,一个用来创建,一个用来销毁,一个用来取内存,一个用来放内存。上面只遇到了创建和销毁的函数,还少两个取内存和放内存的函数,再去同一个文件中找一找。
100 void *hcd_buffer_alloc( 101 struct usb_bus *bus, 102 size_t size, 103 gfp_t mem_flags, 104 dma_addr_t *dma 105 ) 106 { 107 struct usb_hcd *hcd = bus_to_hcd(bus); 108 int i; 109 110 /* some USB hosts just use PIO */ 111 if (!bus->controller->dma_mask) { 112 *dma = ~(dma_addr_t) 0; 113 return kmalloc(size, mem_flags); 114 } 115 116 for (i = 0; i < HCD_BUFFER_POOLS; i++) { 117 if (size <= pool_max [i]) 118 return dma_pool_alloc(hcd->pool [i], mem_flags, dma); 119 } 120 return dma_alloc_coherent(hcd->self.controller, size, dma, 0); 121 } 122 123 void hcd_buffer_free( 124 struct usb_bus *bus, 125 size_t size, 126 void *addr, 127 dma_addr_t dma 128 ) 129 { 130 struct usb_hcd *hcd = bus_to_hcd(bus); 131 int i; 132 133 if (!addr) 134 return; 135 136 if (!bus->controller->dma_mask) { 137 kfree(addr); 138 return; 139 } 140 141 for (i = 0; i < HCD_BUFFER_POOLS; i++) { 142 if (size <= pool_max [i]) { 143 dma_pool_free(hcd->pool [i], addr, dma); 144 return; 145 } 146 } 147 dma_free_coherent(hcd->self.controller, size, addr, dma); 148 }
又可以找到两个函数,即dma_pool_alloc和dma_pool_free函数,现在可以凑齐四个函数了。不过不用管它们四个到底什么长相,只要它们能够干活儿就成了,这里要注意的是以下几个问题。
第一个问题是即使你的主机控制器不支持DMA,这几个函数也是可以用的,只不过创建的不是DMA池子,存取的也不是DMA缓冲区。此时,DMA池子不存在,hcd_buffer_alloc获取的只是适用kmalloc申请的普通内存。当然,你必须在它没有利用价值时使用hcd_buffer_free将它释放掉。
第二个问题是size的问题,它们里面都有一个pool_max,这是个同一个文件中定义的数组。
26 static const size_t pool_max [HCD_BUFFER_POOLS] = { 27 /* platfor ms without dma-friendly caches might need to 28 * prevent cacheline sharing... 29 */ 30 32, 31 128, 32 512, 33 PAGE_SIZE / 2 34 /* bigger --> allocate pages */ 35 };
这个数组中定义的就是四个池子中每个池子里保存的DMA缓冲区的size。注意这里虽说只定义了四种size,但是并不说明你使用hcd_buffer_alloc获取DMA缓冲区时不能指定更大的size,如果这几个池子都满足不了要求,那就会使用dma_alloc_coherent建立一个新的DMA映射。还有,每个人的情况都不一样,不可能都会完全恰好和上面定义的四种size一致,那也不用怕,使用这个size获取DMA缓冲区时,池子会选择一个略大一些的回馈过去。
还是回到struct usb_hcd中来。103行,state,主机控制器的状态,紧挨着它的下面那些代码就是相关的可用值和宏定义。