linux驱动学习之ioctl接口

   这里先用例子介绍一下ioctrl接口的使用, 应用层的ioctl函数传入的cmd和arg参数会直接传入驱动层的ioctl接口,ioctl接口的命令有一定规范详细查看ioctl-number.txt文件,这里命令的定义不在规范内,先看下面测试的例子,驱动只实现ioctrl接口并使用ioctl修改和读取内核中的一个整型参数为例,使用两个不同方式读取(值传递和地址传递)。

 

 应用程序测试代码main.c

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>

#define IOCTL_RESET 100 /*重置命令*/
#define IOCTL_GET1  101 /*读取命令值返回*/
#define IOCTL_GET2  102 /*读取命令地址返回*/
#define IOCTL_SET1  103 /*设置命令值传入*/
#define IOCTL_SET2  104 /*设置命令地址传入*/

int main (int *argc,char**argv)
{
  int  fs;int val;
  fs=open("/dev/moduledev60",O_RDWR);
  if(fs<0)
  {
    printf("open fail\n");
    return -1;
  }

  ioctl(fs,IOCTL_SET1,1000);                               //使用值传入设置参数
  printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));   //使用返回值读取参数
  ioctl(fs,IOCTL_GET2,&val);                               //使用地址读取参数 
  printf("ioctl get2 result:%d\n",val);        

  /*当设置参数是负数时 使用返回值读参数会出错 由于ioctl返回负数会被内核认为错误*/
  ioctl(fs,IOCTL_SET1,-100);                               //使用值传入设置参数
  printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));   //使用返回值读取参数
  ioctl(fs,IOCTL_GET2,&val);                               //使用地址读取参数 
  printf("ioctl get2 result:%d\n",val);  

  /*使用地址传入设置参数*/
  val=5555;
  ioctl(fs,IOCTL_SET2,&val);
  printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));
 
  close(fs);
  return 0;
}


驱动主要部分 fileops.c

#define IOCTL_RESET 100 /*重置命令*/
#define IOCTL_GET1  101 /*读取命令值返回*/
#define IOCTL_GET2  102 /*读取命令地址返回*/
#define IOCTL_SET1  103 /*设置命令值传入*/
#define IOCTL_SET2  104 /*设置命令地址传入*/
int drive_param=0;
int fileops_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
  printk(KERN_ALERT "fileops_ioctl  \n");
  switch(cmd)
  {
    case IOCTL_RESET:
	  drive_param=0;
	  break;
	case IOCTL_GET1:
	  return drive_param;
	  break;
	case IOCTL_GET2:
//	  __put_user(drive_param,(int __user *)arg);
      if(copy_to_user((int __user*)arg,&drive_param,4)) return -ENOTTY;
      break;
	case IOCTL_SET1:
	  drive_param=arg;
	  break;
	case IOCTL_SET2:
//	  __get_user(drive_param,(int __user *)arg);
      if(copy_from_user(&drive_param,(int __user*)arg,4))return -ENOTTY;
      break;  
  }
  return 0;
}

传送单个值时使用 __put_user __get_user要比copy相对快,  注意 __put_user,__get_user 应当只用在已经使用 access_ok 校验过的地址.copy_from_user和copy_to_user跟踪代码会发现已经加了access_ok的校验。


执行结果

ioctl get1 result:1000
ioctl get2 result:1000
ioctl get1 result:-1
ioctl get2 result:-100
ioctl get1 result:5555

会发现使用值返回负数-100时,驱动接口内返回-100应用程序的ioctl返回的是-1,使用地址传递参数则正确读取。


下面是部分ioctl-number.tx的内容

If you are adding new ioctl's to the kernel, you should use the _IO macros defined in <linux/ioctl.h>:

    _IO    an ioctl with no parameters
    _IOW   an ioctl with write parameters (copy_from_user)
    _IOR   an ioctl with read parameters  (copy_to_user)
    _IOWR  an ioctl with both write and read parameters.

'Write' and 'read' are from the user's point of view, just like the system calls 'write' and 'read'.  For example, a SET_FOO ioctl would be _IOW, although the kernel would actually read data from user space;
a GET_FOO ioctl would be _IOR, although the kernel would actually write data to user space.

The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter or number from the table below.  Because of the large number of drivers,many drivers share a partial letter with other drivers.

If you are writing a driver for a new device and need a letter, pick an unused block with enough room for expansion: 32 to 256 ioctl commands.
You can register the block by patching this file and submitting the patch to Linus Torvalds.  Or you can e-mail me at <mec@shout.net> and I'll register one for you.

The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number to distinguish ioctls from each other.  The third argument to _IOW,_IOR, or _IOWR is the type of the data going into the kernel or coming out of the kernel (e.g.  'int' or 'struct foo').  NOTE!  Do NOT use sizeof(arg) as the third argument as this results in your ioctl thinking it passes an argument of type size_t.
Some devices use their major number as the identifier; this is OK, as long as it is unique.  Some devices are irregular and don't follow any convention at all.

Following this convention is good because:
(1) Keeping the ioctl's globally unique helps error checking: if a program calls an ioctl on the wrong device, it will get an  error rather than some unexpected behaviour.
(2) The 'strace' build procedure automatically finds ioctl numbers  defined with _IO, _IOW, _IOR, or _IOWR.
(3) 'strace' can decode numbers back into useful names when the  numbers are unique.
(4) People looking for ioctls can grep for them more easily when  this convention is used to define the ioctl numbers.
(5) When following the convention, the driver code can use generic  code to copy the parameters between user and kernel space.










  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Linux PCIe驱动中,ioctl程序是用来实现设备与应用程序之间的通信的一种机制。通过ioctl程序,应用程序可以向设备发送控制命令或者获取设备的状态信息。ioctl程序通常会定义一些特定的命令码,应用程序通过调用ioctl函数并传递相应的命令码和参数来与设备进行交互。 在编写Linux PCIe驱动中的ioctl程序时,一般需要完成以下几个步骤: 1. 在驱动程序中定义ioctl命令码,可以使用宏定义或者枚举类型来表示不同的命令。 2. 在驱动程序的file_operations结构体中注册ioctl函数的处理函数,该处理函数会根据传入的命令码执行相应的操作。 3. 在ioctl处理函数中,根据命令码和参数进行相应的处理,可以通过设备的寄存器访问接口或者其他适当的方式与设备进行通信。 4. 在应用程序中,通过调用ioctl函数并传递相应的命令码和参数来与设备进行通信。 需要注意的是,ioctl程序的具体实现会根据设备的特性和需求而有所不同。因此,在编写ioctl程序时,需要根据具体的设备和应用场景进行相应的设计和实现。 引用\[1\]中的代码示例展示了在Linux PCIe驱动中注册和注销设备驱动程序的过程,而引用\[3\]中提到了设备驱动程序在Linux中的作用和特点。这些引用内容可以帮助理解Linux PCIe驱动中的ioctl程序的作用和实现方式。 #### 引用[.reference_title] - *1* *2* [linux PCIE驱动开发源代码](https://blog.csdn.net/MQWYY3/article/details/112692417)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [linux PCIE驱动开发](https://blog.csdn.net/weixin_39890452/article/details/111797670)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值