Linux那些事儿之我是UHCI(14)一个函数引发的故事(五)

接着走,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_DEFAULTUSBSOF定义于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 spec2.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,它一共有32bits,位于Base+(08-0Bh),这个寄存器应该包含Frame List在系统内存中的起始地址.其中,bit31bit12对应于内存地址信号[31:12].bit11bit0则是保留位,必须全为0.frame_dma_handle正是我们前面调用dma_alloc_coherentuhci->frame申请内存的时候映射的DMA地址.显然这个地址我们需要写到这个寄存器里,这样主机控制器才会知道去怎么样去访问这个Frame List.基地址的概念是计算机中经常用的,其实生活中也经常用,比如你一个朋友来北京玩,你告诉她去秀水街买假名牌,假设你因为一向孝顺父母,经常去秀水街给他们买假名牌,因而对整条秀水街都特熟悉,那么可能你不用带她去,你直接告诉她说第几家店卖什么,第几家店的什么商品还不错,但是你首先必须告诉她秀水街本身的地理位置,或者说地址,这就是基地址.

接下来, UHCI_MAX_SOF_NUMBER是定义于drivers/usb/host/uhci-hcd.h的宏,值为2047,用二进制来表示就是111,111 1111 1111,USBFRNUM这里我们看到了是6,它对应于UHCI spec中的寄存器FRNUM(FRAME NUMBER REGISTER),地址为Base+(06-07h),这个寄存器一共16bits,这其中bit10bit0包含了当前的Frame,所以把uhci->frame_numberUHCI_MAX_SOF_NUMBER相与就是得到它的bit10bit011bits,即得到Frame号然后写入到FRNUM寄存器中去.unsigned int frame_numberstruct uhci_hcd的一个成员.

然后,设置uhci_to_hcd(uhci)->stateHC_STATE_SUSPENDED,注意我们当初在finish_reset中也有设置过这个状态,只不过当时是设置成了HC_STATE_HALT.凡事都是有因有果的,我们做了这些设置,到时候自然会用到的.别以为写代码的都是无聊做些没意义的事情.

195,pci_write_config_word,写寄存器,写的又是USBLEGSUP,不过这次写的是USBLEGSUP_DEFAULT,这个宏的值为0x2000,这是UHCI spec中规定的默认值.

这样我们就算是配置好了HC,到这里就算万事俱备,只欠东风了.662行就设置uhci->is_initialized1,这意图再明显不过了.

回到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_stopped0.

然后是写寄存器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_stateUHCI_RH_RUNNINNG.并设置uhci_to_hcd(uhci)->poll_rh1.到这里uhci_start就可以返回了,没什么意外的话就返回0.于是咱们还是回到usb_add_hcd中去.

 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值