linux 驱动学习笔记01--Linux 内核的编译

由于用的学习材料是《linux设备驱动开发详解(第二版)》,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式。

#make config(基于文本的最为传统的配置界面,不推荐使用)
#make menuconfig(基于文本菜单的配置界面)
#make xconfig(要求 QT 被安装)
#make gconfig(要求 GTK+被安装)
在配置 Linux 2.6 内核所使用的 make config、 make menuconfig、 make xconfig 和 make gconfig
这 4 种方式中,最值得推荐的是 make menuconfig,它不依赖于 QT 或 GTK+,且非常直观。

make menuconfig的配置主界面:

下图是Device Drive目录下的Real Time Clock菜单,图片对应的驱动位于source/linux-2.6.32-devkit8500/drivers/rtc下,

跟上图相对应的Kconfig如下,可以发现这个界面中的所有内容都是通过Kconfig文件定义的。

Kconfig:

#
# RTC class/drivers configuration
#

config RTC_LIB
    tristate

menuconfig RTC_CLASS
    tristate "Real Time Clock"
    default n
    depends on !S390
    select RTC_LIB
    help
      Generic RTC class support. If you say yes here, you will
       be allowed to plug one or more RTCs to your system. You will
      probably want to enable one or more of the interfaces below.

      This driver can also be built as a module. If so, the module
      will be called rtc-core.

if RTC_CLASS

config RTC_HCTOSYS
    bool "Set system time from RTC on startup and resume"
    depends on RTC_CLASS = y
    default y
    help
      If you say yes here, the system time (wall clock) will be set using
      the value read from a specified RTC device. This is useful to avoid
      unnecessary fsck runs at boot time, and to network better.

config RTC_HCTOSYS_DEVICE
    string "RTC used to set the system time"
    depends on RTC_HCTOSYS = y
    default "rtc0"
    help
      The RTC device that will be used to (re)initialize the system
      clock, usually rtc0. Initialization is done when the system
      starts up, and when it resumes from a low power state. This
      device should record time in UTC, since the kernel won‘t do
      timezone correction.

      The driver for this RTC device must be loaded before late_initcall
      functions run, so it must usually be statically linked.

      This clock should be battery-backed, so that it reads the correct
      time when the system boots from a power-off state. Otherwise, your
      system will need an external clock source (like an NTP server).

      If the clock you specify here is not battery backed, it may still
      be useful to reinitialize system time when resuming from system
      sleep states. Do not specify an RTC here unless it stays powered
      during all this system‘s supported sleep states.

config RTC_DEBUG
    bool "RTC debug support"
    depends on RTC_CLASS = y
    help
      Say yes here to enable debugging support in the RTC framework
      and individual RTC drivers.

comment "RTC interfaces"

config RTC_INTF_SYSFS
    boolean "/sys/class/rtc/rtcN (sysfs)"
    depends on SYSFS
    default RTC_CLASS
    help
      Say yes here if you want to use your RTCs using sysfs interfaces,
      /sys/class/rtc/rtc0 through /sys/.../rtcN.

      If unsure, say Y.

config RTC_INTF_PROC
    boolean "/proc/driver/rtc (procfs for rtc0)"
    depends on PROC_FS
    default RTC_CLASS
    help
      Say yes here if you want to use your first RTC through the proc
      interface, /proc/driver/rtc. Other RTCs will not be available
      through that API.

      If unsure, say Y.

endif # RTC_CLASS

源文件将近千行,这里只截取前面部分进行分析,

Kconfig
内核配置脚本文件的语法比较简单,主要包括如下几个方面。
( 1 )菜单入口 。
大多数的内核配置选项都对应 Kconfig 中的一个菜单入口:
config MODVERSIONS
  bool "Module versioning support"

  help
     Usually, you have to use modules compiled with your kernel.
    Saying Y here makes it ...
