嵌入式 Linux 内核驱动开发【The first day: 36093万字】_linux嵌入式内核及驱动开发


由于篇幅太大以章分块按天写

嵌入式 Linux 内核驱动开发前言


本篇主要讲述嵌入式 Linux 产品开发过程中的内核/驱动开发部分相关内容包括 Linux 内核裁剪定制、驱动编写和驱动移植等。进行嵌入式 Linux 驱动开发一些特定外设需要从零开始编写驱动然而很多外设基本都有可参考驱动在实际工作中仅需进行移植本篇特 意给出了 3个驱动移植实例。


本篇一共分 11 章各章标题和内容概要如下


 第 1 章 Linux 内核裁剪和定制首先介绍了几种内核源码查看工具然后对内核目录树和相关文件进行介绍接着给出了内核配置详情以及裁剪实例
 第 2 章 Linux 设备驱动基础由浅入深的介绍了 Linux驱动编写相关知识点从内核模块、字符设备驱动平台设备驱动都有详细讲解并给出了相应的范例代码
 第 3 章 LED 子系统和驱动分析了内核中的 LED 子系统并给出了相关实现实 例
 第 4 章 GPIO 驱动分析了内核中的GPIOLIB子系统并给出了相关实现实例
 第 5 章 输入子系统和按键驱动分析了内核中的输入子系统并给出了按键驱动 实现范例
 第 6 章 I2C 总线和外设驱动分析了内核中的 I2C 子系统并给出了 I2C 接口 EEPROM 驱动实现范例
 第 7 章 SPI总线和外设驱动简要分析了 SPI 总线驱动并实现了两种典型 SPI 设备驱动
 第 8 章 UART 和 SC16IS752驱动简析了 UART 驱动子系统并对 SC16IS752 的驱动实现进行了详细分析
 第 9 章 SGTL5000声卡驱动移植介绍 SGTL5000 在 i.MX283 平台的移植过程
 第 10 章 AP6181 无线网卡驱动移植介绍 AP6181 无线网卡在i.MX283平台的移植过程
 第 11 章 SIM6360-PCIE 模块驱动移植介绍SIM6360-PCIE 模块驱动移植和 PPP 拨号上网的过程。

本篇的内容涵盖了嵌入式 Linux 产品开发过程中底层开发的大部分工作给出的实例也都具有很强的参考意义。


第1章 Linux 内核裁剪和定制

【1】Linux 内核开发简介

这里所说的“Linux 内核开发”仅仅是指嵌入式 Linux 产品开发中内核和驱动相关开发工作与 Linus所领导的内核开发团队的内核开发有很大不同。 产品开发中对内核进行二次开发需要开发人员具备如下一些基本技能和背景知识

  • 具备操作系统的基本知识理解操作系统原理最好了解 ~~Linux 操作系统~~
  • 内核绝大部分都是 C 语言编写的~~C 语言~~ 是必备技能
  • 内核是用 ~~GNU C 编写的~~ 尽管符合 ISO C89 标准但还是使用了一些 GNU 扩展所以对 GNU C 的一些扩展也必须有所了解
  • 对 ~~Linux 内核源码~~ 基本分布有大致了解
  • 产品级的内核开发通常还包括一些内核驱动工作对~~外设工作原理和驱动编写~~ 也必须有一定的了解。

【2】 Linux 源码阅读工具

俗话说“工欲善其事必先利其器”面对几百兆的 Linux 内核代码要阅读、查看或者搜索其中的代码大部分初次接触到 Linux 内核代码的开发人员都有无从下手的感觉。
下面推荐几个源码阅读和索引工具能为后续内核开发提供一些便利。

【1.2.1】Source Insight

Source Insight 是 Windows 平台下一款流行度极高的源码阅读和编辑工具。不少 Linux开发人员还是习惯于在 Windows 下进行源码编辑甚至查看和编辑 Linux 内核源码依然在 Source Insight 中完成。

注意蓝色字体的超链接是我改过的为了好看而已
安装 Source Insight 软件后新建一个工程取名并指定数据存放位置如图 1.1 所示。
在这里插入图片描述
在这里插入图片描述
然后添加源码。浏览选中 Linux 内核源码文件夹后点击“Add Tree”按钮将内核源码树的全部文件添加到工程中如图 1.3 所示。
在这里插入图片描述
添加完成即可在 Source Insight 中进行源码阅读和编辑了如图 1.4 所示。
在这里插入图片描述

【1.2.2 Eclipse】

Eclipse 是一个跨平台 IDE既能运行于 Windows 平台也能在 Linux 下运行。不少习惯于 图形界面操作的开发人员Linux 下则习惯于用 Eclipse 来查看和编辑 Linux 源码。 如果仅仅是在 Eclipse 中查看 Linux 内核源码则可以不必事先安装交叉编译器否则 则须事先安装好交叉编译器。

创建内核源码工程。点击 FileNewProject开始创建工程在工程创建界面选择创建 C 工程如图 1.5 所示。
在这里插入图片描述
点击 Next在 C Project 界面的 Project name 栏中填写工程名称去掉“Use default location”的勾点击 Browse 将 Location 设置为 Linux 内核源码目录如图 1.6 所示。如果不在 Eclipse中编译内核则使用 Linux GCC 即可否则请使用安装好的 Cross GCC
在这里插入图片描述
然后点击 Finish完成 Linux 内核源码导入在 Eclipse 中即可进行代码阅读和编辑了如图 1.7 所示。
在这里插入图片描述

在 Eclipse 中进行源码跟踪只需选择函数、变量或者宏定义后按 F3 即可。更多的操作可在 Navigate 中找到。

【1.2.3】 vim+ctags+cscope

Vi/Vim 是一个文本编辑器在 Vim 中能高效的实现代码编辑。但 Vim 的功能不仅仅是一个文本编辑器借助 ctags cscope 的配合Vim 能实现堪比图形 IDE 环境的源码编辑和阅读功能在某种程度上甚至比图形 IDE 更方便。 Vi/Vim 的安装不再介绍了。如果不是通过远程登录在远程服务器上工作而是在本地桌面系统操作还可以用 gvim 启动 Vi 编辑器

1. Taglist

Taglist 是 Vim 的一个源码浏览插件可从http://www.vim.org 网站获得。下载到压缩包后在本地解压然后将解压得到目录中的 plugin 目录复制到~/.vim 目录。如果用户主目录 下没有.vim目录则建立命令mkdir .vim一个这样的目录即可。

2. Ctags

Ctags 是一个用于产生 tags 文件的软件可以下载源码进行编译安装在 Ubuntu 下 可通过 apt-get 进行安装

$ sudo apt-get install exuberant-ctags 

3. 源码阅读和跟踪

进入准备查看的源码所在目录首先生成 tags 文件

$ ctags -R 

执行时间长短取决于源码数量的多少执行完毕在当前目录下可看到一个 tags 文件。 源码越多执行时间越长产生的 tags文件也越大。

注意如果修改了源码代码行号发生了变化需要重新生成 tags 文件。

1查看函数等定义。用 Vi/Vim 打开一个 C 文件。若想知道某个函数、变量、结构 或者宏定义在什么地方定义先将光标移动到函数变量、结构或者宏定义上然后按 CTRL+]即可。查看后按 CTRL+o
可回到原来所在位置。
2查看文件函数列表。打开C 文件后在Vi/Vim的命令状态下输入:TlistToggleVi/Vim的命令输入支持补全在 Vi/Vim 左边就会出现函数列表侧栏如图 1.8 所示。按 CTRL+ww 2 次> w可在列表和代码查看区间切换。
在这里插入图片描述
如果在本地桌面用 Gvim 打开 C 文件使用起来比较接近 IDE 集成环境。用鼠标双击函数即可跳转到函数定义的地方CTRL+鼠标右键即可回退到原来所在位置。更多实用特性还需要在实际操作中体验。

