驱动开发day8

基于GPIO子系统编写LED驱动,编写应用程序进行测试

设置定时器,5秒打印一次hello world

mycdev.c

复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/timer.h>
/*
myled                                                                                               
      {
          led1-gpio=<&gpioe 10 0>;
          led2-gpio=<&gpiof 10 0>;
          led3-gpio=<&gpioe 8 0>;
      };

*/
struct device_node *dnode; //解析得到的设备树节点对象指针
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;
struct timer_list mytimer; 

struct class *cls;
struct device *dev;
int major;
char kbuf[128]={0};

//定时器处理函数
void mytimer_function(struct timer_list *timer)
{
    //LED1状态取反
    //gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1));
    //LED2状态取反
    //gpiod_set_value(gpiono2,!gpiod_get_value(gpiono2));
    //LED3状态取反
    //gpiod_set_value(gpiono3,!gpiod_get_value(gpiono3));

    printk("hello world\n");
    //再次启用定时器
    mod_timer(timer,jiffies+5*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 *lof)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    int ret=copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy_to_user filed\n");
        return -EIO;
    }
    return 0;
}
 
ssize_t mycdev_write(struct file *file,const char *ubuf,size_t size,loff_t *lof)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    int ret=copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy_from_user filed\n");
        return -EIO;
    }
    //设定该GPIO管脚的输出值
    if(kbuf[0]=='0')
    {
        gpiod_set_value(gpiono1,0);
        gpiod_set_value(gpiono2,0);
        gpiod_set_value(gpiono3,0);       
    }
    else if(kbuf[0]=='1')
    {
        gpiod_set_value(gpiono1,1);
        gpiod_set_value(gpiono2,1);
        gpiod_set_value(gpiono3,1); 
    }
    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,
    .release=mycdev_close,
};

static int __init mycdev_init(void)
{
    //字符设备驱动注册
    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 = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
            printk("向上提交设备节点失败\n");
            return -PTR_ERR(dev);
        }
    }
    printk("向上提交设备节点成功\n");
    //解析设备树节点信息
    dnode = of_find_node_by_path("/myled");
    if(dnode == NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    //获取LED1 GPIO编号
    gpiono1 = gpiod_get_from_of_node(dnode,"led1-gpio",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono1))
    {
        printk("获取GPIO编号失败\n");
        return -PTR_ERR(gpiono1);
    }
    //获取LED1 GPIO编号
    gpiono2 = gpiod_get_from_of_node(dnode,"led2-gpio",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono2))
    {
        printk("获取GPIO编号失败\n");
        return -PTR_ERR(gpiono2);
    }
    //获取LED1 GPIO编号
    gpiono3 = gpiod_get_from_of_node(dnode,"led3-gpio",0,GPIOD_OUT_LOW,NULL);
    if(IS_ERR(gpiono3))
    {
        printk("获取GPIO编号失败\n");
        return -PTR_ERR(gpiono3);
    }
    //初始化定时器对象
    timer_setup(&mytimer,mytimer_function,0);
    mytimer.expires = jiffies+5*HZ;//定时1s

    //注册定时器
    add_timer(&mytimer);
    return 0;
}
static void __exit mycdev_exit(void)
{
    //注销定时器
    del_timer(&mytimer);
    gpiod_set_value(gpiono1,0);
    gpiod_set_value(gpiono2,0);
    gpiod_set_value(gpiono3,0);
    //释放GPIO编号
    gpiod_put(gpiono1);
    gpiod_put(gpiono2);
    gpiod_put(gpiono3);

    //销毁设备节点信息
    int i;
    for(i = 0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //销毁目录
    class_destroy(cls);

    //注销设备字符驱动
    unregister_chrdev(major,"mychrdev");

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

main.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/wait.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/epoll.h>
/* According to earlier standards */
#include <sys/time.h>
int fd1,fd2,fd3;
char buf[128] ={0};
int main(int argc, char const *argv[])
{
    fd1 = open("/dev/myled0", O_RDWR);
    if (fd1 < 0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while (1)
    {
        bzero(buf, sizeof(buf));
        printf("请输入0(关灯),1(开灯):"); 
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1]='\0';
        write(fd1,buf,sizeof(buf));
    }
    close(fd1);
 
    return 0;
}
相关推荐
cxr8282 天前
SPARC方法论在Claude Code基于规则驱动开发中的应用
人工智能·驱动开发·claude·智能体
sukalot3 天前
window显示驱动开发—显示适配器的子设备
驱动开发
Evan_ZGYF丶3 天前
【RK3576】【Android14】如何在Android14下单独编译kernel-6.1?
linux·驱动开发·android14·rk3576
sukalot4 天前
window显示驱动开发—视频呈现网络简介
驱动开发
sukalot5 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(二)
驱动开发
zwhSunday5 天前
Linux驱动开发(1)概念、环境与代码框架
linux·运维·驱动开发
sukalot5 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(三)
驱动开发
sukalot5 天前
window显示驱动开发—为头装载和专用监视器生成自定义合成器应用(一)
驱动开发
cxr8287 天前
基于Claude Code的 规范驱动开发(SDD)指南
人工智能·hive·驱动开发·敏捷流程·智能体
zwhSunday7 天前
Linux驱动开发(2)进一步理解驱动
linux·驱动开发