驱动开发 作业2

news2024/9/22 1:42:31

使用 ioctl 替换 write/read 控制 LED、蜂鸣器、马达、风扇,并使用 udev 来自动创建设备文件

  1. 完整代码目录,请看这个仓库
  2. 依然使用之前 ARM 课程中的 common 中的结构体
  3. 代码都差不多,就贴个 led.c ,用户空间测试代码 test.c 和头文件 head.h
  4. 不同设备 devcls 以及 major 命名要不同
  5. FSMP1A 扩展板引脚:
    • LED1,LED2,LED3:PE10PF10PE8
    • 蜂鸣器:PB6
    • 马达:PF6
    • 风扇:PE9
#include "linux/leds.h"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "head.h"

struct class *cls;
struct device *dev;

int major; // 用于保存主设备号
char kbuf[128] = { 0 };

unsigned int *vir_gpioe;
unsigned int *vir_gpiof;
unsigned int *vir_rcc;

// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
	printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
	return 0;
}

long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	switch (cmd) {
	case LED_ON:
		switch (arg) {
		case 1: // LED1
			((gpio_t *)vir_gpioe)->ODR |= (0x1 << 10);
			break;
		case 2: // LED2
			((gpio_t *)vir_gpiof)->ODR |= (0x1 << 10);
			break;
		case 3: // LED3
			((gpio_t *)vir_gpioe)->ODR |= (0x1 << 8);
			break;
		}
		break;
	case LED_OFF:
		switch (arg) {
		case 1: // LED1
			((gpio_t *)vir_gpioe)->ODR &= (~(0x1 << 10));
			break;
		case 2: // LED2
			((gpio_t *)vir_gpiof)->ODR &= (~(0x1 << 10));
			break;
		case 3: // LED3
			((gpio_t *)vir_gpioe)->ODR &= (~(0x1 << 8));
			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,
};

int all_led_init(void)
{
	// 地址映射
	vir_gpioe = ioremap((unsigned int)GPIOE, sizeof(gpio_t));
	if (vir_gpioe == NULL) {
		printk("GPIOE结构体映射表失败\n");
		return -EFAULT;
	}
	vir_gpiof = ioremap((unsigned int)GPIOF, sizeof(gpio_t));
	if (vir_gpioe == NULL) {
		printk("GPIOF结构体映射表失败\n");
		return -EFAULT;
	}
	vir_rcc = ioremap((unsigned int)RCC, sizeof(rcc_t));
	if (vir_rcc == NULL) {
		printk("RCC结构体映射表失败\n");
		return -EFAULT;
	}
	printk("寄存器地址映射成功\n");
	// 寄存器初始化
	((rcc_t *)vir_rcc)->MP_AHB4ENSETR |= (1 << 4) | (1 << 5);
	// LED1 初始化
	((gpio_t *)vir_gpioe)->MODER &= (~(0x3 << 20));
	((gpio_t *)vir_gpioe)->MODER |= (0x1 << 20);
	((gpio_t *)vir_gpioe)->ODR &= (~(0x1 << 10));
	// LED2 初始化
	((gpio_t *)vir_gpiof)->MODER &= (~(0x3 << 20));
	((gpio_t *)vir_gpiof)->MODER |= (0x1 << 20);
	((gpio_t *)vir_gpiof)->ODR &= (~(0x1 << 10));
	// LED3 初始化
	((gpio_t *)vir_gpioe)->MODER &= (~(0x3 << 16));
	((gpio_t *)vir_gpioe)->MODER |= (0x1 << 16);
	((gpio_t *)vir_gpioe)->ODR &= (~(0x1 << 8));
	return 0;
}

static int __init mycdev_init(void)
{
	int i;
	//字符设备驱动注册
	major = register_chrdev(0, "myleddev", &fops);
	if (major < 0) {
		printk("字符设备驱动注册失败\n");
		return major;
	}
	printk("字符设备驱动注册成功major=%d\n", major);
	// 向上提交目录
	cls = class_create(THIS_MODULE, "myledcls");
	if (IS_ERR(cls)) {
		printk("创建类失败\n");
		return -EFAULT;
	}
	// 向上提交设备节点信息
	for (i = 0; i < 3; i++) {
		dev = device_create(cls, NULL, MKDEV(major, i), NULL, "led%d",
				    i);
		if (IS_ERR(dev)) {
			printk("创建设备节点失败\n");
			return -EFAULT;
		}
	}
	//映射物理寄存器
	all_led_init();
	return 0;
}

static void __exit mycdev_exit(void)
{
  int i;
	//取消寄存器地址映射
	iounmap(vir_gpioe);
	iounmap(vir_gpiof);
	iounmap(vir_rcc);
  for(i = 0; i < 3; i++) {
    device_destroy(cls, MKDEV(major, i));
  }
  class_destroy(cls);
	//字符设备驱动的注销
	unregister_chrdev(major, "myleddev");
}

module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
#include <stdio.h>
#include <stdlib.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, b;
	char buf[128] = { 0 };
	int led_fd = open("/dev/led0", O_RDWR);
	if (led_fd < 0) {
		printf("打开设备文件失败\n");
		exit(-1);
	}
	int fan_fd = open("/dev/fan", O_RDWR);
  if (fan_fd < 0) {
    printf("打开设备文件失败\n");
    exit(-1);
  }
	int bee_fd = open("/dev/bee", O_RDWR);
  if (bee_fd < 0) {
    printf("打开设备文件失败\n");
    exit(-1);
  }
	int motor_fd = open("/dev/motor", O_RDWR);
  if (motor_fd < 0) {
    printf("打开设备文件失败\n");
    exit(-1);
  }
	while (1) {
		//从终端读取
		printf("请选择要控制的设备\n");
		printf("0(灯) 1(风扇) 2(蜂鸣器) 3(马达) >");

		scanf("%d", &a);
		if (a == 0) {
			printf("请输入要实现的功能\n");
			printf("0(关灯) 1(开灯) >");
			scanf("%d", &a);

			printf("请输入要控制的灯\n");
			printf("1(LED1) 2(LED2) 3(LED3)>");
			scanf("%d", &b);
			if (a == 1) {
				ioctl(led_fd, LED_ON, b);
			} else if (a == 0) {
				ioctl(led_fd, LED_OFF, b);
			}
		} else if (a == 1) {
			printf("请输入要实现的功能\n");
			printf("0(关风扇) 1(开风扇) >");
			scanf("%d", &a);
			if (a == 1) {
				ioctl(fan_fd, FAN_ON);
			} else if (a == 0) {
				ioctl(fan_fd, FAN_OFF);
			}
		} else if (a == 2) {
      printf("请输入要实现的功能\n");
      printf("0(关蜂鸣器) 1(开蜂鸣器) >");
      scanf("%d", &a);
      if (a == 1) {
        ioctl(bee_fd, BEE_ON);
      } else if (a == 0) {
        ioctl(bee_fd, BEE_OFF);
      }
    } else if (a == 3) {
      printf("请输入要实现的功能\n");
      printf("0(关马达) 1(开马达) >");
      scanf("%d", &a);
      if (a == 1) {
        ioctl(motor_fd, MOTOR_ON);
      } else if (a == 0) {
        ioctl(motor_fd, MOTOR_OFF);
      }
    }
	}
	close(led_fd);
	close(fan_fd);
	close(bee_fd);
  close(motor_fd);

	return 0;
}
#ifndef __HEAD_H__
#define __HEAD_H__

