typedef struct _beep_device_extension
device_extension, *pdevice_extension;
上面是蜂鳴器裝置的擴充套件結構體,其中referencecount
是裝置的引用計數,而fast_mutex
用於互斥訪問這個計數器,timer
用於蜂鳴器定時,而timeractive
則計數多少個定時器被啟用。sectionhandle
則儲存整個系統的記憶體控制代碼。
根據慣例,驅動程式的入口處有乙個建立裝置的過程,不過在一般的建立之後需要額外加上乙個對裝置擴充套件體的初始化:
deviceextension->referencecount = 0;
deviceextension->timeractive = false;
ioinitializedpcrequest(deviceobject, (pio_dpc_routine)beepdpc);
keinitializetimer(&deviceextension->timer);
exinitializefastmutex(&deviceextension->mutex);
mmpageentiredriver(driverentry);
最後乙個函式將整個記憶體給換頁出去,因為建立裝置之後整個裝置並不一定是需要的。所以可以暫時將這段**給換頁出去,當然這裡的driverentry
當然,既然在初始化整個裝置和驅動程式的時候講記憶體給換頁出去了,那麼就需要在某乙個階段將整個驅動鎖定到記憶體當中——也就是講記憶體給設定為非換頁記憶體。而乙個裝置的訪問起點往往是create***
呼叫,當控制權轉移到驅動程式的時候,相對應的是irp_mj_create
控制處理函式。建立過程很簡單,直接通過快速互斥體將整個裝置的計數給保護起來,然後將驅動**給鎖定到非換頁記憶體當中,最後返回成功。
exacquirefastmutex(&deviceextension->mutex);
if (++deviceextension->referencecount == 1)
exreleasefastmutex(&deviceextension->mutex);
irp->iostatus.status = status_success;
irp->iostatus.information = 0;
iocompleterequest(irp, io_no_increment);
return status_success;
因為蜂鳴器是乙個比較簡單的裝置,所以沒有過多的讀寫操作。所有的控制都傳送給irp_mj_device_control
控制碼處理函式。這裡的處理僅僅是做一些引數檢驗,如果蜂鳴器的頻率和持續時間均為0
,那麼返回status_pending,
並且將這個irp
放入到佇列當中處理。否則。直接呼叫iocompleterequest
例程完成io請求。
irp->iostatus.status = status;
irp->iostatus.information = 0;
if (status == status_pending)
else
當控制權從iostartpacket
轉入到驅動程式的satrtio
函式的時候,表明整個系統已經開始處理相應的irp
請求了,所以第一步就是防止相應的irp
請求被取消。如果定時器還沒有激發,就將定時器給取消。否則直接發出乙個蜂鳴器響應,然後根據延遲時間設定定時器在定時器超時的時候進行蜂鳴器響應。當然,系統超時使用了dpc
例程,當所有的處理都結束的時候,系統處理排隊當中的下乙個io
請求。並且返回成功。
ioacquirecancelspinlock(&cancelirql);
if (!irp)
(void)iosetcancelroutine(irp, null);
ioreleasecancelspinlock(cancelirql);
beepparam = (pbeep_set_parameters)irp->associatedirp.systembuffer;
iostack = iogetcurrentirpstacklocation(irp);
if (iostack->parameters.deviceiocontrol.iocontrolcode == ioctl_beep_set)
}if (halmakebeep(beepparam->frequency))
}
由於上面試分析io
請求沒有被取消的過程,如果io
請求被取消的時候,系統會轉向呼叫在iostartpacket
函式當中設定的取消例程,也就是
beepcancel
例程,這個歷程的執行分為兩步,第一步檢驗,正在被處理的是否就是將要被取消的irp
,如果是則直接呼叫處理下乙個irp
。否則將需要取消的irqp
從佇列當中移除。
if (irp == deviceobject->currentirp)
else
而作為定時器的dpc
處理過程也很簡單,僅僅發出蜂鳴,然後將定時器技術遞減1
。
pdevice_extension deviceextension = (pdevice_extension)deviceobject->deviceextension;
halmakebeep(0);
interlockeddecrement(&deviceextension->timeractive);
蜂鳴器的關閉操作和建立是乙個相對的反過程,還有乙個是蜂鳴器的解除安裝。蜂鳴器的解除安裝主要是看定時器操作有沒有結束,如果沒有結束,則強制將定時器給取消,然後呼叫iodeletedevice刪除裝置物件。較為複雜的是乙個蜂鳴器的清理例程,蜂鳴器通過裝置的當前
irp迴圈整個
irp佇列,將所有的
irp都處理掉,當然返回值肯定不能是
status_success
,而應該是
status_cancelled
,因為並沒有實質性的蜂鳴處理。
keraiseirql(dispatch_level, &oldirql);
ioacquirecancelspinlock(&cancelirql);
currentirp = deviceobject->currentirp;
deviceobject->currentirp = null;
while (currentirp)
else
}ioreleasecancelspinlock(cancelirql);
kelowerirql(oldirql);
完整的**參見資源頁面 USB驅動程式分析
1.對於每個pc來說,都有乙個或者多個稱為主機 host 控制器的裝置,該主機控制器和乙個根集線器 hub 作為乙個整體。2.每個host控制器其實就是乙個pci裝置,掛載在pci匯流排上。驅動開發人員應該給host控制器提供驅動程式,用usb hcd結構體表示。3.usb host控制器都會自帶乙...
Linux網絡卡驅動程式分析
學習應該是乙個先把問題簡單化,再把問題複雜化的過程。一開始就著手處理複雜的問題,難免讓人有心驚膽顫,捉襟見肘的感覺。讀linux網絡卡驅動 也是一樣。那長長的原始碼夾雜著那些我們陌生的變數和符號,望而生畏便是理所當然的了。不要擔心,事情總有解決的辦法,先把一些我們管不著的 切割出去,留下必須的部分,...
IIC驅動程式分析(一)
根據上一節課的分析,我們來解讀這段 include include include include include include include static unsigned short ignore static unsigned short normal addr 位址值是7位 static...