2023.08.01 驱动开发day8

这篇具有很好参考价值的文章主要介绍了2023.08.01 驱动开发day8。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

2023.08.01 驱动开发day8,驱动开发

驱动层

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#define LED_ON  _IO('l', 1)
#define LED_OFF _IO('l', 0)

struct class *cls;
struct device *dev;
struct device_node *dev_irq, *dev_led;
unsigned int major;
unsigned int irqno1, irqno2, irqno3;
struct gpio_desc *gpiono1, *gpiono2, *gpiono3;

//中断处理函数
irqreturn_t myirq_handler(int irq, void *dev)
{
    if(irq == irqno1) {
		gpiod_set_value(gpiono1, !gpiod_get_value(gpiono1));
	}
	else if(irq == irqno2) {
		gpiod_set_value(gpiono2, !gpiod_get_value(gpiono2));
	}
	else if(irq == irqno3) {
		gpiod_set_value(gpiono3, !gpiod_get_value(gpiono3));
	}
    return IRQ_HANDLED;
}

int mycdev_open(struct inode *inode, struct file *file)
{
    int a = inode->i_rdev;  //获取当前设备文件对应的设备号
    file->private_data = (void *)MINOR(a);  //将次设备号保存到当前文件的file结构中
    return 0;
}

long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned int a = (unsigned int)file->private_data;
    switch(a)
    {
        case 0:
            switch(cmd)
            {
                case LED_ON:
                    gpiod_set_value(gpiono1, 1);
                    break;
                case LED_OFF:
                    gpiod_set_value(gpiono1, 0);
                    break;
            }
            break;   
        case 1:
            switch(cmd)
            {
                case LED_ON:
                    gpiod_set_value(gpiono2, 1);
                    break;
                case LED_OFF:
                    gpiod_set_value(gpiono2, 0);
                    break;
            }
            break; 
        case 2:
            switch(cmd)
            {
                case LED_ON:
                    gpiod_set_value(gpiono3, 1);
                    break;
                case LED_OFF:
                    gpiod_set_value(gpiono3, 0);
                    break;
            }
            break;                          
    }
    return 0;
}

struct file_operations fops = {
    .open = mycdev_open,
    .unlocked_ioctl = mycdev_ioctl,
};

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, "myled");
    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");
	
	int ret;
    //解析设备树节点
    dev_irq = of_find_node_by_path("/myirq");
    if(dev_irq == NULL)
    {
        printk("解析irq设备树节点失败\n");
        return -EFAULT;
    }
	dev_led = of_find_node_by_path("/leds");
    if(dev_led == NULL)
	{
        printk("解析led设备树节点失败\n");
        return -EIO;
    }
    printk("解析设备树节点成功\n");

    // 申请gpio_desc对象并设置输出为低电平
    gpiono1 = gpiod_get_from_of_node(dev_led, "led1-gpios", 0, GPIOD_OUT_LOW, NULL);
    if(IS_ERR(gpiono1))
    {
        printk("申请gpio对象失败\n");
        return -PTR_ERR(gpiono1);
    }
	gpiono2 = gpiod_get_from_of_node(dev_led, "led2-gpios", 0, GPIOD_OUT_LOW, NULL);
    if(IS_ERR(gpiono1))
    {
        printk("申请gpio对象失败\n");
        return -PTR_ERR(gpiono1);
    }
	gpiono3 = gpiod_get_from_of_node(dev_led, "led3-gpios", 0, GPIOD_OUT_LOW, NULL);
    if(IS_ERR(gpiono1))
    {
        printk("申请gpio对象失败\n");
        return -PTR_ERR(gpiono1);
    }
    printk("申请gpio对象成功\n");

    //根据设备树节点解析出软中断号s
    irqno1 = irq_of_parse_and_map(dev_irq, 0); //按键1索引号为0
    if(!irqno1)
    {
        printk("解析软中断号失败\n");
        return -ENXIO;
    }
	irqno2 = irq_of_parse_and_map(dev_irq, 1);
    if(!irqno2)
    {
        printk("解析软中断号失败\n");
        return -ENXIO;
    }
	irqno3 = irq_of_parse_and_map(dev_irq, 2);
    if(!irqno3)
    {
        printk("解析软中断号失败\n");
        return -ENXIO;
    }
    printk("解析软中断号成功 irqno123=%d,%d,%d\n",irqno1,irqno2,irqno3);

    //注册中断
    ret = request_irq(irqno1, myirq_handler, IRQF_TRIGGER_FALLING, "key1", NULL);
    if(ret)
    {
        printk("注册中断失败\n");
        return ret;
    }
	ret = request_irq(irqno2, myirq_handler, IRQF_TRIGGER_FALLING, "key2", NULL);
    if(ret)
    {
        printk("注册中断失败\n");
        return ret;
    }
	ret = request_irq(irqno3, myirq_handler, IRQF_TRIGGER_FALLING, "key3", NULL);
    if(ret)
    {
        printk("注册中断失败\n");
        return ret;
    }
    printk("注册中断成功\n");
    return 0;
}

static void __exit mycdev_exit(void)
{
    //注销中断
    free_irq(irqno1, NULL);
	free_irq(irqno2, NULL);
	free_irq(irqno3, NULL);
	//灭灯
	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, "mycdev");
}

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