“ config” 关键字定义新的配置选项,之后的几行定义了该配置选项的属性。配置选项的属性包括类型、数据范围、输入提示、依赖关系、选择关系及帮助信息和默认值等。
每个配置选项都必须指定类型,类型包括 bool、 tristate、 string、 hex 和 int,其中 tristate 和string 是两种基本的类型,其他类型都基于这两种基本类型。类型定义后可以紧跟输入提示,下面的两段脚本是等价的:
bool "Networking support"

bool
prompt "Networking support"
输入提示的一般格式为:
prompt <prompt> [if <expr>]
其中可选的 if 用来表示该提示的依赖关系。
默认值的格式为:
default <expr> [if <expr>]
一个配置选项可以存在任意多个默认值,这种情况下,只有第一个被定义的值是可用的。如果用户不设置对应的选项,配置选项的值就是默认值。
依赖关系的格式为:
depends on(或者 requires) <expr>
如果定义了多重依赖关系,它们之间用 “ &&” 间隔。依赖关系也可以应用到该菜单中所有的其他选项(同样接受 if 表达式),下面的两段脚本是等价的:
bool "foo" if BAR
default y if BAR

depends on BAR
bool "foo"
default y
选择关系(也称为反向依赖关系)的格式为:
select <symbol> [if <expr>]
A 如果选择了 B,则在 A 被选中的情况下, B 自动被选中。
kbuild Makefile 中的 expr(表达式)定义为:

<expr> ::= <symbol>
    <symbol> ‘=‘ <symbol>
   <symbol> ‘!=‘ <symbol>
   ‘(‘ <expr> ‘)‘
   ‘!‘ <expr>
   <expr> ‘&&‘ <expr>
   <expr> ‘||‘ <expr>
也就是说 expr 是由 symbol、两个 symbol 相等、两个 symbol 不等以及 expr 的赋值、非、与
或运算构成。而 symbol 分为两类,一类是由菜单入口定义配置选项定义的非常数 symbol,另一
类是作为 expr 组成部分的常数 symbol。
数据范围的格式为:
range <symbol> <symbol> [if <expr>]
为 int 和 hex 类型的选项设置可以接受输入值范围,用户只能输入大于等于第一个 symbol,
小于等于第二个 symbol 的值。
帮助信息的格式为:
help(或---help---)
 开始

结束
帮助信息完全靠文本缩进识别结束。“---help---” 和“help” 在作用上没有区别,设计“---help---”
的初衷在于将文件中的配置逻辑与给开发人员的提示分开。
menuconfig 关键字的作用与 config 类似,但它在 config 的基础上要求所有的子选项作为独立
的行显示。
( 2)菜单结构。
菜单入口在菜单树结构中的位置可由两种方法决定。第一种方式为:
menu "Network device support"
 depends on NET
config NETDEVICES
 …
endmenu
所有处于“ menu” 和“ endmenu” 之间的菜单入口都会成为“ Network device support” 的子菜
单。而且,所有子菜单选项都会继承父菜单的依赖关系,比如,“ Network device support” 对“ NET”
的依赖会被加到了配置选项 NETDEVICES 的依赖列表中。
注意 menu 后面跟的“ Network device support”项目仅仅是 1 个菜单,没有对应真实的配置选
项,也不具备 3 种不同的状态。这是它和 config 的区别。
另一种方式是通过分析依赖关系生成菜单结构。如果菜单选项在一定程度上依赖于前面的选
项,它就能成为该选项的子菜单。如果父选项为“ N”,子选项不可见;如果父选项可见,子选项
才能可见。例如:
config MODULES
 bool "Enable loadable module support"
config MODVERSIONS
 bool "Set version information on all module symbols"
 depends on MODULES

