国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

設備驅(qū)動

2019-11-17 05:15:38
字體:
供稿:網(wǎng)友

  概述

一. linux設備概述
在概念上一般把設備分為字符設備、塊設備。字符設備是指設備發(fā)送和接收數(shù)據(jù)以字符形式的進行;而塊設備則以整個數(shù)據(jù)緩沖區(qū)的形式進行。但是,由于網(wǎng)絡設備等有其非凡性,實際上系統(tǒng)對它們單獨處理。

系統(tǒng)用主設備號(MAJOR)加次設備(MINOR)號來唯一標識一個設備。相同主設備號表示同一類設備,例如都是硬盤;次設備號標識同類設備的個數(shù)。所有設備在適當?shù)哪夸洠ㄍǔT?dev目錄下)下必須有相應的文件,這樣字符設備和塊設備都可以通過文件操作的系統(tǒng)調(diào)用了完成。不同的是,塊設備操作經(jīng)常要和緩沖區(qū)打交道,更加復雜一點。



[目錄]

--------------------------------------------------------------------------------


數(shù)據(jù)結(jié)構(gòu)

二. 主要數(shù)據(jù)結(jié)構(gòu)
與設備治理有關的主要數(shù)據(jù)結(jié)構(gòu)如下:
1、登記設備治理
系統(tǒng)對已登記設備的治理是由chrdevs和blkdevs這兩張列表來完成的:
/*srcfsdevices.c*/
strUCt device_struct {
const char * name; //指向設備名稱
struct file_Operations * fops; //指向設備的訪問操作函數(shù)集,file_operati
ons定義在
include/linux/fs.h中
};
static struct device_struct chrdevs[MAX_CHRDEV] = {
{ NULL, NULL },
}; //所有系統(tǒng)登記的字符設備列表
static struct device_struct blkdevs[MAX_BLKDEV] = {
{ NULL, NULL },
} //所有系統(tǒng)登記的塊設備列表

實際上這兩張列表的結(jié)構(gòu)是一樣的,但在登記時每個結(jié)構(gòu)元素的值會不同(見初始化部分)。linux對設備的進行訪問時,訪問文件系統(tǒng)中相應的文件,通過文件系統(tǒng)和文件的屬性描述塊,系統(tǒng)可以找到該文件系統(tǒng)或文件對應設備的設備號。在實際訪問列表時,以chrdevs[MAJOR][MINOR]或blkdevs[MAJOR][MINOR]形式訪問,相同主設備號(MAJOR)的元素中fops的內(nèi)容相同。

文件系統(tǒng)中相關的的數(shù)據(jù)結(jié)構(gòu)如下:
struct super_block {
kdev_t s_dev; //該文件系統(tǒng)所在設備的設備標志符

} //每個文件系統(tǒng)對應一個super_block
struct inode {
kdev_t i_dev; //該文件所在設備的設備標志符通過它可以找到在設備列表中
… 相應設備
} //每個文件對應一個inode

2、I/O請求治理

系統(tǒng)會把一部分系統(tǒng)內(nèi)存作為塊設備驅(qū)動程序與文件系統(tǒng)接口之間的一層緩沖區(qū),每個緩沖區(qū)與某臺塊設備中的特定區(qū)域相聯(lián)系,文件系統(tǒng)首先試圖存在相應的緩沖區(qū),如未找到就向該設備發(fā)出I/O讀寫請求,由設備驅(qū)動程序?qū)@些請求進行處理。因此,需要有相應的數(shù)據(jù)結(jié)構(gòu)進行治理。

