Linux用户与内核空间交互—ioctl

这篇具有很好参考价值的文章主要介绍了Linux用户与内核空间交互—ioctl。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

简介

一、交互方法笔记与总结

二、ioctl

三、实战

1、头文件

2、应用程序

3、内核程序

4、 程序输出


简介

用户空间与内核的交互方式,使用copy_from_user(), copy_to_user().

除了这两种交互方式,内核还提供了其他高级的方式,对于写驱动来说很重要。有proc、sysfs、debugfs、netlink、ioctl。

本文学习ioctl

一、交互方法笔记与总结

procfs sysfs debugfs netlink ioctl
容易开发 容易开发与使用 相对容易学习与使用 非常容易学习与使用 困难,必须用户空间和内核空间同步编程 相对困难,必须写用户空间程序
适合场景 仅仅内核,旧内核使用,避免驱动使用 设备驱动 为生产与调试目的的驱动接口 多种接口(设备、驱动、网络、udev系统) 设备驱动
接口可见性 可见;用户权限控制访问 可见;用户权限控制访问 可见;用户权限控制访问 在文件系统中隐藏,避免污染内核空间 在文件系统中隐藏,避免污染内核空间
支持度 已经废弃使用 与用户空间的“正式”方法 在内核中大量使用 支持很好 支持很好
是否用于debug 不是 对于调试非常有用 不是 是(通过隐藏的命令)

二、ioctl

input-output control

经常用在驱动程序中,与open、read、write一起使用。
 

API

#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);

 读-写-读写 函数

_IO(type,nr)//没有参数
_IOR(type,nr,datatype)//读
_IOW(type,nr,datatype)//写
_IOWR(type,nr,datatype)//读/写

三、实战

1、头文件

公共头文件文章来源地址https://www.toymoban.com/news/detail-498218.html

/* our dummy ioctl (IOC) RESET command */
#define IOCTL_LLKD_IOCRESET             _IO(IOCTL_LLKD_MAGIC, 0)

/* our dummy ioctl (IOC) Query POWER command */
#define IOCTL_LLKD_IOCQPOWER            _IOR(IOCTL_LLKD_MAGIC, 1, int)

/* our dummy ioctl (IOC) Set POWER command */
#define IOCTL_LLKD_IOCSPOWER            _IOW(IOCTL_LLKD_MAGIC, 2, int)

2、应用程序

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

//使用说明

int main(int argc, char **argv)
{
	int fd, power;


    //打开文件
	if ((fd = open(argv[1], O_RDWR, 0)) == -1) {
		perror("open");
		exit(EXIT_FAILURE);
	}
	printf("device opened: fd=%d\n", fd);

	//重置设备
	if (ioctl(fd, IOCTL_LLKD_IOCRESET, 0) == -1) {
		close(fd);
		exit(EXIT_FAILURE);
	}
	printf("%s: device reset.\n", argv[0]);

	// 2. 查询
	if (ioctl(fd, IOCTL_LLKD_IOCQPOWER, &power) == -1) {
		close(fd);
		exit(EXIT_FAILURE);
	}
	printf("%s: power=%d\n", argv[0], power);

	// 3. 翻转power值
	if (0 == power) {
		printf("%s: Device OFF, powering it On now ...\n", argv[0]);

        //设置命令,fd 文件描述符;命令 IOCTL_LLKD_IOCSPOWER ,1 值
		if (ioctl(fd, IOCTL_LLKD_IOCSPOWER, 1) == -1) {
			close(fd);
			exit(EXIT_FAILURE);
		}
		printf("%s: power is ON now.\n", argv[0]);
	} else if (1 == power) {
		printf("%s: Device ON, powering it OFF in 3s ...\n", argv[0]);
		sleep(3);	/* yes, careful here of sleep & signals! */

        //设置命令,fd 文件描述符;命令 IOCTL_LLKD_IOCSPOWER ,0 值
		if (ioctl(fd, IOCTL_LLKD_IOCSPOWER, 0) == -1) {
			close(fd);
			exit(EXIT_FAILURE);
		}
		printf("%s: power OFF ok, exiting..\n", argv[0]);
	}

	close(fd);
	exit(EXIT_SUCCESS);
}

