嵌入式:驱动开发 Day7

news2024/11/24 18:59:52

作业:基于GPIO子系统,编写LED的驱动程序和应用程序

驱动程序:myled.c

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

struct cdev *cdev;
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 *gpiono[3];

//封装操作方法
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(gpiono[0], 1);
            break;
        case LED_OFF: //关灯
            gpiod_set_value(gpiono[0], 0);
            break;
        }
        break;
    case 1: //控制LED2
        switch (cmd)
        {
        case LED_ON: //开灯
            gpiod_set_value(gpiono[1], 1);
            break;
        case LED_OFF: //关灯
            gpiod_set_value(gpiono[1], 0);
            break;
        }
        break;
    case 2: //控制LED3
        switch (cmd)
        {
        case LED_ON: //开灯
            gpiod_set_value(gpiono[2], 1);
            break;
        case LED_OFF: //关灯
            gpiod_set_value(gpiono[2], 0);
            break;
        }
        break;
    }
    return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{

    return 0;
}

ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{

    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,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};

static int __init mycdev_init(void)
{
    //解析LED的设备树节点
    dnode = of_find_node_by_path("/myled");
    if (dnode == NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }

    //申请gpio对象
    int j;
    char nodename[20];
    for (j = 0; j < 3; j++)
    {
        sprintf(nodename, "led%d-gpio", j + 1);
        gpiono[j] = gpiod_get_from_of_node(dnode, nodename, 0, GPIOD_OUT_LOW, NULL);
        if (IS_ERR(gpiono[j]))
        {
            printk("申请gpiono%d失败\n", j);
            goto out0;
        }
    }

    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, minor, 3, "myled");
        if (ret)
        {
            printk("动态申请设备号失败\n");
            goto out2;
        }
        major = MAJOR(devno); //获取主设备号
        minor = MINOR(devno); //获取次设备号
    }
    printk("申请设备号成功 major= %d\n", major);

    //4.注册字符设备驱动对象
    ret = cdev_add(cdev, MKDEV(major, minor), 3);
    if (ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto out3;
    }
    printk("注册字符设备驱动对象成功\n");

    //向上提交目录信息
    cls = class_create(THIS_MODULE, "myled");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret = -PTR_ERR(cls);
        goto out4;
    }
    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");
            ret = -PTR_ERR(dev);
            goto out5;
        }
    }
    printk("向上提交设备信息成功\n");
    return 0;

out5:
    //释放前一次提交成功的设备信息
    for (--i; i >= 0; 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;
out0:
    //释放前一次申请成功gpiono编号
    for (--j; j >= 0; j--)
    {
        gpiod_put(gpiono[j]);
    }
    return -1;
}

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);
    //释放设备驱动对象空间
    kfree(cdev);
    //释放gpiono编号
    for (i = 0; i < 3; i++)
    {
        gpiod_put(gpiono[i]);
    }
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

应用程序: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 "head.h"

int main()
{
	int a, b;
	char buf[128] = "";
	int fd1, fd2, fd3;
	while (1)
	{
		printf("请输入要控制的灯:0(LED1) 1(LED2) 2(LED3) >");
		scanf("%d", &a);
		switch (a)
		{
		case 0:
			fd1 = open("/dev/myled0", O_RDWR);
			if (fd1 < 0)
			{
				printf("设备文件打开失败\n");
				exit(-1);
			}
			printf("请输入对LED的控制命令:0(关灯) 1(开灯)  >");
			scanf("%d", &b);
			switch (b)
			{
			case 0:
				ioctl(fd1, LED_OFF); //关灯
				close(fd1);
				break;
			case 1:
				ioctl(fd1, LED_ON); //开灯
				close(fd1);
				break;
			}
			break;

		case 1:
			fd2 = open("/dev/myled1", O_RDWR);
			if (fd2 < 0)
			{
				printf("设备文件打开失败\n");
				exit(-1);
			}
			printf("请输入对LED的控制命令:0(关灯) 1(开灯)  >");
			scanf("%d", &b);
			switch (b)
			{
			case 0:
				ioctl(fd2, LED_OFF); //关灯
				close(fd2);
				break;
			case 1:
				ioctl(fd2, LED_ON); //开灯
				close(fd2);
				break;
			}
			break;

		case 2:
			fd3 = open("/dev/myled2", O_RDWR);
			if (fd3 < 0)
			{
				printf("设备文件打开失败\n");
				exit(-1);
			}
			printf("请输入对LED的控制命令:0(关灯) 1(开灯)  >");
			scanf("%d", &b);
			switch (b)
			{
			case 0:
				ioctl(fd3, LED_OFF); //关灯
				close(fd3);
				break;
			case 1:
				ioctl(fd3, LED_ON); //开灯
				close(fd3);
				break;
			}
			break;
		}
	}

	close(fd1);
	close(fd2);
	close(fd3);

	return 0;
}