【1.2.4】 LXR

LXR 是 Linux Cross Referencer 的缩写是一个比较流行的 Linux 源码查看工具当然也不仅仅局限于查看 Linux 源码。LXR 的下载地址为http://lxr.sourceforge.net参考该网站
的安装说明很容易在本机搭建一个本地 LXR 用于源码查看。
如果不想搭建本地 LXR可以直接浏览已经搭好的 LXR 网站推荐两个网站一个是开源中国网站提供的 Linux 源码在线阅读 http://lxr.oss.org.cn另一个是http://lxr.free-electrons.com 网站前者速度较快但是提供的 Linux 内核版本较少后者则提供的版本较多。网站提供了源码阅读、关键字搜索和自由文本搜索功能。两者的网页快照分别如图 1.9 和图 1.10 所示。
在这里插入图片描述
在这里插入图片描述

【3】Linux 内核源码

【1.3.1 目录树概览】

解压 Linux 内核源码压缩包将得到内核源码。内核源码很复杂包含多级目录形成 一个庞大的树状结构通常称为 Linux源码目录树。进入源码所在目录可以看到目录树顶 层通常包含如下目录和文件
在这里插入图片描述

各个目录文件的简要说明如表 1.1 所列。

目录内容
arch/包含各体系结构特定的代码如 arm、x86、ia64、mips 等在每个体系结构目录下通常都有 -boot 内核需要的特定平台代码 -kernel 体系结构特有的代码 -lib 通用函数在特定体系结构的实现 -math-emu 模拟 FPU 的代码在 ARM 中使用 mach-xxx 代替 -mm 特定体系结构的内存管理实现 -include 特定体系的头文件
block/存放块设备相关代码
crypto/存放加密、压缩、CRC 校验等算法相关代码
Documentation/存放相关说明文档很多实用文档包括驱动编写
drivers/存放 Linux 内核设备驱动程序源码。驱动源码在 Linux 内核源码中站了很大比例常见外设几乎都有可参考源码对驱动开发而言该目录非常重要。该目录包含众多驱动目录按照设备类别进行分类如 char、block、input、i2c、spi、pci、usb
firmware/存放处理器相关的一些特殊固件
fs/存放所有文件系统代码如 fat、ext2、ext3、ext4、ubifs、nfs、sysfs
include/存放内核所需、与平台无关的头文件与平台相关的头文件已经被移动到 arch 平台的include 目录如 ARM 的头文件目录<arch/arm/include/asm/>
init/包含内核初始化代码
ipc/存放进程间通信代码
kernel/包含 Linux 内核管理代码
lib/库文件代码实现
mm/存放内存管理代码
net/存放网络相关代码
samples/存放提供的一些内核编程范例如 kfifo后者相关用户态编程范例如 hidraw
srcipts/存放一些脚本文件如 menuconfig 脚本
security/存放系统安全性相关代码
sound存放声音、声卡相关驱动
tools/编译过程中一些主机必要工具
usr/cpio 相关实现
virt/内核虚拟机 KVM

Linux 内核源码数量很庞大解压后大约好几百兆字节要能在如此庞大的源码中找到 有效代码熟悉 Linux 源码目录树的结构是基本要求。每个目录所包含的代码量差异也很大 下面是从 http://www.kernel.org 下载的一份源码解压后的统计结果其中drivers目录几乎占了源 码总量的一半arch 目录也差不多有 1/4
在这里插入图片描述

【1.3.2】 快速确定主板关联代码

拿到一份源码和一块评估板如何快速找到与这块板相关的源码是很多研发人员都曾遇到过的问题。如果对内核源码结构有大概了解要完成这些事情也不难通常可按照基础代码、驱动代码和其它代码等方面来梳理。

1. 基础代码

Linux
移植通常分为体系结构级别移植、处理器级别移植和板级移植各级别移植难易程度差异很大工作量和调试方式也各不相同。一般的产品开发人员所进行的内核移植通常都是板级移植这是几个级别中最简单的。
从代码层面来看通常把能让一个主板最小系统能运行的代码称为基础代码这部分代码通常包含体系结构移植代码、处理器核心代码以及板级支持包的部分代码。理清了这部分代码对于了解和掌握整个主板相关代码具有重要意义。

确定主板名称和默认配置文件。

例如对于 EPC-28x 工控板其对应的默认内核配置 文件为<arch/arm/configs/ EPC-M28x_defconfig。通常来说一个评估板的内核默认配置文件名称与评估板的名称相同或者有关联。确定了配置文件后可用任何文本编辑器打开该配 置文件可以对配置的选项进行查看或者进行 make menuconfig 配置进入配置界面查看。

确定对应的主板文件。

在 ARM Linux 移植代码中每个评估板通常都有一个对应的主 板文件在<arch/arm/mach-xxx/>目录下。大多数主板文件都以“board-”开头采用 “board-xxx.c”这样的文件名例如<arch/arm/mach-omap2/board-am335xevm.c>也有以 “mach-”开头的如<arch/arm/mach-mxs/mach-mx28evk.c>。通常来说一个评估板的主板 文件名称与评估板的名称相同或者有关联。


如果遇到名称特征不是很明显不能确定的情况则建议打开默认配置文件找到“CONFIG_MACH_XXX=y”这一行确定主板对应的配置开关变量。然后打开<arm/arm/mach -xxx/Makefile>文件根据配置开关变量来确定主板文件。例如<arch/arm/mach-pxa/Makefile>文件中有如下内容

# Intel/Marvell Dev Platforms 
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o 
obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o 
obj-$(CONFIG_MACH_ZYLONITE300) += zylonite.o zylonite_pxa300.o 

可以看到这几个主板文件命名都既不是以“board-”开头也不是以“mach-”开头 对于这种情况通过 Makefile文件来确定一下是比较好的做法。特别是对于主板开关变量 对应非单一文件的更需要查看 Makefile来确定关联文件否则有可能遗漏某个文件造 成代码阅读理解上的障碍。如 CONFIG_MACH_ZYLONITE300 对应着 zylonite.c 和 zylonite _pxa300.c 两个 C 文件

2. 驱动代码

Linux 内核源码中接近一半的代码量是驱动对某一个特定主板的系统而言驱动也占据很大的比例底层开发的很大一部分是驱动相关工作。掌握从众多驱动中找到正确的驱动 源码文件并根据产品的实际需求进行修改调整的方法能有效促进产品开发的进度。 Linux 内核源码树 drivers 目录很复杂包含了各种外设的驱动。对嵌入式 Linux 开发而 言通常需要关注的目录如表 1.2 所列。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

熟悉各类驱动在源码树中的大概位置能帮助在开发过程中快速进行驱动源码查找和定位。一个系统到底用了哪些代码与系统本身外设相关也与主板配置文件相关。

【4】 Linux 内核中的 Makefile 文件

本节不对内核的 Makefile 文件进行深入展开更多语法和说明请阅读<Documentation /kbuild/makefiles.txt>文件

【1.4.1】 顶层 Makefile

源码目录树顶层 Makefile 是整个内核源码管理的入口对整个内核的源码编译起着决定性作用。编译内核时顶层 Makefile 会按规则递归历遍内核源码的所有子目录下的Makefile 文件完成各子目录下内核模块的编译。熟悉一下该 Makefile对内核编译等方面会有所帮助。

