Linux驱动笔记

1.Linux设备类型:字符设备,块设备,网络设备。

(1)字符设备

    作为字节流来处理。至少实现open,close,read,write系统调用。在文件系统的/dev目录下。

(2)块设备

    整块IO操作。与字符设备接口不同。在文件系统的/dev目录下。

(3)网络接口

    网络接口一般是硬件,也可以是软件,如loopback。并不在文件系统/dev目录下,没有路径,通过名字如eth0来访问。

USB设备可以是字符设备(USB串口),块设备(U盘),网络设备(USB网卡)。

2.内核视图

Linux驱动笔记_第1张图片

3.  内核模块注册之后是为了接收接下来的请求,其初始化程序会马上结束。换言之,模块的初始化函数的作用是为后续调用模块函数功能做准备。模块的exit函数告诉内核,不能再调用模块的函数。

     这种方法类似于事件驱动的编程,每个内核模块都是事件驱动的。模块的资源在调用exit的时候一定要释放,否则只能在系统重启后才会释放。

     内核模块只能调用内核导出的函数,不能调用C的标准库函数,因为不会和libc链接。

     内核的函数可以作为两种方式执行:系统调用、中断处理


4.Unix在调用系统调用或发生硬件中断的时候将执行从用户空间转到内核空间。

   内核代码在一个进程的上下文中执行系统调用,这个进程代表调用进程,可以访问调用进程的地址空间。


5.打印日志不要太多,可用printk_ratelimit限制

if (printk_ratelimit( ))
    printk(KERN_NOTICE "The printer is still on fire\n");


6. /proc文件系统是一个特殊的软件创建的文件系统,内核用它来导出信息。/proc下的每个文件都绑定到一个内核函数,在读取时产生。


7. 进程突然退出后内核会为每个open的设备调用close函数释放资源。


8. 使用gdb调试内核时有许多限制,例如,不能修改内核数据,不能设置断点和观察点,也不能单步执行。为使gdb调试内核时获取到符号信息,需要编译内核时打开CONFIG_DEBUG_INFO,这样编译的内核会比一般的大许多。


9. kdb(或kgdb)可以可以加断点和修改数据。

10.字符设备指那些必须以串行顺序依次进行访问的设备,如触摸屏、磁带驱动器、鼠标等。块设备可以用任意顺序进行访问,以块为单位进行操作,如硬盘、软驱等。字符设备不经过系统的快速缓冲,而块设备经过系统的快速缓冲。但是,字符设备和块设备并没有明显的界限,如 Flash 设备符合块设备的特点,但是我们仍然可以把它作为一个字符设备来访问。


11. input事件类型

#define EV_SYN                  0x00
#define EV_KEY                  0x01
#define EV_REL                  0x02
#define EV_ABS                  0x03
#define EV_MSC                  0x04
#define EV_SW                   0x05
#define EV_LED                  0x11
#define EV_SND                  0x12
#define EV_REP                  0x14
#define EV_FF                   0x15
#define EV_PWR                  0x16
#define EV_FF_STATUS            0x17
#define EV_MAX                  0x1f
#define EV_CNT                  (EV_MAX+1)

12.GNU C对标准C进行一系列扩展,以增强标准C的功能。

1)GNU C 允许使用零长度数组,在定义变长对象的头结构时,这个特性非常有用

2)GNU C中也可以使用1个变量定义数组长度
3)GNU C支持case xy这样的语法,区间[x,y]中的数都会满足这个case的条件
4)GNU C把包含在括号中的复合语句看成是一个表达式,称为语句表达式,它可以出现在
任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环、
局部变量等
5)typeof(x)语句可以获得x的类型
6)在GNU C中,宏也可以接受可变数目的参数
#define pr_debug(fmt,arg...) \
        printk(fmt,##arg)
使用“##”是为了处理arg不代表任何参数的情况,这时候,前面的逗号就变得多余了。
使用“ ##”之后,GNU C预处理器会丢弃前面的逗号

7)标准C要求数组或结构体的初始化值必须以固定的顺序出现,在GNU C 中,通过指定
索引或结构体成员名,允许初始化值以任意顺序出现。
指定数组索引的方法是在初始化
值前添加“[INDEX] =”,当然也可以用“[FIRST ...LAST] =”的形式指定一个范围。
_ _func_ _保存函数在源码中的名字
8)GNU C允许声明函数、变量和类型的特殊属性,以便手动优化代码和定制代码检查的
方法。要指定一个声明的属性,只需要在声明后添加 _ _attribute_ _ (( ATTRIBUTE ))。其
ATTRIBUTE 为属性说明,如果存在多个属性,则以逗号分隔。
unused属性作用于函数和变量,表示该函数或变量可能不会用到,这个属性可以避免编
译器产生警告信息。
aligned属性用于变量、结构体或联合体,指定变量、结构体或联合体的对齐方式,以字
节为单位
packed属性作用于变量和类型,用于变量或结构体成员时表示使用最小可能的对齐,用
于枚举、结构体或联合体类型时表示该类型使用最小的内存。
9)内建函数_ _builtin_expect(EXP, C)用于为编译器提供分支预测信息,其返回值是整数
表达式 EXP 的值, C 的值必须是编译时常数。
10)do{} while(0)的使用完全是为了保证宏定义的使用者能无编译错误
地使用宏,它不对其使用者做任何假设。

13、lsmod命令实际是读取并分析/proc/modules文件。加载hello.ko后内核中将包含/sys/module/hello目录

14、insmod, modprobe, rmmod, lsmod, depmod, modinfo

15、在中定义有错误编码,返回错误编码是种好习惯,这样可以用perror等方法显示错误信息。

16、Linux的“/proc/kallsyms”文件对应着内核符号表,它记录了符号以及符号所在的内存地址,通过如下的宏导出:
EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符号名);

17、lseek返回文件指针相对于文件头的位置,下列调用返回文件长度
lseek(fd, 0, SEEK_END);

18、DOS、Windows中区分二进制文件和文本文件,Linux中不区分。

19、ftell、fseek、fgetpos、fsetpos

20、Linux驱动笔记_第2张图片

21、同一类设备一般使用相同的主设备号,不同类设备一般使用不同的主设备号,次设备号用来描述使用该驱动的设备的序号。

22、
Linux驱动笔记_第3张图片
23、sysfs中的目录来源于bus_type、device_driver、device,而目录中的文件则来源于attribute。

24、Linux驱动笔记_第4张图片
Linux驱动笔记_第5张图片
Linux驱动笔记_第6张图片
25、

26、
Linux驱动笔记_第7张图片
27、
Linux驱动笔记_第8张图片
28、
Linux驱动笔记_第9张图片


你可能感兴趣的:(嵌入式,Unix/Linux)