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);