1. 内核版本号
打开顶层 Makefile开头的几行记录了内核源码的版本号通常如下所示

VERSION = 2 
PATCHLEVEL = 6 
SUBLEVEL = 35 
EXTRAVERSION =3 

说明代码版本为 2.6.35.3编译得到的内核在目标板运行后输入 uname -a 命令可以得 到印证

# uname -a 
Linux boy 2.6.35.3-571-gcca29a0-gd431b3d-dirty #22 PREEMPT Tue Oct 27 20:12:33 CST 2015 armv5tejl 
GNU/Linux

2. 编译控制

  • 1体系结构

Linux 是一个支持众多体系结构的操作系统在编译过程中需指定体系结构以与实际 平台对应。在顶层 Makefile 中通过变量 ARCH 来指定

ARCH ?= $(SUBARCH) 

如果没有在编译命令行中指定 ARCH 参数系统将会进行本地编译通过获取本机信 息来自动指定

SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ 
 -e s/arm.*/arm/ -e s/sa110/arm/ \ 
 -e s/s390x/s390/ -e s/parisc64/parisc/ \ 
 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ 
 -e s/sh[234].*/sh/ ) 

如果进行 ARM 嵌入式 Linux 开发则必须指定 ARCH 为 arm注意大小写须与 arch/ 目录下的 arm 一致如

$make ARCH=arm 

当然也可以修改 Makefile将修改为 ARCH ?= $(SUBARCH)修改为 ARCH = arm在 命令行直接 make即可。

  • 2编译器

如果不是进行本地编译则须指定交叉编译器通过CROSS_COMPILE来指定。Makefile 中与交叉编译器的指定如下

CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) 
…… 
AS = $(CROSS_COMPILE)as 
LD = $(CROSS_COMPILE)ld 
CC = $(CROSS_COMPILE)gcc 
CPP = $(CC) –E 
AR = $(CROSS_COMPILE)ar 
NM = $(CROSS_COMPILE)nm 
STRIP = $(CROSS_COMPILE)strip 
OBJCOPY = $(CROSS_COMPILE)objcopy 
OBJDUMP = $(CROSS_COMPILE)objdump 

CONFIG_CROSS_COMPILE 是一个配置选项可在内核配置时候指定。如果在配置内核时候没有指定 CONFIG_CROSS_COMPILE也没有在编译参数指定 CROSS_COMPILE则会采用本地编译器进行编译。


进行 ARM 嵌入式 Linux 开发必须指定交叉编译器可以在内核配置通过 CONFIG _CROSS_COMPILE 指定交叉编译器也可以通过 CROSS_COMPILE 指定。假定使用的交 叉编译器是 arm-linux-gnueabihf-gcc则指定 CROSS_COMPILE 为 arm-linux-gnueabihf-

$ make ARCH=arm CROSS_COMPILE= arm-linux-gnueabihf- 

或者在 Makefile 中直接指定 CROSS_COMPILE 的值

CROSS_COMPILE = arm-linux-gnueabihf- 

注意CROSS_COMPILE 指定的交叉编译器必须事先安装并正确设置系统环境变量如果没有设置环境变量则需使用绝对地址例如

CROSS_COMPILE =/home/ctools/linux-devkit/bin/arm-linux-gnueabihf- 

如果同时指定了 ARCHCROSS_COMPILE则在编译的时候只需简单的 make 就可以了。

【1.4.2】 子目录的 Makefile

在内核源码的子目录中几乎每个子目录都有相应的 Makefile 文件管理着对应目录下的代码。对该目录的文件或者子目录的编译控制Makefile 中有两种表示方式一种是默认选择编译用 obj-y 表示如

obj-y += usb-host.o # 默认编译 usb-host.c 文件 
obj-y += gpio/ # 默认编译 gpio 目录 

另一种表示则与内核配置选项相关联编译与否以及编译方式取决于内核配置例如

obj-$(CONFIG_WDT) += wdt.o # wdt.c 编译控制 
obj-$(CONFIG_PCI) += pci/ # pci 目录编译控制 

是否编译wdt.c文件或者以何种方式编译取决于内核配置后的变量 CONFIG_WDT值如果在配置中设置为[*]静态编译到内核如果配置为[M]则编译为 wdt.ko 模块否则不编译。


说明受控目标是一个目录obj-y 并不直接决定受控目录的文件以及子目录的文件仅仅是与受控目录 Makefile 交互实际编译控制在受控子目录的 Makefile 中。例如“obj-y += gpio/”最终 gpio 目录下哪些文件被编译完全取决于 gpio 目录下的 Makefile。“obj-$(CONFIG_PCI) += pci/”的含义同理。

【5】 Linux 内核中的 Kconfig 文件

本节不对内核的 Kconfig 文件进行深入展开更多 Kconfig 语法和说明请阅读
<Documentation/kbuild/kconfig-language.txt><Documentation/kbuild/kconfig.txt>

内核源码树每个目录下都还包含一个 Kconfig 文件 用于描述所在目录源代码相关的内核配置菜单各个目录的 Kconfig文件构成了一个分布式的内核配置数据库。通过 make menuconfigmake xconfig 或者 makegconfig命令配置内核的时候从 Kconfig 文件读取菜 单配置完毕保存到文件名为.config 的内核配置文件中供Makefile 文件在编译内核时使用。

【1.5.1】 Kconfig 基本语法

如程序清单 1.1 所示代码摘自<drivers/char/Kconfig>文件是一个比较典型的 Kconfig文件片段包含了 Kconfig 的基本语法。

menu "Character devices" 
 
source "drivers/tty/Kconfig" 
 
config DEVKMEM 
 bool "/dev/kmem virtual device support" 
 default y 
 help 
 Say Y here if you want to support the /dev/kmem device. The 
 /dev/kmem device is rarely used, but can be used for certain 
 kind of kernel debugging operations. 
 When in doubt, say "N". 
 …… 
endmenu 

1. 子菜单

通过menuendmenu来定义一个子菜单程序清单 1.1 所示代码定义了一个“Character devices”子菜单子菜单在界面中用“—>”表示如图 1.11 所示。
在这里插入图片描述
子菜单的菜单项则由config来定义随后的“bool”、“default”、“help”等都是该菜单项的属性

config DEVKMEM 
 bool "/dev/kmem virtual device support" 

这两行语句定义了一个bool选项.config中的配置变量名称为CONFIG_DEVKMEM选项提示信息为“/dev/kmem virtual device support”在内核配置界面的实际表现为

[*] /dev/kmem virtual device support 

由于设置其默认属性 default 为 y所以该选项默认选中。
help 引出帮助信息在内核配置界面选择选项后通过<Help>可以查看帮助信息。

2. 属性

类型定义每个菜单项都必须定义类型可选类型有bool、tristate、string、hex 和 int 各类型描述如表 1.3所列。
在这里插入图片描述
定义选项的类型后面可以加菜单信息用引号“”给出留空则不加提示信息。


对于布尔型选项在配置界面用[ ]表示

 [*] /dev/kmem virtual device support 

[*]表示选中对应 CONFIG_XXX=y[ ]则表示未选中。

对于三态选项在配置界面用< >表示

 <*> Kernel .config support 

<*>表示选中对应 CONFIG_XXXx=y<M>表示编译为模块对应 CONFIG_XXX=m < >表示未选中。 子菜单也可同时设置类型如下列代码在定义 PWM 菜单的同时定义了菜单属性为三态

menuconfig GENERIC_PWM 
 tristate "PWM Support" 
 default n 
 help 
 Enables PWM device support implemented via a generic 
 framework. If unsure, say N. 