/*srcincludelinuxlkdev.h*/
struct blk_dev_struct {
void (*request_fn)(void); //指向請求處理函數(shù)的指針,請求處理函數(shù)是寫設備驅(qū)動程序的重要一環(huán),設備驅(qū)動程序在此函數(shù)中通過outb向位于I/O空間中的設備命令寄存器發(fā)出命令

struct request * current_request; //指向當前正在處理的請求,它和plug共同維護了該設備的請求隊列
struct request plug; //這是LINUX2.0版本與以前版本的一個不同之處,plug主要被用于異步提前讀寫操作,在這種情況下,由于沒有非凡的請求,為了提高系統(tǒng)性能,需要等發(fā)送完所有的提前讀寫請求才開始進行請求處理,即unplug_device。
struct tq_struct plug_tq; //設備對應的任務隊列
};
/*srcdriverslockll_rw_blk.c*/
struct blk_dev_struct blk_dev[MAX_BLKDEV];
其中每個請求以request的類型的結(jié)構(gòu)進行傳遞,定義如下:
/*srcincludelinuxlk_dev.h*/
struct request {
volatile int rq_status; //表示請求的狀態(tài)
kdev_t rq_dev; //是該請求對應的設備號,kdev_t是unsigned s
hort類型,高8位是主設備號,低8位是從設備號,每一請求都針對一個設備發(fā)出的;
int cmd; //表示該請求對應的命令,取READ或WRITE;
int errors;
unsigned long sector; //每一扇區(qū)的字節(jié)數(shù)
unsigned long nr_sectors; //每一扇區(qū)的扇區(qū)數(shù)
unsigned long current_nr_sectors; //當前的扇區(qū)數(shù);

char * buffer; //存放buffer_head.b_data值,表示發(fā)出請求的
數(shù)據(jù)存取地址;
struct semaphore * sem; //一個信號量,用來保證設備讀寫的原語操作,

sem=0時才能處理該請求;
struct buffer_head * bh; //讀寫緩沖區(qū)的頭指針
struct buffer_head * bhtail; //讀寫緩沖區(qū)的尾指針
struct request * next; //指向下一個請求
};

對不同塊設備的所有請求都放在請求數(shù)組all_requests中,該數(shù)組實際上是一個請求緩沖池,請求的釋放與獲取都是針對這個緩沖池進行;同時各個設備的請求用next指針聯(lián)結(jié)起來,形成各自的請求隊列。定義如下:

/*srcdriverslokcll_rw_blk.c*/
static struct request all_requests[NR_REQUEST];

3、中斷請求

設備進行實際的輸入/輸出操作時,假如時間過長而始終被占用CPU,就會影響系統(tǒng)的效率,必須有一種機制來克服這個問題而又不引起其他問題。中斷是最理想的方法。和中斷有關的數(shù)據(jù)結(jié)構(gòu)是;

struct irqaction {
void (*handler)(int, void *, struct pt_regs *); //指向設備的中斷響應函數(shù),它在系統(tǒng)初始化時被置入。當中斷發(fā)生時,系統(tǒng)自動調(diào)用該函數(shù)
unsigned long flags; //指示了中斷類型,如正常中斷、快速中斷等
unsigned long mask; //中斷的屏蔽字
const char *name; //設備名
void *dev_id; //與設備相關的數(shù)據(jù)類型,中斷響應函數(shù)可以根

據(jù)需要將它轉(zhuǎn)化所需的數(shù)據(jù)指針,從而達到訪問系統(tǒng)數(shù)據(jù)的功能
struct irqaction *next; //指向下一個irqaction
};

由于中斷數(shù)目有限,且很少更新,所以系統(tǒng)在初始化時,從系統(tǒng)堆中分配內(nèi)存給每一個irq_action指針,通過next指針將它們連成一個隊列。

4、高速緩沖區(qū)

為了加速對物理設備的訪問速度,linux將塊緩沖區(qū)放在Cache內(nèi),塊緩沖區(qū)是由buffer_head連成的鏈表結(jié)構(gòu)。buffer_head的數(shù)據(jù)結(jié)構(gòu)如下:
/*includelinuxfs.h*/
struct buffer_head {
unsigned long b_blocknr; /* block number */
kdev_t b_dev; /* device (B_FREE = free) */
kdev_t b_rdev; /* Real device */
unsigned long b_rsector; /* Real buffer location on disk */
struct buffer_head * b_next; /* Hash queue list */
struct buffer_head * b_this_page; /* circular list of buffers in one page *
/
unsigned long b_state; /* buffer state bitmap (see above) */
struct buffer_head * b_next_free;
unsigned int b_count; /* users using this block */
unsigned long b_size; /* block size */
char * b_data; /* pointer to data block (1024 bytes) */
unsigned int b_list; /* List that this buffer appears */
unsigned long b_flushtime; /* Time when this (dirty) buffer should be
written */
unsigned long b_lru_time; /* Time when this buffer was last used. */
struct wait_queue * b_wait;
struct buffer_head * b_PRev; /* doubly linked list of hash-queue */
struct buffer_head * b_prev_free; /* doubly linked list of buffers */
struct buffer_head * b_reqnext; /* request queue */
};

