LinuxGod

LinuxGod.net
Linux大神网——精选每一篇高品质的技术干货
  1. 首页
  2. 开源快讯
  3. 正文

引言MMC(MultitmediaCard):底层驱动的实现

2022年12月6日 175点热度

引 言

MMC(Multitmedia Card)是一种体积小巧、容量大、使用方便的存储器,目前在手机等嵌入式系统中有着广泛的应用。MMC通过卡内的一个集成片内控制器对MMC卡进行控制和管理,当主机正确地驱动MMC卡后,就可以像磁盘一样方便地存取数据。本文所研究与实现的Linux驱动程序,以Intel XScale的PXA250为硬件平台,在遵循MMC卡通信协议规范的基础上,实现了卡的底层读写。然后对传统的块设备驱动程序中的单块读写进行了改进,实现了集群读写技术,提高了卡的读写速度;同时增加了电源管理功能,满足了嵌入式系统低功耗的需求;增加了即插即用功能,方便了用户的使用。

1 MMC卡驱动程序的体系结构

MMC卡仅通过5个引脚与主机的控制器相连,通过串行协议与主机通信。MMC卡在硬件上的简单构造必然导致在实现驱动程序上的复杂。依据MMC卡的通信掷议规范和Linux驱动程序的结构,把驱动程序原有的底层驱动、守护线程、单块读写进行改进和扩展,其结构层次再划分为底层驱动、守护线程、集群读写、电源管理及热拔插管理5个部分,如图l所示。

linux 驱动通知应用层_全站弹出层通知_android linux内核层

图1中各部分的功能为:

①底层驱动——处理直接涉及与MMC卡硬件寄存器端口的操作,包括:命令的发布和响应、中断响应和处理、PIO或者DMA通道数据传输等。

②集群读写——将磁盘相邻数据块的读写请求合并起来一起发布读写命令,以加快数据读写,并在读写中实现并发控制。

③电源管理——实现MMC卡的低功耗管理。

④热拔插管理——实现MMC卡的即插即用功能。

⑤守护线程——响应文件系统的读写请求并启动对卡的1/O。

2 MMC卡驱动程序的实现

2.1 底层驱动

全站弹出层通知_android linux内核层_linux 驱动通知应用层

底层驱动指的是直接对MMC卡进行操作。MMC卡采用串行的数据传输方式;是一种比较“精细”的卡,对它的操作比较复杂而且必须有准确的时序安排。以下从命令的发布和响应、中断响应和处理、DMA数据传输3个方面讲述如何进行底层读写驱动。

(1)命令发布和响应

MMC卡的操作是通过对其18个控制寄存器的读写实现的。首先,设置时钟起停寄存器MMC_STRCPL的最低两位为01.关闭MMC卡内部时钟。然后,设置中断屏蔽寄存器MMC_LMASK的最低7位都为1,屏蔽所有对MMC控制器的中断,再向指定的MMC控制寄存器中写入命令参数,如时钟频率设置寄存器MMC_CLKRT,读写块数寄存器MMC_NOB,命令寄存器MMC_CMD等。最后linux 驱动通知应用层,打开内部时钟,解除屏蔽的中断。这时,当前读写进程进入睡眠状态,等待中断处理程序的唤醒。

(2)中断响应和处理

MMC卡在数据传输请求、内部时钟关闭、命令发布完毕、数据传输完毕的情况下都会产生中断,但足MMC卡的控制器只通过1裉GPIO23的引脚与CPU相连,用于中断信号线的复用;因此在中断处理程序中,必须首先判断到底是哪种原因产生的中断,然后再进行相应的处理。这里,MMC卡在正确发布读写命令以后,系统会产生1次中断,中断处理程序中读取MMC_IREG的值,判断命令已经发布成功,同时唤醒等待命令完成的进程。

读写进程被中断唤醒后,首先读取MMC卡响应寄存器MMC_RES中的状态信息,再根据这些状态信息判断命令是否发布成功和卡的当前状态。如果这些状态信息表示命令执行成功,则通过读写缓冲寄存器MMC_RXFIFO和MMC_TXFIFO进行数据的读写(这里使用DMA进行数据传输,提高了数据的传输速度);如果返回的状态信息表明命令执行不成功,则根据状念信息进行相应的出错处理。

(3)DMA数据传输

驱动程序中对MMC卡的数据读写是通过DMA通道进行传输的。为了保汪操作的连续性,驱动程序对MMC卡的输入和输出缓冲各设置1个DMA通道,在进行实际数据传输时linux 驱动通知应用层,读写进程也进入睡眠状态,等待DMA数据传输完毕后,被DMA中断唤醒。实现一次读操作的伪代码如下:

