// // Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved // // nt.c // // IEEE1394 mini-port/call-manager driver // // Main routine (DriverEntry) and global data definitions // // 12/28/98 adube // 9/5/99 alid: added callback registeration and interface to enum1394 // #include "precomp.h" //----------------------------------------------------------------------------- // Local prototypes //----------------------------------------------------------------------------- extern NDIS_SPIN_LOCK g_DriverLock; extern LIST_ENTRY g_AdapterList; NDIS_STATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); VOID NicUnloadHandler( IN PDRIVER_OBJECT DriverObject ); // Mark routine to be unloaded after initialization. // #pragma NDIS_INIT_FUNCTION(DriverEntry) //----------------------------------------------------------------------------- // Routines //----------------------------------------------------------------------------- NDIS_STATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) // Standard 'DriverEntry' driver initialization entrypoint called by the // I/0 system at IRQL PASSIVE_LEVEL before any other call to the driver. // // On NT, 'DriverObject' is the driver object created by the I/0 system // and 'RegistryPath' specifies where driver specific parameters are // stored. These arguments are opaque to this driver (and should remain // so for portability) which only forwards them to the NDIS wrapper. // // Returns the value returned by NdisMRegisterMiniport, per the doc on // "DriverEntry of NDIS Miniport Drivers". // { NDIS_STATUS NdisStatus; NTSTATUS NtStatus = STATUS_SUCCESS; NDIS_MINIPORT_CHARACTERISTICS nmc; NDIS_HANDLE NdisWrapperHandle; UNICODE_STRING CallbackObjectName; OBJECT_ATTRIBUTES ObjectAttr; BOOLEAN fDerefCallbackObject = FALSE, fDeregisterCallback = FALSE; PDEVICE_OBJECT pDummyDeviceObject; TRACE( TL_I, TM_Init, ( " Nic1394 - DriverEntry" ) ); do { #ifdef CHANGE_MEDIUMS DbgPrint ("Nic1394 Driver Entry - Medium Type %x", &g_ulMedium); DbgBreakPoint(); #else // // Now depending on the ETHERNET preprocessor, define a medium // #ifdef _ETHERNET_ g_ulMedium = NdisMedium802_3; #else g_ulMedium = NdisMedium1394; #endif // _ETHERNET_ #endif // CHANGE_MEDIUMS // Register this driver with the NDIS wrapper. This call must occur // before any other NdisXxx calls. // NdisMInitializeWrapper( &NdisWrapperHandle, DriverObject, RegistryPath, NULL ); // Set up the mini-port characteristics table that tells NDIS how to call // our mini-port. // NdisZeroMemory( &nmc, sizeof(nmc) ); nmc.MajorNdisVersion = NDIS_MajorVersion; nmc.MinorNdisVersion = NDIS_MinorVersion; // nmc.CheckForHangHandler = CheckForHang; // no DisableInterruptHandler // no EnableInterruptHandler nmc.HaltHandler = NicMpHalt; // no HandleInterruptHandler nmc.InitializeHandler = NicMpInitialize; // no ISRHandler // no QueryInformationHandler (see CoRequestHandler) nmc.ResetHandler = NicMpReset; // no SendHandler (see CoSendPacketsHandler) // no WanSendHandler (see CoSendPacketsHandler) // no SetInformationHandler (see CoRequestHandler) // no TransferDataHandler // no WanTransferDataHandler // nmc.ReturnPacketHandler = NicMpReturnPacket; // no SendPacketsHandler (see CoSendPacketsHandler) // no AllocateCompleteHandler nmc.CoActivateVcHandler = NicMpCoActivateVc; nmc.CoDeactivateVcHandler= NicMpCoDeactivateVc; nmc.CoSendPacketsHandler = NicMpCoSendPackets; nmc.CoRequestHandler = NicMpCoRequest; nmc.ReturnPacketHandler = NicReturnPacket; #ifdef _ETHERNET_ nmc.QueryInformationHandler = NicEthQueryInformation; nmc.SetInformationHandler = NicEthSetInformation; nmc.SendPacketsHandler = NicMpSendPackets; #endif // // Create a dummy device object // #ifdef Win9X IoCreateDevice(DriverObject, 0, NULL, FILE_DEVICE_PHYSICAL_NETCARD, 0, FALSE,// exclusive flag &pDummyDeviceObject); #endif // Register this driver as the IEEE1394 mini-port. This will result in NDIS // calling back at NicMpInitialize. // TRACE( TL_V, TM_Init, ( "NdisMRegMp" ) ); NdisStatus = NdisMRegisterMiniport( NdisWrapperHandle, &nmc, sizeof(nmc) ); TRACE( TL_A, TM_Init, ( "NdisMRegMp=$%x", NdisStatus ) ); // if (NdisStatus == NDIS_STATUS_SUCCESS) { { extern CALLSTATS g_stats; extern NDIS_SPIN_LOCK g_lockStats; NdisZeroMemory( &g_stats, sizeof(g_stats) ); NdisAllocateSpinLock( &g_lockStats ); } // Initialize driver-wide lock and adapter list. // { NdisAllocateSpinLock( &g_DriverLock ); InitializeListHead( &g_AdapterList ); } // // BINARY_COMPATIBILITY_BUG // #if NDIS_NT NdisMRegisterUnloadHandler(NdisWrapperHandle, NicUnloadHandler); #endif #ifdef PSDEBUG { extern LIST_ENTRY g_listDebugPs; extern NDIS_SPIN_LOCK g_lockDebugPs; InitializeListHead( &g_listDebugPs ); NdisAllocateSpinLock( &g_lockDebugPs ); } #endif // // create a named Callback object with os // then register a callback routine with send a notification to all modules that // have a Callback routine registered with this function // if enum1394 is already loaded, this will let it know the nic driver is loaded // the enum1394 will get the driver registeration entry points from the notification // callback and calls NicRegisterDriver to pass the enum entry points // if enum1394 is not loaded and gets loaded later, it will send a notication to modules // who have registered with this callback object and passes its own driver registeration // the purpose of passign the entry points this way vs. exporting them, is to avoid // getting loaded as a DLL which fatal for both nic1394 and enum1394 // // // every Callback object is identified by a name. // RtlInitUnicodeString(&CallbackObjectName, NDIS1394_CALLBACK_NAME); InitializeObjectAttributes(&ObjectAttr, &CallbackObjectName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); NtStatus = ExCreateCallback(&Nic1394CallbackObject, &ObjectAttr, TRUE, // allow creating the object if it does not exist TRUE); // allow mutiple callback registeration if (!NT_SUCCESS(NtStatus)) { TRACE( TL_A, TM_All, ("Nic1394 DriverEntry: failed to create a Callback object. Status %lx\n", NtStatus)); NtStatus = STATUS_UNSUCCESSFUL; break; } fDerefCallbackObject = TRUE; Nic1394CallbackRegisterationHandle = ExRegisterCallback(Nic1394CallbackObject, Nic1394Callback, (PVOID)NULL); if (Nic1394CallbackRegisterationHandle == NULL) { TRACE(TL_A, TM_All, ("Nic1394 DriverEntry: failed to register a Callback routine%lx\n")); NtStatus = STATUS_UNSUCCESSFUL; break; } fDeregisterCallback = TRUE; // // now notify enum1394 (if it is already loaded) use Arg1 to tell it where // the notification is coming from // ExNotifyCallback(Nic1394CallbackObject, (PVOID)NDIS1394_CALLBACK_SOURCE_NIC1394, (PVOID)&Nic1394Characteristics); NtStatus = STATUS_SUCCESS; fDerefCallbackObject = fDeregisterCallback = FALSE; } else { NdisTerminateWrapper( NdisWrapperHandle, NULL ); NtStatus = NdisStatus; break; } } while (FALSE); if (fDerefCallbackObject) { ObDereferenceObject(Nic1394CallbackObject); } if (fDeregisterCallback) { ExUnregisterCallback(Nic1394CallbackRegisterationHandle); } if (NtStatus != STATUS_SUCCESS) { if (NdisEnum1394DeregisterDriver != NULL) NdisEnum1394DeregisterDriver(); } return NtStatus; } VOID NicUnloadHandler( IN PDRIVER_OBJECT DriverObject ) { ASSERT(IsListEmpty(&g_AdapterList)); if (NdisEnum1394DeregisterDriver != NULL) { NdisEnum1394DeregisterDriver(); } if (Nic1394CallbackRegisterationHandle != NULL) { ExUnregisterCallback(Nic1394CallbackRegisterationHandle); } if (Nic1394CallbackObject != NULL) { ObDereferenceObject(Nic1394CallbackObject); } return; } VOID nicDeregisterWithEnum () { if (NdisEnum1394DeregisterDriver != NULL) { NdisEnum1394DeregisterDriver(); } } VOID nicDeregisterWithKernel () { if (Nic1394CallbackRegisterationHandle != NULL) { ExUnregisterCallback(Nic1394CallbackRegisterationHandle); } if (Nic1394CallbackObject != NULL) { ObDereferenceObject(Nic1394CallbackObject); } } // // the registeration entry for enum1394 // typically this will be only called if enum1394 detects the presence of // the nic1394 through receiving a call back notification. this is how enum1394 // lets nic1394 know that it is there and ready. // if nic1394 detects the presence of the enum1394 by receiving a notification // callbak, it will call NdisEunm1394RegisterDriver and in that case enum1394 // will -not- call Nic1394RegisterDriver. // NTSTATUS NicRegisterEnum1394( IN PNDISENUM1394_CHARACTERISTICS NdisEnum1394Characteristcis ) { PADAPTERCB pAdapter; LIST_ENTRY *pAdapterListEntry; NdisEnum1394RegisterDriver = NdisEnum1394Characteristcis->RegisterDriverHandler; NdisEnum1394DeregisterDriver = NdisEnum1394Characteristcis->DeregisterDriverHandler; NdisEnum1394RegisterAdapter = NdisEnum1394Characteristcis->RegisterAdapterHandler; NdisEnum1394DeregisterAdapter = NdisEnum1394Characteristcis->DeregisterAdapterHandler; Nic1394RegisterAdapters(); return STATUS_SUCCESS; } VOID NicDeregisterEnum1394( VOID ) { PADAPTERCB pAdapter; LIST_ENTRY *pAdapterListEntry; // // go through all the adapters and Deregister them if necessary // NdisAcquireSpinLock (&g_DriverLock); for (pAdapterListEntry = g_AdapterList.Flink; pAdapterListEntry != &g_AdapterList; pAdapterListEntry = pAdapterListEntry->Flink) { pAdapter = CONTAINING_RECORD(pAdapterListEntry, ADAPTERCB, linkAdapter); if (ADAPTER_TEST_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator)) { nicReferenceAdapter(pAdapter,"NicDeregisterEnum1394"); NdisReleaseSpinLock(&g_DriverLock); NdisEnum1394DeregisterAdapter((PVOID)pAdapter->EnumAdapterHandle); NdisAcquireSpinLock( &g_DriverLock); nicDereferenceAdapter(pAdapter, "NicDeregisterEnum1394"); } ADAPTER_CLEAR_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator | fADAPTER_FailedRegisteration); } NdisReleaseSpinLock(&g_DriverLock); NdisEnum1394RegisterDriver = NULL; NdisEnum1394DeregisterDriver = NULL; NdisEnum1394RegisterAdapter = NULL; NdisEnum1394DeregisterAdapter = NULL; } VOID Nic1394Callback( PVOID CallBackContext, PVOID Source, PVOID Characteristics ) { NTSTATUS Status; // // if we are the one issuing this notification, just return // if (Source == (PVOID)NDIS1394_CALLBACK_SOURCE_NIC1394) return; // // notification is coming from Nic1394. grab the entry points. call it and // let it know that you are here // ASSERT(Source == (PVOID)NDIS1394_CALLBACK_SOURCE_ENUM1394); if (Source != (PVOID)NDIS1394_CALLBACK_SOURCE_ENUM1394) { return; } NdisEnum1394RegisterDriver = ((PNDISENUM1394_CHARACTERISTICS)Characteristics)->RegisterDriverHandler; ASSERT(NdisEnum1394RegisterDriver != NULL); if (NdisEnum1394RegisterDriver == NULL) { // // invalid characteristics // return; } Status = NdisEnum1394RegisterDriver(&Nic1394Characteristics); if (Status == STATUS_SUCCESS) { NdisEnum1394DeregisterDriver = ((PNDISENUM1394_CHARACTERISTICS)Characteristics)->DeregisterDriverHandler; NdisEnum1394RegisterAdapter = ((PNDISENUM1394_CHARACTERISTICS)Characteristics)->RegisterAdapterHandler; NdisEnum1394DeregisterAdapter = ((PNDISENUM1394_CHARACTERISTICS)Characteristics)->DeregisterAdapterHandler; Nic1394RegisterAdapters(); } else { NdisEnum1394RegisterDriver = NULL; } } // // This function walks the global list of the adapters and // will register those that have not been registered with enum1394 // VOID Nic1394RegisterAdapters( VOID ) { PADAPTERCB pAdapter; LIST_ENTRY *pAdapterListEntry; LARGE_INTEGER LocalHostUniqueId; NTSTATUS NtStatus; // // go through all the adapters and register them if necessary. if there are // any remote nodes connected to these adapters, they will be indicated back // in the context of registering the adapter // NdisAcquireSpinLock(&g_DriverLock); for (pAdapterListEntry = g_AdapterList.Flink; pAdapterListEntry != &g_AdapterList; pAdapterListEntry = pAdapterListEntry->Flink) { pAdapter = CONTAINING_RECORD(pAdapterListEntry, ADAPTERCB, linkAdapter); if (!ADAPTER_TEST_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator | fADAPTER_FailedRegisteration)) { nicReferenceAdapter (pAdapter, "Nic1394RegisterAdapters"); NdisReleaseSpinLock (&g_DriverLock); NtStatus = NdisEnum1394RegisterAdapter((PVOID)pAdapter, pAdapter->pNdisDeviceObject, &pAdapter->EnumAdapterHandle, &LocalHostUniqueId); NdisAcquireSpinLock(&g_DriverLock); nicDereferenceAdapter(pAdapter, "Nic1394RegisterAdapters"); if (NtStatus == STATUS_SUCCESS) { ADAPTER_SET_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator); } else { ADAPTER_SET_FLAG(pAdapter, fADAPTER_FailedRegisteration); TRACE(TL_A, TM_All, ("Nic1394RegisterAdapters: failed to register Adapter %lx with enum1394. Status %lx\n", pAdapter, NtStatus)); } } } NdisReleaseSpinLock(&g_DriverLock); return; }