在配置界面表现为

 < > PWM Support ---> 

说明子菜单的配置值会影响其子选项的可能值。例如三态子菜单配置为则其三 态子选项依旧可有 3种可能值即可配置为、或者不选中而三态子菜单配置为 则其子选项只有和不选中两种状态可用。
默认值有写选项可以设置默认值无论是哪种类型都可以通过 default 设置其默认值例如

config ARM 
 bool 
 default y 
 select HAVE_AOUT 

选中前面这个示例的 select表示了一种选中关系即选中某个选项后会自动选中 某个或者某些选项。
前面这个示例表明选中 ARM后会自动选中HAVE_AOUT。 依赖关系如果一个选项能否生效与否与其它选项的设置有关则必须通过 depends on 来声明这种依赖关系。例如只有使能了 SMP 才能设置 CPU 个数变量 NR_CPUSKconfig中则写成

config NR_CPUS 
 int "Maximum number of CPUs (2-32)" 
 range 2 32 
 depends on SMP 
 default "4" 

帮助通过 help 关键字引入帮助帮助的正文必须另起一行。
菜单选项属性的每个关键字必须用 TAB 键行首隔开不能用等数的空格替代。

3. 目录层次迭代

通过source可以直接引用下级目录的 Kconfig 文件形成新的菜单项或者子菜单这样方便每个目录独立管理各自的配置内容。“source "drivers/tty/Kconfig"”就是直接引用 <drivers/tty/Kconfig>文件形成更多菜单项。

【1.5.2】 配置项和配置开关

通过config 定义的菜单配置项在内核配置后会产生一个以“CONFIG_”开头的配置开关变量该开关变量可在·Makefile 中或者源代码中使用。
例如“config BAR”将会产生一个开关变量 CONFIG_BAR在 Makefile 中可以这么使用

obj-$(CONFIG_BAR) += file_bar.o 

在源代码中可用这个开关变量来进行一些条件处理例如

#if defined (CONFIG_BAR) 
 实际处理代码 
#endif 

如果定义的 BAR 是三态变量则还可以根据需要这样使用

#if defined (CONFIG_BAR) || defined (CONFIG_BAR_MODULE) 
 实际处理代码 
#endif 

【6】 配置和编译 Linux 内核

对内核进行正确配置后才能进行编译。配置不当的内核很有可能编译出错或者不能正确运行。

【1.6.1】 快速配置内核

进入 Linux 内核源码数顶层目录输入make menuconfig命令可进入如图 1.12 所示的 基于 Ncurses 的 Linux 内核配置主界面注意主机须安装 ncurses 相关库才能正确运行该 命令并出现配置界面。如果没有在 Makefile 中指定 ARCH则须在命令行中指定

$ make ARCH=arm menuconfig 

在这里插入图片描述
在这里插入图片描述

配置完毕将光标移动到配置界面末尾选中“Save an Alternate Configuration File”后回车保存当前内核配置默认配置文件名为.config如图 1.13 所示。
在这里插入图片描述
保存完毕选择退出内核配置界面回到终端命令行。
当然也可以将配置文件命名为其它文件名如 config-bak 等但该配置不会被 Makefile
文件使用Makefile 默认使用文件名为.config 的配置文件所以重新命名配置文件通常在保留或者备份内核配置信息时使用。 也可以不用“Save an Alternate Configuration File”操作连按 ESC 或选择退出内核配置界面将会出现如图 1.14 所示的保存配置提示信息选择后回车内核配置将会被保存为.config 文件。
在这里插入图片描述
备份内核配置在命令行下将.config 文件复制为其它文件名来得更简单快捷

$ cp .config config-bak 

装载某个配置文件可在配置界面选中“Load an Alternate Configuration File”然后填 入已存在的配置文件名称。也可在命令行下将配置文件复制为.config

$ cp config-bak .config 

<arch/arm/configs/>目录下有很多*_defconfig 文件这些都是内核的预设配置文件分别对应各种不同的参考板。如果要使用其中的配置文件作为内核编译配置可用“make xxx_defconfig”命令来完成。对于已经设定好的内核配置也可以命名为某个文件名放到 <arch/arm/configs/>目录下在以后直接用 make 来调用该配置即可。例如将当前配置命名为 m3352_defconfig 并放到<arch/arm/configs/>目录下后续只需执行下列命令即可使用当前配 置

$ make m3352_defconfig 或者 
$ make ARCH=arm CROSS_COMPILE= arm-linux-gnueabihf- m3352_defconfig 

【1.6.2】 内核配置详情

Linux 内核配置菜单比较复杂下面对一些比较重要的配置界面进行介绍更多的详细配置建议进行实际操作。另外由于 Linux 内核版本差异实际看到的内核配置界面可能与本节的介绍有所差异。
图 1.12 所示的内核配置主界面实际包含了如表 1.4 所列的各项一级菜单。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一级菜单下的每一项几乎都有复杂的下级子菜单各自的配置选项也很丰富每项的意义也各不相同如果逐一进行描述将会是一件非常繁琐的事。而实际产品开发中并不需要完全了解内核的每一个配置项通常只需要了解其中一些相关项即可。

1. 通用设置

进入 General setup 是内核通用设置菜单界面菜单选项众多通常可以关注表 1.5 所列 选项。
在这里插入图片描述

2. 内核特性

Kernel Features 是内核特性配置菜单常用选项介绍如表 1.6 所列。
在这里插入图片描述
在这里插入图片描述

3. 启动选项

启动选项一般关心内核启动参数设置即可可设置默认启动参数和内核参数类型。 默认启动参数通过“Default kernel command string”设置例如

(root=/dev/mmcblk0p2 rootwait console=ttyO0,115200) Default kernel command string 

内核参数类型通过 Kernel command line type 来设置可选值

( ) Use bootloader kernel arguments if available 
( ) Extend bootloader kernel arguments 
( ) Always use the default kernel command string 

如果设置为“Always use the default kernel command string”则只能使用默认内核启动参数通常会设置为“Use bootloader kernel arguments if available”可接受 Bootloader 传递的参数启动。

4. 网络支持

网络支持部分包括了以太网、CAN、红外、蓝牙、无线等各种网络的支持配置选项。 网络选项配置。从 Networking support Networking options可进入网络选项配置界面 网络的配置很复杂常用的一些配置选项和说明如表 1.7 所列。
在这里插入图片描述
在这里插入图片描述
通常来说使用Linux的系统都会用到网络而使用网络又往往离不开 TCP/TP故建 议在配置中选中 TCP/IP选项并选中下级全部选项配置后的 TCP/IP 选项如程序清单 1.2 所示。


程序清单 1.2 TCP/IP 配置

[*] TCP/IP networking 
[*] IP: multicasting 
[*] IP: advanced router 
[*] FIB TRIE statistics 
[*] IP: policy routing 
[*] IP: equal cost multipath 
[*] IP: verbose route monitoring 
[*] IP: kernel level autoconfiguration 
[*] IP: DHCP support 
[*] IP: BOOTP support 
[*] IP: RARP support 
<*> IP: tunneling 
<*> IP: GRE demultiplexer 
<*> IP: GRE tunnels over IP 
[*] IP: broadcast GRE over IP 
[*] IP: multicast routing 
[*] IP: multicast policy routing 
[*] IP: PIM-SM version 1 support 
[*] IP: PIM-SM version 2 support 
[*] IP: ARP daemon support 
[*] IP: TCP syncookie support 
<*> IP: AH transformation 
<*> IP: ESP transformation 
<*> IP: IPComp transformation 
<*> IP: IPsec transport mode 
<*> IP: IPsec tunnel mode 
<*> IP: IPsec BEET mode 
<*> Large Receive Offload (ipv4/tcp) 
<*> INET: socket monitoring interface 
[*] TCP: advanced congestion control ---> 
[*] TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL) 
<M> The IPv6 protocol ---> 

