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

驱动:

#include<linux/init.h>
#include<linux/module.h>
#include<linux/of.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include<linux/io.h>
#include<linux/delay.h>
#include<linux/string.h>
#include<linux/cdev.h>
#include <linux/slab.h>
#include<linux/uaccess.h>
#include<linux/gpio.h>
#include<linux/of_gpio.h>
#include<linux/time.h>
#include"led.h"
struct device_node *node;
struct property *nd;
struct gpio_desc *core_led[3];
struct gpio_desc *extern_led[3];
struct device_node *core_node;
struct device_node *extern_node;

//定义设备号
#define CHRNAME "myled"
static int minor = 0;
#if 1
static unsigned int major = 0;
#else
unsigned int major = 200;
#endif
#define COUNT   3

struct cdev *cdev;
struct class *cls;
struct device *dev;

#define MY_TIME jiffies+HZ
struct timer_list mytimer;
int i = 0;

//定时器事件
void timer_hander(struct timer_list *timer)
{
    gpiod_set_value(extern_led[i],!gpiod_get_value(extern_led[i]));
    if(gpiod_get_value(extern_led[i])==0)
    {
        if((i++) == 2)
        i = 0;
    }
    mod_timer(&mytimer,MY_TIME);
}

void led_ctl(unsigned int cmd,unsigned long num)
{
    if(cmd == LED_ON(EXTERN))
    {
        switch (num)
        {
        case LED1:
            gpiod_set_value(extern_led[0],1);
            break;
        case LED2:
            gpiod_set_value(extern_led[1],1);
            break;
        case LED3:
            gpiod_set_value(extern_led[2],1);
            break;
        }
    }
    else if(cmd == LED_OFF(EXTERN))
    {
        switch (num)
        {
        case LED1:
            gpiod_set_value(extern_led[0],0);
            break;
        case LED2:
            gpiod_set_value(extern_led[1],0);
            break;
        case LED3:
            gpiod_set_value(extern_led[2],0);
            break;
        }
    }
    else if(cmd == LED_ON(CORE))
    {
        switch (num)
        {
        case LED1:
            gpiod_set_value(core_led[0],1);
            break;
        case LED2:
            gpiod_set_value(core_led[1],1);
            break;
        case LED3:
            gpiod_set_value(core_led[2],1);
            break;
        }
    }
    else if(cmd == LED_OFF(CORE))
    {
        switch (num)
        {
        case LED1:
            gpiod_set_value(core_led[0],0);
            break;
        case LED2:
            gpiod_set_value(core_led[1],0);
            break;
        case LED3:
            gpiod_set_value(core_led[2],0);
            break;
        }
    }
}

long chrdev_ioctl (struct file *file, unsigned int cmd, unsigned long num)
{
        int whitch,ret;
        ret = copy_from_user(&whitch,(void *)num,sizeof(int));
        printk("whitch = %d\r\n",whitch);
        if (ret)
        {
            printk("copy_from_user failed!\r\n");
            return -1;
        }
        led_ctl(cmd,whitch);

    return 0;
}
int chrdev_open (struct inode *node, struct file *file)
{
    return 0;
}
int chrdev_release (struct inode *inode, struct file *file)
{
    return 0;
}
struct file_operations ops = {
    .open = chrdev_open,
    .release = chrdev_release,
    .unlocked_ioctl = chrdev_ioctl,
};

//初始化led灯
int led_init(void)
{
    int i;
    node=of_find_node_by_path("/mtnode@0x12345678");
    node=of_get_child_by_name(node,"myleds");
    extern_node = of_get_child_by_name(node,"extern_leds");
    core_node = of_get_child_by_name(node,"core_leds");
    if(node == NULL)
    {
        printk("获取节点信息失败\r\n");
        return -1;
    }
    printk("获取节点信息成功!\r\n");
    
    extern_led[0] = gpiod_get_from_of_node(extern_node,"led1",0,GPIOD_OUT_LOW,NULL);
    extern_led[1] = gpiod_get_from_of_node(extern_node,"led2",0,GPIOD_OUT_LOW,NULL);
    extern_led[2] = gpiod_get_from_of_node(extern_node,"led3",0,GPIOD_OUT_LOW,NULL);
    core_led[0] = gpiod_get_from_of_node(core_node,"led1",0,GPIOD_OUT_LOW,NULL);
    core_led[1] = gpiod_get_from_of_node(core_node,"led2",0,GPIOD_OUT_LOW,NULL);
    core_led[2] = gpiod_get_from_of_node(core_node,"led3",0,GPIOD_OUT_LOW,NULL);

    for(i = 0;i<3;i++)
    {
        if(IS_ERR(extern_led[i]))
        {
            printk("申请led%d编号失败\r\n",i+1);
            return PTR_ERR(extern_led[0]);
        }
    }
    gpiod_set_value(extern_led[0],0);
    gpiod_set_value(extern_led[1],0);
    gpiod_set_value(extern_led[2],0);
    gpiod_set_value(core_led[0],1);
    gpiod_set_value(core_led[1],1);
    gpiod_set_value(core_led[2],1);

//    mytimer.expires = MY_TIME;
//    timer_setup(&mytimer,timer_hander,0);
//    add_timer(&mytimer);
    return 0;
}

