首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

LINUX设备驱动程序-翻阅笔记(原创)

2012-08-14 
LINUX设备驱动程序--阅读笔记(原创)LINUX设备驱动程序(LINUX DEVICE DRIVERS )--阅读笔记由? 王宇 原创并

LINUX设备驱动程序--阅读笔记(原创)

LINUX设备驱动程序(LINUX DEVICE DRIVERS )--阅读笔记


由? 王宇 原创并发布


设备驱动程序简介

??? 设备驱动程序的作用

??? 内核功能划分


??? ??? 进程管理

??? ??? 内存管理

??? ??? 文件系统

??? ??? 设备控制

??? ??? 网络功能

??? ??? 可装在模块

??? ??? ??? insmod将模块链接到内核

??? ??? ??? rmmode将模块移除内核

??? 设备和模块的分类


??? ??? 字符模块

??? ??? 块模块

??? ??? 网络模块

??? 安全问题

??? 版本编号

??? 许可证条款

??? 加入内核开发社区



构造和运行模块

??? 设置测试系统

??? HelloWorld模块


??? ??? insmod模块安装工具

??? ??? rmmod模块移去工具

??? 核心模块与应用程序的对比

??? ??? 模块预先注册自己,用于服务某种请求

??? ??? 模块退出时需要释放资源

??? ??? 模块错误会影响到整个系统

??? ??? 用户空间和内核空间

??? ??? ??? 不同地址空间

??? 编译和装载

??? 内核符号表


??? 预备知识

??? 初始化和关闭

??? 模块参数

??? 在用户空间编写驱动程序

??? 快速参考


??? ??? 用来装载模块到正运行的内核和移除模块的用户空间工具:

??? ??? ??? insmod

??? ??? ??? modprobe

??? ??? ??? ??? modprobe功能就是,对系统里的模块进行增、减、安装、删除等等操作。类似于insmod

??? ??? ??? rmmod

??? ??? 用于指定模块的初始化和清除函数的宏(可选的)

?


? .

时间、延迟及延缓操作

??? 概述

??? ??? 如何度量时间差,如何比较时间

??? ??? 如何获得当前时间

??? ??? 如何将操作延迟指定的一段时间

??? ??? 如何调度异步函数到指定的时间之后执行

??? 度量时间差

??? ??? 使用jiffiles计数器

??? ??? 处理器特定的寄存器

??? 获取当前时间

??? 延迟执行


??? ??? 长延迟

??? ??? ??? 忙等待

??? ??? ??? 让出处理器

??? ??? ??? 超时

??? ??? 短延迟

??? 内核定时器

??? ??? 定时器API

??? ??? 内核定时器的实现

??? tasklet

??? ??? 和内核定时器不同的是,我们不能要求tasklet在某个给定时间执行

??? 工作队列

??? ??? 共享队列

??? ??? tasklet会在很短的时间段内很快执行,并且以原子模式执行,而工作队列函数可具有更长的延迟并且不必原子化

??? 快速参考

??? ??? 时钟:#include<linux/param.h>

??? ??? ??? HZ符号指出每秒钟产生的时钟滴答数

??? ??? ??? jiffies_64变量会在每个时钟滴答递增

??? ??? ??? ??? volatieunsignedlongjiffies

??? ??? ??? ??? u64jiffies_64

??? ??? ??? 以安全方式比较:jiffies

??? ??? ??? ??? int time_after(unsignedlonga,unsignedlongb);

??? ??? ??? ??? int time_before(unsignedlonga,unsignedlongb);

??? ??? ??? ??? int time_after_eq(unsignedlonga,unsignedlongb);

??? ??? ??? ??? int time_before_eq(unsignedlonga,unsignedlongb);

??? ??? ??? 无竞争地获得jiffies_64的值

??? ??? ??? ??? u64 get_jiffies_64(void);

??? ??? ??? 在jiffies表示的时间和其他表示法之间转换

??? ??? ??? ??? #include<linux/time.h>

??? ??? ??? ??? unsigned long timespec_to_jiffies(structtimespec*value);

??? ??? ??? ??? void jiffies_to_timespec(unsignedlongjiffies,structtimespec*value);

??? ??? ??? ??? unsigned longtimeval_to_jiffies(structtimeval*value);

??? ??? ??? ??? void timeval_to_jiffies(unsignedlongjiffies,structtimeval*value);

??? ??? ??? x86专用宏,用来读取时间瞬计数器

??? ??? ??? ??? #include<asm/msr.h>

??? ??? ??? ??? ??? rdtsc(low32,high32);

??? ??? ??? ??? ??? rdtscl(low32);

