3 Copyright (c) 1992-2000 Microsoft Corporation
\r
11 Ndis Intermediate Miniport driver sample. This is a passthru driver.
\r
24 #include "precomp.h"
\r
27 #pragma NDIS_INIT_FUNCTION(DriverEntry)
\r
29 NDIS_HANDLE ProtHandle = NULL;
\r
30 NDIS_HANDLE DriverHandle = NULL;
\r
31 NDIS_MEDIUM MediumArray[4] =
\r
33 NdisMedium802_3, // Ethernet
\r
34 NdisMedium802_5, // Token-ring
\r
35 NdisMediumFddi, // Fddi
\r
36 NdisMediumWan // NDISWAN
\r
39 NDIS_SPIN_LOCK GlobalLock;
\r
41 PADAPT pAdaptList = NULL;
\r
42 LONG MiniportCount = 0;
\r
44 NDIS_HANDLE NdisWrapperHandle;
\r
47 // To support ioctls from user-mode:
\r
50 #define LINKNAME_STRING L"\\DosDevices\\Passthru"
\r
51 #define NTDEVICE_STRING L"\\Device\\Passthru"
\r
53 NDIS_HANDLE NdisDeviceHandle = NULL;
\r
54 PDEVICE_OBJECT ControlDeviceObject = NULL;
\r
58 PS_DEVICE_STATE_READY = 0, // ready for create/delete
\r
59 PS_DEVICE_STATE_CREATING, // create operation in progress
\r
60 PS_DEVICE_STATE_DELETING // delete operation in progress
\r
61 } ControlDeviceState = PS_DEVICE_STATE_READY;
\r
67 IN PDRIVER_OBJECT DriverObject,
\r
68 IN PUNICODE_STRING RegistryPath
\r
72 Routine Description:
\r
74 First entry point to be called, when this driver is loaded.
\r
75 Register with NDIS as an intermediate driver.
\r
79 DriverObject - pointer to the system's driver object structure
\r
82 RegistryPath - system's registry path for this driver
\r
86 STATUS_SUCCESS if all initialization is successful, STATUS_XXX
\r
92 NDIS_PROTOCOL_CHARACTERISTICS PChars;
\r
93 NDIS_MINIPORT_CHARACTERISTICS MChars;
\r
96 Status = NDIS_STATUS_SUCCESS;
\r
97 NdisAllocateSpinLock(&GlobalLock);
\r
99 NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);
\r
104 // Register the miniport with NDIS. Note that it is the miniport
\r
105 // which was started as a driver and not the protocol. Also the miniport
\r
106 // must be registered prior to the protocol since the protocol's BindAdapter
\r
107 // handler can be initiated anytime and when it is, it must be ready to
\r
108 // start driver instances.
\r
111 NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));
\r
113 MChars.MajorNdisVersion = PASSTHRU_MAJOR_NDIS_VERSION;
\r
114 MChars.MinorNdisVersion = PASSTHRU_MINOR_NDIS_VERSION;
\r
116 MChars.InitializeHandler = MPInitialize;
\r
117 MChars.QueryInformationHandler = MPQueryInformation;
\r
118 MChars.SetInformationHandler = MPSetInformation;
\r
119 MChars.ResetHandler = NULL;
\r
120 MChars.TransferDataHandler = MPTransferData;
\r
121 MChars.HaltHandler = MPHalt;
\r
122 #ifdef NDIS51_MINIPORT
\r
123 MChars.CancelSendPacketsHandler = MPCancelSendPackets;
\r
124 MChars.PnPEventNotifyHandler = MPDevicePnPEvent;
\r
125 MChars.AdapterShutdownHandler = MPAdapterShutdown;
\r
126 #endif // NDIS51_MINIPORT
\r
129 // We will disable the check for hang timeout so we do not
\r
130 // need a check for hang handler!
\r
132 MChars.CheckForHangHandler = NULL;
\r
133 MChars.ReturnPacketHandler = MPReturnPacket;
\r
136 // Either the Send or the SendPackets handler should be specified.
\r
137 // If SendPackets handler is specified, SendHandler is ignored
\r
139 MChars.SendHandler = NULL; // MPSend;
\r
140 MChars.SendPacketsHandler = MPSendPackets;
\r
142 Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,
\r
146 if (Status != NDIS_STATUS_SUCCESS)
\r
152 NdisMRegisterUnloadHandler(NdisWrapperHandle, PtUnload);
\r
156 // Now register the protocol.
\r
158 NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
\r
159 PChars.MajorNdisVersion = PASSTHRU_PROT_MAJOR_NDIS_VERSION;
\r
160 PChars.MinorNdisVersion = PASSTHRU_PROT_MINOR_NDIS_VERSION;
\r
163 // Make sure the protocol-name matches the service-name
\r
164 // (from the INF) under which this protocol is installed.
\r
165 // This is needed to ensure that NDIS can correctly determine
\r
166 // the binding and call us to bind to miniports below.
\r
168 NdisInitUnicodeString(&Name, L"Passthru"); // Protocol name
\r
169 PChars.Name = Name;
\r
170 PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;
\r
171 PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;
\r
172 PChars.SendCompleteHandler = PtSendComplete;
\r
173 PChars.TransferDataCompleteHandler = PtTransferDataComplete;
\r
175 PChars.ResetCompleteHandler = PtResetComplete;
\r
176 PChars.RequestCompleteHandler = PtRequestComplete;
\r
177 PChars.ReceiveHandler = PtReceive;
\r
178 PChars.ReceiveCompleteHandler = PtReceiveComplete;
\r
179 PChars.StatusHandler = PtStatus;
\r
180 PChars.StatusCompleteHandler = PtStatusComplete;
\r
181 PChars.BindAdapterHandler = PtBindAdapter;
\r
182 PChars.UnbindAdapterHandler = PtUnbindAdapter;
\r
183 PChars.UnloadHandler = PtUnloadProtocol;
\r
185 PChars.ReceivePacketHandler = PtReceivePacket;
\r
186 PChars.PnPEventHandler= PtPNPHandler;
\r
188 NdisRegisterProtocol(&Status,
\r
191 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
\r
193 if (Status != NDIS_STATUS_SUCCESS)
\r
195 NdisIMDeregisterLayeredMiniport(DriverHandle);
\r
199 NdisIMAssociateMiniport(DriverHandle, ProtHandle);
\r
203 if (Status != NDIS_STATUS_SUCCESS)
\r
205 NdisTerminateWrapper(NdisWrapperHandle, NULL);
\r
218 Routine Description:
\r
220 Register an ioctl interface - a device object to be used for this
\r
221 purpose is created by NDIS when we call NdisMRegisterDevice.
\r
223 This routine is called whenever a new miniport instance is
\r
224 initialized. However, we only create one global device object,
\r
225 when the first miniport instance is initialized. This routine
\r
226 handles potential race conditions with PtDeregisterDevice via
\r
227 the ControlDeviceState and MiniportCount variables.
\r
229 NOTE: do not call this from DriverEntry; it will prevent the driver
\r
230 from being unloaded (e.g. on uninstall).
\r
238 NDIS_STATUS_SUCCESS if we successfully register a device object.
\r
242 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
\r
243 UNICODE_STRING DeviceName;
\r
244 UNICODE_STRING DeviceLinkUnicodeString;
\r
245 PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
\r
247 DBGPRINT(("==>PtRegisterDevice\n"));
\r
249 NdisAcquireSpinLock(&GlobalLock);
\r
253 if (1 == MiniportCount)
\r
255 ASSERT(ControlDeviceState != PS_DEVICE_STATE_CREATING);
\r
258 // Another thread could be running PtDeregisterDevice on
\r
259 // behalf of another miniport instance. If so, wait for
\r
262 while (ControlDeviceState != PS_DEVICE_STATE_READY)
\r
264 NdisReleaseSpinLock(&GlobalLock);
\r
266 NdisAcquireSpinLock(&GlobalLock);
\r
269 ControlDeviceState = PS_DEVICE_STATE_CREATING;
\r
271 NdisReleaseSpinLock(&GlobalLock);
\r
274 NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
\r
276 DispatchTable[IRP_MJ_CREATE] = PtDispatch;
\r
277 DispatchTable[IRP_MJ_CLEANUP] = PtDispatch;
\r
278 DispatchTable[IRP_MJ_CLOSE] = PtDispatch;
\r
279 DispatchTable[IRP_MJ_DEVICE_CONTROL] = PtDispatch;
\r
282 NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);
\r
283 NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING);
\r
286 // Create a device object and register our dispatch handlers
\r
289 Status = NdisMRegisterDevice(
\r
290 NdisWrapperHandle,
\r
292 &DeviceLinkUnicodeString,
\r
294 &ControlDeviceObject,
\r
298 NdisAcquireSpinLock(&GlobalLock);
\r
300 ControlDeviceState = PS_DEVICE_STATE_READY;
\r
303 NdisReleaseSpinLock(&GlobalLock);
\r
305 DBGPRINT(("<==PtRegisterDevice: %x\n", Status));
\r
313 IN PDEVICE_OBJECT DeviceObject,
\r
317 Routine Description:
\r
319 Process IRPs sent to this device.
\r
323 DeviceObject - pointer to a device object
\r
324 Irp - pointer to an I/O Request Packet
\r
328 NTSTATUS - STATUS_SUCCESS always - change this when adding
\r
329 real code to handle ioctls.
\r
333 PIO_STACK_LOCATION irpStack;
\r
334 NTSTATUS status = STATUS_SUCCESS;
\r
336 UNREFERENCED_PARAMETER(DeviceObject);
\r
338 DBGPRINT(("==>Pt Dispatch\n"));
\r
339 irpStack = IoGetCurrentIrpStackLocation(Irp);
\r
342 switch (irpStack->MajorFunction)
\r
344 case IRP_MJ_CREATE:
\r
347 case IRP_MJ_CLEANUP:
\r
353 case IRP_MJ_DEVICE_CONTROL:
\r
355 // Add code here to handle ioctl commands sent to passthru.
\r
362 Irp->IoStatus.Status = status;
\r
363 IoCompleteRequest(Irp, IO_NO_INCREMENT);
\r
365 DBGPRINT(("<== Pt Dispatch\n"));
\r
373 PtDeregisterDevice(
\r
378 Routine Description:
\r
380 Deregister the ioctl interface. This is called whenever a miniport
\r
381 instance is halted. When the last miniport instance is halted, we
\r
382 request NDIS to delete the device object
\r
386 NdisDeviceHandle - Handle returned by NdisMRegisterDevice
\r
390 NDIS_STATUS_SUCCESS if everything worked ok
\r
394 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
\r
396 DBGPRINT(("==>PassthruDeregisterDevice\n"));
\r
398 NdisAcquireSpinLock(&GlobalLock);
\r
400 ASSERT(MiniportCount > 0);
\r
404 if (0 == MiniportCount)
\r
407 // All miniport instances have been halted. Deregister
\r
408 // the control device.
\r
411 ASSERT(ControlDeviceState == PS_DEVICE_STATE_READY);
\r
414 // Block PtRegisterDevice() while we release the control
\r
415 // device lock and deregister the device.
\r
417 ControlDeviceState = PS_DEVICE_STATE_DELETING;
\r
419 NdisReleaseSpinLock(&GlobalLock);
\r
421 if (NdisDeviceHandle != NULL)
\r
423 Status = NdisMDeregisterDevice(NdisDeviceHandle);
\r
424 NdisDeviceHandle = NULL;
\r
427 NdisAcquireSpinLock(&GlobalLock);
\r
428 ControlDeviceState = PS_DEVICE_STATE_READY;
\r
431 NdisReleaseSpinLock(&GlobalLock);
\r
433 DBGPRINT(("<== PassthruDeregisterDevice: %x\n", Status));
\r
440 IN PDRIVER_OBJECT DriverObject
\r
443 // PassThru driver unload function
\r
446 UNREFERENCED_PARAMETER(DriverObject);
\r
448 DBGPRINT(("PtUnload: entered\n"));
\r
450 PtUnloadProtocol();
\r
452 NdisIMDeregisterLayeredMiniport(DriverHandle);
\r
454 NdisFreeSpinLock(&GlobalLock);
\r
456 DBGPRINT(("PtUnload: done!\n"));
\r