3、内核程序

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/version.h>
#include <linux/uaccess.h>
#include "ioctl_llkd.h"

#define OURMODNAME   "ioctl_llkd_kdrv"
MODULE_AUTHOR("wy");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_VERSION("0.1");

static int ioctl_intf_major,power = 1;

static long ioctl_intf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	int retval = 0;
	pr_debug("In ioctl method, cmd=%d\n", _IOC_NR(cmd));

	switch (cmd) {
	case IOCTL_LLKD_IOCRESET:
		pr_debug("reset\n");
		break;
	case IOCTL_LLKD_IOCQPOWER:	/*获取参数 */
        //将内核的值power的值,赋值给arg
        //retval是返回值
		retval = __put_user(power, (int __user *)arg);

		break;
	case IOCTL_LLKD_IOCSPOWER:	/*设置参数*/
		power = arg;//用户空间命令行传递的参数arg 赋值给power

		pr_debug("In ioctl cmd option: IOCTL_LLKD_IOCSPOWER\n"
			"power=%d now.\n", power);

		break;
	default:
		return -ENOTTY;
	}
	return retval;
}

static const struct file_operations ioctl_intf_fops = {
	.llseek = no_llseek,
	.unlocked_ioctl = ioctl_intf_ioctl,	
};

static int ioctl_intf_open(struct inode *inode, struct file *filp)
{
	pr_debug("Device node with minor # %d being used\n", iminor(inode));

	switch (iminor(inode)) {
	case 0:
		filp->f_op = &ioctl_intf_fops;
		break;
	default:
		return -ENXIO;
	}
	if (filp->f_op && filp->f_op->open)
		return filp->f_op->open(inode, filp);
	return 0;
}

static struct file_operations ioctl_intf_open_fops = {
	.open = ioctl_intf_open,
};

static int __init ioctl_llkd_kdrv_init(void)
{
	int result;
	result = register_chrdev(ioctl_intf_major, OURMODNAME, &ioctl_intf_open_fops);
	if (result < 0) {
		pr_info("register_chrdev() failed trying to get ioctl_intf_major=%d\n", ioctl_intf_major);
		return result;
	}

	if (ioctl_intf_major == 0)
		ioctl_intf_major = result;	
	pr_debug("registered:: ioctl_intf_major=%d\n", ioctl_intf_major);

	return 0;	
}

static void ioctl_llkd_kdrv_cleanup(void)
{
	unregister_chrdev(ioctl_intf_major, OURMODNAME);
	pr_info("removed\n");
}

module_init(ioctl_llkd_kdrv_init);
module_exit(ioctl_llkd_kdrv_cleanup);

4、 程序输出

# ./ioctl_llkd_userspace /dev/ioctl_intf
device opened: fd=3
./ioctl_llkd_userspace: device reset.
./ioctl_llkd_userspace: power=0
./ioctl_llkd_userspace: Device OFF, powering it On now ...
./ioctl_llkd_userspace: power is ON now.


# ./ioctl_llkd_userspace /dev/ioctl_intf
device opened: fd=3
./ioctl_llkd_userspace: device reset.
./ioctl_llkd_userspace: power=1
./ioctl_llkd_userspace: Device ON, powering it OFF in 3s ...
./ioctl_llkd_userspace: power OFF ok, exiting..

