Hi3511/Hi3512 Linux内核与标准内核差异说明
Hi3511/Hi3512 Linux内核与标准内核差异说明Application Notes
文档版本02
发布日期2008-08-30
BOM编码N/A
秘密
深圳市海思半导体有限公司为客户提供全方位的技术支持,用户可与就近的海思办事处联系,也可直接与公司总部联系。
深圳市海思半导体有限公司
地址:深圳市龙岗区坂田华为基地华为电气生产中心邮编:518129
网址:https://www.360docs.net/doc/642056847.html,
客户服务电话:0755-********
客户服务传真:0755-********
客户服务邮箱:support@https://www.360docs.net/doc/642056847.html,.
版权所有 ? 深圳市海思半导体有限公司2008。保留一切权利。
非经本公司书面许可,任何单位和个人不得擅自摘抄、复制本文档内容的部分或全部,并不得以任何形式传播。
商标声明
、、海思,均为深圳市海思半导体有限公司的商标。
本文档提及的其他所有商标或注册商标,由各自的所有人拥有。
注意
由于产品版本升级或其他原因,本文档内容会不定期进行更新。除非另有约定,本文档仅作为使用指导,本文档中的所有陈述、信息和建议不构成任何明示或暗示的担保。
秘密
Application Notes 目录
目录
前言 (1)
1 概述...............................................................................................................................................1-1
2 Hi3511/Hi3512平台相关代码....................................................................................................2-1
2.1 Hi3511/Hi3512平台相关头文件定义.......................................................................................................2-1
2.2 Hi3511/Hi3512平台相关的实现代码.......................................................................................................2-1
2.3 Hi3511/Hi3512平台相关的修改文件.......................................................................................................2-2
3 驱动代码.......................................................................................................................................3-1
3.1 Hi3511/Hi3512驱动公共组件...................................................................................................................3-1
3.2 Hi3511/Hi3512字符类设备驱动...............................................................................................................3-1
3.3 Hi3511/Hi3512 Flash驱动..........................................................................................................................3-1
3.4 Hi3511/Hi3512 UART驱动.........................................................................................................................3-7
3.5 Hi3511/Hi3512 USB1.1驱动.....................................................................................................................3-7
3.6 Hi3511/Hi3512 MMC驱动.........................................................................................................................3-7
3.7 Hi3511/Hi3512 PCI-SATA驱动................................................................................................................3-21
4 其他代码.......................................................................................................................................4-1
4.1 指定编译工具和平台................................................................................................................................4-1
4.2 增加devfs文件系统配置支持....................................................................................................................4-1
4.3 屏蔽CPU频率调整范围限制....................................................................................................................4-3
4.4 协议栈BUG修改........................................................................................................................................4-5
4.5 内核Phy驱动..............................................................................................................................................4-5
4.6 内核Phy驱动..............................................................................................................................................4-5
Application Notes 前言
前言
概述
本文档描述Hi3511/Hi3512 Linux内核与标准内核的差异,能指导读者区别于标准内核
对Hi3511/Hi3512进行开发。
产品版本
与本文档相对应的产品版本如下。
产品名称产品版本
H.264码处处处 V100
Hi3511编编
H.264处处处 V100
Hi3512 编编码
读者对象
本说明文档主要适用于以下工程师:
z软件开发工程师
z技术支持工程师
内容简介
本文档包含4章,内容如下。
章节内容
1 概述简要介介Hi3511/Hi351
2 Linux内核与标准内核的差异。
2 Hi3511平平相平平码介介Hi3511/Hi3512平平相平的平码。该该该内容该将标
准内核准准准Hi3511/Hi3512的平的。
PCI PCI-SATA驱驱、串
3 驱驱平码介介Hi3511/Hi3512芯芯芯驱驱、
口驱驱、网口驱驱以网USB/OTG驱驱驱的实实平码。
Linux。
4 其其平码介介Hi3511/Hi3512其其其其平码
前言Hi3511/Hi3512 Linux内核与标准内核差异说
明
Application Notes
约定
符号约定
在本文芯可能出实下列标志,它们所平表的含义如下。
通用格式约定
格式说明
宋体以文正用宋体表以。
黑体一一、二一、三一标三正用三体。
楷体警警、提以驱内容一提用楷
体,并并在内容前并并以并并与以文并并。
修订记录
其订记录累积了每次文档更新的说明。最新版本的文档包含以前所有文档版本的更新内
容。
修改日期版本修改说明
2008-8-25 02 并以芯芯以以。
Hi3512
2008-5-20 01 第一次发布版本。
Application Notes 1 概述
1 概述
Hi3511/Hi3512基于ARM926EJ-S CPU,标准内核已能很好地支持ARM。移植标准内核到Hi3511/Hi3512平台,主要是移植平台相关的代码,如中断控制器、定时器和时钟、I/O地址映射等。另外,Hi3511/Hi3512 Linux还包括PCI、Flash、USB、MMC等驱动程序。由于Hi3511/Hi3512硬件特性,目前移植的是相同的Linux内核代码。
Application Notes 2 Hi3511/Hi3512平台相关代码
2 Hi3511/Hi3512平台相关代码
平台相关的头文件存放在include/asm-arm/arch-hi3511v100目录下,平台相关的实现代码
存放在arch/arm/mach-hi3511v100目录下。这些文件均为新增文件。
2.1 Hi3511/Hi3512平台相关头文件定义
include/asm-arm/arch-hi3511v100/system.h
include/asm-arm/arch-hi3511v100/platform.h
include/asm-arm/arch-hi3511v100/pci.h
include/asm-arm/arch-hi3511v100/led.h
include/asm-arm/arch-hi3511v100/memory.h
include/asm-arm/arch-hi3511v100/dma.h
include/asm-arm/arch-hi3511v100/io.h
include/asm-arm/arch-hi3511v100/debug-macro.S
include/asm-arm/arch-hi3511v100/irqs.h
include/asm-arm/arch-hi3511v100/clock.h
include/asm-arm/arch-hi3511v100/hardware.h
include/asm-arm/arch-hi3511v100/cpu.h
include/asm-arm/arch-hi3511v100/timer.h
include/asm-arm/arch-hi3511v100/param.h
include/asm-arm/arch-hi3511v100/uncompress.h
include/asm-arm/arch-hi3511v100/gpio.h
include/asm-arm/arch-hi3511v100/vmalloc.h
include/asm-arm/arch-hi3511v100/early-debug.h
include/asm-arm/arch-hi3511v100/timex.h
include/asm-arm/arch-hi3511v100/entry-macro.S
2.2 Hi3511/Hi3512平台相关的实现代码
arch/arm/mach-hi3511v100/core.c
arch/arm/mach-hi3511v100/systimer.c
2 Hi3511/Hi3512平台相关代码Hi3511/Hi3512 Linux内核与标准内核
差异说明
Application Notes
arch/arm/mach-hi3511v100/Kconfig
arch/arm/mach-hi3511v100/leds.c
arch/arm/mach-hi3511v100/clock.c
arch/arm/mach-hi3511v100/Makefile.boot
arch/arm/mach-hi3511v100/Makefile
arch/arm/mach-hi3511v100/pci.c
arch/arm/mach-hi3511v100/platform-devices.c
arch/arm/mach-hi3511v100/cpu-freq.c
arch/arm/mach-hi3511v100/ahb-clock.c
2.3 Hi3511/Hi3512平台相关的修改文件
平台相关的修改文件如下:
z./arch/arm/Makefile
修改文件。增加Hi3511编译规则,增加内容:
machine-$(CONFIG_ARCH_HI3511V100) := hi3511v100
z./arch/arm/Kconfig.debug
修改文件。将config FRAME_POINTER配置项中bool内容修改为bool "Frame
pointer"。
z./arch/arm/configs
新增目录。存放Hi3511单板配置文件。
z./arch/arm/configs/hi3511v100_full_debug_defconfig
新增文件。Hi3511 debug版本内核配置文件。
z./arch/arm/configs/hi3511v100_full_release_defconfig
新增文件。Hi3511 release版本内核配置文件。
z./arch/arm/mm/Kconfig
修改文件。增加Hi3511支持的配置。在config CPU_ARM926T配置项中增加
HISILICON_ARM926EJ。
z./arch/arm/tools/mach-types
修改文件。增加机器类型号定义,增加内容:
hi3511v100 ARCH_HI3511V100 HI3511V100
387
z./arch/arm/Kconfig
修改文件。增加Hi3511配置信息。
z./arch/arm/boot/compressed/head.S
修改文件。在__setup_mmu中增加溢出检查,增加内容:
mvncs r9, #0 @ check overflow
z./arch/arm/boot/Makefile
修改文件。指定内核解压位置,将内容:
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel /
Application Notes 2 Hi3511/Hi3512平台相关代码
-C none -a $(ZRELADDR) -e $(ZRELADDR) /
-n 'Linux-$(KERNELRELEASE)' -d $< $@
修改为:
uimage_address_ae = $(shell printf 0x%08X $(shell expr `printf %u
$(ZRELADDR)` + `printf %u 0x7F8000`))
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel / -C none -a $(uimage_address_ae) -e $(uimage_address_ae) /
-n 'Linux-$(KERNELRELEASE)' -d $< $@
Application Notes 3 驱动代码
3 驱动代码
3.1 Hi3511/Hi3512驱动公共组件
驱动公共组件修改文件如下:
z./drivers/base/kcom.c
新增文件。Hi3511内核组件管理模块。
z./drivers/base/Makefile
修改文件。增加Hi3511内核组件管理模块编译项,增加内容:
obj-$(CONFIG_MODULES) += kcom.o
z./include/linux/kcom.h
新增文件。定义Hi3511内核组件管理模块头文件。
3.2 Hi3511/Hi3512字符类设备驱动
字符类设备驱动修改文件如下:
z./drivers/char/himedia.c
新增文件。统一定义Hi3511字符类设备接口。
z./drivers/char/Makefile
修改文件。增加编译项,将obj-y += misc.o修改为obj-y += misc.o himedia.o。
z./include/linux/himedia.h
新增文件。定义Hi3511字符类设备接口头文件。
3.3 Hi3511/Hi3512 Flash驱动
Flash驱动修改文件如下:
z./ drivers/mtd/maps/plat-ram.c
修改文件。
?增加头文件,增加内容:
3 驱动代码
Hi3511/Hi3512 Linux内核与标准内核
差异说明
Application Notes
#include
#include
?增加地址映射处理函数,增加内容:
static map_word __xipram mtdram_map_read(struct map_info *map, unsigned long ofs)
{
map_word r;
if(map->cached == NULL)
return inline_map_read(map, ofs);
if (map_bankwidth_is_1(map))
r.x[0] = *((char*)map->cached + ofs);
else if (map_bankwidth_is_2(map))
r.x[0] = *(unsigned short*)((char*)map->cached + ofs);
else if (map_bankwidth_is_4(map))
r.x[0] = *(unsigned long*)((char*)map->cached + ofs);
#if BITS_PER_LONG >= 64
else if (map_bankwidth_is_8(map))
r.x[0] = *(unsigned long long*)((char*)map->cached + ofs);
#endif
else if (map_bankwidth_is_large(map))
memcpy(r.x, map->cached+ofs, map->bankwidth);
return r;
}
static void __xipram mtdram_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
{
if(map->cached == NULL) {
inline_map_write(map, datum, ofs);
return;
}
if (map_bankwidth_is_1(map))
*(char *)((char*)map->cached + ofs) = datum.x[0];
else if (map_bankwidth_is_2(map))
*(unsigned short *)((char*)map->cached + ofs) = datum.x[0];
else if (map_bankwidth_is_4(map))
*(unsigned long *)((char*)map->cached + ofs) = datum.x[0];
#if BITS_PER_LONG >= 64
else if (map_bankwidth_is_8(map))
Hi3511/Hi3512 Linux内核与标准内核差
异说明
Application Notes 3 驱动代码
*(unsigned long long *)((char*)map->cached + ofs) = datum.x[0];
#endif
else if (map_bankwidth_is_large(map))
memcpy(map->virt+ofs, datum.x, map->bankwidth);
mb();
}
static void __xipram mtdram_map_copy_from(struct map_info *map, void
*to, unsigned long from, ssize_t len)
{
inline_map_copy_from(map, to, from, len);
}
static void __xipram mtdram_map_copy_to(struct map_info *map, unsigned
long to, const void *from, ssize_t len)
{
if(map->cached)
memcpy(map->cached + to, from, len);
else
inline_map_copy_to(map, to, from, len);
}
static void mtdram_map_init(struct map_info *map)
{
BUG_ON(!map_bankwidth_supported(map->bankwidth));
map->read = mtdram_map_read;
map->write = mtdram_map_write;
map->copy_from = mtdram_map_copy_from;
map->copy_to = mtdram_map_copy_to;
}
?增加资源释放处理。
增加内容:
if (info->map.cached != NULL)
iounmap(info->map.cached);
将内容:
info->https://www.360docs.net/doc/642056847.html, = pdata->mapname != NULL ? pdata->mapname : pd->name;
修改为:
info->https://www.360docs.net/doc/642056847.html, = pdata->mapname != NULL ? pdata->mapname : (char *)
pd->name;
将内容:
info->map.virt = ioremap(res->start, info->map.size);
3 驱动代码
Hi3511/Hi3512 Linux内核与标准内核
差异说明
Application Notes
dev_dbg(dev, "virt %p, %lu bytes/n", info->map.virt, info->map.size); if (info->map.virt == NULL) {
dev_err(dev, "failed to ioremap() region/n");
err = -EIO;
goto exit_free;
}
simple_map_init(&info->map);
修改为:
if(res->flags &= IORESOURCE_CACHEABLE) {
info->map.cached = ioremap_cached(res->start, info->map.size);
dev_dbg("cached %p, %lu bytes/n", info->map.cached, info->map.size); if (info->map.cached == NULL) {
dev_err(dev, "failed to ioremap_cached() region/n");
err = -EIO;
goto exit_free;
}
} else {
info->map.virt = ioremap(res->start, info->map.size);
dev_dbg(dev, "virt %p, %lu bytes/n", info->map.virt, info->map.size); if (info->map.virt == NULL) {
dev_err(dev, "failed to ioremap() region/n");
err = -EIO;
goto exit_free;
}
}
mtdram_map_init(&info->map);
将内容:
#ifdef CONFIG_MTD_PARTITIONS
if (pdata->nr_partitions > 0) {
const char **probes = { NULL };
if (pdata->probes)
probes = (const char **)pdata->probes;
err = parse_mtd_partitions(info->mtd, probes,
&info->partitions,
0);
if (err > 0) {
err = add_mtd_partitions(info->mtd, info->partitions,
err);
}
}
#endif /* CONFIG_MTD_PARTITIONS */
if (add_mtd_device(info->mtd)) {
dev_err(dev, "add_mtd_device() failed/n");
err = -ENOMEM;
Hi3511/Hi3512 Linux内核与标准内核差
异说明
Application Notes 3 驱动代码 }
修改为:
#ifdef CONFIG_MTD_PARTITIONS
if (pdata->nr_partitions > 0) {
if (pdata->probes) {
const char **probes = (const char **)pdata->probes;
err = parse_mtd_partitions(info->mtd, probes,
0);
&info->partitions,
if (err > 0) {
info->partitions,
add_mtd_partitions(info->mtd,
err
=
err);
}
}
if(pdata->partitions)
err = add_mtd_partitions(info->mtd, pdata->partitions, pdata->nr_partitions);
}
#endif /* CONFIG_MTD_PARTITIONS */
if (!(pdata->nr_partitions > 0)) {
if (add_mtd_device(info->mtd)) {
failed/n");
"add_mtd_device()
dev_err(dev,
-ENOMEM;
=
err
}
}
z./drivers/mtd/maps/physmap.c
修改文件。增加Cached方式的Flash映射,以提高Flash读取的速度。增加代码如
下:
18 #include
62 #ifdef CONFIG_MTD_PHYSMAP_CACHED
63 physmap_map.cached = ioremap_cached(physmap_map.phys,
physmap_map.s
64
65 if (!physmap_map.cached) {
66 printk("Failed to ioremap_cached, use uncached flash
read.\n");
67 }
68 #endif
69
105 physmap_map.virt = NULL;
106
107 if(physmap_map.cached)
3 驱动代码
Hi3511/Hi3512 Linux内核与标准内核
差异说明
Application Notes
108 iounmap(physmap_map.cached);
109 physmap_map.cached = NULL;
110
132
133 if(physmap_map.cached)
134 iounmap(physmap_map.cached);
135 physmap_map.cached = NULL;
z./drivers/mtd/maps/Kconfig
修改文件。增加配置菜单选项,增加内容:
config MTD_PHYSMAP_CACHED
bool "Use cached access for flash read"
depends on MTD_PHYSMAP
default
y
help
Read flash with cpu D-Cache on.
z./drivers/mtd/mtdchar.c
修改文件。
?增加以下代码,用于在devfs文件系统中创建设备文件:
#ifdef CONFIG_DEVFS_FS
#include
#endif
在函数static void mtd_notify_add(struct mtd_info* mtd)中插入:
#ifdef CONFIG_DEVFS_FS
/* DEVFS */
devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
#endif
?在函数static void mtd_notify_remove(struct mtd_info* mtd)中插入:#ifdef CONFIG_DEVFS_FS
/* DEVFS */
devfs_remove("mtd/%d", mtd->index);
devfs_remove("mtd/%dro", mtd->index);
#endif
?在函数static int __init init_mtdchar(void)中插入:
#ifdef CONFIG_DEVFS_FS
/* DEVFS */
devfs_mk_dir("mtd");
#endif
Hi3511/Hi3512 Linux内核与标准内核差
异说明
Application Notes 3 驱动代码?在函数static void __exit cleanup_mtdchar(void)中插入:
#ifdef CONFIG_DEVFS_FS
/* DEVFS */
devfs_remove("mtd");
#endif
3.4 Hi3511/Hi3512 UART驱动
UART驱动修改文件如下:
z./ drivers/serial/amba-pl011.c
修改文件。解决串口接收溢出后无法恢复的BUG;增加串口时钟跟踪的处理函数,
使其支持总线频率的动态调整。
3.5 Hi3511/Hi3512 USB1.1驱动
drivers/usb/storage/transport.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/hcd.h
3.6 Hi3511/Hi3512 MMC驱动
MMC驱动修改文件如下:
z drivers/mmc/card.h
新增文件。
z drivers/mmc/sd.h
新增文件。
z drivers/mmc/w_debug.h
新增文件。
z drivers/mmc/mmc_sysfs.c
修改文件。
?增加头文件:
#include "sd.h"
#include "w_debug.h"
?将头文件:
#include
修改为:
#include "card.h"
3 驱动代码
Hi3511/Hi3512 Linux内核与标准内核
差异说明
Application Notes ?在函数void mmc_remove_card(struct mmc_card *card)中增加内容:mmc_card_release_host(card);
z drivers/mmc/mmc_queue.c
修改文件。
?增加头文件:
#include "w_debug.h"
?在函数static int mmc_prep_request(struct request_queue *q, struct request *req)中,将内容:
struct mmc_queue *mq = q->queuedata;
int ret = BLKPREP_KILL;
if (req->flags & REQ_SPECIAL) {
/*
* Special commands already have the command
* blocks already setup in req->special.
*/
BUG_ON(!req->special);
ret = BLKPREP_OK;
} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
/*
* Block I/O requests need translating according
* to the protocol.
*/
ret = mq->prep_fn(mq, req);
} else {
/*
* Everything else is invalid.
*/
blk_dump_rq_flags(req, "MMC bad request");
}
if (ret == BLKPREP_OK)
req->flags |= REQ_DONTPREP;
return ret;
修改为:
/*
* We only like normal block requests.
*/
if (!blk_fs_request(req) && !blk_pc_request(req)) {
blk_dump_rq_flags(req, "MMC bad request");
return BLKPREP_KILL;
}
req->flags |= REQ_DONTPREP;
Hi3511/Hi3512 Linux内核与标准内核差
异说明
Application Notes 3 驱动代码return BLKPREP_OK;
?在函数static int mmc_queue_thread(void *d)中,将内容:
if (!blk_queue_plugged(q))
mq->req = req = elv_next_request(q);
修改为:
if (!blk_queue_plugged(q))
req = elv_next_request(q);
mq->req = req;
?增加内容:
if (! blk_fs_request(req))
{
printk (" NONE CMD request/n");
end_request(req, 0);
continue;
}
?在函数static void mmc_request(request_queue_t *q)中,增加内容:
struct request *req;
int ret;
if (!mq) {
printk(KERN_ERR "MMC: killing requests for dead queue/n");
while ((req = elv_next_request(q)) != NULL) {
do {
ret = end_that_request_chunk(req, 0,
9);
<<
req->current_nr_sectors
} while (ret);
}
return;
}
?在函数void mmc_cleanup_queue(struct mmc_queue *mq)中,增加内容:request_queue_t *q = mq->queue;
unsigned long flags;
/* Mark that we should start throwing out stragglers */
spin_lock_irqsave(q->queue_lock, flags);
q->queuedata = NULL;
spin_unlock_irqrestore(q->queue_lock, flags);
z drivers/mmc/mmc_block.c
修改文件。
?增加头文件:
#include
#include "w_debug.h"
3 驱动代码
Hi3511/Hi3512 Linux内核与标准内核
差异说明
Application Notes #include "card.h"
?将头文件:
#include
修改为:
#include "card.h"
?在函数static void mmc_blk_put(struct mmc_blk_data *md)中,删除内容:mmc_cleanup_queue(&md->queue);
增加内容:
static void mmc_blk_remove(struct mmc_card *card);
#define MMC_STATE_BLOCKADDR 1<<6
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) ?在函数static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)中,将内容:
int ret;
修改为:
int ret = 1;
将内容:
brq.cmd.arg = req->sector << 9;
修改为:
brq.cmd.arg = req->sector;
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
将内容:
} else {
brq.cmd.opcode = MMC_WRITE_BLOCK;
brq.cmd.flags = MMC_RSP_R1B;
brq.data.flags |= MMC_DATA_WRITE;
brq.data.blocks = 1;
}
修改为:
} else {
brq.cmd.opcode = brq.data.blocks > 1 ? MMC_WRITE_MULTIPLE_BLOCK : MMC_WRITE_BLOCK;
brq.cmd.flags = MMC_RSP_R1B;
brq.data.flags |= MMC_DATA_WRITE;
}
将内容:
do {
ret = end_that_request_chunk(req, 0,
Hi3511/Hi3512 Linux内核与标准内核差
异说明
Application Notes 3 驱动代码
req->current_nr_sectors << 9);
} while (ret);
修改为:
while(ret) {
ret = end_that_request_chunk(req, 0,
req->nr_sectors << 9);
}
删除内容:
struct mmc_command cmd;
删除内容:
do {
int err;
cmd.opcode = MMC_SEND_STATUS;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
if (err) {
printk(KERN_ERR "%s: error %d requesting status/n",
req->rq_disk->disk_name,
err);
goto cmd_err;
}
} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
?在函数static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)中,将内容:
md->block_bits = card->csd.read_blkbits;
修改为:
md->block_bits = 9;
?在函数mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)中,将内容:
cmd.arg = 1 << card->csd.read_blkbits;
修改为:
cmd.arg = 1 << 9;
?在函数static int mmc_blk_probe(struct mmc_card *card)中,增加内容:
mmc_cleanup_queue(&md->queue);
?在函数static void mmc_blk_remove(struct mmc_card *card)中,增加内容:mmc_cleanup_queue(&md->queue);
z drivers/mmc/mmc.c
修改文件。
?增加头文件: