Linux内核编程(五)ioctl驱动编写

news2024/11/24 22:48:16

本文目录

  • 一、系统层和内核层接口
    • 1. ioctl系统层接口
    • 2. ioctl内核层接口
  • 二、标准 unlocked_ioctl 接口的命令合成
  • 三、代码编程

  
   ioctl 主要用于实现对硬件设备控制类操作,实现 write 和 read 不太好实现的功能。
   ioctl 是一个强大的工具,可以用于实现复杂的设备控制和状态查询。尽管它的使用有时被认为不太优雅,因为它打破了标准的读写接口模型,但在许多情况下,它提供了一种有效的方法来与设备驱动程序进行高级交互。开发者在使用 ioctl 时需要小心设计和实现命令码,以确保与设备的交互是清晰且安全的。

一、系统层和内核层接口

1. ioctl系统层接口

头文件:#include <sys/ioctl.h>

int ioctl(int fd, int request, ...);
//int fd :要操作的文件描述符
//int request :命令,可以是系统预定义的,或者自己定义的。
//...:可变参。

2. ioctl内核层接口

long xxx_unlocked_ioctl(struct file *pfile, unsigned int cmd, unsigned long args)
//struct file *pfile:对应于系统调用的 fd 参数。
//unsigned int cmd :对应系统层的命令。
//unsigned long args :对应系统层的可变参。

在这里插入图片描述

二、标准 unlocked_ioctl 接口的命令合成

   这个命令接口有系统预定义的命令,用户也可以自己定义命令,但是为了防止用户定义的命令和系统预定义的命令发生冲突,则定义了一套命名规则。即通过多个参数来合成命令,这样就保证了命令的唯一性。

命令由32个bit位来构成,如下所示。

bit位功能
31 ~ 3000 (用户程序和驱动没有数据传递 uses _IO macro) 、10 (用户程序从驱动读取数据: _IOR) 、 01 (用户程序向驱动写数据: _IOW)、11 (先用户程序写数据到驱动,再从驱动中读取数据)
29 ~ 16当用户程序和驱动程序有数据传递时候才有效,表示要传递的数据大小。
15 ~ 8魔数,幻数,给每一个驱动分配一个惟一的 ASCII 值,用于区分一个驱动的 cmd 和别的不一样。
7 ~ 0同一个设备驱动中所有 cmd 命令的编号,范围 0~255,一般情况同一个驱动值都是连续的。

   假设我们定义一个BEEP_ON的命令,这时不需要传递参数。我们就可以使用32个bit位来合成该命令,如:0<<30 | 0<<16 | 'B'<<8 |1。使用32位来逐个合成会有些繁琐,所以系统给我们提供了更便捷的接口,其原理也是通过位来合成,只不过已经给我们封装好了,我们直接使用即可。

接口功能
_IO(type, nr)定义没有数据传递的命令
_IOR(type, nr ,size)定义从驱动中读取数据的命令
_IOW(type, nr, size)定义向驱动写入数据的命令
_IOWR(type, nr, size)定义数据交换类型的命令,先写入数据,再读取数据这类命令。

其中type:魔数,nr:命令编号,size:参数的数据类型,如要传递 4 字节,可以写 int。

具体使用如下,为了内核层和系图层都可以使用,命令的定义需要写在一个单独的头文件中。

//不带参数的命令
#define BEEP_ON		_IO('B', 0)
#define BEEP_OFF	_IO('B', 1)

//带参数的写命令
#define LEDX_ON		_IOW('L', 0, void *)
#define LEDX_OFF	_IOW('L', 1, void *)

三、代码编程

common.h

#ifndef __COMMON_H
#define __COMMON_H

#define BEEP 36   //GPIO序号为36,低电平触发。
#define LED1 39
#define KEY1 40
 
 
//无参的命令
#define BEEP_ON   _IO('B', 0)
#define BEEP_OFF  _IO('B', 1)

//向内核写的命令
#define LEDX_ON    _IOW('L', 0, void *)
#define LEDX_OFF   _IOW('L', 1, void *)

//读内核的命令
#define KEY1_Read    _IOR('K', 0, void *)

//先向内核写数据,再读取数据的命令
#define KEYX_Read    _IOWR('K', 1, void *)

#endif

my_ioctl.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>

#include "common.h"


int ioctl_open(struct inode *node, struct file *fd)
{
	gpio_set_value(BEEP, 1);//设置无效电平
    return 0;
}

int ioctl_release(struct inode *node, struct file *fd)
{
	   gpio_set_value(BEEP, 1);  //设置无效电平
       return 0;
}

