// // Plug in a NDAS device with a LUR descriptor. // NTSTATUS LSBus_AddTarget( PFDO_DEVICE_DATA FdoData, PNDASBUS_ADD_TARGET_DATA AddTargetData ) { PPDO_DEVICE_DATA pdoData; NTSTATUS status; status = STATUS_SUCCESS; // // Verify LurDesc // TODO: // // Find Pdo Data... pdoData = LookupPdoData(FdoData, AddTargetData->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (FdoData, BUS_DBG_IOCTL_ERROR, ("no pdo for Slot %u\n", AddTargetData->ulSlotNo)); return STATUS_NOT_FOUND; } // // Copy AddDevInfo into the PDO. // if(pdoData->LanscsiAdapterPDO.AddDevInfo) { Bus_KdPrint_Cont (FdoData, BUS_DBG_IOCTL_ERROR, ("AddDevInfo already set.\n")); status = STATUS_DEVICE_ALREADY_ATTACHED; goto cleanup; } pdoData->LanscsiAdapterPDO.AddDevInfo = ExAllocatePoolWithTag(NonPagedPool, AddTargetData->ulSize, BUSENUM_POOL_TAG); if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } RtlCopyMemory(pdoData->LanscsiAdapterPDO.AddDevInfo, AddTargetData, AddTargetData->ulSize); pdoData->LanscsiAdapterPDO.AddDevInfoLength = AddTargetData->ulSize; // // Init PDO status // pdoData->LanscsiAdapterPDO.LastAdapterStatus = NDASSCSI_ADAPTERINFO_STATUS_INIT; pdoData->LanscsiAdapterPDO.DeviceMode = AddTargetData->DeviceMode; InitializeListHead(&pdoData->LanscsiAdapterPDO.NdasPdoEventQueue); // // Notify to NDASCSI // Bus_KdPrint(FdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET SetEvent AddTargetEvent!\n")); KeSetEvent(&pdoData->LanscsiAdapterPDO.AddTargetEvent, IO_NO_INCREMENT, FALSE); cleanup: ObDereferenceObject(pdoData->Self); return status; }
// // Plug in a NDAS device with a LUR descriptor. // NTSTATUS LSBus_AddTargetWithLurDesc( PFDO_DEVICE_DATA FdoData, PLURELATION_DESC LurDesc, ULONG SlotNo ) { PPDO_DEVICE_DATA pdoData; NTSTATUS status; status = STATUS_SUCCESS; // // Verify LurDesc // TODO: // // Find Pdo Data... pdoData = LookupPdoData(FdoData, SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (FdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); return STATUS_NOT_FOUND; } // // Copy AddDevInfo into the PDO. // if(pdoData->LanscsiAdapterPDO.AddDevInfo) { Bus_KdPrint_Cont (FdoData, BUS_DBG_IOCTL_ERROR, ("AddDevInfo already set.\n")); status = STATUS_DEVICE_ALREADY_ATTACHED; goto cleanup; } pdoData->LanscsiAdapterPDO.AddDevInfo = ExAllocatePool(NonPagedPool, LurDesc->Length); if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } else { RtlCopyMemory(pdoData->LanscsiAdapterPDO.AddDevInfo, LurDesc, LurDesc->Length); status = STATUS_SUCCESS; } pdoData->LanscsiAdapterPDO.AddDevInfoLength = LurDesc->Length; pdoData->LanscsiAdapterPDO.Flags |= LSDEVDATA_FLAG_LURDESC; // // Notify to LanscsiMiniport // Bus_KdPrint(FdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET SetEvent AddTargetEvent!\n")); KeSetEvent(&pdoData->LanscsiAdapterPDO.AddTargetEvent, IO_NO_INCREMENT, FALSE); cleanup: ObDereferenceObject(pdoData->Self); return status; }
// // Plug in a NDAS device with a LUR descriptor. // NTSTATUS LSBus_AddTarget( PFDO_DEVICE_DATA FdoData, PLANSCSI_ADD_TARGET_DATA AddTargetData ) { PPDO_DEVICE_DATA pdoData; NTSTATUS status; status = STATUS_SUCCESS; // // Verify LurDesc // TODO: // // Find Pdo Data... pdoData = LookupPdoData(FdoData, AddTargetData->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (FdoData, BUS_DBG_IOCTL_ERROR, ("no pdo for Slot %u\n", AddTargetData->ulSlotNo)); return STATUS_NOT_FOUND; } // // Copy AddDevInfo into the PDO. // if(pdoData->LanscsiAdapterPDO.AddDevInfo) { Bus_KdPrint_Cont (FdoData, BUS_DBG_IOCTL_ERROR, ("AddDevInfo already set.\n")); status = STATUS_DEVICE_ALREADY_ATTACHED; goto cleanup; } pdoData->LanscsiAdapterPDO.AddDevInfo = ExAllocatePool(NonPagedPool, AddTargetData->ulSize); if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } RtlCopyMemory(pdoData->LanscsiAdapterPDO.AddDevInfo, AddTargetData, AddTargetData->ulSize); pdoData->LanscsiAdapterPDO.AddDevInfoLength = AddTargetData->ulSize; // // Notify to LanscsiMiniport // Bus_KdPrint(FdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET SetEvent AddTargetEvent!\n")); KeSetEvent(&pdoData->LanscsiAdapterPDO.AddTargetEvent, IO_NO_INCREMENT, FALSE); cleanup: ObDereferenceObject(pdoData->Self); return status; }
NTSTATUS Bus_DestroyPdo ( PDEVICE_OBJECT Device, PPDO_DEVICE_DATA PdoData ) /*++ Routine Description: The Plug & Play subsystem has instructed that this PDO should be removed. We should therefore - Complete any requests queued in the driver - If the device is still attached to the system, - then complete the request and return. - Otherwise, cleanup device specific allocations, memory, events... - Call IoDeleteDevice - Return from the dispatch routine. Note that if the device is still connected to the bus (IE in this case the enum application has not yet told us that the toaster device has disappeared) then the PDO must remain around, and must be returned during any query Device relations IRPS. --*/ { PAGED_CODE (); // // BusEnum does not queue any irps at this time so we have nothing to do. // // // Free any resources. // if (PdoData->HardwareIDs) { ExFreePool (PdoData->HardwareIDs); PdoData->HardwareIDs = NULL; } if (PdoData->compatible_ids) { ExFreePool (PdoData->compatible_ids); PdoData->compatible_ids = NULL; } //FIXME if (PdoData->fo){ PdoData->fo->FsContext = NULL; PdoData->fo = NULL; } Bus_KdPrint_Cont(PdoData, BUS_DBG_PNP_INFO, ("\tDeleting PDO: 0x%p\n", Device)); IoDeleteDevice (Device); return STATUS_SUCCESS; }
NTSTATUS Bus_IoCtl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Handle user mode PlugIn, UnPlug and device Eject requests. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PIO_STACK_LOCATION irpStack; NTSTATUS status; ULONG inlen, outlen; PFDO_DEVICE_DATA fdoData; PVOID buffer; PAGED_CODE (); // // It is not safe to call IOCTL in raised IRQL. // ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; // // We only take Device Control requests for the FDO. // That is the bus itself. // if (!fdoData->IsFDO) { // // These commands are only allowed to go to the FDO. // status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } // // Check to see whether the bus is removed // if (fdoData->DevicePnPState == Deleted) { Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } Bus_IncIoCount (fdoData); irpStack = IoGetCurrentIrpStackLocation (Irp); buffer = Irp->AssociatedIrp.SystemBuffer; inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength; outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; status = STATUS_INVALID_PARAMETER; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("%d called\n", irpStack->Parameters.DeviceIoControl.IoControlCode)); switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_NDASBUS_ADD_TARGET: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA))); if ((inlen == outlen) && (sizeof(NDASBUS_ADD_TARGET_DATA) <= inlen)) { ULONG ulSize; PNDASBUS_ADD_TARGET_DATA addTargetData = buffer; BOOLEAN accepted; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_ADD_TARGET called\n")); Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET Target Type %d\n", addTargetData->ucTargetType)); status = STATUS_SUCCESS; // // Check structure size // if(VerifySizeOfAddTargetData(addTargetData, &ulSize) == 0) { status = STATUS_INVALID_PARAMETER; break; } if(ulSize != inlen) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Size mismatch. Req %d, in %d\n", ulSize, inlen)); status = STATUS_UNSUCCESSFUL; break; } // // Check to see if acceptable structure. // accepted = TRUE; switch(addTargetData->ucTargetType) { case NDASSCSI_TYPE_DISK_NORMAL: case NDASSCSI_TYPE_DVD: case NDASSCSI_TYPE_VDVD: case NDASSCSI_TYPE_MO: if(addTargetData->ulNumberOfUnitDiskList != 1) accepted = FALSE; break; case NDASSCSI_TYPE_DISK_MIRROR: if(2 != addTargetData->ulNumberOfUnitDiskList) accepted = FALSE; break; case NDASSCSI_TYPE_DISK_AGGREGATION: if (addTargetData->ulNumberOfUnitDiskList < 2 || addTargetData->ulNumberOfUnitDiskList > MAX_NR_UNITDISK_FOR_AGGR) accepted = FALSE; break; case NDASSCSI_TYPE_DISK_RAID0: switch(addTargetData->ulNumberOfUnitDiskList) { case 2: case 4: case 8: break; default: // do not accept accepted = FALSE; break; } break; case NDASSCSI_TYPE_DISK_RAID1R3: { ULONG ulDiskCount; ulDiskCount = addTargetData->ulNumberOfUnitDiskList - addTargetData->RAID_Info.nSpareDisk; if (2 != ulDiskCount) accepted = FALSE; } break; case NDASSCSI_TYPE_DISK_RAID4R3: { ULONG ulDiskCount; ulDiskCount = addTargetData->ulNumberOfUnitDiskList - addTargetData->RAID_Info.nSpareDisk; switch(ulDiskCount) { case 3: // 2 + 1 case 5: // 4 + 1 case 9: // 8 + 1 break; default: // do not accept accepted = FALSE; break; } break; } default: Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Bad Disk Type.\n")); accepted = FALSE; break; } if(accepted == FALSE) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: Invaild type.\n")); status = STATUS_UNSUCCESSFUL; break; } #if DBG NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_TRY_TO_ADDTARGET, IOCTL_NDASBUS_ADD_TARGET, addTargetData->ulSlotNo); #endif // Find Pdo Data... pdoData = LookupPdoData(fdoData, addTargetData->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_ADD_TARGET, addTargetData->ulSlotNo); break; } // // Save the add target information to the PDO extension // pdoData->LanscsiAdapterPDO.AddDevInfo = ExAllocatePoolWithTag(NonPagedPool, inlen, BUSENUM_POOL_TAG); if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { Irp->IoStatus.Information = 0; status = STATUS_INSUFFICIENT_RESOURCES; break; } else { RtlCopyMemory(pdoData->LanscsiAdapterPDO.AddDevInfo, addTargetData, inlen); status = STATUS_SUCCESS; } pdoData->LanscsiAdapterPDO.AddDevInfoLength = inlen; // // Init PDO status // pdoData->LanscsiAdapterPDO.LastAdapterStatus = NDASSCSI_ADAPTERINFO_STATUS_INIT; pdoData->LanscsiAdapterPDO.DeviceMode = addTargetData->DeviceMode; // // Notify to NDASSCSI // Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET SetEvent AddTargetEvent!\n")); KeSetEvent(&pdoData->LanscsiAdapterPDO.AddTargetEvent, IO_NO_INCREMENT, FALSE); // // Register Target // if(pdoData->Persistent) { status = LSBus_RegisterTarget(fdoData, addTargetData); if(!NT_SUCCESS(status)) { ExFreePoolWithTag(pdoData->LanscsiAdapterPDO.AddDevInfo, BUSENUM_POOL_TAG); pdoData->LanscsiAdapterPDO.AddDevInfo = NULL; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("ADD_TARGET: LSBus_RegisterTarget() failed. STATUS=%08lx\n", status)); status = STATUS_INTERNAL_DB_ERROR; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_REGISTER_TARGET_FAIL, IOCTL_NDASBUS_ADD_TARGET, addTargetData->ulSlotNo); } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, ("ADD_TARGET: Successfully registered.\n")); } } ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_ADD_TARGET length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA))); } } break; case IOCTL_NDASBUS_REMOVE_TARGET: { PPDO_DEVICE_DATA pdoData; PNDASBUS_REMOVE_TARGET_DATA removeTarget; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_REMOVE_TARGET called\n")); if (sizeof (NDASBUS_REMOVE_TARGET_DATA) != inlen) break; removeTarget = (PNDASBUS_REMOVE_TARGET_DATA)buffer; pdoData = LookupPdoData(fdoData, removeTarget->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_REMOVE_TARGET, removeTarget->ulSlotNo); break; } // // redirect to the NDAS SCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, NDASSCSI_IOCTL_REMOVE_TARGET, buffer, sizeof(NDASBUS_REMOVE_TARGET_DATA), NULL, 0 ); if(NT_SUCCESS(status) && pdoData->Persistent) { status = LSBus_UnregisterTarget(fdoData, removeTarget->ulSlotNo, removeTarget->ulTargetId); if(!NT_SUCCESS(status)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, ( "REMOVE_TARGET: Removed Target instance," " but LSBus_UnregisterTarget() failed.\n")); status = STATUS_INTERNAL_DB_ERROR; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_UNREGISTER_TARGET_FAIL, IOCTL_NDASBUS_REMOVE_TARGET, removeTarget->ulSlotNo); } #if DBG else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_INFO, ("REMOVE_TARGET: LSBus_UnregisterTarget() succeeded.\n")); } #endif } ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = 0; break; } case IOCTL_NDASBUS_STARTSTOP_REGISTRARENUM:{ PULONG onOff = (PULONG)buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "STARTSTOP_REGISTRARENUM: inlen %d, outlen %d OnOff %u\n", inlen, outlen, *onOff)); KeEnterCriticalRegion(); ExAcquireFastMutexUnsafe(&fdoData->RegMutex); if(*onOff != 0) { // // Save old state. // Activate the registrar's enumeration // *onOff = fdoData->StartStopRegistrarEnum; fdoData->StartStopRegistrarEnum = TRUE; } else { // // Save old state. // Deactivate the registrar's enumeration // *onOff = fdoData->StartStopRegistrarEnum; fdoData->StartStopRegistrarEnum = FALSE; } // // Clean up non-enumerated entries. // LSBus_CleanupNDASDeviceRegistryUnsafe(fdoData); ExReleaseFastMutexUnsafe(&fdoData->RegMutex); KeLeaveCriticalRegion(); Irp->IoStatus.Information = sizeof(ULONG); status = STATUS_SUCCESS; break; } case IOCTL_NDASBUS_REGISTER_DEVICE: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "REGISTER_DEVICE: inlen %d, outlen %d," " sizeof(NDASBUS_PLUGIN_HARDWARE_EX2) %d\n", inlen, outlen, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2))); if ((inlen == outlen)) { PNDASBUS_PLUGIN_HARDWARE_EX2 PlugIn = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("REGISTER_DEVICE: entered\n")); status = LSBus_RegisterDevice(fdoData, PlugIn); Irp->IoStatus.Information = 0; } else Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("REGISTER_DEVICE: length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2) %d\n", inlen, outlen, sizeof(NDASBUS_PLUGIN_HARDWARE_EX2))); } break; case IOCTL_NDASBUS_REGISTER_TARGET: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "REGISTER_TARGET: inlen %d, outlen %d," " sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA))); if ((inlen == outlen)) { PNDASBUS_ADD_TARGET_DATA AddTargetData = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("REGISTER_TARGET: entered\n")); status = LSBus_RegisterTarget(fdoData, AddTargetData); Irp->IoStatus.Information = 0; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "REGISTER_TARGET: length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_ADD_TARGET_DATA))); } } break; case IOCTL_NDASBUS_UNREGISTER_DEVICE: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "UNREGISTER_DEVICE: inlen %d, outlen %d," " sizeof(NDASBUS_UNREGISTER_NDASDEV) %d\n", inlen, outlen, sizeof(NDASBUS_UNREGISTER_NDASDEV))); if ((inlen == outlen)) { PNDASBUS_UNREGISTER_NDASDEV UnregDev = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UNREGISTER_DEVICE: entered\n")); status = LSBus_UnregisterDevice(fdoData, UnregDev->SlotNo); Irp->IoStatus.Information = 0; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "UNREGISTER_DEVICE: length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(NDASBUS_UNREGISTER_NDASDEV))); } } break; case IOCTL_NDASBUS_UNREGISTER_TARGET: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "UNREGISTER_TARGET: inlen %d, outlen %d," " sizeof(NDASBUS_UNREGISTER_TARGET) %d\n", inlen, outlen, sizeof(NDASBUS_UNREGISTER_TARGET))); if ((inlen == outlen)) { PNDASBUS_UNREGISTER_TARGET UnregTarget = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UNREGISTER_TARGET: entered\n")); status = LSBus_UnregisterTarget(fdoData, UnregTarget->SlotNo, UnregTarget->TargetId); Irp->IoStatus.Information = 0; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ( "UNREGISTER_TARGET: length mismatch!!!" " inlen %d, outlen %d, sizeof(NDASBUS_UNREGISTER_TARGET) %d\n", inlen, outlen, sizeof(NDASBUS_UNREGISTER_TARGET))); } } break; case IOCTL_NDASBUS_SETPDOINFO: { PPDO_DEVICE_DATA pdoData; PNDASBUS_SETPDOINFO SetPdoInfo; KIRQL oldIrql; PVOID sectionHandle; BOOLEAN acceptStatus; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_SETPDOINFO called\n")); if (sizeof (NDASBUS_SETPDOINFO) != inlen) break; acceptStatus = TRUE; SetPdoInfo = (PNDASBUS_SETPDOINFO)buffer; pdoData = LookupPdoData(fdoData, SetPdoInfo->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_SETPDOINFO, SetPdoInfo->SlotNo); break; } // // lock the code section of this function to acquire spinlock in raised IRQL. // sectionHandle = MmLockPagableCodeSection(Bus_IoCtl); KeAcquireSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, &oldIrql); Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("!!!!!!!!!!!!!!!!!! SETPDOINFO: PDO %p: %08lx %08lx %08lx\n", pdoData->Self, SetPdoInfo->AdapterStatus, SetPdoInfo->SupportedFeatures, SetPdoInfo->EnabledFeatures)); // // Deny the status change if the current status is STATUS_STOPPED except for RESETSTATUS flag. // if(ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.LastAdapterStatus, NDASSCSI_ADAPTERINFO_STATUS_STOPPED)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: 'An event occured after 'Stopped' event\n")); if(ADAPTERINFO_ISSTATUSFLAG(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTERINFO_STATUSFLAG_RESETSTATUS)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Reset-status event accepted.\n")); } else { acceptStatus = FALSE; } } else { if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { acceptStatus = FALSE; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("!!!!!!!!!!!!!!!!!! SETPDOINFO: AddTarget is not occured. Too early to set status.\n")); } } // // Mask off RESETSTATUS. // NDAS service does not need to know it. // SetPdoInfo->AdapterStatus &= ~NDASSCSI_ADAPTERINFO_STATUSFLAG_RESETSTATUS; // // Set status values to the corresponding physical device object. // Save to the extension // if(acceptStatus) { PNDASBUS_PDOEVENT_ENTRY pdoEventEntry; pdoEventEntry = NdasBusCreatePdoStatusItem(SetPdoInfo->AdapterStatus); if(pdoEventEntry) { NdasBusQueuePdoStatusItem(&pdoData->LanscsiAdapterPDO, pdoEventEntry); } #if DBG else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Could not allocate PDO status entry.\n")); } #endif pdoData->LanscsiAdapterPDO.LastAdapterStatus = SetPdoInfo->AdapterStatus; pdoData->LanscsiAdapterPDO.SupportedFeatures = SetPdoInfo->SupportedFeatures; pdoData->LanscsiAdapterPDO.EnabledFeatures = SetPdoInfo->EnabledFeatures; // // Queue plugout worker if the NDAS SCSI stop abnormally. // Notify the NDAS service of abnormal termination // if(ADAPTERINFO_ISSTATUS(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTERINFO_STATUS_STOPPED) && ADAPTERINFO_ISSTATUSFLAG(SetPdoInfo->AdapterStatus, NDASSCSI_ADAPTERINFO_STATUSFLAG_ABNORMAL_TERMINAT)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: Queueing Unplug worker!!!!!!!!\n")); status = QueueUnplugWorker(fdoData, SetPdoInfo->SlotNo); // // Set disconnection event // KeSetEvent(pdoData->LanscsiAdapterPDO.DisconEventToService, IO_DISK_INCREMENT, FALSE); } else { // // Notify the adapter status change // KeSetEvent(pdoData->LanscsiAdapterPDO.AlarmEventToService, IO_DISK_INCREMENT, FALSE); } } KeReleaseSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, oldIrql); // // Release the code section. // MmUnlockPagableImageSection(sectionHandle); status = STATUS_SUCCESS; ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; } break; case IOCTL_NDASBUS_QUERY_NODE_ALIVE: { PPDO_DEVICE_DATA pdoData; BOOLEAN bAlive; PNDASBUS_NODE_ALIVE_IN pNodeAliveIn; NDASBUS_NODE_ALIVE_OUT nodeAliveOut; // Check Parameter. if(inlen != sizeof(NDASBUS_NODE_ALIVE_IN) || outlen != sizeof(NDASBUS_NODE_ALIVE_OUT)) { status = STATUS_UNKNOWN_REVISION; break; } pNodeAliveIn = (PNDASBUS_NODE_ALIVE_IN)Irp->AssociatedIrp.SystemBuffer; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_NOISE, ("FDO: IOCTL_NDASBUS_QUERY_NODE_ALIVE SlotNumber = %d\n", pNodeAliveIn->SlotNo)); pdoData = LookupPdoData(fdoData, pNodeAliveIn->SlotNo); if(pdoData == NULL) { // Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE, // ("[LanScsiBus]Bus_IoCtl: IOCTL_NDASBUS_QUERY_NODE_ALIVE No pdo\n")); bAlive = FALSE; } else { bAlive = TRUE; } // For Result... nodeAliveOut.SlotNo = pNodeAliveIn->SlotNo; nodeAliveOut.bAlive = bAlive; // Get Adapter Status. if(bAlive == TRUE) { if( ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.LastAdapterStatus, NDASSCSI_ADAPTERINFO_STATUS_STOPPING)) { nodeAliveOut.bHasError = TRUE; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_QUERY_NODE_ALIVE Adapter has Error 0x%x\n", nodeAliveOut.bHasError)); } else { nodeAliveOut.bHasError = FALSE; } } if(pdoData) ObDereferenceObject(pdoData->Self); RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, &nodeAliveOut, sizeof(NDASBUS_NODE_ALIVE_OUT) ); Irp->IoStatus.Information = sizeof(NDASBUS_NODE_ALIVE_OUT); status = STATUS_SUCCESS; } break; // // added by hootch 01172004 // case IOCTL_NDASBUS_UPGRADETOWRITE: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_UPGRADETOWRITE called\n")); // Check Parameter. if(inlen != sizeof(NDASBUS_UPGRADE_TO_WRITE)) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_UPGRADETOWRITE: Invalid input buffer length\n")); status = STATUS_UNKNOWN_REVISION; break; } pdoData = LookupPdoData(fdoData, ((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_UPGRADETOWRITE: No pdo for Slotno:%d\n", ((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo)); status = STATUS_NO_SUCH_DEVICE; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_UPGRADETOWRITE, ((PNDASBUS_UPGRADE_TO_WRITE)buffer)->SlotNo); } else { // // redirect to the NDASSCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, NDASSCSI_IOCTL_UPGRADETOWRITE, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = 0; } break; case IOCTL_NDASBUS_REDIRECT_NDASSCSI: { PPDO_DEVICE_DATA pdoData; PNDASBUS_REDIRECT_NDASSCSI redirectIoctl; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_REDIRECT_NDASSCSI called\n")); // Check Parameter. if(inlen < sizeof(NDASBUS_REDIRECT_NDASSCSI)) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_REDIRECT_NDASSCSI: Invalid input buffer length\n")); status = STATUS_UNKNOWN_REVISION; break; } redirectIoctl = (PNDASBUS_REDIRECT_NDASSCSI)buffer; pdoData = LookupPdoData(fdoData, redirectIoctl->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_REDIRECT_NDASSCSI: No pdo for Slotno:%d\n", redirectIoctl->SlotNo)); status = STATUS_NO_SUCH_DEVICE; } else { // // redirect to the NDASSCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, redirectIoctl->IoctlCode, redirectIoctl->IoctlData, redirectIoctl->IoctlDataSize, redirectIoctl->IoctlData, redirectIoctl->IoctlDataSize ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = 0; } break; case IOCTL_NDASBUS_QUERY_NDASSCSIINFO: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_QUERY_NDASSCSIINFO called\n")); // Check Parameter. if(inlen < FIELD_OFFSET(NDASSCSI_QUERY_INFO_DATA, QueryData) ) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_QUERY_NDASSCSIINFO: Invalid input buffer length too small.\n")); status = STATUS_UNKNOWN_REVISION; break; } pdoData = LookupPdoData(fdoData, ((PNDASSCSI_QUERY_INFO_DATA)buffer)->NdasScsiAddress.SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_QUERY_NDASSCSIINFO No pdo\n")); status = STATUS_NO_SUCH_DEVICE; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_QUERY_NDASSCSIINFO, ((PNDASSCSI_QUERY_INFO_DATA)buffer)->NdasScsiAddress.SlotNo); } else { // // redirect to the NDASSCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, NDASSCSI_IOCTL_QUERYINFO_EX, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = outlen; } break; case IOCTL_NDASBUS_QUERY_INFORMATION: { // PPDO_DEVICE_DATA pdoData; NDASBUS_QUERY_INFORMATION Query; PNDASBUS_INFORMATION Information; LONG BufferLenNeeded; // Check Parameter. if( inlen < sizeof(NDASBUS_QUERY_INFORMATION) /*|| outlen < sizeof(NDASBUS_INFORMATION) */) { status = STATUS_UNKNOWN_REVISION; break; } RtlCopyMemory(&Query, buffer, sizeof(NDASBUS_QUERY_INFORMATION)); Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE, ("FDO: IOCTL_NDASBUS_QUERY_INFORMATION QueryType : %d SlotNumber = %d\n", Query.InfoClass, Query.SlotNo)); Information = (PNDASBUS_INFORMATION)buffer; ASSERT(Information); Information->InfoClass = Query.InfoClass; status = LSBus_QueryInformation(fdoData, IoIs32bitProcess(Irp), &Query, Information, outlen, &BufferLenNeeded); if(NT_SUCCESS(status)) { Information->Size = BufferLenNeeded; Irp->IoStatus.Information = BufferLenNeeded; } else { Irp->IoStatus.Information = BufferLenNeeded; } } break; case IOCTL_NDASBUS_PLUGIN_HARDWARE_EX2: { ULONG structLen; // Without variable length field ULONG wholeStructLen; // With variable length field ULONG inputWholeStructLen; // // Check 32 bit thunking request // if(IoIs32bitProcess(Irp)) { structLen = FIELD_OFFSET(NDASBUS_PLUGIN_HARDWARE_EX2_32, HardwareIDs); wholeStructLen = sizeof(NDASBUS_PLUGIN_HARDWARE_EX2_32); inputWholeStructLen = ((PNDASBUS_PLUGIN_HARDWARE_EX2_32) buffer)->Size; } else { structLen = FIELD_OFFSET(NDASBUS_PLUGIN_HARDWARE_EX2, HardwareIDs); wholeStructLen = sizeof(NDASBUS_PLUGIN_HARDWARE_EX2); inputWholeStructLen = ((PNDASBUS_PLUGIN_HARDWARE_EX2) buffer)->Size; } if ((inlen == outlen) && // // Make sure it has at least two nulls and the size // field is set to the declared size of the struct // ((structLen + sizeof(UNICODE_NULL) * 2) <= inlen) && // // The size field should be set to the sizeof the struct as declared // and *not* the size of the struct plus the multi_sz // (wholeStructLen == inputWholeStructLen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("PlugIn called\n")); status= Bus_PlugInDeviceEx2((PNDASBUS_PLUGIN_HARDWARE_EX2)buffer, inlen, fdoData, IoIs32bitProcess(Irp), Irp->RequestorMode, FALSE); Irp->IoStatus.Information = outlen; } } break; case IOCTL_NDASBUS_GETVERSION: { if (outlen >= sizeof(NDASBUS_GET_VERSION)) { PNDASBUS_GET_VERSION version = (PNDASBUS_GET_VERSION)buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_NDASBUS_GETVERSION: called\n")); try { version->VersionMajor = VER_FILEMAJORVERSION; version->VersionMinor = VER_FILEMINORVERSION; version->VersionBuild = VER_FILEBUILD; version->VersionPrivate = VER_FILEBUILD_QFE; Irp->IoStatus.Information = sizeof(NDASBUS_GET_VERSION); status = STATUS_SUCCESS; } except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); Irp->IoStatus.Information = 0; } } } break; case IOCTL_NDASBUS_UNPLUG_HARDWARE: { if ((sizeof (NDASBUS_UNPLUG_HARDWARE) == inlen) && (inlen == outlen) && (((PNDASBUS_UNPLUG_HARDWARE)buffer)->Size == inlen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UnPlug called\n")); status= Bus_UnPlugDevice( (PNDASBUS_UNPLUG_HARDWARE)buffer, fdoData); Irp->IoStatus.Information = outlen; } } break; case IOCTL_NDASBUS_EJECT_HARDWARE: { if ((sizeof (NDASBUS_EJECT_HARDWARE) == inlen) && (inlen == outlen) && (((PNDASBUS_EJECT_HARDWARE)buffer)->Size == inlen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("Eject called\n")); status= Bus_EjectDevice((PNDASBUS_EJECT_HARDWARE)buffer, fdoData); Irp->IoStatus.Information = outlen; } } break; case IOCTL_NDASBUS_DVD_GET_STATUS: { PPDO_DEVICE_DATA pdoData; PNDASBUS_DVD_STATUS pDvdStatusData; // Check Parameter. if((inlen != outlen) || (sizeof(NDASBUS_DVD_STATUS) > inlen)) { status = STATUS_UNSUCCESSFUL ; break; } pDvdStatusData = (PNDASBUS_DVD_STATUS)Irp->AssociatedIrp.SystemBuffer; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("FDO: IOCTL_NDASBUS_DVD_GET_STATUS SlotNumber = %d\n", pDvdStatusData->SlotNo)); pdoData = LookupPdoData(fdoData, pDvdStatusData->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_DVD_GET_STATUS No pdo\n")); status = STATUS_UNSUCCESSFUL; NDBusIoctlLogError( fdoData->Self, NDASBUS_IO_PDO_NOT_FOUND, IOCTL_NDASBUS_DVD_GET_STATUS, pDvdStatusData->SlotNo); break; } else { if(pdoData->LanscsiAdapterPDO.Flags & LSDEVDATA_FLAG_LURDESC) { // // A LUR descriptor is set. // if(((PLURELATION_DESC)pdoData->LanscsiAdapterPDO.AddDevInfo)->DevType != NDASSCSI_TYPE_DVD) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_DVD_GET_STATUS No DVD Device\n")); status = STATUS_UNSUCCESSFUL; break; } } else { // // ADD_TARGET_DATA is set. // if(((PNDASBUS_ADD_TARGET_DATA)pdoData->LanscsiAdapterPDO.AddDevInfo)->ucTargetType != NDASSCSI_TYPE_DVD) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_NDASBUS_DVD_GET_STATUS No DVD Device\n")); status = STATUS_UNSUCCESSFUL; break; } } // // redirect to the NDASSCSI Device // status = LSBus_IoctlToNdasScsiDevice( pdoData, NDASSCSI_IOCTL_GET_DVD_STATUS, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); status = STATUS_SUCCESS; Irp->IoStatus.Information = outlen; } } break; default: break; // default status is STATUS_INVALID_PARAMETER }
NTSTATUS Bus_FDO_PnP ( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PFDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the Plug & Play system for the BUS itself --*/ { NTSTATUS status; ULONG length, prevcount, numPdosPresent; PLIST_ENTRY entry, listHead, nextEntry; PPDO_DEVICE_DATA pdoData; PDEVICE_RELATIONS relations, oldRelations; PAGED_CODE (); Bus_IncIoCount (DeviceData); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // Send the Irp down and wait for it to come back. // Do not touch the hardware until then. // status = Bus_SendIrpSynchronously (DeviceData->NextLowerDriver, Irp); if (NT_SUCCESS(status)) { // // Initialize your device with the resources provided // by the PnP manager to your device. // status = Bus_StartFdo (DeviceData, Irp); } // // We must now complete the IRP, since we stopped it in the // completion routine with MORE_PROCESSING_REQUIRED. // Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (DeviceData); return status; case IRP_MN_QUERY_STOP_DEVICE: // // The PnP manager is trying to stop the device // for resource rebalancing. Fail this now if you // cannot stop the device in response to STOP_DEVICE. // SET_NEW_PNP_STATE(DeviceData, StopPending); Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP. break; case IRP_MN_CANCEL_STOP_DEVICE: // // The PnP Manager sends this IRP, at some point after an // IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a // device that the device will not be stopped for // resource reconfiguration. // // // First check to see whether you have received cancel-stop // without first receiving a query-stop. This could happen if // someone above us fails a query-stop and passes down the subsequent // cancel-stop. // if (StopPending == DeviceData->DevicePnPState) { // // We did receive a query-stop, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); ASSERT(DeviceData->DevicePnPState == Started); } Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP. break; case IRP_MN_STOP_DEVICE: // // Stop device means that the resources given during Start device // are now revoked. Note: You must not fail this Irp. // But before you relieve resources make sure there are no I/O in // progress. Wait for the existing ones to be finished. // To do that, first we will decrement this very operation. // When the counter goes to 1, Stop event is set. // Bus_DecIoCount(DeviceData); KeWaitForSingleObject( &DeviceData->StopEvent, Executive, // Waiting reason of a driver KernelMode, // Waiting in kernel mode FALSE, // No allert NULL); // No timeout // // Increment the counter back because this IRP has to // be sent down to the lower stack. // Bus_IncIoCount (DeviceData); // // Free resources given by start device. // SET_NEW_PNP_STATE(DeviceData, Stopped); // // We don't need a completion routine so fire and forget. // // Set the current stack location to the next stack location and // call the next device object. // Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: // // If we were to fail this call then we would need to complete the // IRP here. Since we are not, set the status to SUCCESS and // call the next driver. // SET_NEW_PNP_STATE(DeviceData, RemovePending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // If we were to fail this call then we would need to complete the // IRP here. Since we are not, set the status to SUCCESS and // call the next driver. // // // First check to see whether you have received cancel-remove // without first receiving a query-remove. This could happen if // someone above us fails a query-remove and passes down the // subsequent cancel-remove. // if (RemovePending == DeviceData->DevicePnPState) { // // We did receive a query-remove, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); } Irp->IoStatus.Status = STATUS_SUCCESS;// You must not fail the IRP. break; case IRP_MN_SURPRISE_REMOVAL: // // The device has been unexpectedly removed from the machine // and is no longer available for I/O. Bus_RemoveFdo clears // all the resources, frees the interface and de-registers // with WMI, but it doesn't delete the FDO. That's done // later in Remove device query. // SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); Bus_RemoveFdo(DeviceData); ExAcquireFastMutex (&DeviceData->Mutex); listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry,nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); RemoveEntryList (&pdoData->Link); InitializeListHead (&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; } ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP. break; case IRP_MN_REMOVE_DEVICE: // // The Plug & Play system has dictated the removal of this device. // We have no choice but to detach and delete the device object. // // // Check the state flag to see whether you are surprise removed // if (DeviceData->DevicePnPState != SurpriseRemovePending) { Bus_RemoveFdo(DeviceData); } SET_NEW_PNP_STATE(DeviceData, Deleted); // // Wait for all outstanding requests to complete. // We need two decrements here, one for the increment in // the beginning of this function, the other for the 1-biased value of // OutstandingIO. // Bus_DecIoCount (DeviceData); // // The requestCount is at least one here (is 1-biased) // Bus_DecIoCount (DeviceData); KeWaitForSingleObject ( &DeviceData->RemoveEvent, Executive, KernelMode, FALSE, NULL); // // Typically the system removes all the children before // removing the parent FDO. If for any reason child Pdos are // still present we will destroy them explicitly, with one exception - // we will not delete the PDOs that are in SurpriseRemovePending state. // ExAcquireFastMutex (&DeviceData->Mutex); listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry,nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); RemoveEntryList (&pdoData->Link); if (SurpriseRemovePending == pdoData->DevicePnPState) { // // We will reinitialize the list head so that we // wouldn't barf when we try to delink this PDO from // the parent's PDOs list, when the system finally // removes the PDO. Let's also not forget to set the // ReportedMissing flag to cause the deletion of the PDO. // Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO, ("\tFound a surprise removed device: 0x%p\n", pdoData->Self)); InitializeListHead (&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; continue; } DeviceData->NumPDOs--; Bus_DestroyPdo (pdoData->Self, pdoData); } ExReleaseFastMutex (&DeviceData->Mutex); // // We need to send the remove down the stack before we detach, // but we don't need to wait for the completion of this operation // (and to register a completion routine). // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); // // Detach from the underlying devices. // IoDetachDevice (DeviceData->NextLowerDriver); Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO, ("\tDeleting FDO: 0x%p\n", DeviceObject)); IoDeleteDevice (DeviceObject); return status; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceRelation Type: %s\n", DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type))); if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) { // // We don't support any other Device Relations // break; } // // Tell the plug and play system about all the PDOs. // // There might also be device relations below and above this FDO, // so, be sure to propagate the relations from the upper drivers. // // No Completion routine is needed so long as the status is preset // to success. (PDOs complete plug and play irps with the current // IoStatus.Status and IoStatus.Information as the default.) // ExAcquireFastMutex (&DeviceData->Mutex); oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information; if (oldRelations) { prevcount = oldRelations->Count; if (!DeviceData->NumPDOs) { // // There is a device relations struct already present and we have // nothing to add to it, so just call IoSkip and IoCall // ExReleaseFastMutex (&DeviceData->Mutex); break; } } else { prevcount = 0; } // // Calculate the number of PDOs actually present on the bus // numPdosPresent = 0; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) numPdosPresent++; } // // Need to allocate a new relations structure and add our // PDOs to it. // length = sizeof(DEVICE_RELATIONS) + ((numPdosPresent + prevcount) * sizeof (PDEVICE_OBJECT)) -1; relations = (PDEVICE_RELATIONS) ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (NULL == relations) { // // Fail the IRP // ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (DeviceData); return status; } // // Copy in the device objects so far // if (prevcount) { RtlCopyMemory (relations->Objects, oldRelations->Objects, prevcount * sizeof (PDEVICE_OBJECT)); } relations->Count = prevcount + numPdosPresent; // // For each PDO present on this bus add a pointer to the device relations // buffer, being sure to take out a reference to that object. // The Plug & Play system will dereference the object when it is done // with it and free the device relations buffer. // for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) { relations->Objects[prevcount] = pdoData->Self; ObReferenceObject (pdoData->Self); prevcount++; } else { pdoData->ReportedMissing = TRUE; } } Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\t#PDOS present = %d\n\t#PDOs reported = %d\n", DeviceData->NumPDOs, relations->Count)); // // Replace the relations structure in the IRP with the new // one. // if (oldRelations) { ExFreePool (oldRelations); } Irp->IoStatus.Information = (ULONG_PTR) relations; ExReleaseFastMutex (&DeviceData->Mutex); // // Set up and pass the IRP further down the stack // Irp->IoStatus.Status = STATUS_SUCCESS; break; default: // // In the default case we merely call the next driver. // We must not modify Irp->IoStatus.Status or complete the IRP. // break; } IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); Bus_DecIoCount (DeviceData); return status; }
NTSTATUS Bus_FDO_Power ( PFDO_DEVICE_DATA Data, PIRP Irp ) /*++ Handles power Irps sent to the FDO. This driver is power policy owner for the bus itself (not the devices on the bus).Power handling for the bus FDO should be implemented similar to the function driver (toaster.sys) power code. We will just print some debug outputs and forward this Irp to the next level. Arguments: Data - Pointer to the FDO device extension. Irp - Pointer to the irp. Return Value: NT status is returned. --*/ { NTSTATUS status; POWER_STATE powerState; POWER_STATE_TYPE powerType; PIO_STACK_LOCATION stack; stack = IoGetCurrentIrpStackLocation (Irp); powerType = stack->Parameters.Power.Type; powerState = stack->Parameters.Power.State; Bus_IncIoCount (Data); // // If the device is not stated yet, just pass it down. // if (Data->DevicePnPState == NotStarted) { PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); status = PoCallDriver(Data->NextLowerDriver, Irp); Bus_DecIoCount (Data); return status; } if (stack->MinorFunction == IRP_MN_SET_POWER) { Bus_KdPrint_Cont(Data, BUS_DBG_POWER_TRACE, ("\tRequest to set %s state to %s\n", ((powerType == SystemPowerState) ? "System" : "Device"), ((powerType == SystemPowerState) ? \ DbgSystemPowerString(powerState.SystemState) :\ DbgDevicePowerString(powerState.DeviceState)))); } PoStartNextPowerIrp (Irp); IoSkipCurrentIrpStackLocation(Irp); status = PoCallDriver (Data->NextLowerDriver, Irp); Bus_DecIoCount (Data); return status; }
NTSTATUS Bus_PDO_Power ( PPDO_DEVICE_DATA PdoData, PIRP Irp ) /*++ Handles power Irps sent to the PDOs. Typically a bus driver, that is not a power policy owner for the device, does nothing more than starting the next power IRP and completing this one. Arguments: PdoData - Pointer to the PDO device extension. Irp - Pointer to the irp. Return Value: NT status is returned. --*/ { NTSTATUS status; PIO_STACK_LOCATION stack; POWER_STATE powerState; POWER_STATE_TYPE powerType; stack = IoGetCurrentIrpStackLocation (Irp); powerType = stack->Parameters.Power.Type; powerState = stack->Parameters.Power.State; switch (stack->MinorFunction) { case IRP_MN_SET_POWER: Bus_KdPrint_Cont(PdoData, BUS_DBG_POWER_TRACE, ("\tSetting %s power state to %s\n", ((powerType == SystemPowerState) ? "System" : "Device"), ((powerType == SystemPowerState) ? \ DbgSystemPowerString(powerState.SystemState) : \ DbgDevicePowerString(powerState.DeviceState)))); switch (powerType) { case DevicePowerState: PoSetPowerState (PdoData->Self, powerType, powerState); PdoData->DevicePowerState = powerState.DeviceState; status = STATUS_SUCCESS; break; case SystemPowerState: PdoData->SystemPowerState = powerState.SystemState; status = STATUS_SUCCESS; break; default: status = STATUS_NOT_SUPPORTED; break; } break; case IRP_MN_QUERY_POWER: status = STATUS_SUCCESS; break; case IRP_MN_WAIT_WAKE: // // We cannot support wait-wake because we are root-enumerated // driver, and our parent, the PnP manager, doesn't support wait-wake. // If you are a bus enumerated device, and if your parent bus supports // wait-wake, you should send a wait/wake IRP (PoRequestPowerIrp) // in response to this request. // If you want to test the wait/wake logic implemented in the function // driver (toaster.sys), you could do the following simulation: // a) Mark this IRP pending. // b) Set a cancel routine. // c) Save this IRP in the device extension // d) Return STATUS_PENDING. // Later on if you suspend and resume your system, your BUS_FDO_POWER // will be called to power the bus. In response to IRP_MN_SET_POWER, if the // powerstate is PowerSystemWorking, complete this Wake IRP. // If the function driver, decides to cancel the wake IRP, your cancel routine // will be called. There you just complete the IRP with STATUS_CANCELLED. // case IRP_MN_POWER_SEQUENCE: default: status = STATUS_NOT_SUPPORTED; break; } if (status != STATUS_NOT_SUPPORTED) { Irp->IoStatus.Status = status; } PoStartNextPowerIrp(Irp); status = Irp->IoStatus.Status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }
NTSTATUS Bus_IoCtl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Handle user mode PlugIn, UnPlug and device Eject requests. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PIO_STACK_LOCATION irpStack; NTSTATUS status; ULONG inlen, outlen; PFDO_DEVICE_DATA fdoData; PVOID buffer; PAGED_CODE (); fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; // // We only take Device Control requests for the FDO. // That is the bus itself. // if (!fdoData->IsFDO) { // // These commands are only allowed to go to the FDO. // status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } // // Check to see whether the bus is removed // if (fdoData->DevicePnPState == Deleted) { Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } Bus_IncIoCount (fdoData); irpStack = IoGetCurrentIrpStackLocation (Irp); buffer = Irp->AssociatedIrp.SystemBuffer; inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength; outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; status = STATUS_INVALID_PARAMETER; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("%d called\n", irpStack->Parameters.DeviceIoControl.IoControlCode)); switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_LANSCSI_ADD_TARGET: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET inlen %d, outlen %d, sizeof(LANSCSI_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(LANSCSI_ADD_TARGET_DATA))); if ((inlen == outlen) && (sizeof(LANSCSI_ADD_TARGET_DATA) <= inlen)) { ULONG ulSize; PLANSCSI_ADD_TARGET_DATA pBuffer = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_ADD_TARGET called\n")); Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET Target Type %d\n", pBuffer->ucTargetType)); // Check Parameter. switch(pBuffer->ucTargetType) { case DISK_TYPE_NORMAL: case DISK_TYPE_DVD: case DISK_TYPE_VDVD: case DISK_TYPE_MO: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA); if(pBuffer->ulNumberOfUnitDiskList != 1) { ulSize = 0; // Exit when Check if(ulSize != inlen)... } break; case DISK_TYPE_MIRROR: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA) + sizeof(LSBUS_UNITDISK); if(2 != pBuffer->ulNumberOfUnitDiskList) { ulSize = 0; // Exit when Check if(ulSize != inlen)... } break; case DISK_TYPE_AGGREGATION: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA) + sizeof(LSBUS_UNITDISK) * (pBuffer->ulNumberOfUnitDiskList - 1); if (pBuffer->ulNumberOfUnitDiskList < 2 || pBuffer->ulNumberOfUnitDiskList > MAX_NR_TC_PER_TARGET) { ulSize = 0; // Exit when Check if(ulSize != inlen)... } break; case DISK_TYPE_BIND_RAID0: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA) + sizeof(LSBUS_UNITDISK) * (pBuffer->ulNumberOfUnitDiskList - 1); switch(pBuffer->ulNumberOfUnitDiskList) { case 2: case 4: case 8: break; default: // do not accept ulSize = 0; break; } break; case DISK_TYPE_BIND_RAID1: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA) + sizeof(LSBUS_UNITDISK) * (pBuffer->ulNumberOfUnitDiskList - 1); if (pBuffer->ulNumberOfUnitDiskList < 2 || pBuffer->ulNumberOfUnitDiskList > MAX_NR_TC_PER_TARGET) { ulSize = 0; // Exit when Check if(ulSize != inlen)... } if (pBuffer->ulNumberOfUnitDiskList % 2) { // should be the multiples of 2 ulSize = 0; // Exit when Check if(ulSize != inlen)... } break; case DISK_TYPE_BIND_RAID4: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA) + sizeof(LSBUS_UNITDISK) * (pBuffer->ulNumberOfUnitDiskList - 1); switch(pBuffer->ulNumberOfUnitDiskList) { case 3: // 2 + 1 case 5: // 4 + 1 case 9: // 8 + 1 break; default: // do not accept ulSize = 0; break; } break; default: Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET: Bad Disk Type.\n")); status = STATUS_UNSUCCESSFUL; break; } // Check Size. if(ulSize != inlen) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET: Size mismatch. Req %d, in %d\n", ulSize, inlen)); status = STATUS_UNSUCCESSFUL; break; } // Find Pdo Data... pdoData = LookupPdoData(fdoData, pBuffer->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; break; } /* // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_ADD_TARGET, buffer, sizeof(LANSCSI_ADD_TARGET_DATA), NULL, 0 ); */ pdoData->LanscsiAdapterPDO.AddDevInfo = ExAllocatePool(NonPagedPool, inlen); if(pdoData->LanscsiAdapterPDO.AddDevInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } else { RtlCopyMemory(pdoData->LanscsiAdapterPDO.AddDevInfo, pBuffer, inlen); status = STATUS_SUCCESS; } pdoData->LanscsiAdapterPDO.AddDevInfoLength = inlen; // // Notify to LanscsiMiniport // Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET SetEvent AddTargetEvent!\n")); KeSetEvent(&pdoData->LanscsiAdapterPDO.AddTargetEvent, IO_NO_INCREMENT, FALSE); ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; } else { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET length mismatch!!! inlen %d, outlen %d, sizeof(LANSCSI_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(LANSCSI_ADD_TARGET_DATA))); } } break; case IOCTL_LANSCSI_REMOVE_TARGET: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_REMOVE_TARGET called\n")); if (sizeof (LANSCSI_REMOVE_TARGET_DATA) != inlen) break; pdoData = LookupPdoData(fdoData, ((PLANSCSI_REMOVE_TARGET_DATA)buffer)->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; break; } // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_REMOVE_TARGET, buffer, sizeof(LANSCSI_REMOVE_TARGET_DATA), NULL, 0 ); ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; break; } case IOCTL_LANSCSI_REGISTER_DEVICE: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_REGISTER_NDASDEVICE inlen %d, outlen %d, sizeof(LANSCSI_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(LANSCSI_ADD_TARGET_DATA))); if ((inlen == outlen)) { PLANSCSI_REGISTER_NDASDEV RegNdasDev = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_REGISTER_NDASDEVICE called\n")); status = LSBus_RegisterDevice(fdoData, RegNdasDev); Irp->IoStatus.Information = 0; } else Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET length mismatch!!! inlen %d, outlen %d, sizeof(LANSCSI_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(LANSCSI_ADD_TARGET_DATA))); } break; case IOCTL_LANSCSI_UNREGISTER_DEVICE: { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_REGISTER_NDASDEVICE inlen %d, outlen %d, sizeof(LANSCSI_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(LANSCSI_ADD_TARGET_DATA))); if ((inlen == outlen)) { PLANSCSI_UNREGISTER_NDASDEV UnregNdasDev = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_REGISTER_NDASDEVICE called\n")); status = LSBus_UnregisterDevice(fdoData, UnregNdasDev); Irp->IoStatus.Information = 0; } else Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET length mismatch!!! inlen %d, outlen %d, sizeof(LANSCSI_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(LANSCSI_ADD_TARGET_DATA))); } case IOCTL_LANSCSI_SETPDOINFO: { PPDO_DEVICE_DATA pdoData; PBUSENUM_SETPDOINFO SetPdoInfo; KIRQL oldIrql; PVOID sectionHandle; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_SETPDOINFO called\n")); if (sizeof (BUSENUM_SETPDOINFO) != inlen) break; SetPdoInfo = (PBUSENUM_SETPDOINFO)buffer; pdoData = LookupPdoData(fdoData, (SetPdoInfo)->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; break; } // // set information // lock the code section of the function to raise IRQL // because the function is PAGED_CODE. // sectionHandle = MmLockPagableCodeSection(Bus_IoCtl); KeAcquireSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, &oldIrql); Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("!!!!!!!!!!!!!!!!!! IOCTL_LANSCSI_SETPDOINFO: %08lx %08lx %08lx\n", SetPdoInfo->AdapterStatus, SetPdoInfo->DesiredAccess, SetPdoInfo->GrantedAccess)); if(ADAPTERINFO_ISSTATUS(SetPdoInfo->AdapterStatus, ADAPTERINFO_STATUS_STOPPING) && ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.AdapterStatus, ADAPTERINFO_STATUS_STOPPED)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("SETPDOINFO: 'Stopping' event occured after 'Stopped' event\n", SetPdoInfo->AdapterStatus, SetPdoInfo->DesiredAccess, SetPdoInfo->GrantedAccess)); } else { pdoData->LanscsiAdapterPDO.AdapterStatus = SetPdoInfo->AdapterStatus; pdoData->LanscsiAdapterPDO.DesiredAccess = SetPdoInfo->DesiredAccess; pdoData->LanscsiAdapterPDO.GrantedAccess = SetPdoInfo->GrantedAccess; } KeReleaseSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, oldIrql); MmUnlockPagableImageSection(sectionHandle); status = STATUS_SUCCESS; ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; } break; case IOCTL_BUSENUM_QUERY_NODE_ALIVE: { PPDO_DEVICE_DATA pdoData; BOOLEAN bAlive; PBUSENUM_NODE_ALIVE_IN pNodeAliveIn; BUSENUM_NODE_ALIVE_OUT nodeAliveOut; // Check Parameter. if(inlen != sizeof(BUSENUM_NODE_ALIVE_IN) || outlen != sizeof(BUSENUM_NODE_ALIVE_OUT)) { status = STATUS_UNKNOWN_REVISION; break; } pNodeAliveIn = (PBUSENUM_NODE_ALIVE_IN)Irp->AssociatedIrp.SystemBuffer; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_NOISE, ("FDO: IOCTL_BUSENUM_QUERY_NODE_ALIVE SlotNumber = %d\n", pNodeAliveIn->SlotNo)); pdoData = LookupPdoData(fdoData, pNodeAliveIn->SlotNo); if(pdoData == NULL) { // Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE, // ("[LanScsiBus]Bus_IoCtl: IOCTL_BUSENUM_QUERY_NODE_ALIVE No pdo\n")); bAlive = FALSE; } else { // // Check this PDO would be removed... // if(pdoData->Present == TRUE) bAlive = TRUE; else bAlive = FALSE; } // For Result... nodeAliveOut.SlotNo = pNodeAliveIn->SlotNo; nodeAliveOut.bAlive = bAlive; // Get Adapter Status. if(bAlive == TRUE) { if( ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.AdapterStatus, ADAPTERINFO_STATUS_IN_ERROR) || ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.AdapterStatus, ADAPTERINFO_STATUS_STOPPING) /*|| ADAPTERINFO_ISSTATUSFLAG(pdoData->LanscsiAdapterPDO.AdapterStatus, ADAPTERINFO_STATUSFLAG_MEMBER_FAULT) */ ) { nodeAliveOut.bHasError = TRUE; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_BUSENUM_QUERY_NODE_ALIVE Adapter has Error 0x%x\n", nodeAliveOut.bHasError)); } else { nodeAliveOut.bHasError = FALSE; } } if(pdoData) ObDereferenceObject(pdoData->Self); RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, &nodeAliveOut, sizeof(BUSENUM_NODE_ALIVE_OUT) ); Irp->IoStatus.Information = sizeof(BUSENUM_NODE_ALIVE_OUT); status = STATUS_SUCCESS; } break; // // added by hootch 01172004 // case IOCTL_LANSCSI_UPGRADETOWRITE: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_UPGRADETOWRITE called\n")); // Check Parameter. if(inlen != sizeof(BUSENUM_UPGRADE_TO_WRITE)) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_UPGRADETOWRITE: Invalid input buffer length\n")); status = STATUS_UNKNOWN_REVISION; break; } pdoData = LookupPdoData(fdoData, ((PBUSENUM_UPGRADE_TO_WRITE)buffer)->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_UPGRADETOWRITE No pdo for Slotno:%d\n", ((PBUSENUM_UPGRADE_TO_WRITE)buffer)->SlotNo)); status = STATUS_NO_SUCH_DEVICE; } else { // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_UPGRADETOWRITE, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = 0; } break; case IOCTL_LANSCSI_QUERY_LSMPINFORMATION: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_QUERY_LSMPINFORMATION called\n")); // Check Parameter. if(inlen < FIELD_OFFSET(LSMPIOCTL_QUERYINFO, QueryData) ) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_QUERY_LSMPINFORMATION: Invalid input buffer length too small.\n")); status = STATUS_UNKNOWN_REVISION; break; } pdoData = LookupPdoData(fdoData, ((PLSMPIOCTL_QUERYINFO)buffer)->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_QUERY_LSMPINFORMATION No pdo\n")); status = STATUS_NO_SUCH_DEVICE; } else { // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_QUERYINFO_EX, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = outlen; } break; case IOCTL_BUSENUM_QUERY_INFORMATION: { // PPDO_DEVICE_DATA pdoData; BUSENUM_QUERY_INFORMATION Query; PBUSENUM_INFORMATION Information; LONG BufferLenNeeded; // Check Parameter. if( inlen < sizeof(BUSENUM_QUERY_INFORMATION) /*|| outlen < sizeof(BUSENUM_INFORMATION) */) { status = STATUS_UNKNOWN_REVISION; break; } RtlCopyMemory(&Query, buffer, sizeof(BUSENUM_QUERY_INFORMATION)); Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE, ("FDO: IOCTL_BUSENUM_QUERY_INFORMATION QueryType : %d SlotNumber = %d\n", Query.InfoClass, Query.SlotNo)); Information = (PBUSENUM_INFORMATION)buffer; ASSERT(Information); Information->InfoClass = Query.InfoClass; status = LSBus_QueryInformation(fdoData, &Query, Information, outlen, &BufferLenNeeded); if(NT_SUCCESS(status)) { Information->Size = BufferLenNeeded; Irp->IoStatus.Information = BufferLenNeeded; } else { Irp->IoStatus.Information = BufferLenNeeded; } } break; case IOCTL_BUSENUM_PLUGIN_HARDWARE_EX: { if ((inlen == outlen) && // // Make sure it has at least two nulls and the size // field is set to the declared size of the struct // ((sizeof (BUSENUM_PLUGIN_HARDWARE_EX) + sizeof(UNICODE_NULL) * 2) <= inlen) && // // The size field should be set to the sizeof the struct as declared // and *not* the size of the struct plus the multi_sz // (sizeof (BUSENUM_PLUGIN_HARDWARE_EX) == ((PBUSENUM_PLUGIN_HARDWARE_EX) buffer)->Size)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("PlugIn called\n")); status= Bus_PlugInDeviceEx((PBUSENUM_PLUGIN_HARDWARE_EX)buffer, inlen, fdoData, Irp->RequestorMode); Irp->IoStatus.Information = outlen; } } break; case IOCTL_LANSCSI_GETVERSION: { if (outlen >= sizeof(BUSENUM_GET_VERSION)) { PBUSENUM_GET_VERSION version = (PBUSENUM_GET_VERSION)buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_GETVERSION: called\n")); try { version->VersionMajor = VER_FILEMAJORVERSION; version->VersionMinor = VER_FILEMINORVERSION; version->VersionBuild = VER_FILEBUILD; version->VersionPrivate = VER_FILEBUILD_QFE; Irp->IoStatus.Information = sizeof(BUSENUM_GET_VERSION); status = STATUS_SUCCESS; } except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); Irp->IoStatus.Information = 0; } } } break; case IOCTL_BUSENUM_UNPLUG_HARDWARE: { if ((sizeof (BUSENUM_UNPLUG_HARDWARE) == inlen) && (inlen == outlen) && (((PBUSENUM_UNPLUG_HARDWARE)buffer)->Size == inlen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UnPlug called\n")); status= Bus_UnPlugDevice( (PBUSENUM_UNPLUG_HARDWARE)buffer, fdoData); Irp->IoStatus.Information = outlen; } } break; case IOCTL_BUSENUM_EJECT_HARDWARE: { if ((sizeof (BUSENUM_EJECT_HARDWARE) == inlen) && (inlen == outlen) && (((PBUSENUM_EJECT_HARDWARE)buffer)->Size == inlen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("Eject called\n")); status= Bus_EjectDevice((PBUSENUM_EJECT_HARDWARE)buffer, fdoData); Irp->IoStatus.Information = outlen; } } break; case IOCTL_DVD_GET_STATUS: { PPDO_DEVICE_DATA pdoData; PBUSENUM_DVD_STATUS pDvdStatusData; // Check Parameter. if((inlen != outlen) || (sizeof(BUSENUM_DVD_STATUS) > inlen)) { status = STATUS_UNSUCCESSFUL ; break; } pDvdStatusData = (PBUSENUM_DVD_STATUS)Irp->AssociatedIrp.SystemBuffer; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("FDO: IOCTL_DVD_GET_STATUS SlotNumber = %d\n", pDvdStatusData->SlotNo)); pdoData = LookupPdoData(fdoData, pDvdStatusData->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_DVD_GET_STATUS No pdo\n")); status = STATUS_UNSUCCESSFUL; break; } else { if(pdoData->LanscsiAdapterPDO.Flags & LSDEVDATA_FLAG_LURDESC) { // // A LUR descriptor is set. // if(((PLURELATION_DESC)pdoData->LanscsiAdapterPDO.AddDevInfo)->DevType != DISK_TYPE_DVD) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_DVD_GET_STATUS No DVD Device\n")); status = STATUS_UNSUCCESSFUL; break; } } else { // // ADD_TARGET_DATA is set. // if(((PLANSCSI_ADD_TARGET_DATA)pdoData->LanscsiAdapterPDO.AddDevInfo)->ucTargetType != DISK_TYPE_DVD) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_DVD_GET_STATUS No DVD Device\n")); status = STATUS_UNSUCCESSFUL; break; } } // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_GET_DVD_STATUS, buffer, inlen, buffer, outlen ) ; ObDereferenceObject(pdoData->Self); status = STATUS_SUCCESS; Irp->IoStatus.Information = outlen; } } break; default: break; // default status is STATUS_INVALID_PARAMETER }
NTSTATUS Bus_IoCtl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Handle user mode PlugIn, UnPlug and device Eject requests. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PIO_STACK_LOCATION irpStack; NTSTATUS status; ULONG inlen, outlen; PFDO_DEVICE_DATA fdoData; PVOID buffer; PAGED_CODE (); fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; // // We only take Device Control requests for the FDO. // That is the bus itself. // if (!fdoData->IsFDO) { // // These commands are only allowed to go to the FDO. // status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } // // Check to see whether the bus is removed // if (fdoData->DevicePnPState == Deleted) { Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } Bus_IncIoCount (fdoData); irpStack = IoGetCurrentIrpStackLocation (Irp); buffer = Irp->AssociatedIrp.SystemBuffer; inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength; outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; status = STATUS_INVALID_PARAMETER; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("%d called\n", irpStack->Parameters.DeviceIoControl.IoControlCode)); switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_LANSCSI_ADD_TARGET: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET inlen %d, outlen %d, sizeof(LANSCSI_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(LANSCSI_ADD_TARGET_DATA))); if ((inlen == outlen) && (sizeof(LANSCSI_ADD_TARGET_DATA) <= inlen)) { ULONG ulSize; PLANSCSI_ADD_TARGET_DATA pBuffer = buffer; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_ADD_TARGET called\n")); Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET Target Type %d\n", pBuffer->ucTargetType)); // Check Parameter. switch(pBuffer->ucTargetType) { case DISK_TYPE_NORMAL: case DISK_TYPE_DVD: case DISK_TYPE_VDVD: case DISK_TYPE_MO: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA); if(pBuffer->ulNumberOfUnitDiskList != 1) ulSize = 0; // Exit when Check if(ulSize != inlen)... break; case DISK_TYPE_MIRROR: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA) + sizeof(LSBUS_UNITDISK); if(2 != pBuffer->ulNumberOfUnitDiskList) ulSize = 0; // Exit when Check if(ulSize != inlen)... break; case DISK_TYPE_AGGREGATION: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA) + sizeof(LSBUS_UNITDISK) * (pBuffer->ulNumberOfUnitDiskList - 1); if(pBuffer->ulNumberOfUnitDiskList < 1 || pBuffer->ulNumberOfUnitDiskList > 0xFFFF) ulSize = 0; // Exit when Check if(ulSize != inlen)... break; case DISK_TYPE_BIND_RAID1: ulSize = sizeof(LANSCSI_ADD_TARGET_DATA) + sizeof(LSBUS_UNITDISK) * (pBuffer->ulNumberOfUnitDiskList - 1); // if(pBuffer->ulNumberOfUnitDiskList < 1 || pBuffer->ulNumberOfUnitDiskList > MAX_NR_TC_PER_TARGET) if(pBuffer->ulNumberOfUnitDiskList < 2 || pBuffer->ulNumberOfUnitDiskList > 0xFFFF) ulSize = 0; // Exit when Check if(ulSize != inlen)... if(pBuffer->ulNumberOfUnitDiskList % 2) // should be the multiples of 2 ulSize = 0; // Exit when Check if(ulSize != inlen)... break; default: Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET: Bad Disk Type.\n")); status = STATUS_UNSUCCESSFUL; break; } // Check Size. if(ulSize != inlen) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET: Size mismatch. Req %d, in %d\n", ulSize, inlen)); status = STATUS_UNSUCCESSFUL; break; } // Find Pdo Data... pdoData = LookupPdoData(fdoData, pBuffer->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; break; } /* // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_ADD_TARGET, buffer, sizeof(LANSCSI_ADD_TARGET_DATA), NULL, 0 ); */ pdoData->LanscsiAdapterPDO.AddTargetData = ExAllocatePool(NonPagedPool, inlen); if(pdoData->LanscsiAdapterPDO.AddTargetData == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } else { RtlCopyMemory(pdoData->LanscsiAdapterPDO.AddTargetData, pBuffer, inlen); status = STATUS_SUCCESS; } // // Notify to LanscsiMiniport // Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET SetEvent AddTargetEvent!\n")); KeSetEvent(&pdoData->LanscsiAdapterPDO.AddTargetEvent, IO_NO_INCREMENT, FALSE); ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; } else Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_ADD_TARGET length mismatch!!! inlen %d, outlen %d, sizeof(LANSCSI_ADD_TARGET_DATA) %d\n", inlen, outlen, sizeof(LANSCSI_ADD_TARGET_DATA))); } break; case IOCTL_LANSCSI_REMOVE_TARGET: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_REMOVE_TARGET called\n")); if (sizeof (LANSCSI_REMOVE_TARGET_DATA) != inlen) break; pdoData = LookupPdoData(fdoData, ((PLANSCSI_REMOVE_TARGET_DATA)buffer)->ulSlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; break; } // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_REMOVE_TARGET, buffer, sizeof(LANSCSI_REMOVE_TARGET_DATA), NULL, 0 ); ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; break; } case IOCTL_LANSCSI_SETPDOINFO: { PPDO_DEVICE_DATA pdoData; PBUSENUM_SETPDOINFO SetPdoInfo; KIRQL oldIrql; PVOID sectionHandle; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_SETPDOINFO called\n")); if (sizeof (BUSENUM_SETPDOINFO) != inlen) break; SetPdoInfo = (PBUSENUM_SETPDOINFO)buffer; pdoData = LookupPdoData(fdoData, (SetPdoInfo)->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("no pdo\n")); status = STATUS_UNSUCCESSFUL; break; } // // set information // lock the code section of the function to raise IRQL // because the function is PAGED_CODE. // sectionHandle = MmLockPagableCodeSection(Bus_IoCtl); KeAcquireSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, &oldIrql); Bus_KdPrint(fdoData, BUS_DBG_IOCTL_ERROR, ("!!!!!!!!!!!!!!!!!! IOCTL_LANSCSI_SETPDOINFO: %08lx %08lx %08lx\n", SetPdoInfo->AdapterStatus, SetPdoInfo->DesiredAccess, SetPdoInfo->GrantedAccess)); pdoData->LanscsiAdapterPDO.AdapterStatus = SetPdoInfo->AdapterStatus; pdoData->LanscsiAdapterPDO.DesiredAccess = SetPdoInfo->DesiredAccess; pdoData->LanscsiAdapterPDO.GrantedAccess = SetPdoInfo->GrantedAccess; KeReleaseSpinLock(&pdoData->LanscsiAdapterPDO.LSDevDataSpinLock, oldIrql); MmUnlockPagableImageSection(sectionHandle); status = STATUS_SUCCESS; ObDereferenceObject(pdoData->Self); Irp->IoStatus.Information = outlen; } break; case IOCTL_BUSENUM_QUERY_NODE_ALIVE: { PPDO_DEVICE_DATA pdoData; BOOLEAN bAlive; PBUSENUM_NODE_ALIVE_IN pNodeAliveIn; BUSENUM_NODE_ALIVE_OUT nodeAliveOut; // Check Parameter. if(inlen != sizeof(BUSENUM_NODE_ALIVE_IN) || outlen != sizeof(BUSENUM_NODE_ALIVE_OUT)) { status = STATUS_UNKNOWN_REVISION; break; } pNodeAliveIn = (PBUSENUM_NODE_ALIVE_IN)Irp->AssociatedIrp.SystemBuffer; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_NOISE, ("FDO: IOCTL_BUSENUM_QUERY_NODE_ALIVE SlotNumber = %d\n", pNodeAliveIn->SlotNo)); pdoData = LookupPdoData(fdoData, pNodeAliveIn->SlotNo); if(pdoData == NULL) { // Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE, // ("[LanScsiBus]Bus_IoCtl: IOCTL_BUSENUM_QUERY_NODE_ALIVE No pdo\n")); bAlive = FALSE; } else { // // Check this PDO would be removed... // if(pdoData->Present == TRUE) bAlive = TRUE; else bAlive = FALSE; } // For Result... nodeAliveOut.SlotNo = pNodeAliveIn->SlotNo; nodeAliveOut.bAlive = bAlive; // Get Adapter Status. if(bAlive == TRUE) { if( ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.AdapterStatus, ADAPTERINFO_STATUS_IN_ERROR) || ADAPTERINFO_ISSTATUS(pdoData->LanscsiAdapterPDO.AdapterStatus, ADAPTERINFO_STATUS_STOPPING) /*|| ADAPTERINFO_ISSTATUSFLAG(pdoData->LanscsiAdapterPDO.AdapterStatus, ADAPTERINFO_STATUSFLAG_MEMBER_FAULT) */ ) { nodeAliveOut.bHasError = TRUE; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_BUSENUM_QUERY_NODE_ALIVE Adapter has Error 0x%x\n", nodeAliveOut.bHasError)); } else { nodeAliveOut.bHasError = FALSE; } } if(pdoData) ObDereferenceObject(pdoData->Self); RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, &nodeAliveOut, sizeof(BUSENUM_NODE_ALIVE_OUT) ); Irp->IoStatus.Information = sizeof(BUSENUM_NODE_ALIVE_OUT); status = STATUS_SUCCESS; } break; // // added by hootch 01172004 // case IOCTL_LANSCSI_UPGRADETOWRITE: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_UPGRADETOWRITE called\n")); // Check Parameter. if(inlen != sizeof(BUSENUM_UPGRADE_TO_WRITE)) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_UPGRADETOWRITE: Invalid input buffer length\n")); status = STATUS_UNKNOWN_REVISION; break; } pdoData = LookupPdoData(fdoData, ((PBUSENUM_UPGRADE_TO_WRITE)buffer)->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_UPGRADETOWRITE No pdo\n")); status = STATUS_NO_SUCH_DEVICE; } else { // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_UPGRADETOWRITE, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = 0; } break; case IOCTL_LANSCSI_QUERY_LSMPINFORMATION: { PPDO_DEVICE_DATA pdoData; Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("IOCTL_LANSCSI_QUERY_LSMPINFORMATION called\n")); // Check Parameter. if(inlen < sizeof(LSMPIOCTL_QUERYINFO)) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_QUERY_LSMPINFORMATION: Invalid input buffer length too small.\n")); status = STATUS_UNKNOWN_REVISION; break; } pdoData = LookupPdoData(fdoData, ((PLSMPIOCTL_QUERYINFO)buffer)->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_LANSCSI_QUERY_LSMPINFORMATION No pdo\n")); status = STATUS_NO_SUCH_DEVICE; } else { // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_QUERYINFO_EX, buffer, inlen, buffer, outlen ); ObDereferenceObject(pdoData->Self); } Irp->IoStatus.Information = outlen; } break; case IOCTL_BUSENUM_QUERY_INFORMATION: { // PPDO_DEVICE_DATA pdoData; BUSENUM_QUERY_INFORMATION Query; PBUSENUM_INFORMATION Information; LONG BufferLenNeeded; // Check Parameter. if( inlen < sizeof(BUSENUM_QUERY_INFORMATION) /*|| outlen < sizeof(BUSENUM_INFORMATION) */) { status = STATUS_UNKNOWN_REVISION; break; } RtlCopyMemory(&Query, buffer, sizeof(BUSENUM_QUERY_INFORMATION)); Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_TRACE, ("FDO: IOCTL_BUSENUM_QUERY_INFORMATION QueryType : %d SlotNumber = %d\n", Query.InfoClass, Query.SlotNo)); Information = (PBUSENUM_INFORMATION)buffer; ASSERT(Information); Information->InfoClass = Query.InfoClass; status = LSBus_QueryInformation(fdoData, &Query, Information, outlen, &BufferLenNeeded); if(NT_SUCCESS(status)) { Information->Size = BufferLenNeeded; Irp->IoStatus.Information = BufferLenNeeded; } else { Irp->IoStatus.Information = BufferLenNeeded; } } break; /* case IOCTL_BUSENUM_PLUGIN_HARDWARE: status = STATUS_INVALID_PARAMETER; break; */ // inserted by ILGU case IOCTL_BUSENUM_PLUGIN_HARDWARE_EX: if ((inlen == outlen) && // // Make sure it has at least two nulls and the size // field is set to the declared size of the struct // ((sizeof (BUSENUM_PLUGIN_HARDWARE_EX) + sizeof(UNICODE_NULL) * 2) <= inlen) && // // The size field should be set to the sizeof the struct as declared // and *not* the size of the struct plus the multi_sz // (sizeof (BUSENUM_PLUGIN_HARDWARE_EX) == ((PBUSENUM_PLUGIN_HARDWARE_EX) buffer)->Size)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("PlugIn called\n")); status= Bus_PlugInDeviceEx((PBUSENUM_PLUGIN_HARDWARE_EX)buffer, inlen, fdoData, Irp); Irp->IoStatus.Information = outlen; } break; case IOCTL_BUSENUM_UNPLUG_HARDWARE: if ((sizeof (BUSENUM_UNPLUG_HARDWARE) == inlen) && (inlen == outlen) && (((PBUSENUM_UNPLUG_HARDWARE)buffer)->Size == inlen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UnPlug called\n")); status= Bus_UnPlugDevice( (PBUSENUM_UNPLUG_HARDWARE)buffer, fdoData); Irp->IoStatus.Information = outlen; } break; case IOCTL_BUSENUM_EJECT_HARDWARE: if ((sizeof (BUSENUM_EJECT_HARDWARE) == inlen) && (inlen == outlen) && (((PBUSENUM_EJECT_HARDWARE)buffer)->Size == inlen)) { Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("Eject called\n")); status= Bus_EjectDevice((PBUSENUM_EJECT_HARDWARE)buffer, fdoData); Irp->IoStatus.Information = outlen; } break; // Added by ILGU HONG 2004_07_05 case IOCTL_DVD_GET_STATUS: { PPDO_DEVICE_DATA pdoData; PBUSENUM_DVD_STATUS pDvdStatusData; // Check Parameter. if((inlen != outlen) || (sizeof(BUSENUM_DVD_STATUS) > inlen)) { status = STATUS_UNSUCCESSFUL ; break; } pDvdStatusData = (PBUSENUM_DVD_STATUS)Irp->AssociatedIrp.SystemBuffer; Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("FDO: IOCTL_DVD_GET_STATUS SlotNumber = %d\n", pDvdStatusData->SlotNo)); pdoData = LookupPdoData(fdoData, pDvdStatusData->SlotNo); if(pdoData == NULL) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_DVD_GET_STATUS No pdo\n")); status = STATUS_UNSUCCESSFUL; break; } else { if(pdoData->LanscsiAdapterPDO.AddTargetData->ucTargetType != DISK_TYPE_DVD) { Bus_KdPrint_Cont (fdoData, BUS_DBG_IOCTL_ERROR, ("IOCTL_DVD_GET_STATUS No DVD Device\n")); status = STATUS_UNSUCCESSFUL; break; } // // redirect to the LanscsiMiniport Device // status = LSBus_IoctlToLSMPDevice( pdoData, LANSCSIMINIPORT_IOCTL_GET_DVD_STATUS, buffer, inlen, buffer, outlen ) ; ObDereferenceObject(pdoData->Self); status = STATUS_SUCCESS; Irp->IoStatus.Information = outlen; } } break; // Added by ILGU HONG 2004_07_05 end #if 0 case IOCTL_VDVD_GET_VDVD_HD_INFO : { PGET_VDVD_HD_INFO pHeader = NULL; if((inlen == outlen) && (sizeof(GET_VDVD_HD_INFO) <= inlen)) { XXprint(4,("Called IOCTL_VDVD_GET_VDVD_HD_INFO\n")); pHeader = (PGET_VDVD_HD_INFO)buffer; switch(pHeader->COM){ case COM_GET_VDVD_COUNT : { if(inlen != sizeof(GET_VDVD_HD_INFO)){ Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; break; } pHeader->COUNT = FindVDVDPdoCount(fdoData); XXprint(4,("COM_GET_VDVD_COUNT %d\n",pHeader->COUNT)); Irp->IoStatus.Information = outlen; status = STATUS_SUCCESS; } break; case COM_GET_VDVD_HD_INFO : { PPDO_DEVICE_DATA pdoData; PDISC_HEADER pDiscHeader = NULL; if(inlen != sizeof(GET_VDVD_HD_INFO)){ Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; break; } pdoData = FindPdoData(fdoData, pHeader->SlotNo); if(pdoData == NULL) { XXprint(4,("COM_GET_VDVD_HD_INFO : Can't find pdo\n")); status = STATUS_UNSUCCESSFUL; break; } pDiscHeader = pdoData->LanscsiAdapter.LogicalTarget[0].Llu[0].Targets[0].TargetConnectionList.pHeader; pHeader->DISC[0].DISCS = pDiscHeader->DISCS; pHeader->DISC[0].ENABLE_DISCS = pDiscHeader->ENABLE_DISCS; pHeader->DISC[0].SlotNo = pHeader->SlotNo; XXprint(4,("COM_GET_VDVD_HD_INFO : #of DISC(%d), #of ENABLED(%d), SlotNo(%d)\n", pHeader->DISC[0].DISCS,pHeader->DISC[0].ENABLE_DISCS, pHeader->DISC[0].SlotNo)); Irp->IoStatus.Information = outlen; status = STATUS_SUCCESS; } break; case COM_GET_VDVD_HD_INFO_ALL: { int size = sizeof(GET_VDVD_HD_INFO) + (sizeof(VDVD_DISC_HD)*(pHeader->COUNT-1)); if(inlen != size){ Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; break; } FindVDVDPdoInfo(fdoData,pHeader); Irp->IoStatus.Information = outlen; status = STATUS_SUCCESS; } break; default: Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; break; } } else{ Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; } } break; case IOCTL_VDVD_GET_VDVD_DISC_INFO: { XXprint(4,("Called IOCTL_VDVD_GET_VDVD_DISC_INFO START\n")); if((inlen == outlen) && (sizeof(GET_VDVD_DISC_INFO) <= inlen)) { PGET_VDVD_DISC_INFO pDiscInfo = (PGET_VDVD_DISC_INFO)buffer; PTARGET_CONNECTION TargetConnection; XXprint(4,("Called IOCTL_VDVD_GET_VDVD_DISC_INFO\n")); switch(pDiscInfo->COM) { case COM_GET_VDVD_DISC_INFO : { PPDO_DEVICE_DATA pdoData; PJUKE_DISC pInfo = NULL; if(inlen != sizeof(GET_VDVD_DISC_INFO)) { Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; break; } pdoData = FindPdoData(fdoData, pDiscInfo->SlotNo); if(pdoData == NULL) { XXprint(4,("COM_GET_VDVD_DISC_INFO : Can't find pdo\n")); status = STATUS_UNSUCCESSFUL; break; } TargetConnection = &(pdoData->LanscsiAdapter.LogicalTarget[0].Llu[0].Targets[0].TargetConnectionList); if(pDiscInfo->DiscNo >= TargetConnection->pHeader->DISCS ) { XXprint(4,("COM_GET_VDVD_DISC_INFO : DISC nub is too big!!\n")); status = STATUS_UNSUCCESSFUL; break; } pInfo = &(TargetConnection->pInfos[pDiscInfo->DiscNo]); pDiscInfo->DISC[0].LOCATION = pInfo->LOCATION; pDiscInfo->DISC[0].START_SEC = pInfo->START_SEC; pDiscInfo->DISC[0].NR_SEC = pInfo->NR_SEC; pDiscInfo->DISC[0].ENABLED = pInfo->ENABLED; Irp->IoStatus.Information = outlen; XXprint(4,("COM_GET_VDVD_DISC_INFO : LOCATION(0x%I64x), START_SEC(0x%I64x), ENABLED(%d)\n", pDiscInfo->DISC[0].LOCATION, pDiscInfo->DISC[0].START_SEC, pDiscInfo->DISC[0].ENABLED)); status = STATUS_SUCCESS; } break; case COM_VDVD_DISC_INFO_ALL: { PPDO_DEVICE_DATA pdoData; PJUKE_DISC pInfo = NULL; ULONG size = sizeof(GET_VDVD_DISC_INFO) + (sizeof(DISC_INFO) * (pDiscInfo->COUNT - 1)); int i = 0; int max = 0; if(inlen != size) { Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; break; } pdoData = FindPdoData(fdoData, pDiscInfo->SlotNo); if(pdoData == NULL) { XXprint(4,("COM_VDVD_DISC_INFO_ALL : Can't find pdo\n")); status = STATUS_UNSUCCESSFUL; break; } TargetConnection = &(pdoData->LanscsiAdapter.LogicalTarget[0].Llu[0].Targets[0].TargetConnectionList); if(pDiscInfo->COUNT > TargetConnection->pHeader->DISCS) { pDiscInfo->COUNT = TargetConnection->pHeader->DISCS; } max = pDiscInfo->COUNT; for(i = 0; i< max; i++){ pInfo = &(TargetConnection->pInfos[i]); pDiscInfo->DISC[i].LOCATION = pInfo->LOCATION; pDiscInfo->DISC[i].START_SEC = pInfo->START_SEC; pDiscInfo->DISC[i].NR_SEC = pInfo->NR_SEC; pDiscInfo->DISC[i].ENABLED = pInfo->ENABLED; XXprint(4,("COM_VDVD_DISC_INFO_ALL(%d) : LOCATION(0x%I64x), START_SEC(0x%I64x), ENABLED(%d)\n", i,pDiscInfo->DISC[i].LOCATION, pDiscInfo->DISC[i].START_SEC, pDiscInfo->DISC[i].ENABLED)); } Irp->IoStatus.Information = outlen; status = STATUS_SUCCESS; } break; default: Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; break; } }else{ Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; } } break; case IOCTL_VDVD_SET_VDVD_BURN: { if((inlen == outlen) && (sizeof(SET_DVD_DISC_BURN) == inlen)) { XXprint(4,("IOCTL_VDVD_SET_VDVD_BURN\n")); Irp->IoStatus.Information = outlen; status = STATUS_SUCCESS; }else{ Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; } } break; case IOCTL_VDVD_CHANGE_VDVD_DISC: { PCHANGE_VDVD_DISC pChange = (PCHANGE_VDVD_DISC)buffer; if((inlen == outlen) && (sizeof(CHANGE_VDVD_DISC) == inlen)) { XXprint(4,("IOCTL_VDVD_CHANGE_VDVD_DISC\n")); switch(pChange->COM) { case COM_GET_CUR_DISC : { PPDO_DEVICE_DATA pdoData; pdoData = FindPdoData(fdoData, pChange->SlotNo); if(pdoData == NULL) { XXprint(4,("COM_GET_CUR_DISC : Can't find pdo\n")); status = STATUS_UNSUCCESSFUL; break; } KeEnterCriticalRegion(); pChange->DiscNo = pdoData->LanscsiAdapter.LogicalTarget[0].Llu[0].Targets[0].TargetConnectionList.cur_disc; Irp->IoStatus.Information = outlen; KeLeaveCriticalRegion(); status = STATUS_SUCCESS; } break; case COM_SET_CUR_DISC : { PPDO_DEVICE_DATA pdoData; PTARGET_CONNECTION TargetConnection; pdoData = FindPdoData(fdoData, pChange->SlotNo); if(pdoData == NULL) { XXprint(4,("COM_GET_CUR_DISC : Can't find pdo\n")); status = STATUS_UNSUCCESSFUL; break; } KeEnterCriticalRegion(); TargetConnection =&(pdoData->LanscsiAdapter.LogicalTarget[0].Llu[0].Targets[0].TargetConnectionList); if(pChange->DiscNo >= TargetConnection->pHeader->DISCS) { Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; KeLeaveCriticalRegion(); break; } TargetConnection->cur_disc = pChange->DiscNo; TargetConnection->IsChanging = TRUE; TargetConnection->CHCount = 0; Irp->IoStatus.Information = outlen; status = STATUS_SUCCESS; KeLeaveCriticalRegion(); } break; default: Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; } }else{ Irp->IoStatus.Information = outlen; status = STATUS_UNSUCCESSFUL; } } break; #endif // 0 - VDVD default: break; // default status is STATUS_INVALID_PARAMETER } Irp->IoStatus.Status = status; if(Irp->UserIosb) *Irp->UserIosb = Irp->IoStatus; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (fdoData); return status; }
NTSTATUS Bus_PDO_QueryDeviceText( __in PPDO_DEVICE_DATA DeviceData, __in PIRP Irp ) /*++ Routine Description: The PnP Manager uses this IRP to get a device's description or location information. This string is displayed in the "found new hardware" pop-up window if no INF match is found for the device. Bus drivers are also encouraged to return location information for their child devices, but this information is optional. Arguments: DeviceData - Pointer to the PDO's device extension. Irp - Pointer to the irp. Return Value: NT STATUS --*/ { PWCHAR buffer; USHORT length; PIO_STACK_LOCATION stack; NTSTATUS status; PAGED_CODE (); stack = IoGetCurrentIrpStackLocation (Irp); switch (stack->Parameters.QueryDeviceText.DeviceTextType) { case DeviceTextDescription: // // Check to see if any filter driver has set any information. // If so then remain silent otherwise add your description. // This string must be localized to support various languages. // switch (stack->Parameters.QueryDeviceText.LocaleId) { case 0x00000407 : // German // Localize the device text. // Until we implement let us fallthru to English default: // for all other languages, fallthru to English case 0x00000409 : // English if (!Irp->IoStatus.Information) { // 10 for number of digits in the serial number length = (USHORT) \ (wcslen(VENDORNAME) + 1 + wcslen(MODEL) + 1 + 10) * sizeof(WCHAR); buffer = ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (buffer == NULL ) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlStringCchPrintfW(buffer, length/sizeof(WCHAR), L"%ws%ws%02d", VENDORNAME, MODEL, DeviceData->SerialNo); Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tDeviceTextDescription :%ws\n", buffer)); Irp->IoStatus.Information = (ULONG_PTR) buffer; } status = STATUS_SUCCESS; break; } // end of LocalID switch break; case DeviceTextLocationInformation: Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tDeviceTextLocationInformation: Unknown\n")); default: status = Irp->IoStatus.Status; break; } return status; }
NTSTATUS Bus_PDO_QueryDeviceId( __in PPDO_DEVICE_DATA DeviceData, __in PIRP Irp ) /*++ Routine Description: Bus drivers must handle BusQueryDeviceID requests for their child devices (child PDOs). Bus drivers can handle requests BusQueryHardwareIDs, BusQueryCompatibleIDs, and BusQueryInstanceID for their child devices. When returning more than one ID for hardware IDs or compatible IDs, a driver should list the IDs in the order of most specific to most general to facilitate choosing the best driver match for the device. Bus drivers should be prepared to handle this IRP for a child device immediately after the device is enumerated. Arguments: DeviceData - Pointer to the PDO's device extension. Irp - Pointer to the irp. Return Value: NT STATUS --*/ { PIO_STACK_LOCATION stack; PWCHAR buffer; ULONG length; NTSTATUS status = STATUS_SUCCESS; ULONG_PTR result; PAGED_CODE (); stack = IoGetCurrentIrpStackLocation (Irp); switch (stack->Parameters.QueryId.IdType) { case BusQueryDeviceID: // // DeviceID is unique string to identify a device. // This can be the same as the hardware ids (which requires a multi // sz). // buffer = DeviceData->HardwareIDs; while (*(buffer++)) { while (*(buffer++)) { ; } } status = RtlULongPtrSub((ULONG_PTR)buffer, (ULONG_PTR)DeviceData->HardwareIDs, &result); if (!NT_SUCCESS(status)) { break; } length = (ULONG)result; buffer = ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory (buffer, DeviceData->HardwareIDs, length); Irp->IoStatus.Information = (ULONG_PTR) buffer; break; case BusQueryInstanceID: // // total length = number (10 digits to be safe (2^32)) + null wide char // length = 11 * sizeof(WCHAR); buffer = ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlStringCchPrintfW(buffer, length/sizeof(WCHAR), L"%02d", DeviceData->SerialNo); Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_INFO, ("\tInstanceID: %ws\n", buffer)); Irp->IoStatus.Information = (ULONG_PTR) buffer; break; case BusQueryHardwareIDs: // // A device has at least one hardware id. // In a list of hardware IDs (multi_sz string) for a device, // DeviceId is the most specific and should be first in the list. // buffer = DeviceData->HardwareIDs; while (*(buffer++)) { while (*(buffer++)) { ; } } status = RtlULongPtrSub((ULONG_PTR)buffer, (ULONG_PTR)DeviceData->HardwareIDs, &result); if (!NT_SUCCESS(status)) { break; } length = (ULONG)result; buffer = ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory (buffer, DeviceData->HardwareIDs, length); Irp->IoStatus.Information = (ULONG_PTR) buffer; break; case BusQueryCompatibleIDs: // // The generic ids for installation of this pdo. // length = BUSENUM_COMPATIBLE_IDS_LENGTH; buffer = ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory (buffer, BUSENUM_COMPATIBLE_IDS, length); Irp->IoStatus.Information = (ULONG_PTR) buffer; break; default: status = Irp->IoStatus.Status; } return status; }
NTSTATUS Bus_PDO_PnP ( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PPDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the Plug & Play system for the devices on the BUS --*/ { NTSTATUS status; PAGED_CODE (); // // NB: Because we are a bus enumerator, we have no one to whom we could // defer these irps. Therefore we do not pass them down but merely // return them. // switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // Here we do what ever initialization and ``turning on'' that is // required to allow others to access this device. // Power up the device. // DeviceData->DevicePowerState = PowerDeviceD0; SET_NEW_PNP_STATE(DeviceData, Started); status = STATUS_SUCCESS; break; case IRP_MN_STOP_DEVICE: // // Here we shut down the device and give up and unmap any resources // we acquired for the device. // SET_NEW_PNP_STATE(DeviceData, Stopped); status = STATUS_SUCCESS; break; case IRP_MN_QUERY_STOP_DEVICE: // // No reason here why we can't stop the device. // If there were a reason we should speak now, because answering success // here may result in a stop device irp. // SET_NEW_PNP_STATE(DeviceData, StopPending); status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: // // The stop was canceled. Whatever state we set, or resources we put // on hold in anticipation of the forthcoming STOP device IRP should be // put back to normal. Someone, in the long list of concerned parties, // has failed the stop device query. // // // First check to see whether you have received cancel-stop // without first receiving a query-stop. This could happen if someone // above us fails a query-stop and passes down the subsequent // cancel-stop. // if (StopPending == DeviceData->DevicePnPState) { // // We did receive a query-stop, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); } status = STATUS_SUCCESS;// We must not fail this IRP. break; case IRP_MN_QUERY_REMOVE_DEVICE: // // Check to see whether the device can be removed safely. // If not fail this request. This is the last opportunity // to do so. // if (DeviceData->ToasterInterfaceRefCount){ // // Somebody is still using our interface. // We must fail remove. // status = STATUS_UNSUCCESSFUL; break; } SET_NEW_PNP_STATE(DeviceData, RemovePending); status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // Clean up a remove that did not go through. // // // First check to see whether you have received cancel-remove // without first receiving a query-remove. This could happen if // someone above us fails a query-remove and passes down the // subsequent cancel-remove. // if (RemovePending == DeviceData->DevicePnPState) { // // We did receive a query-remove, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); } status = STATUS_SUCCESS; // We must not fail this IRP. break; case IRP_MN_SURPRISE_REMOVAL: // // We should stop all access to the device and relinquish all the // resources. Let's just mark that it happened and we will do // the cleanup later in IRP_MN_REMOVE_DEVICE. // SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: // // Present is set to true when the pdo is exposed via PlugIn IOCTL. // It is set to FALSE when a UnPlug IOCTL is received. // We will delete the PDO only after we have reported to the // Plug and Play manager that it's missing. // if (DeviceData->ReportedMissing) { PFDO_DEVICE_DATA fdoData; SET_NEW_PNP_STATE(DeviceData, Deleted); // // Remove the PDO from the list and decrement the count of PDO. // Don't forget to synchronize access to the FDO data. // If the parent FDO is deleted before child PDOs, the ParentFdo // pointer will be NULL. This could happen if the child PDO // is in a SurpriseRemovePending state when the parent FDO // is removed. // if (DeviceData->ParentFdo) { fdoData = FDO_FROM_PDO(DeviceData); ExAcquireFastMutex (&fdoData->Mutex); RemoveEntryList (&DeviceData->Link); fdoData->NumPDOs--; ExReleaseFastMutex (&fdoData->Mutex); } // // Free up resources associated with PDO and delete it. // status = Bus_DestroyPdo(DeviceObject, DeviceData); break; } if (DeviceData->Present) { // // When the device is disabled, the PDO transitions from // RemovePending to NotStarted. We shouldn't delete // the PDO because a) the device is still present on the bus, // b) we haven't reported missing to the PnP manager. // SET_NEW_PNP_STATE(DeviceData, NotStarted); status = STATUS_SUCCESS; } else { ASSERT(DeviceData->Present); status = STATUS_SUCCESS; } break; case IRP_MN_QUERY_CAPABILITIES: // // Return the capabilities of a device, such as whether the device // can be locked or ejected..etc // status = Bus_PDO_QueryDeviceCaps(DeviceData, Irp); break; case IRP_MN_QUERY_ID: // Query the IDs of the device Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryId Type: %s\n", DbgDeviceIDString(IrpStack->Parameters.QueryId.IdType))); status = Bus_PDO_QueryDeviceId(DeviceData, Irp); break; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceRelation Type: %s\n",DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type))); status = Bus_PDO_QueryDeviceRelations(DeviceData, Irp); break; case IRP_MN_QUERY_DEVICE_TEXT: status = Bus_PDO_QueryDeviceText(DeviceData, Irp); break; case IRP_MN_QUERY_RESOURCES: status = Bus_PDO_QueryResources(DeviceData, Irp); break; case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: status = Bus_PDO_QueryResourceRequirements(DeviceData, Irp); break; case IRP_MN_QUERY_BUS_INFORMATION: status = Bus_PDO_QueryBusInformation(DeviceData, Irp); break; case IRP_MN_DEVICE_USAGE_NOTIFICATION: // // OPTIONAL for bus drivers. // This bus drivers any of the bus's descendants // (child device, child of a child device, etc.) do not // contain a memory file namely paging file, dump file, // or hibernation file. So we fail this Irp. // status = STATUS_UNSUCCESSFUL; break; case IRP_MN_EJECT: // // For the device to be ejected, the device must be in the D3 // device power state (off) and must be unlocked // (if the device supports locking). Any driver that returns success // for this IRP must wait until the device has been ejected before // completing the IRP. // DeviceData->Present = FALSE; status = STATUS_SUCCESS; break; case IRP_MN_QUERY_INTERFACE: // // This request enables a driver to export a direct-call // interface to other drivers. A bus driver that exports // an interface must handle this request for its child // devices (child PDOs). // status = Bus_PDO_QueryInterface(DeviceData, Irp); break; case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // // OPTIONAL for bus drivers. // The PnP Manager sends this IRP to a device // stack so filter and function drivers can adjust the // resources required by the device, if appropriate. // //break; //case IRP_MN_QUERY_PNP_DEVICE_STATE: // // OPTIONAL for bus drivers. // The PnP Manager sends this IRP after the drivers for // a device return success from the IRP_MN_START_DEVICE // request. The PnP Manager also sends this IRP when a // driver for the device calls IoInvalidateDeviceState. // // break; //case IRP_MN_READ_CONFIG: //case IRP_MN_WRITE_CONFIG: // // Bus drivers for buses with configuration space must handle // this request for their child devices. Our devices don't // have a config space. // // break; //case IRP_MN_SET_LOCK: // // Our device is not a lockable device // so we don't support this Irp. // // break; default: // //Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE,("\t Not handled\n")); // For PnP requests to the PDO that we do not understand we should // return the IRP WITHOUT setting the status or information fields. // These fields may have already been set by a filter (eg acpi). status = Irp->IoStatus.Status; break; } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }
NTSTATUS Bus_PDO_QueryDeviceCaps( __in PPDO_DEVICE_DATA DeviceData, __in PIRP Irp ) /*++ Routine Description: When a device is enumerated, but before the function and filter drivers are loaded for the device, the PnP Manager sends an IRP_MN_QUERY_CAPABILITIES request to the parent bus driver for the device. The bus driver must set any relevant values in the DEVICE_CAPABILITIES structure and return it to the PnP Manager. Arguments: DeviceData - Pointer to the PDO's device extension. Irp - Pointer to the irp. Return Value: NT STATUS --*/ { PIO_STACK_LOCATION stack; PDEVICE_CAPABILITIES deviceCapabilities; DEVICE_CAPABILITIES parentCapabilities; NTSTATUS status; PAGED_CODE (); stack = IoGetCurrentIrpStackLocation (Irp); // // Get the packet. // deviceCapabilities=stack->Parameters.DeviceCapabilities.Capabilities; // // Set the capabilities. // if (deviceCapabilities->Version != 1 || deviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES)) { return STATUS_UNSUCCESSFUL; } // // Get the device capabilities of the parent // status = Bus_GetDeviceCapabilities( FDO_FROM_PDO(DeviceData)->NextLowerDriver, &parentCapabilities); if (!NT_SUCCESS(status)) { Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceCaps failed\n")); return status; } // // The entries in the DeviceState array are based on the capabilities // of the parent devnode. These entries signify the highest-powered // state that the device can support for the corresponding system // state. A driver can specify a lower (less-powered) state than the // bus driver. For eg: Suppose the toaster bus controller supports // D0, D2, and D3; and the Toaster Device supports D0, D1, D2, and D3. // Following the above rule, the device cannot specify D1 as one of // it's power state. A driver can make the rules more restrictive // but cannot loosen them. // First copy the parent's S to D state mapping // RtlCopyMemory( deviceCapabilities->DeviceState, parentCapabilities.DeviceState, (PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE) ); // // Adjust the caps to what your device supports. // Our device just supports D0 and D3. // deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0; if (deviceCapabilities->DeviceState[PowerSystemSleeping1] != PowerDeviceD0) deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1; if (deviceCapabilities->DeviceState[PowerSystemSleeping2] != PowerDeviceD0) deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; if (deviceCapabilities->DeviceState[PowerSystemSleeping3] != PowerDeviceD0) deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; // We can wake the system from D1 deviceCapabilities->DeviceWake = PowerDeviceD1; // // Specifies whether the device hardware supports the D1 and D2 // power state. Set these bits explicitly. // deviceCapabilities->DeviceD1 = TRUE; // Yes we can deviceCapabilities->DeviceD2 = FALSE; // // Specifies whether the device can respond to an external wake // signal while in the D0, D1, D2, and D3 state. // Set these bits explicitly. // deviceCapabilities->WakeFromD0 = FALSE; deviceCapabilities->WakeFromD1 = TRUE; //Yes we can deviceCapabilities->WakeFromD2 = FALSE; deviceCapabilities->WakeFromD3 = FALSE; // We have no latencies deviceCapabilities->D1Latency = 0; deviceCapabilities->D2Latency = 0; deviceCapabilities->D3Latency = 0; // Ejection supported deviceCapabilities->EjectSupported = TRUE; // // This flag specifies whether the device's hardware is disabled. // The PnP Manager only checks this bit right after the device is // enumerated. Once the device is started, this bit is ignored. // deviceCapabilities->HardwareDisabled = FALSE; // // Out simulated device can be physically removed. // deviceCapabilities->Removable = TRUE; // // Setting it to TURE prevents the warning dialog from appearing // whenever the device is surprise removed. // deviceCapabilities->SurpriseRemovalOK = TRUE; // We don't support system-wide unique IDs. deviceCapabilities->UniqueID = FALSE; // // Specify whether the Device Manager should suppress all // installation pop-ups except required pop-ups such as // "no compatible drivers found." // deviceCapabilities->SilentInstall = FALSE; // // Specifies an address indicating where the device is located // on its underlying bus. The interpretation of this number is // bus-specific. If the address is unknown or the bus driver // does not support an address, the bus driver leaves this // member at its default value of 0xFFFFFFFF. In this example // the location address is same as instance id. // deviceCapabilities->Address = DeviceData->SerialNo; // // UINumber specifies a number associated with the device that can // be displayed in the user interface. // deviceCapabilities->UINumber = DeviceData->SerialNo; return STATUS_SUCCESS; }
NTSTATUS Bus_PDO_QueryInterface( IN PPDO_DEVICE_DATA DeviceData, IN PIRP Irp ) /*++ Routine Description: This requests enables a driver to export proprietary interface to other drivers. This function and the following 5 routines are meant to show how a typical interface is exported. Note: This and many other routines in this sample are not required if someone is using this sample for just device enumeration purpose. Arguments: DeviceData - Pointer to the PDO's device extension. Irp - Pointer to the irp. Return Value: NT STATUS --*/ { PIO_STACK_LOCATION irpStack; PTOASTER_INTERFACE_STANDARD toasterInterfaceStandard; GUID *interfaceType; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_INFO, ("Entered\n")); irpStack = IoGetCurrentIrpStackLocation(Irp); interfaceType = (GUID *) irpStack->Parameters.QueryInterface.InterfaceType; if (IsEqualGUID(interfaceType, (PVOID) &GUID_LANSCSI_INTERFACE_STANDARD)) { if (irpStack->Parameters.QueryInterface.Size < sizeof(TOASTER_INTERFACE_STANDARD) && irpStack->Parameters.QueryInterface.Version != 1) { return STATUS_INVALID_PARAMETER; } toasterInterfaceStandard = (PTOASTER_INTERFACE_STANDARD) irpStack->Parameters.QueryInterface.Interface; toasterInterfaceStandard->Context = DeviceData; // // Fill in the exported functions // toasterInterfaceStandard->InterfaceReference = (PINTERFACE_REFERENCE) Bus_InterfaceReference; toasterInterfaceStandard->InterfaceDereference = (PINTERFACE_DEREFERENCE) Bus_InterfaceDereference; toasterInterfaceStandard->GetCrispinessLevel = Bus_GetCrispinessLevel; toasterInterfaceStandard->SetCrispinessLevel = Bus_SetCrispinessLevel; toasterInterfaceStandard->IsSafetyLockEnabled = Bus_IsSafetyLockEnabled; // // Must take a reference before returning // Bus_InterfaceReference(DeviceData); } else { // // Interface type not supported // status = Irp->IoStatus.Status; } return status; }