这一章讨论主控制器。主控制器位于usb总线和主控制器驱动之间。主控制器负责处理主控制器驱动建立的各种列表(控制、块、中断和同步)。此外,usb root hub被集成在了主控制器里。
这一章的结构:
· USB状态 这部分讨论了不同USB状态下主控制器的操作
· 帧管理 这部分讨论了管理1ms的USB帧的详细细节
· 列表处理 主控制器的主要功能就是处理列表。这部分详细描述了主控制器助理主控制器驱动建立的数据列表实现细节
·中断处理 这部分描述了主控制器对中断事件的跟踪以及怎么为这些事件提供中断
·根集线器(root hub) 这部分描述了根集线器的支持
对于主控制器驱动,主控制器有四种状态:USB可操作(UsbOperational)、USB复位(UsbReset)、USB暂停(UsbSuspend)和USB恢复(UsbResume),并且在相应的状态,主控制器都给USB发出信号,且使总线进入相应的状态。
在HcControl寄存器的HostControllerFunctionalState域反应了USB的状态。图6-1展示了各个状态之间的转换。例如:当发生一个远程唤醒事件时,主控制器可能从USB暂停态转换到USB恢复态。
Figure 6-1: USB States
当主控制器进入USB可操作态时,她就产生SOF令牌包,并开始处理由HCD建立的列表。USB可操作态可能是由USB恢复态或是USB复位态转换过来的,她又可能转换到USB复位态或是USB暂停态。
当主控制器从USB复位态或USB恢复态转换到USB可操作态,她会按照USB协议书里规定的那样终止USB复位或恢复信号然后开始发送令牌包。
当主控制器转变到USB可操作态时,帧管理寄存器产生变化。当主控制器的状态转化到USB可操作状态时,HcFmInterval 寄存器的FrameInterval域中的数值将会装载到HcFmRemaining寄存器的FrameRemaining域,HcFmNumber寄存器中的FrameNumber域中的数值增加(是不是加1,待定)。而SOF令牌包不会在装载FrameRemaining域的时候发送。在主控制器进入USB可操作态,FrameRemaining域中的值从0变到FrameInterval域中的值时,第一个SOF令牌包发送。
当处于USB复位态时,主控制器在USB总线上强制产生一个复位信号。处于USB复位态,主控制器不在处理HCD建立的列表及不再发送SOF令牌包。HcFmNumber寄存器的FrameNumber域中的数值不再增加。主控制器在任何时候任何状态都可以进入USB复位态。主控制器在硬件复位之后默认的状态就是USB复位态。主控制器驱动负责满足这个USB协议书中定义的USB复位信号时间。(The Host Controller Driver is responsible for satisfying USB Reset signaling timing defined by the USB Specification.)
USB暂停态是指USB挂起。此时,主控制器停止发送SOF令牌包、列表的处理,且HcFmNumber寄存器的FrameNumber域中的数值不再增加。然而,主控制器远程唤醒逻辑单元却时刻监视着USB总线是否有唤醒活动。
一个软件复位或是处在USB可操作态来自主控制器驱动的命令都可以进入USB暂停态。当有一个远程唤醒事件发生时,主控制器就会从USB暂停态转换到USB恢复态,但如果此时主控制器驱动对主控制器复位,主控制器不会进入USB恢复态而优先进入USB复位态。主控制器驱动在进入USB暂停态之后必须等待5ms才可以进入USB恢复态。同样,当主控制器在进入USB暂停态之后,当有本地唤醒事件发生,强迫主控制器转换到USB恢复态时,根集线器(root hub)也要等在5ms。软件复位之后,如果在主控制器进入USB暂停态的1ms之内有状态转化发生,主控制器驱动就可能进入USB可操作态,如果1ms之内没有任何状态转换发生,总线上的设备就可能挂起。( Following a software reset, the Host Controller Driver may cause a transition to UsbOperational if the transition occurs no more than 1 ms from the transition into UsbSuspend. If the 1-ms period is violated, it is possible that devices on the bus will go into Suspend.)
当处于USB恢复态时,主控制器在总线上发出恢复信号,而根集线器(root hub)负责将USB恢复信号传递到下游端口。在USB恢复态时,主控制器不会处理HCD建立的列表,不会发生SOF令牌包,HcFmNumber寄存器的FrameNumber域中的数值也不会增加。
USB恢复态只能从USB暂停态转换。USB恢复态可以主控制器驱动设置的,也可能是根集线器上的远程唤醒信号设置的。主控制器负责消除来自硬件唤醒和主控制器驱动设置的状态冲突。从USB恢复态转换到USB复位态和USB可操作态是合法的。
主控制器驱动负责满足USB协议书里定义的USB恢复信号时间(The Host Controller Driver is responsible for USB Resume signal timing as defined by the USB Specification.)
主控制器负责为USB安排一帧中的所有内容,包括:总线上SOF令牌包的发送、和主控制器驱动传递某些帧信息。
主控制器用三个寄存器来完成对帧的计时,报告帧管理的任务信息。(The Host Controller uses three registers to perform the frame timing and information reporting tasks of frame management.)HcFmNumber寄存器的FrameNumber域用来保存当前的帧号,且主控制器把当前帧号写入HCCA,以便通知主控制器驱动,同样在发送SOF令牌包时主控制器将当前帧号写入SOF令牌包的帧号字段。HcFmInterval寄存器的FrameInterval域和HcFmRemaining 寄存器的FrameRemaining域被用来定义帧的边界。
FrameInterval域中存放的是12MHz位时间(12MHz位时间指的是在1s内发送12000000位数据)时一个USB帧(USB1.1规定1帧1ms)的长度,即其在复位时默认存放是0x2edf(十进制11999)(从0x2edf到0x0,所以可以产生12000位时间(1ms发送12000位数据))。主控制器驱动可能随时改变FrameInterval域中的值。
FrameRemaining域是个14位帧计数器。当主控制器处于USB可操作状态时,此计数器每一个USB位时间递减1。当FrameRemaining域中的值到达0时,FrameInterval域中的值会在下个位时间装载到FrameRemaining域中。帧边界:当FrameRemaining域中的值从0变为FrameInterval域中的数值时。也就是说,当FrameRemaining域中的值是0时为帧的最后一个位时间,当FrameRemaining域中的数值等于FrameInterval域中的值时是帧的开始位时间。
HcFmNumber寄存器的FrameNumber域保存这当前帧号。在每个帧边界,这个域都会被主控制器加1,即当FrameRemaining域中的数值从0变到FrameInterval域中的值时,FrameNumber域值加1。当处理大量的相关联的帧时,FrameNumber域中的值可能会被主控制器驱动用到。为了主控制器驱动能使用FrameNumber域中的值,主控制器会在FrameNumber域中的数值更新之后将其值立即写入HccaFrameNumber,同时设置HcInterruptStatus寄存器中的StartOfFrame 位表示一个StartOfFrame中断事件。
当处在USB可操作态时,主控制器在每个帧周期开始都产生一个SOF令牌包,更确切的说是将SOF令牌包发送到USB总线上。而在其他状态时是不会产生SOF令牌包的。如图6-2
图6-2: Timing for SOF Token Generation on USB
当处在USB可操作态,在每一帧的帧边界,HcFmNumber寄存器的FrameNumber域的值加1后,主控制器会把此值写入HccaFrameNumber变量中(HccaFrameNumber是hcca中的一个32位的变量)。这样主控制器驱动就可以使用HCCA中的32位的HccaFrameNumber的数值,而不是使用16位的FrameNumber域的数值。如果帧开始事件中断使能,主控制器驱动就可以通过这个中断知道HccaFrameNumber变量被更新。
USB在软件和端点之间支持不同的通信模式(块,控制,中断,和同步),并且在总线上各个通信模式在不断的改变。USB未对设备使用总线提供仲裁机制。因此,这都是靠主控制器预测的,并且当主控软件预测到设备需要的时候,会为其分配服务。被ohci使用的方法就是使用两种级别的仲裁来选择其中的端点。首先,需要服务的每一个端点都会被连接到相应的通信模式列表上(例如:块端点链接到块列表),然后主控制器选择其中一个列表进行处理。进而,在列表中,赋予端点的优先级是相等的,以确保列表上所以的端点都会得到一样的服务机会。
一帧中,列表的处理顺序是规定好的。每一帧中,在开始的一段时间(这段时间由HcPeriodicStart寄存器里的值确定)里先处理控制列表和块列表(非周期列表)。之后(当到达HcPeriodicStart寄存器里的值时)就开始处理周期列表(中断列表和同步列表),处理周期列表时,先处理中断列表,处理完中断列表再处理同步列表。当处理完周期列表之后,如果这一帧有剩余时间,就会继续处理控制和块列表。图6-3显示了一帧中主控制器处理周期列表和非周期列表的先后顺序。
Figure 6-3: List Priority within a USB Frame
前面已经提到,被主控制器驱动建立的列表被分成了周期列表和非周期列表。中断和同步列表是周期列表,因为这些列表上的端点需要在特定的时间以特定的方式进行处理。而控制和块列表是非周期列表,因为这些列表上的端点只要最终能完成处理即可,而完成时间却不是要求很高。
注意一下图6-3,主控制器把一帧分成了三个部分。第一部分被用于处理非周期列表。第二部分被用于处理周期列表。第三部分将再次处理非周期列表。
周期列表中,规定中断列表的优先级要高于同步列表的优先级。当处理周期列表时,主控制器实际上只处理的一张列表,即周期列表,也就是说,中断描述符和同步描述符都链接在了这一张周期列表上了。但要注意,中断描述符在前,同步描述符在后。
关于非周期列表,包括控制列表和块列表,她是两张列表,和周期列表不一样。主控制器处理非周期列表,即处理控制列表和块列表,要用到一个比值(控制和块比值:N:1)。主控制器驱动通过对 HcControl 寄存器的ControlBulkServiceRatio域赋不同的值就可以改变控制和块比值(从1:1到4:1)。N:1时,主控制器处理N个控制端点后再处理1个块端点。例如:当是1:1时,主控制器就处理一个控制端点后再处理一个块端点;当是4:1时,主控制器就处理4个控制端点后再处理一个块端点。图6-4是N:1时处理过程
Figure 6-4: Control Bulk Service Ratio of 4:1
主控制器只按控制和块比值来操作,而不管控制列表和块列表上有多少个端点描述符。你比如:当控制和块比值是4:1时,而控制列表上只有1个控制描述符,主控制器依然是对控制列表的端点描述符处理4次,之后再处理块列表上的1个端点描述符。如果控制列表或块列表上没有端点描述符,主控制器就会跳转到有端点描述符的非周期列表上进行处理。
当跨越帧边界时,控制和块比值任然被维护。意思就是说,当控制和块比值是4:1时,在前一帧中主控制器只处理了控制列表的两个端点描述符,那么在下一帧中处理非周期列表时她会接着继续处理剩下的两个端点,之后开始处理块列表中的端点(注意只处理块列表里的一个端点)。
对于主控制器处理一个端点描述符,当主控制器在USB总线上为该端点发起一个事务(事务:transaction,当USB总线上完成了令牌、数据、握手三个阶段后认为是一个事务)后 ,我们认为主控制器处理过了这个端点(无论此事务是否成功)。如果没有发起一个事务,就认为没有处理该端点。如果是这样,那么在主控制器转换到USB可操作态开始处理非周期列表时,假如要处理控制列表里的3个端点,但未对这三个端点发起事务,也就是没有处理这三个端点,那么在转入块列表时,主控制器任然保留这三个端点。
在列表中,主控制器轮流处理原则处理端点描述符。一开始先处理列表头的端点描述符,继而依此处理其它的描述符。当主控制器处理到列表尾的时候,又开始处理表头的端点描述符。在处理端点描述符时,主控制器处理链接在该端点上的第一个传输描述符,但只在USB总线上发起一次事务,无论此事务是否成功。之后就开始处理下一个端点。
队列上的传输描述符的优先级是先来先处理。主控制器总是处理链接在队列上的第一个传输描述符,也就是端点描述符中的NextTransferDescriptor域所指向的。当那个传输描述符“退休“(被主控制器处理完了)后,她就从队列中移除,她的NextTransferDescriptor域中指向的传输描述符(此时端点描述符中的NextTransferDescriptor域指向她)就会移到第一位置。前面已经说过,当主控制器处理一个端点描述符时,只发起一次事务,之后去处理下一个端点。而并不会去把当前端点描述符的传输描述符都处理完。
这部分描述了主控制器在处理列表时需要的动作。这些动作是在主控制器确定了那个列表需要处理后采取的。图6-5描述了列表的服务流程。
当处理列表时,主控制器采取的第一个动作是检测列表是否被使能。为了变更端点或是其他的原因,主控制器驱动会定期禁止列表。如果列表被使能,主控制器可以处理此列表,但如果列表被禁止,主控制器会跳转到下一个列表。可以通过操作HcControl寄存器中的列表使能位来禁止/使能列表。如果列表在一个帧中被禁止,主控制器就不需要再处理此列表了,然而,当一个列表被使能时,主控制器将不需要等到下一帧而立即在当前帧去处理此列表。In addition, when a list is enabled after being previously disabled, the only piece of information the Host Controller may assume is valid is the list’s “HeadED” pointer and, if a nonperiodic list, the list’s “CurrentED” pointer.(此句不明白什么意思)
IsochronousListEnable位被用来禁止处理放在周期列表尾部的同步列表。如果主控制器在处理周期列表时发现了一个同步描述符,而IsochronousListEnable位是0,那么主控制器会停止处理此列表。
Figure 6-5: List Service Flow
判定了一个列表使能之后,主控制器就会定位第一个需要处理的端点描述符。进入USB可操作态后主控制器第一时间处理一个列表,她使用列表头指针定位第一个列表上的端点。如果头指针是0,那么该列表上没有端点描述符,主控制器将处理下一个列表。
当主控制器处理中断(周期)列表时,她总是用头指针来找第一个端点描述符。所有的中断头指针都位于HccaInterruptTable中,主控制器通过使用HcFmNumber寄存器的FrameNumber域的低五位作为表索引入口来决定使用那个头指针。例如:一个二进制的索引值00000相当于是偏移0x00的头指针;一个二进制的索引值11111相当于是偏移0x7C的头指针(一个中断入口占用4个字节,所以用索引值乘上4就是要进入的中断入口地址)。
在非周期列表的情况时,操作略有不同。当处在非周期处理时间段里,主控制器可能在单一的帧中不能处理完整个列表。在轮流处理原则中,为了满足能够处理所有的端点,主控制器必须为每个列表(块列表和控制列表)维护一个“CurrentED”指针(块的用HcBulkCurrentED 寄存器,控制的用HcControlCurrentED 寄存器)。这两个指针总是指向各自列表上的下一个端点描述符。当处理非周期列表时,主控制器检测HcBulkCurrentED 寄存器或是HcControlCurrentED 寄存器是否为一个非零值。如果“CurrentED” 寄存器的值是一个指向一个端点的非零值,主控制器将尝试去处理此端点描述符。如果“CurrentED” 寄存器的值是‘0’,主控制器已经处理到了列表尾部。此时,主控制器检测HcCommandStatus 寄存器的BulkListFilled 位或ControlListFilled 位,如果是‘1’,至少相应的列表上有一个端点描述符需要处理。这种情况下,主控制器将把HcControlHeadED 或HcBulkHeadED 中的值复制到HcControlCurrentED 或HcBulkCurrentED 中,然后清除“Filled”位为‘0’,并且开始尝试去处理“CurrentED”寄存器指向的端点描述符。如果“Filled”位是‘0’,列表上没有需要处理的端点描述符,主控制器转向下一个列表。
处理完一个端点描述符后,主控制器的下一步操作决定于列表类型。如果当前列表是周期列表,主控制器会检测刚处理完的端点描述符中的NextEndpointDescriptor指针。如果是非零,主控制器继续处理下一个端点描述符。如果是零,主控制器转向非周期列表。如果当前列表是块列表,主控制器会转向下一个列表。如果当前列表是控制列表,主控制器会判断当前是否满足了控制和块比值要求,如果满足,主控制器转向下一个列表,否则,继续处理处理控制端点描述符。
当主控制器读一个端点时,她首先判断描述符是否该跳过。如果端点描述符中的sKip为或Halt位是‘1’,此端点将被跳过,主控制器将处理下一个端点描述符或是下一个列表。如果不跳过该端点描述符,主控制器将确定该端点上有无传输描述符。如果没有传输描述符,主控制器处理下一个端点描述符或下一个列表。
如果确定端点描述符上有一个传输描述符,主控制器会比较端点描述符的TailPointer域和NextTransferDescriptor 域,如果这两个域不同,那么就有一个传输描述符等待处理。如果两个域的值相等,就没有一个有效的传输描述符。主控制起在处理有效传输描述符时,只会发起一次事务(事务:transaction,当USB总线上完成了令牌、数据、握手三个阶段后认为是一个事务)。
传输描述符的处理是主控制器执行的基本操作。图6-7展示了一个传输描述符的处理流程。
当处理一个同步传输描述符时,主控制器必须计算相对帧号。对相对帧号的计算将确定哪个数据包在当前帧被发送。计算方法在4.3.2.1部分描述。
当处理一个传输描述符时,相对帧号(R,计算方法在4.3.2.1部分描述)用来选择两个偏移值,Offset[R] 和Offset[R+1]。如果R等于传输描述符中的FrameCount 域,那么Offset[R+1]就是(BufferEnd+1)。用Offset[R+1]减去Offset[R]就会得到数据缓存区的大小,此值不得大于端点描述符中MaximumPacketSize 域中的值(主控制器不会对此进行检测,所以如果软件违反了这个规定,传输就会出现问题)。传输的起始地址由Offset[R]决定,如果Offset[R]的位12(从地位数第13位)是0,那么缓存区的首地址就位于同步传输描述符中BufferPage0 指示的物理内存页里。如果位12是1,那么缓冲区的首地址就位于BufferEnd 中20位以上指示的物理地址。当缓冲区的20位以上的地址确定了以后,她的低12位地址就可以用Offset[R]的低12位来确定。如果Offset[R]和Offset[R+1] 的位12的值一样,那么传输的数据包就不会跨页,如果不一样(Offset[R]的位12是0,Offset[R+1] 的位12是1),那么传输的数据包就会跨页。
Figure 6-7: Transfer Descriptor Service Flow
当主控制器取出一个传输描述符时,她先得到能够从CurrentBufferPointer进入的下一个内存位置的地址。如果CurrentBufferPointer是0,那么数据包的大小也是0,而忽略端点描述符中MaximumPacketSize的值。当数据在CurrentBufferPointer地址上(接受/发送)传输时,CurrentBufferPointer值可能跨越页边界。如过出现这种情况,BufferEnd的20位以上的值将替代当前CurrentBufferPointer的20位以上的值。页边界跨越可能在数据包传输是发生。
接收或发送的数据的最大值是由端点描述符中MaximumPacketSize的值或是传输描述符中给出的剩余的缓冲区的大小决定的。剩余缓冲区大小等于CurrentBufferPointer和BufferEnd的差值。The subtraction may be performed by using two 13-bit terms A and B. The most significant bit of A is set to 0 if CurrentBufferPointer and BufferEnd are identical in their most significant 20 bits (i.e., they indicate the same physical page in memory) and set to 1 if they differ. The most significant bit of B is set to 0. The low order 12 bits of A and B are the low order 12 bits of BufferEnd and CurrentBufferPointer respectively. To the results of A - B add 1 to get the remaining space in the buffer.(此段不明白)
主控制器一旦确定了数据包大小,就必须检测该数据包在帧结束时能否传输完毕。这可以通过帧剩余时间和数据包传输所需的时间进行比较来确定。如果数据包传输所需的时间大于帧剩余的时间,那么将不会发起该传输。对于全速传输,主控制器使用最大数据包计数器来确定一个数据包是否被传输。而对于低速传输,主控制器会忽略数据包大小,而是比较HcFmRemaining 寄存器中FrameRemaining 域的值和HcLSThreshold 寄存器中LSThreshold 域的值,如果FrameRemaining 的值小于LSThreshold 的值,将不会开始低速传输。
在每个帧边界,HcFmInterval寄存器中FSLargestDataPacket域的值赋给最大数据包计数器,同时FrameInterval的值赋给FrameRemaining。USB总线上每7个位时间,最大数据包计数器将递减6个位时间,因为在相同的传输速率下,当总线上位时间经过位填充时,有用的位时间数量不减少。当主控制器加载一个传输描述符时,传输描述符上数据包在总线上传输的最坏情况下的位时间数已经被知道。这个值就是MaximumPacketSize乘上8。如果此值大于Largest Data Packet Counter中剩余的位时间,将不会开始该传输,此时,不会有状态信息写回传输描述符。
一个事务完成后,主控制器将状态写回传输描述符。处理的传输描述符类型不同,写回的状态信息也不同。
在一个事务完成后,主控制器通常会对传输描述符的四个域做出正确的更新:CompletionCode域、DataToggleControl域、CurrentBufferPointer域、ErrorCount域。
DataToggleControl域被更新是为了指出下一个传输的触发值。如果数据包被成功的传输,主控制器就会将DataToggleControl域的MSb置位,并触发LSb反转。这样就指出了下一个数据包的触发值。如果发送了数据包,而未收到ACK 或 NAK(和红字部分说法有点冲突),此域不需要改变。
如果一个传输结束后,无论是成功还是出错,CurrentBufferPointer必须被更新,以指示出当前传输的数据包的数量。如果主控制器收到的握手包是ACK或NAK,而数据触发是错误的,CurrentBufferPointer将不会更新,稍后主控制器会重试此传输。其实更新CurrentBufferPointer就是把传输的数据包的字节数加到CurrentBufferPointer域上。如果如果数据包跨越了页边界,那么就不仅仅是将传输的数据包字节数加到CurrentBufferPointer域上,还要将CurrentBufferPointer域的20位以上的值用CurrentBufferPointer域的20位以上的值来替换。
如果数据包传输是发生了一个错误,ErrorCount域必须加1。当ErrorCount等于2时,如果在出现一此错误,传输描述符将退休,并在CompletionCode域标志出错误码。
在一个事务被处理完后,无论成功与否,传输描述符的CompletionCode域都会被更新。如果成功,CompletionCode域被设置成“No Error”,否则,被设置成相应的错误码。
发起事务时,当端点返回NAK握手包,所有的普通传输描述符不会被更新,主控制器不会对她做任何改变。
主控制器在数据包传输后用数据包状态字来更新Offset[R]/PSW(PacketStatusWord)。对于OUT包,在不出错时Size域设置成0。对于IN包,Size域就是写到内存缓存区的实际字节数。对于CompletionCode域,无论是OUT包还是IN包,被用来反映传输结果。
当一个传输描述符被处理完后(所有的数据被接收或发送)或是处理时出现了问题,传输描述符都会退休。一个传输描述符的退休需要完成几个动作:主控制器必须将传输描述符放入完成队列;更新完成队列的中断计数器值;更新端点描述符中的NextTransferDescriptor指针、DataToggleCarry域,也有可能需要更新Halt域。
传输描述符去列时,主控制器会将该传输描述符中NextTransferDescriptor域的值复制到端点描述符中的NextTransferDescriptor域中。
传输描述符从端点描述符队列上出列后就别链接到了完成队列上了。为了完成此任务,主控制器首先把HcDoneHead寄存器的值写入传输描述符中NextTransferDescriptor域,其次将传输描述符的地址写入HcDoneHead寄存器。
主控制器也必须更新端点描述符的DataToggleCarry域。DataToggleCarry域是用来指示出传输描述符退休时的最后的触发值。如果一个传输描述符是由于一个错误而退休的,那么主控制器就必须更新端点描述符的Halt位。
为了完成传输描述符的退休,主控制器还需要更新完成队列的中断计数器。传输描述符的InterruptDelay域给出了,在主控制器把HcDoneHead写入HCCA之前,产生一个中断的最大SOF包的数量。如果InterruptDelay域的值是111b,主控制器驱动就不需要为传输描述符产生一个中断,同时完成队列中断计数器不会被改变。如果InterruptDelay域的值不是111b,但是大于或是等于完成队列中断计数器的值,计数器也不会改变。出此情况,是因为在完成队列上有其它的传输描述符要比刚退休的传输描述符产生的中断早。如果InterruptDelay域的值不是111b,且小于完成队列中断计数器的值,InterruptDelay域的值就会装载到完成队列中断计数器中。这种情况下,刚退休的传输描述符要比完成队列上的其它所有的传输描述符产生的中都要早。如果传输描述符是由于错误而退休,那么若InterruptDelay域是0的话,完成队列中断计数器将清零
当完成队列中包含有一个或多个传输描述符时,主控制器会不定期的在帧边界处将HcDoneHead寄存器中的值写入HccaDoneHead(是否写入是根据完成队列中断计数器来确定的),并产生一个中断。这样,主控制器驱动就可以来完成对退休的传输描述符的处理。当HcDoneHead的值写入HCCA后,主控制器复位HcDoneHead的值为0,并设置HcInterruptStatus寄存器中WritebackDoneHead位为1。当主控制器驱动已经准备好接收下一个来自主控制器上的完成队列时,她会清除WritebackDoneHead位为0。
主控制器维护一个3位的计数器,用她来确定HcDoneHead寄存器的值写入HccaDoneHead中的频率。当软件复位时、硬件复位时或是主控制器转换到USB可操作状态时,计数器被初始化为111b。
计数器的功能是在主控制器处于USB可操作态时,每一个帧边界都会递减1。而如果当计算器的值是111b或0时,计数器被禁止,且不会递减。
USB可操作态时,主控制器在每一帧的最后一个位时间里检测计数器的值,如果计数器的值是0,主控制器检测HcInterruptStatus中WritebackDoneHead位的值,如果WritebackDoneHead是0,主控制器会在帧边界之后把HcDoneHead寄存器的值写入HccaDoneHead,然后设置WritebackDoneHead位为1,并复位计数器为111b。如果WritebackDoneHead位是1,主控制器不会有更进一步的动作,直到下一个帧边界,主控制器才会再一次检测WritebackDoneHead位。
中断是中控制器发起的与主控制器驱动通讯的一种通讯方法。有几种来自主控制器的事件可能会引起一个中断。每一种特殊的事件都会在HcInterruptStatus寄存器中设置一个特殊的位。当遇到下面的情况,主控制器就会需要一个中断:
· HcControl寄存器里的MasterInterruptEnable被设置成‘1’
· HcInterruptStatus中的一位被设置成‘1’
· 在HcInterruptEnable中和HcInterruptStatus中位相对应的使能位被设置为‘1’
如果主控制器支持SMI管脚,那么大多数事件引起的中断都会根据HcControl寄存器中InterruptRouting位的值来路由该中断到INT管脚还是到SMI管脚。当InterruptRouting位是‘0’时,则使能的中断事件就会在INT管脚上产生中断信号,如果InterruptRouting位是‘1’,则使能的中断事件就会在SMI管脚上产生中断信号。然而,OpenHCI主控制器不需要实现SMI管脚。所以当InterruptRouting位是‘1’时,中断不会产生。而需要我们注意的是6.5.8部分描述的,当是一个OwnershipChange事件时,总会被路由到SMI管脚。
下面每一个部分都描述了一个特殊事件,并且HcInterruptStatus寄存器中每一个特殊位都代表了一个特殊事件。
当发生调度超时时,主控制器在完成下一个HccaFrameNumber更新后将SchedulingOverrun位置位。当主控制器确定周期列表不能在当前帧帧结束时完成时,调度超时发生。
主控制器需要周期性的使用HcDoneHead寄存器的值来更新HccaDoneHead。当HcDoneHead到HccaDoneHead的写操作完成时,主控制器将WritebackDoneHead位置位。主控制器驱动就会执行相应的中断程序来处理完成队列。
当FrameInterval的值装载到FrameRemaining中时,主控制器在完成了对下一个HccaFrameNumber更新后,对StartOfFrame置位。此事件中断发生在帧边界。所以主控制器驱动一般禁止此事件,只有当在帧边界需要中断时,才会使能此事件。
当root hub在USB总线上发现了一个恢复信号时,恢复侦查时间发生。此时,主控制器将ResumeDetected位置位。
If a port is either in the progress of selectively resuming or has completed the selective resume and set PortSuspendStatusChange when the Root Hub enters the UsbSuspend state, the port resume is cleared and the hub resume, ResumeDetected, is generated.
ResumeDetected中断只有可能发生在USB暂停态。恢复事件指的是:1、向上游发出的恢复信号;2、在端口上侦查到一个连接/断开。通过设置HcRhStatus寄存器中RemoteWakeupEnable位来使能一个连接/断开恢复事件。当PortSuspendStatusChange位是1,root hub进入USB暂停态时,If a port is either in the progress of selectively resuming or has completed the selective resume,端口恢复被清除,hub恢复(ResumeDetected事件)发生。If a port is either in the progress of selectively resuming or has completed the selective resume and set PortSuspendStatusChange when the Root Hub enters the UsbSuspend state, the port resume is cleared and the hub resume, ResumeDetected, is generated.(此句可能翻译的不太准确)
注意:硬件发起一个从USB暂停态向USB恢复态转换时,ResumeDetected中断才会发生。
当主控制器侦查到一个与USB无关的系统错误或是一个不能报告的错误时,将UnrecoverableError位置位。
当HcFmNumber寄存器中FrameNumber域的最高位(MSb (bit 15))跳变时(从1到0或从0到1),主控制器在完成了对HccaFrameNumber的更新后,将FrameNumberOverflow位置位。此事件允许主控制器驱动来对软件自己的基准帧号做必要的篡改,以保证帧号的正确性。
只要在HcRhStatus或是HcRhPortStatus中,有任何一位有变化,主控制器都会将RootHubStatusChange位置位。HcRhStatus和HcRhPortStatus寄存器的改变都会有一个状态变化,每一个状态变化都会产生一个中断,来由主控制器驱动处理。由于OpenHCI为root hub提供了寄存器级别的接口,所以就将root hub传输描述符省略了。
当主控制器驱动设置了HcCommandStatus寄存器中OwnershipChangeRequest位时(置位),主控制器就会设置OwnershipChange位。这样可以保证当操作系统的主控制器驱动或基于SMM的系统主控制器驱动获取或放弃主控制器的所有权时,能够产生一个中断。而此事件中断总是被路由到SMI管脚上。如果主控制器未实现SMI管脚,OwnershipChange事件中断不会产生。
USB规范定义了root hub的功能操作。OpenHCI规范只是定义了标寄存器级别的接口。通过寄存器接口,主控制器驱动可以模仿标准的hub端点通信。第七章描述了这些寄存器接口。
通过控制HostControllerFunctionalState位,来控制root hub的USB复位信号和USB恢复信号。主控制器驱动负责与这些操作有关的时序。而端口的复位信号和恢复信号是由硬件来控制的。