long ioctl_unlocked_ioctl(struct file *fd, unsigned int cmd, unsigned long arg)
{
   
  switch(cmd)
  {
    case BEEP_ON:
		gpio_set_value(BEEP, 0);
		break;

	case BEEP_OFF:
		gpio_set_value(BEEP, 1);
		break;
		
	case LEDX_ON:
		gpio_set_value(arg, 0);
		break;
		
    case LEDX_OFF:
		gpio_set_value(arg, 1);
		break;
		
	case KEY1_Read:{
      	    int value, ret;
			value=gpio_get_value(KEY1);
			ret = copy_to_user((void *)arg, &value, sizeof(value));
			if(ret < 0) {
					pr_err("copy_to_user error\r\n");
					return -EINVAL;
				}
			break;
		}
		
	case KEYX_Read:{
      	   
			break;
		}
  }
  
     return 0;	
}

const struct file_operations ioctl_fops={
	.owner = THIS_MODULE,
    .open=ioctl_open,
	.release=ioctl_release,
	.unlocked_ioctl=ioctl_unlocked_ioctl,
};

struct miscdevice misc_ioctl={
   .minor=MISC_DYNAMIC_MINOR,
   .name="my_ioctl",
   .fops=&ioctl_fops,
};


const struct gpio gpio_array[]={
	{ BEEP, GPIOF_OUT_INIT_HIGH, "beep"},
	{ LED1, GPIOF_OUT_INIT_HIGH, "led1"},
	{ KEY1, GPIOF_IN, "key1"},
};


static int __init ioctl_init(void)
{
   int ret;
   ret= misc_register(&misc_ioctl);   //注册杂项设备
   if(ret < 0) {
		pr_err("misc_register error\r\n");
		return -1;
   }
   ret=gpio_request_array(gpio_array, sizeof(gpio_array)/sizeof(gpio_array[0])); // //申请一组GPIO
   if(ret < 0) {
	  pr_err("gpio_request error\r\n");
	  goto gpio_error;
   }
   return 0;
   
gpio_error:    //防止GPIO注册失败后,无法注销杂项设备。
	misc_deregister(&misc_ioctl);
	return -1;	
}


static void __exit ioctl_exit(void)
{

   misc_deregister(&misc_ioctl);
   gpio_free_array(gpio_array, sizeof(gpio_array)/sizeof(gpio_array[0]));  //释放一组GPIO
}

module_init(ioctl_init);
module_exit(ioctl_exit);
MODULE_LICENSE("GPL");

app.c

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


int main()
{

    int fd;
    int read_value;
    fd=open("/dev/my_ioctl",O_RDWR);
    if(fd<0){
       return -1;
    }
/* 无参命令
    ioctl(fd,BEEP_ON);
    sleep(2);
    ioctl(fd,BEEP_OFF);
 */
/*向内核写的命令    
    ioctl(fd, LEDX_ON, LED1);
    sleep(2);
    ioctl(fd, LEDX_OFF, LED1);
 */
//读取内核的命令
    ioctl(fd, KEY1_Read, &read_value);
    printf("%d\n", read_value);  
    return 0;
}

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

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

相关文章

​单级高频谐振小放

目录 高频交流等效电路 质量指标 增益 通频带 选择性 高频交流等效电路 质量指标 增益 YL撇是怎么来的。 通频带 选择性

Spark常见的可以优化的点

Shuffle 复用 # 1.以下操作会复用的shuffle结果&#xff0c;只会读一遍数据源 val rdd1 sc.textFile("hdfs://zjyprc-hadoop/tmp/hive-site.xml").flatMap(_.split(" ")).map(x > (x,1)).reduceByKey(_ _).filter(_._2 > 1) rdd1.count() rdd1.fil…

基于dagger平台实现资源位的接口自动化

文章目录 什么是dagger平台&#xff1f;什么是资源位&#xff1f;什么是接口自动化&#xff1f;如何实现接口自动化&#xff1f;内部调用关系基本概念互相引用关系 目录结构具体实现任务&#xff1a;Task用例&#xff1a;Case场景&#xff1a;Scene接口&#xff1a;Api 监控与数…

基于Itô扩散过程的交易策略偏微分方程matlab求解与仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于It扩散过程的交易策略偏微分方程,提出了一种确定It扩散过程。通过根据的第一次通过时间来确定问题在这个过程中&#xff0c;我们推导出交易长度的分布函数和密…

如何通过Outlook大附件插件,加强外发附件的安全性和管控力度?

因邮件的便捷性和普遍性&#xff0c;企业间业务往来通常会采取邮箱业务&#xff0c;沟通使用成本也比较低&#xff0c;但容易出现附件太大无法上传的问题。Outlook大附件插件是为解决邮件系统中附件大小限制问题而开发的一系列工具。 使用邮件发送附件时&#xff0c;可能会遇到…

R调用Taxonkit展示系统发育信息

Introduction TaxonKit是一个用于处理生物分类学数据的命令行工具。 它的主要功能是处理NCBI的生物分类学数据&#xff0c;包括对分类单元&#xff08;如物种、属、科等&#xff09;的查找、分类单元的上下位关系查询、分类单元名称的标准化等。 为了方便R社区用户&#xff0…

QuickLook最强大的C#开源文件预览神器

