入门学习linux设备驱动开发,首先要熟悉linux操作系统的启动流程以及linux内核组成,以及在linux下编程的命令(这部分内容可以参考linux基础篇),嵌入式linux系统由三个部分:bootloader,bzImage,文件系统。
从操作系统的角度来看,bootloader的最终目标是引导加载内核镜像,分为stage1,stage2,stage1完成基本硬件初始化、为stage2准备内存空间、复制stage2到内存空间、设置堆栈指针、跳转到stage2;在stage2中完成初始化本阶段用到的硬件设备、检测系统的内存映射、加载内核映像和根文件系统、设置内核启动参数、调用内核。
linux由用户空间和内核空间组成,通常内核空间和用户空间是程序执行的两种不同状态,通过系统调用与硬件中断实现从内核空间到用户空间的转移。下图显示了linux内核框架,由7个部分组成,分别为:系统调用接口、虚拟文件系统、进程管理、内存管理、设备驱动、体系结构、网络协议栈。
有关linux内核源码下载,http://www.kernel.org/,解压后查看相关内容。
--内核的编译
进入到linux内核目录,输入命令#make menuconfig (基本文本菜单的配置界面,需要安装可视化界面库ncurses)
显示的内容即为内核配置单选项。保存退出!!
输入命令 #make zImage 会在arch/XXXX/boot下面生成zImage镜像文件,arch目录下面是针对不同的平台,在内核目录Makefile中定义了ARCH?= CROSS_COMPILE?= ,用来选择嵌入式编译平台与交叉编译工具链。
上面的方法是内核中已经存在的程序进行配置,下面介绍如何在linux内核中增加程序:3个步骤
1、将编写的源代码考入到linux内核源代码的相应目录,如/drivers/char/led.c
2、在该目录的Kconfig文件中添加关于新源代码对应项目的编译配置选项
3、在Makefile文件中添加对新源代码的编译条目
---内核模块的简介
在linux中如何将需要的内容包含到linux内核中??
一种方法 如果将所需要的功能全部编译到内核中,导致两问题:内核庞大、我们在现有的内核中增减功能后,不得不重新编译内核。
另一种方法:以模块方式编译;优点:模块本身不会被编译入内核映像;一旦被加载,和内核中其他的部分完全一样。
为了使读者建立对模块的感性认识,以简单的hello.c程序为例
hello.c文件内容
/*
2 * A simple kernel module: "hello world"
3 *
4 * The initial developer of the original code is Barry Song
5 * <21cnbao@gmail.com>. All Rights Reserved.
6 */
7
8 #include <linux/init.h>
9 #include <linux/module.h>
10
11 static int hello_init(void)
12 {
13 printk(KERN_INFO " Hello World enter\n");
14 return 0;
15 }
16
17 static void hello_exit(void)
18 {
19 printk(KERN_INFO " Hello World exit\n ");
20 }
21
22 module_init(hello_init);
23 module_exit(hello_exit);
Makefile文件内容
1 KVERS = $(shell uname -r)
2
3 # Kernel modules
4 obj-m += hello.o
5
6 # Specify flags for the module compilation.
7 #EXTRA_CFLAGS=-g -O0
8
9 build: kernel_modules
10
11 kernel_modules:
12 make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
13
14 clean:
15 make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
注意:这两个文件必须在同一个目录下
然后执行#make 编译
通过安装insmod命令安装
#lsmod查看刚才已经在内核中建立的模块
#rmmod hello删除安装的hello模块
至此,已经将linux内核以及模块编译的相关知识介绍完成了,下节本人将进行简单字符设备驱动程序的案例分析。