#include "pch.h" NTSTATUS PptPdoStartDevice( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoQueryRemove( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoRemoveDevice( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoCancelRemove( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoStopDevice( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoQueryStop( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoCancelStop( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoQueryDeviceRelations( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoQueryCapabilities( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoQueryDeviceText( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoQueryId( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoQueryPnpDeviceState( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoQueryBusInformation( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoSurpriseRemoval( PDEVICE_OBJECT DevObj, PIRP Irp ); NTSTATUS PptPdoDefaultPnpHandler( PDEVICE_OBJECT DevObj, PIRP Irp ); PDRIVER_DISPATCH PptPdoPnpDispatchTable[] = { PptPdoStartDevice, // IRP_MN_START_DEVICE 0x00 PptPdoQueryRemove, // IRP_MN_QUERY_REMOVE_DEVICE 0x01 PptPdoRemoveDevice, // IRP_MN_REMOVE_DEVICE 0x02 PptPdoCancelRemove, // IRP_MN_CANCEL_REMOVE_DEVICE 0x03 PptPdoStopDevice, // IRP_MN_STOP_DEVICE 0x04 PptPdoQueryStop, // IRP_MN_QUERY_STOP_DEVICE 0x05 PptPdoCancelStop, // IRP_MN_CANCEL_STOP_DEVICE 0x06 PptPdoQueryDeviceRelations, // IRP_MN_QUERY_DEVICE_RELATIONS 0x07 PptPdoDefaultPnpHandler, // IRP_MN_QUERY_INTERFACE 0x08 PptPdoQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES 0x09 PptPdoDefaultPnpHandler, // IRP_MN_QUERY_RESOURCES 0x0A PptPdoDefaultPnpHandler, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS 0x0B PptPdoQueryDeviceText, // IRP_MN_QUERY_DEVICE_TEXT 0x0C PptPdoDefaultPnpHandler, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D PptPdoDefaultPnpHandler, // no such PnP request 0x0E PptPdoDefaultPnpHandler, // IRP_MN_READ_CONFIG 0x0F PptPdoDefaultPnpHandler, // IRP_MN_WRITE_CONFIG 0x10 PptPdoDefaultPnpHandler, // IRP_MN_EJECT 0x11 PptPdoDefaultPnpHandler, // IRP_MN_SET_LOCK 0x12 PptPdoQueryId, // IRP_MN_QUERY_ID 0x13 PptPdoQueryPnpDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE 0x14 PptPdoQueryBusInformation, // IRP_MN_QUERY_BUS_INFORMATION 0x15 PptPdoDefaultPnpHandler, // IRP_MN_DEVICE_USAGE_NOTIFICATION 0x16 PptPdoSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL 0x17 PptPdoDefaultPnpHandler // IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18 }; NTSTATUS PptPdoStartDevice( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; pdx->DeviceStateFlags = PPT_DEVICE_STARTED; KeSetEvent(&pdx->PauseEvent, 0, FALSE); // unpause any worker thread PptRegGetDeviceParameterDword( Pdo, L"Event22Delay", &pdx->Event22Delay ); // // Register device interface for Legacy LPTx interface PDOs and set the interface active // - succeed start even if the device interface code fails // if( PdoTypeRawPort == pdx->PdoType ) { // This is a legacy interface "raw port" PDO, don't set interface for other types of PDOs NTSTATUS status; BOOLEAN setActive = FALSE; if( NULL == pdx->DeviceInterface.Buffer ) { // Register device interface status = IoRegisterDeviceInterface( Pdo, &GUID_PARCLASS_DEVICE, NULL, &pdx->DeviceInterface ); if( STATUS_SUCCESS == status ) { setActive = TRUE; } } if( (TRUE == setActive) && (FALSE == pdx->DeviceInterfaceState) ) { // set interface active status = IoSetDeviceInterfaceState( &pdx->DeviceInterface, TRUE ); if( STATUS_SUCCESS == status ) { pdx->DeviceInterfaceState = TRUE; } } } return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } NTSTATUS PptPdoQueryRemove( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; // DDpnp2( ("PptPdoQueryRemove\n") ); // PnP won't remove us if there are open handles to us - so WE don't need to check for open handles pdx->DeviceStateFlags |= (PPT_DEVICE_REMOVE_PENDING | PAR_DEVICE_PAUSED); KeClearEvent(&pdx->PauseEvent); // pause any worker thread return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } NTSTATUS PptPdoRemoveDevice( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; NTSTATUS status; pdx->DeviceStateFlags = PAR_DEVICE_PAUSED; KeClearEvent(&pdx->PauseEvent); // pause any worker thread // Set Device Interface inactive for PdoTypeRawPort - other PDO types don't have device interfaces if( PdoTypeRawPort == pdx->PdoType ) { if( (pdx->DeviceInterface.Buffer != NULL) && (TRUE == pdx->DeviceInterfaceState) ) { IoSetDeviceInterfaceState( &pdx->DeviceInterface, FALSE ); pdx->DeviceInterfaceState = FALSE; } } // If we were not reported in the last FDO BusRelations enumeration then it is safe to delete self if( pdx->DeleteOnRemoveOk ) { DD((PCE)pdx,DDT,"PptPdoRemoveDevice - DeleteOnRemoveOk == TRUE - cleaning up self\n"); P4DestroyPdo( Pdo ); status = P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); return status; } else { return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } } NTSTATUS PptPdoCancelRemove( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; pdx->DeviceStateFlags &= ~(PPT_DEVICE_REMOVE_PENDING | PAR_DEVICE_PAUSED); KeSetEvent(&pdx->PauseEvent, 0, FALSE); // unpause any worker thread return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } NTSTATUS PptPdoStopDevice( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; // DDpnp2( ("PptPdoStopDevice\n") ); pdx->DeviceStateFlags |= PAR_DEVICE_PAUSED; pdx->DeviceStateFlags &= ~PPT_DEVICE_STARTED; KeClearEvent(&pdx->PauseEvent); // pause any worker thread return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } NTSTATUS PptPdoQueryStop( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; // DDpnp2( ("PptPdoQueryStop\n") ); pdx->DeviceStateFlags |= (PPT_DEVICE_STOP_PENDING | PAR_DEVICE_PAUSED); KeClearEvent(&pdx->PauseEvent); // pause any worker thread return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } NTSTATUS PptPdoCancelStop( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; pdx->DeviceStateFlags &= ~PPT_DEVICE_STOP_PENDING; KeSetEvent(&pdx->PauseEvent, 0, FALSE); // unpause any worker thread return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } NTSTATUS PptPdoQueryDeviceRelations( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); DEVICE_RELATION_TYPE requestType = irpSp->Parameters.QueryDeviceRelations.Type; NTSTATUS status = Irp->IoStatus.Status; ULONG_PTR info = Irp->IoStatus.Information; if( TargetDeviceRelation == requestType ) { PDEVICE_RELATIONS devRel = ExAllocatePool( PagedPool, sizeof(DEVICE_RELATIONS) ); if( devRel ) { devRel->Count = 1; ObReferenceObject( Pdo ); devRel->Objects[0] = Pdo; status = STATUS_SUCCESS; info = (ULONG_PTR)devRel; } else { status = STATUS_NO_MEMORY; } } else { DD((PCE)pdx,DDT,"PptPdoQueryDeviceRelations - unhandled request Type = %d\n",requestType); } return P4CompleteRequest( Irp, status, info ); } NTSTATUS PptPdoQueryCapabilities( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); irpSp->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE; if( PdoTypeRawPort == pdx->PdoType ) { // This is the legacy LPTx interface device - no driver should // ever be installed for this so don't bother the user with a popup. irpSp->Parameters.DeviceCapabilities.Capabilities->SilentInstall = TRUE; } return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } NTSTATUS PptPdoQueryDeviceText( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); PWSTR buffer = NULL; ULONG bufLen; ULONG_PTR info; NTSTATUS status; if( DeviceTextDescription == irpSp->Parameters.QueryDeviceText.DeviceTextType ) { // // DeviceTextDescription is: catenation of MFG++MDL // if( pdx->Mfg && pdx->Mdl ) { // // Construct UNICODE string to return from the ANSI strings // that we have in our extension // // need space for and terminating NULL // bufLen = strlen( (const PCHAR)pdx->Mfg ) + strlen( (const PCHAR)pdx->Mdl ) + 2 * sizeof(CHAR); bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) ); buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen ); if( buffer ) { RtlZeroMemory( buffer, bufLen ); _snwprintf( buffer, bufLen/2, L"%S %S", pdx->Mfg, pdx->Mdl ); DD((PCE)pdx,DDT,"PptPdoQueryDeviceText - DeviceTextDescription - <%S>\n",buffer); status = STATUS_SUCCESS; } else { status = STATUS_NO_MEMORY; } } else { DD((PCE)pdx,DDE,"PptPdoQueryDeviceText - MFG and/or MDL NULL - FAIL DeviceTextDescription\n"); status = STATUS_UNSUCCESSFUL; } } else if( DeviceTextLocationInformation == irpSp->Parameters.QueryDeviceText.DeviceTextType ) { // // DeviceTextLocationInformation is LPTx or LPTx.y (note that // this is also the symlink name minus the L"\\DosDevices\\" // prefix) // if( pdx->Location ) { bufLen = strlen( (const PCHAR)pdx->Location ) + sizeof(CHAR); bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) ); buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen ); if( buffer ) { RtlZeroMemory( buffer, bufLen ); _snwprintf( buffer, bufLen/2, L"%S", pdx->Location ); DD((PCE)pdx,DDT,"PptPdoQueryDeviceText - DeviceTextLocationInformation - <%S>\n",buffer); status = STATUS_SUCCESS; } else { status = STATUS_NO_MEMORY; } } else { DD((PCE)pdx,DDE,"PptPdoQueryDeviceText - Location NULL - FAIL DeviceTextLocationInformation\n"); status = STATUS_UNSUCCESSFUL; } } else { // Unknown DeviceTextType - don't change anything in IRP buffer = NULL; status = Irp->IoStatus.Status; } if( (STATUS_SUCCESS == status) && buffer ) { info = (ULONG_PTR)buffer; } else { if( buffer ) { ExFreePool( buffer ); } info = Irp->IoStatus.Information; } return P4CompleteRequest( Irp, status, info ); } NTSTATUS PptPdoQueryId( PDEVICE_OBJECT Pdo, PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); PWSTR buffer = NULL; ULONG bufLen; NTSTATUS status; ULONG_PTR info; switch( irpSp->Parameters.QueryId.IdType ) { case BusQueryDeviceID : // // DeviceID generation: catenate MFG and MDL fields from the // IEEE 1284 device ID string (no space between fields), append // MFG+MDL catenation to LPTENUM\ prefix // if( pdx->Mfg && pdx->Mdl ) { // // Construct UNICODE string to return from the ANSI strings // that we have in our extension // CHAR prefix[] = "LPTENUM\\"; // sizeof(prefix) provides space for NULL terminator bufLen = sizeof(prefix) + strlen( (const PCHAR)pdx->Mfg ) + strlen( (const PCHAR)pdx->Mdl ); bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) ); buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen ); if( buffer ) { RtlZeroMemory( buffer, bufLen ); _snwprintf( buffer, bufLen/2, L"%S%S%S", prefix, pdx->Mfg, pdx->Mdl ); P4SanitizeId( buffer ); // replace any illegal characters with underscore DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryDeviceID - <%S>\n",buffer); status = STATUS_SUCCESS; } else { status = STATUS_NO_MEMORY; } } else { DD((PCE)pdx,DDE,"PptPdoQueryId - MFG and/or MDL NULL - FAIL BusQueryDeviceID\n"); status = STATUS_UNSUCCESSFUL; } break; case BusQueryInstanceID : // // InstanceID is LPTx or LPTx.y Location of the device (note // that this is also the symlink name minus the // \DosDevices\ prefix) // if( pdx->Location ) { // // Construct UNICODE string to return from the ANSI string // that we have in our extension // bufLen = strlen( (const PCHAR)pdx->Location ) + sizeof(CHAR); bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) ); buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen ); if( buffer ) { RtlZeroMemory( buffer, bufLen ); _snwprintf( buffer, bufLen/2, L"%S", pdx->Location ); P4SanitizeId( buffer ); // replace any illegal characters with underscore DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryInstanceID - <%S>\n",buffer); status = STATUS_SUCCESS; } else { status = STATUS_NO_MEMORY; } } else { DD((PCE)pdx,DDE,"PptPdoQueryId - Location NULL - FAIL BusQueryInstanceID\n"); status = STATUS_UNSUCCESSFUL; } break; case BusQueryHardwareIDs : // // HardwareID generation: // // Generate MfgMdlCrc string as follows: // 1) catenate MFG and MDL fields // 2) generate checksum on MFG+MDL catenation // 3) truncate MFG+MDL catenation // 4) append checksum // // Return as HardwareID MULTI_SZ: LPTENUM\%MfgMdlCrc% followed by bare %MfgMdlCrc% // // example: LPTENUM\Acme_CorpFooBarPrint3FA5\0Acme_CorpFooBarPrint3FA5\0\0 // if( pdx->Mfg && pdx->Mdl ) { ULONG lengthOfMfgMdlBuffer = strlen( (const PCHAR)pdx->Mfg ) + strlen( (const PCHAR)pdx->Mdl ) + sizeof(CHAR); PCHAR mfgMdlBuffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, lengthOfMfgMdlBuffer ); if( mfgMdlBuffer ) { const CHAR prefix[] = "LPTENUM\\"; const ULONG mfgMdlTruncationLimit = 20; const ULONG checksumLength = 4; USHORT checksum; // 1) catenate MFG and MDL fields and 2) generate checksum on catenation RtlZeroMemory( mfgMdlBuffer, lengthOfMfgMdlBuffer ); _snprintf( mfgMdlBuffer, lengthOfMfgMdlBuffer, "%s%s", pdx->Mfg, pdx->Mdl ); GetCheckSum( mfgMdlBuffer, (USHORT)strlen(mfgMdlBuffer), &checksum ); // // alloc buffer large enough for result returned to PnP, // include space for 4 checksum chars (twice) + 1 NULL between strings + 2 termination chars (MULTI_SZ) // bufLen = strlen( prefix ) + 2 * mfgMdlTruncationLimit + 2 * checksumLength + 3 * sizeof(CHAR); bufLen *= (sizeof(WCHAR)/sizeof(CHAR)); // convert to size needed for WCHARs buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen ); if( buffer ) { ULONG wcharsWritten; RtlZeroMemory( buffer, bufLen ); // Construct the HardwareID MULTI_SZ: // // Write the first Hardware ID: LPTENUM\xxx wcharsWritten = _snwprintf( buffer, bufLen/2, L"%S%.20S%04X", prefix, mfgMdlBuffer, checksum ); // Skip forward a UNICODE_NULL past the end of the first Hardware ID and write the second // Hardware ID: bare xxx _snwprintf( buffer+wcharsWritten+1, bufLen/2-wcharsWritten-1, L"%.20S%04X", mfgMdlBuffer, checksum ); ExFreePool( mfgMdlBuffer ); DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryHardwareIDs 1st ID - <%S>\n",buffer); DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryHardwareIDs 2nd ID - <%S>\n",buffer+wcslen(buffer)+1); // replace any illegal characters with underscore, preserve UNICODE_NULLs P4SanitizeMultiSzId( buffer, bufLen/2 ); status = STATUS_SUCCESS; // printing looks for PortName in the devnode - Pdo's Location is the PortName P4WritePortNameToDevNode( Pdo, pdx->Location ); } else { ExFreePool( mfgMdlBuffer ); DD((PCE)pdx,DDT,"PptPdoQueryId - no pool for buffer - FAIL BusQueryHardwareIDs\n"); status = STATUS_INSUFFICIENT_RESOURCES; } } else { DD((PCE)pdx,DDT,"PptPdoQueryId - no pool for mfgMdlBuffer - FAIL BusQueryHardwareIDs\n"); status = STATUS_INSUFFICIENT_RESOURCES; } } else { DD((PCE)pdx,DDT,"PptPdoQueryId - MFG and/or MDL NULL - FAIL BusQueryHardwareIDs\n"); status = STATUS_UNSUCCESSFUL; } // // Save the MFG and MDL fields from the IEEE 1284 Device ID string under the // "\Device Parameters" key so that user mode code (e.g., printing) // can retrieve the fields. // PptWriteMfgMdlToDevNode( Pdo, pdx->Mfg, pdx->Mdl ); break; case BusQueryCompatibleIDs : // // Printing group specified that we not report compatible IDs - 2000-04-24 // #define PPT_REPORT_COMPATIBLE_IDS 0 #if (0 == PPT_REPORT_COMPATIBLE_IDS) DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryCompatibleIDs - query not supported\n"); status = Irp->IoStatus.Status; #else // // Return the compatible ID string reported by device, if any // if( pdx->Cid ) { // // Construct UNICODE string to return from the ANSI string // that we have in our extension // bufLen = strlen( pdx->Cid ) + 2 * sizeof(CHAR); bufLen *= ( sizeof(WCHAR)/sizeof(CHAR) ); buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, bufLen ); if( buffer ) { RtlZeroMemory( buffer, bufLen ); _snwprintf( buffer, bufLen/2, L"%S", pdx->Cid ); DD((PCE)pdx,DDT,"PptPdoQueryId - BusQueryCompatibleIDs - <%S>\n",buffer); // // convert the 1284 ID representation of a Compatible ID seperator (',') into // a MULTI_SZ - (i.e., scan the WSTR and replace any L',' with L'\0') // { PWCHAR p = buffer; while( *p ) { if( L',' == *p ) { *p = L'\0'; } ++p; } } // replace any illegal characters with underscore, preserve UNICODE_NULLs P4SanitizeMultiSzId( buffer, bufLen/2 ); status = STATUS_SUCCESS; } else { DD((PCE)pdx,DDT,"PptPdoQueryId - no pool - FAIL BusQueryCompatibleIDs\n"); status = STATUS_INSUFFICIENT_RESOURCES; } } else { DD((PCE)pdx,DDT,"PptPdoQueryId - CID NULL - BusQueryCompatibleIDs\n"); status = Irp->IoStatus.Status; } #endif // #if (0 == PPT_REPORT_COMPATIBLE_IDS) break; default : // // Invalid irpSp->Parameters.QueryId.IdType // DD((PCE)pdx,DDT,"PptPdoQueryId - unrecognized irpSp->Parameters.QueryId.IdType\n"); status = Irp->IoStatus.Status; } if( (STATUS_SUCCESS == status) && buffer ) { info = (ULONG_PTR)buffer; } else { if( buffer ) { ExFreePool( buffer ); } info = Irp->IoStatus.Information; } return P4CompleteRequest( Irp, status, info ); } NTSTATUS PptPdoQueryPnpDeviceState( PDEVICE_OBJECT Pdo, PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; NTSTATUS status = Irp->IoStatus.Status; ULONG_PTR info = Irp->IoStatus.Information; if( PdoTypeRawPort == pdx->PdoType ) { info |= PNP_DEVICE_DONT_DISPLAY_IN_UI; status = STATUS_SUCCESS; } return P4CompleteRequest( Irp, status, info ); } NTSTATUS PptPdoQueryBusInformation( PDEVICE_OBJECT Pdo, PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; NTSTATUS status; ULONG_PTR info; if( pdx->PdoType != PdoTypeRawPort ) { // // we are a "real" device enumerated by parport - report BusInformation // PPNP_BUS_INFORMATION pBusInfo = ExAllocatePool( PagedPool, sizeof(PNP_BUS_INFORMATION) ); if( pBusInfo ) { pBusInfo->BusTypeGuid = GUID_BUS_TYPE_LPTENUM; pBusInfo->LegacyBusType = PNPBus; pBusInfo->BusNumber = 0; status = STATUS_SUCCESS; info = (ULONG_PTR)pBusInfo; } else { // no pool status = STATUS_NO_MEMORY; info = Irp->IoStatus.Information; } } else { // // we are a pseudo device (Legacy Interface Raw Port PDO LPTx) - don't report BusInformation // status = Irp->IoStatus.Status; info = Irp->IoStatus.Information; } return P4CompleteRequest( Irp, status, info ); } NTSTATUS PptPdoSurpriseRemoval( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; // Set Device Interface inactive for PdoTypeRawPort - other PDO types don't have device interfaces if( PdoTypeRawPort == pdx->PdoType ) { if( (pdx->DeviceInterface.Buffer != NULL) && (TRUE == pdx->DeviceInterfaceState) ) { IoSetDeviceInterfaceState( &pdx->DeviceInterface, FALSE ); pdx->DeviceInterfaceState = FALSE; } } pdx->DeviceStateFlags |= PPT_DEVICE_SURPRISE_REMOVED; KeClearEvent(&pdx->PauseEvent); // pause any worker thread return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } NTSTATUS PptPdoDefaultPnpHandler( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { UNREFERENCED_PARAMETER( Pdo ); return P4CompleteRequest( Irp, Irp->IoStatus.Status, Irp->IoStatus.Information ); } NTSTATUS PptPdoPnp( IN PDEVICE_OBJECT Pdo, IN PIRP Irp ) { PPDO_EXTENSION pdx = Pdo->DeviceExtension; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); // diagnostic PptPdoDumpPnpIrpInfo( Pdo, Irp); if( pdx->DeviceStateFlags & PPT_DEVICE_DELETE_PENDING ) { DD((PCE)pdx,DDT,"PptPdoPnp - PPT_DEVICE_DELETE_PENDING - bailing out\n"); return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information ); } if( irpSp->MinorFunction < arraysize(PptPdoPnpDispatchTable) ) { return PptPdoPnpDispatchTable[ irpSp->MinorFunction ]( Pdo, Irp ); } else { DD((PCE)pdx,DDT,"PptPdoPnp - Default Handler - IRP_MN = %x\n",irpSp->MinorFunction); return PptPdoDefaultPnpHandler( Pdo, Irp ); } }