头文件:head.h

#ifndef __HEAD_H__
#define __HEAD_H__

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

#endif

现象:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1021729.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python入门-pack和unpack的用法

struct.calcsize(format) 返回与格式字符串format相对应的结构体的大小&#xff08;以及由 生成的字节对象的大小 &#xff09; 使用大端顺序打包和解包三种不同大小的整数&#xff1a; from struct import *pack(">bhl", 1, 2, 3)unpack(>bhl, b\x01\x00\x…

聚焦企业开放OpenAPI痛难点,华为云API Explorer助力伙伴构建API门户

当前&#xff0c;IT研发的主流架构已从单体架构向微服务架构转型&#xff0c;带动了产品迭代速度和项目交付速度不断加快&#xff0c;随着整个IT产业规模的不断扩大&#xff0c;API数量也随之呈爆发式增长。据不完全统计&#xff0c;目前业界有70%到90%的业务是通过开源代码和第…

数据可视化 -- ECharts 入门

文章目录 引言1. ECharts的基本使用1.1 ECharts的快速上手1.2 相关配置讲解 2. ECharts常用图表2.1 图表1 柱状图2.1.1 柱状图的实现步骤2.1.2 柱状图的常见效果2.1.3 柱状图特点2.1.4 通用配置 2.2 图表2 折线图2.2.1 折线图的实现步骤2.2.2 折线图的常见效果2.2.3 折线图的特…

Java的Socket通信的断网重连的正确写法

Java的Socket通信的断网重连的正确写法 Socket通信的断网重连介绍客户端与服务端源码演示截图本地演示服务器演示演示截图 总结 Socket通信的断网重连介绍 针对于已经建立通信的客户端与服务器&#xff0c;当客户端与服务器因为网络问题导致网络不通而断开连接了或者由于服务器…

ET数据无效值处理(仅代表个人观点)

1将无效值去除查看&#xff0c;查看有效值 有效值范围为1830~9472 2.计算有效范围最大值最小值 如果计算四分数据得将栅格属性表导出execl进行计算 2根据该片文章进行替换 如何处理MODIS蒸散数据(ET)中的填充值&#xff08;仅作参考&#xff09;_Z_W_H_的博客-CSDN博客

大数据学习1.1-Centos8虚拟机安装

1.创建新的虚拟机 2.选择稍后安装OS 3.选择Linux的CentOS8 4.选择安装路径 5.分配20g存储空间 6.自定义硬件 7.分配2g内存 8.分配2核处理器 9.选择镜像位置 10.开启虚拟机安装 推荐密码设置为root

TS开发环境搭建

一、安装Node.js 官网&#xff1a;Node.js (nodejs.org) 可以去看别的大佬安装Node.js的文章&#xff0c;因为大部分人都安装了Node环境&#xff0c;这里我就不做说明 二、使用npm全局安装typescript 在终端中输入如下命令&#xff1a; npm i -g typescript 安装完成会有如…

程序开发:在线报名线下活动小程序源码功能解析

针对线下活动在线报名场景的小程序&#xff0c;支持在线支付费用以及线下核销。 可以应多大多数的线下报名&#xff0c;线上报名客服表单可以定制订单&#xff0c;支持导出报名&#xff0c;支持审核&#xff0c;支持分享&#xff0c;支持分销拓客以及线下核销。 WEB小程序双端…

2023年日经225指数研究报告

