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

在这里插入图片描述

嵌入式 Linux 内核驱动开发【1】

  • 嵌入式 Linux 内核驱动开发前言
  • 第1章 Linux 内核裁剪和定制
    • 【1】Linux 内核开发简介
    • 【2】 Linux 源码阅读工具
      • 【1.2.1】Source Insight
      • 【1.2.2 Eclipse】
      • 【1.2.3】 vim+ctags+cscope
      • 【1.2.4】 LXR
    • 【3】Linux 内核源码
      • 【1.3.1 目录树概览】
      • 【1.3.2】 快速确定主板关联代码
    • 【4】 Linux 内核中的 Makefile 文件
      • 【1.4.1】 顶层 Makefile
      • 【1.4.2】 子目录的 Makefile
    • 【5】 Linux 内核中的 Kconfig 文件
      • 【1.5.1】 Kconfig 基本语法
      • 【1.5.2】 配置项和配置开关
    • 【6】 配置和编译 Linux 内核
      • 【1.6.1】 快速配置内核
      • 【1.6.2】 内核配置详情
      • 【1.6.3】 编译内核
    • 【7】 Linux 内核裁剪实例
      • 【1.7.1】 GPIO 子系统配置
      • 【1.7.2 】LED 子系统配置
      • 【1.7.3】 串口配置
      • 【1.7.4】 USB Host 驱动配置
      • 【1.7.5】 USB Gadget 驱动配置
      • 【1.7.6】 SD/MMC 驱动配置
      • 【1.7.7】 网卡驱动配置
      • 【1.7.8】 NFS Client 配置
      • 【1.7.9】 PPP 拨号配置
      • 【1.7.10】 MTD 配置
      • 【1.7.11】 UBIFS 文件系统配置
      • 【1.7.12】 CAN 驱动配置
    • 【8】 EPC-28x 平台内核快速编译

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

嵌入式 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 内核驱动开发【The first day: 36093万字】_第1张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第2张图片
然后添加源码。浏览选中 Linux 内核源码文件夹后,点击“Add Tree”按钮,将内核源码树的全部文件添加到工程中,如图 1.3 所示。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第3张图片
添加完成,即可在 Source Insight 中进行源码阅读和编辑了,如图 1.4 所示。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第4张图片

【1.2.2 Eclipse】

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

创建内核源码工程。点击 FileNewProject,开始创建工程,在工程创建界面选择创建 C 工程,如图 1.5 所示。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第5张图片
点击 Next,在 C Project 界面的 Project name 栏中填写工程名称,去掉“Use default location”的勾,点击 Browse 将 Location 设置为 Linux 内核源码目录,如图 1.6 所示。如果不在 Eclipse中编译内核,则使用 Linux GCC 即可,否则请使用安装好的 Cross GCC
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第6张图片
然后点击 Finish,完成 Linux 内核源码导入,在 Eclipse 中即可进行代码阅读和编辑了,如图 1.7 所示。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第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的命令状态下输入:TlistToggle(Vi/Vim的命令输入支持补全),在 Vi/Vim 左边就会出现函数列表侧栏,如图 1.8 所示。按 CTRL+ww (2 次> w),可在列表和代码查看区间切换。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第8张图片
如果在本地桌面,用 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 所示。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第9张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第10张图片

【3】Linux 内核源码

【1.3.1 目录树概览】

解压 Linux 内核源码压缩包,将得到内核源码。内核源码很复杂,包含多级目录,形成 一个庞大的树状结构,通常称为 Linux源码目录树。进入源码所在目录,可以看到目录树顶 层通常包含如下目录和文件:
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第11张图片

各个目录文件的简要说明如表 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 的头文件目录
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:
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第12张图片

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

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

1. 基础代码

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

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

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

确定对应的主板文件。

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


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

# 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 所列。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第13张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第14张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第15张图片

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

【4】 Linux 内核中的 Makefile 文件

本节不对内核的 Makefile 文件进行深入展开,更多语法和说明请阅读文件

【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 语法和说明请阅读

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

【1.5.1】 Kconfig 基本语法

