+VOID
+NdisIStartAdapter(
+ WCHAR *DeviceNameStr,
+ UINT DeviceNameStrLength,
+ PMINIPORT_DRIVER Miniport
+)
+/*
+ * FUNCTION: Start an adapter
+ * ARGUMENTS:
+ * DeviceNameStr: 0-terminated wide char string of name of device to start
+ * DeviceNameStrLength: length of DeviceNameStr *IN WCHARs*
+ * NOTES:
+ * TODO:
+ * - verify that all resources are properly freed on success & failure
+ */
+{
+ WCHAR *DeviceName;
+ HANDLE RegKeyHandle;
+ WCHAR *RegKeyPath;
+ UNICODE_STRING RegKeyPathU;
+ OBJECT_ATTRIBUTES RegKeyAttributes;
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+ NTSTATUS Status;
+ UINT SelectedMediumIndex = 0;
+ PLOGICAL_ADAPTER Adapter = 0;
+ NDIS_OID AddressOID;
+ BOOLEAN MemError = FALSE;
+ KIRQL OldIrql;
+ PORPHAN_ADAPTER OrphanAdapter = 0;
+
+ NDIS_DbgPrint(MAX_TRACE, ("Called with %ws\n", DeviceNameStr));
+ Adapter = ExAllocatePool(NonPagedPool, sizeof(LOGICAL_ADAPTER));
+ if (!Adapter)
+ {
+ NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return;
+ }
+
+ /* This is very important */
+ RtlZeroMemory(Adapter, sizeof(LOGICAL_ADAPTER));
+
+ DeviceName = ExAllocatePool(NonPagedPool, sizeof(DEVICE_ROOT) + DeviceNameStrLength * sizeof(WCHAR));
+ if(!DeviceName)
+ {
+ NDIS_DbgPrint(MIN_TRACE,("Insufficient memory\n"));
+ ExFreePool(Adapter);
+ return;
+ }
+
+ /* DEVICE_ROOT is a constant string defined above, incl. 0-term */
+ wcscpy(DeviceName, DEVICE_ROOT);
+
+ /* reg_sz is 0-term by def */
+ wcsncat(DeviceName, DeviceNameStr, DeviceNameStrLength);
+ RtlInitUnicodeString(&Adapter->DeviceName, DeviceName);
+
+ NDIS_DbgPrint(MAX_TRACE, ("creating device %ws\n", DeviceName));
+
+ Status = IoCreateDevice(Miniport->DriverObject, 0, &Adapter->DeviceName, FILE_DEVICE_PHYSICAL_NETCARD,
+ 0, FALSE, &Adapter->NdisMiniportBlock.DeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
+ ExFreePool(Adapter);
+ return;
+ }
+
+ /* find out if there are any adapters in the orphans list and reserve resources */
+ KeAcquireSpinLock(&OrphanAdapterListLock, &OldIrql);
+ OrphanAdapter = (PORPHAN_ADAPTER)OrphanAdapterListHead.Flink;
+ while(&OrphanAdapter->ListEntry != &OrphanAdapterListHead)
+ {
+ PORPHAN_ADAPTER TempAdapter;
+ PCM_RESOURCE_LIST ResourceList;
+ UINT i;
+
+ if(!RtlCompareUnicodeString(&OrphanAdapter->RegistryPath, Miniport->RegistryPath, TRUE))
+ {
+ OrphanAdapter = (PORPHAN_ADAPTER)OrphanAdapter->ListEntry.Flink;
+ continue;
+ }
+
+ NDIS_DbgPrint(MAX_TRACE, ("Found an orphan adapter for RegistryPath %wZ\n", Miniport->RegistryPath));
+
+ /* there is an orphan adapter for us */
+ Adapter->SlotNumber = OrphanAdapter->SlotNumber;
+ Adapter->BusNumber = OrphanAdapter->BusNumber;
+ Adapter->BusType = OrphanAdapter->BusType;
+
+ Status = HalAssignSlotResources(Miniport->RegistryPath, 0, Miniport->DriverObject,
+ Adapter->NdisMiniportBlock.DeviceObject, Adapter->BusType, Adapter->BusNumber,
+ Adapter->SlotNumber, &ResourceList);
+
+ if(!NT_SUCCESS(Status))
+ {
+ NDIS_DbgPrint(MIN_TRACE, ("HalAssignSlotResources broke: 0x%x\n", Status));
+#ifdef DBG
+ __asm__ ("int $3\n");
+#endif
+ /* i guess we should just give up on this adapter */
+ break;
+ }
+
+ /* go through the returned resource list and populate the Adapter */
+ for(i = 0; i<ResourceList->Count; i++)
+ {
+ int j;
+
+ PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor = &ResourceList->List[i];
+
+ for(j=0; j<ResourceDescriptor->PartialResourceList.Count; j++)
+ {
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor =
+ &ResourceDescriptor->PartialResourceList.PartialDescriptors[i];
+
+ switch(PartialResourceDescriptor->Type)
+ {
+ case CmResourceTypeInterrupt:
+ Adapter->Irql = PartialResourceDescriptor->u.Interrupt.Level;
+ Adapter->Vector = PartialResourceDescriptor->u.Interrupt.Vector;
+ Adapter->Affinity = PartialResourceDescriptor->u.Interrupt.Affinity;
+ break;
+
+ case CmResourceTypePort:
+ Adapter->BaseIoAddress = PartialResourceDescriptor->u.Port.Start;
+ break;
+
+ case CmResourceTypeMemory:
+ Adapter->BaseMemoryAddress = PartialResourceDescriptor->u.Memory.Start;
+ break;
+
+ case CmResourceTypeDma:
+ Adapter->DmaPort = PartialResourceDescriptor->u.Dma.Port;
+ Adapter->DmaChannel = PartialResourceDescriptor->u.Dma.Channel;
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+ default:
+ break;
+ }
+ }
+ }
+
+ /* remove the adapter from the list */
+ TempAdapter = (PORPHAN_ADAPTER)OrphanAdapter->ListEntry.Flink;
+ RemoveEntryList(&OrphanAdapter->ListEntry);
+ OrphanAdapter = TempAdapter;
+ }
+ KeReleaseSpinLock(&OrphanAdapterListLock, OldIrql);
+
+ /* includes room for a 0-term */
+ RegKeyPath = ExAllocatePool(PagedPool, (wcslen(SERVICES_ROOT) + wcslen(DeviceNameStr) + 1) * sizeof(WCHAR));
+ if(!RegKeyPath)
+ {
+ NDIS_DbgPrint(MIN_TRACE,("Insufficient resources\n"));
+ ExFreePool(Adapter);
+ return;
+ }
+
+ wcscpy(RegKeyPath, SERVICES_ROOT);
+ wcscat(RegKeyPath, DeviceNameStr);
+ RegKeyPath[wcslen(SERVICES_ROOT) + wcslen(DeviceNameStr)] = 0;
+
+ RtlInitUnicodeString(&RegKeyPathU, RegKeyPath);
+ InitializeObjectAttributes(&RegKeyAttributes, &RegKeyPathU, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ Status = ZwOpenKey(&RegKeyHandle, KEY_ALL_ACCESS, &RegKeyAttributes);
+ if(Status != STATUS_SUCCESS)
+ {
+ NDIS_DbgPrint(MIN_TRACE,("failed to open adapter-specific reg key %ws\n", RegKeyPath));
+ ExFreePool(Adapter);
+ return;
+ }
+
+ NDIS_DbgPrint(MAX_TRACE, ("opened device reg key: %wZ\n", &RegKeyPathU));
+
+ KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
+ InitializeListHead(&Adapter->ProtocolListHead);
+ Adapter->RefCount = 1;
+ Adapter->Miniport = Miniport;
+
+ /* Set handlers (some NDIS macros require these) */
+
+ Adapter->NdisMiniportBlock.EthRxCompleteHandler = MiniEthReceiveComplete;
+ Adapter->NdisMiniportBlock.EthRxIndicateHandler = MiniEthReceiveIndication;
+ Adapter->NdisMiniportBlock.SendCompleteHandler = MiniSendComplete;
+ Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
+ Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
+ Adapter->NdisMiniportBlock.TDCompleteHandler = MiniTransferDataComplete;
+ Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
+
+ KeInitializeDpc(&Adapter->MiniportDpc, MiniportDpc, (PVOID)Adapter);
+
+ /* Put adapter in adapter list for this miniport */
+ ExInterlockedInsertTailList(&Miniport->AdapterListHead, &Adapter->MiniportListEntry, &Miniport->Lock);
+
+ /* Put adapter in global adapter list */
+ ExInterlockedInsertTailList(&AdapterListHead, &Adapter->ListEntry, &AdapterListLock);
+
+ /* Call MiniportInitialize */
+ NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
+ NdisStatus = (*Miniport->Chars.InitializeHandler)( &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
+ MEDIA_ARRAY_SIZE, Adapter, RegKeyHandle);
+
+ ZwClose(RegKeyHandle);
+
+ if ((NdisStatus == NDIS_STATUS_SUCCESS) && (SelectedMediumIndex < MEDIA_ARRAY_SIZE))
+ {
+ NDIS_DbgPrint(MID_TRACE,("successful return from MiniportInitialize\n"));
+
+ Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
+
+ switch (Adapter->NdisMiniportBlock.MediaType)
+ {
+ case NdisMedium802_3:
+ Adapter->MediumHeaderSize = 14; /* XXX figure out what to do about LLC */
+ AddressOID = OID_802_3_CURRENT_ADDRESS;
+ Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
+
+ Adapter->NdisMiniportBlock.FilterDbs.u.EthDB = ExAllocatePool(NonPagedPool, sizeof(ETH_FILTER));
+ if (Adapter->NdisMiniportBlock.FilterDbs.u.EthDB)
+ {
+ RtlZeroMemory(Adapter->NdisMiniportBlock.FilterDbs.u.EthDB, sizeof(ETH_FILTER));
+ Adapter->NdisMiniportBlock.FilterDbs.u.EthDB->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
+ }
+ else
+ MemError = TRUE;
+
+ break;
+
+ default:
+ /* FIXME: Support other types of media */
+ ExFreePool(Adapter);
+ ASSERT(FALSE);
+ return;
+ }
+
+ NdisStatus = DoQueries(Adapter, AddressOID);
+ }
+
+ if ((MemError) || (NdisStatus != NDIS_STATUS_SUCCESS) || (SelectedMediumIndex >= MEDIA_ARRAY_SIZE))
+ {
+ NDIS_DbgPrint(MAX_TRACE, ("return from MiniportInitialize: NdisStatus 0x%x, SelectedMediumIndex 0x%x\n",
+ NdisStatus, SelectedMediumIndex));
+
+ /* Remove adapter from adapter list for this miniport */
+ KeAcquireSpinLock(&Miniport->Lock, &OldIrql);
+ RemoveEntryList(&Adapter->MiniportListEntry);
+ KeReleaseSpinLock(&Miniport->Lock, OldIrql);
+
+ /* Remove adapter from global adapter list */
+ KeAcquireSpinLock(&AdapterListLock, &OldIrql);
+ RemoveEntryList(&Adapter->ListEntry);
+ KeReleaseSpinLock(&AdapterListLock, OldIrql);
+
+ if (Adapter->LookaheadBuffer)
+ ExFreePool(Adapter->LookaheadBuffer);
+
+ IoDeleteDevice(Adapter->NdisMiniportBlock.DeviceObject);
+ ExFreePool(Adapter);
+ NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
+ }
+}
+