//注册字符设备驱动
int chrdev_logon(void)
{
    int ret,i;
    dev_t devno;
    //分配对象
    cdev=cdev_alloc();
    if(cdev == NULL)
    {
        printk("cdev alloc memory default\n");
        ret = -ENOMEM;
        goto END1;
    }
    printk("分配对象成功\n");
    //对象的初始化
    cdev_init(cdev,&ops);
    //设备号申请
    if(major == 0)
    {
        ret = alloc_chrdev_region(&devno,minor,COUNT,CHRNAME);
        if(ret)
        {
            printk("动态设备号申请失败\n");
            goto ERR2;
        }
        major = MAJOR(devno);
        minor = MINOR(devno);
        printk("动态申请设备号成功\n");
    }
    else if(major>0)
    {
        ret = register_chrdev_region(MKDEV(major,minor),COUNT,CHRNAME);
        if(ret)
        {
            printk("静态申请设备号失败\n");
            goto ERR2;
        }
        printk("静态申请设备号成功\n");
    }
    ret=cdev_add(cdev,MKDEV(major,minor),COUNT);
    if(ret)
    {
        printk("字符设备驱动注册失败\n");
        goto ERR3;
    }
    printk("字符设备驱动成功\n");

    //自动创建设备节点
    cls = class_create(THIS_MODULE,"led");
    if(IS_ERR(cls))
    {
        printk("创建节点目录失败\n");
        ret = PTR_ERR(cls);
        goto ERR4;
    }
    printk("创建节点目录成功\n");
    for(i = 0;i<COUNT;i++)
    {
        dev = device_create(cls,NULL,MKDEV(major,i),NULL,"led%d",i);
        if(IS_ERR(dev))
        {
            printk("创建节点失败\n");
            ret = PTR_ERR(dev);
            goto ERR5;
        }
    }
    printk("创建节点成功\n");    

    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),COUNT);
ERR2:
    kfree(cdev);
END1:
    return ret;
}


int __init devtree_init(void)
{
    if (chrdev_logon()!=0)
    {
        printk("创建节点失败\r\n");
        return -1;
    }
    led_init();
    return 0;
}
    //nd = of_find_property(node,"compatible",&len);
    //printk("compatible = %s,values = %s\r\n",nd->name,(char*)nd->value);
/*
    nd = of_find_property(node,"astring",&len);
    printk("compatible = %s,values = %s\r\n",nd->name,(char*)nd->value);

    nd = of_find_property(node,"uint",&len);
    printk("compatible = %s,values = %x,%x\r\n",nd->name,(__be32_to_cpup)(nd->value),(__be32_to_cpup)(nd->value+4));

    nd = of_find_property(node,"binarry",&len);
    if(nd == NULL)
    {
        printk("fond binarry failed!\r\n");
        return -1;
    }
    */
void __exit devtree_exit(void)
{
    int i;
    for(i = 0;i<3;i++)
    {
        gpiod_set_value(extern_led[i],0);
        gpiod_set_value(core_led[i],0);
        gpiod_put(extern_led[i]);
        gpiod_put(core_led[i]);
    }
    //del_timer(&mytimer);
    for(i = 0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    printk("销毁设备节点成功\n");
    class_destroy(cls);
    printk("销毁节点目录成功\n");
    cdev_del(cdev);
    printk("删除字符设备\n");
    unregister_chrdev_region(MKDEV(major,minor),COUNT);
    kfree(cdev);
}

module_init(devtree_init);
module_exit(devtree_exit);
MODULE_LICENSE("GPL");

应用层:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/ioctl.h>
#include"led.h"
#include<wait.h>
#include<sys/epoll.h>
void func(int fd,int place,int num,int state)
{
    printf("place = %d , num = %c , state = %d\n",place,num,state);
    if(state)
    {
        ioctl(fd,LED_ON(place),&num);
        printf("%d LED_ON = %ld\n",state,LED_ON(place));
    }
    else
    {
        ioctl(fd,LED_OFF(place),&num);
        printf("%d LED_ON = %ld\n",state,LED_OFF(place));
    }
}
char buf[128] = {0};
int main()
{
    int fd = open("/dev/led1",O_RDWR);
    if(fd < 0 )
    {
        printf("文件打开失败\n");
        return -1;
    }

    int i;
    char buf[50] = {0};
    char name[50] = {0};
    int state;
    while (1)
    {
        printf("请输入您要控制的设备位置(main or extern)>>>");
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1] = '\0';
        printf("buf = %s\n",buf);
        printf("请输入要控制的设备和状态 例(LED1 1)>>>");
        scanf("%s %d",name,&state);
        while (getchar()!=10);       
        if(strcmp(buf,"main") == 0)
        {
            i = CORE;
            func(fd,i,name[3],state);
        }
        else if(strcmp(buf,"extern") == 0)
        {
            i = EXTERN;
            func(fd,i,name[3],state);
        }
        else
        {
            printf("输入错误,请重新输入\n");
        }
    }
    close(fd);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值