这些配置中三态选项也可以配置为<M>在需要的时候再插入模块
对于 IPv6现在已经有不少应用需求建议配置为并选中配置菜单中的全部选项在需要的时候再插入模块。
特别说明一下CAN的配置选项。CAN-Bus 相关协议支持以及 CAN 设备驱动配置项都在这里并没有将 CAN 设备驱动放在 drivers 配置菜单中。CAN-Bus 子系统配置界面如图
1.15 所示。
在这里插入图片描述
其中的“CAN Device Drivers”子菜单下可选择具体的 CAN 设备如图 1.16 所示。具体选择哪个 CAN 设备驱动与具体的硬件平台相关。
在这里插入图片描述

5. 设备驱动

Linux 内核支持众多外设设备驱动程序很多配置界面也很复杂有众多配置项如 表 1.8 所列。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. 文件系统

进入 File systems是内核文件系统配置界面可以看到很多文件系系统配置选项如 图 1.17 所示。
在这里插入图片描述

一个完整的嵌入式 Linux 系统往往会支持多种文件系统但绝非“File systems”菜单下的全部。这里仅对当前主流系统比较常用的一些文件系统配置项进行介绍如表 1.9 所列。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

【1.6.3】 编译内核

内核配置完成输入 make 命令即可开始编译内核。如果没有修改 Makefile 文件并指定 ARCHCROSS_COMPILE参数则须在命令行中指定

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- 

目前大多数主机都是多核处理器为了加快编译进度可以开启多线程编译在 make 的时候加上“-jN”即可N 的值为处理器核心数目的 2倍。例如对于 I7 4 核处理器可将 N 设置为 8

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- -j8 

采用多线程编译的优点是能加快编译进度缺点是如果内核中有错误某个编译线程遇到错误终止了编译而其它编译线程却还在继续出错线程的错误提示通常会被其它编译线 程的输出信息淹没不利于排查。对于这种情况则建议改为单线程编译直到错误排除。


如果编译不出错编译完成会生成 vmlinux、Image、zImage 等文件各文件说明如 表 1.10 所列。
在这里插入图片描述

1. zImage

zImage是通常情况下默认的压缩内核可以直接加载到内存地址并开始执行。它从 <arch/arm/boot/compressed/vmlinux>文件经过 objcopy 处理得到。在 ARM Linux 下最终生成 zImage 的各个参数记录在<arch/arm/boot/.zImage.cmd>文件中。AM3352 内核生成 zImage
实际参数为

cmd_arch/arm/boot/zImage := /home/ctools/i686-arago-linux/usr/bin/arm-linux-gnueabihf-objcopy -O binary 
-R .comment -S arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage 

说明 1路径信息与实际具体编译环境有关。
说明 2如果在 64 位 ubuntu 下编译 Linux 内核在编译过程中很有可能出现
“arm-fsl-linux-gnueabi/bin/as: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory”这样的错误这是因为没有正确安装libz库所致
可“sudo apt-get install zlib1g:i386”命令安装解决。


2. uImage

对于 ARM Linux 系统大多数采用U-Boot引导很少直接使用 zImage 映像实际上更多的是 uImage。uImage 是 U-Boot 默认采用的内核映像文件它是在 zImage 内核映像之前加上了一个长度为 64 字节信息头的映像。这 64 字节信息头包括映像文件的类型、加载位置、生成时间、大小等信息可参考 U-Boot 源码<include/image.h>文件的 image_header_t 数据结构定义。进入<arch/arm/boot/>目录用 ls 命令查看uImage 文件大小比 zImage 大 64字节

$ cd arch/arm/boot 
$ ls -la Image zImage uImage 
-rwxrwxr-x 1 chenxibing chenxibing 6460852 Jul 25 09:24 Image 
-rw-rw-r-- 1 chenxibing chenxibing 3135544 Jul 25 09:24 uImage 
-rwxrwxr-x 1 chenxibing chenxibing 3135480 Jul 25 09:24 zImage 

在 U-Boot 下通过 bootm 命令可以引导 uImage 映像文件启动。

3. mkimage 工具

zImage生成uImage需要 用到 mkimage 工具。该工具可在编译 U-Boot 源码后从 tools 目录下获得复制到系统/usr/bin 目录即可对于 Ubuntu 系统还可用 sudo apt-get install u-boot-tools 命令安装得到。进入 mkimage 文件所在目录执行该文件或者在安装 mkimage 工具后直接在终端输入 mkimage 命令可以得到 mkimage 工具的用法

$ ./mkimage 或者 mkimage 
Usage: ./mkimage -l image 
 -l ==> list image header information 
 ./mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image 
 -A ==> set architecture to 'arch' 
 -O ==> set operating system to 'os' 
 -T ==> set image type to 'type' 
 -C ==> set compression type 'comp' 
 -a ==> set load address to 'addr' (hex) 
 -e ==> set entry point to 'ep' (hex) 
 -n ==> set image name to 'name' 
 -d ==> use image data from 'datafile' 
 -x ==> set XIP (execute in place) 
 ./mkimage [-D dtc_options] -f fit-image.its fit-image 
 ./mkimage -V ==> print version information and exit 

使用 mkimage 工具根据 zImage 制作 uImage 映像文件的命令如下

$ mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image 

命令参数中需要指定体系结构、操作系统类型、压缩方式和入口地址等信息各参数说明如表 1.11 所列。
在这里插入图片描述

对于EPC-28x处理器内存起始地址为 0x40000000从 zImage 生成 uImage 映像文件的命令实际操作范例

$ mkimage -A arm -O linux -T kernel -C none -a 0x40008000 -e 0x40008000 -n 'Linux-2.6.35' -d 
arch/arm/boot/zImage arch/arm/boot/uImage 

说明内存地址与处理器相关在不同处理器上可能有差异。
mkimage 除了可以制作 uImage 映像文件之外还可以查看一个 uImage 映像文件的文件头信息用法

$ mkimage -l uImage_file 

例如用 mkimage 工具查看 EPC-28x 工控主板的 uImage 内核映像可以得到如下信息

$ mkimage -l uImage 
Image Name: Linux-2.6.35.3-571-gcca29a0-g191 
Created: Tue Nov 17 11:57:47 2015 
Image Type: ARM Linux Kernel Image (uncompressed) 
Data Size: 2572336 Bytes = 2512.05 kB = 2.45 MB 
Load Address: 40008000 
Entry Point: 40008000 

如果只有zImage内核映像文件需要转换成 uImage 映像文件则只能通过上述命令来实现。但是如果有内核源码那生成 uImage 的方法就简单很多。实际上Linux 内核已经支持直接生成 uImage 格式映像文件在<arch/arm/boot/Makefile>文件中给出了uImage的生
成规则

quiet_cmd_uimage = UIMAGE $@ 
 cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \ 
 -C none -a $(LOADADDR) -e $(STARTADDR) \ 
 -n 'Linux-$(KERNELRELEASE)' -d $< $@ 

生成 uImage 的编译命令为 make uImage

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- -j8 uImage 

在 ARM Linux 下最终生成uImage的各个参数记录在<arch/arm/boot/.uImage.cmd>文件中。对于在 EPC-28x 的 Linux 内核实际参数为