塊緩沖區(qū)主要由鏈表組成。空閑的buffer_head組成的鏈表是按塊大小的不同分類組成,linux目前支持塊大小為512、1024、2048、4096和8192字節(jié);第二部分是正在用的塊,塊以Hash_table的形式組織,具有相同hash索引的緩沖塊連在一起,hash索引根據(jù)設備標志符和該數(shù)據(jù)塊的塊號得到;同時將同一狀態(tài)的緩沖區(qū)塊用LRU算法連在一起。對緩沖區(qū)的各個鏈表定義如下:
/* fsuffer.c*/
static struct buffer_head ** hash_table;
static struct buffer_head * lru_list[NR_LIST] = {NULL, };
static struct buffer_head * free_list[NR_SIZES] = {NULL, };
static struct buffer_head * unused_list = NULL;
static struct buffer_head * reuse_list = NULL;





[目錄]

--------------------------------------------------------------------------------


初始化

三. 設備的初始化
LINUX啟動時,完成了實模式下的系統(tǒng)初始化(arch/i386/boot/setup.S)與保護模式下的核心初始化包括初始化寄存器和數(shù)據(jù)區(qū)(arch/i386/boot/compressed/head.S)、核心代碼解壓縮、頁表初始化(arch/i386/kernel/head.S)、初始化idt、gdt和ldt等工作
后,系統(tǒng)轉(zhuǎn)入了核心。調(diào)用函數(shù)start_kernel啟動核心(init/main.c)后,將繼續(xù)各方面的初始化工作,其中start_kernel最后將調(diào)用kernel_thread (init, NULL, 0),創(chuàng)建init進程進行系統(tǒng)配置(其中包括所有設備的初始化工作)。
static int init(void * unused)
{
…………
/* 創(chuàng)建后臺進程bdflush,以不斷循環(huán)寫出文件系統(tǒng)緩沖區(qū)中"臟"的內(nèi)容 */
kernel_thread(bdflush, NULL, 0);
/* 創(chuàng)建后臺進程kswapd,專門處理頁面換出工作 */
kswapd_setup();
kernel_thread(kswapd, NULL, 0);
…………
setup();
…………
在setup函數(shù)中,調(diào)用系統(tǒng)調(diào)用sys_setup()。sys_setup()的定義如下:
//fs/filesystems.c
asmlinkage int sys_setup(void)
{
static int callable = 1;
… …
if (!callable)
return -1;
callable = 0;
… …
device_setup();
… …
在該系統(tǒng)調(diào)用中,靜態(tài)變量callable保證只被調(diào)用實際只一次,再次調(diào)用時后面的初始化程序不執(zhí)行。在該調(diào)用開始就先進行設備的初始化:device_setup()。
//dirvers/block/genhd.c
void device_setup(void)
{
extern void console_map_init(void);
… …
chr_dev_init();
blk_dev_init();
… …
可以看到device_setup()將依次執(zhí)行chr_dev_init()、blk_dev_init()等各類設備的初始化程序。每個具體的init函數(shù)的內(nèi)容和具體設備就有關了,但是它們都有一些必須完成的任務:
1、 告訴內(nèi)核這一驅(qū)動程序使用的主設備號,同時提供指向file_operation的指針,以完成對chrdevs和blkdevs的初始化。
2、 對塊設備,需要將輸入/輸出處理程序的入口地址告訴內(nèi)核。
3、 對塊設備,需要告訴緩沖區(qū)設備存取的數(shù)據(jù)塊的大小。





[目錄]

--------------------------------------------------------------------------------


治理流程

四. 設備治理的流程
下面我們介紹一下整個設備治理的流程。我們以塊設備為例,字符設備的流程也和塊設備類似,只是沒有請求隊列治理。
首先,文件系統(tǒng)通過調(diào)用ll_rw_block發(fā)出塊讀寫命令,讀寫請求治理層接到命令后,向系統(tǒng)申請一塊讀寫請求緩沖區(qū),在填寫完請求信息后,請求進入設備的讀寫請求隊列等候處理。假如隊列是空的,則請求立即得到處理,否則由系統(tǒng)負責任務調(diào)度,喚醒請求處理。在請求處理過程中,系統(tǒng)向I/O空間發(fā)出讀寫指令返回。當讀寫完畢后,通過中斷通知系統(tǒng),同時調(diào)用與設備相應的讀寫中斷響應函數(shù)。





[目錄]

--------------------------------------------------------------------------------


添加字符設備

五. 添加一個字符設備
作為對linux設備治理的分析的總結(jié),我們介紹一下如何添加一個設備,首先介紹如何添加一個字符設備。在后面的文章中,我們將新添加的設備稱為新設備,說明以我們實現(xiàn)的虛擬的字符設備為例,步驟基本如下:
1. 確定設備的設備名稱和主設備號:
我們必須找一個還沒有被使用的主設備號,分配給自己的字符設備。假設主設備號為30(在2.0.34的內(nèi)核中還沒有以30作為主設備號的字符設備)。

2. 確定編寫需要的file_operations中的操作函數(shù),包括:
static int my_open(struct inode * inode,struct file * file)
//通過宏指令MINOR()提取inode參數(shù)的I_rdev字段,確定輔助設備號,然后檢查相應的讀寫忙標志,看新設備是否已經(jīng)打開。假如是,返回錯誤信息;
否則置讀寫忙標志為true,阻止再次打開新設備。
static void my_release(struct inode * inode,struct file * file)
//同my_open類似,只是置讀寫忙標志為false,答應再次打開新設備。
static int my _write(struct inode * inode,struct file * file,const char * bu
ffer,int count)

//用于對該設備的寫
static int my _read(struct inode * inode , struct file * file,char * buffer,
int count)
//用于對該設備的讀
static int my_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
//用于傳送非凡的控制信息給設備驅(qū)動程序,或者長設備驅(qū)動程序取得狀態(tài)信息,在我們實現(xiàn)的虛擬字符設備中,這個函數(shù)的功能是用來打開和關閉跟蹤功能。

3. 確定編寫需要的初始化函數(shù):
void my_init(void)
//首先需要將上述的file_operations中的操作函數(shù)的地址賦給某個file_operations的結(jié)構(gòu)變量my_fops中的相應域;然后調(diào)用標準內(nèi)核函數(shù)登記該設備:register_chrdev(30,"mychd",&my_fops);最后對必要的變量(例如讀寫忙標志、跟蹤標志等)賦初值。

4. 在drivers/char/mem.c中添加相應語句;
在chr_dev_init函數(shù)之前添加drgn_init的原型說明:
void my_init (void);
在chr_dev_init函數(shù)的return語句之前添加以下語句:
my_init (); //用于在字符設備初始化時初始化新設備

5. 修改drivers/char/Makefile;
假設我們把所以必要的函數(shù)寫mychd.c中,則找到"L_OBJS := tty_io.o n_tty.o con
sole.o "行,將"mychd.o"加到其中。
6. 將該設備私有的*.c,*.h復制到目錄drivers/char下。
7. 用命令:make clean;make dep;make zImage重新編譯內(nèi)核。
8. 用mknod命令在目錄/dev下建立相應主設備號的用于讀寫的非凡文件。
完成了上述步驟,你在linux環(huán)境下編程時就可以使用新設備了。





[目錄]

--------------------------------------------------------------------------------


添加塊設備

六. 添加一個塊設備
接下來我們將介紹如何添加一個塊設備。在后面的文章中,我們將新添加的塊設備稱為新設備,塊設備的添加過程和字符設備有相似之處,我們將主要介紹其不同點,步驟基本如下:
1. 確定設備的設備名稱和主設備號
我們必須找一個還沒有被使用的主設備號,分配給自己的新設備。假設主設備號為30(在2.0.34的內(nèi)核中還沒有以30作為主設備號的塊設備),則需要在include/linux/major.h中加入如下句:
#define MY_MAJOR 30
這樣我們可以通過MY_MAJOR來確定設備為新設備,保證通用性。

2. 確定編寫需要的file_operations中的操作函數(shù):
static int my_open(struct inode * inode,struct file * file)
static void my_release(struct inode * inode,struct file * file)
static int my_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
由于使用了高速緩存,塊設備驅(qū)動程序就不需要包含自己的read()、write()和fsync()函數(shù),但必須使用自己的open()、 release()和 ioctl()函數(shù),這些函數(shù)的作用和字符設備的相應函數(shù)類似。

3. 確定編寫需要的輸入/輸出函數(shù):
static int my _read(void) //正確處理時返回值為1,錯誤時返回值為0
static int my _write(void) //正確處理時返回值為1,錯誤時返回值為0
值得注重的是這兩個函數(shù)和字符設備中的my read()、mywrite()函數(shù)不同:

參數(shù)不同:字符設備中的函數(shù)是帶參數(shù)的,用于對其工作空間(也可以看成是簡單的緩沖區(qū))中的一定長度(長度也是參數(shù)傳遞的)的字符進行讀寫;而塊設備的函數(shù)是沒有參數(shù)的,它通過當前請求中的信息訪問高速緩存中的相應的塊,因此不需要參數(shù)輸入。
調(diào)用形式不同:字符設備中的函數(shù)地址是存放在file_operations中的,在對字符設備進行讀寫時就調(diào)用了;而塊設備的讀寫函數(shù)是在需要進行實際I/O時在request中調(diào)用。這在后面可以看到。

4. 確定編寫需要的請求處理函數(shù):
static void my_request(void)
在塊設備驅(qū)動程序中,不帶中斷服務子程序的請求處理函數(shù)是簡單的,典型的格式如下

static void my_request(void)
{
loop:
INIT_REQUEST;

if (MINOR(CURRENT->dev)>MY_MINOR_MAX)
{
end_request(0);
goto loop;
}

if (CURRENT ->cmd==READ)
//CUREENT是指向請求隊列頭的request結(jié)構(gòu)指針
{
end_request(my_read()); //my_read()在前面已經(jīng)定義
goto loop;
}


if (CURRENT ->cmd==WRITE)
{
end_request(my_write()); //my_write()在前面已經(jīng)定義
goto loop;
}

end_request(0);
goto loop;
}
實際上,一個真正的塊設備一般不可能沒有中斷服務子程序,另外設備驅(qū)動程序是在系統(tǒng)調(diào)用中被調(diào)用的,這時由內(nèi)核程序控制CPU,因此不能搶占,只能自愿放棄;因此驅(qū)動程序必須調(diào)用sleep_on()函數(shù),釋放對CPU的占用;在中斷服務子程序?qū)⑺璧臄?shù)據(jù)復制到內(nèi)核內(nèi)存后,再由它來發(fā)出wake_up()調(diào)用,

5. 假如需要,編寫中斷服務子程序
實際上,一個真正的塊設備一般不可能沒有中斷服務子程序,另外設備驅(qū)動程序是在系統(tǒng)調(diào)用中被調(diào)用的,這時由內(nèi)核程序控制CPU,因此不能搶占,只能自愿放棄;因此驅(qū)動程序必須調(diào)用sleep_on()函數(shù),釋放對CPU的占用;在中斷服務子程序?qū)⑺璧臄?shù)據(jù)復制到內(nèi)核內(nèi)存后,再由它來發(fā)出wake_up()調(diào)用。
另外兩段中斷服務子程序都要訪問和修改特定的內(nèi)核數(shù)據(jù)結(jié)構(gòu)時,必須要仔細協(xié)調(diào),以防止出現(xiàn)災難性的后果。

