首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >linux ioctl方法《Rice linux 学习开发》

linux ioctl方法《Rice linux 学习开发》

作者头像
Rice加饭
发布于 2022-05-09 21:12:48
发布于 2022-05-09 21:12:48
2.6K0
举报
文章被收录于专栏:Rice嵌入式Rice嵌入式

这篇文章来讲讲:ioctl的概念、函数的使用方法。

在之前的文章中,驱动程序都是使用read()和write()来操作设备,但是大部分的驱动程序还需要另外一种能力,就是通过设备驱动程序执行各种类型的硬件控制。比如:用户控件经常会请求设备锁门、弹出介质、报告错误信息、改变波特率或执行破坏等操作。这些操作通常是通过ioctl方法来实现。

用户空间:

ioctl系统调用函数原型:int ioctl(int fd,int cmd, ...);

其中:fd 使要操作的文件描述符

cmd:控制命令

...:可选参数,具体形式依赖于第二个参数cmd,因为有些控制命令需要参数,有些命令不需要参数。

内核驱动程序:

ioctl方法函数原型:int (*ioctl)(struct inode *inode,struct file *filp,unsigned intcmd,unsigned long arg);

参数inode和filp:和open方法的参数一样,表示文件节点和打开的file结构

参数cmd:由用户空间不经修改地传递进来

参数arg:使用户空间传递的整数值;如果用户空间的调用程序没有第三个参数,则驱动的arg参数为未定义状态。

其中ioctl方法中的cmd:

1需要选择对应不同命令的编号。

2为了防止对错误的设备使用正确的命令,命令号必须在系统范围内唯一。

3内核规定每一个命令号被分为4个位段,对于ARM来说,4个位段的含义分别是:

dr

sizes

type

number

在内核头文件<asm-generic/ioctl.h>中,

提供了一些宏来构造命令号:

_IO(type,nr):用于构造无参数的命令号

_IOR(type,nr,datetype):用于构造从驱动程序中读取数据的命令号

_IOW(type,nr,datatype):用于构造向驱动程序写入数据的命令号

_IORW(type,nr,datatype):用于构造双向传输的命令号

解开位字段的宏:

_IOC_DIR(cmd):获得传输方向位段的值

_IOC_WRITE应用层写数据掩码,_IOC_READ应用层读数据掩码

_IOC_TYPE(cmd):获得类型的值

_IOC_NR(cmd);获得编号的值

_IOC_SIZE(cmd):获得大小的值

例程实现:

首先需要定义头文件,用于定义命令编号,提供给内核和应用层使用。这里定义了两个编号,分别是读命令号,写命令号。

代码语言:javascript
复制
#ifndef __CMD_H
#define __CMD_H

#include <linux/ioctl.h>

#define BIN_TYPE 'f' 

#define BIN_SET _IOW(BIN_TYPE, 1, char)
#define BIN_GET _IOR(BIN_TYPE, 2, char)

#endif

驱动程序的实现:加入ioctl方法,并在将该方法注册到file_operations结构体中:

代码语言:javascript
复制
static long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
  switch(cmd)
  {
  case BIN_SET:
    copy_from_user(&gpio_val, (void __user *)arg, sizeof(char));
    GPIO_SET_PIN(GPF4, gpio_val);
    break;
  case BIN_GET:
    gpio_val = GPIO_GET_PIN(GPF4);
    copy_to_user((void __user *)arg, &gpio_val, sizeof(char));  
    break;
  }  
  return 0;
}
static struct file_operations leds_fops = {
  .owner   = THIS_MODULE,
  .open   = led_open,
  .ioctl   = led_ioctl,
};

应用层的实现:

代码语言:javascript
复制
#include <fcntl.h>
#include <sys/ioctl.h>

#include "cmd.h"

#define file_name  "/dev/led"

int main(void)
{
  int fd;
  char val;
  fd = open(file_name, O_RDWR);
  if(fd < 0) {
    printf("error: can`t open %s", file_name);
    return 0;
  }

  val = 1;
  ioctl(fd,BIN_SET, &val);
  ioctl(fd, BIN_GET, &val);
  printf("ioctl: get val1 %d\n",val);

  val = 0;
  ioctl(fd, BIN_SET, &val);
  ioctl(fd, BIN_GET, &val);  
  printf("ioctl: get val2 %d\n",val);

  return 0;
}

实验结果:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-31,如有侵权请联系 cloudcommunity@tencent.com 删除
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档