目录
- 介绍
- 问题陈述
- 执行
- 总结
介绍
有时需要升级到较新版本的 linux 内核,并因此需要移植现有的设备驱动程序。
移植过程可能需要几分钟甚至更长时间。这不仅取决于驱动程序的复杂度,还取决于您要升级的内核版本(API 往往会发生变化,而所有问题都源于此),以及代码实现的质量。有时重写比移植更容易,但我们不会讨论这个问题。
遗憾的是,我无法附上驱动程序的源代码,但我们会涵盖您和我在移植过程中可能遇到的所有问题。下面,我们将看一个将简单驱动程序从内核版本 2.6.25 移植到 4.12.5 的示例,该驱动程序位于 drivers/serial/name_uart.c 中。
问题陈述
任务非常简单直接:我们需要将上述驱动程序从内核版本 2.6.25 移植到 4.12.5。
执行
首先,如果你不熟悉你正在移植的驱动程序,我建议你至少简单研究一下。这可以使任务变得容易得多。之后,你就可以开始移植了。
第一步:
- 我们的驱动程序在 2.6.25 内核中有以下路径:drivers/serial/name_uart.c现在我们需要找到一个合适的目录来放置它。
- 在这里我们遇到了第一个问题:4.12.5 内核中没有 drivers/serial/ 这样的目录。
- 解决方案很简单:只需将我们的驱动程序放在drivers/tty/serial/name_uart.c中
第二步:
- 之后,为了确保 Linux 可以在构建中包含我们的驱动程序,我们需要将它添加到两个文件中。
- 第一个文件是:drivers/tty/serial/Makefile 。
- 在其中添加以下行:
obj-$(CONFIG_SERIAL_NAME) += name_uart.o
- 第二个文件:drivers/tty/serial/Kconfig
- 我们在里面写入以下内容:
config SERIAL_NAME tristate "SERIAL_NAME UART driver" help Write description here
第三步:
- 完成前两步后,我们就可以开始构建了。
- 在根目录下,运行 make menuconfig 并将我们的驱动程序包含在构建中。
- 运行该命令后,会打开一个图形界面,在那里找到我们的驱动程序应该没有问题(您可以按 / 键并输入完整或部分名称,然后按 Enter 键进行搜索)。
- 另一种选择是直接编辑 .config 文件,并将您的驱动程序包含在构建中。
- 接下来,您可以尝试构建包含我们驱动程序的内核。
第四步:
- 尝试构建内核后,我们可能会遇到一系列错误,需要解决这些错误才能成功构建内核并确保测试驱动程序的功能。
- 我遇到的错误是由于与 proc 系统交互的接口过时以及一个宏被删除造成的。
- 例如,在内核 2.6.25 中调用 irequest_irq 函数可以正常工作,但是
irequest_irq(64 + ISC_DMA, dma_interrupt_handler, IRQF_DISABLED, "DMA", NULL);
在内核 4.12.5 中,IRQF_DISABLED 宏已被移除,导致驱动程序无法构建。
解决方案是用 0 替换 IRQF_DISABLED。
irequest_irq(64 + ISC_DMA,编程客栈 dma_interrupt_handler, 0, "DMA", NULL);
下一个 bug 是,在内核版本 2.6.25 中,与 proc 系统的交互是通过 create_prolnQWqvlLLuc_entry 函数实现的,而这个实现在内核版本 4.12.5 中已经不存在了。
因此,需要对该实现进行轻微的重写,最终版本如下:
/****************************************************************************** * /proc interface ******************************************************************************/ static int xr16_get_status(struct seq_file *m, void *v) { struct uart_name_uart *phttp://www.devze.comp; unsigned long f; u64 tmp; int i, xmax = ARRAY_SIZE(pp->in_irq); seq_printf(m, "UART NAME ports stat:\n"); for (i = 0; i < UART_NAME_MAXPORTS; i++) { pp = &uart_name_16_ports[i]; if (!pp->used) continue; local_irq_save(f); tmp = ktime_to_us(ktime_sub(ktime_get(), pp->ktm_last)); do_div(tmp, USEC_PER_SEC); local_irq_restore(f); } return 0; } static int xr16_proc_open(struct inode *ijsnode, struct file *file) { return single_open(file, uart_name_get_status, NULL); } static const struct file_operations uart_name_proc_fops = { .owner = THIS_MODULE编程, .open = uart_name_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }
总而言之,驱动程序移植可以按照以下步骤完成:
- 1. 将旧版驱动程序的源代码复制到新的 Linux 内核;
- 2. 为 Kconfig 和 Makefile 添加描述;
- 3. 使用 busybox 将驱动程序集成到内核构建中(或直接编辑 .config 文件);
- 4. 修复所有构建错误,直到内核构建成功。
总结
至此,我们介绍了将设备驱动程序移植到较新 Linux 内核的基础知识,以及您可能遇到的问题。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。
精彩评论