用檔案那樣向裝置傳送資料。可是為什麼使用者使用write函式就可以把資料寫到裝置裡面
去,這個過程到底是怎麼實現的呢?
這個奧秘就在於裝置驅動程式的write實現中,這裡我結合一些源**來解釋如何使得一
個簡簡單單的write函式能夠完成向裝置裡面寫資料的複雜過程。
這裡的源**主要來自兩個地方。第一是oreilly出版的《linux device driver》中的
例項,第二是linux kernel 2.2.14核心源**。我只列出了其中相關部分的內容,如果
讀者有興趣,也可以查閱其它源**。不過我不是在講解如何編寫裝置驅動程式,所以不
會對每乙個細節都進行說明,再說有些地方我覺得自己還沒有吃透。
由於《linux device driver》一書中的例子對於我們還是複雜了一些,我將其中的乙個
例程簡化了一下。這個驅動程式支援這樣乙個裝置:核心空間中的乙個長度為10的陣列
kbuf[10]。我們可以通過使用者程式open它,read它,write它,close它。這個裝置的名
字我稱為short_t。
現在言歸正傳。
對於乙個裝置,它可以在/dev下面存在乙個對應的邏輯裝置節點,這個節點以檔案的形式
存在,但它不是普通意義上的檔案,它是裝置檔案,更確切的說,它是裝置節點。這個節
點是通過mknod命令建立的,其中指定了主裝置號和次裝置號。主裝置號表明了某一類設
備,一般對應著確定的驅動程式;次裝置號一般是區分是標明不同屬性,例如不同的使用
方法,不同的位置,不同的操作。這個裝置號是從/proc/devices檔案中獲得的,所以一
般是先有驅動程式在核心中,才有裝置節點在目錄中。這個裝置號(特指主裝置號)的主
要作用,就是宣告裝置所使用的驅動程式。驅動程式和裝置號是一一對應的,當你開啟一
個裝置檔案時,作業系統就已經知道這個裝置所對應的驅動程式是哪乙個了。這個"知道"
的過程後面就講。
我們再說說驅動程式的基本結構吧。這裡我只介紹動態模組型驅動程式(就是我們使用
insmod載入到核心中並使用rmmod解除安裝的那種),因為我只熟悉這種結構。
模組化的驅動程式由兩個函式是固定的:int init_module(void) ;void
cleanup_module(void)。前者在insmod的時候執行,後者在rmmod的時候執行。
init_nodule在執行的時候,進行一些驅動程式初始化的工作,其中最主要的工作有三
件:註冊裝置;申請i/o埠位址範圍;申請中斷irq。這裡和我們想知道的事情相關的只
有註冊裝置。
下面是乙個典型的init_module函式:
int init_module(void)/* init_module*/
上面這個函式我只保留了最重要的部分,其中最重要的函式是
result = register_chrdev(short_major, "short", &short_fops);
這是乙個驅動程式的精髓所在!!當你執行indmod命令時,這個函式可以完成三件大事:
第一,申請主裝置號(short_major),或者指定,或者動態分配;第二,在核心中註冊設
備的名字("short");第三,指定fops方法(&short_fops)。其中所指定的fops方法就是
我們對裝置進行操作的方法(例如read,write,seek,dir,open,release等),如何實現
這些方法,是編寫裝置驅動程式大部分工作量所在。
現在我們就要接觸關鍵部分了--如何實現fops方法。
我們都知道,每乙個檔案都有乙個file的結構,在這個結構中有乙個file_operations的
結構體,這個結構體指明了能夠對該檔案進行的操作。
下面是乙個典型的file_operations結構:
struct file_operations ;
我們可以看到它實際上就是許多檔案操作的函式指標,其中就有write,其它的我們就不
去管它了。這個write指標在實際的驅動程式中會以程式設計師所實現的函式名字出現,它指
向程式設計師實現的裝置write操作函式。下面就是乙個實際的例子,這個write函式可以向核
心記憶體的乙個陣列裡輸入乙個字串。
int short_write (struct inode *inode, struct file *filp, const char *buf,
int count)/* short_write */
裝置short_t對應的fops方法是這樣宣告的:
struct file_operations short_fops = ;
其中null的專案就是不提供這個功能。所以我們可以看出short_t裝置只提供了
read,write,open,release功能。其中write功能我們在上面已經實現了,具體的實現函
數起名為short_write。這些函式就是真正對裝置進行操作的函式,這就是驅動程式的一
大好處:不管你實現的時候是多麼的複雜,但對使用者來看,就是那些常用的檔案操作函式。
但是我們可以看到,驅動程式裡的write函式有四個引數,函式格式如下:
short_write (struct inode *inode, struct file *filp, const char *buf, int count)
而使用者程式中的write函式只有三個引數,函式格式如下:
write(inf fd, char *buf, int count)
那他們兩個是怎麼聯絡在一起的呢?這就要靠作業系統核心中的函式sys_write了,下面
是linux kernel 2.2.14中sys_write中的源**:
asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
我寫了乙個簡單的程式來測試這個驅動程式,該程式源**節選如下(該省的我都省了):
main()
現在我們就演示一下使用者使用write函式將資料寫到裝置裡面這個過程到底是怎麼實現的:
1,insmod驅動程式。驅動程式申請裝置名和主裝置號,這些可以在/proc/devieces中獲得。
2,從/proc/devices中獲得主裝置號,並使用mknod命令建立裝置節點檔案。這是通過主
裝置號將裝置節點檔案和裝置驅動程式聯絡在一起。裝置節點檔案中的file屬性中指明了
驅動程式中fops方法實現的函式指標。
3,使用者程式使用open開啟裝置節點檔案,這時作業系統核心知道該驅動程式工作了,就
呼叫fops方法中的open函式進行相應的工作。open方法一般返回的是檔案標示符,實際
上並不是直接對它進行操作的,而是有作業系統的系統呼叫在背後工作。
4,當使用者使用write函式操作裝置檔案時,作業系統呼叫sys_write函式,該函式首先通
過檔案標示符得到裝置節點檔案對應的inode指標和flip指標。inode指標中有裝置號信
息,能夠告訴作業系統應該使用哪乙個裝置驅動程式,flip指標中有fops資訊,可以告訴
作業系統相應的fops方法函式在那裡可以找到。
5,然後這時sys_write才會呼叫驅動程式中的write方法來對裝置進行寫的操作。
其中1-3都是在使用者空間進行的,4-5是在核心空間進行的。使用者的write函式和作業系統
的write函式通過系統呼叫sys_write聯絡在了一起。
注意:對於塊裝置來說,還存在寫的模式的問題,這應該是由gnu c庫來解決的,這裡不予討
論,因為我沒有看過gnu c庫的源**。
另外,這是乙個測試版的文章,請各位朋友們多提意見和建議,非常感謝!
**
linux驅動中的write函式
linux下我們在使用裝置的時候,都會用到write這個函式,通過這個函式我們可以象使 用檔案那樣向裝置傳送資料。可是為什麼使用者使用write函式就可以把資料寫到裝置裡面 去,這個過程到底是怎麼實現的呢?這個奧秘就在於裝置驅動程式的write實現中,這裡我結合一些源 來解釋如何使得一 個簡簡單單的...
write在sqlserver中的使用
我用乙個簡單的例子來說明一下 下面是乙個表 declare table table id int identity 1,1 window nvarchar max insert into table window select aaaa1111 union all select aaa111 uni...
Linux 驅動框架 驅動中的非同步
非同步io是對阻塞和輪詢io的機制補充,所謂非同步io就是在裝置資料就緒時主動通知所屬程序進行處理的機制。之所以說是非同步是相對與被通知程序的,因為程序不知道也無法知道什麼時候會被通知 這一機制非常類似於硬體上的中斷。非同步io的實現也依賴於linux核心程序的訊號機制,因為非同步io就是通過sig...