驱动开发 作业 day7 9/18

2023-11-13

基于GPIO子系统实现led灯点亮

head.h

#ifndef __HEAD_H__
#define __HEAD_H__ 

//构建LED开关的功能码,不添加ioctl第三个参数
#define LED_ON _IO('l',1)
#define LED_OFF _IO('l',0)

#endif 

test.c

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


int main(int argc, char const *argv[])
{
    int a;
    char buf[128] = {0};
    int fd = open("/dev/myled1", O_RDWR);
    if (fd < 0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while (1)
    {
        // 从终端读取
        printf("请输入对LED灯的控制:1(开灯)0(关灯)>");
        scanf("%d", &a);
        switch (a)
        {
        case 1:
            ioctl(fd, LED_ON); // 开灯
            break;
        case 0:
            ioctl(fd, LED_OFF); // 关灯
        }
    }

    close(fd);

    return 0;
}

mychrdev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include "head.h"

struct cdev *cdev;
char kbuf[128] = {0};
unsigned int major = 0;
unsigned int minor = 0;
dev_t devno;
module_param(major, uint, 0664); // 方便在命令行传递major的值
struct class *cls;
struct device *dev;
struct device_node *dnode;
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;

// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    int min = MINOR(inode->i_rdev); // 根据打开的文件对应的设备号获取次设备号
    file->private_data = (void *)min;
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{

    int min = (int)file->private_data;
    switch (min)
    {
    case 0: // 控制LED1
        switch (cmd)
        {
        case LED_ON:
            // 开灯
            gpiod_set_value(gpiono1, 1);
            break;
        case LED_OFF:
            // 关灯
            gpiod_set_value(gpiono1, 0);
            break;
        }
        break;
    case 1: // 控制LED2
        switch (cmd)
        {
        case LED_ON:
            // 开灯
            gpiod_set_value(gpiono2, 1);
            break;
        case LED_OFF:
            // 关灯
            gpiod_set_value(gpiono2, 0);
            break;
        }
        break;
    case 2: // 控制LED3
        switch (cmd)
        {
        case LED_ON:
            // 开灯
            gpiod_set_value(gpiono3, 1);
            break;
        case LED_OFF:
            // 关灯
            gpiod_set_value(gpiono3, 0);
            break;
        }
        break;
    }
    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,
    .unlocked_ioctl = mycdev_ioctl,
    .release = mycdev_close,
};

static int __init mycdev_init(void)
{
    int ret;
    // 字符设备注册
    // 1.申请驱动对象
    cdev = cdev_alloc();
    if (cdev == NULL)
    {
        printk("申请对象空间失败!\n");
        ret = -EFAULT;
        goto out1;
    }
    printk("申请对象成功!\n");
    // 2.初始化驱动对象
    cdev_init(cdev, &fops);
    printk("初始化对象成功!\n");

    // 3.申请主设备号和一定数量设备资源
    if (major > 0) // 静态指定设备号
    {
        ret = register_chrdev_region(MKDEV(major, minor), 3, "myled");
        if (ret)
        {
            printk("静态申请设备号失败!\n");
            goto out2;
        }
    }
    else if (major == 0) // 动态申请设备号
    {
        ret = alloc_chrdev_region(&devno, 0, 3, "myled");
        if (ret)
        {
            printk("动态申请设备号失败!\n");
            goto out2;
        }
        major = MAJOR(devno); // 获取主设备号
        minor = MINOR(devno); // 获取此设备号
    }
    printk("申请设备号成功!\n");

    // 4.根据申请的设备号和驱动对象注册驱动
    ret = cdev_add(cdev, MKDEV(major, minor), 3);
    if (ret)
    {
        printk("驱动注册失败!\n");
        goto out3;
    }
    printk("注册驱动成功!\n");

    // 5.向上提交目录信息
    cls = class_create(THIS_MODULE, "myled");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败!\n");
        ret = -PTR_ERR(cls);
        goto out4;
    }
    printk("向上提交目录成功!\n");

    // 6.向上提交设备信息文件
    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");
            ret = -PTR_ERR(dev);
            goto out5;
        }
    }
    printk("向上提交设备信息文件成功!\n");

    // 从内核获取设备节点
    dnode = of_find_node_by_path("/myled");
    if (dnode == NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析GPIO信息成功\n");

    // 对设备进行相关章节初始化  GPIO章节
    // 根据设备节点解析出gpio对象,并向内核申请
    gpiono1 = gpiod_get_from_of_node(dnode, "led-gpios", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono1))
    {
        printk("申请gpio失败\n");
    }
    printk("申请成功\n");

    gpiono2 = gpiod_get_from_of_node(dnode, "led-gpios", 1, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono2))
    {
        printk("申请gpio失败\n");
    }
    printk("申请成功\n");

    gpiono3 = gpiod_get_from_of_node(dnode, "led-gpios", 2, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono3))
    {
        printk("申请gpio失败\n");
    }
    printk("申请成功\n");

    /*
        // 获取GPIO信息
        gpiono1 = of_get_named_gpio(dnode, "led-gpios", 0);
        if (gpiono1 < 0)
        {
            printk("获取引脚编号1失败\n");
        }
        printk("获取引脚编号1成功\n");

        gpiono2 = of_get_named_gpio(dnode, "led-gpios", 1);
        if (gpiono2 < 0)
        {
            printk("获取引脚编号2失败\n");
        }
        printk("获取引脚编号2成功\n");

        gpiono3 = of_get_named_gpio(dnode, "led-gpios", 2);
        if (gpiono3 < 0)
        {
            printk("获取引脚编号3失败\n");
        }
        printk("获取引脚编号3成功\n");

        // 申请gpio编号
        ret = gpio_request(gpiono1, NULL);
        if (ret)
        {
            printk("申请gpio编号失败\n");
            return -1;
        }
        printk("申请gpio编号成功\n");

        ret = gpio_request(gpiono2, NULL);
        if (ret)
        {
            printk("申请gpio编号失败\n");
            return -1;
        }
        printk("申请gpio编号成功\n");

        ret = gpio_request(gpiono3, NULL);
        if (ret)
        {
            printk("申请gpio编号失败\n");
            return -1;
        }
        printk("申请gpio编号成功\n");
        // 设置为输出
        gpio_direction_output(gpiono1, 0);
        gpio_direction_output(gpiono2, 0);
        gpio_direction_output(gpiono3, 0);
    */
    return 0;
