linux字符设备驱动开发之内存映射

本文章参考正点原子相关教程,仅学习使用

linux驱动最终都死通过配置寄存器完成,linux驱动开发需要满足linux的驱动框架.所以存在一个内存管理单元(MMU)实现虚拟地址与物理地址的映射,内存保护和虚拟地址缓存功能.

通过内存映射,只需要对虚拟地址进行操作,就可以实现相应的驱动开发.

内存映射
在这里插入图片描述
映射函数

//内存映射
void __iomem *ioremap(phys_addr_t addr, unsigned long size)
//取消映射
void iounmap(void __iomem *addr)

IO读写函数

//读写虚拟地址
static inline u8 readb(const volatile void __iomem *addr)
static inline u16 readw(const volatile void __iomem *addr)
static inline u32 readl(const volatile void __iomem *addr)
static inline void writeb(u8 data, volatile void __iomem *addr)
static inline void writew(u16 data, volatile void __iomem *addr)
static inline void writel(u32 data, volatile void __iomem *addr)

内存映射简单例子

// physical address
#define CCM_CCGR1_BASE          (0x020C406C)
#define SW_MUX_GPIO1_IO03_BASE  (0x020E0068)
#define SW_PAD_GPIO1_IO03_BASE  (0x020E02F4)
#define GPIO1_DR_BASE           (0x0209C000)
#define GPIO1_GDIR_BASE         (0x0209C004)


// virtual address
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;

// address mapping
IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE,4);
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE,4);
SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE,4);
GPIO1_DR = ioremap(GPIO1_DR_BASE,4);
GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE,4);

// cancel mapping
iounmap(CCM_CCGR1_BASE);
iounmap(SW_MUX_GPIO1_IO03_BASE);
iounmap(SW_PAD_GPIO1_IO03_BASE);
iounmap(GPIO1_DR_BASE);
iounmap(GPIO1_GDIR_BASE);

完整例子

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>

#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define LED_MAJOR 200
#define LED_NAME 'led'

#define LEDOFF 0
#define LEDON 1

// physical address
#define CCM_CCGR1_BASE          (0x020C406C)
#define SW_MUX_GPIO1_IO03_BASE  (0x020E0068)
#define SW_PAD_GPIO1_IO03_BASE  (0x020E02F4)
#define GPIO1_DR_BASE           (0x0209C000)
#define GPIO1_GDIR_BASE         (0x0209C004)


// virtual address
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;

// open or close led
void led_switch(uint8_t sta){
    uint32_t val = 0;

    if(sta == LEDON){
        val = readl(GPIO1_DR);
        val &= ~(1 << 3);
        writel(val, GPIO1_DR);
    }else if (sta == LEDOFF)
    {
        val = readl(GPIO1_DR);
        val |= (1 << 3);
        writel(val, GPIO1_DR);
    }
    
}


// open device 
static int led_open(struct inode *inode , struct file *flip){
    return 0;
}

// release device 
static int led_release(struct inode *inode, struct file *filp){
    return 0;
}


// read data
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt){
    return 0;
}


// write data
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt){
    int ret;
    unsigned char databuf[1];
    unsigned char ledstat;

    ret = copy_from_user(databuf,buf,cnt);
    if (ret < 0 ){
        printk("kernel write failed!\n");
        return -1;
    }

    ledstat = databuf[0];

    if (ledstat == LEDON){
        led_switch(LEDON);
    }else if(ledstat == LEDOFF){
        led_switch(LEDOFF);
    }

    return 0;
}

// device operation
static struct file_operation led_fops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .read = led_read,
    .write = led_write,
    .release = led_read,
};

// device init 
static int __init led_init(void){
    int ret = 0;
    uint32_t val = 0;

    // address mapping
    IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE,4);
    SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE,4);
    SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE,4);
    GPIO1_DR = ioremap(GPIO1_DR_BASE,4);
    GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE,4);

    // init gpio1 time
    val = readl(IMX6U_CCM_CCGR1);
    val &= ~(3 << 26);
    val |= (3 << 26);
    writel(val, IMX6U_CCM_CCGR1);

    // set reuse
    writel(5, SW_MUX_GPIO1_IO03);

    // set io
    writel(0x10B0,SW_PAD_GPIO1_IO03);

    // set gpio1 3 as output
    val = readl(GPIO1_GDIR);

    val &= ~(1 << 3);
    val |= (1 << 3);
    writel(val, GPIO1_GDIR);

    // close led
    val = readl(GPIO1_DR);
    val |= (1 << 3);
    writel(val, GPIO1_DR);

    // register device
    ret =  register_chrdev(LED_MAJOR,LED_MAJOR,&led_fops){
        if(ret < 0){
            printk("register chrdev failed.\n");
            return -1;
        }
        return 0;
    }
}

// device exit
static void __exit led_exit(void){

    // cancel mapping
    iounmap(CCM_CCGR1_BASE);
    iounmap(SW_MUX_GPIO1_IO03_BASE);
    iounmap(SW_PAD_GPIO1_IO03_BASE);
    iounmap(GPIO1_DR_BASE);
    iounmap(GPIO1_GDIR_BASE);

    unregister_chrdev(LED_MAJOR,LED_NAME);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("TAN");

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值