www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]我們知道默認(rèn)外設(shè)I/O資源是不在Linux內(nèi)核空間中的(如sram或硬件接口寄存器等),若需要訪問該外設(shè)I/O資源,必須先將其地址映射到內(nèi)核空間中來,然后才能在內(nèi)核空間中訪問它。Linux內(nèi)核訪問外設(shè)I/O內(nèi)存資源的方式有兩

我們知道默認(rèn)外設(shè)I/O資源是不在Linux內(nèi)核空間中的(如sram或硬件接口寄存器等),若需要訪問該外設(shè)I/O資源,必須先將其地址映射到內(nèi)核空間中來,然后才能在內(nèi)核空間中訪問它。

Linux內(nèi)核訪問外設(shè)I/O內(nèi)存資源的方式有兩種:動(dòng)態(tài)映射(ioremap)和靜態(tài)映射(map_desc)。

一、動(dòng)態(tài)映射(ioremap)方式

動(dòng)態(tài)映射方式是大家使用了比較多的,也比較簡(jiǎn)單。即直接通過內(nèi)核提供的ioremap函數(shù)動(dòng)態(tài)創(chuàng)建一段外設(shè)I/O內(nèi)存資源到內(nèi)核虛擬地址的映射表,從而可以在內(nèi)核空間中訪問這段I/O資源。
Ioremap宏定義在asm/io.h內(nèi):
#define ioremap(cookie,size) __ioremap(cookie,size,0)

__ioremap函數(shù)原型為(arm/mm/ioremap.c):
void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags);
phys_addr:要映射的起始的IO地址
size:要映射的空間的大小
flags:要映射的IO空間和權(quán)限有關(guān)的標(biāo)志
該函數(shù)返回映射后的內(nèi)核虛擬地址(3G-4G). 接著便可以通過讀寫該返回的內(nèi)核虛擬地址去訪問之這段I/O內(nèi)存資源。

舉一個(gè)簡(jiǎn)單的例子: (取自s3c2410的iis音頻驅(qū)動(dòng))
比如我們要訪問s3c2410平臺(tái)上的I2S寄存器, 查看datasheet 知道IIS物理地址為0x55000000,

我們把它定義為宏S3C2410_PA_IIS,如下:
#define S3C2410_PA_IIS (0x55000000)
若要在內(nèi)核空間(iis驅(qū)動(dòng))中訪問這段I/O寄存器(IIS)資源需要先建立到內(nèi)核地址空間的映射:
our_card->regs = ioremap(S3C2410_PA_IIS, 0x100);
if (our_card->regs == NULL) {
err = -ENXIO;
goto exit_err;
}
創(chuàng)建好了之后,我們就可以通過readl(our_card->regs )或writel(value, our_card->regs)等IO接口函數(shù)去訪問它。

二、靜態(tài)映射(map_desc)方式

下面重點(diǎn)介紹靜態(tài)映射方式即通過map_desc結(jié)構(gòu)體靜態(tài)創(chuàng)建I/O資源映射表。
內(nèi)核提供了在系統(tǒng)啟動(dòng)時(shí)通過map_desc結(jié)構(gòu)體靜態(tài)創(chuàng)建I/O資源到內(nèi)核地址空間的線性映射表(即page table)的方式,這種映射表是一種一一映射的關(guān)系。程序員可以自己定義該I/O內(nèi)存資源映射后的虛擬地址。創(chuàng)建好了靜態(tài)映射表,在內(nèi)核或驅(qū)動(dòng)中訪問該I/O資源時(shí)則無需再進(jìn)行ioreamp動(dòng)態(tài)映射,可以直接通過映射后的I/O虛擬地址去訪問它。

下面詳細(xì)分析這種機(jī)制的原理并舉例說明如何通過這種靜態(tài)映射的方式訪問外設(shè)I/O內(nèi)存資源。

內(nèi)核提供了一個(gè)重要的結(jié)構(gòu)體struct machine_desc ,這個(gè)結(jié)構(gòu)體在內(nèi)核移植中起到相當(dāng)重要的作用,內(nèi)核通過machine_desc結(jié)構(gòu)體來控制系統(tǒng)體系架構(gòu)相關(guān)部分的初始化。
machine_desc結(jié)構(gòu)體的成員包含了體系架構(gòu)相關(guān)部分的幾個(gè)最重要的初始化函數(shù),包括map_io, init_irq, init_machine以及phys_io , timer成員等。
machine_desc結(jié)構(gòu)體定義如下:
struct machine_desc {
/*
* Note! The first four elements are used
* by assembler code in head-armv.S
*/
unsigned int nr; /* architecture number */
unsigned int phys_io; /* start of physical io */
unsigned int io_pg_offst; /* byte offset for io
* page tabe entry */
const char *name; /* architecture name */
unsigned long boot_params; /* tagged list */
unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */
unsigned int reserve_lp0 :1; /* never has lp0 */
unsigned int reserve_lp1 :1; /* never has lp1 */
unsigned int reserve_lp2 :1; /* never has lp2 */
unsigned int soft_reboot :1; /* soft reboot */
void (*fixup)(struct machine_desc *,
struct tag *, char **,
struct meminfo *);
void (*map_io)(void);/* IO mapping function */
void (*init_irq)(void);
struct sys_timer *timer; /* system tick timer */
void (*init_machine)(void);
};

