SD密码卡驱动程序设计.docx

上传人:b****1 文档编号:23275229 上传时间:2023-05-15 格式:DOCX 页数:29 大小:252.90KB
下载 相关 举报
SD密码卡驱动程序设计.docx_第1页
第1页 / 共29页
SD密码卡驱动程序设计.docx_第2页
第2页 / 共29页
SD密码卡驱动程序设计.docx_第3页
第3页 / 共29页
SD密码卡驱动程序设计.docx_第4页
第4页 / 共29页
SD密码卡驱动程序设计.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

SD密码卡驱动程序设计.docx

《SD密码卡驱动程序设计.docx》由会员分享,可在线阅读,更多相关《SD密码卡驱动程序设计.docx(29页珍藏版)》请在冰豆网上搜索。

SD密码卡驱动程序设计.docx

SD密码卡驱动程序设计

SD密码卡驱动程序设计指南

SD卡(SecureDigitalMemoryCard),安全数码卡,是一种基于Flash的新一代存储设备,被广泛地用于便携式设备,例如移动电话、数码相机、个人数码助理(PDA)和多媒体播放器等。

SD卡拥有体积小,容量大、数据传输快、移动灵活及安全等优点。

因其价格低廉,应用也越来越广泛,本章将重点介绍其驱动分析和移植过程。

1.1SD卡简介

SD存储卡是专门为满足安全、大容量和内置于消费者的新型语音和视频电子设备中而设计的。

SD内存卡将包含的机械保护装置,遵循SDMI标准,具有安全、快速、大容量等特性。

SD卡的安全系统采用相互认证和“新密码算法”以防止卡中的内容被非法使用。

下面将从以下几个方面简单介绍SD卡协议内容。

1.1.1SD卡系统概念

下面分别描述SD卡的读写特性、容量、速度、电压等特性和分类。

❑ 读写特性:

根据读写特性可以将SD卡分为两种。

一种为读/写卡,这种卡生产出来就是一张空白卡,专门用于记录用户的视频声音、图像的大容量记忆卡;另一种为只读卡,这种卡在制造时就定制了内容,其典型的应用是在软件、音频或视频等的发行媒体中。

❑ 支持电压:

根据支持的电压可以将SD卡分为高电压SD卡和双重电压SD卡两类。

❑ 卡容量:

根据卡的容量大小将SD分为两类型。

一类为标准容量的SD卡,其支持的容量上线为2GB,包括2GB在内;另一种为高容量SD卡,其容量超过2GB,最大可达32GB。

❑ 速度:

根据速度类可以将SD卡分为4种速度类。

类0,这种类型卡兼具所有类型的优点;类2,其速度大于等于2MB/S;类4,其速度大于等于4MB/S;类6,其速度大于等于6MB/S。

高容量SD卡支持速度类描述,其性能相当于或超过类2。

1.1.2SD卡寄存器

每张卡都有一系列寄存器的信息,寄存器的信息如表1.1所示。

表1.1SD卡寄存器信息

名字

宽度

描述

CID

128

卡识别号,每张卡都有唯一的识别号

RCA

16

发布卡的地址,卡的局部系统地址,在初始化过程中,由主机和卡动态支持

DSR

16

驱动级寄存器,配置卡的驱动输出

CSD

128

卡的协议数据,关于卡的操作状态数据

SCR

64

卡配置寄存器,关于卡特性容量的信息

OCR

32

操作状态寄存器

SSR

512

SD状态,有关卡拥有的特性信息

CSR

32

卡状态,有关卡状态的信息

1.1.3SD功能描述

主机与卡之间的通信都是由主机控制的,主机发送的命令有两种类型,分别为广播命令和地址(点对点)命令。

❑ 广播命令:

该命令是发给所有的卡,有些广播命令需要响应。

❑ 地址(点对点)命令:

这些命令发往具体地址的卡,并且从这些卡生成响应。

❑ 卡识别模式:

