注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

嵌入式开发实战4——内核的编译之十六MMC(SD、SDIO)卡的驱动说明3  

2012-07-19 21:31:34|  分类: ARM开发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

嵌入式开发实战4——内核的编译之十六MMC(SD、SDIO)卡的驱动说明3


 
接着说上一回的函数,477-480这几行,非常明显,是位图的映射的控制,主要是用来状态控制的。495行分配了个gendisk结构,前面讲过这个东西,这里不再赘述,再下来,可就是真正有戏的东西出来了:
ret = mmc_init_queue(&md->queue, card, &md->lock);
好,那就跳到这个函数里:

card/queue.c

111  int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)   

112  {                                            

113            struct mmc_host *host = card->host;                                

114            u64 limit = BLK_BOUNCE_HIGH;                                

115            int ret;                                 

116                                                

117            if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)                                 

118                     limit = *mmc_dev(host)->dma_mask;                      

119                                                

120            mq->card = card;                                

121            mq->queue = blk_init_queue(mmc_request, lock);                                    

122            if (!mq->queue)                                   

123                     return -ENOMEM;                     

124                                                

125            mq->queue->queuedata = mq;                                   

126            mq->req = NULL;                                 

127                                                

128            blk_queue_prep_rq(mq->queue, mmc_prep_request);                            

129            blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);                               

130            queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);                            

131                                                

132  #ifdef CONFIG_MMC_BLOCK_BOUNCE                                     

133            if (host->max_hw_segs == 1) {                                    

134                     unsigned int bouncesz;                     

135                                                

136                     bouncesz = MMC_QUEUE_BOUNCESZ;                   

137                                                

138                     if (bouncesz > host->max_req_size)                          

139                              bouncesz = host->max_req_size;            

140                     if (bouncesz > host->max_seg_size)                          

141                              bouncesz = host->max_seg_size;            

142                     if (bouncesz > (host->max_blk_count * 512))                   

143                              bouncesz = host->max_blk_count * 512;                 

144                                                

145                     if (bouncesz > 512) {                           

146                              mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);            

147                              if (!mq->bounce_buf) {             

148                                        printk(KERN_WARNING "%s: unable to "       

149                                                 allocate bounce buffer\n,

150                                                 mmc_card_name(card));

151                              }                

152                     }                          

153                                                

154                     if (mq->bounce_buf) {                        

155                              blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);          

156                              blk_queue_max_sectors(mq->queue, bouncesz / 512);         

157                              blk_queue_max_phys_segments(mq->queue, bouncesz / 512);            

158                              blk_queue_max_hw_segments(mq->queue, bouncesz / 512);               

159                              blk_queue_max_segment_size(mq->queue, bouncesz);                 

160                                                

161                              mq->sg = kmalloc(sizeof(struct scatterlist),            

162                                        GFP_KERNEL);

163                              if (!mq->sg) {            

164                                        ret = -ENOMEM;     

165                                        goto cleanup_queue;      

166                              }                

167                              sg_init_table(mq->sg, 1);                 

168                                                

169                              mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *            

170                                        bouncesz / 512, GFP_KERNEL);       

171                              if (!mq->bounce_sg) {               

172                                        ret = -ENOMEM;     

173                                        goto cleanup_queue;      

174                              }                

175                              sg_init_table(mq->bounce_sg, bouncesz / 512);            

176                     }                          

177            }                                   

178  #endif                                           

179                                                

180            if (!mq->bounce_buf) {                                

181                     blk_queue_bounce_limit(mq->queue, limit);                    

182                     blk_queue_max_sectors(mq->queue,                      

183                              min(host->max_blk_count, host->max_req_size / 512));                

184                     blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);                          

185                     blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);                       

186                     blk_queue_max_segment_size(mq->queue, host->max_seg_size);                        

187                                                

188                     mq->sg = kmalloc(sizeof(struct scatterlist) *                   

189                              host->max_phys_segs, GFP_KERNEL);            

190                     if (!mq->sg) {                      

191                              ret = -ENOMEM;              

192                              goto cleanup_queue;               

193                     }                          

194                     sg_init_table(mq->sg, host->max_phys_segs);                        

195            }                                   

196                                                

197            init_MUTEX(&mq->thread_sem);                              

198                                                

199            mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");                                     

200            if (IS_ERR(mq->thread)) {                                    

201                     ret = PTR_ERR(mq->thread);                    

202                     goto free_bounce_sg;                       

203            }                                   

204                                                

205            return 0;                             

206  free_bounce_sg:                                        

207         if (mq->bounce_sg)                            

208                  kfree(mq->bounce_sg);                     

209         mq->bounce_sg = NULL;                            

210  cleanup_queue:                                         

211         if (mq->sg)                                   

212                     kfree(mq->sg);                           

213            mq->sg = NULL;                                   

214            if (mq->bounce_buf)                                    

215                     kfree(mq->bounce_buf);                   

216            mq->bounce_buf = NULL;                                    

217            blk_cleanup_queue(mq->queue);                               

218            return ret;                                   


219 }
又臭又长的代码,看121行:
mq->queue = blk_init_queue(mmc_request, lock);
顾名思义,初始化队列么,并且将MMC的请求函数利用函数指针传进去。下来还有两个函数:

128            blk_queue_prep_rq(mq->queue, mmc_prep_request);为请求队列定义准备函数                       

129            blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);             这个函数是进行屏蔽请求服务的。             

card/queue.c:

29     static int mmc_prep_request(struct request_queue *q, struct request *req)              

