首页 技术 正文
技术 2022年11月15日
0 收藏 819 点赞 3,390 浏览 4360 个字

ioctl函数是用于控制的设备的接口

1.底层: long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long args);

file_operations结构中的一个函数指针成员,具体的函数接口是自己实现的。

参数:args是4字节的类型,可以传递整型数据,也可以传递指针,指针的话就可以传递一个结构,在cmd中的size位域传递这个结构的字节大小

2.应用层:int ioctl(int fd, int request, …);

  功能:ioctl()  函数操纵特殊文件的底层设备参数。

  参数:fd: 文件描述符

     request :请求cmd  关于cmd命令制作参考下面介绍

     …:可变参数  char *p;

  返回值: 成功: 0 失败: -1

3.关于cmd:

其中对于request(cmd)即命令的操作,要保证值的唯一性。

cmd就是一个数,是应用层传递给驱动的值,在驱动中对应的这个值是否有操作,自己实现。

内核使用几个宏来制作cmd:

_IO   : 不传递参数   #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
_IOW : 只写方式 #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
_IOR :只读方式 #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
_IOWR :读写方式 #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

cmd 中各 bit 对应的功能

关于 ioctl 函数

|———–|————-|———-|———–|

|31   30  |29       16  | 15    8 |7       0  |

|———–|————-|———-|———–|

| dir        | size       | type    |  nr       |

|———–|————-|———-|———–|

cmd  命令码中相应位对应的功能:

dir :方向: 读 _IOR  写 _IOW  可读可写_IOWR   _IO(type,nr) //没有第三个参数  …

size :13位 —->传递的数据类型(char short int …struct )的大小 2^14 = 16384

type :8位  类型—-> 给定一个ASCII码, a-z  =====>幻数magic  借助这个幻数让cmd更加唯一 ==类似共享内存中构建键值的== ftok

nr  :8位  命令码的序号: 2^8 = 256;对设备的控制状态,对命令码中一般不使用2号,内核貌似已使用

通过这几个宏制作一个cmd命令,然后通过ioctl传递到底层的demo_ioctl中判断cmd对应的nr位域执行对应的操作。

简单例子:

——-demo.c驱动程序

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/kfifo.h>
#include "demo.h"/* 变量定义区域 */
const char * name = "demochdrev"; // 字符驱动名字
unsigned int major; // 主设备号
const char *clsname = "mychr"; // 创建class类的名字(不清楚具体什么用途)
struct class *mycls;
struct device *mydev;// read 系统调用
ssize_t demo_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
{
printk(KERN_INFO "kernel read \n");
return ; // 返回读取字节数
}// write 系统调用
ssize_t demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset)
{
printk(KERN_INFO "kernel write \n");
return ;
}// close 系统调用
int demo_release(struct inode *iod, struct file *filp)
{
printk(KERN_INFO "kernel release \n");
return ;
}// open 系统调用
int demo_open(struct inode *iod, struct file *filp)
{
printk(KERN_INFO "kernel open \n");
return ;
}
long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
printk(KERN_INFO "kernel ioctl \n");
switch(cmd)
  {
case DEMO_CTL_INT0:
printk(KERN_INFO " OPEN LED \n");
break;
case DEMO_CTL_INT1:
printk(KERN_INFO " CLOSE LED \n");
break;
default:
break;
}
return ;
}// 对文件的操作方法集
struct file_operations fops = {
.owner = THIS_MODULE,
.read = demo_read, // 函数实现要在其上面,不然在此处找不到函数的声明
.write = demo_write,
.open = demo_open,
.release = demo_release,
.unlocked_ioctl = demo_ioctl,
};/* 模块 3 步操作c */// 模块入口,申请字符设备用到的资源
static int __init demo_init(void)
{
printk(KERN_INFO "module init \n");
// 1. 注册一个字符设备 cdev
major = register_chrdev(, name, &fops); // major=0 表示自动分配主设备号,其返回值是主设备号
if(major <= ){ // 注册字符设备失败
printk(KERN_INFO "register chrdev fail \n");
} // 2.自动创建设备节点 /sys/class 目录下的文件夹名
// 2.1 创建一个 class 类
mycls = class_create(THIS_MODULE, clsname); // 返回值 struct class* 类型
if (IS_ERR(mycls)){ // 创建 class 失败
printk(KERN_INFO "class create fail \n");
unregister_chrdev(major, name); // 在每步检测申请失败了,就要释放前面申请的资源
return PTR_ERR(mycls);
}
// 2.2 创建设备节点的名字
mydev = device_create(mycls, NULL,MKDEV(major, ) , NULL, "demochr%d", ); // 最后 2 个参数会制作这个驱动的可见的名字,安装模块时会看见/dev/demochr0
if (IS_ERR(mydev)) { // 创建设备节点失败
printk(KERN_INFO "failed to create device\n");
unregister_chrdev(major, name);
class_destroy(mycls);
return PTR_ERR(mydev);
}
return ;
}// 模块出口,释放申请的资源
static void __exit demo_exit(void)
{
printk(KERN_INFO "module exit \n");
device_destroy(mycls, MKDEV(major, )); // 上面创建的顺序反向操作,栈操作
class_destroy(mycls);
unregister_chrdev(major, name);
}module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");

——demo.h 文件定义的cmd 命令

#ifndef __DEMO_H
#define __DEMO_H#define DEMO_TYPE 's'
#define DEMO_CTL_INT0 _IO(DEMO_TYPE,0)
#define DEMO_CTL_INT1 _IO(DEMO_TYPE,1)#endif // __DEMO_H

——-test.c测试文件

#include <sys/ioctl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "demo.h"const char *pathname = "/dev/demochr0";
int main(int argc, const char *argv[])
{
int fd = open(pathname, O_RDWR);
ioctl(fd,DEMO_CTL_INT1);
ioctl(fd,DEMO_CTL_INT0); return ;
}

—-Makfile文件

#KERNELDIR=/lib/modules/3.13.--generic/build
KERNELDIR=/home/linux/share/kernel-3.4.PWD=$(shell pwd)
all:
make -C $(KERNELDIR) M=$(PWD) modules
arm-linux-gcc test.c -o test
cp test demo.ko ~/rootfs/home/clean:
make -C $(KERNELDIR) M=$(PWD) clean
rm testobj-m +=demo.o

烧写到开发板测试:

关于 ioctl 函数

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,906
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,430
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,247
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,058
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,690
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,727