#include "rcc.h"
#include "gpio.h"

#define LED_ON _IOW('l', 1, int) //开灯
#define LED_OFF _IOW('l', 0, int) //关灯

#define FAN_ON _IO('f', 0)
#define FAN_OFF _IO('f', 1)

#define BEE_ON _IO('b', 0)
#define BEE_OFF _IO('b', 1)

#define MOTOR_ON _IO('m', 0)
#define MOTOR_OFF _IO('m', 1)
#endif

请添加图片描述

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

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

相关文章

多元回归预测 | Matlab主成分分析PCA降维,PLS偏小二乘回归预测。PCA-PLS回归预测模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab主成分分析PCA降维,PLS偏小二乘回归预测。PCA-PLS回归预测模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %% 清空环境变量 warn…

硬件性能 - 磁盘瓶颈分析

简介 本文章通过Linux命令输出指标项&#xff0c;简单的介绍硬件资源-磁盘的性能瓶颈分析。其他硬件性能分析如下&#xff1a; 1. 硬件性能 - CPU瓶颈分析 2. 硬件性能 - 掌握内存知识 3. 硬件性能 - 网络瓶颈分析 目录 1. 测试磁盘性能 1.1. 读性能 1.2. 写性能 1.3. 同时…

MachineLearningWu_5_MultipleLinearRegression

