I/O模型 阻塞态部分:
wait_queue_head_t wq;
//定义等待队列头
init_waitqueue_head(&wq);
//初始化等待队列头
<1> wait_event(wq, condition) //不可中断的等待态
wait_event_interruptible(wq, condition) //可中断的等待态
功能:让当前的进程休眠
参数:
@wq :等待队列头
(休眠的进程在内核中会被放到一个
队列中,这里的wq就是队列头)
@condition:条件为假,要休眠
为真,不需要休眠(数据准备好了)
返回值:成功返回0,失败返回错误码
<2> wake_up(&wq)
wake_up_interruptible(&wq)
功能:唤醒休眠的进程
参数:
@等待队列头
epoll部分:
#include <sys/epoll.h>
int epoll_create(int size);
功能:创建一个epoll的实例
参数:
@size: 已经不再使用,可以填写任意值
返回值:成功返回epoll的文件描述符,失败返回-1;
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:控制箱epfd中添加、修改、删除本次要监听的事件的类型
参数:
@epfd:epoll的文件描述符
@op :EPOLL_CTL_ADD 添加事件
EPOLL_CTL_MOD 修改事件
EPOLL_CTL_DEL 删除事件
@fd :文件描述符
@event:事件的结构体对象
返回值:成功返回0,失败返回-1
int epoll_wait(int epfd, struct epoll_event *revents,
int maxevents, int timeout);
功能:完成阻塞,如果有数据准备好,就返回
参数:
@epfd :epoll的文件描述符
@revents :返回的事件结构体
@maxevents:最大的结构体个数
@timeout :超时时间
返回值:1.成功返回准备好的文件描述符的个数
2.超时返回0
3.失败返回-1;
Linux内核中断部分
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags,const char *name, void *dev)
功能:在linux内核中注册中断处理函数
参数:
@irq :软中断号:根据gpio号通过映射得到软中断号
例:
A B C D E
组号m: 0 1 2 3 4
A组内偏移号n: 0 - 31
gpio的编号 = 组号*32+组内偏移号
gpioc18: = 2*32+18
将gpio号映射成软中断号:
软中断号 = gpio_to_irq(gpio号);
@handler:中断处理函数的指针
typedef irqreturn_t (*irq_handler_t)(int, void *);
中断函数
@irqno :软中断号
@args :request_irq最后一个参数传递过来的值
irqreturn_t handle_key_irq(int irqno, void * args)
{
return IRQ_NONE :
1.中断处理函数执行失败,返回IRQ_NONE
2.如果是共享中断,同时有两个中断处理函数,
都被同时触发了,不需要执行中断处理函数
的设备就返回IRQ_NONE
return IRQ_HANDLED :中断正常执行成功了
}
@flags :中断的触发方式
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
#define IRQF_DISABLED 0x00000020 #快速中断,在处理本中断的时候关闭其他中断
#define IRQF_SHARED 0x00000080 #共享中断
@name :中断的名字 cat /proc/interrupts(最后一个字段)
@dev :向中断处理函数传递的参数
返回值:成功返回0,失败返回错误码
void free_irq(unsigned int irq, void *dev_id)
功能:释放中断
参数:
@irq :软中断号
@dev_id:中断处理函数最后一个成员传递的参数
按键中断:
gpiob8 左键
gpiob16 右键
gpio子系统部分:
int gpio_request(unsigned gpio, const char *label)
功能:申请一个gpio去使用
参数:
@gpio :gpio的编号
@label:名字,NULL
返回值:成功返回0,失败返回错误码
int gpio_direction_input(unsigned gpio)
功能:设置gpio为输入
参数:
@gpio :gpio编号
返回值:成功返回0,失败返回错误码
int gpio_direction_output(unsigned gpio, int value)
功能:设置gpio为输出
参数:
@gpio :gpio编号
@value: 1输出高 0输出低
返回值:成功返回0,失败返回错误码
void gpio_set_value(unsigned gpio, int value)
功能:设置gpio输出的高低电平
参数:
@gpio :gpio编号
@value: 1输出高 0输出低
int gpio_get_value(unsigned gpio)
功能:获取gpio的高低电平的值
参数:
@gpio :gpio编号
返回值:读到1表示输出高电平 读到0表示输出低
void gpio_free(unsigned gpio)
功能:释放gpio
参数:
@gpio :gpio编号
platform总线部分:
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num)
功能:在驱动端获取设备信息
参数:
@dev :设备端的对象的指针
@type :资源的类型
@num :同类资源中的第几个,每种资源都是从0开始的。
返回值:成功返回struct resource *的结构体指针
失败返回NULL
int platform_get_irq(struct platform_device *dev, unsigned int num)
功能:获取中断资源
参数:
@dev :设备端的对象的指针
@num :中断资源中的第几个,每种资源都是从0开始的。
返回值:成功返回中断号,失败返回错误码
i2c驱动控制部分:
int i2c_register_board_info(int busnum,
struct i2c_board_info const *info, unsigned len)
功能:向控制器提交名字
参数:
@busnum :总线号(它和控制器的序号一一对应) 2
@info :被提交的信息
@len :提交的i2c_board_info的个数
返回值:成功返回0,失败返回错误码
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
功能:消息的发送函数
参数:
@adap :总线驱动的对象 client->adapter
@msgs :消息结构体指针
@num :消息的个数
返回值:成功返回发送了的消息的格式,
否者不是发送的消息的个数。
块儿设备驱动部分:
struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
功能:初始化一个队列
参数:
@rfn :队列处理函数
typedef void (request_fn_proc) (struct request_queue *q);
//这个是队列处理函数的原型,在这个函数中要进行读写操作
@lock :自旋锁
返回值:成功返回初始化好的队列的指针
失败返回NULL
struct request *blk_fetch_request(struct request_queue *q)
功能:从队列中取出一个请求
参数:
@q :队列
返回值:成功返回request结构体指针
失败返回NULL
void blk_cleanup_queue(struct request_queue *q)
功能:清除队列
参数:
@q:被清除的队列
返回值:无
request的操作:
sector_t blk_rq_pos(const struct request *rq)
功能:从请求中获取本次操作的起始的函数
unsigned int blk_rq_cur_sectors(const struct request *rq)
功能:获取本次想读写的扇区的个数
int blk_rq_cur_bytes(const struct request *rq)
功能:获取本次想读写的字节的个数
rq_data_dir(rq)
功能:从request中获取本次是读还是写
rq_data_dir(rq) == READ 读
rq_data_dir(rq) == WRITE 写
bool __blk_end_request_cur(struct request *rq, 0)
功能:判断request的读写是否处理完了
参数:
@rq :请求队列
返回值:真:表示数据没有处理完
假:数据处理完成了
gendisk内存分配并初始化的函数
struct gendisk *alloc_disk(int minors)
功能:分配内存并初始一些内容
参数:
@minors :设备的个数
int register_blkdev(unsigned int major, const char *name)
功能:申请块设备的设备号
参数:
@major :如果填写的是大于0的值静态指定设备号
如果填写的是0表示动态申请设备号
@name :cat /proc/devices
返回值:
major > 0 成功返回0,失败返回错误码
major = 0 成功返回主设备号,失败返回小于等于0的值
void unregister_blkdev(unsigned int major, const char *name)
功能:失败块设备的设备号
参数:
@major :主设备号
@name :名字
返回值:无
void add_disk(struct gendisk *disk)
功能:注册gendisk
参数:
@disk :gendisk对象的地址
void del_gendisk(struct gendisk *disk)
功能:注销gendisk
参数:
@disk :gendisk对象的地址
Linux内存分配部分:
void *kmalloc(size_t s, gfp_t gfp)
功能:分配对应的虚拟内存
参数:size:分配内存区的大小(2的次幂,最大是128K,连续)
flags:内存分配标志
GFP_KERNEL:内核可能被休眠,进程上下文,不能用于中断上下文中
GFP_ATOMIC:处理紧急的事务,用在中断上下文
返回值:对应虚拟地址
特点:最大128k , 分配虚拟地址,其虚拟地址空间连续,物理地址空间也是连续
类似函数:kzalloc:kmalloc+memset(buf,0,sizeof(buf));
void kfree(const void *x)
功能:释放对应的虚拟内存
参数:x:虚拟内存的起始地址
返回值:无
void *vmalloc(unsigned long size)
功能:分配对应的虚拟内存
参数:size:分配内存区的大小
返回值:对应虚拟地址
特点:分配虚拟地址,其虚拟地址空间连续,但是物理地址空间不一定连续
void vfree(const void *addr)
功能:释放对应的虚拟内存
参数:addr:虚拟内存区的首地址
返回值:无
unsigned long __get_free_page(gfp_t gfp)
功能:分配一个物理页
参数:
@gfp:
GFP_KERNEL:内核可能被休眠,进程上下文,不能用于中断上下文中
GFP_ATOMIC:处理紧急的事务,用在中断上下文
void free_page(unsigned long addr)
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
功能:分配多个物理页
参数:
@gfp_mask:
GFP_KERNEL:内核可能被休眠,进程上下文,不能用于中断上下文中
GFP_ATOMIC:处理紧急的事务,用在中断上下文
@order:填写的是想分配内存的次值n=get_order(57600)
57600 = 2^n
void free_pages(unsigned long addr, unsigned long order)