假設咱們在 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
做者:流星