開發虛擬串列埠驅動程式

2021-05-22 00:25:37 字數 4241 閱讀 8225

虛擬串列埠就是當本地並沒有對應的串列埠硬體裝置,而為應用層提供串列埠裝置一樣的系統呼叫介面,以相容原本使用本地串列埠的應用軟體的「虛」裝置。本文作者給出了一種在windows平台上實現虛擬串列埠的方法,由此實現的「串列埠」具有真實串列埠完全相同的系統呼叫介面。

在很多應用中需要用到虛擬串列埠,如在modem卡出現之前,已經有了接在計算機串列埠上的外部modem,而且各種拔號程式也是通過串列埠與外部modem通訊的。為了讓已有的拔號程式不做修改,像使用外部modem一樣使用內建卡,就需要內建卡的驅動程式虛擬乙個串列埠裝置。又如當前工業界使用的一些串列埠伺服器,往往有8個或16個甚至更多的串列埠,以連線多個串列埠裝置,再通過乙個網絡卡直接連入乙太網。與它在同一網路上的計算機就通過乙太網與串列埠伺服器上掛接的串列埠裝置通訊。為了讓計算機中原來使用本地串列埠的軟體相容,就需要在計算機上提供虛擬串列埠驅動。

虛擬串列埠的設計關鍵在於,該「串列埠」實現後必須具有與真實串列埠完全相同的系統呼叫介面。要做到這點,從已有的串列埠裝置驅動程式上做修改是最佳捷徑。下文就介紹以windows nt上的串列埠驅動程式為基礎,開發可執行於windows nt、windows 2000、windows xp的各個版本虛擬串列埠驅動程式。

串列埠驅動中使用的幾個鍊錶

由於串列埠是雙工裝置,在乙個讀請求發出來還沒有完成之前,同時可以發出寫請求,加上在驅動程式層所有i/o請求都要求非同步完成,即前乙個請求尚沒有完成,下乙個相同的請求可能又來了。為此,串列埠驅動程式需要使用多個雙向鍊錶資料結構來處理各種irp(i/o request packet,i/o請求包)。當收到乙個irp,先判斷是否可立即完成,可以馬上處理並返回,如果不允許則將irp插在相應鍊錶尾,在適當的時候如裝置有空閒時處理,這時往往會產生乙個硬體中斷,激發dpc(deferred procedure call,暫緩過程呼叫)過程,由dpc處理函式逐個從煉表頭取出irp並試著完成它。串列埠驅動中有以下幾個鍊錶和dpc(在serial.h中有定義):

readqueue 和 completereaddpc

用於儲存read irp的鍊錶和用於排程的dpc,與dpc對應的處理函式是serialcompleteread,它在read.c檔案中,該函式的主要任務就是從readqueue中提取下乙個irp,並試著完成它。

writequeue 和 completewritedpc

用於儲存write irp的鍊錶和對應的dpc,與dpc對應的函式是seriacompletewrite,它的實現在write.c中,該函式負責從writequeue中提取irp,並試著完成它。

maskqueue 和 commwaitdpc

這一對鍊錶用於處理windows串列埠驅動的乙個特性:事件驅動機制。它允許應用程式預設乙個事件標誌,而後等待與標誌對應事件發生。dpc所呼叫的函式是serialcompletewait,它實現在waitmask.c檔案中,該函式也是試著從maskqueue中提取irp並完成它。

purgequeue

該鍊錶與前面幾個稍有不同,它沒有與之相對應的dpc機制,而是在每次收到purge請求時從purgequeue中逐個提取irp並試著完成,因某種原因不能完成時則插入鍊錶。相應的函式是purge.c檔案中的serialstartpurge。

以上機制是串列埠驅動程式的重要實現方法,在虛擬串列埠驅動中需要保留,但不同的是,硬體串列埠驅動中是isr(中斷服務程式)根據收、發或modem中斷來激發相應的dpc,而在虛擬串列埠驅動中將因實際情況不同會有不同的激發機制。

driverentry的實現

driverentry是驅動程式的入口函式,相當於應用程式c語言中的main函式,開發乙個虛擬串列埠驅動首先要修改的就是它。它的函式實體在initunlo.c檔案中。只是在虛擬串列埠驅動中由於不與具體的硬體打交道,就不存在硬體資源分析、硬體初始化、判斷其工作狀態等處理,只需要為虛擬串建立裝置物件、符號鏈結和初始化資料結構。乙個典型函式實現大體如下:

ntstatus driverentry(in pdriver_object driverobject, in punicode_string registrypath)

