Udostępnij za pośrednictwem


Przetwarzanie IRP w sterowniku Lowest-Level

Kierowcy fizyczni najniższego poziomu mają pewne standardowe procedury, których kierowcy wyższego poziomu nie potrzebują. Zestaw standardowych procedur dla kierowców najniższego poziomu również różni się w zależności od następujących kryteriów:

  • Charakter urządzenia, który kontroluje każdy sterownik

  • Określa, czy sterownik konfiguruje swoje obiekty urządzenia dla operacji we/wy w trybie bezpośrednim lub buforowanym

  • Konstrukcja poszczególnych sterowników

Aby zilustrować role standardowych procedur sterowników, na poniższej ilustracji przedstawiono ścieżkę, którą może przyjąć przykładowy protokół IRP, ponieważ jest przetwarzany przez sterownik urządzenia magazynu masowego najniższego poziomu. Sterownik na rysunku ma następujące cechy:

  • Urządzenie generuje przerwania na końcu każdej operacji I/O, więc ten sterownik ma procedury ISR i DpcForIsr.

  • Sterownik ma procedurę StartIo, zamiast konfigurować kolejki wewnętrzne dla IRP i zarządzać własnym kolejkowaniem.

  • Sterownik używa systemowego DMA, dlatego ustawia flagi obiektów urządzenia dla operacji we/wy bezpośrednich i ma procedurę AdapterControl.

diagram ilustrujący ścieżkę irp przez procedury najniższego poziomu sterownika.

Jak widzimy na tej ilustracji, menedżer we/wy tworzy IRP i wysyła go do procedury obsługi sterownika dla konkretnego kodu funkcji głównej. Przy założeniu, że kod funkcji jest IRP_MJ_READ lub IRP_MJ_WRITE, procedury wysyłania DDDispatchReadWrite.

Wywoływanie metody IoGetCurrentIrpStackLocation

Każda procedura sterownika, która wymaga parametrów IRP, musi wywołać IoGetCurrentIrpStackLocation w celu uzyskania lokalizacji stosu I/O sterownika. Takie rutyny obejmują rutyny wysyłania, które obsługują więcej niż jeden główny kod funkcji We/Wy (IRP_MJ_*XXX), obsługują funkcję, która obsługuje funkcje drugorzędne (IRP_MN_XXX) lub obsługują żądania kontroli We/Wy urządzenia (*IRP_MJ_DEVICE_CONTROL i/lub IRP_MJ_INTERNAL_DEVICE_CONTROL), wraz ze wszystkimi innymi rutynami sterowników, które przetwarzają IRP.

Lokalizacja stosu we/wy tego sterownika jest najniższa, z nieokreśloną liczbą lokalizacji stosu we/wy sterowników wyższego poziomu pokazanych jako zacienione. Dla uproszczenia wywołania IoGetCurrentIrpStackLocation z DispatchReadWrite, StartIo, AdapterControli DpcForIsr nie są pokazane na poprzedniej ilustracji.

Wywoływanie IoMarkIrpPending i IoStartPacket

Przykładowy sterownik nie ukończy protokołu IRP w swojej procedurze wysyłania, ale zamiast tego przetwarza protokół IRP w procedurze StartIo. Zanim to nastąpi, procedura wysyłania wywołuje IoMarkIrpPending, aby wskazać, że żądanie IRP nie zostało jeszcze ukończone. Następnie wywołuje IoStartPacket w celu kolejkowania protokołu IRP w celu dalszego przetwarzania przez procedurę Start Io sterownika. Procedura wysyłania zwraca również wartość NTSTATUS STATUS_PENDING.

Na poniższej ilustracji przedstawiono wywołanie IoStartPacket.

diagram ilustrujący wywołanie pakietu iostartpacket.

Jeśli sterownik jest zajęty przetwarzaniem innego protokołu IRP na urządzeniu, IoStartPacket wstawia protokół IRP do kolejki urządzenia skojarzonej z obiektem urządzenia. Sterownik może opcjonalnie dostarczyć wartość klucza jako parametr do IoStartPacket, aby narzucić kolejność określoną przez sterownik dla IRP w kolejce urządzenia.

Jeśli sterownik nie jest zajęty, a kolejka urządzenia jest pusta, menedżer we/wy natychmiast wywołuje procedurę StartIo, przekazując wejściowy protokół IRP.

W przypadku urządzeń pamięci masowej sterownik najniższego poziomu nie musi dostarczać procedury Anuluj, gdy wywołuje IoStartPacket z dwóch powodów:

  1. System plików warstwowy nad takim sterownikiem zwykle obsługuje anulowanie żądań we/wy plików.

  2. Sterowniki urządzeń pamięci masowej szybko przetwarzają IRP.

Zazwyczaj sterownik najwyższego poziomu w łańcuchu sterowników warstwowych obsługuje anulowanie IRP.

Wywoływanie metody AllocateAdapterChannel i MapTransfer