cmd_arch/arm/boot/uImage := /bin/bash /home/vmuser/prj/m28x/kernel/linux-2.6.35.3/scripts/mkuboot.sh -A arm 
-O linux -T kernel -C none -a 0x40008000 -e 0x40008000 -n 'Linux-2.6.35.3-571-gcca29a0-g1914ba0' -d 
arch/arm/boot/zImage arch/arm/boot/uImage 

4. 编译内核模块

如果内核中有配置为<M>的模块或者驱动需要在编译内核后再通过 make modules 命 令编译这些模块或者驱动

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- modules

编译得到的内核模块文件以“.ko”结尾这些可以通过insmod命令插入到运行的内核中。
有的模块编译得到单一的“.ko”文件且不依赖于其它模块这样的模块可以直接用insmod 命令插入系统而不会出现错误。
有的模块则可能编译后得到多个“.ko”文件或者依赖于其它模块文件且各文件插入还有顺序要求这就是常说的模块依赖。对于这样的情况用 insmod 命令手工尝试得到依赖关系然后按顺序插入也是可以的但不推荐这样做毕竟很麻烦。
建议编译模块后再通过 make modules_install 命令安装模块可将编译得到的全部模块安装到某一目录下并且还会生成模块的依赖关系文件。默认情况下会将内核模块安装到编译机器的“/”目录下这一方面需要root权限另一方面容易与主机文件混淆。建议通过INSTALL_MOD_PATH参数指定模块安装路径

$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabiINSTALL_MOD_PATH=/home/chenxibing/work/rootfs
modules_install 

安装后将在安装目录下生成“lib/modules/内核版本/”目录该目录下通常有下列文件 和目录
在这里插入图片描述


所有的内核模块都在kernel目录下modules.dep 是全部模块的依赖关系文件。将“lib/modules/内核版本/”复制到目标系统后根目录后就可以用 modprobe 命令进行模块安装而不用手工逐一加载各个模块。该文件内容多少与内核模块多少相关现在摘取一个实例片段进行说明

kernel/drivers/net/bonding/bonding.ko: (1) 
kernel/drivers/usb/serial/usbserial.ko: (2) 
kernel/drivers/usb/serial/ftdi_sio.ko:kernel/drivers/usb/serial/usbserial.ko (3) 

每行开头至冒号(:)之前的表示一个内核模块冒号之后的表示该模块所依赖的其它模块 必须先加载后面的模块才能加载该模块文件。冒号后面为空则表示该模块没有依赖关系。 第(1)行表示模块文件 bonding.ko 没有依赖关系可以直接用 insmod 命令加载到内核中

# insmod kernel/drivers/net/bonding/bonding.ko 

用 insmod 加载模块必须指明文件路径否则不能加载。用 modprobe 命令加载则无需 带路径

# modprobe bonding 

第(2)和(3)则共同说明了模块文件ftdi_sio.ko依赖于usbserial.ko文件usbserial.ko 没有依赖文件。用 insmod 命令用法如下

# indmod kernel/drivers/usb/serial/usbserial.ko 
# insmod kernel/drivers/usb/serial/ftdi_sio.ko 

用 modprobe 命令就简单了

# modprobe ftdi_sio 

1.6.4 运行内核

得到 uImage 映像文件后将 uImage 加载到内存地址ep-0x40处通过 bootm 命令即可 运行内核

# tftp 40007fc0 uImage 
# bootm 40007fc0 

uImage 启动会打印文件头信息并进行校验和计算校验通过后开始内核自解压并运行

## Booting kernel from Legacy Image at 40007fc0 ... 
 Image Name: Linux-2.6.35.3-571-gcca29a0-gd43 
 Image Type: ARM Linux Kernel Image (uncompressed) 
 Data Size: 2653928 Bytes = 2.5 MB 
 Load Address: 40008000 
 Entry Point: 40008000 
 Verifying Checksum ... OK 
 Loading Kernel Image ... OK 
OK 
 
Starting kernel ... 
 
Uncompressing Linux... done, booting the kernel. 
…… 
以下省略 

【7】 Linux 内核裁剪实例

从零开始配置内核是不明智的建议在某一个默认配置的基础上进行修改以达到自己 产品的实际需求。 裁剪和配置内核的基本原则

 基于某一个最接近的主板配置来修改 
 必须的、能确定的选项选中 
 不能确定的则不要改变原来配置 
 可选可不选的建议根据 help 信息决定或者不选 
 一次改动不要太多渐进式修改和验证 
 注意及时备份配置文件出现意外可以回退恢复。 

下面给出一些常见功能的配置裁剪实例很多功能与所采用的主板硬件相关与其它不 同主板的内核配置上不一定完全相同但还是有一些参考意义。

【1.7.1】 GPIO 子系统配置

Linux 2.6 以上内核引入了子系统 GPIO 子系统将全部 GPIO 的操作接口都通过 “/sys/class/gpio/” 目录导出非常方便用户使用。 输入下列命令进入内核配置菜单

$ make ARCH=arm menuconfig 

在主菜单界面中选择“Device Drivers”

 [*] Networking support ---> 
 Device Drivers ---> 
 File systems ---> 
 Kernel hacking ---> 

进入“Device Drivers”界面选择并进入“GPIO Support”

 [*] SPI support ---> 
 PPS support ---> 
 PTP clock support 
 -*- GPIO Support ---> 
 <*> PWM Support ---> 

在“GPIO Support”中选中“/sys/class/gpio…”

--- GPIO Support 
 [*] /sys/class/gpio/... (sysfs interface) 
 *** Memory mapped GPIO drivers: *** 

配置后重新编译内核使用新内核的系统即可通过“/sys/class/gpio/”访问系统的 GPIO了。

【1.7.2 】LED 子系统配置

Linux LED 子系统提供了“/sys/class/leds/”的访问接口启用 LED 子系统能很方便地 操作系统的 LED 资源。

在“Device Drivers”配置界面选中“LED Support”支持

<*> MMC/SD/SDIO card support ---> 
< > Sony MemoryStick card support (EXPERIMENTAL) ---> 
[*] LED Support ---> 
[ ] Accessibility support ---> 

进入“LED Support”子菜单选中 LED 类支持和 LED 触发器支持并根据需要设置触发器

--- LED Support 
[*] LED Class Support 
 *** LED drivers *** 
... 
[*] LED Trigger support 
 *** LED Triggers *** 
<*> LED Timer Trigger 
<*> LED Heartbeat Trigger 
< > LED backlight Trigger 
<*> LED GPIO Trigger 
<*> LED Default ON Trigger 

只要将系统的 LED 设备驱动添加到 LED 子系统中即可通过“/sys/class/leds/”接口来进行访问。

【1.7.3】 串口配置

串口是嵌入式 Linux 必不可少的外设默认控制台通常就是串口所以必须在内核中使能串口以及串口控制台支持。
在“Device Drivers”配置界面选择“Character devices”

Input device support ---> 
 Character devices ---> 
 -*- I2C support ---> 

进入“Character devices”配置菜单选择“Serial drivers

[*] /dev/kmem virtual device support 
 Serial drivers ---> 
 [ ] ARM JTAG DCC console 

进入“Serial drivers”在配置界面进行串口控制器配置。嵌入式 Linux 默认控制台是串口所以还需使能串口控制台支持。串口控制器与具体处理器相关需要根据硬件进行选择很多处理器移植代码会默认选中自身的串口驱动支持例如 EPC-28x已经默认选中了“i.MXS Application serial port support

<M> 8250/16550 and compatible serial support 
 *** Non-8250 serial port support *** 
