ioctl--字符设备的控制技术【转】
本文转载自:http://blog.csdn.net/coding__madman/article/details/51356313
字符设备的控制
1. 字符设备控制理论
1.1 作用
大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力。比如:改变波特率
1.2 应用程序接口
在用户空间,使用ioctl系统调用来控制设备,原型如下:
int ioctl(int fd, unsigned long cmd, ...)
fd: 要控制的设备文件描述符
cmd: 发送给设备的控制命令
...: 第三个参数是可选的参数,存在与否依赖于控制命令(第二个参数)
1.3 设备驱动方法
2. 字符设备控制实现
2.1 定义命令
命令其实质而言就是一个整数,但为了让这个整数具备更好的可读性,我们通常会把这个整数分为几个段,类 型(8位),序号, 参数传送方向,参数长度
type(类型/幻数):表明这是属于哪个设备的命令
number(序号):用来区分同一设备的不同命令
direction: 参数传送的方向,可能的值是_IOC_NONE(没有数据传输),_IOC_READ, _IOC_WRITE(向设备读写 参数)
size : 参数长度
Linux系统提供了下面的宏来帮助定义命令:
* _IO(type, nr) : 不带参数的命令
*_IOR(type, nr, datatype) : 从设备中读取参数的命令
*_IOW(type, nr, datatype) : 向设备写入参数的命令
例如:
#define MEM_MAGIC 'm' //定义幻数
#define MEM_SET _IOW(MEM_MAGIC, 0, int)
2.2 实现设备方法
unlocked_ioctl函数的实现通常是根据命令执行的一个switch语句。但是,当命令号不能匹配任何一个设备所支 持的命令时, 返回 -EINVAL
编程模型:
switch cmd:
case 命令A:
//执行A所对应的操作
case 命令B:
//执行B对应的操作
defaule:
return -EINVAL;
实例代码分析来实现ioctl:
这里的memdev.c还是接着上篇的基础上改的
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <linux/errno.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <asm/uaccess.h>
- #include <linux/slab.h>
- #include "memdev.h"
- int dev1_registers[5];
- int dev2_registers[5];
- struct cdev cdev;
- dev_t devno;
- /*文件打开函数*/
- int mem_open(struct inode *inode, struct file *filp)
- {
- /*获取次设备号*/
- int num = MINOR(inode->i_rdev);
- if (num==0)
- filp->private_data = dev1_registers;
- else if(num == 1)
- filp->private_data = dev2_registers;
- else
- return -ENODEV; //无效的次设备号
- return 0;
- }
- /*文件释放函数*/
- int mem_release(struct inode *inode, struct file *filp)
- {
- return 0;
- }
- /*读函数*/
- static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
- {
- unsigned long p = *ppos;
- unsigned int count = size;
- int ret = 0;
- int *register_addr = filp->private_data; /*获取设备的寄存器基地址*/
- /*判断读位置是否有效*/
- if (p >= 5*sizeof(int))
- return 0;
- if (count > 5*sizeof(int) - p)
- count = 5*sizeof(int) - p;
- /*读数据到用户空间*/
- if (copy_to_user(buf, register_addr+p, count))
- {
- ret = -EFAULT;
- }
- else
- {
- *ppos += count;
- ret = count;
- }
- return ret;
- }
- /*写函数*/
- static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
- {
- unsigned long p = *ppos;
- unsigned int count = size;
- int ret = 0;
- int *register_addr = filp->private_data; /*获取设备的寄存器地址*/
- /*分析和获取有效的写长度*/
- if (p >= 5*sizeof(int))
- return 0;
- if (count > 5*sizeof(int) - p)
- count = 5*sizeof(int) - p;
- /*从用户空间写入数据*/
- if (copy_from_user(register_addr + p, buf, count))
- ret = -EFAULT;
- else
- {
- *ppos += count;
- ret = count;
- }
- return ret;
- }
- /* seek文件定位函数 */
- static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
- {
- loff_t newpos;
- switch(whence) {
- case SEEK_SET:
- newpos = offset;
- break;
- case SEEK_CUR:
- newpos = filp->f_pos + offset;
- break;
- case SEEK_END:
- newpos = 5*sizeof(int)-1 + offset;
- break;
- default:
- return -EINVAL;
- }
- if ((newpos<0) || (newpos>5*sizeof(int)))
- return -EINVAL;
- filp->f_pos = newpos;
- return newpos;
- }
- <span style="color:#ff0000;">//设备控制函数
- long mem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- {
- switch(cmd)
- {
- case MEM_RESTART: //假如这里传入的是重启的命令
- printk(KERN_WARNING"restart device!\n");//这里通过虚拟设备来模拟
- return 0;
- case MEM_SET: //如果传入的是设置参数命令
- printk(KERN_WARNING"arg is : %d\n", arg);//打印出传入的参数
- return 0;
- default:
- return -EINVAL;//其他的打印错误
- }
- return 0;
- }</span>
- /*文件操作结构体*/
- static const struct file_operations mem_fops =
- {
- .llseek = mem_llseek,
- .read = mem_read,
- .write = mem_write,
- .open = mem_open,
- .release = mem_release,
- <span style="color:#ff0000;">.unlocked_ioctl = mem_ioctl,</span>
- };
- /*设备驱动模块加载函数*/
- static int memdev_init(void)
- {
- /*初始化cdev结构*/
- cdev_init(&cdev, &mem_fops);
- /* 注册字符设备 */
- alloc_chrdev_region(&devno, 0, 2, "memdev");
- cdev_add(&cdev, devno, 2);
- //printk(KERN_WARNING"Hello Memdev!\n");
- printk("Hello Memdev!\n");
- }
- /*模块卸载函数*/
- static void memdev_exit(void)
- {
- cdev_del(&cdev); /*注销设备*/
- unregister_chrdev_region(devno, 2); /*释放设备号*/
- printk(KERN_WARNING"exit Memdev!\n");
- }
- MODULE_LICENSE("GPL");
- module_init(memdev_init);
- module_exit(memdev_exit);
memdev.h
- #define MEM_MAGIC 'm' //定义一个幻数,而长度正好和ASC码长度一样为8位,所以这里定义个字符
- #define MEM_RESTART _IO(MEM_MAGIC, 0) //第一个命令是重启的命令,重启的命令不带参数 第一命令这里序号定义成0
- #define MEM_SET _IOW(MEM_MAGIC, 1, int) //设置参数命令 序号为1, 类型为int
测试应用程序mem_ctl.c
- #include<sys/types.h>
- #include<sys/stat.h>
- #include<fcntl.h>
- #include<sys/ioctl.h>
- #include "memdev.h"
- int main()
- {
- int fd;
- fd = open("/dev/memdev0", O_RDWR);//可读可写打开文件
- ioctl(fd, MEM_SET, 115200);//第一个参数fd,第二个是我们要发送的命令,第三个是要传入的参数
- ioctl(fd, MEM_RESTART);//重启
- close(fd);
- }
Makefile
- obj-m := memdev.o
- KDIR := /home/kernel/linux-ok6410
- all:
- make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
- clean:
- rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
这里ioctl函数原型可以查看内核源码Fs.h(/include/linux目录下)文件
然后这次采用静态编译mem_ctl.c文件 arm-linux-gcc -static -o memctl (这里采用静态编译上面博文有说道)
由于挂载了整个rootfs目录,这里编译产生的文件会同步到我的开发板
安装设备驱动模块,然后cat /proc/device 查看设备驱动程序的主设备号
然后创建设备文件,这样我们的应用程序就可以通过这个设备文件来访问设备了(当然这里我们的设备是虚拟出来的字符设备,不过麻雀虽小五脏俱全)
mknod memdev0 c 252 0 (执行该命令)
memdevo是我们给字符设备取的名字, 252是该字符设备的设备号,
这里可以看到/dev目录下就会产生memdev0这个设备文件了,运行mem_clt应用程序
至此ioctl字符设备的控制就OVER了!
ioctl--字符设备的控制技术【转】的更多相关文章
- Linux 字符设备控制技术
字符设备控制技术 一.字符设备控制理论 1.作用 大部分设备除了具有<读写设备>的能力,还应该有<控制设备>的能力.比如改变 波特率 2. 应用程序接口 在用户空间中使用 Io ...
- 转:内核空间与用户空间数据交换的方式之一 --ioctl(通过字符设备演示)
对于linux而言,内核程序和用户程序分别运行在内核空间和用户空间,要实现两者的数据交换,主要有以下几种方式:系统调用,读写系统文件(procfs,sysfs, seq_file,debugfs等), ...
- linux 高级字符设备驱动 ioctl操作介绍 例程分析实现【转】
转自:http://my.oschina.net/u/274829/blog/285014 1,ioctl介绍 ioctl控制设备读写数据以及关闭等. 用户空间函数原型:int ioctl(int f ...
- Linux字符设备驱动框架
字符设备是Linux三大设备之一(另外两种是块设备,网络设备),字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,常见的字符设备包括鼠标.键盘.显示器.串口等等,当我们执行ls -l ...
- 字符设备驱动之Led驱动学习记录
一.概述 Linux内核就是由各种驱动组成的,内核源码中大约有85%的各种渠道程序的代码.一般来说,编写Linux设备驱动大致流程如下: 1.查看原理图,数据手册,了解设备的操作方法. 2.在内核中找 ...
- NeuSoft(4)编写字符设备驱动
1.要求:实现简单的字符设备驱动程序 2.源码清单 #include <linux/module.h> #include <linux/types.h> #include &l ...
- Linux字符设备
一.linux系统将设备分为3类:字符设备.块设备.网络设备. 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的 ...
- 深入理解Linux字符设备驱动
文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...
- Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...
随机推荐
- 第一章-第六题(帮人抢票,帮人选课这些软件是否合法 你怎么看?)--By梁旭晖
我觉得这些软件是合法的,符合道德规范的. 计算机当初设计的初衷就是简化甚至替代人类的工作.而软件作为计算机硬件的驱动着,其设计就是体现这些原则. 现在互联网上的订票,选课类型的网站还是有很多的,比如: ...
- Matlab的标记分水岭分割算法
1 综述 Separating touching objects in an image is one of the more difficult image processing operation ...
- 一篇UI规范文件
一篇UI规范文件 这是一个UI模板规范,在做B/S版应用程序时比较适用,其实这样的东西算不上什么正规的规范,只是为了适应我们现在面对的开发环境和组织流程做的一些权宜的努力,和解决了一些与程序沟通和接口 ...
- Hardware Solutions CACHE COHERENCE AND THE MESI PROTOCOL
COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION Hardware-based soluti ...
- Secure Digital
https://en.wikipedia.org/wiki/Secure_Digital#Technical_details Secure Digital (SD) is a non-volatile ...
- 【php】命名空间 和 自动加载的关系
目的 本文的目的主要是说明 命名空间的 use 关键词 和 new ClassName 这两个步骤,哪个步骤才会执行自动加载,这是逻辑有点混乱的表现,这种想法也是很正常的,让我们来解密吧 命名空间(n ...
- 带你玩转JavaWeb开发之四 -如何用JS做登录注册页面校验
今日内容 使用JQuery完成页面定时弹出广告 使用JQuery完成表格的隔行换色 使用JQuery完成复选框的全选效果 使用JQuery完成省市联动效果 使用JQuery完成下列列表左右选择 使用J ...
- 关于ios 3D变换 CGAffineTransformIdentity
每次做完3D变换以后,重新设置view的frame时,记得用CGAffineTransformIdentity 对3D变换进行还原,否则将会影响frame.当你对view进行3D变换后,重新设置vie ...
- Windows Live Writer体验
[安装] 首先下载安装包安装软件,没啥好说的,baidupan有记录: 顺便下载两个工具,备用: a)SourceCodePlugin_version_1.1.zip 将WindowsLiveWrit ...
- Python之路-python(html、css)
html: 概述: HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记).相当于定义统一的一套规则,大家都来遵守他,这样 ...