首先,在必要時可以禁止中斷,這可以通過sti()和cli()來答應和禁止中斷請求。
其次,修改特定的內(nèi)核數(shù)據(jù)結(jié)構(gòu)的程序段要盡可能的短,使中斷不至于延時過長。含有中斷服務子程序的塊設備驅(qū)動程序的編寫相對比較復雜,我們還沒有完全實現(xiàn),主要問題是在中斷處理之間的協(xié)調(diào)。因為這些程序是要加入內(nèi)核的,系統(tǒng)默認為你是完全正確的,假如引起循環(huán)或者中斷長時間不響應,結(jié)果非常嚴重。我們正在努力實現(xiàn)這一程序。

6. 確定編寫需要的初始化函數(shù):
void my_init(void)
需要將的file_operations中的操作函數(shù)的地址賦給某個file_operations的結(jié)構(gòu)變量my_fops中的相應域;一個典型的形式是:
struct file_operations my_fops=
{
0,
block_read,
block_write,
0,
0,
my_ioctl,
0,
my_open,
my_release,
block_fsync,
0,
0,
0,
}
my_init中需要作的工作有:

首先調(diào)用標準內(nèi)核函數(shù)登記該設備:
register_chrdev(MY_MOJOR,"my--bdev",&my_fops);
將request()函數(shù)的地址告訴內(nèi)核:
blk_dev[MY_MAJOR].request_fn=DEVICE_REQUEST;
DEVICE_REQUEST是請求處理函數(shù)的地址,它的定義將在稍后可以看到。
告訴新設備的高速緩存的數(shù)據(jù)塊的塊大小:
my_block_size=512; //也可以是1024等等
blksize_size[MY_MAJOR]=& my_block_size;
為了系統(tǒng)在初始化時能夠?qū)π略O備進行初始化,需要在blk_dev_init()中添加一行代碼,可以插在blk_dev_init()中return 0的前面,格式為:
my_init();