Pxa_read_mmc(){

关闭时钟,屏蔽中断;

设置读写寄存器的内容; /*读写块数,起始块数,读写速度等*/

打开时钟,发布读写命令;

Interruptible_sleep_on(); /*进入可打断睡眠状态,等待中断程序的唤醒*/

linux 驱动通知应用层_全站弹出层通知_android linux内核层

被中断程序唤醒,打开DMA通道,进行数据传输,再次进入可打断睡眠状态;

被DMA传输完毕中断唤醒,发布结束传输命令,结束数据传输;

2.2 集群(clustering)读写和并发控制

2.2.1 传统的块设备驱动程序结构和不足

块没备驱动程序是Linux系统中最复杂的驱动程序之一,参阅文献[3,4]可以详细了解Linux块设备驱动程序。这里简单介绍与集群读写相关的数据结构和操作。扇区(seetor)是块设备硬件传输数据的基本单位,而块(block)是块设备请求1次I/O操作所涉及的一组相邻扇区,每个块都需要有自己的内存缓冲区。缓冲区首部(buffer_head)是与每个缓冲区相关的数据结构,每次对块没备的I/O传输都必须经过块的缓冲区。

Linux块没备驱动程序采取一种延迟I/O策略。当进程有I/O请求时,驱动程序延迟一段时间kali linux,把块设备上相连续的buffer_head结构关联在一起形成一个I/O请求描述符(struct request),再把request结构按照电梯算法排队到设备的请求队列(request_queue_t)。这样实际执行I/O传输时,顺次处理对应块设备的请求队列。

对于request结构的电梯排队算法,避免由于频繁的移动磁头而导致块设备性能下降;然而,目前在Linux块设备驱动程序中,对一个request结构中的

各个buffer_head结构分别发布I/O读写命令,会导致每次对一个buffer_head的输入/输出时,磁头都会停顿一段时间,进行DMA数据读写。这样频繁的磁头启停会导致磁盘性能下降。

2.2.2 集群读写的实现

传统的块设备驱动程序中每次发布读写命令都只对一个buffer_head缓冲而导致块设备性能下降。针对这一问题,我们对传统块设备进行改进,实现了集群读写。由于每一个request结构的buffer_head结构链对应的物理块都是相邻的,因此为进行集群读写创造了条件。request结构中的nr_sectors表示该request结构需要读写的块数。进行读写时,一次性发布读写块数为nr_seetors,读入块设备内容到requem结构指向的第一个buffer_head结构对应的内存区域。在一个buffer_head结构的缓冲区读写满了以后,就调整读写缓冲区地址为下一个buffer_head所指向的缓冲区,同时配合DMA进行数据传输,提高了读写速度。对一个request结构操作完成以后,释放request结构资源。实现集群读操作伪码如下:

Read_mmc(){

发布读写命令,读入的数据块数为一个rcquest一>nr_sectors的块数;

缓冲区的指针指向第1个bh结构所指的缓冲区;

linux 驱动通知应用层_全站弹出层通知_android linux内核层

while(数据还没有读完){

读入数据到buffer_head结构所指定的缓冲区;/*调用Pxa_read_mmc()*/

调整缓冲区的指针到下一个buffer_head结构所指向的缓冲区;

}

}

2.2.3集群读写中的并发控制

如果I/O请求队列request_queue_t是在内核中的许多地方都被访问的,则该队列就成为了临界资源。为了对该队列进行互斥保护,Linux2.4中所有的请求队列都受一个单独的全局自旋锁io_request_lock的保护。所有对清求队列的操作必须要求拥有该锁并禁止中断,然而,在驱动程序拥有这个锁的同时,其他任何读写请求不能排队到系统的任何块设备上,其他读写处理函数也不能运行。为了尽量减轻由于驱动程序长期的拥有该锁而导致系统性能下降的问题,在实现集群读写时必须遵循以下原则:

①对请求队列进行读写操作时要获得锁;

②对请求队列操作完毕后释放请求锁;

③为了减少占用锁的时间,可先把队列中的request结构从队列中取下来,再打开锁,然后在开锁的情况下对取下的request结构进行操作。

基于以上原则linux通配符,读/写处理函数的伪码如下所示:

mmc_request_fn()

whilc(1){

android linux内核层_全站弹出层通知_linux 驱动通知应用层

加锁io_request_lock;

读取当前MMC卡请求队列的第一个请求结构request;

释放锁io_request_lock;

if(request为空)

cxit(O); /*没有可以处理的队列,返回*/

read_mmc(); /*调用集群读写函数*/

加锁io_request_lock;

在queue结构中取处理完毕的request结构,释放request资源;

释放锁io_request_lock;

}

}

2.3 守护线程

