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

修改文件。

?增加头文件:

相关文档
最新文档