platform(驱动层+应用层)实现终端和中断开关点灯
设备树文件添加
myplatform{compatible="hqyj,myplatform";interrupt-parent=<&gpiof>;interrupts=<8 0>,<7 0>,<9 0>;led1-gpio=<&gpioe 10 0>;led2-gpio=<&gpiof 10 0>;led3-gpio=<&gpioe 8 0>;reg=<0x12345678 0x400>;};
应用层
#include<stdio.h>
#include<stdlib.h>
#include<string.h>#include<fcntl.h>
#include<unistd.h>#include<sys/types.h>
#include<sys/stat.h>
#include<sys/ioctl.h>#include"head.h"int main(int argc, char const *argv[])
{int fd;int devc;//设备的编号char buf[128];printf("选择需要打开的设备文件(led)>>");//配置需要打开的设备文件scanf("%d",&devc);sprintf(buf,"/dev/myled%d",devc);printf("路径为:%s",buf);fd=open(buf,O_RDWR);if (fd<0){printf("文件打开失败\n");return -1;}printf("设备文件打开成功\n");int a,b;//输入的值while (1){out:printf("选择需要打开的灯led 1 led 2 led 3>>");scanf("%d",&a);printf("选择要实现的功能 0 关 1开>>");scanf("%d",&b);switch (b){case 0:ioctl(fd,LED_OFF,a); break;case 1:ioctl(fd,LED_ON,a); break;default:printf("输入错误请重新输入\n");goto out;break;}}return 0;
}
头文件
#ifndef __HEAD_H__
#define __HEAD_H__#define LED_ON _IOW('l',1,int)
#define LED_OFF _IOW('l',0,int)
#endif
设备层
#include <linux/init.h>
#include <linux/module.h>#include<linux/fs.h>
#include<linux/io.h>
#include<linux/device.h>#include<linux/gpio.h>
#include<linux/of.h>
#include<linux/of_gpio.h>#include"head.h"#include <linux/platform_device.h>void pdev_release(struct device *dev)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
}
struct resource res[]={[0]={.start=0x50006000,//起始地址.end=0x50006000+0x400,//终止地址.name="pe_mem",//名字.flags=IORESOURCE_MEM ,//标志位地址空间},[1]={.start=71,.end=71,.name="key1_irq",.flags=IORESOURCE_IRQ,},[2]={.start=72,.end=72,.name="key2_irq",.flags=IORESOURCE_IRQ,},[3]={.start=73,.end=73,.name="key3_irq",.flags=IORESOURCE_IRQ,},
};
//设备结构体
struct platform_device pdev={.name="aaaaa",.id=PLATFORM_DEVID_AUTO,.dev={.release=pdev_release,},.num_resources=ARRAY_SIZE(res),.resource=res,
};
static int __init mycdev_init(void)
{platform_device_register(&pdev);return 0;
}
static void __exit mycdev_exit(void)
{platform_device_unregister(&pdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
驱动层
#include <linux/init.h>
#include <linux/module.h>#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/gpio.h>#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>#include <linux/interrupt.h>
#include"head.h"struct resource *res;
unsigned int irq_no[3];int major;
char kbuf[128]={0};struct class *cls;
struct device *dev_c;struct device_node *dnode;struct gpio_desc *lednode1;
struct gpio_desc *lednode2;
struct gpio_desc *lednode3;int mycdev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);unsigned long ret;//向用户空间读取拷贝if(size>sizeof(kbuf))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小size=sizeof(kbuf);ret=copy_to_user(ubuf,kbuf,size);if(ret)//拷贝失败{printk("copy_to_user filed\n");return ret;}return 0;
}ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{unsigned long ret;//从用户空间读取数据if(size>sizeof(kbuf))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小size=sizeof(kbuf);ret=copy_from_user(kbuf,ubuf,size);if(ret)//拷贝失败{printk("copy_to_user filed\n");return ret;}return 0;
}long mycdev_ioctl (struct file * file, unsigned int cmd, unsigned long arg)
{switch (cmd){case LED_OFF:switch (arg){case 1:gpiod_set_value(lednode1,0);break;case 2:gpiod_set_value(lednode2,0);break;case 3:gpiod_set_value(lednode3,0);break;}break;case LED_ON:switch (arg){case 1:gpiod_set_value(lednode1,1);break;case 2:gpiod_set_value(lednode2,1);break;case 3:gpiod_set_value(lednode3,1);break;}break;default:break;}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,.read=mycdev_read,.write=mycdev_write,.unlocked_ioctl=mycdev_ioctl,.release=mycdev_close,
};irqreturn_t myirq_handle(int irq,void *dev)
{switch ((unsigned int)dev){case 0://反转电平gpiod_set_value(lednode1,!gpiod_get_value(lednode1));//防止其他灯亮gpiod_set_value(lednode2,0);gpiod_set_value(lednode3,0);break;case 1://反转电平gpiod_set_value(lednode2,!gpiod_get_value(lednode2));//防止其他灯亮gpiod_set_value(lednode1,0);gpiod_set_value(lednode3,0);break;case 2://反转电平gpiod_set_value(lednode3,!gpiod_get_value(lednode3));//防止其他灯亮gpiod_set_value(lednode1,0);gpiod_set_value(lednode2,0);break;default:break;}return IRQ_HANDLED;}int pdrv_probe(struct platform_device *dev)
{printk("%s:%s:%d",__FILE__,__func__,__LINE__);//字符设备驱动注册major=register_chrdev(0,"mychrdev",&fops);if(major<0){printk("字符设备驱动注册失败\n");return major;}printk("字符设备驱动注册成功:major=%d\n",major);//向上提交目录cls=class_create(THIS_MODULE,"mychrdev");if(IS_ERR(cls)){printk("向上提交目录失败\n");return -PTR_ERR(cls);}printk("向上提交目录成功\n");int i;for(i=0;i<3;i++){dev_c=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);//制作字符设备文件if(IS_ERR(dev_c)){printk("向上提交设备节点失败\n");return -PTR_ERR(dev_c);}}printk("向上提交设备节点成功\n");res=platform_get_resource(dev,IORESOURCE_MEM,0);if(res==NULL){printk("获取MEM类型资源失败\n");return -EFAULT;} printk("MEM类型资源为%x\n",res->start);//获取中断类型的资源for ( i = 0; i < 3; i++){irq_no[i]=platform_get_irq(dev,i);if (irq_no[i]<0){printk("获取中断类型资源失败\n");return irq_no[i];}printk("获取中断类型资源值为%d\n",irq_no[i]);}//解析LED1的gpio编号lednode1=gpiod_get_from_of_node(dev->dev.of_node,"led1-gpio",0,GPIOD_OUT_LOW,NULL);if (lednode1==NULL){printk("解析gpio编号失败\n");return -ENXIO;}lednode2=gpiod_get_from_of_node(dev->dev.of_node,"led2-gpio",0,GPIOD_OUT_LOW,NULL);if (lednode2==NULL){printk("解析gpio编号失败\n");return -ENXIO;}lednode3=gpiod_get_from_of_node(dev->dev.of_node,"led3-gpio",0,GPIOD_OUT_LOW,NULL);if (lednode3==NULL){printk("解析gpio编号失败\n");return -ENXIO;}printk("解析gpio-led编号成功\n");for ( i = 0; i < 3; i++){irq_no[i]=irq_of_parse_and_map(dev->dev.of_node,i);if(!irq_no[i]){printk("解析软中断失败\n");return -ENXIO;}printk("解析%d 软中断成功\n",i+1);int ret=request_irq(irq_no[i],myirq_handle,IRQF_TRIGGER_FALLING,"key",(void*)i); if(ret){printk("注册按键请求中断失败\n");return ret;}}printk("注册按键请求中断成功\n");return 0;
}int pdrv_remove(struct platform_device *dev)
{gpiod_set_value(lednode1,0);gpiod_put(lednode1);gpiod_set_value(lednode2,0);gpiod_put(lednode2);gpiod_set_value(lednode3,0);gpiod_put(lednode3);int i;
for ( i = 0; i < 3; i++)
{free_irq(irq_no[i],(void*)i);device_destroy(cls,MKDEV(major,i));
}//销毁目录class_destroy(cls);//注销字符设备驱动unregister_chrdev(major,"mychrdev");printk("%s:%s:%d",__FILE__,__func__,__LINE__);return 0;
}struct of_device_id oftable[]=
{{.compatible="hqyj,myplatform",},{/*end node*/},//防止数组越界
};struct platform_driver pdrv={.probe=pdrv_probe,.remove=pdrv_remove,.driver={.name="bbbbb",.of_match_table=oftable,//设置设备树匹配},};module_platform_driver(pdrv);
MODULE_LICENSE("GPL");
现象演示