comment "module support disabled"
depends on !MODULES
MODVERSIONS 直接依赖 MODULES,只有 MODULES 不为“ n”时,该选项才可见。
除此之外, Kconfig 中还可能使用“ choices … endchoice”、“ comment”、“ if…endif” 这样的语
法结构。其中 “ choices … endchoice” 的结构为:
choice
<choice options>
<choice block>
endchoice"
它定义一个选择群,其接受的选项(choice options)可以是前面描述的任何属性, 例如 LDD6410
的 VGA 输出分辨率可以是 1 024 !768 或者 800 !600,在 drivers/video/samsung/Kconfig 就定义了如
下的 choice:
choice
depends on FB_S3C_VGA
prompt "Select VGA Resolution for S3C Framebuffer"
default FB_S3C_VGA_1024 _768
config FB_S3C_VGA_1024 _768
bool "1 024 *[email protected]"
---help---
TBA
config FB_S3C_VGA_640_480
bool "640*[email protected]"
---help---
TBA
endchoic

下面介绍drivers/rtc下的Makefile:

#
# Makefile for RTC class/drivers.
#

ifeq ($(CONFIG_RTC_DEBUG),y)
    EXTRA_CFLAGS        += -DDEBUG
endif

obj-$(CONFIG_RTC_LIB)        += rtc-lib.o
obj-$(CONFIG_RTC_HCTOSYS)    += hctosys.o
obj-$(CONFIG_RTC_CLASS)        += rtc-core.o
rtc-core-y            := class.o interface.o

obj-$(CONFIG_RTC_INTF_ALARM) += alarm.o
obj-$(CONFIG_RTC_INTF_ALARM_DEV) += alarm-dev.o
rtc-core-$(CONFIG_RTC_INTF_DEV)    += rtc-dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o

# Keep the list ordered.

obj-$(CONFIG_RTC_DRV_AB3100)    += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9)    += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_AU1XXX)    += rtc-au1xxx.o
obj-$(CONFIG_RTC_DRV_BFIN)    += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_BQ4802)    += rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_CMOS)    += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331)    += rtc-coh901331.o
obj-$(CONFIG_RTC_DRV_DM355EVM)    += rtc-dm355evm.o
obj-$(CONFIG_RTC_DRV_DS1216)    += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1286)    += rtc-ds1286.o
obj-$(CONFIG_RTC_DRV_DS1302)    += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1305)    += rtc-ds1305.o
obj-$(CONFIG_RTC_DRV_DS1307)    += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1374)    += rtc-ds1374.o
obj-$(CONFIG_RTC_DRV_DS1390)    += rtc-ds1390.o
obj-$(CONFIG_RTC_DRV_DS1511)    += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553)    += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672)    += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742)    += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS3234)    += rtc-ds3234.o
obj-$(CONFIG_RTC_DRV_EFI)    += rtc-efi.o
obj-$(CONFIG_RTC_DRV_EP93XX)    += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130)    += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_GENERIC)    += rtc-generic.o
obj-$(CONFIG_RTC_DRV_ISL1208)    += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_M41T80)    += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T94)    += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T35)    += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59)    += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86)    += rtc-m48t86.o
obj-$(CONFIG_RTC_MXC)        += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MAX6900)    += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902)    += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MSM6242)    += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MV)    += rtc-mv.o
obj-$(CONFIG_RTC_DRV_OMAP)    += rtc-omap.o
obj-$(CONFIG_RTC_DRV_PCAP)    += rtc-pcap.o
obj-$(CONFIG_RTC_DRV_PCF8563)    += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583)    += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PCF2123)    += rtc-pcf2123.o
obj-$(CONFIG_RTC_DRV_PCF50633)    += rtc-pcf50633.o
obj-$(CONFIG_RTC_DRV_PL030)    += rtc-pl030.o
obj-$(CONFIG_RTC_DRV_PL031)    += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_PS3)    += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PXA)    += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R9701)    += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RP5C01)    += rtc-rp5c01.o
obj-$(CONFIG_RTC_DRV_RS5C313)    += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348)    += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372)    += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_RX8025)    += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8581)    += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_S35390A)    += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C)    += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_SA1100)    += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SH)    += rtc-sh.o
obj-$(CONFIG_RTC_DRV_STARFIRE)    += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8)    += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_STMP)    += rtc-stmp3xxx.o
obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
obj-$(CONFIG_RTC_DRV_TEST)    += rtc-test.o
obj-$(CONFIG_RTC_DRV_TWL4030)    += rtc-twl.o
obj-$(CONFIG_RTC_DRV_TX4939)    += rtc-tx4939.o
obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX)    += rtc-vr41xx.o
obj-$(CONFIG_RTC_DRV_WM831X)    += rtc-wm831x.o
obj-$(CONFIG_RTC_DRV_WM8350)    += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o

