ioctl
大多數ioctl
的實現中都包括乙個
switch
語句來根據
cmd引數選擇對應的操作。
使用者空間,ioctl
原型如下:
int ioctl(int fd, unsigned long cmd, …);
最後省略號一般表示可變引數,但在實際系統中,系統呼叫不會真正的使用可變數目的引數。它只是為了在編譯時防止編譯器進行型別檢查。因為有時它是乙個整形數,有時是乙個指標。
驅動程式的ioctl
原型:
int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
inode和
filp
兩個指標的值對應於應用程式傳遞的檔案描述符fd。
cmd是使用者空間傳遞過來的值。可選的
arg,無論使用者傳遞的是整數還是指標,都以
unsigned long
的形式傳給
arg。
通常ioctl
是乙個switch
語句,根據傳遞進來的
cmd執行相應的操作。
選擇ioctl
命令為驅動程式選擇乙個ioctl
編號,應該首先看看
include/asm/ioctl.h
和documention/ioctl-number.txt
這兩個檔案。
cmd由
type
,number
,direction
,size
四個部分組成。四部分定義在中。
包含的包含了大量的構造以及解析
cmd的巨集。如
_io(type, nr); //構造無引數的命令編號
_ior(type, nr, datatype); //構造從驅動程式讀取資料的命令編號
_iow(type, nr, datatype); //給驅動程式寫資料的命令編號
_iowr(type, nr, datatype); //雙向傳輸
解析cmd
的巨集:_ioc_dir(nr)
,_ioc_type(nr)
,_ioc_nr(nr)
,_ioc_size(nr)。
預定義命令
在定義我們用於ioctl
的命令時,需要注意避免與核心已有的命令相衝突。核心已有的命令有:
fioclex
,fionclex
,fioasync
,fioqsize
,fionbio。
使用ioctl
引數在驅動程式中,如果需要與使用者空間位址資料做交換,可以首先使用定義在
中的access_ok
來驗證位址。
int access_ok(int type, const void *addr, unsigned long size);
第乙個引數是verify_read
或者verify_write
,取決於是讀取還是寫入
使用者空間。如果既要讀取又要寫入,則應該是verify_write
。返回1
表示成功,
0表示失敗。
定義在中的函式:
put_user(data, ptr)
,__put_user(data, ptr)
,get_user(data, ptr)
,__get_user(data, ptr)
。可以用來與使用者空間交換1,
2,4,
8位元組內容。若
ptr是乙個指向字元的指標,則傳遞
1個位元組的內容。
權能和受限操作
對裝置的訪問由裝置檔案的許可權控制,驅動程式一般不進行檢查。
全部的權能操作可以在
中找到,對驅動程式開發者有意義的權能有:
cap_dac_override, cap_net_admin, cap_sys_module, cap_sys_rawio, cap_sys_admin, cap_sys_tty_config。
權能的檢查通過capable
函式實現(定義在
中)。
int capable(int capability);
休眠
休眠程序被從排程器的執行佇列移走,直到某情況下修改這個狀態,程序才會在cpu
上排程。
² 永遠不要在原子上下文進入休眠。
² 除非我們知道有其他人在其他地方會喚醒我們,否則程序不能進入休眠。
在linux
中,乙個等待佇列通過乙個「等待佇列頭
(wait queue head)
」管理。等待佇列頭是乙個型別為
wait_queue_head_t
的結構體。定義在中。
靜態初始化乙個等待佇列頭:
declare_wait_queue_head(name);
動態初始化乙個等待佇列頭:
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
linux核心中最簡單的休眠是
wait_event
巨集。如下:
wait_event(queue, condition);
wait_event_interruptible(queue, condition);
wait_event_timeout(queue, condition, timeout);
wait_event_iterruptible_timeout(queue, condition, timeout);
queue是等待佇列頭,它通過「值」傳遞。
condition
是乙個布林表示式,此表示式會被多次求值,因此對該表示式的求值不能帶來任何***。
wait_event_interruptible
返回乙個整數值,非零值表示休眠被某個訊號中斷。
喚醒的巨集有:
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
wake_up會喚醒
queue
上的所有程序,
wake_up_interruptible
只會喚醒哪些執行可中斷休眠的程序。
阻塞和非阻塞型操作
顯式的非阻塞io
由filp->f_flags
中的o_nonblock
標誌決定,這個標誌定義在。
在驅動程式中實現輸出緩衝區可以提高效能。
只有read
,write
和open
檔案操作受非阻塞標誌影響。
schedule函式:告訴核心重新選擇其他程序執行。
高階休眠----
手工休眠
1. 建立並初始化乙個等待佇列入口:
define_wait(my_wait);
也可以通過下步驟建立:
wait_queue_t my_wait;
init_wait(&my_wait);
2. 將我們的等待佇列入口加到佇列中。
void prepare_to_wait( wait_queue_head_t *queue,
wait_queue_t *wait,
int state);
3. 在prepare_to_wait
之後,程序即可呼叫
schedule
,當然在這之前,應確保仍有必要等待。
4. 最後清理。
void finish_wait(wait_queue_t *queue, wait_queue_t *wait);
獨佔等待
void prepare_to_wait_exclusive( wait_queue_head_t *queue,
wait_queue_t *wait,
int state);
設定等待佇列入口的「獨佔」標誌,並將程序新增到等待佇列的尾部。
查漏補缺
_sync版本函式一般在函式返回前不會重新排程
cpu。
#include
void poll_wait(struct file *filp, wait_queue_head_t *q, poll_table *p);
將當前程序置於某個等待佇列但不立即排程,該函式主要用於裝置驅動程式的poll
方法。
第六章 高階字元驅動程式操作
1 ioctl 除了讀取和寫入裝置之外,大部分驅動程式還需要另外一種能力,即通過裝置驅動程式執行各種型別的硬體控制。在使用者空間,ioctl系統呼叫有如下原型 int ioctl intfd,unsigned long cmd,char argp 驅動程式的ioctl方法原型與使用者空間的版本不一樣...
第六章 字元裝置
記錄一下 建立乙個簡單的字元裝置的編碼過程 前提準備 已經編譯好的linux核心 進入.drivers char 目錄 這裡存放著這字元裝置驅動 mkdir globalmem 建立乙個我們新建驅動的目錄並進入 新建globalmem.c檔案,清單如下 include include include...
第六章 LCD驅動移植
6.1 認識lcd相關硬體原理 lcd顯示屏相關引數,如何設定引數,如何根據型號編寫驅動 6.1.1 概述 0 顯示漢字,字元,圖形 低壓,低功耗,體積小,重量輕,超薄 1 根據物理結構 扭曲向列型 tn lcd 超扭曲向列型 stn lcd 雙層超扭曲向列型 dstn lcd 薄膜電晶體型 tft...