如程序清单 1.1 所示代码摘自文件,是一个比较典型的 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 所示。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第16张图片
子菜单的菜单项则由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 引出帮助信息,在内核配置界面,选择选项后,通过可以查看帮助信息。

2. 属性

类型定义:每个菜单项都必须定义类型,可选类型有:bool、tristate、string、hex 和 int, 各类型描述如表 1.3所列。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第17张图片
定义选项的类型后面可以加菜单信息,用引号(“”)给出,留空则不加提示信息。


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

 [*] /dev/kmem virtual device support 

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

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

 <*> Kernel .config support 

<*>表示选中,对应 CONFIG_XXXx=y表示编译为模块,对应 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_CPUS,在Kconfig中则写成:

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"”就是直接引用 文件,形成更多菜单(项)。

【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 

嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第18张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第19张图片

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

$ cp .config config-bak 

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

$ cp config-bak .config 

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

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

【1.6.2】 内核配置详情

Linux 内核配置菜单比较复杂,下面对一些比较重要的配置界面进行介绍,更多的详细配置,建议进行实际操作。另外,由于 Linux 内核版本差异,实际看到的内核配置界面可能与本节的介绍有所差异。
图 1.12 所示的内核配置主界面,实际包含了如表 1.4 所列的各项一级菜单。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第22张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第23张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第24张图片

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

1. 通用设置

进入 General setup 是内核通用设置菜单界面,菜单选项众多,通常可以关注表 1.5 所列 选项。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第25张图片

2. 内核特性

Kernel Features 是内核特性配置菜单,常用选项介绍如表 1.6 所列。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第26张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第27张图片

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 内核驱动开发【The first day: 36093万字】_第28张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第29张图片
通常来说,使用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 ---> 

这些配置中,三态选项也可以配置为,在需要的时候再插入模块
对于 IPv6,现在已经有不少应用需求,建议配置为,并选中配置菜单中的全部选项,在需要的时候再插入模块。
特别说明一下CAN的配置选项。CAN-Bus 相关协议支持以及 CAN 设备驱动配置项都在这里,并没有将 CAN 设备驱动放在 drivers 配置菜单中。CAN-Bus 子系统配置界面如图
1.15 所示。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第30张图片
其中的“CAN Device Drivers”子菜单下可选择具体的 CAN 设备,如图 1.16 所示。具体选择哪个 CAN 设备驱动,与具体的硬件平台相关。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第31张图片

5. 设备驱动

Linux 内核支持众多外设,设备驱动程序很多,配置界面也很复杂,有众多配置项,如 表 1.8 所列。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第32张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第33张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第34张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第35张图片
在这里插入图片描述

6. 文件系统

进入 File systems,是内核文件系统配置界面,可以看到很多文件系系统配置选项,如 图 1.17 所示。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第36张图片

一个完整的嵌入式 Linux 系统往往会支持多种文件系统,但绝非“File systems”菜单下的全部。这里仅对当前主流系统比较常用的一些文件系统配置项进行介绍,如表 1.9 所列。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第37张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第38张图片
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第39张图片

【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 所列。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第40张图片

1. zImage

zImage是通常情况下默认的压缩内核,可以直接加载到内存地址并开始执行。它从 文件经过 objcopy 处理得到。在 ARM Linux 下最终生成 zImage 的各个参数记录在文件中。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 源码文件的 image_header_t 数据结构定义)。进入目录,用 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 所列。
嵌入式 Linux 内核驱动开发【The first day: 36093万字】_第41张图片

对于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 格式映像文件,在文件中给出了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的各个参数记录在文件中。对于在 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. 编译内核模块

如果内核中有配置为的模块或者驱动,需要在编译内核后再通过 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 编译模块,在目录下会生成 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 

编译完成,将得到内核文件。 另外,在执行 make distclean 或者 make mrproper 之前,请先将.config 配置文件备份, 如:

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

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

你可能感兴趣的:(嵌入式Linux驱动工程师课程,嵌入式Linux开发工程师课程,驱动开发,linux,运维,eclipse,Source,insght,4)