第一章 驱动概述

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 <linux/module.h>

#include <linux/kernel.h>

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("bobeyfeng@163.com"); //作者

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:         bobeyfeng@163.com

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:         bobeyfeng@163.com

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 <stdio.h>

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 <linux/module.h>

#include <linux/kernel.h>

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("bobeyfeng@163.com");

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 <linux/module.h>

#include <linux/kernel.h>

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("bobeyfeng@163.com");

MODULE_DESCRIPTION("the first demo of module");

MODULE_LICENSE("GPL"); //符合GPL协议

MODULE_VERSION("V1.0");

//-------------------------------------

2. Filename:  led_drv.c

#include <linux/module.h>

#include <linux/kernel.h>

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("bobeyfeng@163.com");

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

linux 驱动笔记(一)相关推荐

  1. 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl【转】

    转自:https://blog.csdn.net/Guet_Kite/article/details/78574781 权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!谢谢合作 h ...

  2. 嵌入式Linux驱动笔记--转自风筝丶

    为了阅读学习方便,将系列博客的网址进行粘贴,感谢原博客的分享. 嵌入式Linux驱动笔记(一)------第一个LED驱动程序 嵌入式Linux驱动笔记(二)------定时器 嵌入式Linux驱动笔 ...

  3. 嵌入式Linux驱动笔记(十六)------设备驱动模型(kobject、kset、ktype)

    ###你好!这里是风筝的博客, ###欢迎和我一起交流. 前几天去面试,被问到Linux设备驱动模型这个问题,没答好,回来后恶补知识,找了些资料,希望下次能答出个满意答案. Linux早期时候,一个驱 ...

  4. 嵌入式Linux驱动笔记(五)------学习platform设备驱动

    你好!这里是风筝的博客, 欢迎和我一起交流. 设备是设备,驱动是驱动. 如果把两个糅合写一起,当设备发生变化时,势必要改写整个文件,这是非常愚蠢的做法.如果把他们分开来,当设备发生变化时,只要改写设备 ...

  5. 嵌入式Linux驱动笔记(二十四)------framebuffer之使用spi-tft屏幕(上)

    你好!这里是风筝的博客, 欢迎和我一起交流. 最近入手了一块spi接口的tft彩屏,想着在我的h3板子上使用framebuffer驱动起来. 我们知道: Linux抽象出FrameBuffer这个设备 ...

  6. 嵌入式Linux驱动笔记(十一)------i2c设备之mpu6050驱动

    ###你好!这里是风筝的博客, ###欢迎和我一起交流. 上一节讲了i2c框架: 嵌入式Linux驱动笔记(十)------通俗易懂式了解i2c框架 这次就来写一写真正的i2c设备驱动: mpu605 ...

  7. linux 驱动笔记(四)

    第六章 GPIO的标准接口函数 1 什么是GPIO的标准接口函数 思考: 1.1设计GPIO驱动的方法??? 1.1.1 找到配置/控制GPIO的寄存器,得到了访问该寄存器的物理地址 1.1.2 申请 ...

  8. Linux驱动笔记-TNYCL

    0.小计 IRQ:中断 RST:存储 FP:寄存器 backlight:linux背光子系统: SOC:系统及芯片,即片上系统: UART:通用异步收发传输号,串行异步收发协议,二进制按位为单位传输: ...

  9. linux驱动笔记1---linux内核驱动目录结构

      在Linux内核中新增驱动时,需要增加以下结构和文件更改,下面做一个笔记进行记录. 驱动结构的Xmind展示 新增驱动test详解   新增驱动为drivers下的test文件夹,里面包含了驱动源 ...

最新文章

  1. 关于ref 和 out 关键字【整理】
  2. Struts2+Android (3) 多种方式向服务器发送信息
  3. Android FFmpeg系列——5 音视频同步播放
  4. iOS线程锁中你还不知道的内容
  5. spring boot集成mybatis+事务控制
  6. c3p0 服务启动获取连接超时_JDBC数据库连接池
  7. Java基本数据类型的自动转换_彻底理解Java中的基本数据类型转换(自动、强制、提升)...
  8. Java案例:读取XML文档
  9. 简单-三层-存储过程-增删改《一》
  10. java中aop和aoc的区别_你喝到的波尔多AOC、AOP红酒是真的吗?
  11. Linux下comm命令比较两个文件的异同
  12. 基于android的家庭财务通 .apk,毕业设计(论文)-基于Android的家庭财务管家的设计与实现.doc...
  13. 2021-06-19:交错字符串。 有三个字符串s1,s2,s3。判断s3是否由s1和s2交错组成的。比如s1=“abc“,s2=“123“,s3=“12ab3c“,应该返回true,因为s3去掉12
  14. HTML5 全局属性
  15. 贝塞尔曲线(Bezier)之 QQ 消息拖拽动画效果
  16. 酬乐天扬州初逢席上见赠
  17. Revit导入CAD图纸,要提前优化图纸,你做到了吗?
  18. c语言实验--九九乘法表,C语言程序设计实验四 参考答案.doc
  19. 安装过程中弹出错误信息,Xshell4提示nslicense.dll无法安装成功
  20. Xsolla与Ubisoft游戏Rainbow Six Siege 和刺客信条:辛迪加展开战略合作

热门文章

  1. 易语言调用子程序_ c,易语言汇编调用子程序源码
  2. 10路智能电动自行车充电桩功能特点优势
  3. 李迅雷+趋势的力量+K型分化时代如何赢取超额收益
  4. 一页纸商业计划书模板(转载)
  5. oracle12c备份与恢复,Oracle 12c 备份与恢复
  6. django踩坑关于django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.
  7. 沙尘暴天气空气净化器市场走俏
  8. [转载]你手里期权值多少钱?写给上市公司的同学
  9. GBase 8c技术特点
  10. 微信公众号服务号申请-模板消息发送-自定义菜单-测试账号指南