GPIO子系统和字符设备驱动实现点灯

GPIO子系统和字符设备驱动实现点灯
.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "led.h"
#include <linux/device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#define CNAME "myled"
//向上层提交目录结构体
struct class* clas;
//字符设备结构体
struct device* devic;
//设备号
dev_t dev;
//主设备号
int major;
//次设备号
int minjor=0;
char kbuf[128] = {0};
//设备树节点结构体
struct device_node* node;

int i=0;
struct cdev* cdev;
#if 1
int major =0;//动态申请设备号
#else
int major = 500;    //静态申请设备号
#endif



int count =6;
dev_t dev;
//设置gpio变量
int gpiono1,gpiono2,gpiono3,gpiono4,gpiono5,gpiono6;

int mycdev_open(struct inode *inode, struct file *file)
{

    int minjor;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    //通过inode结构体取到次设备号
    minjor = MINOR(inode->i_rdev);
    //将次设备号放到file结构体私有数据中
    file->private_data = (void*)minjor;
    return 0;
}

ssize_t mycdev_write(struct file *file, const char __user *user, size_t size, loff_t *loff)
{
    

    
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
    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 my_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    
    int minjor;
    //利用私有数据传参拿到open函数渠道的次设备号
    minjor = (int)file->private_data;
    //判断次设备号
    switch(minjor)
    {
        //次设备号0
        case 0:
        //判断顶二个参数传过来的命令码
        switch(cmd)
        {
            case LED_ON:
            //让gpio输入高电平
            gpio_set_value(gpiono1, 1);
            break;
            case LED_OFF:
            //让gpio输入低电平
            gpio_set_value(gpiono1, 0);
            break;
        }
        break;
         //次设备号0
        case 1:
        switch(cmd)
        {
            case LED_ON:
             //让gpio输入高电平
             gpio_set_value(gpiono2, 1);
            break;
            case LED_OFF:
            //让gpio输入低电平
            gpio_set_value(gpiono2, 0);
            break;
        }

        break;
         //次设备号2
        case 2:
        switch(cmd)
        {
            case LED_ON:
             //让gpio输入高电平
             gpio_set_value(gpiono3, 1);
            break;
            case LED_OFF:
            //让gpio输入低电平
            gpio_set_value(gpiono3, 0);
            break;
        }

        break;
         //次设备号3
        case 3:
        switch(cmd)
        {
            case LED_ON:
             //让gpio输入高电平
             gpio_set_value(gpiono4, 1);
            break;
            case LED_OFF:
            //让gpio输入低电平
            gpio_set_value(gpiono4, 0);
            break;
        }
        break;
         //次设备号4
        case 4:
        switch(cmd)
        {
            case LED_ON:
             //让gpio输入高电平
            gpio_set_value(gpiono5, 1);
            break;
            case LED_OFF:
             //让gpio输入低电平
            gpio_set_value(gpiono5, 0);
            break;
        }
        break;
         //次设备号5
        case 5:
        switch(cmd)
        {
            case LED_ON:
             //让gpio输入高电平
             gpio_set_value(gpiono6, 1);
            break;
            case LED_OFF:
             //让gpio输入低电平
            gpio_set_value(gpiono6, 0);
            break;
        }
        break;

    }
    return 0;

}
//操作方法结构体
const struct file_operations fops =
    {
        .open = mycdev_open,
        .release = mycdev_close,
        .read = mycdev_read,
        .write = mycdev_write,
        .unlocked_ioctl = my_ioctl,

};

//入口
static int __init mycdev_init(void)
{
    int ret;
    //1.分配cdev字符设备结构体指针
    
     cdev = cdev_alloc();
     if(NULL==cdev)
     {
        goto ERR1;
     }

    //2.初始化字符设备
        //
    cdev_init(cdev, &fops);
    

    //3.动态申请设备号
    if(major == 0)
    {                  //申请到的设备号  从0开始  数量    名字                           
        ret = alloc_chrdev_region(&dev, minjor, count, CNAME);     //  //proc/devices可以查看
        if(ret)
        {
            printk("alloc_chrdev_rejion is error\n");
            ret =  -ENOMEM;
            goto ERR2;      
        }
        //获取主设备号
        major = MAJOR(dev);
        //获取次设备号
        minjor = MINOR(dev);
    }
    //静态动态申请设备号
    else{                           //静态指定设备号      个数    名字
        ret = register_chrdev_region(MKDEV(major,minjor),count,CNAME);//proc/devices可以查看
        if(ret)
        {
            printk("register is error\n");
            ret = ENOMEM;
            goto ERR2;
        }
    }
    //4.驱动的注册  结构体  设备号               数量   
    ret = cdev_add(cdev, MKDEV(major, minjor), count);
    if(ret)
    {
        printk("cdev_add is err\n");
        ret = EIO;
        goto ERR3;

    }
    //5.自动创建设备节点

    printk("major=%d\n", major);
    //向上层提交目录获取目录句柄指针
    clas = class_create(THIS_MODULE,"lisi");    //   /sys/class可查看
    if(IS_ERR(clas))
    {
        ret = PTR_ERR(clas);
        goto ERR4;
    }
    for(i=0; i<6; i++)
    {
        //向上层提交设备节点    句柄     设备号                    名字
        devic = device_create(clas, NULL,MKDEV(major,i),  NULL,"myled%d", i);    //  /dev可以查看
        if(IS_ERR(clas))
        {
                ret = PTR_ERR(clas);
                goto ERR5;
        }  
    }
    //根据名字找到设备树节点信息结构体
    node = of_find_node_by_name(NULL, "myleds");
    //根据键名获取gpio号      设备树节点信息结构体  键名  索引号

    gpiono1 = of_get_named_gpio(node,"myled1",0);
    gpiono2 = of_get_named_gpio(node,"myled2",0);
    gpiono3 = of_get_named_gpio(node,"myled3",0);
    gpiono4 = of_get_named_gpio(node,"myled4",0);
    gpiono5 = of_get_named_gpio(node,"myled5",0);
    gpiono6 = of_get_named_gpio(node,"myled6",0);
    //申请指定gpio号的使用权
    //
    gpio_request(gpiono1, NULL);
    gpio_request(gpiono2, NULL);
    gpio_request(gpiono3, NULL);
    gpio_request(gpiono4, NULL);
    gpio_request(gpiono5, NULL);
    gpio_request(gpiono6, NULL);
    //设置gpio为输出
    gpio_direction_output(gpiono1, 0);
    gpio_direction_output(gpiono2, 0);
    gpio_direction_output(gpiono3, 0);
    gpio_direction_output(gpiono4, 0);
    gpio_direction_output(gpiono5, 0);
    gpio_direction_output(gpiono6, 0);
    
    
    return 0;

ERR5:
    for(--i; i>=0; i--)
    {
        device_destroy(clas, i);
    }
ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(MKDEV(major,minjor),count);
ERR2:
    kfree(cdev);
ERR1:
    return EIO;



}


//出口
static void __exit mycdev_exit(void)
{
    //
    gpio_set_value(gpiono1,0);
    gpio_set_value(gpiono2,0);
    gpio_set_value(gpiono3,0);
    gpio_set_value(gpiono4,0);
    gpio_set_value(gpiono5,0);
    gpio_set_value(gpiono6,0);
    //释放gpio编号
    gpio_free(gpiono1);
    gpio_free(gpiono2);
    gpio_free(gpiono3);
    gpio_free(gpiono4);
    gpio_free(gpiono5);
    gpio_free(gpiono6);
    

    //1。销毁设备节点信息
    for(i=0; i<6; i++)
    {
        device_destroy(clas, MKDEV(major,i));
    }
    //2.销毁目录信息
    class_destroy(clas);

    //3.驱动的注销
     cdev_del(cdev);
    //4.销毁设备号
    unregister_chrdev_region(MKDEV(major,minjor),count);
    //5.释放cdev结构体   
    kfree(cdev);
    
}

module_init(mycdev_init);
module_exit(mycdev_exit);

MODULE_LICENSE("GPL");

.h