7. 在include/linux/blk.h中添加相應語句;
到目前為止,除了DEVICE_REQUEST符合外,還沒有告訴內(nèi)核到那里去找你的request()函數(shù),為此需要將一些宏定義加到blk.h中。在blk.h中找到類似的一行:
#endif /*MAJOR_NR==whatever */
在這行前面加入如下宏定義:
#elif (MAJOR_NR==whatever)

static void my_request(void);
#define DEVICE_NAME "MY_BLK_DEV" //驅(qū)動程序名稱
#define DEVICE_REQUEST my_request //request()函數(shù)指針
#define DEVIEC_NR(device) (MINOR(device)) //計算實際設備號
#define DEVIEC_ON(device) //用于需要打開的設備
#define DEVIEC_OFF(device) //用于需要關閉的設備
8. 修改drivers/block/Makefile;
假設我們把所以必要的函數(shù)寫mybd.c中,則找到"L_OBJS := tty_io.o n_tty.o cons
ole.o "行,將"mybd.o"加到其中。
9. 將該設備私有的*.c,*.h復制到目錄drivers/block下。
10. 用命令:make clean;make dep;make zImage重新編譯內(nèi)核。
11. 用mknod命令在目錄/dev下建立相應主設備號的用于讀寫的非凡文件。
完成了上述步驟,你在linux環(huán)境下編程時就可以使用新設備了。





