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

mac2026-04-05  3

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

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");
最新回复(0)