這里的map_io成員即內(nèi)核提供給用戶的創(chuàng)建外設(shè)I/O資源到內(nèi)核虛擬地址靜態(tài)映射表的接口函數(shù)。Map_io成員函數(shù)會(huì)在系統(tǒng)初始化過程中被調(diào)用,流程如下:
Start_kernel -> setup_arch() --> paging_init() --> devicemaps_init()中被調(diào)用Machine_desc結(jié)構(gòu)體通過MACHINE_START宏來初始化。
注:MACHINE_START的使用及各個(gè)成員函數(shù)的調(diào)用過程請(qǐng)參考:
http://blog.chinaunix.net/u2/60011/showart_1010489.html

用戶可以在定義Machine_desc結(jié)構(gòu)體時(shí)指定Map_io的接口函數(shù),這里以s3c2410平臺(tái)為例。
s3c2410 machine_desc結(jié)構(gòu)體定義如下:
/* arch/arm/mach-s3c2410/Mach-smdk2410.c */
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
* to SMDK2410 */
/* Maintainer: Jonas Dietsche */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = smdk2410_init,
.timer = &s3c24xx_timer,
MACHINE_END

如上,map_io被初始化為smdk2410_map_io。smdk2410_map_io即我們自己定義的創(chuàng)建靜態(tài)I/O映射表的函數(shù)。在Porting內(nèi)核到新開發(fā)板時(shí),這個(gè)函數(shù)需要我們自己實(shí)現(xiàn)。

(注:這個(gè)函數(shù)通常情況下可以實(shí)現(xiàn)得很簡(jiǎn)單,只要直接調(diào)用iotable_init創(chuàng)建映射表就行了,我們的板子內(nèi)核就是。不過s3c2410平臺(tái)這個(gè)函數(shù)實(shí)現(xiàn)得稍微有點(diǎn)復(fù)雜,主要是因?yàn)樗鼘⒁獎(jiǎng)?chuàng)建IO映射表的資源分為了三個(gè)部分(smdk2410_iodesc, s3c_iodesc以及s3c2410_iodesc)在不同階段分別創(chuàng)建。這里我們?nèi)∑渲幸粋€(gè)部分進(jìn)行分析,不影響對(duì)整個(gè)概念的理解。)

S3c2410平臺(tái)的smdk2410_map_io函數(shù)最終會(huì)調(diào)用到s3c2410_map_io函數(shù)。
流程如下:s3c2410_map_io -> s3c24xx_init_io -> s3c2410_map_io

下面分析一下s3c2410_map_io函數(shù):
void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size)
{
/* register our io-tables */
iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
……
}

iotable_init內(nèi)核提供,定義如下:
/*
* Create the architecture specific mappings
*/
void __init iotable_init(struct map_desc *io_desc, int nr)
{
int i;
for (i = 0; i nr; i++)
create_mapping(io_desc + i);
}

由上知道,s3c2410_map_io最終調(diào)用iotable_init建立映射表。

iotable_init函數(shù)的參數(shù)有兩個(gè):一個(gè)是map_desc類型的結(jié)構(gòu)體,另一個(gè)是該結(jié)構(gòu)體的數(shù)量nr。這里最關(guān)鍵的就是struct map_desc。map_desc結(jié)構(gòu)體定義如下:
/* include/asm-arm/mach/map.h */
struct map_desc {
unsigned long virtual; /* 映射后的虛擬地址 */
unsigned long pfn; /* I/O資源物理地址所在的頁幀號(hào) */
unsigned long length; /* I/O資源長(zhǎng)度 */
unsigned int type; /* I/O資源類型 */
};

create_mapping函數(shù)就是通過map_desc提供的信息創(chuàng)建線性映射表的。
這樣的話我們就知道了創(chuàng)建I/O映射表的大致流程為:只要定義相應(yīng)I/O資源的map_desc結(jié)構(gòu)體,并將該結(jié)構(gòu)體傳給iotable_init函數(shù)執(zhí)行,就可以創(chuàng)建相應(yīng)的I/O資源到內(nèi)核虛擬地址空間的映射表了。