在MMC卡驱动程序初始化的时候,启动守护线程mme_block_thread。它平时处于睡眠状态,当有对MMC卡的读/写请求时,mmc_blok_thread被唤醒。该线程调用上述读/写处理函数mmc_request_fn(),处理完毕后再进入睡眠状态。

linux 驱动通知应用层_全站弹出层通知_android linux内核层

2.4 电源管理

嵌入式系统一般有低功耗要求,当某设备长期没有运行时,就应该停止给该设备供电,以减少电能消耗。在内核中有一个需要注册的电源管理设备的队列pm_list,同时也有电源管理线程kpowered,它的优先级是所有运行进程中最低的。当系统长时间没有进程运行时,kpowered被唤醒,扫描pm_lis

t队列各个注册的设备。如果发现该设备长期没有运行,则向该设备发出PM_SUSPEND事件;而当设备重新开始使用时,则向pm_list队列发出:PM_RESUME事件。

在MMC卡驱动模块中注册了电源管理的回调函数mme_block_callback,即pm_register(PM_UNKNOWN_DEV,0,mme_pm_callback)。这样MMC卡就注册到了pm_list队列中去了。当有电源事件时,就触发mmc_pm_callback函数。该函数处理各种电源事件。

程序中的电源事件有两种:

①PM_SUSPEND事件。该事件使MMC卡进入省电模式。这时驱动程序保存MMC卡的当前状态和重要寄存器的内容,如时钟寄存器MMC_CLKRT和状态寄存器MMC_STAT等。然后,设置MMC卡的供电GPIO为高电平,关闭MMC卡的电源供应,没置MMC卡在时钟使能寄存器CKEN的相应位为O,关闭MMC卡的时钟脉冲。这时,MMC卡就进入了省电模式。

②PM_RESUME事件。该事件使MMC卡进入正常工作模式。这时程序恢复在进入省电模式前保存的寄存器,打开电源供应和时钟脉冲,MMC卡恢复到正常的工作模式。

当然电源事件也可以由用户进程自愿触发。在文件系统的接口file_operaion io_control中留有电源理管理接口,用户可以通过io_contol向卡发送电源事件请求。

2.5 热插拔管理

在手机、PDA等嵌入式系统中,都要求提供对设备的即插即用功能,使用户无须安装驱动程序就可以即时使用设备。Linux在系统层和应用层都要对热插拔事件进行处理。在系统层,一方面要探测MMC卡的热插拔事件,分配或释放系统资源,并驱动MMC卡;另一方面,要将此事件准确及时地通知给应用层,应用层则根据热插拔事件作相应的处理。

在操作系统层,需要注册一个字符型设备mmc_plug文件,用于应用层探测MMC卡的热插拔事什。CPU通过GPIO12引脚与MMC卡相连,用于卡插拔的中断探测。同时驱动程序巾设置一个信号量MMC_EVENT,它取MMC_INSERT和MMC_REMOVAL两个值。当卡插入和或者拔出时,在中断处理程序中被分别设置为MMC_INSERT和MMC_REMCOVAL;并同时传给字符设备mmc_plug,供上层的应用程序使用。为了让应用层能够知晓卡的拔插事件,在字符设备mmc_plug使用异步I/O机制poll,需要接收内核拔插事件的进程通过poll在一个等待队列上睡眠,当有卡拔插事件时产生中断,中断处理程序唤醒在队列上等待的进程。上层进程在被唤醒后就读取字符设备,获取所发生的事件。

在应用层,进程通过select机制监听MMC卡所发生的热插拔事件,在没有拔插事件的时候,进程进入阻塞状态,让出CPU资源;当发生热拔插事件时,系统唤醒通过poll加入到等待队列中的进程,然后应用层通过read函数得到MMC卡的热插拔事件,进行相应的应用层处理。当然,应用层也可以通过write方法通知系统层对卡进行处理。

结语

本文研究实现的MMC卡驱动程序,其实现的集群读写证明有稳定而较高的读/写速度;增加了电源管理功能,降低了电源的功耗,满足了嵌入式系统低功耗的要求;增加的即插即用功能,大大方便了用户的使用。驱动程序的体系结构是实现嵌入式系统块设备驱动的一种好方法。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 中断处理 块设备 数据寄存器 状态寄存器 集群技术
最后更新:2022年12月6日

Linux大神网

每日更新,欢迎收藏♥ 不积跬步无以至千里,加油,共勉。

点赞
< 上一篇
下一篇 >

Linux大神网

每日更新,欢迎收藏♥
不积跬步无以至千里,加油,共勉。

