简单驱动程序

字符设备驱动(点灯)

驱动程序leddrv.c

#include <linux/module.h>
	#include <linux/kernel.h>
	#include <linux/fs.h>
	#include <linux/init.h>
	#include <linux/delay.h>
	#include <linux/of.h>
	#include <linux/of_device.h>
	#include <linux/of_platform.h>
	#include <linux/uaccess.h>
	#include <asm/irq.h>
	#include <asm/io.h>
	#define S3C2440_GPA(n)  (0<<16 | n)
	#define S3C2440_GPB(n)  (1<<16 | n)
	#define S3C2440_GPC(n)  (2<<16 | n)
	#define S3C2440_GPD(n)  (3<<16 | n)
	#define S3C2440_GPE(n)  (4<<16 | n)
	#define S3C2440_GPF(n)  (5<<16 | n)
	#define S3C2440_GPG(n)  (6<<16 | n)
	#define S3C2440_GPH(n)  (7<<16 | n)
	#define S3C2440_GPI(n)  (8<<16 | n)
	#define S3C2440_GPJ(n)  (9<<16 | n)
	static int led_pin = S3C2440_GPF(5);
	static int major;
	static struct class *led_class;
	static volatile unsigned int *gpio_con;
	static volatile unsigned int *gpio_dat;
	static unsigned int gpio_base[] = {
		0x56000000, // GPACON寄存处地址
		0x56000010, // GPBCON寄存处地址
		0x56000020, // GPCCON寄存处地址
		0x56000030, // GPDCON寄存处地址
		0x56000040, // GPECON寄存处地址
		0x56000050, // GPFCON寄存处地址
		0x56000060, // GPGCON寄存处地址
		0x56000070, // GPHCON寄存处地址
		0x56000080, // GPICON寄存处地址
		0x56000090, // GPJCON寄存处地址
	};
	//1.分配
	static struct file_operations myled_oprs = {
		.owner = THIS_MODULE, //模块本身
		.open = led_open,
		.write = led_write,
		.release = led_close,
	}
	//2.设置
	static int led_open(struct inode * node, struct file * filp){
		//不能直接操作物理地址,需要映射。举例GPF5
		int bank = led_pin >> 16;
		int base = gpio_base(bank);
		int pin = led_pin & 0xffff;
		gpio_con = ioremap(base, 8);//8为映射的大小,一般为一页。
		gpio_dat = gpio_con + 1;//指针加4
		*gpio_con &= ~(3<<(pin * 2));//bit10、11清零操作
		*gpio_con |= ~(1<<(pin * 2));//bit10、11置1,设置为输出。
		return 0;
	}
	static ssize_t led_write(struct file *filp, const char __user *buf, size_t size, loff_t *off){
		//根据应用传入的值来设置LED引脚
		unsigned char val;
		int pin = led_pin & 0xffff;
		copy_from_user(&val, buf, 1);
		if(val){
		//点灯
			*gpio_dat &= ~(1<<pin);
		}else{
		//灭队
			*gpio_dat |= ~(1<<pin);
		}
		return 1;//已写入一个数据。
	}
	static int led_close(struct inode *node, struct file * filp){
		iounmap(gpio_con);//取消之前的映射
		return 0;
	}
	//3.注册file_operations
	//4.入口
	static int myled_init(void)
	{
		major = register_chrdev(0, "myled", &myled_oprs);//主设备号0代表系统自动分配给major
		led_class = class_create(THIS_MODULE,"myled");
		device_class(led_class, NULL, MKDEV(major, 0), NULL, "led");//在用户空间通过led访问灯
		return 0;
	}
	//5.出口
		static int myled_exit(void)
	{
		unregister_chrdev(major, "myled“);
		device_destory(led_class, MKDE(major, 0));
		class_destroy(led_class);
		return 0;
	}
	
	module_init(myled_init);//module宏定义实际上给myled_init起别名,以后可以直接通过module_init找到myled_init。
	module_exit(myled_exit);//同理
	MODULE_LICENSE("GPL");//加上协议避免警告

测试程序ledtest.c

#include <sys/types.h>
	#include <sys/stat.h>
	#include <fcntl.h>
	#include <stdio.h>
	
	int main(int argc, char **argv){
		int fd;
		int val = 1;
		fd = open("dev/led", O_RDWR);
		if(fd < 0){
			printf("Can't open!\n");
		}
		if(argc != 2){
			printf("Usage : \n");
			printf(" %s <on|off>\n", argv[0]);
			return 0;
		}
		if(strcmp(argv[1], "on") == 0){
			val = 1;
		}else{
			val = 0;
		}
	}

使用方法:

       将leddrv.c放入内核目录,然后编译内核。

       交叉编译ledtest.c,将编译好的ledtest应用程序放到板端执行。

发布了146 篇原创文章 · 获赞 160 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/baidu_33879812/article/details/104541288