<*> i.MXS debug serial port support 
<*> i.MXS Application serial port support 

【1.7.4】 USB Host 驱动配置

USB 可以外接多种设备不同设备的驱动配置也是不同的。下面以常用的 U 盘、USB鼠标键盘配置为例进行介绍。

1. 使用 U 盘

U 盘在 Linux 系统下被认为是 SCSI 设备所以必须在内核中选择支持 SCSI。在主菜单 界面选择“Device Drivers”进入设备驱动配置界面选择“SCSI device support

[*] Block devices ---> 
[*] Misc devices ---> 
 SCSI device support ---> 
< > Serial ATA and Parallel ATA drivers ---> 

进入“SCSI device support”配置界面进行如下配置

< > RAID Transport Class 
<*> SCSI device support 
< > SCSI target support 
[*] legacy /proc/scsi/ support 
 *** SCSI support type (disk, tape, CD-ROM) *** 
<*> SCSI disk support 
< > SCSI tape support 
< > SCSI OnStream SC-x0 tape support 

然后在驱动中配置 USB 控制器。进入“Device Drivers”选中“USB support”

< > Sound card support ---> 
[ ] HID Devices ---> 
[*] USB support ---> 
<*> MMC/SD/SDIO card support ---> 

进入“USB support”菜单选中“Support for Host-side USB”并根据处理器的控制器 情况配置 USB 控制器。下面是 EPC-28x 处理器 USB 控制器的配置

--- USB support 
<*> Support for Host-side USB 
[*] USB device filesystem (DEPRECATED) 
[*] USB device class-devices (DEPRECATED) 
[*] USB runtime power management (suspend/resume and wakeup) 
<*> EHCI HCD (USB 2.0) support 
[*] Support for Freescale controller 
[*] Support for Host1 port on Freescale controller 
[*] Support for DR host port on Freescale controller 
[*] Root Hub Transaction Translators 

使用 U 盘必须使能 USB 大容量类支持选中“USB Mass Storage support

<*> USB Mass Storage support 
[ ] USB Mass Storage verbose debug 

大多数情况下U 盘都在用 FAT 格式为了能正常使用 U 盘还需在内核中使能 FAT支持。菜单路径和配置如下

File systems ---> 
 DOS/FAT/NT Filesystems ---> 
 <*> MSDOS fs support 
 <*> VFAT (Windows-95) fs support 
 (437) Default codepage for FAT 
 (iso8859-1) Default iocharset for FAT 
 < > NTFS file system support 

保存配置重新编译内核基于新内核的系统就能使用 U 盘了。

2. 使用 USB 键盘和鼠标

使用 USB 键盘或者鼠标需要在内核中使能 HID 支持。在“Device Drivers”菜单界面选中“HID Devices

<*> Sound card support ---> 
[*] HID Devices ---> 
[*] USB support ---> 
<*> MMC/SD/SDIO card support ---> 

进入“HID Devices”选中“USB Human Interface Device (full HID) support

--- HID Devices 
-*- Generic HID support 
[ ] /dev/hidraw raw HID device support 
 *** USB Input Devices *** 
<*> USB Human Interface Device (full HID) support 
[ ] PID device support 
[ ] /dev/hiddev raw HID device support 
 Special HID drivers ---> 

另外还需使能 Event 支持。在“Device Drivers”配置界面选择“Input device support

< > Telephony support ---> 
 Input device support ---> 
 Character devices ---> 
-*- I2C support ---> 

进入“Input device support”选中“Event interface

< > Joystick interface 
<*> Event interface 
< > Event debugging 
`当然还需要 USB Host 支持参考前面“使用 U 盘”配置部分配置好 USB 控制器。
保存配置并编译内核使用新内核的系统即可支持 USB 键盘和鼠标。`

【1.7.5】 USB Gadget 驱动配置

USB Gadget 能通过 USB Device 实现诸如 U 盘模拟、USB 串口、USB 网卡等多种功能。 首先在内核配置使能“USB Gadget Support

Device Drivers ---> 
 [*] USB support ---> 
 <*> USB Gadget Support ---> 

然后进入“USB Gadget Support”根据实际情况选择 USB 控制器如下是 AM335xUSB 控制器选择

<*> USB Peripheral Controller (Inventra HDRC USB Peripheral (TI, ADI, ...)) ---> 

最后在配置菜单中根据实际需要选择配置相应的功能。对于 USB Gadget 的功能建议编译为模块在需要的时候插入模块用完后将模块卸载

<M> USB Gadget Drivers 
< > Gadget Zero (DEVELOPMENT) 
< > Audio Gadget (EXPERIMENTAL) 
<M> Ethernet Gadget (with CDC Ethernet support) 
[*] RNDIS support 
... 
<M> File-backed Storage Gadget (DEPRECATED) 
[ ] File-backed Storage Gadget testing version 
<M> Mass Storage Gadget 
< > Serial Gadget (with CDC ACM and CDC OBEX support) 

【1.7.6】 SD/MMC 驱动配置

在“Device Drivers”菜单中使能“MMC/SD/SDIO card support”

Device Drivers ---> 
 <*> MMC/SD/SDIO card support ---> 

进入“MMC/SD/SDIO card support”使能“MMC block device driver”。在“MMC/SD/SDIO Host Controller Drivers”下选择处理器对应的 SD/MMC 控制器

--- MMC/SD/SDIO card support 
... 
*** MMC/SD/SDIO Card Drivers *** 
<*> MMC block device driver 
(8) Number of minors per block device 
[*] Use bounce buffer for simple hosts 
< > SDIO UART/GPS class support 
< > MMC host test driver 
 *** MMC/SD/SDIO Host Controller Drivers *** 
... 
[*] Freescale i.MX Secure Digital Host Controller Interface 
<*> MXS MMC support 

另外还需根据 SD/MMC 卡的文件系统格式在内核中配置相应的文件系统支持。如果是FAT 格式请参考前面“使用 U 盘”中 VFAT 的配置如果采用 Ext2/3/4 格式则进行如下配置

File systems ---> 
 <*> Second extended fs support 
 <*> Ext3 journalling file system support 
 <*> The Extended 4 (ext4) filesystem 

【1.7.7】 网卡驱动配置

配置网卡首先要在主菜单中使能网络即选中“Networking support”

Power management options ---> 
[*] Networking support ---> 
 Device Drivers ---> 
 File systems ---> 
为了正常使用网络通常还需在“`Networking options`”中配置 `TCP/IP` 
[*] Networking support ---> 
 Networking options ---> 
 <*> Packet socket 
 <*> Unix domain sockets 
 < > PF_KEY sockets 
 [*] TCP/IP networking 
 [*] IP: multicasting 
 [ ] IP: advanced router 
 [*] IP: kernel level autoconfiguration 
 [*] IP: DHCP support 
 [*] IP: BOOTP support 
 [*] IP: RARP support 

只有开启“Networking support”支持后才能在“Device Drivers”菜单中看到“Network device support”子菜单

Device Drivers ---> 
 [ ] Multiple devices driver support (RAID and LVM) ---> 
 < > Generic Target Core Mod (TCM) and ConfigFS Infrastructure ---> 
[*] Network device support ---> 
 [ ] ISDN support ---> 
 < > Telephony support ---> 
 Input device support ---> 

选中“Network device support”并进入根据主板实际硬件在“Ethernet driver support”中配置物理网卡。如下是基于 EPC-28x 的主板网卡配置示例

