[Linux]第一个驱动程序-LED驱动
第一个驱动程序-LED驱动
艾恩凝 2021/3/22
序
记录学习过程,最后一个程序调了好久,到头来是一个被自己忽略的小问题,程序编译没问题,装载驱动没问题,验证驱动程序没问题,但就是点亮不了led,这种不是语法错误的问题真是让人头疼,开始从驱动程序初始化开始,一步一步地找错误,看看主设备号是否装载成功,负设备号是否正确,led寄存器是否初始化成功,搞了好久,到头来是因为一个变量数据为char型,自己定义的为int,本身是char型数字,但在程序过程中还是出现了问题
简单驱动程序
led驱动程序
1#include <linux/module.h>
2#include <linux/kernel.h>
3#include <linux/fs.h>
4#include <linux/init.h>
5#include <linux/delay.h>
6#include <asm/uaccess.h>
7#include <asm/irq.h>
8#include <asm/io.h>
9#include <asm/arch/regs-gpio.h>
10#include <asm/hardware.h>
11
12static struct class *second_drv_class;
13static struct class_device *second_drv_class_dev;
14
15volatile unsigned long *gpfcon = NULL;
16volatile unsigned long *gpfdat = NULL;
17
18static int second_drv_open(struct inode *inode,struct file *file){
19 //printk("second_drv_open\n");
20 *gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));
21 *gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));
22 return 0;
23}
24
25static ssize_t second_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){
26 //printk("second_drv_write\n");
27 int val;
28 copy_from_user(&val, buf, count); // copy_to_user();
29 if(val ==1){
30 *gpfdat &= ~((1<<4) | (1<<5) | (1<<6));
31 }else{
32 *gpfdat |= ((1<<4) | (1<<5) | (1<<6));
33 }
34 return 0;
35}
36
37static struct file_operations second_drv_fops = {
38 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
39 .open = second_drv_open,
40 .write = second_drv_write,
41};
42int major;
43int second_drv_init(void){
44
45 major = register_chrdev(0, "second_drv", &second_drv_fops);//register tell kernel
46
47 second_drv_class = class_create(THIS_MODULE, "seconddrv");
48 second_drv_class_dev = class_device_create(second_drv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */
49
50 gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
51 gpfdat = gpfcon + 1;
52
53 return 0;
54
55}
56void second_drv_exit(void){
57 unregister_chrdev(111, "second_drv");//unregister tell kernel
58
59 class_device_unregister(second_drv_class_dev);
60 class_destroy(second_drv_class);
61
62 iounmap(gpfcon);
63}
64
65module_init(second_drv_init);
66module_exit(second_drv_exit);
67
68MODULE_LICENSE("GPL");
测试程序
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <fcntl.h>
4#include <stdio.h>
5
6int main(int argc,char **argv){
7 int fd;
8 int val = 1;
9 fd = open("/dev/xyz",O_RDWR);
10 if(fd<0){
11 printf("can't open ! \n");
12 }
13 if (argc != 2)
14 {
15 printf("Usage :\n");
16 printf("%s <on|off>\n", argv[0]);
17 return 0;
18 }
19
20 if (strcmp(argv[1], "on") == 0)
21 {
22 val = 1;
23 }
24 else
25 {
26 val = 0;
27 }
28 write(fd,&val,4);
29 return 0;
30}
复杂驱动程序
驱动程序
1#include <linux/module.h>
2#include <linux/kernel.h>
3#include <linux/fs.h>
4#include <linux/init.h>
5#include <linux/delay.h>
6#include <asm/uaccess.h>
7#include <asm/irq.h>
8#include <asm/io.h>
9#include <asm/arch/regs-gpio.h>
10#include <asm/hardware.h>
11
12#define DEVICE_NAME "leds"
13#define LED_MAJOR_NUMBER 200
14
15static struct class *leds_drv_class;
16static struct class_device *leds_drv_class_devs[4];
17
18volatile unsigned long *GPFCON = NULL;
19volatile unsigned long *GPFDAT = NULL;
20
21
22void led_config(int led_nums){
23 *GPFCON &= ~(0x3<<(led_nums*2));
24 *GPFCON |= (0x1<<(led_nums*2));
25 *GPFDAT &= ~(1<<led_nums);
26}
27static int leds_drv_open(struct inode *inode,struct file *file){
28 int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);
29 //printk("open_minor = %d \n",minor);
30 switch(minor){
31 case 0:{
32 led_config(4);
33 led_config(5);
34 led_config(6);
35 break;
36 }
37 case 1:{
38 led_config(4);
39 break;
40 }
41 case 2:{
42 led_config(5);
43 break;
44 }
45 case 3:{
46 led_config(6);
47 break;
48 }
49 }
50
51 return 0;
52}
53void led_on_off(char val,int led_nums){
54 if(val == 0){
55 *GPFDAT &= ~(1<<led_nums);
56 }
57 if(val == 1){
58 *GPFDAT |= (1<<led_nums) ;
59 }
60}
61static ssize_t leds_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){
62 char val;
63 int minor = MINOR(file->f_dentry->d_inode->i_rdev);
64 //printk("write_minor = %d \n",minor);
65 copy_from_user(&val, buf, count); // copy_to_user();
66 switch (minor){
67 case 0:{
68 led_on_off(val,4);
69 led_on_off(val,5);
70 led_on_off(val,6);
71 break;
72 }
73 case 1:{
74 led_on_off(val,4);
75 break;
76 }
77 case 2:{
78 led_on_off(val,5);
79 break;
80 }
81 case 3:{
82 led_on_off(val,6);
83 break;
84 }
85 }
86
87 return 0;
88}
89
90static struct file_operations leds_drv_fops = {
91 .owner = THIS_MODULE,
92 .open = leds_drv_open,
93 .write = leds_drv_write,
94};
95
96static int leds_drv_init(void){
97 int major,minor=0;
98 GPFCON = (volatile unsigned long *)ioremap(0x56000050, 16);
99 GPFDAT = (volatile unsigned long *)ioremap(0x56000054, 16);
100
101 major = register_chrdev(LED_MAJOR_NUMBER,DEVICE_NAME, &leds_drv_fops);//register tell kernel
102
103 leds_drv_class = class_create(THIS_MODULE, DEVICE_NAME);
104 leds_drv_class_devs[0] = class_device_create(leds_drv_class, NULL, MKDEV(LED_MAJOR_NUMBER, 0), NULL, DEVICE_NAME);
105 for(minor=1;minor<4;minor++){
106 leds_drv_class_devs[minor] = class_device_create(leds_drv_class, NULL, MKDEV(LED_MAJOR_NUMBER, minor), NULL, "led%d", minor);
107 }
108
109 printk(DEVICE_NAME " had initialized\n");
110 return 0;
111
112}
113static void leds_drv_exit(void){
114 int minor=0;
115 unregister_chrdev(LED_MAJOR_NUMBER, DEVICE_NAME);//unregister tell kernel
116 for (minor = 0; minor < 4; minor++){
117 class_device_unregister(leds_drv_class_devs[minor]);
118 }
119 class_destroy(leds_drv_class);
120 iounmap(GPFCON);
121}
122
123module_init(leds_drv_init);
124module_exit(leds_drv_exit);
125MODULE_AUTHOR("https://aeneag.xyz");
126MODULE_VERSION("0.1");
127MODULE_DESCRIPTION("S3C2440 LED Driver");
128MODULE_LICENSE("GPL");
测试程序
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <fcntl.h>
4#include <stdio.h>
5void print_menu(char *file)
6{
7 printf("Usage:\n");
8 printf("%s <dev> <on|off>\n",file);
9 printf("eg. \n");
10 printf("%s /dev/leds on\n", file);
11 printf("%s /dev/leds off\n", file);
12 printf("%s /dev/led1 on\n", file);
13 printf("%s /dev/led1 off\n", file);
14}
15int main(int argc,char **argv){
16 int fd;
17 char val;
18
19 if (argc != 3)
20 {
21 print_menu(argv[0]);
22 return 0;
23 }
24 fd = open(argv[1], O_RDWR);
25 if (fd < 0)
26 {
27 printf("error, can't open %s\n", argv[1]);
28 return 0;
29 }
30 if (!strcmp(argv[2], "on"))
31 {
32 val = 0;
33 write(fd, &val, 1);
34 }
35 else if(!strcmp(argv[2], "off"))
36 {
37 val = 1;
38 write(fd,&val,1);
39 }else{
40 print_menu(argv[0]);
41 return 0;
42 }
43 return 0;
44}
总结
led驱动程序算是处女作了,多搞搞嵌入式,多注意细节,一个细节上的错误,搞了俩小时
评论
0 评论