在Linux字符设备驱动入门(一)中,我们实现了字符设备的简单读写字符功能,接下来我们要在这个基础上加入ioctl功能。首先,我们先来看看3.0内核下../include/linux/fs.h中file_operations结构体的定义:

struct file_operations {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    int (*readdir) (struct file *, void *, filldir_t);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
    int (*check_flags)(int);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
    int (*setlease)(struct file *, long, struct file_lock **);
    long (*fallocate)(struct file *file, int mode, loff_t offset,
              loff_t len);
};

红色字体已经标出在kernel 3.0中已经完全删除了struct file_operations 中的ioctl 函数指针,剩下unlocked_ioctlcompat_ioctl,取而代之的是unlocked_ioctl,主要改进就是不再需要上大内核锁 (调用之前不再先调用lock_kernel()然后再unlock_kernel())。

所以,在hellow.c中,我们在file_operations中加入成员函数hello_ioctl(红色字体部分):

/* file operations for hello device */
static struct file_operations hello_ops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = hello_ioctl,
    .open = hello_open,
    .read = hello_read,
    .write = hello_write,
    .release = hello_release,
};

hello_ioctl()的定义如下:

static int hello_ioctl( struct file *file,
            unsigned int cmd, unsigned long arg)
{    int temp = 0;
    switch(cmd)
    {
      case HELLO_CMD1:
               {
            temp = 1;
            if(copy_to_user( (int *)arg, &temp, sizeof(int))) return -EFAULT;
            break;
               }
      case HELLO_CMD2:
            {
            temp = 2;
            if(copy_to_user( (int *)arg, &temp, sizeof(int))) return -EFAULT;
            break;
            }
    }
    printk( KERN_NOTICE"ioctl CMD%d done!\n",temp);

return 0;

}

这里强调一下cmd的定义:

#define HELLO_MAGIC 'k'
#define HELLO_CMD1    _IO(HELLO_MAGIC,0x1a)
#define HELLO_CMD2    _IO(HELLO_MAGIC,0x1b)

其中'k'为幻数,要按照Linux内核的约定方法为驱动程序选择ioctl编号,应该首先看看include/asm/ioctl.h和Documentation/ioctl-number.txt这两个文件,下面是ioctl.h的部分内容,也是比较重要的:

_IO(type, nr) 用于构造无参数的命令编号;
_IOR(type, nr, datatype) 用于构造从驱动程序中读取数据的命令编号;
_IOW(type, nr, datatype)用于写入数据的命令;
_IOWR(type, nr, datatype)用于双向传输。注意千万不能重复定义。

注意对幻数的编号千万不能重复定义,如ioctl-number.txt已经说明‘k'的编号已经被占用的范围为:

'k'    00-0F    linux/spi/spidev.h    conflict!
'k'    00-05    video/kyro.h        conflict!

所以我们在这里分别编号为0x1a和0x1b,到这里,我们已经完成了对ioctl功能的编写,接下来就是在测试程序中利用系统调用来测试它。

=============================================================

ioctl测试程序

=============================================================
#include <stdio.h>  
#include <fcntl.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>

#define HELLO_MAGIC 'k'  //当然我们也可以定义一个相应的头文件,把ioctl的cmd放进里面,然后再include进 来
#define HELLO_CMD1    _IO(HELLO_MAGIC,0x1a)
#define HELLO_CMD2    _IO(HELLO_MAGIC,0x1b)

int main(void)
{
    int ioctl_rdata;
    int fd, ret;

fd = open ( "/dev/hellow" , O_RDWR);
    if ( fd == -1 )
    {
      perror("open");
      exit(0);
        }

ret = ioctl( fd, HELLO_CMD2,&ioctl_rdata);
    if ( ret == -1)
    {
     perror("ioctl");
     exit(0);
    }
    printf("ioctl_rdata= %d \n",ioctl_rdata);

close(fd);
    return 0;
}
=============================================================

运行结果

=============================================================

root@Ubuntu:~/share/hellow# insmod hellow.ko
root@Ubuntu:~/share/hellow# mknod /dev/hellow c 251 0
root@Ubuntu:~/share/hellow# ./a.out
ioctl_rdata= 2 
root@Ubuntu:~/share/hellow# dmesg | tail

[ 2431.126532] hello init. major:251, minor:0
[ 2453.326022] Hello device open!

[ 2453.326047] ioctl CMD2 done!
[ 2453.326487] Hello device close!