在进行多元线性回归的时候&#xff0c;我们需要规定一些基本法则。例如我们使用 x j ( i ) x_j^{(i)} xj(i)​来表示第i个sample的第j个特征。 将单元的线性回归变为多元线性回归&#xff0c;公式将变换为如下&#xff0c; 为了实现更简单的数学表达式&#xff0c;我们将表达式…

haproxy负载均衡

目录 一.常见的web集群调度器 二.haproxy的概念 三.特性 四 图解haproxy 五 haproxy的配置文件详解 一.常见的web集群调度器 1.目前常见的web集群调度器分为软件和硬件 2.软件通常使用开源的lvs/haproxy/nginx 3.硬件一般使用比较多的是f5 也有国内的产品 二.haproxy的…

LeetCode:合并区间

题目&#xff1a;56. 合并区间 - 力扣&#xff08;Leetcode&#xff09; 讲这道题之前&#xff0c;先介绍一下sort函数的骚操作。 sort函数可以用于二维数组的排序&#xff01;&#xff01;&#xff01; 解释&#xff1a; 这里sort函数也是从小到大进行排序&#xff0c;只…

确保无缝、安全的云转型

随着云计算继续主导数字化转型&#xff08;这是理所当然的&#xff09;&#xff0c;组织面临着双重挑战&#xff1a;将运营无缝转移到云并确保这种转型的安全。 虽然云的采用保证了可扩展性、成本效率和生产力的提高&#xff0c;但保持警惕对于组织防范网络安全威胁和安全漏洞…

webpack5搭建与基本概念

webpack基础构建 新建文件夹进入文件夹查看是否安装node&#xff0c;命令&#xff1a;node-v创建package.json文件&#xff0c;命令&#xff1a;npm init -y安装webpack和webpack-cli&#xff0c;&#xff08;命令自动创建出package-lock.json文件和node_modules文件夹&#x…

【智慧交通项目实战】《 OCR车牌检测与识别》(一)项目介绍

👨‍💻作者简介: CSDN、阿里云人工智能领域博客专家,新星计划计算机视觉导师,百度飞桨PPDE,专注大数据与AI知识分享。✨公众号:GoAI的学习小屋 ,免费分享书籍、简历、导图等,更有交流群分享宝藏资料,关注公众号回复“加群”或➡️点击链接 加群。 🎉专栏推荐: 点…

指针进阶(1)(字符指针,指针数组,数组指针,函数指针)

目录 前言&#xff1a; 字符指针 TIP&#xff1a; 指针数组 数组指针 概念辨析 形式辨析 数组名的理解&#xff1a; 数组指针如何使用&#xff1f; 二维数组的传参 函数指针 函数的地址&#xff1a; 函数指针的形式 函数指针的作用 关于函数指针一些奇特的点 前言&…

Java基础知识 之 java Applet 小训练