我們來看看s3c2410是怎么定義map_desc結(jié)構(gòu)體的(即上面s3c2410_map_io函數(shù)內(nèi)的

s3c2410_iodesc)。
/* arch/arm/mach-s3c2410/s3c2410.c */
static struct map_desc s3c2410_iodesc[] __initdata = {
IODESC_ENT(USBHOST),
IODESC_ENT(CLKPWR),
IODESC_ENT(LCD),
IODESC_ENT(TIMER),
IODESC_ENT(ADC),
IODESC_ENT(WATCHDOG),
};

IODESC_ENT宏如下:
#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x,

__phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }

展開后等價(jià)于:
static struct map_desc s3c2410_iodesc[] __initdata = {
{
.virtual = (unsigned long)S3C24XX_VA_ LCD),
.pfn = __phys_to_pfn(S3C24XX_PA_ LCD),
.length = S3C24XX_SZ_ LCD,
.type = MT_DEVICE
},
……
};

S3C24XX_PA_ LCD和S3C24XX_VA_ LCD為定義在map.h內(nèi)的LCD寄存器的物理地址和虛擬地址。在這里map_desc 結(jié)構(gòu)體的virtual成員被初始化為S3C24XX_VA_ LCD,pfn成員值通過__phys_to_pfn內(nèi)核函數(shù)計(jì)算,只需要傳遞給它該I/O資源的物理地址就行。Length為映射資源的大小。MT_DEVICE為I/O類型,通常定義為MT_DEVICE。
這里最重要的即virtual 成員的值S3C24XX_VA_ LCD,這個(gè)值即該I/O資源映射后的內(nèi)核虛擬地址,創(chuàng)建映射表成功后,便可以在內(nèi)核或驅(qū)動(dòng)中直接通過該虛擬地址訪問這個(gè)I/O資源。

S3C24XX_VA_ LCD以及S3C24XX_PA_ LCD定義如下:
/* include/asm-arm/arch-s3c2410/map.h */
/* LCD controller */
#define S3C24XX_VA_LCD S3C2410_ADDR(0x00600000) //LCD映射后的虛擬地址
#define S3C2410_PA_LCD (0x4D000000) //LCD寄存器物理地址
#define S3C24XX_SZ_LCD SZ_1M //LCD寄存器大小

S3C2410_ADDR 定義如下:
#define S3C2410_ADDR(x) ((void __iomem *)0xF0000000 + (x))
這里就是一種線性偏移關(guān)系,即s3c2410創(chuàng)建的I/O靜態(tài)映射表會(huì)被映射到0xF0000000之后。(這個(gè)線性偏移值可以改,也可以你自己在virtual成員里手動(dòng)定義一個(gè)值,只要不和其他IO資源映射地址沖突,但最好是在0XF0000000之后。)

(注:其實(shí)這里S3C2410_ADDR的線性偏移只是s3c2410平臺(tái)的一種做法,很多其他ARM平臺(tái)采用了通用的IO_ADDRESS宏來計(jì)算物理地址到虛擬地址之前的偏移。
IO_ADDRESS宏定義如下:
/* include/asm/arch-versatile/hardware.h */
/* macro to get at IO space when running virtually */
#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) &0x0f000000)+ 0xf0000000) )

s3c2410_iodesc這個(gè)映射表建立成功后,我們?cè)趦?nèi)核中便可以直接通過S3C24XX_VA_ LCD訪問

LCD的寄存器資源。
如:S3c2410 lcd驅(qū)動(dòng)的probe函數(shù)內(nèi)
/* Stop the video and unset ENVID if set */
info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
lcdcon1 = readl(S3C2410_LCDCON1); //read映射后的寄存器虛擬地址
writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1); //write映射后的虛擬地址

S3C2410_LCDCON1寄存器地址為相對(duì)于S3C24XX_VA_LCD偏移的一個(gè)地址,定義如下:
/* include/asm/arch-s3c2410/regs-lcd.h */
#define S3C2410_LCDREG(x) ((x) + S3C24XX_VA_LCD)
/* LCD control registers */
#define S3C2410_LCDCON1 S3C2410_LCDREG(0x00)

到此,我們知道了通過map_desc結(jié)構(gòu)體創(chuàng)建I/O內(nèi)存資源靜態(tài)映射表的原理了??偨Y(jié)一下發(fā)現(xiàn)其實(shí)過程很簡(jiǎn)單,一通過定義map_desc結(jié)構(gòu)體創(chuàng)建靜

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