内核等待机制学习(一)

假设咱们在 kernel有一个 buffer,应用能够经过read,write等系统调用来读取或写数据到这个 buffer 里。node

若是有一个 app 写数据到 buffer 时,此时 buffer 已经满了。那么如何去处理这种情形呢 ? linux

第一种,传给 user 一个错误讯息,说 buffer 已经满了,不能再写入。app

第二种,将 user 的要求 block 住, 等app将 buffer 数据读走,留出空位时,再让 user 写入资料。框架

若是采用第二种,咱们就要用到wait_queue了。wait_queue 是 kernel 所提供的.函数

假设这里这个驱动例子将维护一个大小为20的buffer,并加入read和write功能:指针

当 buffer 中没有数据时,read() 就会被 block 住,直到有数据写入为止。blog

而当 write buffer 时,若是调用 write() 时,空间已满或写入的数据比 buffer 大时,就会被 block 住,进程

直到有A数据读出来为止。在 write buffer 的程序代码中,咱们使用 wait_queue 来作到 block IO 的功能。内存

今天主要先创建linux驱动程序的框架资源

1、linux驱动程序框架

第1步:创建Linux驱动程序框架(装载和卸载Linux驱动)

任何类型的程序都有一个基本的结构,例如,C语言须要有一个入口函数main。Linux驱动程序也不例外。Linux内核在使用驱动时首先须要装载驱动。

在装载过程当中须要进行一些初始化工做,例如,创建设备文件,分配内存地址空间等。当Linux系统退出时须要卸载Linux驱动,在卸载的过程当中须要释放

由Linux驱动占用的资源,例如,删除设备文件、释放内存地址空间等。在Linux驱动程序中须要提供两个函数来分别处理驱动初始化和退出的工做。这两个函数分别用module_init和module_exit宏指定。

Linux驱动程序通常都都须要指定这两个函数,所以包含这两个函数以及指定这两个函数的两个宏的C程序文件也可看做是Linux驱动的骨架。

第2步:注册和注销设备文件

任何一个Linux驱动都须要有一个设备文件。不然应用程序将没法与驱动程序交互。创建设备文件的工做通常在第1步编写的处理Linux初始化工做的函数

中完成。删除设备文件通常在第1步编写的处理Linux退出工做的函数中完成。

第3步:指定与驱动相关的信息

驱动程序是自描述的。例如,能够经过modinfo命令获取驱动程序的做者姓名、使用的开源协议、别名、驱动描述等信息。这些信息都须要在驱动源代

码中指定。经过 MODULE_AUTHOR、MODULE_LICENSE 、MODULE_ALIAS 、MODULE_DESCRIPTION等宏能够指定与驱动相关的信息。

第4步:定义能在设备上进行的操做

struct file_operations,函数指针的集合,定义能在设备上进行的操做。

当执行exampledev_init时,它将调用内核函数 register_chrdev,

把驱动程序的基本入口点指针存放在内核的字符设备地址表中,在用户进程对该设备执行系统调用时提供入口地址

二.模块

linux中的驱动程序,是以模块的形式编写的。模块的加载方式有两种:

1)用insmod命令手工加载模块。

2)一种直接编译进内核。

模块的卸载经过rmmod命令来删除模块。

模块的实现机制:

对于每个内核模块来讲,一定包含两个函数:卸载函数和初始化函数

一、将模块插入到内核时的初始化工做

1)准备struct file_operations结构体;

2)使用register_chrdev_region注册,申请设备号;

3)使用cdev_init初始化struct cdev结构体,创建cdev和file_operation之间的链接;

4)使用cdev_add增长struct cdev结构体;

5)出错处理。

1.2 从内核中删除模块时的清理工做

1)使用cdev_del删除struct cdev结构体;

2)释放其余申请的资源;

3)使用unregister_chrdev_region释放设备号。

3、设备注册

在linux2.6内核中,字符设备使用struct cdev结构来描述。

本文中,字符设备的注册分为两个步骤:

一、初始化cdev结构

struct cdev的初始化使用cdev_init来完成

syntax:

void cdev_init(struct cdev *cdev,struct file_operations *fops)

参数:

cdev:待初始化的cdev结构

fops:设备对应的操做函数集

二、添加cdev

struct cdev的注册使用cdev_add来完成

syntax:

int cdev_add(struct cdev *p,dev_t dev,unsigned count)

参数:

p:要注册的字符设备

dev:设备号,驱动程序对应的主设备号

count:添加的设备个数

如下是代码

globalfifo.c

#include <linux/module.h>

#include <linux/types.h>

#include <linux/fs.h>

#include <linux/errno.h>

#include <linux/mm.h>

#include <linux/sched.h>

#include <linux/init.h>

#include <linux/cdev.h>

#include <asm/io.h>

#include <asm/system.h>

#include <asm/uaccess.h>

#define GLOBALFIFO_SIZE 20

#define GLOBALFIFO_MAJOR 150

static int globalfifo_major = GLOBALFIFO_MAJOR;

struct globalfifo_dev

{

struct cdev cdev;

unsigned int current_len;

unsigned char mem[GLOBALFIFO_SIZE];

};

struct globalfifo_dev *globalfifo_devp;

int globalfifo_open(struct inode *inode, struct file *filp)

{

filp->private_data = globalfifo_devp;

return 0;

}

int globalfifo_release(struct inode *inode, struct file *filp)

{

return 0;

}

static const struct file_operations globalfifo_fops =

{

.owner = THIS_MODULE,

.open = globalfifo_open,

.release = globalfifo_release,

};

static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)

{

int err, devno = MKDEV(globalfifo_major, index);

cdev_init(&dev->cdev, &globalfifo_fops);

dev->cdev.owner = THIS_MODULE;

dev->cdev.ops = &globalfifo_fops;

err = cdev_add(&dev->cdev, devno, 1);

if(err)

printk(KERN_NOTICE "Error %d adding LED%d", err, index);

}

int globalfifo_init(void)

{

int ret;

dev_t devno = MKDEV(globalfifo_major, 0);

ret = register_chrdev_region(devno, 1, "globalfifo");

if(ret < 0)

return ret;

globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);

if(!globalfifo_devp)

{

ret = - ENOMEM;

goto fail_malloc;

}

memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));

globalfifo_setup_cdev(globalfifo_devp, 0);

return 0;

fail_malloc: unregister_chrdev_region(devno, 1);

return ret;

}

void globalfifo_exit(void)

{

cdev_del(&globalfifo_devp->cdev);

kfree(globalfifo_devp);

unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1);

}

MODULE_LICENSE("Dual BSD/GPL");

module_init(globalfifo_init);

module_exit(globalfifo_exit);

本文欢迎转载,转载请注明出处与做者

出处:http://blog.sina.com.cn/staratsky

做者:流星

相关文章
相关标签/搜索