第一章 驱动概述
1 为什么要学linux驱动?
linux分成内核空间和用户空间,这样对linux内核是一个保护,应用程序不能随便的访问内核,进而访问硬件。
应用程序(linuxIO编程 多进程 多线程 网络编程)---->运行在用户空间(0x0000_0000~0xBFFF_FFFF)
驱动程序(在linux系统,只要访问硬件,如:LED显卡 声卡 网卡 串口)--->内核空间(0xC000_0000~0xFFFF_FFFF).
linux应用程序如果要访问硬件,必须要经过linux的驱动。
linux的驱动编程---->linux内核编程。
2 linux驱动学什么内容?
1) linux内核的module--->设备驱动是封装在module中的,在设计一个驱动之前,首先设计一个module。
2) linux的字符设备驱动模型 --->如何申请设备号 如何做字符设备的初始化 如何设计应用程序的标准接口
3) IO内存映射 --->驱动如何访问硬件
4) GPIO口驱动设计 --->LED灯 蜂鸣器 按键。
5) 如何将一个驱动程序编译进内核 ---> *.ko放到zImage,在zImage初始化的过程中,自动安装驱动。
6) 混杂设备驱动模型 --->简化字符设备驱动设计。
7) linux中断驱动的设计
8) linux内核的内存分配
9) linux内核的动态定时器
10) 同步与互斥
11) platform 模型
12) 输入子系统模型
3 驱动的设计思想
1) 要求简洁 高效 稳定 可移植性
2) 简单的设备驱动程序可以自行设计
3) 复杂的设备驱动程序,一般都是需要移植
4) 学习驱动主要是学习驱动的框架
第二章 内核模块
1. 什么是module
module是linux的内核模块,linux的设备驱动封装在linux的内核模块中的。这样设备驱动成为linux内核中的独立模块,方便内核来管理驱动。
module存在的两种形式:
1.1 将驱动编译成独立的 内核外部的一个模块
*.ko ---> 安装驱动 #insmod led_drv.ko --->将驱动装到内核,在内核中创建该驱动的模型,等待应用程序访问。
卸载驱动 #rmmod led_drv
insmod --- insert module;
rmmod --- remove module
1.2 驱动程序可以编译进linux内核
当linux内核在启动的过程中,会自动安装驱动,就不需要手动安装。
如:
[1.048778] s3cfb s3cfb: registered successfully //显卡驱动,自动注册的
[1.294921] S3C NAND Driver, (c) 2008 Samsung Electronics //nand flash 驱动
内核启动输出,已初始化,
启动界面最后几行,有些是手动安装的一些驱动,
自动运行自定义的脚本,有两个
1. /etc/init.d/rcS //初始化一些环境,IP
2. /etc/profile //先执行第一个,再执行到这里,如两个文件里有同的配置,以最后一个为准.
source upiot.sh //up启动 iot互联网, 启动粤嵌互联网实验箱.
[root@GEC210 /]# vi upiot.sh
source /IOT/driver/auto.sh //先执行此脚本
cd /IOT/ //再到此目录下执行下面的程序
./iot -qws& //iot 应用程序名字,-qws ,QT的window窗口soft程序,&后台运行
cd /
[root@GEC210 /]# vi /IOT/driver/auto.sh //这些驱动是独立安装,不合进内核里,可按情况选择加载,前面加#注释掉,即不安装
insmod /IOT/driver/adc_drv.ko
#insmod /IOT/driver/buttons_drv.ko
insmod /IOT/driver/buzzer_drv.ko
#insmod /IOT/driver/led_drv.ko
insmod /IOT/driver/second.ko
insmod /IOT/driver/timer_irq.ko
insmod /IOT/driver/ov9650.ko
#insmod /IOT/driver/keypad.ko
insmod /IOT/driver/humidity.ko
2. 设计一个最简单的module
示例
/**********************************************************
#include
#include
static int __init gec210_led_init(void)//(入口)驱动的初始化及安装函数
{
printk("hello gec210\n"); //替代printf()
return 0;
}
static void __exit gec210_led_exit(void)//(出口)
{
printk("good bye gec210\n");
}
module_init(gec210_led_init); //驱动的入口
module_exit(gec210_led_exit); //驱动的出口
//内核模块的描述
MODULE_INFO //信息
MODULE_ALLAS //别名
MODULE_PARM_DESC //参数描述
MODULE_DEVICE_TABLE //设备条
//常用以下4个
MODULE_AUTHOR("[email protected]"); //作者
MODULE_DESCRIPTION("the first demo of module"); //描述
MODULE_LICENSE("GPL"); //符合GPL协议
MODULE_VERSION("V1.0") //版本
*****************************************************************/
3. module的分析
3.1 驱动有入口有出口
module_init(gec210_led_init); //驱动的入口
module_exit(gec210_led_exit); //驱动的出口
3.2 模块的描述
不是必需的,但是一般都会加上。
驱动编译完成后会生成一个ko,但是我们加了module描述可以使用命令:
#modinfo *.ko
会输出驱动的作者 版本描述 符合的协议......
3.3 __init和__exit
__init 声明该函数是一个初始化函数,该函数在编译连接的时候会放在init.text,当linux执行完该函数后,后释放该函数说占用的内存。
/**************************************************************
示例: uboot 启动
[0.000000] Virtual kernel memory layout:
[0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
[0.000000] fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
[0.000000] DMA : 0xff000000 - 0xffe00000 ( 14 MB)
[0.000000] vmalloc : 0xe0800000 - 0xfc000000 ( 440 MB)
[0.000000] lowmem : 0xc0000000 - 0xe0000000 ( 512 MB)
[0.000000] modules : 0xbf000000 - 0xc0000000 ( 16 MB)
[0.000000] .init : 0xc0008000 - 0xc008e000 ( 536 kB)
[0.000000] .text : 0xc008e000 - 0xc07d5000 (7452 kB)
[0.000000] .data : 0xc07d6000 - 0xc08345a0 ( 378 kB)
[ 11.135623] Freeing init memory: 536K
*********************************************************************/
4 驱动程序的编译
错误的用法:不要在shell 单个编译
$ arm-linux-gcc -o led_drv.ko led_drv.c
4.1 需要一个makefile文件
/***********************************
#Makefile 示例
obj-m += led_drv.o
#将目标文件led_drv.o(led_drv.c编译而来的),链接成一个独立module,即一个ko。
KERNELDIR := /home/gec/linux-2.6.35.7-gec-v3.0-gt110
#定义的一个变量,该变量是linux内核源码包的路径
PWD:=$(shell pwd)
#获取当前Makefile的路径,该路径下有驱动源文件。
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
#去内核源码包的路径下找编译工具(Makefile),然后回到当前的目录下将驱动的源文件编译成一个module(*.ko)
clean:
rm -rf *.o *.mod.c *.mod.o *.ko
#删除编译后的过程文件。
*****************************************/
4.2 如何编译ubuntu平台使用的ko
4.2.1 Makefile
/****************************************************
obj-m += led_drv.o
KERNELDIR := /lib/modules/$(shell uname -r)/build //编译工具在此目录下root@ubuntu: /lib/modules/3.5.0-23-generic
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko
*****************************************************/
4.2.2 驱动的编译信息
[@gec]$ make
make -C /home/gec/linux-2.6.35.7-gec-v3.0-gt110 M=/mnt/hgfs/driver/1module/demo/demo1 modules
make[1]: Entering directory `/home/gec/linux-2.6.35.7-gec-v3.0-gt110'
CC [M] /mnt/hgfs/driver/1module/demo/demo1/led_drv.o
Building modules, stage 2.
MODPOST 1 modules
CC /mnt/hgfs/driver/1module/demo/demo1/led_drv.mod.o
LD [M] /mnt/hgfs/driver/1module/demo/demo1/led_drv.ko
4.3 查看驱动的信息
$ file led_drv.ko
led_drv.ko: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), BuildID[sha1]=0x4e9bafa699a0df1eacd709d56f555260d88dd58f, not stripped
$ size led_drv.ko
text data bss dec hex filename
309 292 0 601 259 led_drv.ko
$ modinfo led_drv.ko
filename: led_drv.ko
version: V1.0
license: GPL
description: the first demo of module
author: [email protected]
srcversion: 3B0A4B330C5A695876920D6
depends:
vermagic: 2.6.35.7-GEC210 preempt mod_unload ARMv7
$ modinfo led_drv.ko
filename: led_drv.ko
version: V1.0
license: GPL
description: the first demo of module
author: [email protected]
srcversion: 3B0A4B330C5A695876920D6
depends:
vermagic: 2.6.35.7-GEC210 preempt mod_unload ARMv7
注意:
我们编译好的ko,安装环境:
软件环境:linux内核版本:2.6.35.7-GEC210
硬件环境:ARMv7
4.4目标硬件的信息:
# uname -r
# uname -a
Linux GEC210 2.6.35.7-GEC210 #1 PREEMPT Mon Sep 16 17:05:23 CST 2013 armv7l GNU/Linux
========================================================
5编译驱动使用的linux内核源码
5.1 为什么要使用内核源码?
1)设计驱动 --->我们可以使内核源码包来查看驱动程序设计过程中使用的函数原型。
2)编译驱动 --->编译驱动过程中,要使用内核源码包提供的编译工具Kbuild,用这个工具来编译驱动。
5.2 如何编译粤嵌发布的内核源码?
内核源码文件: linux-2.6.35.7-gec-v3.0-ft5206.tar.bz2 (据三星发布基于kernle2.6.35.7与210芯片相关的源码包基础上修改)
5.2.1粤嵌做好的配置文件,解压内核源码文件,在根目录下有以下配置文件
GEC210_1024X768_CONFIG ---> VGA输出
GEC210_4.3INCH_CONFIG ---> 4.3英寸电阻屏
GEC210_7INCH_CONFIG-FT5x06 --->7英寸电容屏,电容屏的控制芯片FT5x06 (ok)
GEC210_7INCH_CONFIG-GT911 --->7英寸电容屏,电容屏的控制芯片GT911
GEC210_7INCH_CONFIG-TSC2007 --->7英寸电阻屏,电阻屏的控制器TSC2007
//三星提供的默认配置文件:arch/arm/configs/smdkc110_android_defconfig (里面有条件编译选项)
#cp GEC210_7INCH_CONFIG-FT5x06 .config //(据当前使用的设备选择)
5.2.2配置
#make menuconfig //选项面板,此处不做更改,默认按GEC设置的值
注意:
make menuconfig若出现
*** Unable to find the ncurses libraries or the错误,则执行
解决方法:sudo apt-get install libncurses5-dev
5.2.3编译
#make -j4
/**********************************
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
AS arch/arm/boot/compressed/head.o
GZIP arch/arm/boot/compressed/piggy.gzip
AS arch/arm/boot/compressed/piggy.gzip.o
CC arch/arm/boot/compressed/misc.o
CC arch/arm/boot/compressed/decompress.o
SHIPPED arch/arm/boot/compressed/lib1funcs.S
AS arch/arm/boot/compressed/lib1funcs.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
***********************************/
5.2.4生成zImage
arch/arm/boot/zImage //编译成功在此目录下生成zImage
5.3 编译驱动的内核源码的要求
1)驱动的原码必须要针对硬件平台配置过。 --->设置驱动的硬件平台
2)内核源码包需要编译过 --->内核的信息
最好:驱动安装的目标环境的源码包 (内核相同的版本),用来编译驱动。
6 驱动程序和应用程序的差异
6.1 驱动程序是没有main函数的。但是有相应的入口(相当于C的main函数)
#insmod *.ko --->系统调用module_init(s3c_adc_init)--->调用s3c_adc_init()--->初始化并安装一个驱动。
6.2 应用程序是没有出口,但是驱动程序有出口
#rmmod * --->系统调用module_exit(s3c_adc_exit)--->调用s3c_adc_exit()---->释放驱动的资源(设备号,文件操作集,内存等),卸载驱动。
6.3 驱动程序的设计不能使用C的库函数
如:
#include
printf()
只能使用linux内核提供的函数
6.4 设计驱动程序使用的头文件在linux内核源码包中。(include/linux)
6.5 编译驱动的时候要使用linux的内核源码包
7 驱动的安装和卸载
7.1 安装 insmod
# insmod led_drv.ko
[ 260.996066] hello gec210
7.2 查看内核中的驱动模块lsmod
# lsmod
led_drv 568 0 - Live 0xbf038000 -->我们安装的
humidity 2560 0 - Live 0xbf032000 -->/etc/profile -->upiot.sh--->/IOT/driver/auto.sh //粤嵌的脚本
ov9650 8851 0 - Live 0xbf029000
timer_irq 2207 0 - Live 0xbf023000
second 1934 0 - Live 0xbf01d000
buzzer_drv 1414 0 - Live 0xbf017000
adc_drv 3829 0 - Live 0xbf011000
snd_soc_gec210_wm8960 3134 0 - Live 0xbf00b000
snd_soc_wm8960 19792 1 snd_soc_gec210_wm8960, Live 0xbf000000
[0.000000] Virtual kernel memory layout:
[0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
[0.000000] fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
[0.000000] DMA : 0xff000000 - 0xffe00000 ( 14 MB)
[0.000000] vmalloc : 0xe0800000 - 0xfc000000 ( 440 MB)
[0.000000] lowmem : 0xc0000000 - 0xe0000000 ( 512 MB)
[0.000000] modules : 0xbf000000 - 0xc0000000 ( 16 MB) //放的是ko
[0.000000] .init : 0xc0008000 - 0xc008e000 ( 536 kB)
[0.000000] .text : 0xc008e000 - 0xc07d5000 (7452 kB)
[0.000000] .data : 0xc07d6000 - 0xc08345a0 ( 378 kB)
7.3 卸载 rmmod
# rmmod led_drv
[ 887.499755] good bye gec210
8 printk函数
在内核中,使用printk()从控制台输出字符串,如应用程序的printf()
8.1 printk()有优先级,而printf()没有
例: 定义一个字符串,并把字符串输出
static char banner[] __initdata = KERN_INFO \
"S5PV210 ADC driver, (c) 2010 Samsung Electronics\n";
printk(banner);
知识点1 -->static声明一个全局变量
知识点2 -->__initdata 修饰初始化数据,该数据使用完以后,会将该数据所占用的内存释放掉。
知识点3 --> \ 续行符
知识点4 -->KERN_INFO,printk的优先级
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant condition */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
8.2 查看linux系统默认的优先级。
# cat /proc/sys/kernel/printk
7 4 1 7
7--->优先级超过7的printk,可以通过控制台输出该信息
4--->printk()默认的优先级
1/7 --->写入日志的优先级范围。
8.3 修改linux系统默认的额优先级
#echo 6 3 2 6 >/proc/sys/kernel/printk
9 内核符号表
cd /proc //目录,动态反映linux工作过程等信息
如:作出了哪些中断,申请了哪些内存,工作了多长时间, cpu信息,内核版本,启动了哪些进程,进程的优先级,进程使用了哪些栈,进程的状态,内核符号表等
驱动程序A(ko)使用驱动程序B(ko)提供的函数。驱动程序B将该函数添加到内核符号表中,内核符号表相当于内核中一个全局的表,驱动A可以从内核符号表中拿到这个函数,使用这个函数。
EXPORT_SYMBOL(sym)
EXPORT_SYMBOL_GPL(sym) --->符合GPL协议的module(驱动)才可以使用内核符号表中的该符号
# grep add_xy -r /proc/kallsyms //查看
bf044030 r __kstrtab_add_xy [add]
bf044058 r __ksymtab_add_xy [add]
A作业 //内核模块作业
1,按下开关,累计计数,以下以下哪个可以实现 计数(即变量不能存在栈中)
///-----------可以,静态变量存在内存数据段,不存在栈中--
Static 修饰局部变量,静态,变量放在内存里,不是放在栈里(函数一执行,就使用变量,给分配空间,)函数执行完后,变量的空间就会释放掉.
如用静态,第一次调用,给变量赋初始值,变量的初始值就放在内存里,第二次调用就不会给变量赋初始值,直接使用上一次给这变量赋好的值,不管函数调不调用,这变量一直在内存里.
例: 有一个按键的中断服务程序,每次按一下按键中断服务程序执行一次,以下哪个可以记录中断服务次数
void key_isr(void)
{
static unsigned int key_cnt = 0;
key_cnt++;
}
//-------------可以,是全局变量,不会被回收
unsigned int key_cnt = 0;
void key_isr(void)
{
key_cnt++;
}
//-------------可以,是静态全局变量
static unsigned int key_cnt = 0;
void key_isr(void)
{
key_cnt++;
}
//---------------不可以,是局部变量,存在栈中,会被回收
void key_isr(void)
{
unsigned int key_cnt = 0;
key_cnt++;
}
//==============================
2.stdio.h ---->在哪里???
????
gcc
arm-linux-gcc
//=================================
3. uImage和zImage的区别????
**************************/
(1)uImage是引导器uboot专用的内核文件格式,uboot目前只能支持uImage启动,不支持zImage启动。uImage是zImage进一步压缩来的。
(2)zimage,bzimage,压缩方式不一样。zimage用的zip压缩,bzimage用的bzip2压缩,后者的压缩率更高,文件更小。这两种是GRUB引导程序支持的格式,也是linux的标准格式,后者更常用。
/***************************************
//===================================
4. make clean
make distclean = make clean + 删除配置文件
假如:
make clean ---> make
make distclean ---> #cp GEC210_7INCH_CONFIG-FT5x06 .config
#make menuconfig
#make
//================================
5.+= ?= := =
在Makefile中的区别
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
1 “=”
make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
x = foo
y = $(x) bar
x = xyz
在上例中,y的值将会是 xyz bar ,而不是foo bar 。
2 “:=”
“:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
x := foo
y := $(x) bar
x := xyz
在上例中,y的值将会是 foo bar ,而不是xyz bar 了。
******************=
在Makefile中我们经常看到= := ?= +=这几个赋值运算符,那么他们有什么区别呢?我们来做个简单的实验
新建一个Makefile,内容为:
ifdef DEFINE_VRE
VRE = “Hello World!”
else
endif
ifeq ($(OPT),define)
VRE ?= “Hello World! First!”
endif
ifeq ($(OPT),add)
VRE += “Kelly!”
endif
ifeq ($(OPT),recover)
VRE := “Hello World! Again!”
endif
all:
@echo $(VRE)
敲入以下make命令:
make DEFINE_VRE=true OPT=define 输出:Hello World!
make DEFINE_VRE=true OPT=add 输出:Hello World! Kelly!
make DEFINE_VRE=true OPT=recover 输出:Hello World! Again!
make DEFINE_VRE= OPT=define 输出:Hello World! First!
make DEFINE_VRE= OPT=add 输出:Kelly!
make DEFINE_VRE= OPT=recover 输出:Hello World! Again!
从上面的结果中我们可以清楚的看到他们的区别了
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
之前一直纠结makefile中“=”和“:=”的区别到底有什么区别,因为给变量赋值时,两个符号都在使用。网上搜了一下,有人给出了解答,但是本人愚钝,看不懂什么意思。几寻无果之下,也就放下了。今天看一篇博客,无意中发现作者对于这个问题做了很好的解答。解决问题之余不免感叹,有时候给个例子不就清楚了吗?为什么非要说得那么学术呢。^_^
1 “=”
make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
x = foo
y = $(x) bar
x = xyz
在上例中,y的值将会是 xyz bar ,而不是 foo bar 。
2 “:=”
“:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
x := foo
y := $(x) bar
x := xyz
在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。
***************************************************************/
//===================
6. /proc下各个文件的作用
1. /proc目录
Linux 内核提供了一种通过 /proc文件系统,在运行时访问内核内部数据结构 改变内核设置的机制。proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。
用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取proc文件时,proc文件系统是动态从系统内核读出所需信息并提交的。下面列出的这些文件或子文件夹,并不是都是在你的系统中存在,这取决于你的内核配置和装载的模块。另外,在/proc下还有三个很重要的目录:net,scsi和sys。Sys目录是可写的,可以通过它来访问或修改内核的参数,而net和scsi则依赖于内核配置。例如,如果系统不支持scsi,则scsi目录不存在。
除了以上介绍的这些,还有的是一些以数字命名的目录,它们是进程目录。系统中当前运行的每一个进程都有对应的一个目录在/proc下,以进程的PID号为目录名,它们是读取进程信息的接口。而self目录则是读取进程本身的信息接口,是一个link。
2. 子文件或子文件夹
/proc/buddyinfo 每个内存区中的每个order有多少块可用,和内存碎片问题有关
/proc/cmdline 启动时传递给kernel的参数信息
/proc/cpuinfo cpu 的信息
/proc/crypto 内核使用的所有已安装的加密密码及细节
/proc/devices 已经加载的设备并分类
/proc/dma 已注册使用的ISA DMA频道列表
/proc/execdomains Linux内核当前支持的execution domains
/proc/fb 帧缓冲设备列表,包括数量和控制它的驱动
/proc/filesystems 内核当前支持的文件系统类型
/proc/interrupts x86架构中的每个IRQ中断数
/proc/iomem 每个物理设备当前在系统内存中的映射
/proc/ioports 一个设备的输入输出所使用的注册端口范围
/proc/kcore 代表系统的物理内存,存储为核心文件格式,里边显示的是字节数,等于RAM大小加上4kb
/proc/kmsg 记录内核生成的信息,可以通过/sbin/klogd或/bin/dmesg来处理
/proc/loadavg 根据过去一段时间内CPU和IO的状态得出的负载状态,与uptime命令有关
/proc/locks 内核锁住的文件列表
/proc/mdstat 多硬盘,RAID配置信息(md=multiple disks)
/proc/meminfo RAM 使用的相关信息
/proc/misc 其他的主要设备(设备号为10)上注册的驱动
/proc/modules 所有加载到内核的模块列表
/proc/mounts 系统中使用的所有挂载
/proc/mtrr 系统使用的Memory Type Range Registers (MTRRs)
/proc/partitions 分区中的块分配信息
/proc/pci 系统中的PCI设备列表
/proc/slabinfo 系统中所有活动的 slab 缓存信息
/proc/stat 所有的CPU活动信息
/proc/sysrq-trigger 使用echo命令来写这个文件的时候,远程root用户可以执行大多数的系统请求关键命令,就好像在本地终端执行一样。要写入这个文件,需要把/proc/sys/kernel/sysrq不能设置为0。这个文件对root也是不可读的
/proc/uptime 系统已经运行了多久
/proc/swaps 交换空间的使用情况
/proc/version Linux 内核版本和gcc版本
/proc/bus 系统总线(Bus)信息,例如pci/usb等
/proc/driver 驱动信息
/proc/fs 文件系统信息
/proc/ide ide 设备信息
/proc/irq 中断请求设备信息
/proc/net 网卡设备信息
/proc/scsi scsi 设备信息
/proc/tty tty 设备信息
/proc/net/dev 显示网络适配器及统计信息
/proc/vmstat 虚拟内存统计信息
/proc/vmcore 内核panic时的内存映像
/proc/diskstats 取得磁盘信息
/proc/schedstat kernel 调度器的统计信息
/proc/zoneinfo 显示内存空间的统计信息,对分析虚拟内存行为很有用
以下是/proc目录中进程N的信息
/proc/N pid 为N的进程信息
/proc/N/cmdline 进程启动命令
/proc/N/cwd 链接到进程当前工作目录
/proc/N/environ 进程环境变量列表
/proc/N/exe 链接到进程的执行命令文件
/proc/N/fd 包含进程相关的所有的文件描述符
/proc/N/maps 与进程相关的内存映射信息
/proc/N/mem 指代进程持有的内存,不可读
/proc/N/root 链接到进程的根目录
/proc/N/stat 进程的状态
/proc/N/statm 进程使用的内存的状态
/proc/N/status 进程状态信息,比stat/statm更具可读性
/proc/self 链接到当前正在运行的进程
B1代码一 //内核模块
1. Filename: led_drv.c
#include
#include
static int __init gec210_led_init(void) //驱动的初始化及安装函数
{
printk("hello gec210\n"); //替代printf()
return 0;
}
static void __exit gec210_led_exit(void)
{
printk("good bye gec210\n");
}
module_init(gec210_led_init); //驱动的入口
module_exit(gec210_led_exit); //驱动的出口
//内核模块的描述
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("the first demo of module");
MODULE_LICENSE("GPL"); //符合GPL协议
MODULE_VERSION("V1.0");
//-------------
2. Filename: Makefile
obj-m += led_drv.o
#KERNELDIR := /lib/modules/$(shell uname -r)/build
KERNELDIR := /home/gec/linux-2.6.35.7-gec-v3.0-gt110
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko
B2代码二 //内核模块
一个驱动调用另一个驱动里的函数,生成两个ko,在makefile里设置好,要安装两个ko
1. Filename: add.c
#include
#include
int add_xy(int x,int y)
{
return (x+y);
}
EXPORT_SYMBOL(add_xy); //把一个符号出口到内核符号表里,让其它驱动可以调用,
static int __init gec210_led_init(void) //驱动的初始化及安装函数
{
printk("hello gec210\n"); //替代printf()
return 0;
}
static void __exit gec210_led_exit(void)
{
printk("good bye gec210\n");
}
module_init(gec210_led_init); //驱动的入口
module_exit(gec210_led_exit); //驱动的出口
//内核模块的描述
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("the first demo of module");
MODULE_LICENSE("GPL"); //符合GPL协议
MODULE_VERSION("V1.0");
//-------------------------------------
2. Filename: led_drv.c
#include
#include
extern int add_xy(int x,int y);
static int __init gec210_led_init(void) //驱动的初始化及安装函数
{
int a=10,b=20,sum;
sum = add_xy(a,b);
printk("sum=%d\n", sum); //替代printf()
return 0;
}
static void __exit gec210_led_exit(void)
{
printk("good bye gec210\n");
}
module_init(gec210_led_init); //驱动的入口
module_exit(gec210_led_exit); //驱动的出口
//内核模块的描述
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("the first demo of module");
MODULE_LICENSE("GPL"); //符合GPL协议
MODULE_VERSION("V1.0");
3. Filename: Makefile ,生成两个ko文件
obj-m += led_drv.o
obj-m += add.o
KERNELDIR := /home/gec/linux-2.6.35.7-gec-v3.0-gt110
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko