傳統方式編寫驅動程序

字符設備驅動(點燈)

驅動程序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應用程序放到板端執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章