[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 评论
avatar

取消