功能特点&#xff1a; 快速预览&#xff1a;用户只需选中文件并按下空格键&#xff0c;即可立即查看文件内容&#xff0c;无需打开特定应用程序或软件。 多格式支持&#xff1a;QuickLook支持预览几乎所有常见的文件类型&#xff0c;包括但不限于&#xff1a; 图像&#xff1…

【计算机网络】已解决:“‘ping‘ 不是内部或外部命令,也不是可运行的程序或批处理文件”报错

文章目录 一、问题分析背景二、可能出错的原因三、错误代码示例四、正确解决方法与示例五、注意事项 已解决“‘ping’ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件”报错 一、问题分析背景 在Windows操作系统中&#xff0c;ping 命令是一个常用的网络诊断…

STM32CubeMX配置-外部中断配置

一、简介 MCU为STM32G070&#xff0c;配置为上升沿触发外部中断&#xff0c;在上升沿外部中断回调函数中进行相关操作。 二、外部中断配置 查看规格书中管教描述&#xff0c;找到I/O对应的外部中断线&#xff0c;然后进行如下上升沿触发外部中断配置。 三、生成代码 调用上升沿…

【Linux】进程_6

文章目录 五、进程8. 进程地址空间 未完待续 五、进程 8. 进程地址空间 上图可能很多人都看过了&#xff0c;这里再来验证一下&#xff1a; 验证位置&#xff1a; 验证堆栈的生长方向&#xff1a; 在上面的空间布局图中&#xff0c;有一个疑问&#xff0c;画的空间是 内存…

【探索Linux】P.34(HTTPS协议)

阅读导航 引言一、HTTPS是什么1. 什么是"加密"2. 为什么要加密3. 常见的加密方式&#xff08;1&#xff09;对称加密&#xff08;2&#xff09;非对称加密 二、证书认证1. CA认证 三、HTTPS的加密底层原理✅非对称加密对称加密证书认证 温馨提示 引言 在上一篇文章中…

Ubuntu 22.04 解决 firefox 中文界面乱码

问题复现 在为Ubuntu 22.04 Server安装完整的GNOME 42.01桌面后&#xff0c;将桌面语言设置为中文时&#xff0c;打开Firefox可能会出现中文乱码的问题。经过网上调查发现&#xff0c;这个问题是由Snap软件包引起的。 解决方案 为了避免在Ubuntu 22.04中文模式下的乱码问题…

消息队列-RabbitMQ-消息确认机制

为了保证消息的不丢失&#xff0c;可靠抵达&#xff0c;可以使用事务消息&#xff0c;但是性能会下降250倍&#xff0c;为此引入确认机制。 1.ConfirmCallBack 服务器收到消息就回调 ● 被broker接收到只能表示Message已经到达服务器&#xff0c;并不能保证消息一定会投递到目…

【漏洞复现】红海云eHR PtFjk.mob 任意文件上传漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

c++编程(18)——deque的模拟实现(2)容器篇

欢迎来到博主的专栏——c编程 博主ID&#xff1a;代码小豪 文章目录 deque的数据结构deque的构造默认构造填充构造 deque的其他操作deque的插入、删除push_back和push_frontpop_back和pop_frontclear、erase和insert操作 传送门 在上一篇中&#xff0c;我们已经实现了deque最核…

2024/6/16 英语每日一段

Nature has the means--to a degree--to limit the effects of climate change. Intact ecosystems such as forests, grasslands, oceans and peatlands are “carbon sinks”--natural storage systems that remove atmospheric carbon and other greenhouse gases--and are …

【Java03】Java中数组在内存中的机制

1. 内存中的数组 Java中的数组是一种引用类型&#xff0c;数组变量&#xff08;引用&#xff09;和数组元素在内存中是分开的。 Java中的数组变量其实就是指针。 如果想要访问数组元素&#xff0c;只能通过这个数组的引用变量&#xff08;指针&#xff09;来访问。 实际数组对…

华为OD机试 - 多段线数据压缩(Java 2024 D卷 100分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

Hadoop+Spark大数据技术(微课版)总复习

图1 Hadoop开发环境 图2 HDFS 图3 MapReduce 图4 HBase 图5 Scala 图6 Spark 图7 Spark RDD 图8 &#xff08;不考&#xff09; 图9 Spark SQL 图10 Spark Streaming 图11 Spark GraphX 第一章 Hadoop大数据开发环境 hadoop是什么&#xff1f; &#xff08;判断题&#…

数字化转型中的数据资产运营:从数据资产的获取、存储、分析到应用的全流程管理策略

一、引言 随着信息技术的迅猛发展&#xff0c;数字化转型已成为企业提升竞争力、实现可持续发展的关键途径。数据资产作为数字化转型的核心要素&#xff0c;其运营与管理水平直接决定了企业能否在激烈的市场竞争中脱颖而出。本文将从数据资产的获取、存储、分析到应用的全流程…