应用层 文章来源地址https://www.toymoban.com/news/detail-627722.html

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define LED_ON  _IO('l', 1)
#define LED_OFF _IO('l', 0)

int main(int argc,const char * argv[])
{
    int sel;
    int fd1 = open("/dev/myled0", O_RDWR);
    if(fd1 < 0)
    {
        perror("open");
        printf("%s : %s : %d\n", __FILE__, __func__, __LINE__);
        return -1;
    }
    int fd2 = open("/dev/myled1", O_RDWR);
    if(fd2 < 0)
    {
        perror("open");
        printf("%s : %s : %d\n", __FILE__, __func__, __LINE__);
        return -1;
    }
    int fd3 = open("/dev/myled2", O_RDWR);
    if(fd3 < 0)
    {
        perror("open");
        printf("%s : %s : %d\n", __FILE__, __func__, __LINE__);
        return -1;
    }

    while(1)
    {
        printf("1> LED1 ON\n");
        printf("2> LED1 OFF\n");
        printf("3> LED2 ON\n");
        printf("4> LED2 OFF\n");
        printf("5> LED3 ON\n");
        printf("6> LED3 OFF\n");
        printf("请选择功能>>>");
        scanf("%d", &sel);
        getchar();
        switch(sel)
        {
            case 1:
                ioctl(fd1, LED_ON); 
                break;
            case 2:
                ioctl(fd1, LED_OFF);
                break;
            case 3:
                ioctl(fd2, LED_ON); 
                break;
            case 4:
                ioctl(fd2, LED_OFF);
                break;
            case 5:
                ioctl(fd3, LED_ON); 
                break;
            case 6:
                ioctl(fd3, LED_OFF);
                break;
        }
    }
    close(fd1);
    close(fd2);
    close(fd3);
    return 0;
}

到了这里,关于2023.08.01 驱动开发day8的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 驱动day8

    驱动代码: 应用程序代码: 头文件: 实验结果:

    2024年02月08日
    浏览(36)
  • 数据结构day8(2023.7.25)

    排序:把无需序列转换为有序序列的一种算法。 内排:在计算机内存中实现的排序算法【多用适用于数据量较小的情况】 外排:在计算机内存以及外部介质实现的排序算法【先内存,在外部】 排序的分类: 交换排序:冒泡排序、快速排序 插入排序:直接插入排序,希尔排

    2024年02月15日
    浏览(38)
  • IO进程线程day8(2023.8.6)

    管道的原理: 有名管道的特点:  信号的原理: 练习1:pipe 功能:创建一个无名管道,同时打开无名管道的读写端 原型: 参数: 返回值: 小练:  练习2:mkfifo 功能:创建一根有名管道 原型: 参数: 返回值: 练习3:操作有名管道 功能:操作有名管道与用文件IO操作普通

    2024年02月14日
    浏览(36)
  • 前端学习记录~2023.7.16~CSS杂记 Day8

    由于有很多知识非常符合直觉或者和其他语言有通用性,因此个人觉得不需要全部记下来,本篇只记录一些个人觉得需要注意或单独记忆的知识点。 同时为了提高效率和减少对不重要内容的时间投入,会考虑更加精简。 相比上一篇总览,本篇更详细记录了正常布局流、弹性

    2024年02月17日
    浏览(35)
  • 2023.07.29 驱动开发DAY6

    通过epoll实现一个并发服务器 服务器 客户端 运行结果  

    2024年02月15日
    浏览(44)
  • C语言 DAY08 指针01

            地址编号: 地址编号: 就是计算机为了存储数据 , 每一个程序在 32 机中占 4G, 以一个字节为最小单位进行操作, 每一个字节都有其对应的地址 , 该地址就是地址编。         指针: 地址编号的数据类型         指针变量: 存储地址编号的变量 , 其数据类型为指针

    2024年02月05日
    浏览(29)
  • 2023-08-01 LeetCode每日一题(英雄的力量)

    点击跳转到题目位置 给你一个下标从 0 开始的整数数组 nums ,它表示英雄的能力值。如果我们选出一部分英雄,这组英雄的 力量 定义为: i 0 ,i 1 ,… i k 表示这组英雄在数组中的下标。那么这组英雄的力量为 max(nums[i0],nums[i1] … nums[ik])2 * min(nums[i0],nums[i1] … nums[ik]) 。 请你

    2024年02月14日
    浏览(60)
  • Wpf 使用 Prism 实战开发Day08

    1.效果图 MemoView.xaml 页面代码      1. 在  ItemsControl 中,添加滚动条  ScrollViewer  这样使用 ScrollViewer 把内容区域包裹起来,就能让内容区域支持滚动了        2 . 添加滚动条后的效果图如下:  使用md 中的一个自带动画 md:TransitioningContent 来实现该功能  需要设置一个属性,

    2024年02月03日
    浏览(38)
  • linux驱动开发 - 08_内核定时器

    链接: C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂 1.1 内核时间管理简介 Linux 内核中有大量的函数需要时间管理,比如周期性的调度程序、延时程序、对于驱动编写者来说最常用的定时器。 硬件定时器提供时钟源,时钟源的频率可以设置, 设置好以

    2024年02月02日
    浏览(33)
  • idea的datagrip报错[08S01] 驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。

    今天第一次使用idea中的datagrip就报了这个问题,有说要导入证书的有说要关闭验证的但都没什么作用。 [08S01] 驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid cer

    2024年02月08日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包