
驱动代码:
-
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_gpio.h>
- #include <linux/gpio.h>
- #include<linux/fs.h>
- #include<linux/io.h>
- #include <linux/uaccess.h>
- #include <linux/timer.h>
- #include <linux/device.h>
- #include <linux/cdev.h>
- #include <linux/slab.h>
- #include"head.h"
- struct device_node *dnode;
- struct gpio_desc *gpiono;
- struct gpio_desc *gpiono1;
- struct gpio_desc *gpiono2;
- struct timer_list mytimer;
- unsigned int major=0;
- unsigned int minor=0;
- struct cdev *mychdev;
- struct class *cls;
- struct device *dev;
- dev_t devno;
- int mycdev_open(struct inode *inode, struct file *file)
- {
- int min=MINOR(inode->i_rdev);//获取打开的的文件的次设备号
- file->private_data= (void *)min;
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- return 0;
- }
- long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- int min=(int)file->private_data;//获取到文件的次设备号
- switch(min)
- {
- case 0: //控制LED1
- switch(cmd)
- {
- case LED_ON: //开灯
- gpiod_set_value(gpiono,1);
- break;
- case LED_OFF: //关灯
- gpiod_set_value(gpiono,0);
- break;
- }
- break;
- case 1: //控制LED2
- switch(cmd)
- {
- case LED_ON: //开灯
- gpiod_set_value(gpiono1,1);
- break;
- case LED_OFF: //关灯
- gpiod_set_value(gpiono1,0);
- break;
- }
- break;
- case 2: //控制LED3
- switch(cmd)
- {
- case LED_ON: //开灯
- gpiod_set_value(gpiono2,1);
- break;
- case LED_OFF: //关灯
- gpiod_set_value(gpiono2,0);
- break;
- }
- break;
- }
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- return 0;
- }
- int mycdev_close(struct inode *inode, struct file *file)
- {
- printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
- return 0;
- }
- //定义操作方法结构体变量并赋值
- struct file_operations fops = {
-
- .open = mycdev_open,
- .unlocked_ioctl = mycdev_ioctl,
- .release = mycdev_close,
- };
- int k=0;
-
- void mytimer_function(struct timer_list *timer)
- {
- k++;
- if(k%5==0)
- {
- printk("hello world");
- }
- mod_timer(timer,jiffies+HZ);
- }
-
- //入口函数
- static int __init mydev_init(void)
- {
-
- dnode=of_find_node_by_path("/myled");
- if(dnode==NULL)
- {
- printk("解析设备树节点失败\n");
- return -1;
- }
- //获取LED1 GPIO编号
- gpiono=gpiod_get_from_of_node(dnode,"led-gpios",0,GPIOD_OUT_LOW,NULL);
- gpiono1=gpiod_get_from_of_node(dnode,"led-gpios",1,GPIOD_OUT_LOW,NULL);
- gpiono2=gpiod_get_from_of_node(dnode,"led-gpios",2,GPIOD_OUT_LOW,NULL);
-
- //初始化定时器对象
- timer_setup(&mytimer,mytimer_function,0);
- mytimer.expires=jiffies+HZ;
- //注册定时器
- add_timer(&mytimer);
-
- int ret;
- //1.申请一个对象空间cdev_alloc
- mychdev=cdev_alloc();
- if(mychdev == NULL)
- {
- printk("申请字符设备驱动对象失败\n");
- ret = -EFAULT;
- goto out1;
- }
- printk("申请字符设备驱动对象成功\n");
- //2.初始化对象cdev_init
- cdev_init(mychdev,&fops);
- //3.申请设备号 register_chrdev_region()/alloc_chrdev_region()
- if(major == 0)
- {
- ret = alloc_chrdev_region(&devno,minor,3,"burger");
- if(ret)
- {
- printk("动态申请设备号失败\n");
- goto out2;
- }
- major=MAJOR(devno);
- minor=MINOR(devno);
- }
- else
- {
- ret = register_chrdev_region(MKDEV(major,minor),3,"burger");
- if(ret)
- {
- printk("静态申请设备号失败\n");
- goto out2;
- }
- }
- printk("申请设备号成功\n");
- //4.注册驱动对象 cdev_add
- ret = cdev_add(mychdev,MKDEV(major,minor),3);
- if(ret)
- {
- printk("注册字符设备驱动对象失败\n");
- goto out3;
- }
- printk("注册字符设备驱动对象成功\n");
- //5.向上提交目录 class_create
- cls=class_create(THIS_MODULE,"burger");
- if(IS_ERR(cls))
- {
- printk("向上提交目录失败\n");
- goto out4;
- }
- printk("向上提交目录成功\n");
- //6.向上提交设备节点信息 device_create
- int i; //向上提交三次设备节点信息
- for(i=0;i<3;i++)
- {
- dev=device_create(cls,NULL,MKDEV(major,i),NULL,"burger%d",i);
- if(IS_ERR(dev))
- {
- printk("向上提交节点失败\n");
- goto out5;
- }
- }
- printk("向上提交节点成功\n");
- return 0;
- out5:
- for(--i;i>=0;i--)
- {
- device_destroy(cls,MKDEV(major,i));
- }
- class_destroy(cls);
- out4:
- cdev_del(mychdev);
- out3:
- unregister_chrdev_region(MKDEV(major,minor),3);
- out2:
- kfree(mychdev);
- out1:
- return ret;
- }
- //出口函数
- static void __exit mydev_exit(void)
- {
- //灭灯
- gpiod_set_value(gpiono,0);
- gpiod_set_value(gpiono1,0);
- gpiod_set_value(gpiono2,0);
- //注销定时器
- del_timer(&mytimer);
- //释放GPIO信号
- gpiod_put(gpiono);
- gpiod_put(gpiono1);
- gpiod_put(gpiono2);
- //注销字符设备驱动
- int i;
- for(i=0;i<3;i++)
- {
- device_destroy(cls,MKDEV(major,i));
- }
- class_destroy(cls);
- cdev_del(mychdev);
- unregister_chrdev_region(MKDEV(major,minor),3);
- kfree(mychdev);
- }
- //声明入口函数
- module_init(mydev_init);
- //声明出口函数
- module_exit(mydev_exit);
- MODULE_LICENSE("GPL");
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include "head.h"
-
- int main(int argc, char const *argv[])
- {
- int a,b,fd;
- while(1)
- {
- fd=-1;
- //从终端读取
- printf("请输入要实现的功能 ");
- printf("1(关灯) 0(开灯)\n");
- printf("请输入>");
- scanf("%d",&a);
- printf("请选择要控制的灯:1(LED1)2(LED2) 3(LED3)\n");
- printf("请输入>");
- scanf("%d",&b);
- switch(b)
- {
- case 1:
- fd=open("/dev/burger0",O_RDWR);
- if(a == 0)
- {
- ioctl(fd,LED_ON,&b);
- break;
- }
- else
- {
- ioctl(fd,LED_OFF,&b);
- break;
- }
- case 2:
- fd=open("/dev/burger1",O_RDWR);
- if(a == 0)
- {
- ioctl(fd,LED_ON,&b);
- break;
- }
- else
- {
- ioctl(fd,LED_OFF,&b);
- break;
- }
- case 3:
- fd=open("/dev/burger2",O_RDWR);
- if(a == 0)
- {
- ioctl(fd,LED_ON,&b);
- break;
- }
- else
- {
- ioctl(fd,LED_OFF,&b);
- break;
- }
- }
- close(fd);
- }
- close(fd);
- return 0;
- }
头文件:
- #ifndef __HEAD_H__
- #define __HEAD_H__
-
- // 构建开灯关灯的功能码
- #define LED_ON _IOW('l', 1,int)
- #define LED_OFF _IOW('l', 0,int)
- #endif
实验结果:

