秋招进入密集面试期,嵌入式软件岗里“驱动开发”方向因为门槛高、坑位稳定,一直是不少人的主战场。面试官问的问题往往不追求背概念,而是看你能不能把内核机制和真实硬件关联起来。这篇文章整理了近期嵌入式驱动岗面试中最常出现的十连问,覆盖字符设备、platform 总线、中断、并发、设备树、内存映射、调试手段、电源管理和外设驱动,每一问都给出考察意图、回答思路、易错点和扩展追问,适合准备秋招的嵌入式软件工程师、驱动方向求职者直接对照复习。
1. 嵌入式驱动岗面试考察能力地图
先把面试官的视角拆开看。嵌入式驱动开发不是单纯写寄存器的操作代码,面试提问基本围绕下面这张能力地图展开:
| 考察维度 | 常见提问方式 | 核心技能 |
|---|---|---|
| 驱动基本框架 | 字符设备驱动怎么编写 | file_operations、设备号分配、misc 设备 |
| 驱动模型 | platform 总线如何匹配设备和驱动 | of_match_table、ACPI 匹配、probe 触发时机 |
| 内核并发 | 自旋锁和互斥锁怎么选择 | 锁的上下文限制、死锁预防 |
| 中断机制 | 中断上下半部如何划分 | tasklet、workqueue、threaded irq |
| 设备树 | DTS 语法和驱动如何解析 | compatible、reg、中断属性解析 |
| 内存管理 | ioremap 和 DMA 映射的区别 | 一致性映射、流式映射、cache 一致性 |
| 调试能力 | 驱动崩溃和卡死怎么排查 | printk、sysfs、ftrace、kprobe、devmem |
| 电源管理 | 休眠唤醒流程是什么 | suspend/resume 回调、runtime PM |
| 外设驱动 | I2C/SPI/UART 驱动框架 | client/driver 模型、spi_transfer、tty 层 |
| 场景应变 | 接口不稳定、时序异常怎么解决 | 定位思路、日志分析、时序测量 |
面试十连问基本是这张表的浓缩。复习时不要只看表面,要能把每个知识点延伸到“如果硬件 behavior 异常,你怎么办”。
2. 第一问:字符设备驱动框架
面试官通常会先问一个最基本的:字符设备驱动的主体结构是什么?请你描述一下打开、读写、关闭的完整流程。
这道题的目的不是看你能否背出file_operations里的函数指针,而是考察你是否清楚应用层 open/read/write 与内核驱动的调用链路,是否了解设备号在现代内核中如何分配。
参考答案建议按“驱动注册 -> 设备节点创建 -> 数据通路”三个层次展开:
#include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> static int demo_open(struct inode *inode, struct file *filp) { return 0; } static ssize_t demo_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { return 0; } static const struct file_operations demo_fops = { .owner = THIS_MODULE, .open = demo_open, .read = demo_read, };然后是设备号的分配和字符设备的注册,步骤如下:
- 使用
alloc_chrdev_region动态分配主设备号,避免手动指定冲突。 - 调用
cdev_init初始化cdev结构,并关联file_operations。 - 使用
cdev_add将字符设备注册到内核。 - 通过
device_create在/sys/class下创建设备节点,用户空间即可访问。 - 退出时依次
device_destroy、cdev_del、unregister_chrdev_region。
面试官喜欢追问的问题是:为什么现代驱动多用 misc 设备?
misc 设备(miscdevice)是字符设备的封装,主设备号固定为 10,子设备号可以自定义。对很多简单外设来说,动态分配主设备号、手工创建设备节点都显得繁琐,misc 设备自动在/dev下创建设备节点,省掉了大量样板代码。很多传感器、按键、LED 驱动、看门狗驱动等小型驱动都采用 misc 设备框架。
易错点要重点提:内核空间不能直接访问用户空间指针,必须使用copy_to_user和copy_from_user。否则用户传入的指针是虚拟地址,在内核态访问会导致非法地址访问,甚至崩溃。这个问题在面试中出现的概率很高,写代码演示时一定要把用户空间和内核空间的数据拷贝写完整。
3. 第二问:platform 总线与设备匹配机制
第二个高频问题围绕 platform 驱动展开:platform 总线如何知道一个设备应该由哪个驱动来处理?
这题的背景是 Linux 设备模型。平台总线把设备(device)和驱动(driver)抽象成两个对象,总线负责匹配。匹配方式主要有三种:
- 设备树匹配:通过
compatible属性匹配。 - ACPI 匹配:在 x86 或支持 ACPI 的 ARM 平台上通过 ACPI 表匹配。
- ID 表匹配:通过
platform_device_id表中的 name 字段匹配。
设备树匹配是 ARM 嵌入式平台上最常见的方式。设备节点中的compatible字符串是关键,例如:
led_demo { compatible = "vendor,led-demo"; reg = <0x020c4000 0x100>; interrupts = <0 22 4>; };驱动侧需要提供对应的匹配表:
static const struct of_device_id demo_of_match[] = { { .compatible = "vendor,led-demo", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, demo_of_match); static struct platform_driver demo_pdriver = { .probe = demo_probe, .remove = demo_remove, .driver = { .name = "demo", .of_match_table = demo_of_match, }, }; module_platform_driver(demo_pdriver);面试官在这个问题上通常会有三个追问方向。
第一个追问:probe 函数是如何触发的?
当设备树解析到compatible属性为"vendor,led-demo"的节点时,内核会创建对应的platform_device,然后通过platform_match查找是否有driver匹配。匹配成功后会调用platform_driver的probe回调,传给它一个platform_device指针,驱动在这个函数里完成资源申请、寄存器映射、中断注册等初始化工作。
第二个追问:如果设备树里有对应节点但驱动没有 probe,怎么排查?
排查顺序一般是:
- 检查设备树是否被正确编译进 dtb,使用
dtc工具反编译确认。 - 查看
/sys/bus/platform/devices下是否生成了对应的设备目录。 - 检查
compatible字符串是否与of_match_table完全一致,包括大小写和厂商前缀。 - 检查驱动模块是否成功 insmod,通过
dmesg看是否出现注册信息。
第三个追问:设备树中reg发生了什么?
reg描述的地址资源会通过platform_get_resource获取,比如:
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);拿到起始地址后,要用ioremap将物理地址映射到内核虚拟地址空间,之后才能通过读写寄存器访问外设。这里的物理地址映射和访问是驱动开发中的核心操作,面试官会比较关注你是否清楚物理地址和虚拟地址的区别。
4. 第三问:内核同步机制与锁的选择
并发问题是嵌入式驱动的重灾区。面试官会问:内核中有哪些同步机制?你在驱动里怎么选择锁?
回答时要覆盖这些基本概念:
- 原子操作:
atomic_t、set_bit、test_and_set_bit等,适用于简单的计数和标志位操作。 - 自旋锁:
spinlock_t,适用于临界区很短的场景,尤其是中断上下文中不能睡眠的情况下。 - 互斥锁:
struct mutex,适用于临界区包含阻塞操作、进程上下文的场景。 - 信号量:
struct semaphore,目前内核中用于资源计数的场景已经较少,大部分被 mutex 替代。 - RCU:适用于读多写少的场景,读侧无锁开销,写侧在发布和回收时需要额外处理。
- 完成量:
struct completion,常用于一个线程等待另一个线程完成某事件的同步。
面试官关心的是使用场景的区别,而不是单纯罗列。最常考的对比是自旋锁和互斥锁的选择:
| 比较维度 | 自旋锁 | 互斥锁 |
|---|---|---|
| 获取不到锁时 | 原地自旋忙等 | 进程进入睡眠等待 |
| 上下文要求 | 可用于中断上下文 | 只能在进程上下文使用 |
| 临界区要求 | 短、不能睡眠 | 可以包含阻塞操作 |
| 开销 | 低 | 相对较高 |
| 生动例子 | 保护一个寄存器状态标志 | 保护一块数据缓冲区 |
追问会落在“自旋锁临界区为什么不能睡眠”。如果持有自旋锁时进入睡眠,其他 CPU 试图获取该锁时可能长时间自旋等待,影响系统实时性和调度效率。在内核中自旋锁持有期间调度或睡眠会触发 BUG 检查,实际表现可能是内核卡死、软狗超时或被BUG: scheduling while atomic报错直接终止。
还有一类高频场景题:中断处理函数里需要保护共享数据,选什么锁?
回答是在中断上下文只能使用自旋锁,而且最好用spin_lock_irqsave保存当前中断状态,防止本地中断在持锁期间被触发而导致死锁。如果这个共享数据还会被普通进程上下文访问,则要同时考虑关闭中断和上半部的竞态。
再往下,面试官可能追问死锁的四个必要条件,并要求现场举例。这个属于基础中的基础,必须答准:互斥、持有并等待、不可剥夺、循环等待。在实际驱动中,最常见的死锁原因是锁的顺序不一致,比如两个线程分别持有 A 锁等待 B 锁、持有 B 锁等待 A 锁。复盘时也要说一句“出现死锁应先看 lockdep 输出”,这是内核自带的死锁检测工具,面试官会认为你有实战意识。
5. 第四问:中断上下半部机制
驱动岗面试基本必考中断,常见问题是:为什么中断处理要分上下半部?Linux 提供了哪些下半部机制?
上半部是在中断上下文里执行的request_irq注册的处理函数,必须快速响应硬件事件,不能做耗时操作。下半部负责处理那些不紧急但需要完成的剩余工作。划分原则是:需要立刻响应的、访问硬件的、对时间敏感的操作放在上半部;可以延后的数据处理、消息通知、任务操作放入下半部。
Linux 经典的下半部机制有:
- softirq:内核自身使用较多,如网络收发、块设备层。
- tasklet:基于 softirq 实现,串行执行,同一个 tasklet 不会并发执行。
- workqueue:在进程上下文执行,可以睡眠,适合较重的任务。
- threaded irq:将整个中断处理放到内核线程中执行,适合需要睡眠的中断处理场景。
实际驱动中,tasklet 和 workqueue 使用率最高。在设备树中还可以直接配置中断为线程化中断:
static irqreturn_t demo_irq_handler(int irq, void *dev_id) { /* 上半部,只做置标志和唤醒工作 */ schedule_work(&work); return IRQ_HANDLED; } static void demo_work_handler(struct work_struct *work) { /* 下半部,可以睡眠 */ } INIT_WORK(&work, demo_work_handler);回答时要能说明 tasklet 和 workqueue 的本质差异:tasklet 依然运行在中断上下文,不能睡眠;workqueue 运行在进程上下文,可以睡眠。如果面试官追问“如果你的中断处理函数要做一次 SPI 读取怎么办”,标准回答是用 threaded irq 或者把读取任务下放到 workqueue,因为 SPI 传输过程需要休眠等待。
另一个常见追问是中断申请函数的参数含义,特别是IRQF_TRIGGER_RISING、IRQF_SHARED和dev_id参数。共享中断要求所有中断处理程序都支持IRQF_SHARED,而dev_id在共享中断中用于区分具体是哪个设备触发了中断。
6. 第五问:设备树语法与驱动解析
设备树问题主要考察两部分:能不能看 DTS 文件,能不能写驱动解析 API。
基础语法要非常熟练,常见属性如下:
| 属性 | 含义 | 示例 |
|---|---|---|
| compatible | 设备兼容字符串 | "vendor,device" |
| reg | 地址资源和长度 | reg = <0x10000000 0x1000> |
| interrupts | 中断号和触发方式 | interrupts = <0 22 4> |
| status | 设备状态 | "okay"、"disabled" |
| pinctrl-* | 引脚配置 | pinctrl-0 = <&pinctrl_demo> |
| clocks | 时钟引用 | clocks = <&clk 1> |
驱动侧常用 API 也需要熟悉:
static int demo_probe(struct platform_device *pdev) { struct resource *res; void __iomem *base; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); return 0; }追问方向通常是:
devm_ioremap_resource与ioremap的区别是什么?devm_系列 API 绑定设备生命周期,设备移除或 probe 失败时自动释放,能避免资源泄漏,现代驱动首选。- 如何自定义设备树属性?通过
of_property_read_u32、of_property_read_string等接口从设备节点读取。 - 中断号如何获取?使用
platform_get_irq:int irq = platform_get_irq(pdev, 0);。
易错点有三个:一是compatible建议写成厂商前缀加设备名的形式,避免冲突;二是reg的地址是物理地址,不能直接在 C 代码里解引用;三是设备树中修改status为"disabled"后,probe 不会触发,这是排查“驱动加载但没执行”的常见原因。
7. 第六问:并发与竞态的实战排查
面试官前五问如果能顺利过关,后面就会进入嵌入式驱动岗的实战考察,也就是“给你一个具体的并发 Bug,你如何定位修复”。
题目可能如下:你的 GPIO 按键驱动在快速连续按下时,输出的按键事件经常丢失,偶尔还会出现两次按键读到的电平状态相同,你判断问题出在哪?
回答要有定位思路,分三步:
首先怀疑共享变量。如果按键状态记录在一个全局变量中,中断上半部写入、进程上下文读取,没有加锁保护,就会出现竞态。快速连续按下时,同一变量可能被多次写入,进程上下文可能在两次完整更新之间读取到不完整数据。
处理方法:引入spinlock_t或原子变量保护共享状态,并结合test_and_set_bit实现标志去重。
其次怀疑中断丢失。GPIO 中断触发方式设为上升沿或下降沿时,如果硬件没有挂起寄存器,电平变化发生在中断处理完成前,新中断就会被覆盖。解决思路是改用双边沿触发,或者在中断处理中读取并挂起 GPIO 状态寄存器,确保每次状态变化都得到响应。
最后怀疑下半部调度延迟。workqueue 调度受系统负载影响,如果按键消抖和事件上报都堆积在工作队列里,高速按键时事件就会合并或丢弃。更合理的做法是 interrupt handler 只做状态采样,按键事件存入环形缓冲区,由内核线程或 workqueue 批量上报。
这类题目充分体现驱动开发与普通应用开发的区别。候选人不一定答出标准答案,但要有清晰的排查路径:代码审查 -> 加锁 -> 看中断触发条件 -> 看任务调度时序 -> 最后用逻辑分析仪或示波器验证硬件电平。
8. 第七问:内存映射与 DMA 映射
涉及到 DMA 的问题通常面试难度会上一个台阶。面试官会问:驱动里访问寄存器用 ioremap,DMA 传输时地址怎么映射?两者有区别吗?
首先明确 ioremap 和 DMA 的关系。ioremap 是外设寄存器内存映射,访问的是 MMIO 地址空间,数据可能经过 cache,但寄存器操作通常要求绕过 cache 或保证写顺序。DMA 传输时,CPU 与外设都会访问同一块内存,所以必须解决 cache 一致性问题。
内核提供的 DMA API 分为两类:
- 一致性映射(coherent mapping):使用
dma_alloc_coherent,保证 CPU 和设备看到的访问是一致的,内部通常会分配 uncached 或 write-through 的内存区域,适合 DMA 描述符、命令缓冲区等需要持续访问的场景。 - 流式映射(streaming mapping):使用
dma_map_single或dma_map_sg,在每次传输前映射、传输后解映射,并通过dma_sync_single_for_cpu或dma_sync_single_for_device维护缓存一致性,适合大批量数据搬运。
常见代码模式:
dma_addr_t dma_handle; void *cpu_addr; cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL); if (!cpu_addr) return -ENOMEM; /* dma_handle 是给外设使用的 DMA 地址 */追问:外设拿到的 DMA 地址是物理地址吗?
准确说法是总线地址。在大多数嵌入式 SoC 上总线地址等于物理地址,但在 IOMMU 或复杂总线拓扑下,外设看到的地址可能经过映射。驱动代码应当使用 DMA API 返回的dma_addr_t,不要假设它等于物理地址。
再追问:cache 一致性问题如何检测?
典型现象是 DMA 收到的数据偶尔是旧数据,或者在 CPU 写数据后外设没有立即读到新值。需要检查是否缺少dma_sync_*调用、缓冲区是否被分配成了 cacheable。使用dma_alloc_coherent分配的内存天然规避该问题,这也是为什么它常用在关键传输路径上。
另一个高频考点是mmap实现。驱动如何把内核缓冲区映射到用户空间?使用remap_pfn_range或dma_mmap_coherent。用户空间可以直接读写缓冲区,减少数据拷贝。面试官借此考察候选人对内核地址空间和用户地址空间的理解程度。
9. 第八问:驱动的调试手段与工具链
驱动调试能力直接决定候选人是“会写”还是“会调”。面试官经常问:你的驱动加载后系统崩溃,如何定位问题?
回答要分几个层级:
第一层是日志。printk依然是驱动调试的第一手段,但要掌握分级:KERN_EMERG、KERN_ERR、KERN_WARNING、KERN_INFO、KERN_DEBUG,以及/proc/sys/kernel/printk对应的日志级别控制。动态调试dynamic_debug可以在不重新编译的情况下按文件、函数、行号开启或关闭。
第二层是文件系统接口。把运行状态暴露到sysfs或debugfs,用户空间可以用cat、echo读取或控制。debugfs是驱动调试最常用的手段:
struct dentry *d = debugfs_create_dir("demo", NULL); debugfs_create_u32("reg_val", 0644, d, ®_val); debugfs_create_file("status", 0644, d, NULL, &fops);第三层是内核动态追踪工具。条件允许时可以用ftrace跟踪函数调用、用kprobe在指定函数插入探针、用trace-cmd和perf分析调度和中断延迟。在低版本内核或资源受限环境下,devmem命令可以直接读写物理地址寄存器,是裸调硬件的常用工具。
第四层是硬件工具。驱动行为异常时,示波器、逻辑分析仪往往是最终裁决手段。比如 I2C 通信不畅,先用逻辑分析仪抓 SCL/SDA 波形,确认 ACK 位和时钟频率,再回头检查驱动里的时序设置。
面试官如果继续追问 oops 信息如何定位,应当能说出以下几点:
Unable to handle kernel NULL pointer dereference表示空指针。PC寄存器值指向的地址和Call trace中的函数名,基本可以定位到出错的 C 函数。- 使用
addr2line将 PC 地址转换为源码行号。 - 如果使用的是
CONFIG_DEBUG_INFO编译的内核,gdb可以对 vmlinux 和 ko 文件进行离线反汇编分析。
驱动的崩溃问题往往不是代码逻辑错误,而是资源未申请、指针未判空、中断注册失败但继续操作等工程化细节。这要求写驱动时每个返回都要检查,每个资源释放都要在错误路径上做完整处理。
10. 第九问:电源管理与休眠唤醒
嵌入式设备越来越关注功耗,驱动岗面试常见问题:设备驱动的 suspend/resume 流程是什么?runtime PM 是什么?
当系统进入睡眠时,内核会按照设备模型的顺序依次调用驱动的 suspend 回调,将设备设置到低功耗状态;唤醒时调用 resume 回调,恢复设备功能。举例:
static int demo_suspend(struct device *dev) { /* 保存寄存器状态,关时钟,关电源 */ return 0; } static int demo_resume(struct device *dev) { /* 重新初始化硬件,恢复寄存器 */ return 0; } static const struct dev_pm_ops demo_pm_ops = { .suspend = demo_suspend, .resume = demo_resume, };追问一:suspend 回调里不能做什么?
在系统睡眠过程中,设备可能已经进入低功耗状态,CPU 也在逐步关闭,所以 suspend 回调里不能申请锁、不能分配内存、不能做长时间阻塞操作。如果对时序有要求,建议在suspend_late和resume_early阶段处理特别敏感的设备。
追问二:runtime PM 与系统 suspend 有什么区别?
系统 suspend 是全局性的,所有设备一起进入低功耗状态;runtime PM 是单个设备在没有任务时动态进入低功耗,其他设备继续工作。驱动中使用pm_runtime_get_sync和pm_runtime_put_sync管理设备使用计数,当引用计数降到 0 时调用 runtime_suspend 回调。
追问三:如何验证电源管理功能是否正常?
使用cat /sys/power/state查看支持的睡眠状态,写入mem或standby让系统进入睡眠。然后在 resume 后检查设备是否恢复正常、中断是否丢失、DMA 是否继续工作。查看/sys/kernel/debug/pm_qos和trace跟踪 PM 事件可以进一步定位唤醒源。
面试官在这个知识点上主要考察候选人的工程意识:是否清楚系统睡眠导致的中断依赖问题、时钟关闭导致的外设挂死问题、恢复后未重新初始化寄存器的问题。这一题能答好的候选人通常都有实际调板经验。
11. 第十问:I2C / SPI / UART 驱动框架
外设驱动是嵌入式驱动岗的日常大头,面试官会从 I2C、SPI、UART 三类中挑一个深挖。
I2C 驱动要掌握i2c_driver注册流程。设备侧通常由设备树描述,驱动侧需要实现probe、remove和id_table。核心数据交互通过struct i2c_client完成,传输函数使用i2c_transfer或i2c_smbus_read/write_byte_data。一个常见代码框架:
static const struct of_device_id demo_i2c_of_match[] = { { .compatible = "vendor,xxx-sensor" }, { } }; MODULE_DEVICE_TABLE(of, demo_i2c_of_match); static struct i2c_driver demo_i2c_driver = { .probe = demo_i2c_probe, .remove = demo_i2c_remove, .id_table = demo_i2c_id_table, .driver = { .name = "demo-i2c", .of_match_table = demo_i2c_of_match, }, }; module_i2c_driver(demo_i2c_driver);追问通常包括:I2C 传输失败时应该排查什么?回答顺序是:检查设备树地址是否和原理图一致,检查总线时钟频率是否在器件支持范围内,检查 ACK 是否正常,最后看dmesg中的 -EIO、-ENXIO 错误码。
SPI 驱动则要掌握spi_driver、struct spi_device、spi_transfer和spi_message的关系。SPI 全双工传输、CS 控制模式和时钟极性配置需要清晰描述。高频错误是 SPI 模式配置错误导致数据完全错乱,排查方法是先看波形确认 CPOL/CPHA 是否匹配从机规格。
UART 驱动相对复杂,通常涉及 tty 层和 serial core。常见面试问题:为什么 UART 驱动不直接暴露file_operations给用户空间?
因为串口驱动要接入 Linux tty 子系统,通过struct uart_driver、struct uart_port和struct uart_ops三个核心结构体向上层提供标准读写作息,用户空间只需访问/dev/ttySx或/dev/ttyUSBx,驱动内部则处理 FIFO、DMA、流控、波特率等硬件细节。
面试官对外设驱动的考察重点是:框架理解、设备树匹配、收发流程和故障排查。只要能把这四条线清晰地串在一起,回答就能让面试官信服。
12. 面试官追问:如何设计一个可测试的驱动
十连问之后,有些面试官还会加一个开放性设计题:如果让你重新写这个驱动,你会做哪些改进?
这道题高分回答不是堆叠新特性,而是体现工程经验。可以从以下几个方面展开:
第一,增加 debugfs 接口。每个驱动的关键寄存器、状态变量、中断计数都可以实时导出,方便在开发板上直接排查问题。
第二,错误路径完整处理。probe 失败时要释放所有已经申请的资源,确保可以安全重新 probe。要习惯使用devm_系列接口,减少手动管理资源的负担,但不是所有资源都能用 devm 管理,例如request_irq的dev_id需要在 remove 时显式释放。
第三,增加互斥保护。所有对外可访问的接口(read/write/ioctl)都应当检查并发访问,保证多线程访问时不会破坏内部状态。
第四,考虑中断负载。如果中断频率很高,可以通过合并中断事件、使用环形缓冲、在 bottom half 中批量上报等方式降低系统负载。
第五,增加版本和兼容性控制。设备树解析时对未知属性要容错,不能在缺少某个属性时直接 panic。驱动接口要有版本字段,避免用户空间工具与新驱动不匹配时产生难以排查的行为。
这道题没有标准答案,面试官真正想听的是候选人与普通应用开发者之间的差异,也就是“你对资源、并发、错误的感知”,所以回答时最好带着真实项目里的教训来谈。
13. 秋招嵌入式驱动岗位的复习策略
最后说两点复习建议。
第一,不要把知识割裂成孤立考点。十个问题里,字符设备和 platform 总线是关联的,中断和并发是关联的,内存映射和 DMA 是关联的,外设驱动和设备树是关联的。面试官问第一个问题时,往往会在后续追问中延伸到其他知识面。所以建议画一张自己的知识链路图,比如“按键中断 -> 上半部置位 -> 下半部上报 -> 字符设备 read -> 用户空间获取事件”,整条通路的所有环节都要能讲清楚。
第二,没有真实板子时,先把手头的内核源码和文档读透。嵌入式内核源码的组织方式、driver 目录下的示例驱动、Documentation 下的驱动开发文档,都是不花钱就能获得的复习材料。重点看内核源码里 platform、i2c、spi、input、gpio 这几个子系统的代码结构,不用背代码,但要能复述框架和调用流程。
面试遇到不会的问题,不要直接沉默,可以用“我目前的理解是……,但还需要验证”来过渡。嵌入式驱动岗的面试官更关注思路是否清晰、排查路径是否合理,而不是要求候选人对所有内核实现都了如指掌。
把上面十连问逐题梳理一遍,再结合自己实际的项目经验归纳总结,进入考场时就会比只背面经的候选人有优势。建议收藏备用,在复习最后一周对照着过一遍。