这里主要对内核源代码各级子目录中的 kbuild( 内核的编译系统) Makefile 进行简单介绍,这部分是内核模块或设备驱动的开发者最常接触到的。
Makefile 的语法包括如下几个方面。
( 1 )目标定义。
目标定义就是用来定义哪些内容要作为模块编译,哪些要编译并连接进内核。
例如:
obj -y += foo.o
表示要由 foo.c 或者 foo.s 文件编译得到 foo.o 并连接进内核,而 obj-m 则表示该文件要作为模
块编译。除了 y、 m 以外的 obj-x 形式的目标都不会被编译。
而更常见的做法是根据.config 文件的 CONFIG_变量来决定文件的编译方式,如:
obj -$(CONFIG_ISDN) += isdn.o
obj -$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
除了 obj-形式的目标以外,还有 lib-y library 库, hostprogs-y 主机程序等目标,但是基本都应
用在特定的目录和场合下。
( 2)多文件模块的定义。
最简单的 Makefile 如上一节一句话的形式就够了,如果一个模块由多个文件组成,会稍微复
杂一些,这时候应采用模块名加-y 或-objs 后缀的形式来定义模块的组成文件。如以下例子:
#
# Makefile for the linux ext2-filesystem routines.
#
obj -$(CONFIG_EXT2 _FS) += ext2.o
ext2-y := balloc.o dir.o file.o fsync.o ialloc.o inode.o \
   ioctl.o namei.o super.o symlink.o
