【嵌入式Linux驱动开发】四、LED驱动完善 - 加入iounmap释放虚拟地址

  考虑一千次,不如去做一次;犹豫一万次,不如实践一次。华丽的跌倒,胜过无谓的徘徊,迈出第一步,你就成功了一半。


一、完善地址映射

在上一节,做IO地址映射时,为求代码精简易于理解,没有加入取消映射,这一节就来继续完善LED驱动程序。

修改led_opr.h结构体,单独加入地址映射和取消映射函数。

#ifndef _LED_OPR_H
#define _LED_OPR_H

struct led_operations {
	int num;	/* num-LED数量 */
	int (*remap) (void);	  /* LED寄存器地址映射 */
	int (*init)  (int which); /* 初始化LED, which-哪个LED */       
	int (*ctl)   (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
	int (*unmap) (void);	  /* LED寄存器地址取消映射 */
};

struct led_operations *get_board_led_opr(void);


#endif

接着在board_qemu.c中,初始化映射和取消映射函数,别忘了在board_qemu_led_init删除IO映射那一部分内容!

...
static int board_qemu_led_remap(void)
{
    CCM_CCGR1 = ioremap(0x20C406C, 4);
    IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x2290014, 4);
    iomux = ioremap(0x20E0000, sizeof(struct iomux));
    gpio1 = ioremap(0x209C000, sizeof(struct imx6ull_gpio));
    gpio5 = ioremap(0x20AC000, sizeof(struct imx6ull_gpio));

    return 0;
}
...

static int board_qemu_led_unmap(void)
{
    iounmap(CCM_CCGR1);
    iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
    iounmap(iomux);
    iounmap(gpio1);
    iounmap(gpio5);

    return 0;
}


static struct led_operations board_qemu_led_opr = {
    .num  = 4,
    .remap = board_qemu_led_remap,
    .init  = board_qemu_led_init,
    .ctl   = board_qemu_led_ctl,
    .unmap = board_qemu_led_unmap,
};


修改LED驱动leddrv.c,在open和close时单独进行调用映射和取消映射!

static int led_drv_open (struct inode *node, struct file *file)
{
	int minor = iminor(node);
	
	/* LED寄存器映射 */
	p_led_opr->remap();
	/* 根据次设备号初始化LED */
	p_led_opr->init(minor);
	
	return 0;
}

static int led_drv_close (struct inode *node, struct file *file)
{
	/* LED取消寄存器映射 */
	p_led_opr->unmap();
	return 0;
}

其他内容基本一致。

二、完善虚拟地址读写

还有要说的,使用 ioremap 函数将寄存器的物理地址映射到虚拟地址以后,我们就可以直接通过指针访问这些地址,但是 Linux 内核不建议这么做,而是推荐使用一组操作函数来对映射后的内存进行读写操作。而上面的程序我们也并没有这样做,原因还是这样做了之后程序显得更加臃肿了,不易于理解掌握,此处仅作介绍。

  • 读操作函数
    • u8 readb(const volatile void __iomem *addr)
    • u16 readw(const volatile void __iomem *addr)
    • u32 readl(const volatile void __iomem *addr)
  • readb、 readw 和 readl 这三个函数分别对应 8bit、 16bit 和 32bit 读操作,参数 addr 就是要读取写内存地址,返回值就是读取到的数据。
  • 写操作函数
    • void writeb(u8 value, volatile void __iomem *addr)
    • void writew(u16 value, volatile void __iomem *addr)
    • void writel(u32 value, volatile void __iomem *addr)
  • writeb、 writew 和 writel 这三个函数分别对应 8bit、 16bit 和 32bit 写操作,参数 value 是要写入的数值, addr 是要写入的地址。
发布了702 篇原创文章 · 获赞 1154 · 访问量 81万+

猜你喜欢

转载自blog.csdn.net/ReCclay/article/details/105026372