到了这里,关于Linux用户与内核空间交互—ioctl的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Linux内核4.14版本——drm框架分析(7)——用户态和内核态间的交互

             驱动会注册一个支持KMS的DRM设备时,会在/dev/drm/下创建一个card%d文件,用户态可以通过打开该文件,并对文件描述符做相应的操作实现相应的功能。该文件描述符对应的文件操作回调函数(filesystem_operations)位于drm_driver中,并由驱动程序填充。典型如下:      

    2024年02月09日
    浏览(51)
  • Linux内核4.14版本——drm框架分析(9)——DRM_IOCTL_MODE_GETCONNECTOR(drm_mode_getconnector)

    目录  1. drm_mode_getconnector分析 1.1 找到connector 1.2 计算该connector的encoder数量 1.3 把connector支持的encoder和数量返回给用户 1.4 把找到的connector的参数返回给应用 1.5 填充mode(很重要) 1.6 把找到的connector的参数返回给应用 1.7 计算mode的数量 1.8 把mode的参数和mode的数量返回给应用

    2024年02月11日
    浏览(32)
  • 用户空间与内核通信(二)

    文章:用户空间与内核通信(一)介绍了系统调用(System Call),内核模块参数和sysfs,sysctl函数方式进行用户空间和内核空间的访问。本章节我将介绍使用netlink套接字和proc文件系统实现用户空间对内核空间的访问。 netlink是一种基于socket的通信机制,用于在用户空间与内核

    2024年02月20日
    浏览(34)
  • linux驱动和应用的数据交互ioctl函数和copy_from_user、copy_to_user

    首先,我们需要规定一些命令码,这些命令码在应用程序和驱动程序中需要保持一致。应用程序只需向驱动程序下发一条指令码,用来通知它执行哪条命令。如何解读这条指令和怎么实现相关操作,就是驱动程序自己要做的事。 应用程序的接口函数为ioctl,参考官方文档,函

    2024年02月07日
    浏览(33)
  • 内核与用户空间的通信实现—netlink

            netlink是一个内核空间与用户空间通信的机制,相对ioctl和procfs方式来说,netlink有很多优点: netlink使用简单,与UDO的socket编程类似,直接使用socket编程的API即可。只需要自定义一个新类型的 netlink 协议定义即可。 netlink是一种异步通信机制,在内核与用户态应用之间

    2024年02月16日
    浏览(24)
  • 进程空间管理:用户态和内核态

    用户态虚拟空间里面有几类数据,例如代码、全局变量、堆、栈、内存映射区等。在 struct mm_struct 里面,有下面这些变量定义了这些区域的统计信息和位置。 其中,total_vm 是总共映射的页的数目。我们知道,这么大的虚拟地址空间,不可能都有真实内存对应,所以这里是映射

    2024年02月06日
    浏览(28)
  • 字符设备驱动(内核态用户态内存交互)

    内核驱动:运行在内核态的动态模块,遵循内核模块框架接口,更倾向于插件。 应用程序:运行在用户态的进程。 应用程序与内核驱动交互通过既定接口,内核态和用户态访问依然遵循内核既定接口。 系统:openEuler-20.03-LTS-SP3 char_module.c Makefile 驱动构建 驱动信息确认 应用程

    2024年02月11日
    浏览(32)
  • 内核和用户空间中的TID,GID, PID,uid

    要获取关于eBPF中的进程信息,可以使用以下函数: bpf_get_current_pid_tgid()、 bpf_get_current_uid_gid()、 bpf_get_current_comm(char *buf, int size_of_buf)。 当程序被绑定到对某个内核函数调用时,就可以使用它们。UID/GID应该比较明确,但对于那些以前没有接触过内核操作细节的人来说,还是需要

    2024年02月07日
    浏览(41)
  • Ioctl()方式实现与驱动交互简洁框架

    ioctl是linux中一种除read和write之外的数据传递机制 驱动层IOCTL: 以上函数参数的含义如下 。 inode和fp用来确定被操作的设备。 request就是用户程序下发的命令。 args就是用户程序在必要时传递的参数。 在2.6.36以后ioctl函数已经不存在了,用unlocked_ioctl和compat_ioctl两个函数代替。

    2024年02月09日
    浏览(47)
  • ifconfig工具与驱动交互解析(ioctl)

    Linux ifconfig命令用于显示或设置网络设备。ifconfig可设置网络设备的状态,或是显示目前的设置。 同netstat一样,ifconfig源码也位于net-tools中。 源码位于net-tools工具包中,这是linux网络的基本工具包,此外还有arp,hostname,route等命令。 此文章不考虑ifconfig的具体功能介绍,而是侧

    2024年02月07日
    浏览(97)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包