??? ??? ??? ??? ??? rdtscll(var32);

??? ??? ??? 以平台无关的方式返回时间瞬计算器

??? ??? ??? ??? #include<linux/timex.h>

??? ??? ??? ??? cycle_tget_cycles(void)

??? ??? ??? 根据6个无符号的int参数返回在Epoch以来的秒数

??? ??? ??? ??? #include<time.h>

??? ??? ??? ??? unsigned long mktime(year,mon,day,h,m,s);

??? ??? ??? 以自Epoch以来的秒数和毫秒数的形式返回当前时间

??? ??? ??? ??? void do_gettimeofday(structtimeval*tv);

??? ??? ??? 以jiffies为分辨率返回当前时间

??? ??? ??? ??? struct timespeccurrent_kernel_time(void);

??? ??? 延时:#include<linux/wait.h>

??? ??? ??? 是当前进程休眠在等待队列上,并指定用jiffies表达的超时值

??? ??? ??? ??? longwait_event_interruptible_timeout(wait_queue_interruptible*q,intconditon,unsingedlongtimeout);

??? ??? ??? 调用调度器,确保当前进程可在给定的超时值之后被唤醒

??? ??? ??? ??? #include<linux/sched.h>

??? ??? ??? ??? signed long schedule_timeout(signedlongtimeout);

??? ??? ??? 引入整数的纳秒、微秒、毫秒级延时

??? ??? ??? ??? #include<linux/delay.h>

??? ??? ??? ??? void ndelay(unsignedlongnsec);

??? ??? ??? ??? void udelay(unsignedlongusec);

??? ??? ??? ??? void mdely(unsignedlongmsec);

??? ??? ??? 使进程休眠给定的毫秒数

??? ??? ??? ??? void msleep(unsignedlongmillisec);

??? ??? ??? ??? unsigned long msleep_interruptible(unsignedlongmillisec);

??? ??? ??? ??? void ssleep(unsignedintseconds);

??? ??? 内核定时器

??? ??? ??? 返回布尔值已告知调度代码是否在中断上下文或者在原子上下文中执行

??? ??? ??? ??? #include<asm/hardirq.h>

??? ??? ??? ??? int in_interruptible(void);

??? ??? ??? ??? int in_atomic(void);

??? ??? ??? 初始化定时器

??? ??? ??? ??? #include<linux/timer.h>

??? ??? ??? ??? void init_timer(structtimer_list*timer);

??? ??? ??? ??? struct timer_listTIMER_INITIALIZER(_function,_expires,_data);

??? ??? ??? 注册定时器结构,以在当前CPU上运行

??? ??? ??? ??? voidadd_timer(structtimer_list*timer);

??? ??? ??? 修改一个已经调度的定时器结构的到期时间

??? ??? ??? ??? intmod_timer(structtimer_list*timer,unsignedlongexpires);

??? ??? ??? 用来判断给定的定时器结构是否已经被注册运行

??? ??? ??? ??? int timer_pending(structtimer_list*timer)

??? ??? ??? 从活动定时器清单中删除一个定时器

??? ??? ??? ??? void del_timer(structtimer_list*timer);

??? ??? ??? ??? void del_timer_sync(structtimer_list*timer);

??? ??? tasklet

??? ??? ??? 声明tasklet结构和初始化

??? ??? ??? ??? #include<linux/interrupt.h>

??? ??? ??? ??? DECLARE_TASKLET(name,func,data);

??? ??? ??? ??? DECLARE_TASKLET_DISABLED(name,func,data);

??? ??? ??? 禁用或重新启用tasklet

??? ??? ??? ??? void tasklet_disable(structtasklet_struct*t);

??? ??? ??? ??? void tasklet_disable_nosync(structtasklet_struct*t);

??? ??? ??? ??? void tasklet_enable(structtaslet_struct*t);

??? ??? ??? 调度运行某个tasklet

??? ??? ??? ??? void tasklet_schedule(structtasklet_struct*t);

??? ??? ??? ??? void tasklet_hi_schedule(structtaskletstruct*t);

??? ??? ??? 从活动列表中删除

??? ??? ??? ??? void tasklet_kill(structtasklet_struct*t);

??? ??? 工作队列

??? ??? ??? 结构和入口项

??? ??? ??? ??? #include<linux/workqueue.h.>

??? ??? ??? ??? struct workqueue_struct;

??? ??? ??? ??? struct work_struct;

??? ??? ??? 用于创建和消除工作队列

??? ??? ??? ??? struct workqueue_struct*create_workqueue(constchar*name);

??? ??? ??? ??? struct workqueue_struct*create_singlethread_workqueue(constchar*name);

