Linux字符设备驱动怎么写?file_operations与ioctl怎么用?嵌入式Linux面试

浏览量:2
时间: 2026-09-16 10:01:50
一句话答案

字符驱动核心是 file_operations 结构体:open/read/write/ioctl/release 各对应一个函数,注册后在 /dev 下生成设备节点;用户态 open/read/write/ioctl 系统调用最终调到这些函数;ioctl 用于用户态和驱动传命令和参数。

本文概述

字符驱动是 Linux 驱动入门,面试常考:字符驱动框架、file_operations、ioctl、主设备号、设备节点。回答要能写出最小骨架,并讲清用户态和内核态怎么交互。

核心要点

  • 字符驱动骨架:register_chrdev 注册主设备号→class_create→device_create 生成 /dev 节点

  • file_operations 结构体把 open/read/write/ioctl 系统调用映射到驱动函数

  • ioctl 用于用户态发命令(如设置频率、读状态),命令用 _IO/_IOR/_IOW 宏编码

  • 用户态 open() 打开 /dev/xxx,read/write 读写,ioctl 发控制命令

  • 中断和工作队列在驱动里处理硬件事件,通过 wait_queue 或 poll 通知用户态

终端显示字符设备驱动代码,开发板加载驱动后 /dev 下出现设备节点

面试官:写一个最简单的字符设备驱动,用户态能 open、read、ioctl,骨架怎么写?

面试官考察点

这是驱动开发手到擒来的题。面试官看:①file_operations 是否填对;②主设备号和设备节点怎么生成;③ioctl 命令怎么定义。

回答思路

先给骨架代码,再讲注册流程,最后讲用户态怎么调用。

参考回答

驱动骨架。

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>

#define MY_MAJOR 200
static int my_open(struct inode *i, struct file *f) { return 0; }
static ssize_t my_read(struct file *f, char __user *buf, size_t cnt, loff_t *off) { return 0; }
static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { return 0; }

static struct file_operations fops = {
  .owner = THIS_MODULE,
  .open = my_open,
  .read = my_read,
  .unlocked_ioctl = my_ioctl,
};

static int __init my_init(void) {
  register_chrdev(MY_MAJOR, "mydev", &fops);
  /* class_create / device_create 生成 /dev/mydev */
  return 0;
}

注册流程。

步骤函数作用
注册主设备号register_chrdev告诉内核这个主设备号归你
创建设备类class_create在 /sys/class 下建类
创建设备device_create自动在 /dev 下生成 mydev 节点
卸载unregister_chrdev反过来清理

ioctl 命令。用户态用 ioctl(fd, cmd, arg) 发命令,驱动里用 _IO/_IOR/_IOW 宏定义命令号:

#define CMD_SET_FREQ _IOW('k', 1, int)
#define CMD_GET_STATE _IOR('k', 2, int)

驱动 my_ioctl 里 switch(cmd) 处理不同命令,copy_to_user/copy_from_user 传数据。

用户态怎么用。

int fd = open("/dev/mydev", O_RDWR);
ioctl(fd, CMD_SET_FREQ, &freq);
read(fd, buf, len);
close(fd);

面试官可能追问

追问 1:主设备号和次设备号什么区别?
主设备号标识驱动(register_chrdev 注册),次设备号标识同一个驱动管理的不同设备节点(如 /dev/mydev0、/dev/mydev1)。
追问 2:为什么要有 udev/mdev?
udev 在用户态监听内核设备事件,自动在 /dev 下创建节点。没有 udev 要手动 mknod。
追问 3:read 和 write 怎么处理用户空间指针?
不能直接解引用用户指针,要用 copy_to_user()/copy_from_user(),否则可能崩溃或有安全漏洞。
追问 4:驱动里怎么响应中断?
request_irq() 注册中断处理函数,中断里只做最少工作(读数据、清标志),下半部用 tasklet/workqueue 推迟。
追问 5:怎么调试驱动?
printk+dmesg 最基础;复杂问题用 strace 看用户态系统调用、用 ftrace 跟踪、kgdb 内核调试。

常见失分表达

✗ 驱动就是写个 C 文件 — 不知道 register_chrdev/file_operations/device_create 框架。
✗ 用户态指针直接用 — 不 copy_to_user,内核态直接解引用用户指针会崩。
✗ 驱动里死循环等数据 — 阻塞应用应该用 wait_queue,不是忙等。

准备动作

1
在 IMX6ULL/RPi 上写一个 hello 字符驱动,insmod 后 ls /dev
2
写一个 ioctl 命令,用户态 set/get 参数
3
了解 misc 设备、平台驱动、设备树的基本概念
4
准备一个驱动调试案例:printk 看不到、oops 栈回溯

核心关键词

字符设备file_operationsioctlregister_chrdev设备节点copy_to_user


声明:本网站所收集的部分公开资料来源于互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。仅供学习交流使用,不构成商业目的。版权归原作者所有,如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时删除。侵权投诉
相关推荐HOT
PCB上晶振的EMC防护布局怎么做?硬件面试要从频域干扰讲到接地屏蔽

分类:硬件工程师面试题经验要求:中高级难度:中高级题型:EMC防护设计📖 本文概述晶振是PCB上常见的高辐射源之一,也是硬件工程师面试中EMC防护的高频考点。... 详情>>

2026-08-04 15:58:40
面试官问“你还有什么想问我的”,电子工程师怎么回答?求职反问策略

其他类面试基础求职策略题本文概述反问环节是面试的加分项也是常见的失分点,面试中需要讲清反问环节的意义(展示主动性和岗位匹配度、获取关键信息、避免踩雷)、可以问的... 详情>>

2026-09-01 13:51:07
PCB板材怎么选?FR4与高速板材Dk/Df怎么权衡?PCB工程师面试

PCB设计中高级技术基础题本文概述板材选型决定了阻抗控制、损耗、成本和可靠性,是PCB工程师从入门到进阶的分水岭。面试官想听的不是“高速就换板材”,而是你懂不懂... 详情>>

2026-09-05 09:50:38
Arm2440和6410有什么区别?

1. 主频不同。2440是400M的。6410是533/667M的;2. 处理器版本不⼀样:2440是arm920T内核,6410是arm1176ZJF内核;3... 详情>>

2023-10-27 11:11:02
RS-485接口电路怎么设计与防护?硬件工程师面试从总线拓扑讲到浪涌防护

硬件设计中级技术基础题本文概述RS-485是工业现场最常用的差分总线接口,面试中需要讲清总线拓扑(总线型vs星型)、终端电阻的计算和位置、偏置电阻(fail-s... 详情>>

2026-08-30 10:53:17
开班信息