30     {                

31              /*    

32              * We only like normal block requests.  

33              */  

34              if (!blk_fs_request(req)) {        

35                       blk_dump_rq_flags(req, "MMC bad request");

36                       return BLKPREP_KILL;

37              }       

38                      

39              req->cmd_flags |= REQ_DONTPREP;     

40                      

41              return BLKPREP_OK;       

42     }       


这个函数不怎么用得到,主要是进行请求的过滤,对一些不合理的请求该CUT就得CUT,别手软。
第132-178行,也就是预编译宏部分,主要是进行平衡服务请求的,

181-186行根据主机控制器的特性来设置请求队列的一些属性。

189-194行散列存储结构struct scatterlist的申请与初始化。

199行创建并启动内核线程,关于这个线程所做的工作,在MINI2440的编译手册上有比较详细的说明。

这样子的话,就又回到了mmc_blk_alloc函数。

第508行:     md->queue.issue_fn = mmc_blk_issue_rq;放到内核线程时候再详细分析。

         md->queue.data = md;

 

         md->disk->major      = MMC_BLOCK_MAJOR;

         md->disk->first_minor = devidx << MMC_SHIFT;

         md->disk->fops = &mmc_bdops;

         md->disk->private_data = md;

         md->disk->queue = md->queue.queue;

         md->disk->driverfs_dev = &card->dev;

对前面分配的gendisk进行必要的参数设置。至于设置这个有啥用,大家慢慢看,别急。

第530-546行:

         sprintf(md->disk->disk_name, "mmcblk%d", devidx);

 

         blk_queue_logical_block_size(md->queue.queue, 512);

 

         if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {

                   /*

                    * The EXT_CSD sector count is in number or 512 byte

                    * sectors.

                    */

                   set_capacity(md->disk, card->ext_csd.sectors);

         } else {

                   /*

                    * The CSD capacity field is in units of read_blkbits.

                    * set_capacity takes units of 512 bytes.

                    */

                   set_capacity(md->disk,

                            card->csd.capacity << (card->csd.read_blkbits - 9));

继续设置gendisk的一些属性状态值,为后面的add_disk做准备。

这样很OK,就回到了mmc_blk_probe这个函数中。

第601行:

err = mmc_blk_set_blksize(md, card);

card/block.c:

558  static int                    

559  mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)                   

560  {                          

561            struct mmc_command cmd;           

562            int err;              

563                             

564            /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */           

565            if (mmc_card_blockaddr(card))                

566                     return 0; 

567                             

568            mmc_claim_host(card->host);                 

569            cmd.opcode = MMC_SET_BLOCKLEN;            

570            cmd.arg = 512;                 

571            cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;              

572            err = mmc_wait_for_cmd(card->host, &cmd, 5);           

573            mmc_release_host(card->host);             

574                             

575            if (err) {             

576                     printk(KERN_ERR "%s: unable to set block size to %d: %d\n",      

577                              md->disk->disk_name, cmd.arg, err);

578                     return -EINVAL;       

579            }                

580                             

581            return 0;          

582  }       

这个函数说很复杂,不过简单来说吧。这个函数主要是用来进行SD卡的扇区设置的,当然如果在这个函数里会得到一些配置的命令参数,如果不允许设置就直接返回呗,否则就通过CORE层的服务函数交给HOST层搞定扇区设置。

mmc_claim_host(card->host);取得控制器

err = mmc_wait_for_cmd(card->host, &cmd, 5);前面说得通过CORE函数交给HOST搞定扇区的函数

mmc_release_host(card->host);释放控制器

这样,胡汉三又回到了mmc_blk_probe中去。

第611行,LINUX中的老风格:

mmc_set_drvdata(card, md); #define mmc_set_drvdata(c,d)       dev_set_drvdata(&(c)->dev, d)

目的很简单,通过设置可以互相访问。

然后,然后就是add_disk(md->disk);

/**

 * add_disk - add partitioning information to kernel list

 * @disk: per-device partitioning information

 *

 * This function registers the partitioning information in @disk

 * with the kernel.

 *

 * FIXME: error handling

 */

void add_disk(struct gendisk *disk)

{

         struct backing_dev_info *bdi;

         dev_t devt;

         int retval;

 

         /* minors == 0 indicates to use ext devt from part0 and should

          * be accompanied with EXT_DEVT flag.  Make sure all

          * parameters make sense.

          */

         WARN_ON(disk->minors && !(disk->major || disk->first_minor));

         WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT));

 

         disk->flags |= GENHD_FL_UP;

 

         retval = blk_alloc_devt(&disk->part0, &devt);

         if (retval) {

                   WARN_ON(1);

                   return;

         }

         disk_to_dev(disk)->devt = devt;

 

         /* ->major and ->first_minor aren't supposed to be

          * dereferenced from here on, but set them just in case.

          */

         disk->major = MAJOR(devt);

         disk->first_minor = MINOR(devt);

 

         blk_register_region(disk_devt(disk), disk->minors, NULL,

                                exact_match, exact_lock, disk);

         register_disk(disk);

         blk_register_queue(disk);

 

         bdi = &disk->queue->backing_dev_info;

         bdi_register_dev(bdi, disk_devt(disk));

         retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj, "bdi");

         WARN_ON(retval);

}

这个就比较常见了,其实主要是在最后几行,前面也讲过,真正的设备的注册就在这个函数里。然后,这个mmc_blk_probe就完成了自己的任务。

今天就说到这儿,慢慢来。

  评论这张
 
阅读(1474)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017