??? ??? ??? 声明和初始化工作队列

??? ??? ??? ??? DECLARE_WORK();

??? ??? ??? ??? INIT_WORK();

??? ??? ??? ??? PREPARE_WORK;

??? ??? ??? 用于安排工作以便从工作队列中执行的函数

??? ??? ??? ??? int queue_work(structworkqueue_struct*queue,structwork_struct*work)

??? ??? ??? ??? intqueue_delayed_work(structworkqueue_struct*queue,structwork_struct*work,unsignedlongdelay);

??? ??? ??? 删除一个入口项

??? ??? ??? ??? int cancel_delayed_work(structwork_struct*work);

??? ??? ??? ??? void flush_workqueue(structworkqueue_struct*queue);

??? ??? ??? 使用共享工作队列的函数

??? ??? ??? ??? int schedule_work(structwork_struct*work);

??? ??? ??? ??? int schedule_delayed_work(structwork_struct*work);

??? ??? ??? ??? void flush_schedule_work(void);

分配内存

??? kmalloc函数的内幕

??? 后备高速缓存

??? get_free_page和相关函数

??? vmalloc及其辅助函数

??? per-CPU变量

??? 获取大的缓冲区


与硬件通讯

??? I/O端口和I/O内存

??? ??? I/O寄存器和常规内存

??? ??? ??? I/O操作具有边际效应

??? ??? 外部设备寄存器和内存结构的映射可以有两种方法1映射到内存地址中,但是不占用物理内存;ARM体系结构采用这种方法。2映射到IO端口号中,使用专门的CPU命令INOUT进行处理;X86体系结构采用这种方法。

??? ??? 控制寄存器、状态寄存器和数据寄存器三大类

??? 使用I/O端口

??? ??? I/O端口分配

??? ??? 操作I/O端口

??? ??? 在用户空间访问I/O端口

??? ??? 串操作

??? ??? 暂停时I/O

??? ??? 平台相关性

??? ??? ??? 相关平台IO表

??? I/O端口示例

??? ??? 并口介绍

??? ??? 示例驱动程序

??? 使用I/O内存

??? ??? I/O内存分配和映射

??? ??? 访问I/O内存

??? ??? 像I/O内存一样使用端口

??? ??? 为I/O内存重用short

??? ??? 1MB地址空间之下的ISA内存

??? ??? isa_readb及相关函数

??? 快速参考

??? ??? 内存屏蔽

??? ??? ??? “软件”内存屏蔽

??? ??? ??? #include<linux/kernel.h>

??? ??? ??? void barrier(void);

??? ??? ??? “硬件”内存屏蔽

??? ??? ??? #include<asm/system.h>

??? ??? ??? void rmb(void);

??? ??? ??? void wmb(void);

??? ??? ??? void read_barrier_depends();

??? ??? ??? void mb();

??? ??? ??? 用于读写I/O端口

??? ??? ??? #include<asm/io.h>

??? ??? ??? ??? unsigned inb(unsignedport);

??? ??? ??? ??? void outb(unsignedcharbype,unsignedport);

??? ??? ??? ??? unsigned inw(unsignedport);

??? ??? ??? ??? void outw(unsignedshortword,unsignedport);

??? ??? ??? ??? unsigned inl(unsignedport);

??? ??? ??? ??? void outl(unsigneddoubleword,unsignedport);

??? ??? ??? ??? 如果用户空间有访问端口的权限

??? ??? ??? ??? ??? unsigned inb_p(unsignedport);....

??? ??? 端口

??? ??? ??? 为端口分配资源的函数

??? ??? ??? ??? struct resourcerequest_region(unsignedlongstart,unsignedlonglen,char*name);

??? ??? ??? ??? void release_region(unsignedlongstart,unsignedlonglen);

??? ??? ??? ??? int check_region(unsignedlongstart,unsignedlonglen);

??? ??? ??? 这类传输是通过对同一端口连续读/写count次实现

??? ??? ??? ??? void insb(unsignedport,void*addr,longcount);

??? ??? ??? ??? void outsb(unsinedport,void*addr,longcount);

??? ??? ??? ??? void intwb(unsignedport,void*addr,longcount);

??? ??? ??? ??? void outwb(unsignedport,void*addr,longcount);

??? ??? ??? ??? void inlb(unsignedport,void*addr,longcount);

??? ??? ??? ??? voidoutlb(unsignedport,void*addr,longcount);

??? ??? 内存IO

??? ??? ??? 处理对内存区域的资源分配

??? ??? ??? ??? struct resourcerequest_mem_region(unsignedlongstart,unsignedlonglen,char*name);