linux字符设备驱动的 ioctl 幻数相关推荐

  1. linux3.0字符设备驱动,linux字符设备驱动的 ioctl 幻数

    在Linux字符设备驱动入门(一)中,我们实现了字符设备的简单读写字符功能,接下来我们要在这个基础上加入ioctl功能.首先,我们先来看看3.0内核下../include/linux/fs.h中fil ...

  2. Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析

    前面在 Linux 字符设备驱动开发基础 (三)-- 字符设备驱动结构(中) ,我们已经介绍了两种重要的数据结构 struct inode{...}与 struct file{...} ,下面来介绍另 ...

  3. linux字符设备驱动在哪里设置,从点一个灯开始学写Linux字符设备驱动!

    原标题:从点一个灯开始学写Linux字符设备驱动! [导读] 前一篇文章,介绍了如何将一个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成一 ...

  4. Linux字符设备驱动

    /*Linux字符设备驱动源代码scdd.c*/ #include <linux/init.h>   /*模块头文件*/ #include <linux/module.h> # ...

  5. Linux字符设备驱动中container_of宏的作用

    Linux字符设备驱动中container_of宏的作用 首先看看这个宏的原型: container_of(ptr,type,member) 功能:根据一个结构体变量中的一个成员变量的指针来获取指向整 ...

  6. Linux 字符设备驱动的编写

    Linux 字符设备驱动的编写 作者:解琛 时间:2020 年 8 月 17 日 Linux 字符设备驱动的编写 一.Linux 设备分类 二.open() 三.数据结构 3.1 struct fil ...

  7. Linux 字符设备驱动结构(三)—— file、inode结构体及chardevs数组等相关知识解析

    前面我们学习了字符设备结构体cdev Linux 字符设备驱动开发 (一)-- 字符设备驱动结构(上)  下面继续学习字符设备另外几个重要的数据结构. 先看下面这张图,这是Linux 中虚拟文件系统. ...

  8. ()shi linux字符设备,Linux字符设备驱动基础(三)

    Linux字符设备驱动基础(三) 6 创建设备节点 6.1 手动创建设备节点 查看申请的设备名及主设备号: cat /proc/devices # cat /proc/devices Characte ...

  9. linux设备模型 字符设备,Linux 字符设备驱动模型之框架解说

    一.软件操作硬件设备模型 在进行嵌入式开发的过程中,在常做的事情就是驱动配置硬件设 备,然后根据功能需求使用硬件设备,实现功能的逻辑.如下图为其 相互之间的关系. 如上图所示: 驱动程序:主要作为操作 ...

最新文章

  1. 创业者说:我从创业者大会看到了什么
  2. python测试udp端口_怎样测试UDP端口
  3. ubuntu下使用visual studio code来编译和调试C++
  4. 【C#】【Thread】BackgroundWorker的使用
  5. python矩阵计算器心得_NLP-tas词汇共现矩阵计算工具
  6. Kinetics数据集下载
  7. RFID电子标签对于图书管理的应用
  8. 武汉大学计算机学院2018夏令营,武汉大学
  9. 《面膜行业网络关注度分析报告》
  10. 驱动里面如何操作regulator
  11. ​2020年,5大顶级数据分析预测
  12. win7下安装centOS7双系统
  13. 想进入游戏建模行业,必须要了解的基础知识
  14. 【Quectel移远展锐平台5G模组RX500U/RG200U使用指南(二)-USB/TTL的使用】
  15. 比FFT还容易明白的NTT(快速数论变换)
  16. P8865 [NOIP2022] 种花
  17. Android二维码扫描
  18. AI智能文章生成器python仿文案狗AI文章写作
  19. Could not open the requested SVN filesystem问题的可能原因
  20. 天猫代运营排行,国内电商领域前十位

热门文章

  1. boost::mpl模块实现sizeof相关的测试程序
  2. boost::math模块计算因子和二项式系数的测试程序
  3. VTK:可视化之ShadowsLightsDemo
  4. VTK:PolyData之ResampleAppendedPolyData
  5. VTK:PolyData之GradientFilter
  6. OpenCV离散傅立叶变换DFT的实例(附完整代码)
  7. OpenGL 本机MSAA的实例
  8. C语言实现pid算法(附完整源码)
  9. C++有哪些性质(面向对象特点)
  10. linux组群账户存放在,linux用户和群组