linux驱动:[3]高级字符设备驱动之ioctl
来源:互联网 发布:char在c语言中什么意思 编辑:程序博客网 时间:2024/05/29 12:14
linux驱动:[3]高级字符设备驱动之ioctl
linux驱动:[3]高级字符设备驱动之ioctl
测试平台: x86 PC linux-4.4.0
1.实验目的:
- 学习并编写ioctl linux高级字符设备驱动程序。
- 编写驱动 scull ,使用5个指令实现对设备数据的清零,读取,写入操作。
2.驱动代码:(解析见下方)
scull.c:
#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/device.h>#include "scull.h"//设备私有数据struct scull_dev { int data; struct cdev cdev;} dev;//最大IOCTL命令号#define SCULL_IOC_MAXNR 4//默认自动分配主设备号#define SCULL_DEV_MAJOR 0static int scull_major = SCULL_DEV_MAJOR;module_param(scull_major, int, S_IRUGO);struct class *scull_class;struct cdev cdev;long scull_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0, retval = 0;//判断命令幻数是否匹配 if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;//判断命令序号是否非法 if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY;//判断空间是否可访问 /* VERIFY_WRITE 是 VERIFY_READ 超集 */ if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; switch (cmd) { case SCULL_IOC_CLEAR://数据清零 dev.data = 0; printk("SCULL_IOC_CLEAR data: 0\n"); break; case SCULL_IOC_GET://获取数据(通过指针) retval = __put_user(dev.data, (int __user *)arg); printk("SCULL_IOC_GET data: %d\n", dev.data); break; case SCULL_IOC_QUERY://获取数据(通过返回值) printk("SCULL_IOC_QUERY data: %d\n", dev.data); retval = dev.data; break; case SCULL_IOC_SET://设置数据(通过指针) retval = __get_user(dev.data, (int __user *)arg); printk("SCULL_IOC_SET data: %d\n", dev.data); break; case SCULL_IOC_TELL://设置数据(通过直接引用参数值) dev.data = arg; printk("SCULL_IOC_TELL data: %d\n", arg); break; default: retval = -EINVAL; break; } return retval;}static const struct file_operations scull_fops = { .owner = THIS_MODULE, .unlocked_ioctl = scull_ioctl,//linux 2.6.36内核之后unlocked_ioctl取代ioctl};static int scull_init(void){ //设备号 dev_t devno = MKDEV(scull_major, 0); int result; if (scull_major)//静态分配设备号 result = register_chrdev_region(devno, 1, "scull"); else {//动态分配设备号 result = alloc_chrdev_region(&devno, 0, 1, "scull"); scull_major = MAJOR(devno); } if (result < 0) return result;//用于udev/mdev自动创建节点 scull_class = class_create(THIS_MODULE, "scull"); device_create(scull_class, NULL, devno, NULL, "scull");//静态添加cdev cdev_init(&cdev, &scull_fops); cdev.owner = THIS_MODULE; cdev_add(&cdev, devno, 1); printk("scull init success\n"); return 0;}static void scull_exit(void){ cdev_del(&cdev); device_destroy(scull_class, MKDEV(scull_major, 0)); class_destroy(scull_class); unregister_chrdev_region(MKDEV(scull_major, 0), 1); printk("scull exit success\n");}MODULE_AUTHOR("Ziping Chen <techping.chan@gmail.com>");MODULE_LICENSE("GPL");module_init(scull_init);module_exit(scull_exit);
scull.h:
#ifndef SCULL_H_#define SCULL_H_//定义幻数#define SCULL_IOC_MAGIC '$'//定义命令->//数据清零#define SCULL_IOC_CLEAR _IO(SCULL_IOC_MAGIC, 0)//获取数据(通过指针)#define SCULL_IOC_GET _IOR(SCULL_IOC_MAGIC, 1, int)//获取数据(通过返回值)#define SCULL_IOC_QUERY _IO(SCULL_IOC_MAGIC, 2)//设置数据(通过指针)#define SCULL_IOC_SET _IOW(SCULL_IOC_MAGIC, 3, int)//设置数据(通过直接引用参数值)#define SCULL_IOC_TELL _IO(SCULL_IOC_MAGIC, 4)#endif
Makefile:
obj-m := scull.o #编译进模块KERNELDIR := /lib/modules/4.4.0-59-generic/build #此处为linux内核库目录PWD := $(shell pwd) #获取当前目录OUTPUT := $(obj-m) $(obj-m:.o=.ko) $(obj-m:.o=.mod.o) $(obj-m:.o=.mod.c) modules.order Module.symversmodules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesclean: rm -rf $(OUTPUT)
linux c应用程序测试:
#include <stdio.h>#include <fcntl.h>#include <sys/ioctl.h>#include "scull.h"int main(void){ int fd; int data;//打开设备 fd = open("/dev/scull", O_RDWR); if (fd == -1) { printf("open scull device failed!\n"); return -1; }//数据清零 ioctl(fd, SCULL_IOC_CLEAR);//直接传值测试 data = ioctl(fd, SCULL_IOC_QUERY); printf("app data %d\n", data); data = 100; ioctl(fd, SCULL_IOC_TELL, data);//指针传值测试 ioctl(fd, SCULL_IOC_GET, &data); data = 122; ioctl(fd, SCULL_IOC_SET, &data); return 0;}
测试结果:
3.代码解析:
代码的大部分解析都位于上面测试,这里我只是提一下程序编写过程中可能出现的问题:
error: unknown field 'ioctl' specified in initializer
这个错误是因为在linux 2.6.36内核之后,去掉了原来的ioctl,添加两个新的成员:
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
将scull_fops中
.ioctl
替换为.unlocked_ioctl
,另外scull_ioctl()要去掉inode参数,返回类型为long。没有编写scull_open()函数,设备默认成功打开。
- 编译没有成功可能是没有包含对应的头文件,头文件可以通过查阅手册或者网络搜索得知。
- 查看printk信息可通过
dmesg
shell指令。 - 每个函数的参数都是确定的不变的,不要自己擅自改动。
- 我的个人主页:http://www.techping.cn/
- 我的个人站点博客:http://www.techping.cn/blog/wordpress/
- 我的CSDN博客:http://blog.csdn.net/techping
- 我的简书:http://www.jianshu.com/users/b2a36e431d5e/timeline
- 我的GitHub:https://github.com/techping
欢迎相互follow~
0 0
- linux驱动:[3]高级字符设备驱动之ioctl
- linux高级字符设备驱动(一 设备Ioctl控制)
- linux设备驱动学习(5) 高级字符驱动程序操作--ioctl
- linux字符设备驱动的 ioctl 幻数
- linux内核ioctl(字符设备驱动)
- linux字符设备驱动的 ioctl 幻数
- linux字符设备驱动的 ioctl 幻数
- 高级字符设备驱动-Ioctl设备控制笔记
- 高级字符设备驱动-Ioctl设备控制笔记
- Linux高级字符设备驱动
- Linux高级字符设备驱动
- 《Linux设备驱动程序》学习2—高级字符设备驱动ioctl
- 《Linux设备驱动程序》学习2—高级字符设备驱动ioctl
- linux设备驱动 ioctl
- 设备驱动之---ioctl()
- linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- JPA学习记录三(使用jpa映射关联和继承)
- 剑指offer-46.孩子们的游戏(圆圈中最后剩下的数)
- PyTorch(二)——搭建和自定义网络
- 使用eclipse开发的RAP项目打包war包并发布到tomcat服务器以及访问该项目
- oracle--数据库对象
- linux驱动:[3]高级字符设备驱动之ioctl
- XSS简单预防
- CG group
- Python descriptor
- 在windows上eclipse安装hadoop2.7插件
- 如何学习计算机编程语言
- 利用elasticsearch的python模型进行日志数据分析
- hdoj 5882 Balanced Game
- Problem C: 类的初体验(V)