Chinaunix首页 | 论坛 | 博客
  • 博客访问: 852369
  • 博文数量: 189
  • 博客积分: 4310
  • 博客等级: 上校
  • 技术积分: 1925
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-27 08:56
文章分类

全部博文(189)

文章存档

2015年(1)

2013年(2)

2012年(1)

2011年(39)

2010年(98)

2009年(48)

分类: LINUX

2010-03-28 16:33:58

sd卡驱动主要参照已有的文件即可,2410,9260都挺好。其实写驱动主要是搞清楚工作流程即可。我这里写一些心得与大家分享下,基于2.6.24:


1、主要的结构体:

static const struct mmc_host_ops my_mci_ops =
{
    .request    = my_mci_request,    //命令数据请求
    .set_ios    = my_mci_set_ios,    //设置时钟电源等
    .get_ro        = my_mci_get_ro,    //判断卡是否写保护,readonly

   //新内核还有.set_ro
};

一般的电路板会用gpio来判断卡是否插入,卡是否可以关电源等。这个跟芯片、SD卡座的连接方式有关,不是全部一致。

我们要做的就是.requet和.set_ios函数。

2、首先启动的时候上层会通过调用mmc_detect_change()去枚举卡,这个是照协议来的。在上层的函数中,会先.set_ios来设置sd卡模块的时钟、数据宽度等等。然后调用.request来发送命令、数据请求。

在我们的驱动中,一般是在.request判断要发送的命令、数据类型,然后根据相应的情况设置寄存器的相应位。然后发送命令后,在中断里判断命令是否响应超时还是ok。如果超时就设置返回值为错误,否则设置为正确(0)。然后调用mmc_rquest_done()来结束本次请求。

注意,一定是调用mmc_rquest_done()后上层才会进行下一步操作,否则系统就会死等。


精华之处就在于.rquest函数,其流程大致如下:

1)、先通过request->cmd的flags来判断命令是否需要response、是长还是短response,是否需要data等。根据这些就可以设置你的cmd寄存器。

2)、如果有数据传输的话,那么需要设置相关的dma或者其他方式来操作,这个2410和9260都有很好的范例。

3)、最后写你的寄存器,一般是命令cmd,参数arg,块数blocks,块大小block_size。然后就等待中断吧


中断也很有讲究,因为sd卡协议很繁琐,所以中断里面也必须处理比较多的事件。比如在枚举过程中,上层会发送一些非当前卡的命令,比如插的是sd卡,但发了个cmd5来探测是不是sdio,那么在中断里肯定会收到响应超时,即response timeout的错误。这时候就要返回该错误,让上层知道这个命令对当前卡是没有效的。

另外有数据读写时,因为上层先发命令,所以中断会有好多个。第一个是命令ok的中断,第二个是dma传输完毕的中断,第三个是fifo达到阀值的中断,等等。如果用dma,那么fifo阀值中断可以关掉。但是仍然需要区分另外2个中断。这个可以再request的时候设置一个标志位来判断,方法有很多。

因为传输数据时,块设备用的是scatter(散布表)方面的知识,所以在dma准备阶段会进行dma缓冲区映射请求。等数据读写完毕后再注销该次dma的映射。要注意的是,在注销dma映射时最好不要放到中断里面 ,这可以通过tasklet等来实现。


3、最后说下结构体的几个成员:

.request原型为static void my_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)

阅读(1535) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~