Przy założeniu, że procedura StartIo, pokazana na rysunku ilustrującym ścieżkę IRP przez procedury sterownika najniższego poziomu, określa, że żądanie przeniesienia może być wykonane przez pojedynczą operację DMA, procedura StartIo wywołuje AllocateAdapterChannel z punktem wejścia procedury AdapterControl oraz IRP.

Gdy systemowy kontroler DMA jest dostępny, menedżer we/wy wywołuje procedurę sterownika AdapterControl, aby skonfigurować operację transferu. Procedura AdapterControl wywołuje MapTransfer w celu skonfigurowania systemowego kontrolera DMA. Następnie sterownik programuje swoje urządzenie dla operacji DMA i zwraca. (Aby uzyskać więcej informacji o korzystaniu z obiektów DMA i adaptera, zobacz Input/Output Techniques.)

Wywoływanie IoRequestDpc z ISR sterownika

Gdy urządzenie przerywa, aby wskazać, że operacja transferu jest zakończona, ISR sterownika zatrzymuje urządzenie przed generowaniem przerwań i wywołuje IoRequestDpc, jak pokazano na rysunku ilustrującym ścieżkę IRP przez rutyny sterownika najniższego poziomu.

To wywołanie ustawia w kolejce rutynę sterownika DpcForIsr, aby ukończyć jak najwięcej operacji transferu w możliwie najniższym priorytecie sprzętu (IRQL).

Wywoływanie IoStartNextPacket i IoCompleteRequest

Gdy procedura DpcForIsr zakończy przetwarzanie transferu, wywołuje IoStartNextPacket natychmiast, tak aby procedura sterownika StartIo mogła być wywołana z następnym IRP w kolejce urządzenia, jeśli jakieś są w kolejce. DpcForIsr procedura ustawia również właśnie ukończony blok stanu we/wy IRP, a następnie wywołuje IoCompleteRequest dla IRP.

Na poniższej ilustracji przedstawiono wywołania tego sterownika do IoStartNextPacket i IoCompleteRequest.

wywoływanie iostartnextpacket oraz iocompleterequest.

Sterowniki powinny wywoływać IoStartNextPacket lub IoStartNextPacketByKey, aby rozpocząć następną żądaną operację we/wy tak szybko, jak to możliwe, najlepiej przed wywołaniem IoCompleteRequest.

Jeśli jakiekolwiek IRP są kolejkowane dla urządzenia, IoStartNextPacket wywołuje KeRemoveDeviceQueue, aby usunąć następne IRP z kolejki. Menedżer we/wy następnie wywołuje rutynę StartIo sterownika, przekazując zdejmowany z kolejki IRP. Jeśli żadne IRP nie znajdują się obecnie w kolejce urządzenia, IoStartNextPacket po prostu zwraca sterowanie do wywołującego.

ustawienie bloku stanu we/wy w IRP

Każdy sterownik najniższego poziomu musi ustawić blok stanu I/O protokołu IRP przed wywołaniem IoCompleteRequest. (Na poprzedniej ilustracji drugi zacieniony obszar oznacza blok stanu). Blok stanu I/O dostarcza informacje wyższej warstwie sterowników, a ostatecznie do pierwotnego podmiotu żądającego operacji I/O. Każdy sterownik wyższego poziomu umieszczony powyżej sterownika na poprzedniej ilustracji mógł skonfigurować rutynę IoCompletion , która odczytuje blok stanu we/wy ustawiony przez ten sterownik. Sterowniki wyższego poziomu zwykle nie modyfikują bloku stanu we/wy w IRP, który został zakończony przez sterownik urządzenia, chyba że sterownik wyższego poziomu ponownie podejmuje próbę wykonania IRP, w takim przypadku ponownie inicjuje blok stanu we/wy.

Każdy sterownik wyższego poziomu, który kończy obsługę IRP bez przekazywania go do następnego niższego sterownika, musi również ustawić blok stanu I/O w tym IRP przed wywołaniem IoCompleteRequest. Aby uzyskać dobrą ogólną przepustowość I/O, sterownik wyższego poziomu powinien sprawdzić parametry we własnej lokalizacji stosu I/O dla każdego IRP i, jeśli parametry są nieprawidłowe, powinien ustawić blok stanu I/O i samodzielnie zakończyć żądanie. Jeśli to możliwe, sterownik powinien unikać przekazywania nieprawidłowego żądania do niższych sterowników w łańcuchu.

Przy założeniu, że operacja transferu na poprzedniej ilustracji zakończyła się pomyślnie, procedura DpcForIsr, przedstawiona na rysunku ilustrującym ścieżkę IRP przez procedury sterowników najniższego poziomu, ustawia STATUS_SUCCESS w Status i liczbę bajtów przesłanych w Informacji dla bloku stanu wejścia/wyjścia dla protokołu IRP.

Wiele standardowych procedur sterowników zwraca również wartości typu NTSTATUS. Aby uzyskać więcej informacji na temat stałych NTSTATUS, takich jak STATUS_SUCCESS, zobacz błędy rejestrowania.