天天看點

ioremap在linux驅動中應用執行個體--S3C2440開發闆LED驅動

作者:有AI野心的電工和碼農
又一篇講老版本核心驅動的,多年沒寫過核心驅動了,也不知這些技術現在還适用不,權當紀念吧。

剛開始學字元裝置驅動,感覺最難的是驅動和底層硬體的連接配接。

linux上的驅動程式,是基于作業系統之上的,他并不直接和底層的硬體打交道,但是我們寫的驅動必須能使硬體“跑”起來,即與硬體緊密相連。

就拿最簡單的LED驅動來說,我們的驅動程式是在虛拟的記憶體上面跑的,但是最終,LED的點亮還是必須靠GPIO管腳的高低電平來控制。

那麼,我們的虛拟的記憶體怎麼才能和實際的硬體上面的寄存器對應起來呢?

這篇要寫的就是ioremap這個映射函數,他可以将我們硬體上面的寄存器,映射為虛拟的記憶體,進而使驅動程式在我們的虛拟的記憶體中運作。

void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)

入口:

  • phys_addr:要映射的起始的IO位址,即:實體位址
  • size:要映射的空間的大小;
  • flags:要映射的IO空間的和權限有關的标志;

下面是我用ioremap函數寫的第一個LED 的驅動:(硬體是S3C2440的開發闆)

/***************************************************************/
//file name: ioremap_driver.c
#include <linux/module.h>
#include <linux/init.h>
#include <asm/io.h>

volatile unsigned long virt, phys;//用于存放虛拟位址和實體位址
volatile unsigned long *GPBCON, *GPBDAT, *GPBUP;//用與存放三個寄存器的位址

void led_device_init(void)
{
    // 0x56000010 + 0x10 包攬全所有的IO引腳寄存器位址
    phys = 0x56000010; // 0x56000010=GPBCON
    //在虛拟位址空間中申請一塊長度為0x10的連續空間
    //這樣,實體位址phys到phys+0x10對應虛拟位址virt到virt+0x10
    virt =(unsigned long)ioremap(phys, 0x10);
    GPBCON = (unsigned long *)(virt + 0x00);//指定需要操作的三個寄存器的位址
    GPBDAT = (unsigned long *)(virt + 0x04);
    GPBUP  = (unsigned long *)(virt + 0x08);
}

//led配置函數,配置開發闆的GPIO的寄存器
void led_configure(void)
{
    *GPBCON &= ~(3 << 10)&~(3<<12)&~(3 << 16)&~(3<<20);//GPB12 defaule 清零
    *GPBCON |= (1 << 10)|(1<<12)|(1<<16)|(1<<20); //output  輸出模式
    *GPBUP |= (1 << 5)|(1 <<6)|(1 <<8)|(1 <<10);  //禁止上拉電阻
}

void led_on(void) //點亮led
{
    *GPBDAT &= ~(1 << 5)&~(1 << 6)&~(1 << 8)&~(1 << 10);
}

void led_off(void) //滅掉led
{
    *GPBDAT |= (1 << 5)|(1 << 6)|(1 << 8)|(1 << 10);
}

static int __init led_init(void) //子產品初始化函數
{
    led_device_init(); //實作IO記憶體的映射
    led_configure();  //配置GPB5 6 8 10為輸出
    led_on();
    printk("hello ON!\n");
    return 0;
}

static void __exit led_exit(void) //子產品解除安裝函數
{
    led_off();
    iounmap((void *)virt); //撤銷映射關系
    printk("led OFF!\n");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hurryliu<>");
MODULE_VERSION("2012-8-5.1.0");
/*************************************************************************/           

實驗現象:

啟動開發闆,在指令行模式下将編譯好的ioremap_driver.ko子產品加載到核心中

# insmod ioremap_driver.ko

這時,我們可以看到,開發闆上面的LED4個燈全亮了。

# rmmod ioremap_driver 解除安裝子產品

這時,我們的LED燈就滅了。

繼續閱讀