2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
5 * PURPOSE: NDIS Configuration Services
6 * PROGRAMMERS: Vizzini (vizzini@plasmic.com)
8 * Vizzini 08-20-2003 Created
10 * - Currently this only supports enumeration of Root and PCI devices
11 * - This whole thing is really just a band-aid until we have real PnP
12 * - Strictly speaking, I'm not even sure it's my job to call
13 * HalAssignSlotResources(), but the vmware nic driver likes it
14 * - Please send me feedback if there is a better way :)
16 * - Break these functions up a bit; i hate 200-line functions
22 /* Registry path to the enumeration database */
23 #define ENUM_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum"
25 /* Registry path to the services database */
26 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
29 * This has to be big enough to hold enumerated registry paths until
30 * registry accesses are properly re-coded
32 #define KEY_INFORMATION_SIZE 512
34 /* same sort of deal as above */
35 #define VALUE_INFORMATION_SIZE 100
38 * NET class GUID, as defined by Microsoft, used to tell if a
39 * device belongs to NDIS or not.
41 #define NET_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
43 #define RZ() do { DbgPrint("%s:%i Checking RedZone\n", __FILE__, __LINE__ ); ExAllocatePool(PagedPool,0); } while (0);
46 extern LIST_ENTRY OrphanAdapterListHead
;
47 extern KSPIN_LOCK OrphanAdapterListLock
;
50 BOOLEAN
NdisFindDevicePci(UINT VendorID
, UINT DeviceID
, PUINT BusNumber
, PUINT SlotNumber
)
52 * FUNCTION: Find a PCI device given its Vendor and Device IDs
54 * VendorID: The card's PCI Vendor ID
55 * DeviceID: The card's PCI Device ID
56 * BusNumber: The card's bus number on success
57 * SlotNumber: The card's slot number on success
59 * TRUE if the card is fouund
62 * - This only finds the first card of a type
63 * - This doesn't handle function enumeration correctly
64 * - Based loosely on Dekker & Newcomer examples
67 PCI_COMMON_CONFIG PciData
;
70 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
72 /* dekker says there are 256 possible PCI buses */
73 for(i
= 0; i
< 256; i
++)
75 for(j
= 0; j
< PCI_MAX_DEVICES
; j
++)
77 for(k
= 0; k
< PCI_MAX_FUNCTION
; k
++)
79 /* TODO: figure out what to do with k */
81 if(HalGetBusData(PCIConfiguration
, i
, j
, &PciData
, sizeof(PciData
)))
83 if(PciData
.VendorID
== 0xffff) /* Is this handled right? */
86 if(PciData
.VendorID
== VendorID
&& PciData
.DeviceID
== DeviceID
)
100 NDIS_DbgPrint(MAX_TRACE
, ("Didn't find device 0x%x:0x%x\n", VendorID
, DeviceID
));
106 VOID
NdisStartDriver(PUNICODE_STRING uBusName
, PUNICODE_STRING uDeviceId
, PUNICODE_STRING uServiceName
)
108 * FUNCTION: Starts an NDIS driver
110 * uBusName: the card's bus type, by name, as extracted from the
111 * enumeration database in the registry
112 * uDeviceId: the card's device ID
113 * uServiceName: the driver (scm db entry) associated with the card
115 * - This doesn't prooperly handle multiple instances of the same card or driver
116 * - for PCI cards, this finds the card and creates an "orphan" adapter object for
117 * it. This object is tagged with the registry key to the driver and includes
118 * the slot number and bus number of the card. NOTE that some stupid nic drivers
119 * still depend on a registry key for slot number, so this isn't always enough.
120 * Whatever the case, all of the card's resources are enumerated and assigned
121 * via HalAssignSlotResources() and the orphan adapter is put onto the list.
122 * When the miniport calls NdisMRegisterMiniport(), ndis loops through the list
123 * of orphans and associates any orphans that belong to that miniport with
124 * its corresponding LOGICAL_ADAPTER objects.
132 UNICODE_STRING ServiceKey
;
133 PWCHAR ServiceKeyStr
;
135 PORPHAN_ADAPTER OrphanAdapter
;
137 NDIS_DbgPrint(MAX_TRACE
, ("Called; Starting %wZ\n", uServiceName
));
139 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
141 /* prepare a services key */
142 ServiceKeyStr
= ExAllocatePool(PagedPool
, sizeof(SERVICES_KEY
) + sizeof(WCHAR
) + uServiceName
->Length
);
145 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient Resources.\n"));
149 wcscpy(ServiceKeyStr
, SERVICES_KEY
);
150 wcscat(ServiceKeyStr
, L
"\\");
151 wcsncat(ServiceKeyStr
, uServiceName
->Buffer
, uServiceName
->Length
/sizeof(WCHAR
));
152 ServiceKeyStr
[wcslen(SERVICES_KEY
)+1+uServiceName
->Length
/sizeof(WCHAR
)] = 0;
154 RtlInitUnicodeString(&ServiceKey
, ServiceKeyStr
);
156 if(!wcsncmp(uBusName
->Buffer
, L
"PCI", uBusName
->Length
))
159 * first see if a card with the requested id exists.
160 * PCI IDs are formatted VEN_ABCD&DEV_ABCD[&...]
163 if(wcsncmp(uDeviceId
->Buffer
, L
"VEN_", 4))
165 NDIS_DbgPrint(MIN_TRACE
, ("Bogus uDeviceId parsing VEN\n"));
166 ExFreePool(ServiceKeyStr
);
170 Temp
.Buffer
= &(uDeviceId
->Buffer
[4]); /* offset of vendor id */
171 Temp
.Length
= Temp
.MaximumLength
= 4 * sizeof(WCHAR
); /* 4-digit id */
173 NtStatus
= RtlUnicodeStringToInteger(&Temp
, 16, &VendorId
);
174 if(!NT_SUCCESS(NtStatus
))
176 NDIS_DbgPrint(MIN_TRACE
, ("RtlUnicodeStringToInteger returned 0x%x\n", NtStatus
));
177 ExFreePool(ServiceKeyStr
);
181 if(wcsncmp(&(uDeviceId
->Buffer
[9]), L
"DEV_", 4))
183 NDIS_DbgPrint(MIN_TRACE
, ("Bogus uDeviceId parsing DEV\n"));
184 ExFreePool(ServiceKeyStr
);
188 Temp
.Buffer
= &(uDeviceId
->Buffer
[13]); /* offset of device id */
189 Temp
.Length
= 4 * sizeof(WCHAR
); /* 4-dight id */
191 NtStatus
= RtlUnicodeStringToInteger(&Temp
, 16, &DeviceId
);
192 if(!NT_SUCCESS(NtStatus
))
194 NDIS_DbgPrint(MIN_TRACE
, ("RtlUnicodeStringToInteger returned 0x%x\n", NtStatus
));
195 ExFreePool(ServiceKeyStr
);
199 if(!NdisFindDevicePci(VendorId
, DeviceId
, &BusNumber
, &SlotNumber
))
201 NDIS_DbgPrint(MIN_TRACE
, ("Didn't find a configured card 0x%x 0x%x\n", VendorId
, DeviceId
));
202 ExFreePool(ServiceKeyStr
);
206 NDIS_DbgPrint(MAX_TRACE
, ("Found a card 0x%x 0x%x at bus 0x%x slot 0x%x\n", VendorId
, DeviceId
, BusNumber
, SlotNumber
));
208 OrphanAdapter
= ExAllocatePool(PagedPool
, sizeof(ORPHAN_ADAPTER
));
211 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient Resources.\n"));
212 ExFreePool(ServiceKeyStr
);
216 OrphanAdapter
->RegistryPath
.Buffer
= ExAllocatePool(PagedPool
, Temp
.MaximumLength
);
217 if(!OrphanAdapter
->RegistryPath
.Buffer
)
219 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient Resources.\n"));
220 ExFreePool(ServiceKeyStr
);
224 OrphanAdapter
->RegistryPath
.Length
= Temp
.Length
;
225 OrphanAdapter
->RegistryPath
.MaximumLength
= Temp
.MaximumLength
;
226 memcpy(OrphanAdapter
->RegistryPath
.Buffer
, Temp
.Buffer
, Temp
.Length
);
228 OrphanAdapter
->BusType
= PCIBus
;
229 OrphanAdapter
->BusNumber
= BusNumber
;
230 OrphanAdapter
->SlotNumber
= SlotNumber
;
232 ExInterlockedInsertTailList(&OrphanAdapterListHead
, &OrphanAdapter
->ListEntry
, &OrphanAdapterListLock
);
236 * found a card; start its driver. this should be done from a
237 * system thread, after NDIS.SYS's DriverEntry returns, but I
238 * really don't know how to block on DriverEntry returning, so
242 NDIS_DbgPrint(MID_TRACE
, ("Loading driver %wZ\n", &ServiceKey
));
243 ZwLoadDriver(&ServiceKey
);
245 ExFreePool(ServiceKeyStr
);
249 VOID
NdisStartDevices()
251 * FUNCTION: Find and start all NDIS Net class devices
253 * - Not sure if this handles multiple instances of the same
254 * device or driver correctly yet
258 OBJECT_ATTRIBUTES ObjectAttributes
;
259 UNICODE_STRING KeyName
;
263 PKEY_BASIC_INFORMATION KeyInformation
;
264 ULONG KeyInformationLength
;
266 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
268 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
270 RtlInitUnicodeString(&KeyName
, ENUM_KEY
);
271 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, 0, 0);
272 NtStatus
= ZwOpenKey(&EnumHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
273 if(!NT_SUCCESS(NtStatus
))
275 NDIS_DbgPrint(MIN_TRACE
, ("Unable to open the Enum key\n"));
279 NDIS_DbgPrint(MAX_TRACE
, ("Opened the enum key\n"));
281 KeyInformation
= ExAllocatePool(PagedPool
, KEY_INFORMATION_SIZE
); // should be enough for most key names?
284 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
288 KeyInformationLength
= KEY_INFORMATION_SIZE
;
290 while(NT_SUCCESS(ZwEnumerateKey(EnumHandle
, EnumIndex
,
291 KeyBasicInformation
, KeyInformation
, KeyInformationLength
, &ResultLength
)))
293 /* iterate through each enumerator (PCI, Root, ISAPNP, etc) */
295 HANDLE EnumeratorHandle
;
296 WCHAR
*EnumeratorStr
;
297 UINT EnumeratorIndex
= 0;
299 NDIS_DbgPrint(MAX_TRACE
, ("Enum iteration 0x%x\n", EnumIndex
));
303 EnumeratorStr
= ExAllocatePool(PagedPool
, sizeof(WCHAR
) + KeyInformation
->NameLength
);
306 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
310 wcsncpy(EnumeratorStr
, KeyInformation
->Name
, KeyInformation
->NameLength
/sizeof(WCHAR
));
311 EnumeratorStr
[KeyInformation
->NameLength
/sizeof(WCHAR
)] = 0;
313 RtlInitUnicodeString(&KeyName
, EnumeratorStr
);
314 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, EnumHandle
, 0);
315 if(!NT_SUCCESS(ZwOpenKey(&EnumeratorHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
)))
317 NDIS_DbgPrint(MIN_TRACE
, ("Failed to open key %wZ\n", &KeyName
));
321 while(NT_SUCCESS(ZwEnumerateKey(EnumeratorHandle
, EnumeratorIndex
, KeyBasicInformation
,
322 KeyInformation
, KeyInformationLength
, &ResultLength
)))
324 /* iterate through each device id */
328 UINT DeviceIndex
= 0;
329 UNICODE_STRING BusName
;
331 BusName
.Buffer
= KeyName
.Buffer
;
332 BusName
.Length
= KeyName
.Length
;
333 BusName
.MaximumLength
= KeyName
.MaximumLength
;
337 DeviceStr
= ExAllocatePool(PagedPool
, KeyInformation
->NameLength
+ sizeof(WCHAR
));
340 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
344 wcsncpy(DeviceStr
, KeyInformation
->Name
, KeyInformation
->NameLength
/sizeof(WCHAR
));
345 DeviceStr
[KeyInformation
->NameLength
/sizeof(WCHAR
)] = 0;
347 RtlInitUnicodeString(&KeyName
, DeviceStr
);
348 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, EnumeratorHandle
, 0);
349 if(!NT_SUCCESS(ZwOpenKey(&DeviceHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
)))
351 NDIS_DbgPrint(MIN_TRACE
, ("Failed to open key %wZ\n", &KeyName
));
355 while(NT_SUCCESS(ZwEnumerateKey(DeviceHandle
, DeviceIndex
, KeyBasicInformation
,
356 KeyInformation
, KeyInformationLength
, &ResultLength
)))
358 /* iterate through each instance id, starting drivers in the process */
359 HANDLE InstanceHandle
;
361 UNICODE_STRING ValueName
;
362 UNICODE_STRING ServiceName
;
363 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
364 ULONG KeyValueInformationLength
;
365 UNICODE_STRING DeviceId
;
367 DeviceId
.Buffer
= KeyName
.Buffer
;
368 DeviceId
.Length
= KeyName
.Length
;
369 DeviceId
.MaximumLength
= KeyName
.MaximumLength
;
373 InstanceStr
= ExAllocatePool(PagedPool
, KeyInformation
->NameLength
+ sizeof(WCHAR
));
376 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
380 wcsncpy(InstanceStr
, KeyInformation
->Name
, KeyInformation
->NameLength
/sizeof(WCHAR
));
381 InstanceStr
[KeyInformation
->NameLength
/sizeof(WCHAR
)] = 0;
383 NDIS_DbgPrint(MAX_TRACE
, ("NameLength = 0x%x and InstanceStr: %ws\n", KeyInformation
->NameLength
, InstanceStr
));
385 RtlInitUnicodeString(&KeyName
, InstanceStr
);
386 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, DeviceHandle
, 0);
387 if(!NT_SUCCESS(ZwOpenKey(&InstanceHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
)))
389 NDIS_DbgPrint(MIN_TRACE
, ("Failed to open key %wZ\n", &KeyName
));
393 /* read class, looking for net guid */
394 RtlInitUnicodeString(&ValueName
, L
"ClassGUID");
396 NDIS_DbgPrint(MAX_TRACE
, ("About to ask for 0x%x bytes\n", VALUE_INFORMATION_SIZE
));
398 KeyValueInformation
= ExAllocatePool(PagedPool
, VALUE_INFORMATION_SIZE
);
399 if(!KeyValueInformation
)
401 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
405 KeyValueInformationLength
= VALUE_INFORMATION_SIZE
;
407 NtStatus
= ZwQueryValueKey(InstanceHandle
, &ValueName
, KeyValuePartialInformation
,
408 KeyValueInformation
, KeyValueInformationLength
, &ResultLength
);
409 if(!NT_SUCCESS(NtStatus
))
411 /* this isn't fatal, it just means that this device isn't ours */
412 NDIS_DbgPrint(MID_TRACE
, ("Failed to query value %wZ from key %wZ\n", &ValueName
, &KeyName
));
416 if(!wcsncmp(NET_GUID
, (PWCHAR
)KeyValueInformation
->Data
, KeyValueInformation
->DataLength
/sizeof(WCHAR
)))
418 RtlInitUnicodeString(&ValueName
, L
"Service");
420 NtStatus
= ZwQueryValueKey(InstanceHandle
, &ValueName
, KeyValuePartialInformation
,
421 KeyValueInformation
, KeyValueInformationLength
, &ResultLength
);
422 if(!NT_SUCCESS(NtStatus
))
425 NDIS_DbgPrint(MID_TRACE
, ("Failed to query value %wZ from key %wZ\n", &ValueName
, &KeyName
));
429 /* this is a net driver; start it */
430 ServiceName
.Length
= ServiceName
.MaximumLength
= KeyValueInformation
->DataLength
;
431 ServiceName
.Buffer
= (PWCHAR
)KeyValueInformation
->Data
;
432 NdisStartDriver(&BusName
, &DeviceId
, &ServiceName
);
435 NDIS_DbgPrint(MAX_TRACE
, ("...this device is not ours\n"));
437 ExFreePool(KeyValueInformation
);
438 ExFreePool(InstanceStr
);
439 ZwClose(InstanceHandle
);
442 ExFreePool(DeviceStr
);
443 ZwClose(DeviceHandle
);
446 ExFreePool(EnumeratorStr
);
447 ZwClose(EnumeratorHandle
);
451 ExFreePool(KeyInformation
);