LED的驱动程序很简单,按照张字符型设备驱动设计方法顺下来即可实现,这里主要讲几个注意事项。
一、在linux系统中,操作硬件不能够使用物理地址,一定要用虚拟地址。将物理地址转化为虚拟地址的函数如下:
#define ioremap(cookie,size)
其中cookie为要转化的物理地址,size为转化空间的大小,单位为字节。返回值为转化后的虚拟地址。
二、在执行程序时我们需要顺带输入参数进去,但是是以字符串的形式输入的,不方便操控。所以用atoi函数将字符串转化为整数,函数原型如下:
int atoi(const char *nptr);
三、点亮LED是对设备的控制,而不是读写。即在驱动程序中ioctl函数里相对应的寄存器的虚拟地址写入值即可。向某个地址写入值的函数为writel函数,原型:
static inline void writel(unsigned int b, volatile void __iomem *addr)
第一个参数为写入的值,第二个参数是虚拟地址。
接下来也没什么了,最关键的就是驱动程序模型。要想写出字符设备驱动一定要学好它,特别重要!!
头文件:
1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/cdev.h> 4 #include <linux/fs.h> 5 #include <linux/io.h> 6 7 #define LED_MAGIC 'L' 8 #define LED_OFF _IO(LED_MAGIC,0) 9 #define LED_1 _IO(LED_MAGIC,1) 10 #define LED_2 _IO(LED_MAGIC,2) 11 #define LED_3 _IO(LED_MAGIC,3) 12 #define LED_4 _IO(LED_MAGIC,4) 13 #define LED_ALL _IO(LED_MAGIC,5)
驱动程序代码:
1 #include "led.h" 2 3 #define GPBCON 0x56000010 4 #define GPBDAT 0x56000014 5 6 /*控制LED寄存器的物理地址*/ 7 unsigned int *led_config; 8 unsigned int *led_data; 9 10 /*存储设备号*/ 11 dev_t devno; 12 13 /*分配cdev*/ 14 struct cdev cdev; 15 16 int led_open(struct inode *node, struct file *filp) 17 { 18 /*将物理地址转为虚拟地址*/ 19 led_config = ioremap(GPBCON,3); 20 led_data = ioremap(GPBDAT,2); 21 22 /*向某一地址写入值*/ 23 writel(0x15400,led_config); 24 25 return 0; 26 } 27 /*驱动程序里的设备控制函数*/ 28 long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 29 { 30 switch(cmd) 31 { 32 case LED_1: 33 writel(0b00011100000,led_data); 34 return 0; 35 case LED_2: 36 writel(0b00101100000,led_data); 37 return 0; 38 case LED_3: 39 writel(0b00110100000,led_data); 40 return 0; 41 case LED_4: 42 writel(0b00111000000,led_data); 43 return 0; 44 case LED_OFF: 45 writel(0b00111100000,led_data); 46 return 0; 47 case LED_ALL: 48 writel(0,led_data); 49 return 0; 50 51 default: 52 return -EINVAL; 53 } 54 } 55 56 /*函数映射关系表*/ 57 struct file_operations led_fops = 58 { 59 .open = led_open, 60 .unlocked_ioctl = led_ioctl, 61 }; 62 63 64 65 static int led_init() 66 { 67 68 /*初始化cdev*/ 69 cdev_init(&cdev, &led_fops); 70 /*注册cdev*/ 71 alloc_chrdev_region(&devno, 0, 1,"myled"); //动态分配设备号,第四个参数为设备名称 72 cdev_add(&cdev, devno, 1); 73 return 0; 74 } 75 76 static void led_exit() 77 { 78 /*删除设备*/ 79 cdev_del(&cdev); 80 /*释放设备号*/ 81 unregister_chrdev_region(devno,1); 82 } 83 84 MODULE_LICENSE("GPL"); 85 module_init(led_init); 86 module_exit(led_exit);
应用程序代码:
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <sys/ioctl.h> 5 #include <stdio.h> 6 #include "led.h" 7 8 int main(int argc, char *argv[]) 9 { 10 int fd; 11 int cmd; 12 13 if (argc <2 ) 14 { 15 printf("please enter the second para!\n"); 16 return 0; 17 } 18 19 cmd = atoi(argv[1]); 20 21 fd = open("/dev/myled",O_RDWR); 22 23 if(cmd == 0) 24 ioctl(fd,LED_OFF); 25 if(cmd == 1) 26 ioctl(fd,LED_1); 27 if(cmd == 2) 28 ioctl(fd,LED_2); 29 if(cmd == 3) 30 ioctl(fd,LED_3); 31 if(cmd == 4) 32 ioctl(fd,LED_4); 33 if(cmd == 5) 34 ioctl(fd,LED_ALL); 35 36 return 0; 37 }