??? ??? ??? ??? void release_mem_region(unsignedlongstart,unsignedlonglen);

??? ??? ??? ??? int check_mem_reqion(unsignedlongstart,unsignedlonglen);

??? ??? ??? 把一个物理地址范围重新映射到处理器的虚拟地址空间,以提供内核使用

??? ??? ??? ??? #include<asm/io.h>

??? ??? ??? ??? void*ioremap(unsignedlong*phys_add,unsignedlongsize);

??? ??? ??? ??? void*ioremap_nocache(unsignedlong*phys_add,unsignedlongsize);

??? ??? ??? ??? voidiounmap(void*virt_addr);

??? ??? ??? 用来访问I/O内存

??? ??? ??? ??? #inlcude<as/io.h>

??? ??? ??? ??? unsigned int ioread8(void*addr);

??? ??? ??? ??? unsigned int ioread16(void*addr);

??? ??? ??? ??? unsigned int ioread32(void*addr);

??? ??? ??? ??? voidio write8(u8value,void*addr);

??? ??? ??? ??? voidio write16(u16value,void*addr);

??? ??? ??? ??? voidio write32(u32value,void*addr);

??? ??? ??? ??? 重复版本

??? ??? ??? ??? ??? void ioread8_req(void*addr,void*buf,unsignedlongcount);

??? ??? ??? ??? ??? void iowrite8_req(void*addr,void*buf,unsignedlongcount);

??? ??? ??? ??? 不安全的老IO内存函数

??? ??? ??? ??? ??? unsigned readb(address);

??? ??? ??? ??? ??? unsigned readw(address);

??? ??? ??? ??? ??? unsigned readl(address);

??? ??? ??? ??? ??? void writeb(unsignedvalue,address);。。。

??? ??? ??? 如果驱动程序作者希望将I/O端口作为I/O内存一样进行操作

??? ??? ??? ??? void*ioport_map(unsignedlongport,unsignedintcount);

??? ??? ??? ??? voidioport_unmap(void*addr);

中断处理

??? 准备并口

??? 安装中断处理例程

??? 实现中断处理例程

??? 顶半部和底半部

??? 中断共享

??? 中断驱动的I/O


??? 快速参考

??? ??? 注册和注销中断处理例程

??? ??? ??? #include<linux/interrupt.h>

??? ??? ??? ??? int request_irq(unsignedintirq,irqrequst_t(*handler)(),unsigndlongflags,constchar*dev_name,void*dev_id);

??? ??? ??? ??? void free_irq(unsignedintirq,void*dev_id);

??? ??? i386和x86_64体系架构上可用

??? ??? ??? int can_request_irq(unsignedintirq,unsignedlongflag);

??? ??? request_irq函数的标志

??? ??? ??? #include<asm/signal.h>

??? ??? ??? SA_INTERRUPT安装一个快速的处理例程

??? ??? ??? SA_SHIRQ安装一个共享的处理例程

??? ??? ??? SA_SAMPLE_RANDOM中断时间瞬可用来产生系统X

??? ??? 文件系统节点用于汇报关于硬件中断和已安装处理例程的信息

??? ??? ??? /proc/interrupts

??? ??? ??? /proc/stat

??? ??? 当驱动程序不得不深探测设备,以确定该设备使用那根中断信号线时

??? ??? ??? unsigned long probe_irq_on(void);

??? ??? ??? int probe_irq_off(unsignedlong);

??? ??? 中断处理例程的可能返回值

??? ??? ??? IRQ_NONE

??? ??? ??? IRQ_HANDLE

??? ??? ??? IRQ_RETVAL

??? ??? 驱动程序可以启动和禁止中断报告

??? ??? ??? voiddisable_irq(intirq);

??? ??? ??? voiddisable_irq_nosync(intirq);

??? ??? ??? voidenable_irq(intirq);

??? ??? 禁止和启用本地处理器上的中断

??? ??? ??? void local_irq_save(unsignedlongflags);

??? ??? ??? void local_irq_restore(unsignedlongflags);

??? ??? 用于无条件禁用和启用当前处理器中断的函数

??? ??? ??? void local_irq_disable(void);

??? ??? ??? void local_irq_enable(void);

内核的数据类型

??? 内核开发人员移植遇到若干问题都和不正确数据类型有关

??? 使用标准C语言类型

??? 为数据项分配确定的空间大小

??? 接口特定的类型

??? 其他有关移植性的问题

??? 链表


PCI驱动程序

USB驱动程序

Linux设备模型

内存映射和DMA

块设备驱动程序

网络驱动程序

TTY驱动程序

热点排行