驱动
#include <linux/init.h> #include <linux/module.h> #include<linux/platform_device.h> #include<linux/mod_devicetable.h> #include<linux/of.h> #include<linux/of_gpio.h> #include <linux/interrupt.h> #include <linux/of_irq.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> #include <linux/slab.h> //创建设备节点,便于应用层对设备文件进行读写 struct cdev *cdev; dev_t devno; struct class *cls; struct device *device; unsigned int minor = 0; unsigned int major = 0; struct resource *res; int irqno; struct gpio_desc *gpiono_d; //解析设备树,管理gpio子系统 struct device_node *denode; int irq; struct gpio_desc *gpiono[4]; //ioctl灯的状态宏 enum{ LED1, LED2, LED3, }; #define LED_ON _IOW('a',1,int) #define LED_OFF _IOW('a',0,int) irqreturn_t irq_handler(int irq,void *arg) { gpiod_set_value(gpiono[3],!gpiod_get_value(gpiono[3])); return IRQ_HANDLED; } int mycdev_open(struct inode *inode, struct file *file) { 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; } long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long args) { int which; int ret; switch(cmd) { case LED_ON: ret = copy_from_user(&which,(void*)args,sizeof(int)); if(ret) { printk("copy from user is error\n"); return -EIO; } switch (which) { case LED1: gpiod_set_value(gpiono[0],1); break; case LED2: gpiod_set_value(gpiono[1],1); break; case LED3: gpiod_set_value(gpiono[2],1); break; } break; case LED_OFF: ret = copy_from_user(&which,(void*)args,sizeof(int)); if(ret) { printk("copy from user is error\n"); return -EIO; } switch (which) { case LED1: gpiod_set_value(gpiono[0],0); break; case LED2: gpiod_set_value(gpiono[1],0); break; case LED3: gpiod_set_value(gpiono[2],0); break; } break; } return 0; } const struct file_operations fops = { .open = mycdev_open, .unlocked_ioctl = mycdev_ioctl, .release = mycdev_close, }; int fun_dev(void) { int ret; int i; //1.分配对象 cdev = cdev_alloc(); if(NULL == cdev) { printk("分配对象失败\n"); ret= -ENOMEM; goto ERR1; } printk("分配对象成功\n"); //2.对象初始化 cdev_init(cdev,&fops); //3.设备资源的申请 ret = alloc_chrdev_region(&devno,minor,3,"mycdev"); if(ret) { printk("动态申请设备好失败\n"); goto ERR2; } major = MAJOR(devno); minor = MINOR(devno); //4.注册 ret = cdev_add(cdev,devno,3); if(ret) { printk("驱动独享注册内核失败\n"); goto ERR3; } //5.提交目录 cls = class_create(THIS_MODULE,"mycdev"); if(IS_ERR(cls)) { printk("向上提交目录失败\n"); goto ERR4; } //6.提交设备节点信息,需要提交3次节点信息 for(i = 0;i < 3;i++) { device = device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i); if(IS_ERR(device)) { printk("向上提交节点信息失败\n"); goto ERR5; } } return 0; ERR5:// for(--i;i>=0;i--) { device_destroy(cls,MKDEV(major,i)); } class_destroy(cls); ERR4:// cdev_del(cdev); ERR3:// unregister_chrdev_region(MKDEV(major,minor),3); ERR2:// kfree(cdev); ERR1://对象空间申请失败 return ret; } //分配对象并且初始化 //probe函数 int pdrv_probe(struct platform_device *pdev) { char *p[4] = {"led1","led2","led3","fan"}; int ret; int i; fun_dev(); //由设备名解析对应的设备树节点 denode = of_find_node_by_name(NULL,"keyirq"); if(denode == NULL) { printk("解析设备树失败\n"); return -EIO; } //获取中断号 irq = irq_of_parse_and_map(denode,0); if(!irq) { printk("获取软中断号失败\n"); return -ENXIO; } //注册中断号 ret = request_irq(irq,irq_handler,IRQF_TRIGGER_FALLING,"myirq1",NULL); if(ret) { printk("注册中断号失败\n"); return -EIO; } denode = of_find_node_by_name(NULL,"extend-leds"); if(denode == NULL) { printk("解析设备树失败\n"); return -EIO; } //根据得到的设备树节点解析对应的gpio编号 for(i = 0;i < 4;i++) { gpiono[i] = gpiod_get_from_of_node(denode,p[i],0,GPIOD_OUT_LOW,NULL); if(IS_ERR(gpiono[i])) { printk("编号led%d解析失败\n",i); return PTR_ERR(gpiono[i]); } } return 0; } //remove函数 int pdrv_remove(struct platform_device *pdev) { int i; for(i = 0;i < 4;i++) { gpiod_set_value(gpiono[i],0); gpiod_put(gpiono[i]); } free_irq(irq,NULL); //1.销毁节点信息 for(i=0;i<3;i++) { device_destroy(cls,MKDEV(major,i)); } //2.销毁目录 class_destroy(cls); //3.注销 cdev_del(cdev); //4.回收设备资源 unregister_chrdev_region(MKDEV(major,minor),3); //5.回收对象空间 kfree(cdev); } //构建设备树匹配标配 struct of_device_id oftable[]= { {.compatible="hqyj,platform"}, {.compatible="hqyj,platform1"}, {}, }; //分配对象并且初始化 struct platform_driver pdrv={ .probe=pdrv_probe, .remove=pdrv_remove, .driver={ .name="aaaaa", .of_match_table=oftable,//设置设备树匹配 }, }; //一键注册宏 module_platform_driver(pdrv); MODULE_LICENSE("GPL");
应用
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/ioctl.h> enum{ LED1, LED2, LED3, }; #define LED_ON _IOW('a',1,int) #define LED_OFF _IOW('a',0,int) int main(int argc,const char * argv[]) { int which; int fd = -1; fd = open("/dev/mycdev0",O_RDWR); if(fd == -1) { perror("open is error\n"); return -1; } while(1) { which = LED1; ioctl(fd,LED_ON,&which); sleep(1); ioctl(fd,LED_OFF,&which); which = LED2; ioctl(fd,LED_ON,&which); sleep(1); ioctl(fd,LED_OFF,&which); which = LED3; ioctl(fd,LED_ON,&which); sleep(1); ioctl(fd,LED_OFF,&which); } close(fd); return 0; }
基于platform驱动框架编写LED灯的驱动,编写应用程序测试
最新推荐文章于 2024-10-28 21:09:56 发布
该文章详细介绍了如何在Linux内核中开发GPIO驱动,包括创建设备节点、管理GPIO子系统、解析设备树、处理中断以及实现ioctl命令来控制LED灯的状态。同时,文章还展示了应用层如何通过ioctl调用来控制设备。
摘要由CSDN通过智能技术生成