第一章 指数概况 1.1 概述 日经225指数&#xff0c;又被称为日经平均股票价格或日经225平均指数&#xff0c;通常被称为日经或日经指数&#xff0c;是东京证券交易所的一个重要股价指数。该指数自1950年起由日本经济新闻&#xff08;The Nikkei&#xff09;日报计算&#xff…

Chrome浏览器崩溃“STATUS_INVALID_IMAGE_HASH”的解决方法

原文地址&#xff1a;Chrome浏览器崩溃"STATUS_INVALID_IMAGE_HASH"的解决方法 | JUNES BLOG | 六月博客 今天无意间&#xff0c;发现Chrome浏览器多了个“ 由贵单位管理 ”的提示&#xff0c;出于安全的考虑&#xff0c;想立马把它搞掉&#xff0c;百度了一堆方法&a…

【编程实践】在VS studio中配置Eigen库

1 介绍 Eigen库是C标准模板库&#xff0c;能够进行向量运算、矩阵运算、矢量运算、数值分析等操作&#xff0c;并且包含相应的运算算法。 Eigen官方地址: 地址 可在官网下载指定版本的压缩包&#xff0c;将压缩包解压至后面配置的“附件包含目录”中。 2 配置 2.1 VS studi…

基于SSM的校园车辆管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

如何借助上线初期运维管理守住项目建设最后一公里

随着运营商技术升级、业务发展&#xff0c;以及服务能力要求提升&#xff0c;当下新建项目的交付或系统大版本升级大多数都需要历经千辛万苦才达到上线的彼岸。然而&#xff0c;项目上线并不意味着项目结束&#xff0c;“上线”也并不意味着终点&#xff0c;而是一个新的管理模…

Linux服务器初始化、yum安装java、redis、mysql

目录 前言 一、yum安装java二、yum安装redis三、yum安装mysql 前言 本文使用yum命令安装部署可能会用到的相关应用 安装软件包之前&#xff0c;我们需要先更新系统&#xff0c;以确保安装的软件包是最新的版本。执行以下命令&#xff1a; sudo yum update一、yum安装java 1、…

【阿里国际笔试】编程13

1.小红拿到了一个01串&#xff0c;她有以下两种操作: 1.选择一个字符取反&#xff0c;代价为x。 2.选择两个相邻的字符同时取反&#xff0c;代价为y。 小红想知道&#xff0c;自己将字符串变成全0”的最小代价是多少? 字符取反&#xff0c;指的是1变成0’"0变成1 样例 3 …

更新GitLab上的项目

更新GitLab上的项目 如有需要&#xff0c;请参考这篇&#xff1a;上传项目到gitlab上 1.打开终端&#xff0c;进入到本地项目的根目录。 2.如果你还没有将远程GitLab仓库添加到本地项目&#xff0c;你可以使用以下命令&#xff1a; 比如&#xff1a; git remote add origin …

响应式网页设计(Responsive Web Design)的核心原理

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 响应式网页设计的核心原理⭐ 优点和缺点优点缺点 ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚…

JUC第三讲:Java 并发-线程基础

JUC第三讲&#xff1a;Java 并发-线程基础 本文是JUC第三讲&#xff0c;主要概要性的介绍线程的基础&#xff0c;为后面的章节深入介绍Java并发的知识提供基础。 文章目录 JUC第三讲&#xff1a;Java 并发-线程基础1、带着BAT大厂的面试问题去理解2、线程状态转换2.1、新建(New…

Unity 开发人员转CGE(castle Game engine)城堡游戏引擎指导手册

Unity 开发人员的城堡游戏引擎概述 一、简介2. Unity相当于什么GameObject&#xff1f;3. 如何设计一个由多种资产、生物等组成的关卡&#xff1f;4. 在哪里放置特定角色的代码&#xff08;例如生物、物品&#xff09;&#xff1f;Unity 中“向 GameObject 添加 MonoBehaviour”…

权限提升数据库(基于MySQL的UDF,MOF,启动项提权)

获取数据库权限 如何获取数据库的最高权限用户的密码&#xff0c;常用方法有这些 网站存在高权限SQL注入点 数据库的存储文件或备份文件 网站应用源码中的数据库配置文件 采用工具或脚本爆破 网站存在高权限SQL注入点 可以通过sqlmap拿到user表的账号密码&#xff0c;密码可能…