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

目录

简介

一、交互方法笔记与总结

二、ioctl

三、实战

1、头文件

2、应用程序

3、内核程序

4、 程序输出


简介

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

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

本文学习ioctl

一、交互方法笔记与总结

procfssysfsdebugfsnetlinkioctl
容易开发容易开发与使用相对容易学习与使用非常容易学习与使用困难,必须用户空间和内核空间同步编程相对困难,必须写用户空间程序
适合场景仅仅内核,旧内核使用,避免驱动使用设备驱动为生产与调试目的的驱动接口多种接口(设备、驱动、网络、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、头文件

公共头文件

/* 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..

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值