serialread和serialcompleteread的實現

函式serailread和serialcompleteread決定了對read irp的響應策略,它們都存於read.c中。以串列埠伺服器要用的虛擬串列埠為例,當串列埠伺服器收到來自外部資料時將通過網路發至計算機,計算機則產生相應的網路中斷並進行協議資料處理。網路接收執行緒快取新收到的資料並啟用completereaddpc,從而serialcompletereadirp得到呼叫,它再呼叫completereadirp對每個irp進行處理。它們的實現大體如下:

ntstatus serialread(in pdevice_object deviceobject,in pirp irp)

/*是否已讀到足夠資料?是的話則完成該irp*/

if( 0 == readlen)

/*沒有則將irp插入佇列中,通過網路向串列埠伺服器發出讀資料請求*/

iomarkirppending(irp);

insertwaitlist(extension->readqueue,irp);

status = tdisendasync(extension->comchannel,packpacket,packetlen(packpacket),(pvoid)readackcomplete,irp);

/*返回pending,表示該irp尚沒有完成*/

return status_pending;

} void completereadirp(in pserial_device_extension extension,in pirp irp,in puchar pindata,in ulong length )

else

if(preadasync->totalneedread == preadasync->readalready)

/*本irp沒有完成也沒有超時,則繼續等待本dpc下次被啟用,注意此時要判斷irp是否被要求取消*/

} serialwrite和serailcompletewrite的實現

serialwrite和serailcompletewrite決定了write irp的實現。在serialwrite中呼叫了網路傳送函式tdisendasync,當該傳送完成後將啟用completewritedpc,排程serialcompletewrite函式,而它主要就是取出當前的writeirp,設定已經傳送的資料數量,呼叫completewriteirp做該irp的進一步處理。它們大體如下:

ntstatus serialwrite(in pdevice_object deviceobject,in pirp irp)

//儲存非同步資料

… //設定網路傳送資料報

builddatapacket(ppacket,write,(ushort)sendlen,pwriteasync->pwritebuffer);

/*先將irp暫時阻塞並插入佇列,在completewrite中完成*/

iomarkirppending(irp);

insertwaitlist(extension->writequeue, irp);

/*將寫請求和相關資料通過網路發向串列埠伺服器,由它負責將資料傳到具體串列埠裝置*/

status = tdisendasync(extension->comchannel,ppacket,packetlen(ppacket),(pvoid)completewriteirp,irp);

//統計資料累加

extension->perfstats.transmittedcount += sendlen;

return status_pending;

} ntstatus completewriteirp(in pdevice_object deviceobject,in pirp pirp,in pvoid context)

else //傳送剩餘資料

else }

} 其他幾個介面函式的實現

除read/write外,serialunload、serialcreateopen、 serialclose、serialcleanup、serailflush等呼叫介面是硬體相關性比較弱的介面函式,基本不要修改,直接刪除原來操作硬體的部分即可。複雜一點就是serialiocontrol,該介面函式包含有大量設定、讀取串列埠硬體狀態的處理,可建立乙個本地資料結構隨時儲存虛擬串列埠的當前硬體狀態。同時為了保證串列埠伺服器端的真實串列埠狀態和上層軟體要求的一致,需要將所有設定請求通過網路傳送到伺服器端,由它負責改變真實硬體的狀態。

虛擬鍵盤驅動程式

文章出處 作者 李先靜 前 段時間寫乙個程式,要向系統中注入按鍵事件,我又不想信賴於具體的gui,就寫乙個虛擬鍵盤裝置驅動程式,感覺挺好用的,不過後來發現linux其實有一 個uinput驅動程式實現了類似的功能。幸好後來才發現uinput這玩意兒,否則就沒有機會去寫了這個程式了,有時真是寧願知識面...

Linux串列埠驅動程式 1 tty驅動程式架構

1.tty概念分析 控制台終端 dev console 虛擬終端 dev tty 在linux核心中printk函式處理是交給控制台終端的,控制台終端又把它對映到串列埠終端或者螢幕終端上。而虛擬終端更多是在應用程式中使用。2.tty架構解析 3.回溯串列埠資料傳送 static void s3c24...

介面驅動程式開發

介面驅動程式開發 介紹了在android開發環境下,採用 j a 編寫介面驅動程式。包括 led介面及驅動程式 背光調節控制程式 鍵盤介面及驅動程式 uart 序列口及通訊程式 wi fi 介面及通訊程式 3g介面及驅動程式 mediaplayer led燈由 gpio 介面的gpj3 0 和gpj...