/*++ Copyright (c) 1998-99 Microsoft Corporation Module Name: enum1394.c Abstract: 1394 ndis enumerator Author: Alireza Dabagh (alid) Environment: Kernel mode Revision History : --*/ #include // // extra stuff to keep ks.h happy // #ifndef CDECL #define CDECL #endif #ifndef BOOL #define BOOL int #endif #define ENUM1394_NT 1 #include "1394.h" #include "ndis1394.h" #include "enum1394.h" #include "ntdd1394.h" #define NDISENUM1394_DEVICE_NAME L"\\Device\\NdisEnum1394" #define NDISENUM1394_SYMBOLIC_NAME L"\\DosDevices\\NDISENUM1394" NDISENUM1394_CHARACTERISTICS NdisEnum1394Characteristics = { 1, 0, 0, NdisEnum1394RegisterDriver, NdisEnum1394DeregisterDriver, NdisEnum1394RegisterAdapter, NdisEnum1394DeregisterAdapter }; KSPIN_LOCK ndisEnum1394GlobalLock; ULONG Enum1394DebugLevel = ENUM1394_DBGLEVEL_ERROR ; PNDISENUM1394_LOCAL_HOST LocalHostList = (PNDISENUM1394_LOCAL_HOST)NULL; NIC1394_ADD_NODE_HANLDER AddNodeHandler = NULL; NIC1394_REMOVE_NODE_HANLDER RemoveNodeHandler = NULL; NIC1394_REGISTER_DRIVER_HANDLER RegisterDriverHandler = NULL; NIC1394_DEREGISTER_DRIVER_HANDLER DeRegisterDriverHandler = NULL; PDEVICE_OBJECT ndisEnum1394DeviceObject = NULL; PDRIVER_OBJECT ndisEnum1394DriverObject = NULL; PCALLBACK_OBJECT ndisEnum1394CallbackObject = NULL; PVOID ndisEnum1394CallbackRegisterationHandle = NULL; NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine is called at system initialization time so we can fill in the basic dispatch points Arguments: DriverObject - Supplies the driver object. RegistryPath - Supplies the registry path for this driver. Return Value: STATUS_SUCCESS --*/ { OBJECT_ATTRIBUTES ObjectAttr; UNICODE_STRING CallBackObjectName; NTSTATUS Status; UNICODE_STRING DeviceName; UNICODE_STRING SymbolicLinkName; BOOLEAN fDerefCallbackObject = FALSE; BOOLEAN fDeregisterCallback = FALSE; DBGPRINT(ENUM1394_DBGLEVEL_INFO,("Enum1394 DriverEntry.\n")); do { KeInitializeSpinLock(&ndisEnum1394GlobalLock); RtlInitUnicodeString(&DeviceName, NDISENUM1394_DEVICE_NAME); ndisEnum1394DriverObject = DriverObject; RtlInitUnicodeString(&CallBackObjectName, NDIS1394_CALLBACK_NAME); InitializeObjectAttributes(&ObjectAttr, &CallBackObjectName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); Status = ExCreateCallback(&ndisEnum1394CallbackObject, &ObjectAttr, TRUE, TRUE); if (!NT_SUCCESS(Status)) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR,("Enum1394 DriverEntry: failed to create a Callback object. Status %lx\n", Status)); Status = STATUS_UNSUCCESSFUL; break; } fDerefCallbackObject = TRUE; ndisEnum1394CallbackRegisterationHandle = ExRegisterCallback(ndisEnum1394CallbackObject, Enum1394Callback, (PVOID)NULL); if (ndisEnum1394CallbackRegisterationHandle == NULL) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR,("Enum1394 DriverEntry: failed to register a Callback routine%lx\n")); Status = STATUS_UNSUCCESSFUL; break; } fDeregisterCallback = TRUE; ExNotifyCallback(ndisEnum1394CallbackObject, (PVOID)NDIS1394_CALLBACK_SOURCE_ENUM1394, (PVOID)&NdisEnum1394Characteristics); // // Initialize the Driver Object with driver's entry points // DriverObject->DriverExtension->AddDevice = ndisEnum1394AddDevice; // // Fill in the Mandatory handlers // DriverObject->DriverUnload = ndisEnum1394Unload; DriverObject->MajorFunction[IRP_MJ_CREATE] = ndisEnum1394CreateIrpHandler; DriverObject->MajorFunction[IRP_MJ_CLOSE] = ndisEnum1394CloseIrpHandler; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ndisEnum1394DeviceIoControl; DriverObject->MajorFunction[IRP_MJ_PNP] = ndisEnum1394PnpDispatch; DriverObject->MajorFunction[IRP_MJ_POWER] = ndisEnum1394PowerDispatch; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ndisEnum1394WMIDispatch; fDerefCallbackObject = fDeregisterCallback = FALSE; Status = STATUS_SUCCESS; } while(FALSE); if (fDeregisterCallback) { ExUnregisterCallback(ndisEnum1394CallbackRegisterationHandle); } if (fDerefCallbackObject) { ObDereferenceObject(ndisEnum1394CallbackObject); } if (Status != STATUS_SUCCESS) { if (DeRegisterDriverHandler != NULL) DeRegisterDriverHandler(); } return Status; } NTSTATUS ndisEnum1394AddDevice( PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject ) /*++ Routine Description: This is our PNP AddDevice called with the PDO ejected from the bus driver Arguments: Return Value: --*/ { NTSTATUS Status; PNDISENUM1394_REMOTE_NODE RemoteNode; PDEVICE_OBJECT DeviceObject, NextDeviceObject; KIRQL OldIrql; PNDISENUM1394_LOCAL_HOST LocalHost; BOOLEAN FreeDevice = FALSE; BOOLEAN fNewHost = FALSE; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394AddDevice: PDO %lx\n", PhysicalDeviceObject)); do { // // first create a FDO // Status = IoCreateDevice( DriverObject, sizeof (NDISENUM1394_REMOTE_NODE), // extension size NULL, // name (null for now) FILE_DEVICE_NETWORK, // device type 0, // characteristics FALSE, &DeviceObject); if (!NT_SUCCESS(Status)) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394AddDevice: failed to create FDO. Status %lx, PDO %lx\n", Status, PhysicalDeviceObject)); break; } FreeDevice = TRUE; DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; // // Mark the device as being pageable. // DeviceObject->Flags |= DO_POWER_PAGABLE; // // Attach our FDO to the PDO. This routine will return the top most // device that is attached to the PDO or the PDO itself if no other // device objects have attached to it. // NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); RtlZeroMemory(DeviceObject->DeviceExtension, sizeof (NDISENUM1394_REMOTE_NODE)); RemoteNode = (PNDISENUM1394_REMOTE_NODE)DeviceObject->DeviceExtension; RemoteNode->DeviceObject = DeviceObject; RemoteNode->PhysicalDeviceObject = PhysicalDeviceObject; RemoteNode->NextDeviceObject = NextDeviceObject; RemoteNode->PnPDeviceState = PnPDeviceAdded; KeInitializeSpinLock(&RemoteNode->Lock); ndisEnum1394InitializeRef(&RemoteNode->Reference); Status = ndisEnum1394GetLocalHostForRemoteNode(RemoteNode, &LocalHost); if (Status != STATUS_SUCCESS) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394AddDevice: ndisEnum1394GetLocalHostForRemoteNode failed. Status %lx\n", Status)); break; } RemoteNode->LocalHost = LocalHost; ExAcquireSpinLock(&LocalHost->Lock, &OldIrql); RemoteNode->Next = LocalHost->RemoteNodeList; LocalHost->RemoteNodeList = RemoteNode; ExReleaseSpinLock(&LocalHost->Lock, OldIrql); FreeDevice = FALSE; } while(FALSE); if (FreeDevice) { IoDeleteDevice(DeviceObject); } DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394AddDevice: Status %lx, PDO %lx, FDO %lx\n", Status, PhysicalDeviceObject, DeviceObject)); return (Status); } NTSTATUS ndisEnum1394PowerDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION IrpSp, NextIrpSp; NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT NextDeviceObject; PNDISENUM1394_REMOTE_NODE RemoteNode; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394PowerDispatch: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); Irp->IoStatus.Status = STATUS_SUCCESS; PoStartNextPowerIrp(Irp); // // Set up the Irp for passing it down, no completion routine is needed // IoSkipCurrentIrpStackLocation(Irp); RemoteNode = (PNDISENUM1394_REMOTE_NODE)DeviceObject->DeviceExtension; // // Get a pointer to the next miniport. // NextDeviceObject = RemoteNode->NextDeviceObject; // // Call the lower device // PoCallDriver (NextDeviceObject, Irp); Status = STATUS_SUCCESS; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394PowerDispatch: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); return Status; } NTSTATUS ndisEnum1394WMIDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION NextIrpStack; NTSTATUS ntStatus = STATUS_SUCCESS; PNDISENUM1394_REMOTE_NODE RemoteNode = NULL; PDEVICE_OBJECT NextDeviceObject = NULL; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394WMIDispatch: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); // // Get a pointer to the adapter block and miniport block then determine // which one we should use. // RemoteNode = (PNDISENUM1394_REMOTE_NODE)DeviceObject->DeviceExtension; // // Get a pointer to the next miniport. // NextDeviceObject = RemoteNode->NextDeviceObject; // // Pass the Irp Down // // // Set up the Irp for passing it down, no completion routine is needed // IoSkipCurrentIrpStackLocation(Irp); ntStatus = IoCallDriver (NextDeviceObject, Irp); return ntStatus; } NTSTATUS ndisEnum1394StartDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PNDISENUM1394_REMOTE_NODE RemoteNode, TmpRemoteNode; PNDISENUM1394_LOCAL_HOST LocalHost; NTSTATUS Status = STATUS_SUCCESS; KIRQL OldIrql; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394StartDevice: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); RemoteNode = (PNDISENUM1394_REMOTE_NODE)DeviceObject->DeviceExtension; LocalHost = RemoteNode->LocalHost; ExAcquireSpinLock(&LocalHost->Lock, &OldIrql); do { // // if this is a duplicate node, leave it in the queue. but don't tag it as // being started so we don't end up indicating it // for (TmpRemoteNode = LocalHost->RemoteNodeList; TmpRemoteNode != NULL; TmpRemoteNode = TmpRemoteNode->Next) { if ((TmpRemoteNode->UniqueId[0] == RemoteNode->UniqueId[0]) && (TmpRemoteNode->UniqueId[1] == RemoteNode->UniqueId[1]) && ENUM_TEST_FLAG(TmpRemoteNode, NDISENUM1394_NODE_PNP_STARTED)) break; } if (TmpRemoteNode != NULL) { // // duplicate node // DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394StartDevice: duplicate node. new node %lx, original Node %lx\n", TmpRemoteNode, RemoteNode)); ENUM_CLEAR_FLAG(RemoteNode, NDISENUM1394_NODE_PNP_STARTED); break; } ENUM_SET_FLAG(RemoteNode, NDISENUM1394_NODE_PNP_STARTED); if((AddNodeHandler != NULL) && (LocalHost->Nic1394AdapterContext != NULL)) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394StartDevice: Notifying Nic1394 of device arrival, Miniport PDO %lx, Node PDO %lx\n", LocalHost->PhysicalDeviceObject, RemoteNode->PhysicalDeviceObject)); if (!ENUM_TEST_FLAG(RemoteNode, NDISENUM1394_NODE_INDICATED)) { ENUM_SET_FLAG(RemoteNode, NDISENUM1394_NODE_INDICATED); ExReleaseSpinLock(&LocalHost->Lock, OldIrql); Status = AddNodeHandler(LocalHost->Nic1394AdapterContext, (PVOID)RemoteNode, RemoteNode->PhysicalDeviceObject, RemoteNode->UniqueId[0], RemoteNode->UniqueId[1], &RemoteNode->Nic1394NodeContext); ASSERT(Status == STATUS_SUCCESS); ExAcquireSpinLock(&LocalHost->Lock, &OldIrql); if (Status == STATUS_SUCCESS) { ENUM_SET_FLAG(RemoteNode, NDISENUM1394_NODE_ADDED); } else { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394StartDevice: AddAdapter failed %lx\n", Status)); } } } } while (FALSE); ExReleaseSpinLock(&LocalHost->Lock, OldIrql); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394StartDevice: Status %lx, DeviceObject %lx, Irp %lx\n", Status, DeviceObject, Irp)); return Status; } VOID ndisEnum1394IndicateNodes( PNDISENUM1394_LOCAL_HOST LocalHost ) { PNDISENUM1394_REMOTE_NODE RemoteNode; NTSTATUS Status = STATUS_UNSUCCESSFUL; KIRQL OldIrql; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394IndicateNodes: LocalHost %lx\n", LocalHost)); // // notify 1394 NIC driver // if (AddNodeHandler == NULL) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394IndicateNodes: LocalHost %lx\n", LocalHost)); return; } ExAcquireSpinLock(&LocalHost->Lock, &OldIrql); if (ENUM_TEST_FLAG(LocalHost, NDISENUM1394_LOCALHOST_REGISTERED)) { next: for (RemoteNode = LocalHost->RemoteNodeList; RemoteNode != NULL; RemoteNode = RemoteNode->Next) { if ((!ENUM_TEST_FLAG(RemoteNode, NDISENUM1394_NODE_INDICATED)) && ENUM_TEST_FLAG(RemoteNode, NDISENUM1394_NODE_PNP_STARTED)) { ENUM_SET_FLAG(RemoteNode, NDISENUM1394_NODE_INDICATED); break; } } if (RemoteNode != NULL) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394IndicateNodes: Notifying Nic1394 of device arrival, Miniport PDO %lx, Node PDO %lx\n", LocalHost->PhysicalDeviceObject, RemoteNode->PhysicalDeviceObject)); ExReleaseSpinLock(&LocalHost->Lock, OldIrql); Status = AddNodeHandler(LocalHost->Nic1394AdapterContext, (PVOID)RemoteNode, RemoteNode->PhysicalDeviceObject, RemoteNode->UniqueId[0], RemoteNode->UniqueId[1], &RemoteNode->Nic1394NodeContext); ASSERT(Status == STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { ENUM_SET_FLAG(RemoteNode, NDISENUM1394_NODE_ADDED); } else { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394IndicateNodes: AddAdapter failed %lx\n", Status)); } ExAcquireSpinLock(&LocalHost->Lock, &OldIrql); goto next; } } else { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394IndicateNodes: LocalHost is not registered %lx\n", Status)); } ExReleaseSpinLock(&LocalHost->Lock, OldIrql); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394IndicateNodes: LocalHost %lx\n", LocalHost)); } NTSTATUS ndisEnum1394CreateIrpHandler( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394CreateIrpHandler: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394CreateIrpHandler: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); return STATUS_SUCCESS; } NTSTATUS ndisEnum1394CloseIrpHandler( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394CloseIrpHandler: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394CloseIrpHandler: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); return STATUS_SUCCESS; } NTSTATUS ndisEnum1394DeviceIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394DeviceIoControl: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394DeviceIoControl: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); return STATUS_SUCCESS; } VOID ndisEnum1394Unload( IN PDRIVER_OBJECT DriverObject ) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394Unload: DriverObject %lx\n", DriverObject)); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394Unload: DriverObject %lx\n", DriverObject)); // // Tell nic1394 that we are going away // if (DeRegisterDriverHandler != NULL ) { DeRegisterDriverHandler() ; } // // Deregister our callback structure // ExUnregisterCallback(ndisEnum1394CallbackRegisterationHandle); // // Dereference our callback structure // ObDereferenceObject(ndisEnum1394CallbackObject); return; } /* EXPORT NTSTATUS NdisEnum1394RegisterAdapter( IN PVOID Nic1394AdapterContext, IN PDEVICE_OBJECT PhysicalDeviceObject, OUT PVOID* pEnum1394AdapterHandle, OUT PLARGE_INTEGER pLocalHostUniqueId ); This routine is called at system initialization time so we can fill in the basic dispatch points Arguments: DriverObject - Supplies the driver object. RegistryPath - Supplies the registry path for this driver. Return Value: STATUS_SUCCESS Routine Description: This function is called by Nic1394 during its Ndis IntializeHandler to register a new Adapter. each registered adapter corresponds to a local host controller. in response Enum1394 finds the local host and for each remote node on the local host that have not been indicated yet calls the Nic1394 AddNodes handler. Arguments: Nic1394AdapterContext Nic1394 context for the local host PhysicalDeviceObject PDO created by 1394 Bus driver for the local host pEnum1394AdapterHandle a pointer a pointer to be initialized to Enum1394 LocalHost context pLocalHostUniqueId a pointer to a LARGE_INTEGER to be initialized to local host unique ID */ NTSTATUS NdisEnum1394RegisterAdapter( IN PVOID Nic1394AdapterContext, IN PDEVICE_OBJECT PhysicalDeviceObject, OUT PVOID* pEnum1394AdapterHandle, OUT PLARGE_INTEGER pLocalHostUniqueId ) { PNDISENUM1394_LOCAL_HOST LocalHost; PNDISENUM1394_REMOTE_NODE LocalNode; NTSTATUS Status; KIRQL OldIrql; IRB Irb; GET_LOCAL_HOST_INFO1 uId; PDEVICE_OBJECT DeviceObject; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>NdisEnum1394RegisterAdapter, PhysicalDeviceObject %lx\n", PhysicalDeviceObject)); do { // // get the unique ID for the local host for this adapter // RtlZeroMemory(&Irb, sizeof(IRB)); Irb.FunctionNumber = REQUEST_GET_LOCAL_HOST_INFO; Irb.u.GetLocalHostInformation.nLevel = GET_HOST_UNIQUE_ID; Irb.u.GetLocalHostInformation.Information = (PVOID)&uId; Status = ndisEnum1394BusRequest(PhysicalDeviceObject, &Irb); if (Status != STATUS_SUCCESS) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("NdisEnum1394RegisterAdapter: ndisEnum1394BusRequest for REQUEST_GET_LOCAL_HOST_INFO failed. Status %lx\n", Status)); break; } // // GetLocal Host Refs the LocalHost - Derefed in DeRegisterAdapter // ndisEnum1394GetLocalHostForUniqueId(uId.UniqueId, &LocalHost); #if 0 ExAcquireSpinLock(&ndisEnum1394GlobalLock, &OldIrql); for (LocalHost = LocalHostList; LocalHost != NULL; LocalHost = LocalHost->Next) { if ((LocalHost->UniqueId.LowPart == uId.UniqueId.LowPart) && (LocalHost->UniqueId.HighPart == uId.UniqueId.HighPart)) { break; } } ExReleaseSpinLock(&ndisEnum1394GlobalLock, OldIrql); #endif ASSERT(LocalHost != NULL); if (LocalHost == NULL) { Status = STATUS_UNSUCCESSFUL; break; } *pEnum1394AdapterHandle = (PVOID)LocalHost; LocalHost->Nic1394AdapterContext = Nic1394AdapterContext; LocalHost->PhysicalDeviceObject = PhysicalDeviceObject; *pLocalHostUniqueId = LocalHost->UniqueId; ENUM_SET_FLAG(LocalHost, NDISENUM1394_LOCALHOST_REGISTERED); ndisEnum1394IndicateNodes(LocalHost); Status = STATUS_SUCCESS; } while (FALSE); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==NdisEnum1394RegisterAdapter: Status %lx\n", Status)); return Status; } VOID NdisEnum1394DeregisterAdapter( IN PVOID Enum1394AdapterHandle ) { PNDISENUM1394_LOCAL_HOST LocalHost = (PNDISENUM1394_LOCAL_HOST)Enum1394AdapterHandle; KIRQL OldIrql; PNDISENUM1394_REMOTE_NODE RemoteNode; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>NdisEnum1394DeregisterAdapter: LocalHost %lx\n", Enum1394AdapterHandle)); // // go through all the nodes and remove them // ExAcquireSpinLock(&LocalHost->Lock, &OldIrql); // // make sure we will not try to indicate any new dev node on this // ENUM_CLEAR_FLAG(LocalHost, NDISENUM1394_LOCALHOST_REGISTERED); next: for (RemoteNode = LocalHost->RemoteNodeList; RemoteNode != NULL; RemoteNode = RemoteNode->Next) { ENUM_CLEAR_FLAG(RemoteNode, NDISENUM1394_NODE_INDICATED); if (ENUM_TEST_FLAG(RemoteNode, NDISENUM1394_NODE_ADDED)) { break; } } if (RemoteNode != NULL) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("NdisEnum1394DeregisterAdapter: Notifying Nic1394 of device removal, Miniport PDO %lx, Node PDO %lx\n", LocalHost->PhysicalDeviceObject, RemoteNode->PhysicalDeviceObject)); ExReleaseSpinLock(&LocalHost->Lock, OldIrql); RemoveNodeHandler(RemoteNode->Nic1394NodeContext); ExAcquireSpinLock(&LocalHost->Lock, &OldIrql); ENUM_CLEAR_FLAG(RemoteNode, NDISENUM1394_NODE_ADDED); goto next; } LocalHost->Nic1394AdapterContext = NULL; LocalHost->PhysicalDeviceObject = NULL; ExReleaseSpinLock(&LocalHost->Lock, OldIrql); // // Dereference the Ref made in RegisterAdapter by calling GetLocalHost for Unique ID // { BOOLEAN bIsRefZero; bIsRefZero = ndisEnum1394DereferenceLocalHost(LocalHost); if (bIsRefZero == TRUE) { ndisEnum1394FreeLocalHost(LocalHost); } } DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==NdisEnum1394DeregisterAdapter: LocalHost %lx\n", Enum1394AdapterHandle)); } NTSTATUS ndisEnum1394GetLocalHostForRemoteNode( IN PNDISENUM1394_REMOTE_NODE RemoteNode, OUT PNDISENUM1394_LOCAL_HOST * pLocalHost ) { NTSTATUS Status; PNDISENUM1394_LOCAL_HOST LocalHost; KIRQL OldIrql; IRB Irb; GET_LOCAL_HOST_INFO1 uId; ULONG SizeNeeded; PVOID ConfigInfoBuffer = NULL; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394GetLocalHostForRemoteNode: RemoteNode %lx\n", RemoteNode)); do { // // get the unique ID for the local host which this device // is connected on. then walk through all the existing local // hosts and see if this a new local host or not. // RtlZeroMemory(&Irb, sizeof(IRB)); Irb.FunctionNumber = REQUEST_GET_LOCAL_HOST_INFO; Irb.u.GetLocalHostInformation.nLevel = GET_HOST_UNIQUE_ID; Irb.u.GetLocalHostInformation.Information = (PVOID)&uId; Status = ndisEnum1394BusRequest(RemoteNode->NextDeviceObject, &Irb); if (Status != STATUS_SUCCESS) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394GetLocalHostForRemoteNode: ndisEnum1394BusRequest for REQUEST_GET_LOCAL_HOST_INFO failed. Status %lx\n", Status)); break; } // // now get the unique ID for the remote node // // we have to make this call twice. first to get the size, then the actual data // RtlZeroMemory(&Irb, sizeof(IRB)); Irb.FunctionNumber = REQUEST_GET_CONFIGURATION_INFO; Status = ndisEnum1394BusRequest(RemoteNode->NextDeviceObject, &Irb); if (Status != STATUS_SUCCESS) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394GetLocalHostForRemoteNode: ndisEnum1394BusRequest for REQUEST_GET_CONFIGURATION_INFO (size) failed. Status %lx\n", Status)); break; } SizeNeeded = sizeof(CONFIG_ROM) + Irb.u.GetConfigurationInformation.UnitDirectoryBufferSize + Irb.u.GetConfigurationInformation.UnitDependentDirectoryBufferSize + Irb.u.GetConfigurationInformation.VendorLeafBufferSize + Irb.u.GetConfigurationInformation.ModelLeafBufferSize; ConfigInfoBuffer = (PVOID)ALLOC_FROM_POOL(SizeNeeded, ' 4N'); if (ConfigInfoBuffer == NULL) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394GetLocalHostForRemoteNode: Failed to allocate memory for config info.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; break; } Irb.u.GetConfigurationInformation.ConfigRom = (PCONFIG_ROM)ConfigInfoBuffer; Irb.u.GetConfigurationInformation.UnitDirectory = (PVOID)((PUCHAR)ConfigInfoBuffer + sizeof(CONFIG_ROM)); Irb.u.GetConfigurationInformation.UnitDependentDirectory = (PVOID)((PUCHAR)Irb.u.GetConfigurationInformation.UnitDirectory + Irb.u.GetConfigurationInformation.UnitDirectoryBufferSize); Irb.u.GetConfigurationInformation.VendorLeaf = (PVOID)((PUCHAR)Irb.u.GetConfigurationInformation.UnitDependentDirectory + Irb.u.GetConfigurationInformation.UnitDependentDirectoryBufferSize); Irb.u.GetConfigurationInformation.ModelLeaf = (PVOID)((PUCHAR)Irb.u.GetConfigurationInformation.VendorLeaf + Irb.u.GetConfigurationInformation.VendorLeafBufferSize); Irb.FunctionNumber = REQUEST_GET_CONFIGURATION_INFO; Status = ndisEnum1394BusRequest(RemoteNode->NextDeviceObject, &Irb); if (Status != STATUS_SUCCESS) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394GetLocalHostForRemoteNode: ndisEnum1394BusRequest for REQUEST_GET_CONFIGURATION_INFO failed. Status %lx\n", Status)); break; } ASSERT(Irb.u.GetConfigurationInformation.ConfigRom != NULL); RemoteNode->UniqueId[0] = Irb.u.GetConfigurationInformation.ConfigRom->CR_Node_UniqueID[0]; RemoteNode->UniqueId[1] = Irb.u.GetConfigurationInformation.ConfigRom->CR_Node_UniqueID[1]; #if DBG DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("Unique ID for Node %lx: %02x, %02x, %02x, %02x, %02x, %02x, %02x, %02x\n", RemoteNode->PhysicalDeviceObject, *((PUCHAR)&RemoteNode->UniqueId[0]), *(((PUCHAR)&RemoteNode->UniqueId[0])+1), *(((PUCHAR)&RemoteNode->UniqueId[0])+2), *(((PUCHAR)&RemoteNode->UniqueId[0])+3), *((PUCHAR)&RemoteNode->UniqueId[1]), *(((PUCHAR)&RemoteNode->UniqueId[1])+1), *(((PUCHAR)&RemoteNode->UniqueId[1])+2), *(((PUCHAR)&RemoteNode->UniqueId[1])+3))); #endif ndisEnum1394GetLocalHostForUniqueId(uId.UniqueId, &LocalHost); if (LocalHost == NULL) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394GetLocalHostForUniqueId: Failed to get the local host.\n")); Status = STATUS_UNSUCCESSFUL; break; } *pLocalHost = LocalHost; Status = STATUS_SUCCESS; } while (FALSE); if (ConfigInfoBuffer != NULL) { FREE_POOL(ConfigInfoBuffer); } DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394GetLocalHostForRemoteNode: Status %lx, RemoteNode %lx, LocalHostList %lx\n", Status, RemoteNode, LocalHostList)); return Status; } NTSTATUS ndisEnum1394IrpCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This routine will get called after the next device object in the stack processes the IRP_MN_QUERY_CAPABILITIES IRP this needs to be merged with the miniport's capabilites and completed. Arguments: DeviceObject Irp Context Return Value: --*/ { SET_EVENT(Context); return(STATUS_MORE_PROCESSING_REQUIRED); } NTSTATUS ndisEnum1394PassIrpDownTheStack( IN PIRP pIrp, IN PDEVICE_OBJECT pNextDeviceObject ) /*++ Routine Description: This routine will simply pass the IRP down to the next device object to process. Arguments: pIrp - Pointer to the IRP to process. pNextDeviceObject - Pointer to the next device object that wants the IRP. Return Value: --*/ { KEVENT Event; NTSTATUS Status = STATUS_SUCCESS; // // Initialize the event structure. // INITIALIZE_EVENT(&Event); // // Set the completion routine so that we can process the IRP when // our PDO is done. // IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)ndisEnum1394IrpCompletion, &Event, TRUE, TRUE, TRUE); // // Pass the IRP down to the PDO. // Status = IoCallDriver(pNextDeviceObject, pIrp); if (Status == STATUS_PENDING) { // // Wait for completion. // WAIT_FOR_OBJECT(&Event, NULL); Status = pIrp->IoStatus.Status; } return(Status); } NTSTATUS ndisEnum1394PnpDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: The handler for IRP_MJ_PNP_POWER. Arguments: DeviceObject - The adapter's functional device object. Irp - The IRP. Return Value: --*/ { PIO_STACK_LOCATION IrpSp, NextIrpSp; NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT NextDeviceObject; PNDISENUM1394_REMOTE_NODE RemoteNode; ULONG PnPDeviceState; KEVENT RemoveReadyEvent; BOOLEAN fSendIrpDown = TRUE; BOOLEAN fCompleteIrp = TRUE; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394PnpDispatch: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); if (DbgIsNull(Irp)) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394PnpDispatch: Null Irp\n")); DBGBREAK(); } // // Get a pointer to the adapter block and miniport block then determine // which one we should use. // RemoteNode = (PNDISENUM1394_REMOTE_NODE)DeviceObject->DeviceExtension; // // Get a pointer to the next miniport. // NextDeviceObject = RemoteNode->NextDeviceObject; IrpSp = IoGetCurrentIrpStackLocation (Irp); switch(IrpSp->MinorFunction) { case IRP_MN_START_DEVICE: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, IRP_MN_START_DEVICE\n", RemoteNode)); IoCopyCurrentIrpStackLocationToNext(Irp); Status = ndisEnum1394PassIrpDownTheStack(Irp, NextDeviceObject); // // If the bus driver succeeded the start irp then proceed. // if (NT_SUCCESS(Status)) { Status = ndisEnum1394StartDevice(DeviceObject, Irp); } else { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394PnpDispatch: bus driver failed START IRP RemoteNode %lx\n", RemoteNode)); } RemoteNode->PnPDeviceState = PnPDeviceStarted; Irp->IoStatus.Status = Status; fSendIrpDown = FALSE; // we already did send the IRP down break; case IRP_MN_QUERY_REMOVE_DEVICE: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, IRP_MN_QUERY_REMOVE_DEVICE\n", RemoteNode)); RemoteNode->PnPDeviceState = PnPDeviceQueryRemoved; Irp->IoStatus.Status = STATUS_SUCCESS; // // if we failed query_remove, no point sending this irp down // fSendIrpDown = TRUE; break; case IRP_MN_CANCEL_REMOVE_DEVICE: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, IRP_MN_CANCEL_REMOVE_DEVICE\n", RemoteNode)); RemoteNode->PnPDeviceState = PnPDeviceStarted; Irp->IoStatus.Status = STATUS_SUCCESS; fSendIrpDown = TRUE; break; case IRP_MN_REMOVE_DEVICE: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, IRP_MN_REMOVE_DEVICE\n", RemoteNode)); ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); // // call notify handler // PnPDeviceState = RemoteNode->PnPDeviceState; if (PnPDeviceState != PnPDeviceSurpriseRemoved) { RemoteNode->PnPDeviceState = PnPDeviceRemoved; Status = ndisEnum1394RemoveDevice(DeviceObject, Irp, NdisEnum1394_RemoveDevice); Irp->IoStatus.Status = Status; } else { Irp->IoStatus.Status = STATUS_SUCCESS; } // // when we are done, send the Irp down here // we have some post-processing to do // IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(NextDeviceObject, Irp); IoDetachDevice(NextDeviceObject); IoDeleteDevice(DeviceObject); fSendIrpDown = FALSE; fCompleteIrp = FALSE; break; case IRP_MN_SURPRISE_REMOVAL: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, IRP_MN_SURPRISE_REMOVAL\n", RemoteNode)); ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); RemoteNode->PnPDeviceState = PnPDeviceSurpriseRemoved; Status = ndisEnum1394RemoveDevice(DeviceObject, Irp, NdisEnum1394_SurpriseRemoveDevice); Irp->IoStatus.Status = Status; // // when we are done, send the Irp down here // we have some post-processing to do // IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(NextDeviceObject, Irp); fSendIrpDown = FALSE; fCompleteIrp = FALSE; break; case IRP_MN_QUERY_STOP_DEVICE: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, IRP_MN_QUERY_STOP_DEVICE\n", RemoteNode)); RemoteNode->PnPDeviceState = PnPDeviceQueryStopped; Irp->IoStatus.Status = STATUS_SUCCESS; fSendIrpDown = TRUE; break; case IRP_MN_CANCEL_STOP_DEVICE: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, IRP_MN_CANCEL_STOP_DEVICE\n", RemoteNode)); RemoteNode->PnPDeviceState = PnPDeviceStarted; Irp->IoStatus.Status = STATUS_SUCCESS; fSendIrpDown = TRUE; break; case IRP_MN_STOP_DEVICE: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, IRP_MN_STOP_DEVICE\n", RemoteNode)); RemoteNode->PnPDeviceState = PnPDeviceStopped; Status = ndisEnum1394RemoveDevice(DeviceObject, Irp,NdisEnum1394_StopDevice); Irp->IoStatus.Status = Status; fSendIrpDown = TRUE; break; case IRP_MN_QUERY_CAPABILITIES: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode, IRP_MN_QUERY_CAPABILITIES\n", RemoteNode)); IoCopyCurrentIrpStackLocationToNext(Irp); Status = ndisEnum1394PassIrpDownTheStack(Irp, NextDeviceObject); #ifdef ENUM1394_NT // // Memphis does not support SurpriseRemovalOK bit // // If the bus driver succeeded the start irp then proceed. // if (NT_SUCCESS(Status)) { // // Modify the capabilities so that the device is not suprise removable. // IrpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = 1; } #endif // NDIS_NT fSendIrpDown = FALSE; break; case IRP_MN_QUERY_PNP_DEVICE_STATE: Irp->IoStatus.Status = Status; fSendIrpDown = TRUE ; break; case IRP_MN_QUERY_DEVICE_RELATIONS: case IRP_MN_QUERY_INTERFACE: case IRP_MN_QUERY_RESOURCES: case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: case IRP_MN_READ_CONFIG: case IRP_MN_WRITE_CONFIG: case IRP_MN_EJECT: case IRP_MN_SET_LOCK: case IRP_MN_QUERY_ID: default: DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394PnpDispatch: RemoteNode %lx, MinorFunction 0x%x\n", RemoteNode, IrpSp->MinorFunction)); // // We don't handle the irp so pass it down. // fSendIrpDown = TRUE; break; } // // First check to see if we need to send the irp down. // If we don't pass the irp on then check to see if we need to complete it. // if (fSendIrpDown) { IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(NextDeviceObject, Irp); } else if (fCompleteIrp) { Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394PnpDispatch: Status %lx, RemoteNode %lx\n", Status, RemoteNode)); return(Status); } NTSTATUS ndisEnum1394RemoveDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp, NDISENUM1394_PNP_OP PnpOp ) /*++ Routine Description: This function is called in the RemoveDevice and Stop Device code path. In the case of a Stop the function should undo whatever it received in the Start and it the case of a Remove it Should do undo the work done in AddDevice Arguments: DeviceObject - The adapter's functional device object. Irp - The IRP. Return Value: --*/ { PNDISENUM1394_REMOTE_NODE RemoteNode, *ppDB; PNDISENUM1394_LOCAL_HOST LocalHost; KIRQL OldIrql; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394RemoveDevice: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); ASSERT(KeGetCurrentIrql()==PASSIVE_LEVEL ); // // call 1394Nic about this device getting removed // if this is the last PDO on local host, get rid of // the PDO created for the local host // RemoteNode = (PNDISENUM1394_REMOTE_NODE)DeviceObject->DeviceExtension; LocalHost = RemoteNode->LocalHost; // // if the node has been indicated, let the nic1394 know // it is going away // if ((RemoveNodeHandler != NULL) && (ENUM_TEST_FLAGS(RemoteNode, NDISENUM1394_NODE_ADDED))) { RemoveNodeHandler(RemoteNode->Nic1394NodeContext); ENUM_CLEAR_FLAG(RemoteNode, NDISENUM1394_NODE_ADDED); } // // If this is a stop device then do NOT do any software specific cleanup work .. // leave it for the RemoveDevice // DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394RemoveDevice: - pRemoteNode %p LocalHost %p Op %x\n", RemoteNode, LocalHost, PnpOp)); if (PnpOp != NdisEnum1394_StopDevice && LocalHost != NULL) { // // find the device block and remove it from local host // ExAcquireSpinLock(&LocalHost->Lock, &OldIrql); for (ppDB = &LocalHost->RemoteNodeList; *ppDB != NULL; ppDB = &(*ppDB)->Next) { if (*ppDB == RemoteNode) { *ppDB = RemoteNode->Next; break; } } ExReleaseSpinLock(&LocalHost->Lock, OldIrql); ASSERT(*ppDB == RemoteNode->Next); // // Remove the Ref made in the Add Devive when calling GetLocalHost for Unique ID // { BOOLEAN bIsRefZero; RemoteNode->LocalHost = NULL; bIsRefZero = ndisEnum1394DereferenceLocalHost(LocalHost); if (bIsRefZero == TRUE) { ndisEnum1394FreeLocalHost(LocalHost); } } } ENUM_CLEAR_FLAG(RemoteNode, NDISENUM1394_NODE_PNP_STARTED); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394RemoveDevice: DeviceObject %lx, Irp %lx\n", DeviceObject, Irp)); return STATUS_SUCCESS; } /*+++ NTSTATUS ndisEnum1394BusRequest( PDEVICE_OBJECT DeviceObject, PIRB Irb ); Routine Description: this function issues a 1394 bus request to the device object. the device object could be the NextDeviceObject of the remote PDO or the virtual PDO 1394 bus ejected (net PDO) Arguments: DeviceObject: the target device object to send the request to Irb: the request block Return Value: as appropriate ---*/ NTSTATUS ndisEnum1394BusRequest( PDEVICE_OBJECT DeviceObject, PIRB Irb ) { NTSTATUS Status; PIRP Irp; PIO_STACK_LOCATION IrpSp; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394BusRequest: DeviceObject %lx, Irb %lx\n", DeviceObject, Irb)); do { Irp = IoAllocateIrp((CCHAR)(DeviceObject->StackSize + 1), FALSE); if (Irp == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394BusRequest: IoAllocateIrp failed. Status %lx\n", Status)); break; } IrpSp = IoGetNextIrpStackLocation(Irp); ASSERT(IrpSp != NULL); RtlZeroMemory(IrpSp, sizeof(IO_STACK_LOCATION )); IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; IrpSp->DeviceObject = DeviceObject; IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS; IrpSp->Parameters.Others.Argument1 = Irb; Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; Status = ndisEnum1394PassIrpDownTheStack(Irp, DeviceObject); if (Status != STATUS_SUCCESS) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394BusRequest: 1394 Bus driver failed the IRB. Status %lx\n", Status)); } }while (FALSE); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394BusRequest: DeviceObject %lx, Irb %lx\n", DeviceObject, Irb)); return Status; } BOOLEAN ndisEnum1394ReferenceLocalHost( IN PNDISENUM1394_LOCAL_HOST LocalHost ) { BOOLEAN rc; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394ReferenceLocalHost : LocalHost %p\n", LocalHost)); rc = ndisEnum1394ReferenceRef(&LocalHost->Reference); return rc; } BOOLEAN ndisEnum1394DereferenceLocalHost( IN PNDISENUM1394_LOCAL_HOST LocalHost ) { BOOLEAN rc; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("ndisEnum1394DereferenceLocalHost : LocalHost %p\n", LocalHost)); rc = ndisEnum1394DereferenceRef(&LocalHost->Reference); return rc; } VOID ndisEnum1394FreeLocalHost( IN PNDISENUM1394_LOCAL_HOST LocalHost ) { KIRQL OldIrql; PNDISENUM1394_LOCAL_HOST * ppLH; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394FreeLocalHost: LocalHost %p\n", LocalHost)); ASSERT(LocalHost->RemoteNodeList == NULL); ASSERT(LocalHost->Reference.ReferenceCount == 0); // // make sure we have not created a PDO for this local host // ASSERT(LocalHost->PhysicalDeviceObject == NULL); ExAcquireSpinLock(&ndisEnum1394GlobalLock, &OldIrql); for (ppLH = &LocalHostList; *ppLH != NULL; ppLH = &(*ppLH)->Next) { if (*ppLH == LocalHost) { *ppLH = LocalHost->Next; break; } } ExReleaseSpinLock(&ndisEnum1394GlobalLock, OldIrql); ASSERT(*ppLH == LocalHost->Next); FREE_POOL(LocalHost); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394FreeLocalHost: LocalHost %p\n", LocalHost)); } VOID ndisEnum1394InitializeRef( IN PREFERENCE RefP ) /*++ Routine Description: Initialize a reference count structure. Arguments: RefP - The structure to be initialized. Return Value: None. --*/ { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394InitializeRef\n")); RefP->Closing = FALSE; RefP->ReferenceCount = 1; KeInitializeSpinLock(&RefP->SpinLock); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394InitializeRef\n")); } BOOLEAN ndisEnum1394ReferenceRef( IN PREFERENCE RefP ) /*++ Routine Description: Adds a reference to an object. Arguments: RefP - A pointer to the REFERENCE portion of the object. Return Value: TRUE if the reference was added. FALSE if the object was closing. --*/ { BOOLEAN rc = TRUE; KIRQL OldIrql; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394ReferenceRef\n")); ExAcquireSpinLock(&RefP->SpinLock, &OldIrql); if (RefP->Closing) { rc = FALSE; } else { ++(RefP->ReferenceCount); } ExReleaseSpinLock(&RefP->SpinLock, OldIrql); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394ReferenceRef: RefCount %lx\n", RefP->ReferenceCount)); return(rc); } BOOLEAN ndisEnum1394DereferenceRef( IN PREFERENCE RefP ) /*++ Routine Description: Removes a reference to an object. Arguments: RefP - A pointer to the REFERENCE portion of the object. Return Value: TRUE if the reference count is now 0. FALSE otherwise. --*/ { BOOLEAN rc = FALSE; KIRQL OldIrql; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394DereferenceRef\n")); ExAcquireSpinLock(&RefP->SpinLock, &OldIrql); --(RefP->ReferenceCount); if (RefP->ReferenceCount == 0) { rc = TRUE; } ExReleaseSpinLock(&RefP->SpinLock, OldIrql); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394DereferenceRef: RefCount %lx\n", RefP->ReferenceCount)); return(rc); } BOOLEAN ndisEnum1394CloseRef( IN PREFERENCE RefP ) /*++ Routine Description: Closes a reference count structure. Arguments: RefP - The structure to be closed. Return Value: FALSE if it was already closing. TRUE otherwise. --*/ { KIRQL OldIrql; BOOLEAN rc = TRUE; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394CloseRef\n")); ExAcquireSpinLock(&RefP->SpinLock, &OldIrql); if (RefP->Closing) { rc = FALSE; } else RefP->Closing = TRUE; ExReleaseSpinLock(&RefP->SpinLock, OldIrql); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394CloseRef\n")); return(rc); } NTSTATUS NdisEnum1394RegisterDriver( IN PNIC1394_CHARACTERISTICS Characteristics ) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>NdisEnum1394RegisterDriver\n")); // // Todo: do some check for the version, etc. and make sure the handlers are // not null and this is not a dup registeration // AddNodeHandler = Characteristics->AddNodeHandler; RemoveNodeHandler = Characteristics->RemoveNodeHandler; RegisterDriverHandler = Characteristics->RegisterDriverHandler; DeRegisterDriverHandler = Characteristics->DeRegisterDriverHandler; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==NdisEnum1394RegisterDriver\n")); return STATUS_SUCCESS; } VOID NdisEnum1394DeregisterDriver( ) { DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>NdisEnum1394DeregisterDriver\n")); AddNodeHandler = NULL; RemoveNodeHandler = NULL; RegisterDriverHandler = NULL; DeRegisterDriverHandler = NULL; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==NdisEnum1394DeregisterDriver\n")); } /*+++ this routine will call the 1394 bus driver to create a virtual PDO on the local host with matching unique ID ---*/ NTSTATUS ndisEnum1394CreateVirtualPdo( IN PDEVICE_OBJECT PhysicalDeviceObject, IN LARGE_INTEGER UniqueId ) { PDEVICE_OBJECT BusDeviceObject = NULL; PIRP pirp; PIO_STACK_LOCATION pirpSpN; NTSTATUS Status; PIEEE1394_API_REQUEST pApiReq; PIEEE1394_VDEV_PNP_REQUEST pDevPnpReq; PSTR DeviceId = "NIC1394"; ULONG ulStrLen; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394CreateVirtualPdo\n")); do { pirp = IoAllocateIrp((CCHAR)(PhysicalDeviceObject->StackSize + 1),FALSE); if (NULL == pirp) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394CreateVirtualPdo failed to allcoate IRP\n")); Status = STATUS_INSUFFICIENT_RESOURCES; break; } ulStrLen = strlen(DeviceId) + sizeof(UCHAR); pApiReq = ALLOC_FROM_POOL(sizeof(IEEE1394_API_REQUEST) + ulStrLen, NDISENUM1394_TAG_1394API_REQ); if (pApiReq == NULL) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394CreateVirtualPdo failed to allcoate 1394 request\n")); Status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlZeroMemory(pApiReq, sizeof(IEEE1394_API_REQUEST) + ulStrLen); pApiReq->RequestNumber = IEEE1394_API_ADD_VIRTUAL_DEVICE; pApiReq->Flags = 0; pDevPnpReq = &pApiReq->u.AddVirtualDevice; pDevPnpReq->fulFlags = 0; pDevPnpReq->Reserved = 0; pDevPnpReq->InstanceId.LowPart = (ULONG)UniqueId.LowPart; pDevPnpReq->InstanceId.HighPart = (ULONG)UniqueId.HighPart; strncpy(&pDevPnpReq->DeviceId, DeviceId, ulStrLen); // // Get the stack pointer. // pirpSpN = IoGetNextIrpStackLocation(pirp); ASSERT(pirpSpN != NULL); RtlZeroMemory(pirpSpN, sizeof(IO_STACK_LOCATION ) ); // // Set the default device state to full on. // pirpSpN->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; pirpSpN->MinorFunction = 0; pirpSpN->Parameters.DeviceIoControl.IoControlCode = IOCTL_IEEE1394_API_REQUEST; pirpSpN->Parameters.DeviceIoControl.InputBufferLength = sizeof(IEEE1394_API_REQUEST) + ulStrLen; pirp->IoStatus.Status = STATUS_NOT_SUPPORTED; pirp->AssociatedIrp.SystemBuffer = pApiReq; Status = ndisEnum1394PassIrpDownTheStack(pirp, PhysicalDeviceObject); if (Status != STATUS_SUCCESS) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394CreateVirtualPdo IOCTL to create the virtual PDO failed with Status %lx\n", Status)); } IoFreeIrp(pirp); FREE_POOL(pApiReq); } while (FALSE); DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394CreateVirtualPdo: Status %lx\n", Status)); return Status; } // // this functions searchs through the list of local hosts trying to find one // with matching unique ID. if it does not, it will allocate a new one // VOID ndisEnum1394GetLocalHostForUniqueId( LARGE_INTEGER UniqueId, OUT PNDISENUM1394_LOCAL_HOST * pLocalHost ) { PNDISENUM1394_LOCAL_HOST TempLocalHost; PNDISENUM1394_LOCAL_HOST LocalHost; KIRQL OldIrql; BOOLEAN bFreeTempLocalHost = FALSE; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>ndisEnum1394GetLocalHostForUniqueId\n")); do { ExAcquireSpinLock(&ndisEnum1394GlobalLock, &OldIrql); for (LocalHost = LocalHostList; LocalHost != NULL; LocalHost = LocalHost->Next) { if (LocalHost->UniqueId.QuadPart == UniqueId.QuadPart) break; } ExReleaseSpinLock(&ndisEnum1394GlobalLock, OldIrql); if (LocalHost == NULL) { TempLocalHost = (PNDISENUM1394_LOCAL_HOST)ALLOC_FROM_POOL(sizeof(NDISENUM1394_LOCAL_HOST), NDISENUM1394_TAG_LOCAL_HOST); if (TempLocalHost == NULL) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("ndisEnum1394GetLocalHostForUniqueId: Failed to allocate memory LocalHost.\n")); break; } RtlZeroMemory(TempLocalHost, sizeof (NDISENUM1394_LOCAL_HOST)); ExAcquireSpinLock(&ndisEnum1394GlobalLock, &OldIrql); // // need to do the search again just in case between the time we release the // spinlock and now, we have added the local host // for (LocalHost = LocalHostList; LocalHost != NULL; LocalHost = LocalHost->Next) { if (LocalHost->UniqueId.QuadPart == UniqueId.QuadPart) break; } if (LocalHost == NULL) { LocalHost = TempLocalHost; LocalHost->Next = LocalHostList; LocalHostList = LocalHost; LocalHost->RemoteNodeList = NULL; LocalHost->UniqueId.QuadPart = UniqueId.QuadPart; KeInitializeSpinLock(&LocalHost->Lock); ndisEnum1394InitializeRef(&LocalHost->Reference); } else { bFreeTempLocalHost = TRUE; } ExReleaseSpinLock(&ndisEnum1394GlobalLock, OldIrql); if (bFreeTempLocalHost) FREE_POOL(TempLocalHost); } else { // // Give the caller a reference to our struct // ndisEnum1394ReferenceLocalHost(LocalHost); } } while (FALSE); *pLocalHost = LocalHost; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==ndisEnum1394GetLocalHostForUniqueId: LocalHost %lx\n", LocalHost)); return; } VOID Enum1394Callback( PVOID CallBackContext, PVOID Source, PVOID Characteristics ) { NTSTATUS Status; DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("==>Enum1394Callback: Source %lx, Characteristics %lx\n", Source, Characteristics)); // // if we are the one issuing this notification, just return // if (Source == NDIS1394_CALLBACK_SOURCE_ENUM1394) 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_NIC1394); RegisterDriverHandler = ((PNIC1394_CHARACTERISTICS)Characteristics)->RegisterDriverHandler; ASSERT(RegisterDriverHandler != NULL); if (RegisterDriverHandler == NULL) { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("Enum1394Callback: Callback called with invalid Characteristics. Characteristics %lx\n", Characteristics)); return; } Status = RegisterDriverHandler(&NdisEnum1394Characteristics); if (Status == STATUS_SUCCESS) { AddNodeHandler = ((PNIC1394_CHARACTERISTICS)Characteristics)->AddNodeHandler; RemoveNodeHandler = ((PNIC1394_CHARACTERISTICS)Characteristics)->RemoveNodeHandler; DeRegisterDriverHandler = ((PNIC1394_CHARACTERISTICS)Characteristics)->DeRegisterDriverHandler; } else { DBGPRINT(ENUM1394_DBGLEVEL_ERROR, ("Enum1394Callback: RegisterDriverHandler failed: Status %lx\n", Status)); RegisterDriverHandler = NULL; } DBGPRINT(ENUM1394_DBGLEVEL_INFO, ("<==Enum1394Callback: Source, %lx\n", Source)); }