(莱昂氏unix源代码分析导读-32) RK磁盘驱动

                          by cszhao1980

别紧张,RK磁盘是一种非常简单设备——这一点从其代码量中也可以看出。

首先,它由一个控制器外加 1~8devices组成,这8devices编号为0~7,缓

冲头的b_devminor号记录的就是该device编号,为简单起见,我们不考虑多

8device的情况——对RK磁盘来说,b_devminor部分就是0~7,而major部分为0

 

RK驱动器在core空间上有6个控制寄存器,其起始地址为“ RKADDR

5363: #define RKADDR 0177400

 

通过下列struct可访问到这6个寄存器,莱昂对这几个寄存器有详细的介绍,再次不再赘述。

5376: struct {

5377:    int rkds;

5378:    int rker;

5379:    int rkcs;

5380:    int rkwc;

5381:    int rkba;

5382:    int rkda;

5383: };

 

要启动磁盘驱动,需要首先设置rkdarkbarkwc三个寄存器,然后,设置rkwc

——这就直接启动了磁盘设备。而磁盘操作结束后,会通过矢量地址220产生中断

——处理函数是“rkintr”。

 

首先看一下“rkaddr(bp)”,它会根据输入缓存头内的物理块号,来返回满足rkda

存器格式的值。这个函数容易让人困惑的地方是其对b_dev的处理——记住,我们的

模型里最多只有8device,故“5430: if(m <= 0)”的结果一定为真。

 

函数devstart(bp, devloc, devblk, hbcom)用来启动磁盘驱动器,它有4个参数:

(1)         bp   缓存头,存放此次启动的各种配置信息;

(2)         devloc:指向rkda寄存器,见上面所示struct

(3)         devblk:按rkda格式设置的Block信息,即rkaddr的返回值;

(4)         hbcom:在我们的模型里,都为0。可忽略此项。

 

devstart的操作其实很简单,即按照我们前面所述配置各个寄存器(要理解这一点,

请仔细观察上面列出的struct,看看各个寄存器的位置关系),最后设置rkcs启动操作。

 

如下所示,rkstart是更高层一些的函数,它检查rktab的任务队列,如果还有任务

就调用devstart启动RK设备。

5440: rkstart()

5441: {

5442:     register struct buf *bp;

5443:

5444:     if ((bp = rktab.d_actf) == 0)

5445:     return;

5446:     rktab.d_active++;

5447:     devstart(bp, &RKADDR->rkda, rkaddr(bp), 0);

5448: }

 

RK设备启动后,就自行进行工作,工作完成后通过220中断进入中断处理函数rkintr

 

5451: rkintr()

5452: {

5453:     register struct buf *bp;

5454:

5455:     if (rktab.d_active == 0)

5456:          return;

5457:     bp = rktab.d_actf;

5458:     rktab.d_active = 0;

5459:     if (RKADDR->rkcs < 0) {   /* error bit */

                  ……

5468:     }

5469:     rktab.d_errcnt = 0;

5470:     rktab.d_actf = bp->av_forw;

5471:     iodone(bp);

5472:     rkstart();

5473: }

 

简单起见,我们不讨论设备出错的情况,即5429行的判断一直为假。这样的话,整个

程序就很简单了:

(1)         首先,在进入rkintr时,设备的“忙”标记应该是置位的,否则,就是一个

                 “假中断”,直接退出即可;

(2)         清除“忙”标志,调用iodone()——它主要有两个功能:

                i. 设置Done标记

                   p_flag =| B_DONE

              ii. 通知等待的进程;

【注】:对iodone的描述偏简单了,因为对异步io来讲,情况更复杂些。

 

(3)         取下一个任务,启动之;

                                       

最后,介绍最后一个RK驱动程序——rkstrategy函数。事实上,前面介绍的内容多数

RK驱动程序的内部函数,而rkstrategy才是驱动提供给OS的接口函数。正如莱昂所

说,该函数的开头几行似乎走了弯路,事实上对我们的模型而言,第5397~5401行可

忽略不看。剩下的内容就很清晰了:

(1)         参数abp指向一个缓存头,该结构内记录了要进行的操作信息;

(2)         检查要操作的磁盘块号,如果已经超出RK磁盘的最大块号则报错;

(3)         abp指向的缓存头结构插入到rktab的任务队列中;

(4)         如果此时设备空闲,则调用rkstart启动磁盘操作。

 

 

博客地址:http://blog.csdn.net/cszhao1980

博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html

 

你可能感兴趣的:((莱昂氏unix源代码分析导读-32) RK磁盘驱动)