[*] --- Ethernet (10 or 100Mbit) ---><*> FEC ethernet controller (of ColdFire and some i.MX CPUs) 
[*] Second FEC ethernet controller (on some ColdFire CPUs) 

【1.7.8】 NFS Client 配置

使用 NFS 文件系统首先需要保证网卡可用且在内核已经配置了网卡。在“File system”配置界面使能“Network File Systems”并进行配置

File systems ---> 
 [*] Network File Systems ---> 
 <*> NFS client support 
 [*] NFS client support for NFS version 3 
 [*] NFS client support for the NFSv3 ACL protocol extension 
 [*] NFS client support for NFS version 4 
 [*] NFS client support for NFSv4.1 (EXPERIMENTAL) 
 [*] Root file system on NFS 

选中“Root file system on NFS”能够通过 NFS 挂载服务器上的根文件系统这点在裁剪文件系统中特别有用。

【1.7.9】 PPP 拨号配置

PPP 拨号配置在“Device Drivers”的“Network device support”菜单下。选中并使能“PPP (point-to-point protocol) support”及子选项即可使用 PPP 拨号功能。这里以模块方式编译

Device Drivers ---> 
 [*] Network device support ---> 
 <M> PPP (point-to-point protocol) support 
 <M> PPP BSD-Compress compression 
 <M> PPP Deflate compression 
 [*] PPP filtering 
 <M> PPP MPPE compression (encryption) (EXPERIMENTAL) 
 [*] PPP multilink support (EXPERIMENTAL) 
 <M> PPP over Ethernet (EXPERIMENTAL) 
 <M> PPP support for async serial ports 
 <M> PPP support for sync tty ports 

编译内核后通过 make modules 编译模块在<drivers/net/ppp/>目录下会生成 slhc.ko、pppox.ko、pppoe.ko 等模块。将这些模块复制到目标系统中然后按照下列顺序依次插入模块

#insmod slhc.ko 
#insmod ppp_generic.ko 
#insmod pppox.ko 
#insmod pppoe.ko 
插入模块后生成/dev/ppp 设备节点通过 ppp 拨号脚本即可进行拨号了。

【1.7.10】 MTD 配置

在内核配置主菜单界面进入“Device Drivers”界面选择“Memory Technology Device (MTD) support

< > Connector - unified userspace <-> kernelspace linker ---> 
<*> Memory Technology Device (MTD) support ---> 
 Device Tree and Open Firmware support ---> 
< > Parallel port support ---> 

并进入“Memory Technology Device (MTD) support”进行如下配置

--- Memory Technology Device (MTD) support 
< > MTD tests support (DANGEROUS) 
< > RedBoot partition table parsing 
[*] Command line partition table parsing 
... 
<*> Direct char device access to MTD devices 
-*- Common interface to block layer for MTD 'translation layers' 
<*> Caching block device access to MTD devices 
… 
<*> NAND Device Support ---> 

进入“NAND Device Support”对系统 NAND 控制器进行选择

--- NAND Device Support 
[ ] Verify NAND page writes 
[ ] Support software BCH ECC 
[ ] Enable chip ids for obsolete ancient NAND devices 
< > GPIO NAND Flash driver 
<*> NAND Flash device on OMAP2, OMAP3 and OMAP4

保存配置编译内核。采用新内核启动的系统在驱动无误的情况下可以看到系统的MTD 分区信息。如下是 EPC-28x 进入系统后可通过/proc/mtd 文件查看

[root@M283 ~] # cat /proc/mtd 
dev: size erasesize name 
mtd0: 00c00000 00020000 "reserve" 
mtd1: 00080000 00020000 "reserve" 
mtd2: 00080000 00020000 "reserve" 
mtd3: 00080000 00020000 "reserve" 
mtd4: 00080000 00020000 "reserve" 
mtd5: 04000000 00020000 "rootfs" 
mtd6: 02e00000 00020000 "opt" 

【1.7.11】 UBIFS 文件系统配置

UBIFS 是工作于 UBI 子系统之上的文件系统而 UBI 又工作于 MTD 设备上所以首先需要在 MTD 中使能 UBI

Device Drivers ---> 
 <*> Memory Technology Device (MTD) support ---> 
 <*> Enable UBI - Unsorted block images ---> 

进入“Enable UBI - Unsorted block images”对 UBI 进行配置

--- Enable UBI - Unsorted block images 
(4096) UBI wear-leveling threshold 
(1) Percentage of reserved eraseblocks for bad eraseblocks handling 
< > MTD devices emulation driver (gluebi) 
[ ] UBI debugging 

其中“Percentage of reserved eraseblocks for bad eraseblockshandling”设置用于坏块管理 的保留块的百分比默认是 1%可以适当调整大一些不过必须与 U-Boot 中的设置一致。 还需在文件系统设置中使能和配置 UBIFS

File systems ---> 
 [*] Miscellaneous filesystems ---> 
 <*> UBIFS file system support 
 [*] Extended attributes support 
 [*] Advanced compression options 
 [*] LZO compression support (NEW) 
 [*] ZLIB compression support (NEW) 

【1.7.12】 CAN 驱动配置

前面已经提到过CAN 设备驱动的配置路径不在“Devie Drivers”下而是在“Networking support”中。进入内核配置主菜单选择“Networking support

 Power management options ---> 
[*] Networking support ---> 
 Device Drivers ---> 
 File systems ---> 

选中或者模块编译“CAN bus subsystem support”

 --- Networking support 
 Networking options ---> 
[ ] Amateur Radio support ---> 
<*> CAN bus subsystem support ---> 
< > IrDA (infrared) subsystem support ---> 

进入“CAN bus subsystem support”选中“Raw CAN Protocol”和“Broadcast Manager CAN Protocol”

--- CAN bus subsystem support 
<*> Raw CAN Protocol (raw access with CAN-ID filtering) 
<*> Broadcast Manager CAN Protocol (with content filtering) 
< > CAN Gateway/Router (with netlink configuration) (NEW) 
 CAN Device Drivers ---> 

然后进入“CAN Device Drivers”对 CAN 设备驱动进行配置如下

CAN Device Drivers ---> 
 <*> Virtual Local CAN Interface (vcan) (NEW) 
 <> Serial / USB serial CAN Adaptors (slcan) (NEW) 
 < > Platform CAN drivers with Netlink support (NEW) 
 <*> Freescale FlexCAN 

【8】 EPC-28x 平台内核快速编译

从 EPC-28x光盘内获取内核源码包EPC-28x.xxxxx.tar.bz2然后把它拷贝到Ubuntu 下面执行如下步骤

1. 解压缩

vmuser@Linux-host ~$ tar -vxjf EPC-28x.xxxxx.tar.bz2 

解压后产生内核目录 linux-2.6.35.3。

2. 编译内核

EPC-28x 内核源码的 Makefile 文件内已经配置好了 ARCHCROSS_COMPILE所以 在 make 时无需指定ARCH CROSS_COMPILEEPC-28x 的源码已经包含配置好的.config 文件无需 makemenuconfig 配置即可使用默 认配置除非需要改动内核配置。

vmuser@Linux-host ~$ cd linux-2.6.35.3 
vmuser@Linux-host ~/ linux-2.6.35.3$ make uImage 

编译完成将得到内核文件<arch/arm/boot/uImage>。 另外在执行 make distclean 或者 make mrproper 之前请先将.config 配置文件备份 如

vmuser@Linux-host ~/ linux-2.6.35.3$cp .config config-bak 

第二章等你
在这里插入图片描述

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux

“嵌入式 Linux 内核驱动开发【The first day: 36093万字】_linux嵌入式内核及驱动开发” 的相关文章