(十二)ioctl的介绍和使用

本文介绍了ioctl命令的基本用法及其应用场景,ioctl用于向设备发送控制和配置命令,并获取设备的物理信息。文章通过两个示例程序展示了如何使用ioctl获取终端窗口大小及帧缓冲区信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


  ioctl用于向设备发控制和配置命令,有些命令也需要读写一些数据,但这些数据是不能用read/write读写的,称为Out-of-band数据。也就是说,read/write读写的数据是in-band数据,是I/O操作的主体,而ioctl命令传送的是控制信息,其中的数据是辅助的数据。例如,在串口线上收发数据通过read/write操作,而串口的波特率、校验位、停止位通过ioctl设置,A/D转换的结果通过read读取,而A/D转换的精度和工作频率通过ioctl设置。

#include <sys/ioctl.h> 
int ioctl(int d, int request, ...);


  d是某个设备的文件描述符request是ioctl的命令,可变参数取决于request,通常是一个指向变量或结构体的指针。若出错则返回-1,若成功则返回其他值,返回值也是取决于request。
  以下程序使用TIOCGWINSZ命令获得终端设备的窗口大小。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main(void)
{
    struct winsize size;//该结构体是在sys/ioctl.h中被内核定义的
  //isatty(fd);作用是检测fd中的文件描述符是否为tty终端文件,是则返回大于0的数
    if (isatty(STDOUT_FILENO) == 0)
        exit(1);
    //获取终端窗口的大小,将获取的值放到size结构体中
    if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &size)<0) {
        perror("ioctl TIOCGWINSZ error");
        exit(1);
    }
    printf("%d rows, %d columns\n,%d", size.ws_row, size.ws_col,size);
    return 0;
}
//在图形界面的终端里多次改变终端窗口的大小并运行该程序,观察结果。


ioctl是对应于不同的驱动的,没有固定的用法,这里举例获取终端的窗口大小。
ioctl不同于fcntl,前者可以获取设备的物理信息,而后者之只获取访问控制属性。
不同的设备文件的ioctl会有不同的操作,对比于下一个例子。

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/fb.h>

int main(void)
{
    int fd;

    struct fb_var_screeninfo fb_info;

    fd = open("/dev/fb0",O_RDONLY);
    if(fd < 0)
    {
        perror("open /dev/fb0");
        exit(1);
    }

    ioctl(fd, FBIOGET_VSCREENINFO, &fb_info);
    printf("R = %d, C = %d\n",fb_info.xres,fb_info.yres);

    close(fd);

    return 0;
}
### 使用 `ioctl` 头文件进行设备控制操作 #### 定义命令码 为了使用 `ioctl` 进行设备控制,首先需要定义一组唯一的命令码。这些命令码通常被放置在一个头文件中以便于用户空间内核空间共享。 ```c #ifndef __DEVICE_IOCTL_H__ #define __DEVICE_IOCTL_H__ #include <linux/ioctl.h> // 定义幻数作为设备类型标识符 #define DEVICE_IOC_MAGIC 'd' // 定义具体的 ioctl 命令 #define IOCTL_CMD_GET_STATUS _IOR(DEVICE_IOC_MAGIC, 0x01, int) // 获取状态 #define IOCTL_CMD_SET_CONFIG _IOW(DEVICE_IOC_MAGIC, 0x02, struct config_data) // 设置配置 #define IOCTL_CMD_RESET_DEVICE _IO (DEVICE_IOC_MAGIC, 0x03) // 设备重置 #endif /* __DEVICE_IOCTL_H__ */ ``` 上述代码展示了如何创建一个简单的头文件来声明特定的 `ioctl` 操作[^2]。 #### 实现内核模块中的处理逻辑 接下来,在对应的内核模块里实现对这些命令的支持: ```c static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd){ case IOCTL_CMD_GET_STATUS: // 执行获取状态的操作... break; case IOCTL_CMD_SET_CONFIG:{ struct config_data user_config; if(copy_from_user(&user_config, (struct config_data *)arg, sizeof(user_config))) return -EFAULT; // 应用新的配置参数... break; } case IOCTL_CMD_RESET_DEVICE: // 执行设备重启过程... break; default: return -ENOTTY; // 表明不支持该命令 } return 0; } ``` 这段代码片段说明了当接收到不同的 `ioctl` 请求时应采取的动作[^1]。 #### 用户空间调用示例 最后是在应用程序层面通过打开相应的设备节点并发送指令给驱动程序来进行实际的控制动作: ```c #include "device_ioctl.h" int main(void) { int fd = open("/dev/my_device", O_RDWR); if(fd < 0){ perror("Failed to open the device"); return errno; } // 发送设置配置请求 struct config_data my_config = { ... }; if(ioctl(fd, IOCTL_CMD_SET_CONFIG, &my_config)){ perror("ioctl set configuration failed"); close(fd); return errno; } // 关闭文件描述符 close(fd); return 0; } ``` 此部分演示了怎样从用户态发起一次典型的 `ioctl` 调用来修改某个虚拟硬件组件的行为模式。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值