嵌入式Linux驱动GPIO操作改进包括从驱动到测试程序

说明

这篇博客记录的是上一次编撰GPIO驱动的改进版本linux系统介绍red hat linux 下载。这儿改进了两个地方:

字符的驱动编撰小结字符设备驱动编撰步骤

这儿出现的代码是从前面的程序拷贝下来的嵌入式 linux驱动嵌入式 linux驱动

字符设备驱动编撰步骤:

模块加载入口函数中:创建设备节点文件(为用户提供一个可操作的文件插口)硬件的初始化实现file_operations(文件插口的实现)操作寄存器的形式总结

	    u32 value = readl(led_dev->reg_virt_base);
	    value &=~(1<<0);
	    value |=1<reg_virt_base);
	    gpiol20_dat = gpiol20_cof+1;

		 writel(read(led_dev->reg_virt_base+4) |(1<reg_virt_base+4);

代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define GPIOL2_CON 0x11000000+0x0100
#define LEN 8
/*
用一个类来管理

嵌入式linux驱动程序详解_嵌入式linux驱动开发教程_嵌入式 linux驱动

*/
struct led_desc{ unsigned int dev_major; struct class *cls; struct device *dev; void* reg_virt_base; }; static struct led_desc *led_dev; ssize_t chr_drv_read (struct file *filp, char __user *buffer, size_t count, loff_t *fpos) { u32 value=0; int ret; printk("-------%s-------n",__FUNCTION__); value = readl(led_dev->reg_virt_base+4); value &=1<<0; ret = copy_to_user(buffer, &value, count); return 0 ; } ssize_t chr_drv_write (struct file *flip, const char __user *buffer, size_t count, loff_t *fpos) { int ret; int value; static int num=0; printk("write:%d ",num++); ret = copy_from_user(&value, buffer, count); if(value == 1) { printk("vaule:%d n",value); writel(readl(led_dev->reg_virt_base+4) |(1<<0), led_dev->reg_virt_base+4); } else { printk("vaule:%d n",value); writel(readl(led_dev->reg_virt_base+4) & ~(1<<0), led_dev->reg_virt_base+4); } return 0; } int chr_drv_open (struct inode *inode, struct file *filp) { printk("-------%s-------n",__FUNCTION__); return 0; } int chr_drv_release (struct inode *inode, struct file *filp) { printk("-------%s-------n",__FUNCTION__); return 0; } static struct file_operations file_ops={ .owner = THIS_MODULE, .open = chr_drv_open, .read = chr_drv_read, .write = chr_drv_write, .release = chr_drv_release, }; static int __init chr_io_init(void) { int ret; u32 value; printk("-----------%s--------n",__FUNCTION__); //GFP_KERNEL 如果内存不够用函数会一直阻塞(休眠) led_dev = kmalloc(sizeof(struct led_desc), GFP_KERNEL); if(led_dev == NULL) { //KERN_ERR 用于筛选调试信息 printk(KERN_ERR "malloc error!n"); return -ENOMEM; } //动态分配设备节点 led_dev->dev_major = register_chrdev(0 , "led",&file_ops); if(led_dev->dev_major < 0) { printk(KERN_ERR "register_chrdev error!n"); ret = -ENODEV; goto err_0; } led_dev->cls = class_create(THIS_MODULE, "led_cls");

嵌入式linux驱动开发教程_嵌入式linux驱动程序详解_嵌入式 linux驱动

if(IS_ERR(led_dev->cls))//用宏做出错判断 在这里出错了 之前的都要释放 { printk(KERN_ERR "class_create error!n"); ret = PTR_ERR(led_dev->cls);//将指针出错的具体原因转换成出错码 goto err_1; } led_dev->dev = device_create(led_dev->cls, NULL, MKDEV(led_dev->dev_major,0), NULL, "led%d",0); if(IS_ERR(led_dev->dev)) { printk(KERN_ERR "device_create error!n"); ret = PTR_ERR(led_dev->dev); goto err_2; } led_dev->reg_virt_base = ioremap(GPIOL2_CON, LEN); if(IS_ERR(led_dev->reg_virt_base)) { printk(KERN_ERR "ioremap error!n"); ret = -ENOMEM; goto err_3; } //规范的输入输出方式 value = readl(led_dev->reg_virt_base); value &=~(1<<0); value |=1<<0; writel(value, led_dev->reg_virt_base); return 0; //梯形结构的错误处理 err_3: device_destroy(led_dev->cls , MKDEV(led_dev->dev_major,0)); err_2: class_destroy(led_dev->cls); err_1: unregister_chrdev(led_dev->dev_major, "led0"); //先释放设备号 再释放内存空间 err_0: kfree(led_dev);//防止在发生错误的时候以前申请的内存得不到释放 return ret; } static void __exit chr_io_exit(void) { printk("-----------%s--------n",__FUNCTION__); iounmap(led_dev->reg_virt_base); unregister_chrdev(led_dev->dev_major, "led0"); device_destroy(led_dev->cls, MKDEV(led_dev->dev_major,0)); //和创建相反 class_destroy(led_dev->cls); } MODULE_LICENSE("GPL"); module_init(chr_io_init); module_exit(chr_io_exit);

Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复