主机被复位或者在总线上寻找新卡时,主机处于该状态下。

卡在复位以后和收到SEND_RCA命令以前都处于此模式下。

❑ 数据传输模式:

卡在它们的RCA第一发布后进入数据传输模式。

主机识别总线上所有的卡后进入数据传输模式。

下面通过表1.2说明卡的状态与操作模式之间的依赖关系,SD的每种状态都关联一种操作模式,其状态图将在随后进行介绍。

表1.2卡的状态和操作模式的对应关系

卡状态

操作模式

无活动状态

无活动

空闲态

卡识别模式

准备态

识别态

等待态

数据传输模式

传输态

发送数据态

接收数据态

编程态

断开态

1.操作状态的验证

通过一系列过程后,主机才能识别卡。

下面给出它们的通信过程。

❑ 在主机和卡通信前,主机不知道卡支持的电压,卡也不知道是否支持主机当前提供的电压。

主机将发布一个复位命令(CMD0),带着它能提供给卡的电压信息。

❑ 为了验证SD卡的接口操作状态,主机发送SEND_IF_COND(CMD8),SD卡通过分析SEND_IF_COND命令参数检查操作状态的有效性,主机通过检查SD分析后的响应来判断电压的有效性。

❑ 如果SD能够操作在提供的电压下,则发回的响应带上提供的电压,且检验模式被设置在命令参数中。

如果SD卡不支持主机提供的电压,则不响应且保持在空闲态下。

在发送ACMD41命令初始化高容量SD卡前,强制发送CMD8命令。

❑ 强制低电压主机在发送CMD8前发送ACMD41。

万一双重电压SD卡没有收到CMD8命令且工作在高电压状态,在这种情况下,低电压主机不发送CMD8命令给卡,则收到ACMD41后进入无活动状态。

❑ SD_SEND_OP_COND(ACMD41)命令是为SD卡主机识别卡或电压不匹配时拒绝卡的机制而设计的。

主机发送命令操作数代表要求的电压窗口大小。

如果SD卡在所给的范围内不能实现数据传输,将放弃下一步的总线操作而进入无活动状态。

操作状态寄存器也将被定义。

❑ 在主机发出复位命令(CMD0)后,主机将先发送CMD8再发送ACMD41命令重新初始化SD卡。

卡的识别模式的状态可以用下面的状态图1.1表示。

图1.1卡在识别模式下的命令流程

2.卡的初始化和识别处理

当总线被激活后,主机就开始卡的初始化和识别处理。

初始化处理设置它的操作状态和设置OCR中的HCS比特位命令SD_SEND_OP_COND(ACMD41)开始。

HCS比特位被设置为1表示主机支持高容量SD卡。

HCS被设置为0表示主机不支持高容量SD卡。

3.数据传输模式

卡的识别模式结束后,主机时钟fpp(数据传输时钟速率)将保持为fOD(卡识别模式下的时钟),因为有些卡对操作时钟有限制。

主机必须发送SEND_CSD(CMD9)来获得卡规格数据寄存器内容,如块大小、卡容量等。

广播命令SET_DSR(CMD4)配置所有识别卡的驱动阶段。

它对DSR寄存器进行编程以适应应用总线布局、总线上的卡数目和数据传输频率。

SD卡数据传输模式下的状态图,如图1.3所示。

 

1.2SD卡驱动程序分析

SD卡驱动程序包括驱动的注册和注销、设备接口函数和I/O操作。

在linux-2.6.29内核MMC子系统中支持SD卡驱动。

本节对MMC源码进行分析,后面将介绍SD卡驱动移植过程。

MMC子系统在driver/mmc目录下进行描述,该目录下包括host、core、card这3个文件夹,下面分别对这3个部分进行介绍。

1.2.1host驱动部分

host驱动部分是针对不同类型主机的驱动,支持的开发板包括atmel、S3C等。

这里就以S3C系统为例介绍host部分的主要内容。