import java.applet.Applet; import java.awt.*; import java.util.Random;import static java.lang.Math.cos; import static java.lang.Math.sin;public class HelloWorldApplet extends Applet {public void paint(Graphics g) {// 将Graphics对象转换为Graphics2D类型java.…

Linux 系统编辑 --文件IO

目录 1.文件 IO 1.1系统调用 1.2 C 标准库文件 IO 函数 1.3 open/close 函数 1.4 文件描述符表 1.7 read/write 函数 1.8 缓冲区 1.9 错误处理函数 2.0 阻塞、非阻塞 2.1 lseek 函数 辅助学习资料 参考书 1 &#xff1a;《 Unix 环境高级编程》 W.Richard St…

MFC学习日记(二)——VS2012应用程序工程中文件的组成结构

上一篇我们用应用程序向导生成框架程序后&#xff0c;我们可以打开工程所在的文件夹看到以下以解决方案命名的文件夹&#xff0c;此文件夹中包含了几个文件和一个以工程名命名的子文件夹&#xff0c;这个子文件夹中又包含了若干个文件和一个res文件夹&#xff0c;创建工程时的选…

Vue2:axios解决跨域的问题(vue2没有config情况下)

在vue2上用axios发起Post模拟注册的时候&#xff0c;调用接口&#xff0c;提示报错&#xff1a; axios({method: post,url: http://1.12.254.80:8080/api/user/register,// url: /user/api/user/register,data: { // 请求体数据userAccount: userName,userPassword: pwd1,check…

离线环境下安装微软Visual Studio 2022 生成工具

1. 前言 最近&#xff0c;在学习cython的时候&#xff0c;需要安装windows下的C/C编译、链接工具。开始觉得传统的msvc太大了&#xff0c;想要尝试Mingw&#xff0c;但是都是编译错误。无奈之下&#xff0c;还是要安装msvc。 微软提供了Visual Studio 2022 Build Tools &…

MySQl数据库第五课 --------在SQl的简单命令--------学习学习

作者前言 欢迎小可爱们前来借鉴我的gtiee秦老大大 (qin-laoda) - Gitee.com ———————————————————————————— 目录 数据库的简单介绍 1.数据储存 2.数据库类型 &#xff08;1&#xff09;.关系型数据库 &#xff08;2&#xff09;.非关系型数据库…

大学英语六级相当于雅思考试多少分

雅思考试的难度&#xff0c;可以和大学英语六级进行对应&#xff0c;大家可以通过分数来基本确认雅思考试的难度系数。跟着小编来一起看看大学英语六级相当于雅思考试多少分&#xff1f; 英语六级相当于雅思多少分 大学英语六级和雅思没有直接的分数对应关系&#xff0c;一般大…

部署LVS+Keepalived高可用集群

目录 一、keepalived概述 1.1管理LVS负载均衡软件 1.2VRRP(Virtual Router Redundancy Protocol) 原理 二、keepalived服务的重要功能 2.1自动切换&#xff08;failover&#xff09; 2.2健康检查&#xff08;health checking&#xff09; 2.3高可用&#xff08;HA&#x…

深度神经网络剪枝算法基础理论

非结构化剪枝可获得更高的剪枝率与精度&#xff0c;但是其非结构化特征带来的随机连接使得往往需要专门的软、硬件设计来支持其推理加速&#xff0c;而在现有的边缘硬件上难以满足其应用条件。鉴于此&#xff0c;目前在剪枝领域的研究多集中在结构化剪枝上&#xff0c;如图1.11…

RabbitMQ系列(22)--RabbitMQ优先级队列

前言&#xff1a;在购物系统中有一个订单催付的场景&#xff0c;如果客户在购物系统下单后在设定的时间内未付款那么就会给客户推送一条短信提醒&#xff0c;这是一个比较简单的功能&#xff0c;但是&#xff0c;商家对我们来说&#xff0c;肯定是要区分大客户和小客户的&#…

Xshell7/Xftp7 解决强制更新问题:要继续使用此程序,您必须应用最新的更新或使用最新版本

文章目录 一、背景二、解决方案方案一&#xff1a;重新安装&#xff08;推荐&#xff09;方案二&#xff1a;修改nslicense.dll文件&#xff08;不推荐&#xff09;方案三&#xff1a;修改系统时间&#xff08;可选&#xff09;Xshell.batXftp.bat 三、总结 一、背景 Xshell7/…