嵌入式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
/*
用一个类来管理

*/
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");

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);