[目錄]

--------------------------------------------------------------------------------


一個虛擬的字符設備驅(qū)動程序

七. 一個虛擬的字符設備驅(qū)動程序
以下是一個虛擬的字符設備驅(qū)動程序,該程序是我和潘剛同學的試驗結(jié)果,本來我們還打算寫一個虛擬的塊設備驅(qū)動程序,由于時間關系,沒有能夠完全明白中斷中斷服務子程序的編寫方法,因此沒有沒有能夠?qū)崿F(xiàn)一個可以所有的虛擬的塊設備,非常遺憾。不過主要步驟已經(jīng)在上文中進行了介紹,我想再有一段時間應該能夠完成,到時候一定交給李老師看一下。
虛擬的字符設備驅(qū)動程序如下,在潘剛同學的試驗報告中也有介紹:
/* drgn.h */
#ifdef KERNEL
#define TRACE_TXT(text) {if(drgn_trace) {console_print(text);console_print("


");}}
#define TRACE_CHR(chr) {if(drgn_trace) console_print(chr);}
#define DRGN_READ 1
#define DRGN_WRITE 0
#endif
#define FALSE 0
#define TRUE 1
#define MAX_BUF 120
#define DRGN_TRON (('M' << icon_cool.gif0x01)
#define DRGN_TROFF (('M' << icon_cool.gif0x02)
struct drgn_buf
{
int buf_size;
char buffer[MAX_BUF];
struct drgn_buf *link;
};
/* drgn.c */
#define KERNEL
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/irq.h>
#include "drgn.h"
static int drgn_trace;
static int write_busy;
static int read_busy;
static struct drgn_buf * qhead;
static struct drgn_buf * qtail;
static int drgn_read(struct inode * , struct file * , char * , int );
static int drgn_write(struct inode * , struct file * , const char *, int );
static int drgn_ioctl(struct inode * , struct file * , unsigned int , unsig
ned long );
static int drgn_open(struct inode *,struct file *);
static void drgn_release(struct inode *,struct file *);
/* extern void console_print(char *);*/
struct file_operations drgn_fops=
{
NULL,
drgn_read,
drgn_write,
NULL,
NULL,
drgn_ioctl,
NULL,
drgn_open,
drgn_release,
NULL,
NULL,
NULL,
NULL
};
void drgn_init(void)
{
drgn_trace=TRUE;
if(register_chrdev(30,"drgn",&drgn_fops))
TRACE_TXT("Cannot register drgn driver as major device 30.")
else
TRACE_TXT("Tiny devie driver registered successfully.")
qhead=0;
write_busy=FALSE;
read_busy=FALSE;
/* drgn_trace=FALSE;*/
return;
}
static int drgn_open(struct inode * inode,struct file * file)
{
TRACE_TXT("drgn_open")
switch (MINOR(inode->i_rdev))
{
case DRGN_WRITE:
if(write_busy)
return -EBUSY;
else{
write_busy=TRUE;
return 0;
}
case DRGN_READ:
if(read_busy)
return -EBUSY;
else{
read_busy=TRUE;
return 0;
}
default:
return -ENXIO;
}
}
static void drgn_release(struct inode * inode,struct file * file)
{
TRACE_TXT("drgn_release")
switch (MINOR(inode->i_rdev))
{
case DRGN_WRITE:
write_busy=FALSE;
return;
case DRGN_READ:
read_busy=FALSE;
return;
}
}
static int drgn_write(struct inode * inode,struct file * file,

const char * buffer,int count)
{
int i,len;
struct drgn_buf * ptr;
TRACE_TXT("drgn_write")
if (MINOR(inode->i_rdev)!=DRGN_WRITE)
return -EINVAL;
if ((ptr=kmalloc(sizeof(struct drgn_buf),GFP_KERNEL))==0)
return -ENOMEM;
len=count < MAX_BUF?count:MAX_BUF;
if (verify_area(VERIFY_READ,buffer,len))
return -EFAULT;
for(i=0;i < count && i<MAX_BUF;++i)
{
ptr->buffer[i]=(char) get_user((char*)(buffer+i));
TRACE_CHR("w")
}
ptr->link=0;
if(qhead==0)
qhead=ptr;
else
qtail->link=ptr;
qtail=ptr;
TRACE_CHR("
")
ptr->buf_size=i;
return i;
}
static int drgn_read(struct inode * inode , struct file * file,
char * buffer, int count)
{
int i,len;
struct drgn_buf * ptr;
TRACE_TXT("drgn_read")
if(MINOR(inode->i_rdev)!=DRGN_READ)
return -EINVAL;
if (qhead==0)
return -ENODATA;
ptr=qhead;
qhead=qhead->link;
len=count < ptr->buf_size?count:ptr->buf_size;
if (verify_area(VERIFY_WRITE,buffer,len))
return -EFAULT;
for (i=0; i<count && i<ptr->buf_size; ++i)
{
put_user((char) ptr->buffer[i],(char *)(buffer+i));
TRACE_CHR("r")
}
TRACE_CHR("
")
kfree_s(ptr,sizeof(struct drgn_buf));
return i;
}
static int drgn_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
TRACE_TXT("drgn_ioctl")
/* if (cmd==DRGN_TRON){
drgn_trace=TRUE;
return 0;
}
else
if (cmd==DRGN_TROFF){
drgn_trace=FALSE;
return 0;
}
else
return -EINVAL;*/
switch(cmd)
{
case DRGN_TRON:
drgn_trace=TRUE;
return 0;
case DRGN_TROFF:
drgn_trace=FALSE;
return 0;
default:
return -EINVAL;
}
}

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 肥城市| 开封县| 牟定县| 灵宝市| 马山县| 阿拉善盟| 隆回县| 昌吉市| 桓台县| 舒兰市| 师宗县| 柞水县| 靖州| 绥宁县| 剑河县| 江安县| 永清县| 庆元县| 九龙县| 修文县| 瓦房店市| 绵阳市| 孝昌县| 赣州市| 武川县| 巴楚县| 盐亭县| 永丰县| 比如县| 中江县| 墨玉县| 汝城县| 延边| 建湖县| 罗甸县| 易门县| 扎赉特旗| 甘洛县| 义乌市| 永济市| 双流县|