out5:
    for (--i; i > -1; i--)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);
out4:
    cdev_del(cdev);
out3:
    unregister_chrdev_region(MKDEV(major, minor), 3);
out2:
    kfree(cdev);
out1:
    return ret;
}
static void __exit mycdev_exit(void)
{
    // 销毁设备信息文件
    int i;
    for (i = 0; i < 3; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    // 销毁设备类目录
    class_destroy(cls);
    // 注销驱动
    cdev_del(cdev);
    // 注销设备号
    unregister_chrdev_region(MKDEV(major, minor), 3);
    // 释放cdev对象
    kfree(cdev);

    // 熄灭led灯
    gpiod_set_value(gpiono1, 0);
    gpiod_set_value(gpiono2, 0);
    gpiod_set_value(gpiono2, 0);
    // 释放gpio对象
    gpiod_put(gpiono1);
    gpiod_put(gpiono2);
    gpiod_put(gpiono3);
}

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

驱动开发 作业 day7 9/18 的相关文章

  • Linux·i2c驱动示例

    I2C 是很常用的一个串行通信接口 常用于连接各种外设 传感器等器件 一 Linux I2C 驱动框架 Linux 内核将 I2C 驱动分为两部分 I2C 总线驱动 I2C 总线驱动就是 SOC 的 I2C 控制器驱动 也叫做 I2C 适配
  • DDK(Driver Developer Kit)和WDK(Windows Driver Kit)的区别

    首先 先从基础的东西说起 开发WINDOWS下的驱动程序 需要一个专门的开发包 如 开发JAVA程序 我们可能需要一个JDK 开发WINDOWS应用程序 我们需要WINDOWS的SDK 现在开发WINDOWS下的驱动程序 我们需要一个DDK
  • 第七篇 硬件内存资源的获取,解析

    硬件资源的获取 解析 1 生成WDF的KMDFhelloWorld程序 2 改写INF文件中硬件ID 3 编译安装 以上三点不重复介绍 下面直接关注更新 增加的代码 在DeviceADD例程中添加 首先是增加即插即用管理 应该对应于WDM的
  • 嵌入式内核及驱动开发中级(上)

    目录 第一部分 一 设备分类 设备申请和注销 一 Linux内核对设备的分类 二 设备号 内核中同类设备的区分 三 申请和注销设备号 二 Code exerccise 三 知识补充 第二部分 一 函数指针复习 一 函数指针复习 1 1 内存
  • 嵌入式Linux驱动开发(LCD屏幕专题)(四)

    单Buffer的缺点与改进方法 1 单Buffer的缺点 如果APP速度很慢 可以看到它在LCD上缓慢绘制图案 即使APP速度很高 LCD控制器不断从Framebuffer中读取数据来显示 而APP不断把数据写入Framebuffer 假设
  • 字符设备驱动详解(主次设备号、注册/卸载字符设备驱动、创建设备节点、地址映射)

    1 主次设备号 1 主次设备号是内核用来索引设备的 每个主次设备号在内核中都是唯一的 每个注册的设备都有一个分配的主次设备号 2 同一个主设备号可以有多个从设备号 主设备是对应的驱动程序 次设备号对应设备文件所指的设备 一个Soc可能接同样
  • 嵌入式linux驱动之路19:U-Boot 移植(2)

    uboot 的最终目的就是启动 Linux 内核 所以需要通过启动 Linux 内核来判断 uboot 移植是否成功 在启动 Linux 内核之前我们先来学习两个重要的环境变量 bootcmd 和 bootargs bootcmd 环境变量
  • Linux 设备树的加载与匹配

    之前学习了platform设备与总线是如何匹配的 但是在读某一驱动程序中 该设备由dts文件描述 设备的匹配与platform设有所不同 因此记录下来 1 什么是设备树 在内核源码中存在大量对板级细节信息描述的代码 但是对于内核而言 这些代
  • Linux驱动:应用程序open如何调用到驱动程序的open函数

    字符设备文件的打开流程 相关结构体 流程涉及相关结构体如下 struct inode dev t i rdev const struct file operations i fop former gt i op gt default fil
  • 驱动开发 作业 day7 9/18

    基于GPIO子系统实现led灯点亮 head h ifndef HEAD H define HEAD H 构建LED开关的功能码 不添加ioctl第三个参数 define LED ON IO l 1 define LED OFF IO l
  • Linux驱动_多点电容触摸

    一丶Linux下多点电容触摸驱动框架 电容触摸屏IC是FT5426 为IIC协议芯片 因此需要编写IIC驱动 触摸IC会发出中断信号 并在中断服务函数中上报信息 因此需要编写中断框架 触摸屏向Linux内核上报的信息都属于Input子系统
  • Robot Framework 自动化测试详解

    一 Robot Framework 简介 1 界面自动化测试工具 界面自动化测试 即UI自动化测试 比较常见的工具有 QTP AutoIt Selenium等 像QTP经历了很多版本 最新的版本好像叫UFT了 对初学者来说 录制回放是相当容
  • ARM(IMX6U)裸机模仿STM32驱动开发实验(定义外设结构体)

    参考 Linux之ARM IMX6U 裸机模仿STM32驱动开发格式 作者 一只青木呀 发布时间 2020 08 15 12 11 56 网址 https blog csdn net weixin 45309916 article deta
  • 正点原子STM32 H743完成RT Thread下的LAN8720 网卡驱动 LWIP跑起来

    目前RT官网对H743的支持力度还不理想 本想按照F407的搞定网卡的套路来搞定H743的网卡 因为phy也是LAN 8720 以为会很轻松 没想到却是一条遍布荆棘的路 好在已经有不少大佬做了不少工作 终于在巨人肩膀人完成了网卡的驱动 能p
  • Linux MISC 驱动实验

    我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动 MISC 驱动其实就是最简单的字符设备驱动 通常嵌套在 platform 总线驱动中 实现复杂的驱动 一 MISC 设备驱动简介 所有的 MISC 设备驱动的主设备号都为 1
  • 自举电路原理

    文章目录 一 自举电路核心原理 二 为什么要自举升压 三 简单的自举电路模型 四 自举电路在高电压栅极驱动电路中的应用 1 MOS管Q开通时 2 MOS管Q关断时 一 自举电路核心原理 电容两端电压不能突变 根据电容公式 i t C du
  • RK3568 CAN驱动更新说明

    RK3568 CAN问题 同时收发数据一段时间 几秒钟 can出现错误收发功能异常 必须重新down up恢复正常 内核更新rockchip canfd c iopoll h 配置Networking support gt CAN bus
  • 32位/64位WINDOWS驱动之-突破进程保护映射的方法进行跨进程读内存2

    32位 64位WINDOWS驱动之 突破进程保护映射的方法进行跨进程读内存2 一 在过保护读写筛选器中添加 读写驱动2 c 驱动层 代码如下 include
  • LCD背光调节实验

    目录 LCD 背光调节简介 硬件原理分析 实验程序编写 编译下载验证 编写Makefile 和链接脚本 编译下载 不管是使用显示器还是手机 其屏幕背光都是可以调节的 通过调节背光就可以控制屏幕的亮度 在户外阳光强烈的时候可以通过调高背光来看
  • linux应用程序直接return与exit的区别

    在Linux应用程序中 可以使用 return 语句直接从 main 函数返回 这将导致程序终止并返回给操作系统 然而 有时候使用 exit 函数比直接使用 return 语句更有优势 以下是一些原因 清理资源 exit 函数可以确保在程序

随机推荐

  • ICCV 2023

    导读 TL DR 本文提出了FeatEnHancer 一种用于低光照视觉任务的增强型多尺度层次特征的新方法 提议的解决方案重点增强相关特征 通过提供强大的语义表示 使其优于现有的低光照图像增强方法 该方法不仅改进了单个特征的质量 而且还有效
  • ctfshow 文件包含

    目录 web78 web79 web80 81 web82 web83 web78 简单的伪协议文件包含 payload php filter convert base64 encode resource flag php web79 pa
  • npm install安装sharp包失败

    初次使用Lincm 使用后端koa框架初始化环境报错 npm config set sharp binary host https npm taobao org mirrors sharp npm config set sharp libv
  • Groovy与Java的不同点

    本文参考自Groovy文档 Differences with Java 所有代码都是Groovy文档中的 也可以将本文看做英文源文档的简略翻译 Groovy设计时目标之一就是让Java程序员快速习惯Groovy 不过在Groovy中也有很多
  • C#数据库MS SQL打开关闭演示

    书上记的比喻 有助于记忆 ADO NET类 CONNECTION对象好比伸入水中的水龙头 保持与水的接触 只有它与水进行了连接 其它对象才可以抽到水 COMMAND对象则像抽水机 为抽水提供动力和执行方法 先通过水龙头 然后把水返回给上面的
  • linux下rename函数用法,Linux学习之关于rename的用法

    linux下的rename是有两个版本的 一个是C语言版本 一个是Perl语言版本 如何判断当前是哪个版本 输入man rename 看到第一行是 RENAME 1 Linux Programmer s Manual RENAME 1 这个
  • 架构简洁之道:从阿里开源应用架构COLA说起

    导读 COLA 的主要目的是为应用架构提供一套简单的可以复制 可以理解 可以落地 可以控制复杂性的 指导和约束 在实践中作者发现 COLA 在简洁性上仍有不足 因此给 COLA 做了一次 升级 在这次升级中 没有增加任何新的功能 而是尽量多
  • 通过user-agent判断用户是用QQ、微信还是支付宝打开链接或二维码

    通过user agent判断用户是用QQ 微信还是支付宝打开链接或二维码 function is weixn qq var ua navigator userAgent toLowerCase if ua match MicroMessen
  • 表格嵌套表格css_HTML5和CSS3的登录和注册表格

    表格嵌套表格css View demo 查看演示 Download Source 下载源 In this tutorial we are going to create two HTML5 forms that will switch be
  • 快速理解Faster RCNN

    Faster RCNN 1 网络结构 2 锚框生成 3 RPN结构 4 Roi pooling 5 分类和回归任务 6 损失函数 7 训练流程 1 网络结构 首先输入图像 进行尺度裁剪成固定的M N 如果比例不匹配可以先填充再裁剪 back
  • 云计算入门——IT架构九重天

    文章目录 一 概述 二 各层简述 2 1 基础层 2 2 计算机网络 2 3 存储层 2 4 服务器层 2 5 操作系统层 2 6 数据库层 2 7 中间件 运行库 2 8 应用软件 2 9 数据层 一 概述 一个公司搭建IT应用一般都会涉
  • [ElasticSearch]间隔搜索IntervalsQuery及JavaSDK简单调用

    1 概念 intervals query 允许用户精确控制查询词在文档中出现的先后关系 实现了对terms顺序 terms之间的距离以及它们之间的包含关系的灵活控制 通过intervals query 间隔搜索 我们可以完成各个terms在
  • MYSQL导出数据出现The MySQL server is running with the --secure-file-priv option

    今天尝试使用 into outfile导出数据的时候出现错误 The MySQL server is running with the secure file priv option so it cannot execute this st
  • 服务器r730系统备份软件,r730服务器

    r730服务器 内容精选 换一换 创建外表语法 CREATE FOREIGN TABLE SQL on Hadoop or OBS 中 需指定一个与MRS数据源连接相关联的外部服务器 当您通过GaussDB DWS 管理控制台创建MRS数据
  • 区块链为每一笔交易盖上时间戳

    黄老邪在传授记账方法时 要求居民将发生在桃花岛上的每一笔交易都记录下来 并且要求他们将交易发生的时间也一并记录在账本上 这就相当于区块链为每一笔交易在发生时盖上了时间戳 在区块链中 时间戳的应用是对每一次交易记录的认证 它就像交易合同公证一
  • 判断map集合是否为空和是否为null

  • 稀疏矩阵转置(C语言)

    最近有数据结构实验课了 还得学一学数据结构喽 以后就把学习经过贴上来了 稀疏矩阵 当一个数组中大部分元素为 或者为同一个值的数组时 可以使用稀疏数组来保存该数组 稀疏数组的处理方法 1 记录数组一共有几行几列 有多少个不同的值 假设有sum
  • linux 切换不了csh,BASH & CSH linux  重定向(ZZ)

    bash 应该允许输入来自以下两种方式 在命令行上指定的文件名 例如 command input file 在这个例子中 command 应该读取文件 input file 标准输入 stdin 缺省情况下为终端 也就是用户的键盘 例如 c
  • TX2支持reboot办法

    手头有台TX2 想要远程控制reboot 在nvidia账号下直接敲命令 nvidia tegra ubuntu sudo reboot h sudo password for nvidia nvidia is not in the sud
  • 驱动开发 作业 day7 9/18

    基于GPIO子系统实现led灯点亮 head h ifndef HEAD H define HEAD H 构建LED开关的功能码 不添加ioctl第三个参数 define LED ON IO l 1 define LED OFF IO l