接着走,661行,configure_hc,来自drivers/usb/host/uhci-hcd.c,
175 /*
176 * Store the basic register settings needed by the controller.
177 */
178 static void configure_hc(struct uhci_hcd *uhci)
179 {
180 /* Set the frame length to the default: 1 ms exactly */
181 outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
182
183 /* Store the frame list base address */
184 outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
185
186 /* Set the current frame number */
187 outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
188 uhci->io_addr + USBFRNUM);
189
190 /* Mark controller as not halted before we enable interrupts */
191 uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
192 mb();
193
194 /* Enable PIRQ */
195 pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
196 USBLEGSUP_DEFAULT);
197 }
USBSOF_DEFAULT和USBSOF定义于drivers/usb/host/uhci-hcd.h:
43 #define USBFRNUM 6
44 #define USBFLBASEADD 8
45 #define USBSOF 12
46 #define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */
UHCI spec中定义了一个START OF FRAME(SOF) MODIFY REGISTER,这里称作SOF寄存器,其地址位于Base+(0Ch)处,0Ch即这里的12.这个寄存器的值的修改意味着的frame周期的改变,通常我们没有必要修改这个寄存器,直接设置为默认值即可,默认值为64,按照UHCI spec中2.1.6的陈述,这意味着对于常见的12MHz的时钟输入的情况,frame周期将为1ms.(The default value is decimal 64 which gives a SOF cycle time of 12000. For a 12 MHz SOF counter clock input, this produces a 1 ms Frame period.)
紧接着USBFLBASEADD用来表示另一个寄存器,UHCI spec中称之为FLBASEADD,即FRAME LIST BASE ADDRESS REGISTER,它一共有32个bits,位于Base+(08-0Bh),这个寄存器应该包含Frame List在系统内存中的起始地址.其中,bit31到bit12对应于内存地址信号[31:12].而bit11到bit0则是保留位,必须全为0.frame_dma_handle正是我们前面调用dma_alloc_coherent为uhci->frame申请内存的时候映射的DMA地址.显然这个地址我们需要写到这个寄存器里,这样主机控制器才会知道去怎么样去访问这个Frame List.基地址的概念是计算机中经常用的,其实生活中也经常用,比如你一个朋友来北京玩,你告诉她去秀水街买假名牌,假设你因为一向孝顺父母,经常去秀水街给他们买假名牌,因而对整条秀水街都特熟悉,那么可能你不用带她去,你直接告诉她说第几家店卖什么,第几家店的什么商品还不错,但是你首先必须告诉她秀水街本身的地理位置,或者说地址,这就是基地址.
接下来, UHCI_MAX_SOF_NUMBER是定义于drivers/usb/host/uhci-hcd.h的宏,值为2047,用二进制来表示就是11个1,即111 1111 1111,而USBFRNUM这里我们看到了是6,它对应于UHCI spec中的寄存器FRNUM(FRAME NUMBER REGISTER),地址为Base+(06-07h),这个寄存器一共16个bits,这其中bit10到bit0包含了当前的Frame号,所以把uhci->frame_number与UHCI_MAX_SOF_NUMBER相与就是得到它的bit10到bit0这11个bits,即得到Frame号然后写入到FRNUM寄存器中去.unsigned int frame_number是struct uhci_hcd的一个成员.
然后,设置uhci_to_hcd(uhci)->state为HC_STATE_SUSPENDED,注意我们当初在finish_reset中也有设置过这个状态,只不过当时是设置成了HC_STATE_HALT.凡事都是有因有果的,我们做了这些设置,到时候自然会用到的.别以为写代码的都是无聊做些没意义的事情.
195行,pci_write_config_word,写寄存器,写的又是USBLEGSUP,不过这次写的是USBLEGSUP_DEFAULT,这个宏的值为0x2000,这是UHCI spec中规定的默认值.
这样我们就算是配置好了HC,到这里就算万事俱备,只欠东风了.662行就设置uhci->is_initialized为1,这意图再明显不过了.
回到uhci_start中,还剩下最后一个函数,start_rh(),rh表示Root Hub.这个函数来自drivers/usb/host/uhci-hcd.c:
324 static void start_rh(struct uhci_hcd *uhci)
325 {
326 uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
327 uhci->is_stopped = 0;
328
329 /* Mark it configured and running with a 64-byte max packet.
330 * All interrupts are enabled, even though RESUME won't do anything.
331 */
332 outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD);
333 outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
334 uhci->io_addr + USBINTR);
335 mb();
336 uhci->rh_state = UHCI_RH_RUNNING;
337 uhci_to_hcd(uhci)->poll_rh = 1;
338 }
又一次设置了uhci_to_hcd(uhci)->state,只不过这次设置的是HC_STATE_RUNNING.
然后设置is_stopped为0.
然后是写寄存器USBCMD,这次写的是什么呢?先看drivers/usb/host/uhci-hcd.h中关于这个命令寄存器定义的宏:
15 /* Command register */
16 #define USBCMD 0
17 #define USBCMD_RS 0x0001 /* Run/Stop */
18 #define USBCMD_HCRESET 0x0002 /* Host reset */
19 #define USBCMD_GRESET 0x0004 /* Global reset */
20 #define USBCMD_EGSM 0x0008 /* Global Suspend Mode */
21 #define USBCMD_FGR 0x0010 /* Force Global Resume */
22 #define USBCMD_SWDBG 0x0020 /* SW Debug mode */
23 #define USBCMD_CF 0x0040 /* Config Flag (sw only) */
24 #define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */
结合Spec和这里的注释来看,USBCMD_RS表示RUN/STOP.1表示RUN,0表示STOP.USBCMD_CF表示Configure Flag,在配置阶段结束的时候,应该把这个flag设置好.USBCMD_MAXP则表示FSBR最大包的size.这位为1表示64bytes,为0表示32bytes.关于FSBR我们以后会知道.
然后写另一个寄存器,USBINTR,表示中断使能寄存器.这个寄存器我们前面曾经提过.当时我们贴出了关于它的图片,知道它的bit3,bit2,bit1,bit0分别表示四个开关,为1就是使能,为0就是使不能,drivers/usb/host/uhci-hcd.h中也定义了这些相关的宏,
36 /* Interrupt enable register */
37 #define USBINTR 4
38 #define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */
39 #define USBINTR_RESUME 0x0002 /* Resume interrupt enable */
40 #define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */
41 #define USBINTR_SP 0x0008 /* Short packet interrupt enable */
显而易见的是,咱们这里就是把这四个开关全部打开.这四种中断的意思都在注释里说的很清楚了,第一种是超时,第二种是从Suspended进入Resume,第三种是完成了一个交易,第四种是接收到的包小于预期的长度.在这四种情况下,USB主机控制器可以向系统主机或者说向系统的CPU发送中断请求.
最后设置uhci->rh_state为UHCI_RH_RUNNINNG.并设置uhci_to_hcd(uhci)->poll_rh为1.到这里uhci_start就可以返回了,没什么意外的话就返回0.于是咱们还是回到usb_add_hcd中去.