Linux嵌入式开发--驱动设备开发

一、根据下面的应用程序代码,试写出对应的LED灯的字符设备驱动程序。

//应用程序
#include<stdio.h>		
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>    //头文件的查看可用 man 2 open命令查看
#include<sys/stat.h>	    //open所需的头文件
#include<fcntl.h>
#include<unistd.h>
int main(int argc,char *argv[]){
	int fd;			//调用驱动;
	int value[10];
	fd=open(/dev/chr2”,O_RDWR);	
		//注意打开的文件名就是mknod创建的设备节点名称。
	if(fd<0){
		perror(“open error”);
		exit(1);while(1)
	{	value="LED_ON";	
		write(fd,&value,strlen(value));		//点亮GPX2_7控制的LED灯
		sleep(1);
		value="LED_OFF";
		write(fd,&value,strlen(value));		//熄灭GPX2_7控制的LED灯
		sleep(1);
	}
	close(fd);
	return 0;
}

二、程序

在这里插入图片描述

//驱动程序led.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <string.h>

#define GPX2_CON 0x11000C40  
#define GPX2_SIZE 8
struct cha_dev{
	unsigned int dev_major;
	struct class *cls;
	struct device *devs;
	unsigned int *virt_base;
};
struct cha_dev  *c_dev;

int led_open(struct inode *fnod, struct file *filp)
{
	printk("%s\n",__FUNCTION__);
	return 0;
}

char kernel_value[10];
ssize_t  led_write(struct file *filp, const char *buff, size_t count, loff_t *offp)
{	
	//从用户空间写到内核空间	
	copy_from_user(&kernel_value,buff,count);
	if(strcmp(kernel_value,"LED_ON")==0){
		writel(readl(c_dev->virt_base+1)|(0x1<<7),c_dev->virt_base+1);
	}else if(strcmp(kernel_value,"LED_OFF")==0){
		writel(readl(c_dev->virt_base+1)&(~(0x1<<7)),c_dev->virt_base+1);
	}
	return 0;
}

struct file_operations myops={
	//接口给用户调用
	.open=led_open,
	.write=led_write,
};

static int __init led_init(void){
	int  ret=0;
	//分配空间
	c_dev=kmalloc(sizeof(struct cha_dev),GFP_KERNEL);
	if(c_dev==NULL)
	{
		printk(KERN_ERR "malloc error\n");
		return -ENOMEM;
	}
	//申请设备号
	c_dev->dev_major=register_chrdev(0, "led", &myops);
	if(c_dev->dev_major<0)
	{
		printk(KERN_ERR "register_chrdev error\n");
		ret = -ENODEV;
		goto err_0;
	}
	//创建设备节点
	c_dev->cls=class_create(THIS_MODULE,"mycls");
	if(IS_ERR(c_dev->cls))
	{
		printk(KERN_ERR "class_create error\n");
		ret = PTR_ERR(c_dev->cls); //将指针出错的具体原因转换成一个出错码
		goto	err_1;
	}
	//创建设备文件
	c_dev->devs=device_create(c_dev->cls,NULL,MKDEV(c_dev->dev_major,0),NULL,"chr2");
	if(IS_ERR(c_dev->devs))
	{
		printk(KERN_ERR "device_create error\n");
		ret = PTR_ERR(c_dev->devs); //将指针出错的具体原因转换成一个出错码
		goto err_2;
	}
	//设置设备物理地址
	c_dev->virt_base=ioermap(GPX2_CON,GPX2_SIZE);
	if(c_dev->virt_base== NULL)
	{
		printk(KERN_ERR "ioremap error\n");
		ret = -ENOMEM;
		goto err_3;
	}
	//设置gpx2_7为输出模式,CON的28~31为置为0x1
	writel((readl(c_dev->virt_base)&(~0xf<<4*7)|(0x1<<4*7)),c_dev->virt_base);
	return ret;
err_3:
	device_destroy(c_dev->cls, MKDEV(c_dev->dev_major, 0));
err_2:
	class_destroy(c_dev->cls);
err_1:
	unregister_chrdev(c_dev->dev_major, "chr2");
err0:
	kfree(c_dev);
	return ret;
}

static int __exit led_exit(void){
	iounmap(c_dev->virt_base);
	device_destroy(c_dev->cls, MKDEV(c_dev->dev_major, 0));
	class_destroy(c_dev->cls);
	unregister_chrdev(c_dev->dev_major, "chr2");
	kfree(c_dev);
}

//模块声明
module _init(led_init);
module _exit(led_exit);
//版本GPL
MODULE_LICENSE(“GPL”);


posted @ 2021-11-24 21:17  TTMoon  阅读(16)  评论(0)    收藏  举报  来源