1.驱动的注册函数

驱动的注册函数s3cmci_init(),用于注册平台设备驱动。

staticint__inits3cmci_init(void)

{

platform_driver_register(&s3cmci_2440_driver);//注册平台设备驱动

return0;

}

2.驱动注销函数

驱动注销函数s3cmci_exit(),用于注销平台设备驱动。

staticvoid__exits3cmci_exit(void)

{

platform_driver_unregister(&s3cmci_2440_driver);//注销平台设备驱动

}

3.接口函数

平台设备接口函数包括probe、remove、shutdown、suspend、resume。

其结构如下:

staticstructplatform_drivers3cmci_2440_driver={

.driver.name="s3c2440-sdi",

.driver.owner=THIS_MODULE,

.probe=s3cmci_2440_probe,

.remove=__devexit_p(s3cmci_remove),

.shutdown=s3cmci_shutdown,

.suspend=s3cmci_suspend,

.resume=s3cmci_resume,

};

4.探针函数

探针函数s3cmci_probe(),用于分配s3cmci_host结构体,然后对该结构体进行设置。

对结构体mmc_host进行设置,将结构体mmc添加到主机。

staticint__devinits3cmci_probe(structplatform_device*pdev,intis2440)

{

structs3cmci_host*host;

structmmc_host*mmc;

intret;

/*为主机设备分配空间*/

mmc=mmc_alloc_host(sizeof(structs3cmci_host),&pdev->dev);

if(!

mmc){

ret=-ENOMEM;

gotoprobe_out;

}

/*对host结构体各个字段进行设置*/

host=mmc_priv(mmc);

host->mmc=mmc;

host->pdev=pdev;

host->is2440=is2440;

/*设置平台数据*/

host->pdata=pdev->dev.platform_data;

if(!

host->pdata){

pdev->dev.platform_data=&s3cmci_def_pdata;

host->pdata=&s3cmci_def_pdata;

}

/*初始化自旋锁,自旋锁在使用前应该被初始化*/

spin_lock_init(&host->complete_lock);

/*函数tasklet_init()用于初始化一个tasklet,参数pio_tasklet是软中断响应函数*/

tasklet_init(&host->pio_tasklet,pio_tasklet,(unsignedlong)host);

/*结构体参数设置*/

host->sdiimsk=S3C2440_SDIIMSK;

host->sdidata=S3C2440_SDIDATA;

host->clk_div=1;

host->dodma=0;

host->complete_what=COMPLETION_NONE;

host->pio_active=XFER_NONE;

host->dma=S3CMCI_DMA;

/*获取平台资源信息*/

host->mem=platform_get_resource(pdev,IORESOURCE_MEM,0);

/*该函数的任务是检查申请的资源是否可用,如果可用则申请成功,并标志为已经使用,其他驱动想再申请该资源时就会失败*/

host->mem=request_mem_region(host->mem->start,

RESSIZE(host->mem),pdev->name);

/*系统在运行时,外设的I/O内存资源的物理地址是已知的,由硬件的设计决定。

但是CPU

通常并没有为这些已知的外设I/O内存资源的物理地址预定义虚拟地址范围,驱动程序并不能直接通过物理地址访问I/O内存资源,而必须将它们映射到内核虚地址空间内(采用页表),然后才能根据映射所得到的内核虚地址范围,通过访内指令访问这些I/O内存资源。

*/

host->base=ioremap(host->mem->start,RESSIZE(host->mem));

/*获取设备的中断号*/

host->irq=platform_get_irq(pdev,0);

if(host->irq==0){

dev_err(&pdev->dev,"failedtogetinterruptresouce.\n");

ret=-EINVAL;

gotoprobe_iounmap;

}

/*向系统申请中断*/

if(request_irq(host->irq,s3cmci_irq,0,DRIVER_NAME,host)){

dev_err(&pdev->dev,"failedtorequestmciinterrupt.\n");

ret=-ENOENT;

gotoprobe_iounmap;

}

/*关闭中断*/

disable_irq(host->irq);

/*给定端口号转换为中断号*/

host->irq_cd=s3c2410_gpio_getirq(host->pdata->gpio_detect);

/*添加irq_cd的中断号为IRQ_EINT16且设置GPG8脚为16号中断的输入引脚*/

host->irq_cd=IRQ_EINT16;

s3c2410_gpio_cfgpin(S3C2410_GPG8,S3C2410_GPG8_EINT16);

/*获取dma通道的控制权*/

s3c2410_dma_request(S3CMCI_DMA,&s3cmci_dma_client,NULL);

/*获取时钟响应给时钟的生产者producer()*/

host->clk=clk_get(&pdev->dev,"sdi");

/*当时钟源运行的时候通知系统,参数host->clk为时钟源*/

clk_enable(host->clk);

/*获得当前时钟频率*/

host->clk_rate=clk_get_rate(host->clk);

/*下面是对mmc结构体参数的设置*/

mmc->ops=&s3cmci_ops;

mmc->ocr_avail=MMC_VDD_32_33|MMC_VDD_33_34;

mmc->caps=MMC_CAP_4_BIT_DATA;

mmc->f_min=host->clk_rate/(host->clk_div*256);

mmc->f_max=host->clk_rate/host->clk_div;

if(host->pdata->ocr_avail)

mmc->ocr_avail=host->pdata->ocr_avail;

mmc->max_blk_count=4095;

mmc->max_blk_size=4095;

mmc->max_req_size=4095*512;

mmc->max_seg_size=mmc->max_req_size;

mmc->max_phys_segs=128;

mmc->max_hw_segs=128;

/*注册带CPU频率的host驱动*/

s3cmci_cpufreq_register(host);

/*初始化mmc*/

mmc_add_host(mmc);

/*设置驱动数据*/

platform_set_drvdata(pdev,mmc);

return0;

}