#ifndef __MYLED_H__
#define __MYLED_H__





#define LED_ON _IOW('a',1,int)
#define LED_OFF _IOW('a',0,int)


typedef enum{
    LED1,
    LED2,
    LED3,
    LED4,
    LED5,
    LED6
}led_t;
#endif

test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "led.h"
char buf[128] = {"lisi"};


int fd1 = -1;
int fd2 = -1;
int fd3 = -1;
int fd4 = -1;
int fd5 = -1;
int fd6 = -1;

int main(int argc, char const *argv[])
{
   
    fd1 = open("/dev/myled0", O_RDWR);
    if (-1 == fd1)
    {
        perror("open is error\n");
        exit(1);
    }
    fd2 = open("/dev/myled1", O_RDWR);
    if (-1 == fd2)
    {
        perror("open is error\n");
        exit(1);
    }
    fd3 = open("/dev/myled2", O_RDWR);
    if (-1 == fd3)
    {
        perror("open is error\n");
        exit(1);
    }
    fd4 = open("/dev/myled3", O_RDWR);
    if (-1 == fd4)
    {
        perror("open is error\n");
        exit(1);
    }
    fd5 = open("/dev/myled4", O_RDWR);
    if (-1 == fd5)
    {
        perror("open is error\n");
        exit(1);
    }
    fd6 = open("/dev/myled5", O_RDWR);
    if (-1 == fd6)
    {
        perror("open is error\n");
        exit(1);
    }
    int whitch;
    while (1)
    {
        whitch = LED1;
        ioctl(fd1,LED_ON);
        sleep(1);
        ioctl(fd1,LED_OFF);
        sleep(1);

        whitch = LED2;
        ioctl(fd2,LED_ON);
        sleep(1);
        ioctl(fd2,LED_OFF);
        sleep(1);

        whitch = LED3;
        ioctl(fd3,LED_ON);
        sleep(1);
        ioctl(fd3,LED_OFF);
        sleep(1);

        ioctl(fd4,LED_ON);
        sleep(1);
        ioctl(fd4,LED_OFF);

        ioctl(fd5,LED_ON);
        sleep(1);
        ioctl(fd5,LED_OFF);

        ioctl(fd6,LED_ON);
        sleep(1);
        ioctl(fd6,LED_OFF);
    }
    close(fd1);
    close(fd2);
    close(fd3);
    close(fd4);
    close(fd5);
    close(fd6);

    return 0;
}

实验现象
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GPIO子系统框架是Linux内核中用于管理GPIO设备的框架,它提供了一种标准的方式来描述和管理GPIO设备GPIO子系统框架的实现步骤如下: 1. 定义GPIO设备对象:GPIO设备对象是GPIO子系统框架的核心部分。它包含了GPIO设备的名称、GPIO号、方向和状态等信息。在定义GPIO设备对象时,需要使用`struct gpio_chip`结构体,它定义了GPIO设备对象的基本属性。 2. 定义GPIO操作函数:GPIO操作函数是实现GPIO设备操作的核心代码。GPIO操作函数通常包括初始化和清理函数,以及实现GPIO操作的读写函数和控制函数等。在定义GPIO操作函数时,需要使用`struct gpio_chip`结构体中定义的回调函数接口。 3. 注册GPIO设备对象:在Linux内核中,GPIO设备对象需要通过`gpiochip_add()`函数进行注册。在注册GPIO设备对象时,需要指定GPIO号范围、GPIO操作函数等参数。 4. 注销GPIO设备对象:在GPIO设备不再使用时,需要通过`gpiochip_remove()`函数进行注销。在注销GPIO设备对象时,需要释放相关资源并取消注册。 5. 调用GPIO操作函数:在使用GPIO设备时,可以通过`gpio_direction_input()`、`gpio_direction_output()`、`gpio_set_value()`、`gpio_get_value()`等函数调用GPIO操作函数。 以上是GPIO子系统框架的实现步骤。在编写GPIO驱动程序时,您需要了解这些步骤的基本原理和使用方法,并根据具体的硬件和需求来选择和使用适当的GPIO操作函数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值