內核等待機制學習(一)

假設咱們在 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

做者:流星

相關文章
相關標籤/搜索