5.mmc接口函数

mmc子系统的接口函数包括request、set_ios、get_ro、get_cds。

其结构如下:

staticstructmmc_host_opss3cmci_ops={

.request=s3cmci_request,//实现命令和数据的发送

.set_ios=s3cmci_set_ios,//根据核心层传来的ios来设置硬件IO

.get_ro=s3cmci_get_ro,//从GPIO口读取,判断卡是否写保护

.get_cd=s3cmci_card_present,//从GPIO口读取,判断卡是否存在

};

6.传递结构体为mmc_request类型的请求

函数s3cmci_request()用于CORE部分发送mrq请求。

staticvoids3cmci_request(structmmc_host*mmc,structmmc_request*mrq)

{

structs3cmci_host*host=mmc_priv(mmc);

host->status="mmcrequest";

host->cmd_is_stop=0;

host->mrq=mrq;

/*如果卡准备就绪,则通过s3cmci_send_request()发送请求,将mrq赋给host->mrq,如果卡没有准备就绪,则调用mmc_request_done()终止请求*/

if(s3cmci_card_present(mmc)==0){

dbg(host,dbg_err,"%s:

nomediumpresent\n",__func__);

host->mrq->cmd->error=-ENOMEDIUM;

mmc_request_done(mmc,mrq);

}else

/*函数s3cmci_send_request()首先判断是否为发送数据命令,如果为发送数据则通过函数s3cmci_send_request()建立数据,然后判断是否为dma方式,如果为dma方式则通过dma方式发送数据,否则采用fifo方式发送数据。

如果为命令则通过函数s3cmci_send_command()发送命令*/

s3cmci_send_request(mmc);

}

1.2.2core驱动部分

core驱动部分完成不同协议和规范的实现,包括设置在1.1节中介绍的有关SD卡相关的状态或修改状态、修改寄存器等操作。

1.用于卡的探测和初始化函数mmc_sd_init_card()

在重启时,函数mmc_sd_init_card()参数oldcard中包含准备初始化的卡,该函数检测卡的有效性,并对该卡初始化。

该函数首先让卡的状态回到空闲态,然后设置操作状态寄存器,接着进行SD卡主机识别或电压匹配,正确识别和匹配后,读取卡的识别号;比较读取的CID与原来的CID是否相同,不相同则需要重新为卡分配结构体;最后对卡进行设置和初始化。

staticintmmc_sd_init_card(structmmc_host*host,u32ocr,structmmc_card*oldcard)

{

structmmc_card*card;

interr;

u32cid[4];

unsignedintmax_dtr;

BUG_ON(!

host);

WARN_ON(!

host->claimed);

/*改变状态寄存器OCR的值时,需要卡的状态回到空闲态。

等待1ms让卡响应*/

mmc_go_idle(host);

/*SD_SEND_IF_COND是用于验证SD卡接口操作状态的有效性命令(CMD8)。

如果SD_SEND_IF_COND指示为符合SD2.0标准的卡,则设置操作状态寄存器ocrbit30指示能够处理块地址SDHC卡*/

err=mmc_send_if_cond(host,ocr);

if(!

err)

ocr|=1<<30;

/*SD_SEND_OP_COND(ACMD41)该命令为SD卡主机识别或电压不匹配时拒绝机制而设计*/

mmc_send_app_op_cond(host,ocr,NULL);

/*如果主机采用SPI总线则采用适当的CRC*/

if(mmc_host_is_spi(host)){

mmc_spi_set_crc(host,use_spi_crc);

}

/*从卡中读取CID,卡的识别号*/

if(mmc_host_is_spi(host))

mmc_send_cid(host,cid);

else

mmc_all_send_cid(host,cid);

/*比较读取的CID与原来的CID是否相同*/

if(oldcard){

if(memcmp(cid,oldcard->raw_cid,sizeof(cid))!

=0){

err=-ENOENT;

gotoerr;

}

card=oldcard;

}else{

/*为卡分配结构体*/

card=mmc_alloc_card(host,&sd_type);

if(IS_ERR(card)){

err=PTR_ERR(card);

gotoerr;

}

/*设置卡的类型*/

card->type=MMC_TYPE_SD;

memcpy(card->raw_cid,cid,sizeof(card->raw_cid));

}

if(!

mmc_host_is_spi(host)){

/*获得卡的RCA,该寄存器表示发布卡的地址,卡的局部系统地址,在初始化过程中,

由主机和卡动态支持*/

mmc_send_relative_addr(host,&card->rca);

/*设置总线模式*/

mmc_set_bus_mode(host,MMC_BUSMODE_PUSHPULL);

}

if(!

oldcard){

/*获得卡CSD,该寄存器表示卡的协议数据,关于卡的操作状态数据*/

mmc_send_csd(card,card->raw_csd);

/*卡的CSD结构的解码*/

mmc_decode_csd(card);

/*卡的CID结构解码*/

mmc_decode_cid(card);

}

if(!

mmc_host_is_spi(host)){

/*选择卡,后续的命令都依赖该操作*/

mmc_select_card(card);

}

if(!

oldcard){

/*获得卡的SCR,该寄存器表示卡配置寄存器,关于卡特性容量的信息*/

mmc_app_send_scr(card,card->raw_scr);

/*解码SCR结构*/

mmc_decode_scr(card);

/*获得卡的switch信息*/

mmc_read_switch(card);

}

/*尝试转化为高速*/

mmc_switch_hs(card);

/*计算总线速率*/

max_dtr=(unsignedint)-1;

if(mmc_card_highspeed(card)){

if(max_dtr>card->sw_caps.hs_max_dtr)

max_dtr=card->sw_caps.hs_max_dtr;

}elseif(max_dtr>card->csd.max_dtr){

max_dtr=card->csd.max_dtr;

}

/*设置可能的最高主机的时钟*/

mmc_set_clock(host,max_dtr

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1