NTSTATUS Serenum_IoCtl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: --*/ { PIO_STACK_LOCATION irpStack; NTSTATUS status; PCOMMON_DEVICE_DATA commonData; PFDO_DEVICE_DATA fdoData; HANDLE keyHandle; ULONG actualLength; status = STATUS_SUCCESS; irpStack = IoGetCurrentIrpStackLocation (Irp); ASSERT (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction); commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension; fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; status = IoAcquireRemoveLock(&commonData->RemoveLock, Irp); if (!NT_SUCCESS(status)){ Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } //buffer = Irp->AssociatedIrp.SystemBuffer; // // We only take Device Control requests for the FDO. // That is the bus itself. // // The request is one of the propriatary Ioctls for // // NB We ARE a filter driver, so we DO pass on the irp if we don't handle it // //inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength; //outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; if (!commonData->IsFDO) { // // These commands are only allowed to go to the FDO. Since they came // into the PDO, we need to fire them down to the serenum Fdo. // return Serenum_Generic_FireAndRelease_RemoveLock(((PPDO_DEVICE_DATA) DeviceObject->DeviceExtension)->ParentFdo,Irp); } switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_SERENUM_GET_PORT_NAME: // // Get the port name from the registry. // This IOCTL is used by the modem cpl. // status = IoOpenDeviceRegistryKey(fdoData->UnderlyingPDO, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); if (!NT_SUCCESS(status)) { // // This is a fatal error. If we can't get to our registry key, // we are sunk. // Serenum_KdPrint_Def (SER_DBG_PNP_ERROR, ("IoOpenDeviceRegistryKey failed - %x \n", status)); Irp->IoStatus.Information = 0; } else { status = Serenum_GetRegistryKeyValue( keyHandle, L"PortName", sizeof(L"PortName"), Irp->AssociatedIrp.SystemBuffer, irpStack->Parameters.DeviceIoControl.OutputBufferLength, &actualLength); if ( STATUS_OBJECT_NAME_NOT_FOUND == status || STATUS_INVALID_PARAMETER == status ) { status = Serenum_GetRegistryKeyValue( keyHandle, L"Identifier", sizeof(L"Identifier"), Irp->AssociatedIrp.SystemBuffer, irpStack->Parameters.DeviceIoControl.OutputBufferLength, &actualLength); } Irp->IoStatus.Information = actualLength; ZwClose (keyHandle); } break; default: // // This is not intended for us - fire and Protect! // return Serenum_DispatchPassThroughWithoutAcquire( DeviceObject, Irp); } IoReleaseRemoveLock(&commonData->RemoveLock, Irp); Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }
NTSTATUS Serenum_AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT BusPhysicalDeviceObject) /*++ Routine Description. A bus has been found. Attach our FDO to it. Allocate any required resources. Set things up. And be prepared for the first ``start device.'' Arguments: BusPhysicalDeviceObject - Device object representing the bus. That to which we attach a new FDO. DriverObject - This very self referenced driver. --*/ { NTSTATUS status; PDEVICE_OBJECT deviceObject; PFDO_DEVICE_DATA pDeviceData; HANDLE keyHandle; ULONG actualLength; PAGED_CODE(); Serenum_KdPrint_Def(SER_DBG_PNP_TRACE, ("Add Device: 0x%x\n", BusPhysicalDeviceObject)); // // Create our FDO // status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_DATA), NULL, FILE_DEVICE_BUS_EXTENDER, 0, TRUE, &deviceObject); if (NT_SUCCESS(status)) { pDeviceData = (PFDO_DEVICE_DATA)deviceObject->DeviceExtension; RtlFillMemory (pDeviceData, sizeof (FDO_DEVICE_DATA), 0); pDeviceData->IsFDO = TRUE; pDeviceData->DebugLevel = SER_DEFAULT_DEBUG_OUTPUT_LEVEL; pDeviceData->Self = deviceObject; pDeviceData->AttachedPDO = NULL; pDeviceData->NumPDOs = 0; pDeviceData->DeviceState = PowerDeviceD0; pDeviceData->SystemState = PowerSystemWorking; pDeviceData->PDOForcedRemove = FALSE; pDeviceData->SystemWake=PowerSystemUnspecified; pDeviceData->DeviceWake=PowerDeviceUnspecified; pDeviceData->Removed = FALSE; // // Set the PDO for use with PlugPlay functions // pDeviceData->UnderlyingPDO = BusPhysicalDeviceObject; // // Attach our filter driver to the device stack. // the return value of IoAttachDeviceToDeviceStack is the top of the // attachment chain. This is where all the IRPs should be routed. // // Our filter will send IRPs to the top of the stack and use the PDO // for all PlugPlay functions. // pDeviceData->TopOfStack = IoAttachDeviceToDeviceStack(deviceObject, BusPhysicalDeviceObject); if (!pDeviceData->TopOfStack) { Serenum_KdPrint(pDeviceData, SER_DBG_PNP_ERROR, ("AddDevice: IoAttach failed (%x)", status)); IoDeleteDevice(deviceObject); return STATUS_UNSUCCESSFUL; } // // Set the type of IO we do // if (pDeviceData->TopOfStack->Flags & DO_BUFFERED_IO) { deviceObject->Flags |= DO_BUFFERED_IO; } else if (pDeviceData->TopOfStack->Flags & DO_DIRECT_IO) { deviceObject->Flags |= DO_DIRECT_IO; } // // Bias outstanding request to 1 so that we can look for a // transition to zero when processing the remove device PlugPlay IRP. // pDeviceData->OutstandingIO = 1; KeInitializeEvent(&pDeviceData->RemoveEvent, SynchronizationEvent, FALSE); KeInitializeSemaphore(&pDeviceData->CreateSemaphore, 1, 1); KeInitializeSpinLock(&pDeviceData->EnumerationLock); // // Tell the PlugPlay system that this device will need an interface // device class shingle. // // It may be that the driver cannot hang the shingle until it starts // the device itself, so that it can query some of its properties. // (Aka the shingles guid (or ref string) is based on the properties // of the device.) // status = IoRegisterDeviceInterface(BusPhysicalDeviceObject, (LPGUID)&GUID_SERENUM_BUS_ENUMERATOR, NULL, &pDeviceData->DevClassAssocName); if (!NT_SUCCESS(status)) { Serenum_KdPrint(pDeviceData, SER_DBG_PNP_ERROR, ("AddDevice: IoRegisterDCA failed (%x)", status)); IoDetachDevice(pDeviceData->TopOfStack); IoDeleteDevice(deviceObject); return status; } // // If for any reason you need to save values in a safe location that // clients of this DeviceClassAssociate might be interested in reading // here is the time to do so, with the function // IoOpenDeviceClassRegistryKey // the symbolic link name used is was returned in // pDeviceData->DevClassAssocName (the same name which is returned by // IoGetDeviceClassAssociations and the SetupAPI equivs. // #if DBG { PWCHAR deviceName = NULL; ULONG nameLength = 0; status = IoGetDeviceProperty(BusPhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &nameLength); if ((nameLength != 0) && (status == STATUS_BUFFER_TOO_SMALL)) { deviceName = ExAllocatePool(NonPagedPool, nameLength); if (NULL == deviceName) { goto someDebugStuffExit; } IoGetDeviceProperty(BusPhysicalDeviceObject, DevicePropertyPhysicalDeviceObjectName, nameLength, deviceName, &nameLength); Serenum_KdPrint(pDeviceData, SER_DBG_PNP_TRACE, ("AddDevice: %x to %x->%x (%ws) \n", deviceObject, pDeviceData->TopOfStack, BusPhysicalDeviceObject, deviceName)); } someDebugStuffExit: ; if (deviceName != NULL) { ExFreePool(deviceName); } } #endif // DBG // // Turn on the shingle and point it to the given device object. // status = IoSetDeviceInterfaceState(&pDeviceData->DevClassAssocName, TRUE); if (!NT_SUCCESS(status)) { Serenum_KdPrint(pDeviceData, SER_DBG_PNP_ERROR, ("AddDevice: IoSetDeviceClass failed (%x)", status)); return status; } // // Open the registry and read in our settings // status = IoOpenDeviceRegistryKey(pDeviceData->UnderlyingPDO, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); if (status == STATUS_SUCCESS) { status = Serenum_GetRegistryKeyValue(keyHandle, L"SkipEnumerations", sizeof(L"SkipEnumerations"), &pDeviceData->SkipEnumerations, sizeof(pDeviceData->SkipEnumerations), &actualLength); if ((status != STATUS_SUCCESS) || (actualLength != sizeof(pDeviceData->SkipEnumerations))) { pDeviceData->SkipEnumerations = 0; status = STATUS_SUCCESS; } ZwClose(keyHandle); } } if (NT_SUCCESS(status)) { deviceObject->Flags |= DO_POWER_PAGABLE; deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; } return status; }