ext2-$(CONFIG_EXT2 _FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
ext2-$(CONFIG_EXT2 _FS_POSIX_ACL) += acl.o
ext2-$(CONFIG_EXT2 _FS_SECURITY) += xattr_security.o
ext2-$(CONFIG_EXT2 _FS_XIP) += xip.o
模块的名字为 ext2,由 balloc.o、 dir.o、 file.o 等多个目标文件最终链接生成 ext2.o 直至 ext2.ko
文件,并且是否包括 xattr.o、 acl.o 等则取决于内核配置文件的配置情况,例如, 如果 CONFIG_
EXT2
_FS_POSIX_ACL 被选择,则编译 acl.c 得到 acl.o 并最终链接进 ext2。

( 3)目录层次的迭代。
如下例:
obj -$(CONFIG_EXT2 _FS) += ext2/
当 CONFIG_EXT2_FS 的值为 y 或 m 时, kbuild 将会把 ext2 目录列入向下迭代的目标中。

时间: 2024-10-08 10:24:26

linux 驱动学习笔记01--Linux 内核的编译的相关文章

Linux CentOS学习笔记--01

公司现在要求学习Linux,现在才刚刚学了一些简单的命令,以后就要到51CTO看看了,书是看不进去了. 下面是学习笔记: 1,清屏命令 clear reset  是把屏目上的所有內容全部刪除 alias 設定別名  alias cl='clear'   直接用cl 2,切換用戶 su root   然后输入密码 3,设置系统主机名 hostname 主机名 hostname --> 显示主机名 4,关机.重起.注销 关机  init 0     shutdown -h now 重起  init

linux 驱动学习笔记03--Linux 内核的引导

如图所示为 X86 PC 上从上电/复位到运行 Linux 用户空间初始进程的流程.在进入与 Linux相关代码之间,会经历如下阶段. ( 1 ) 当系统上电或复位时, CPU 会将 PC 指针赋值为一个特定的地址 0xFFFF0 并执行该地址处的指令.在 PC 机中,该地址位于 BIOS 中,它保存在主板上的 ROM 或 Flash 中. ( 2) BIOS 运行时按照 CMOS 的设置定义的启动设备顺序来搜索处于活动状态并且可以引导的设备. 若从硬盘启动, BIOS 会将硬盘 MBR(主引导

linux 驱动学习笔记02--应用实例:在内核中新增驱动代码目录和子目录

下面来看一个综合实例,假设我们要在内核源代码 drivers 目录下为 ARM 体系结构新增如下用于 test driver 的树型目录:| --test  | -- cpu  | -- cpu.c  | -- test.c  | -- test_client.c  | -- test_ioctl.c  | -- test_proc.c  | -- test_queue.c在内核中增加目录和子目录,我们需为相应的新增目录创建 Makefile 和 Kconfig 文件,而新增目录的父目录中的 K

linux 驱动学习笔记04--简单驱动

首先贴代码helloworld.c和Makefile /************************************************************************* > File Name: helloworld.c > Author: hailin.ma > Mail: > Created Time: Wed 15 Jul 2015 02:39:35 PM CST ***************************************

Linux驱动学习之Linux-2.6.20.4内核移植

最近一段时间一直在学习向TQ2440开发板移植内核.移植驱动.真心觉得这方面的知识有很大的难度.但是从另一角度去看,难度越大,能力提升的空间就越大!! 1.解压源码 从网上下载一个Linux 内核,我是用的是Linux-2.6.20.4.然后用命令解压.建议解压到"/home/用户名"目录下.我的内核源码存放在: 2.添加对ARM的支持 因为所用的是TQ2440开发板,属于ARM9.因此要在系统中添加对ARM的支持. 方法:进入内核源码目录, 修改"Makefile"

Linux Kernel学习笔记

转自:http://blog.sina.com.cn/s/blog_55465b470100eb8c.html 这里贴部分内容: Chapter 2. 设备驱动程序开发 在编程思路上,机制表示需要提供什么功能,策略表示如何使用这些功能.区分机制和策略是UNIX设计最重要和最好的思想之一.如X系统就由X服务器和X客户端组成.X服务器实现机制,负责操作硬件,给用户程序提供一个统一的接口.而X客户端实现策略,负责如何使用X服务器提供的功能.设备驱动程序也是机制与策略分离的典型应用.在编写硬件驱动程序时

Linux系统学习笔记:序

Linux系统学习笔记:序 ??Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程序和网络协议.它支持32位和64位硬件.Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统. 本人使用的Linux为Ubuntu,主要以<APUE>(第3版)为学习蓝本. 1. Unix/Linux 体系结构 如图: 内核的接口被称为系统调用.公用函数库构建在

Linux 操作系统学习笔记

一,unix 1.unix 特点 伸缩性强,开放性好, 2.基本原则 所有对象,硬件都是文件 配置数据以文本形式保存 短小的单目的程序构成 多个程序合作完成复杂任务 3.gnu 基本原则是共享,建立自由开放的unix系统 1984年 richard stallman 发起 基本体系是micro kernel 4.gpl Copyleft 原作者所有权 5.linux起源 Linustorvalds, 自由的类unix操作系统, 遵循gnu和gpl 6.linux 可以实现unix功能 遵循开源许

linux基础学习笔记——操作大全

作者:liaoyi 更新时间:2014-6-2 ****************基本操作***************** 关机 shutdown -h now    root用户               init 0              root用户halt      root+一般用户poweroff 重启shutdown -r now    root用户init6     root用户reboot            root+一般用户 注意:1.shutdown 比较灵活,可