最新 热点 随机
最新 热点 随机
Linux默认的最大文件描述符数量是1024 关于LinuxQt安装教程及配置的回答及解决办法的 MySQL8.0的f配置文件是管理MySQL服务器的重要文件 局域网聊天软件简单介绍TOP1内网通传书 ARM嵌入式Linux系统开发详解.rar 一说unix/linux中对于文件操作的这几个函数 如何利用linux来开发属于自己的嵌入式Linux操作系统 腦/網絡>操作系統/系統-alternate-i386.iso(EXT)这几个版本有什么区别 精通unixshell脚本编程之文件描述符数ulimitulimit-n ubuntu离线安装软件 鸿蒙OS环境搭建过程中遇到的问题及解决方案 写入数据覆盖的分析与执行 解读Rainbond集群的安装和运维的原理,便于用户搭建Rainbond Linux基础知识:文件描述符、文件指针、索引节点 如何解决Linux下的无线网卡驱动的问题? linux 文件描述符 (师)-unused-fdKernel:2.6.14CPUarchitecture Linux系统下如何搭建SVN服务器,详细说明各配置项的功能 修改软件源文件、UI界面设置换源操作|Ubuntu Ubuntu14.04.2为例进行说明,其它Ubuntu版本与此类似 Linux图形界面用户和Windows用户来说获取系统硬件信息都不算问题 Ubuntu下换内核的过程及详细分析内核操作分析
ubuntu离线安装软件 鸿蒙OS环境搭建过程中遇到的问题及解决方案精通unixshell脚本编程之文件描述符数ulimitulimit-n腦/網絡>操作系統/系統-alternate-i386.iso(EXT)这几个版本有什么区别如何利用linux来开发属于自己的嵌入式Linux操作系统一说unix/linux中对于文件操作的这几个函数ARM嵌入式Linux系统开发详解.rar局域网聊天软件简单介绍TOP1内网通传书MySQL8.0的f配置文件是管理MySQL服务器的重要文件关于LinuxQt安装教程及配置的回答及解决办法的Linux默认的最大文件描述符数量是1024C语言教程-Qt.12安装教程05-27Linux有7个运行级别(关机,停机模式、DellG3)(Linux基础知识)文件压缩、打包命令解析的Linux操作系统怎样执行?LinuxDNS服务器,如何安装、配置和维护它?AMD2950x+技嘉x399免驱USB网卡,我的无线网卡linux解压gz文件命令 蓝易云香港五网CN2网络压缩比率的测试环境Linux系统中用于管理和控制系统服务的强大工具介绍围绕API创建封装器的开源项目正变得越来越流行主频93.75MHz的MIPS64NECVR4300处理器在N64上运行
无窗口的Python可执行程序(图)命令(组图) 如何在Linux上安装Diablo3操作系统Diablo3 轻松掌握:如何查询Linux内核版本? 【Linux运维学习必看书籍推荐】——Linux运维大环境说明 linuxVPS计划任务crond命令的使用方法分享,需要的朋友可以参考下 lsblk的大小扩容(2)-sh 使用u盘在IBMx3650服务器上安装linux系统?我猜两种情况 CentOS8虚拟机的网络设置对话框的解决方法和解决办法 如何在Linux使用unzip命令合并解压分卷文件文件? 教下大伙儿红旗linux系统镜像系统安装实例教程流程汇总 Linux include头文件路径全解析:系统默认路径一网打尽! Linux常用命令大全(标记为红色的位必须掌握!) U盘安装linux系统解决方法:确保Linux下采用dd命令 Linux版本的Interbase4.0,这是一个高性能 如何管理Linux软件包软件包命名deb软件包的命名遵循以下约定 unix系统界面 没有最好的Linux发行版是什么样的? Linux上运行Windows可执行文件和运行可执行文件的基本信息开始了 瑞星ESM防病毒终端安全防护系统查杀Sfile勒索软件 Linux内核设计与线程上周的运作机制与实现及其相关资料 Linux集群技术热点与发展趋势分分:
标签聚合
linux服务器 sudo 命令 软件 操作 文件 命令模式 虚拟机 文件目录 linux系统
书籍
课程
技术群
技术干货大合集↓
  • 2023年6月 / 26篇
  • 2023年5月 / 93篇
  • 2023年4月 / 90篇
  • 2023年3月 / 129篇
  • 2023年2月 / 84篇
  • 2023年1月 / 161篇
  • 2022年12月 / 187篇
  • 2022年11月 / 76篇
友情链接:

Linux书籍 | Linux命令 | Linux系统 | RHCE红帽认证 | Linux软件 | Linux教程 | CentOS系统 | Linux内核 | Linux服务器 | Linux大神 | IT资源

COPYRIGHT © 2023 linuxgod.net ALL RIGHTS RESERVED.