基于GPIO子系统实现led灯驱动的编写,应用层控制三个灯的亮灭

mydev.c 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include"head.h"
#include <linux/io.h> 
#include <linux/device.h> 
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/of_gpio.h> 
#include <linux/timer.h> 
int major;
char kbuf[128];
struct device_node *node;
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;
int major=500;
int minor=0;//存放次设备号的变量
dev_t devno;
struct cdev *cdev;
struct class *cls;
struct device *dev;
/*
//定义定时器对象
struct timer_list  mytimer;
//定时器处理函数
void mytimer_function(struct timer_list *timer)
{
	//对灯的状态取反
     gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1));
     gpiod_set_value(gpiono2,!gpiod_get_value(gpiono2));
	 mod_timer(timer,jiffies+HZ);
}*/
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 * loff)
{
	int ret;
    if(size<sizeof(kbuf))
     {
        size=sizeof(kbuf);
     }
     ret=copy_to_user(ubuf,kbuf,size);
     if(ret)
     {
        printk("copy_from_user failed\n");
        return -EIO;
     }

    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
     return 0;
}
ssize_t mycdev_write(struct file *file ,const char * ubuf,size_t size,loff_t * loff)
{
	int ret;
      
     if(size>sizeof(kbuf))
     {
        size=sizeof(kbuf);
     }
     ret=copy_from_user(kbuf,ubuf,size);
     if(ret)
     {
        printk("copy_from_user failed\n");
        return -EIO;
     }
     printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
      return 0;
}
int mycdev_release(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 arg)
{
   int ret;
   int which;
   ret=copy_from_user(&which,(void *)arg,sizeof(int));
    if(ret)
           {
            printk("copy_from_user err\n");
            return -ENOMEM;
           }
   switch(cmd)
   {
      case DEVICE_ON:
       switch(which)
       {
        case 1:
    gpiod_set_value(gpiono1,1);
      break;
      case 2:
    gpiod_set_value(gpiono2,1);
      break;
       case 3:
    gpiod_set_value(gpiono3,1);
      break;
       }
       break;
      case DEVICE_OFF:
       switch(which)
       {
        case 1:
    gpiod_set_value(gpiono1,0);
      break;
      case 2:
    gpiod_set_value(gpiono2,0);
      break;
       case 3:
    gpiod_set_value(gpiono3,0);
      break;
       }
       break;
   }
   return 0;

}

struct file_operations fops=
{
    .open=mycdev_open,
    .read=mycdev_read,
    .write=mycdev_write,
    .release=mycdev_release,
	.unlocked_ioctl=mycdev_ioctl,

};

static int __init mycdev_init(void)
{
     int i;              
	 int ret;
   //解析设备树节点
   node=of_find_node_by_path("/myleds");
   if(node==NULL)
   {
	   printk("解析设备树节点失败\n");
	   return -ENOENT;
   }
	   printk("解析设备树节点成功\n");
//获取并注册GPIO编号,并且状态为输出低电平
    gpiono1=gpiod_get_from_of_node(node,"led1",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono1))
    {
        printk("获取并注册gpio1失败\n");
        return PTR_ERR(gpiono1);
    }
	
    gpiono2=gpiod_get_from_of_node(node,"led2",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono2))
    {
        printk("获取并注册gpio2失败\n");
        return PTR_ERR(gpiono2);
    }

    
    gpiono3=gpiod_get_from_of_node(node,"led3",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono3))
    {
        printk("获取并注册gpio3失败\n");
        return PTR_ERR(gpiono3);
    }


 //给字符设备驱动申请空间
     cdev=cdev_alloc();
	 if(cdev==NULL)
	 {
		 printk("申请设备驱动失败");
		 ret =-ENOMEM;
		 goto ERROR1 ; 
	 }
  //初始化字符设备驱动对象
   cdev_init(cdev, &fops);
   //申请设备号(动态)
   if(major==0)
   {
     ret=alloc_chrdev_region(&devno,minor, 3, "myled");
	 if(ret)
	 {
		 printk("动态申请设备号失败");
		 ret =-ENOMEM;
		 goto ERROR2 ; 
	 }
	   major=MAJOR(devno);//获取主设备号
       minor=MINOR(devno);//获取次设备号
   }
   else
   {
    ret=register_chrdev_region(MKDEV(major,minor),3, "myled");
	 if(ret)
	 {
		 printk("静态申请设备号失败");
		 ret =-ENOMEM;
		 goto ERROR2 ; 
	 }
   }
   //将驱动对象注册进内核
   ret=cdev_add(cdev,MKDEV(major,minor),3);
	 if(ret)
	 {
		 printk("驱动对象注册失败");
		 ret =-ENOMEM;
		 goto ERROR3; 
	 }
	 //上传目录
     cls=class_create(THIS_MODULE,"mycdev");
    if(IS_ERR(cls))//指针指向预留空间,函数调用失败
    {
        printk("向上提交目录失败\n");
        ret=PTR_ERR(cls);
		goto ERROR4;
    }
     printk("向上提交目录成功\n"); 
	//上传设备节点
   for(i=0;i<3;i++)
   {
      dev=device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i);
    if(IS_ERR(dev))//指针指向预留空间,函数调用失败
    {
        printk("向上提交设备节点失败\n");
        ret=PTR_ERR(cls);
		goto ERROR5;
    }
   }
     printk("向上提交设备节点成功\n"); 
     printk("初始化成功\n");
     return 0; 
ERROR5:
	for(--i;i>=0;i--)
	{
	device_destroy(cls,MKDEV(major,i));
	}
	class_destroy(cls);
ERROR4:
	cdev_del(cdev);//删除内核驱动
ERROR3:
	unregister_chrdev_region(MKDEV(major,minor),3);//释放设备号
ERROR2:
	kfree(cdev);//删除设备对象空间
ERROR1:return ret;   
}
/*
    //初始化定时器
    mytimer.expires=jiffies+HZ;
	timer_setup(&mytimer,mytimer_function,0);
	add_timer(&mytimer);*/
static void __exit mycdev_exit(void)
{
	//先灭灯
    gpiod_set_value(gpiono1,0);
    gpiod_set_value(gpiono2,0);
    gpiod_set_value(gpiono3,0);
    gpiod_put(gpiono1);     
    gpiod_put(gpiono2);     
    gpiod_put(gpiono3); 
	//取消设备节点
   class_destroy(cls);
	//取消上传目录
    cdev_del(cdev);
	//释放设备号
     unregister_chrdev_region(MKDEV(major,minor),3);
	//释放驱动对象空间
     kfree(cdev);
//	del_timer(&mytimer);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include "head.h"
#include <sys/ioctl.h>
int main(int argc,const char * argv[])
{
	int able;
	int which;
    char buf[128]={0};
    int fd=open("/dev/mycdev0",O_RDWR);
     if(fd<0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
	while(1)
	{
	  printf("请输入1表示打开设备,输入0表示关闭设备\n");
	  scanf("%d",&able);
	  if(able==1)
	  {
	  printf("选择led:led1on(1),,led2on(2),led3on(3)\n");
	  scanf("%d",&which);
	  ioctl(fd,DEVICE_ON,&which);
	  }
      else{ 
	  printf("选择led:led1off(1),led2off(2),led3off(3)\n");
	  scanf("%d",&which);
	  ioctl(fd,DEVICE_OFF,&which);	 
	  }
	}
    close(fd);
    
    return 0;
}

head.h 

#ifndef __HEAD_H__
#define __HEAD_H__


#define DEVICE_ON _IOW('l',1,int)//打开设备
#define DEVICE_OFF _IOW('l',0,int)//关闭设备
#endif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值