//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 1999 // // File: ppa3x.c // //-------------------------------------------------------------------------- #include "pch.h" VOID ParCheckEnableLegacyZipFlag() /*++ Routine Description: Initialize debugging variables from registry; set to default values if anything fails. Arguments: RegistryPath - Root path in registry where we should look Return Value: None --*/ { NTSTATUS Status; RTL_QUERY_REGISTRY_TABLE paramTable[2]; ULONG defaultZipEnabled = 0; PWSTR suffix = L"\\Parameters"; UNICODE_STRING path = {0,0,0}; ULONG length; // // set up table entries for call to RtlQueryRegistryValues // RtlZeroMemory( paramTable, sizeof(paramTable)); paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; paramTable[0].Name = (PWSTR)L"ParEnableLegacyZip"; paramTable[0].EntryContext = &ParEnableLegacyZip; paramTable[0].DefaultType = REG_DWORD; paramTable[0].DefaultData = &defaultZipEnabled; paramTable[0].DefaultLength = sizeof(ULONG); // // leave paramTable[2] as all zeros - this terminates the table // Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, RegistryPath.Buffer, ¶mTable[0], NULL, NULL); ParDump2(PARPNP4, ("ppa3x::ParCheckEnableLegacyZipFlag - status from RtlQueryRegistryValues = %x\n", Status) ); if( !NT_SUCCESS( Status ) ) { // registry read failed, use defaults ParEnableLegacyZip = defaultZipEnabled; return; } if( ParEnableLegacyZip ) { // we found a non-zero value - enable PnP for old parallel port Zip ParDump2(PARPNP1, ("ppa3x::ParCheckEnableLegacyZipFlag - FOUND - ParEnableLegacyZip Flag = %08x\n", ParEnableLegacyZip) ); return; } // // We didn't find the registry flag, maybe it's under the Parameters subkey // // compute the size of the path including the "parameters" suffix ParDump2(PARPNP4, ("ppa3x::ParCheckEnableLegacyZipFlag - RegPath length = %d\n", RegistryPath.Length) ); length = ( sizeof(WCHAR) * wcslen( suffix ) ) + sizeof(UNICODE_NULL); ParDump2(PARPNP4, ("ppa3x::ParCheckEnableLegacyZipFlag - suffix length = %d\n", length) ); length += RegistryPath.Length; ParDump2(PARPNP4, ("ppa3x::ParCheckEnableLegacyZipFlag - total dest length = %d\n", length) ); // build the path path.Buffer = ExAllocatePool( PagedPool, length ); if( NULL == path.Buffer ) { // out of pool, use defaults ParEnableLegacyZip = defaultZipEnabled; return; } RtlZeroMemory( path.Buffer, length ); path.MaximumLength = (USHORT)length; RtlCopyUnicodeString( &path, &RegistryPath ); RtlAppendUnicodeToString( &path, suffix ); ParDump2(PARPNP4, ("ppa3x::ParCheckEnableLegacyZipFlag - path = <%wZ>\n", &path) ); // query at new location in registry Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, path.Buffer, ¶mTable[0], NULL, NULL); RtlFreeUnicodeString( &path ); ParDump2(PARPNP4, ("ppa3x::ParCheckEnableLegacyZipFlag - status from RtlQueryRegistryValues on SubKey = %x\n", Status) ); if( !NT_SUCCESS( Status ) ) { // registry read failed, use defaults ParEnableLegacyZip = defaultZipEnabled; return; } ParDump2(PARPNP1, ("ppa3x::ParCheckEnableLegacyZipFlag - FOUND SubKey ParEnableLegacyZip Flag = %08x\n", ParEnableLegacyZip) ); } BOOLEAN ParLegacyZipCheckDevice( PUCHAR Controller ) { WRITE_PORT_UCHAR( Controller+DCR_OFFSET, (UCHAR)(DCR_NOT_INIT | DCR_AUTOFEED) ); if ( (READ_PORT_UCHAR( Controller+DSR_OFFSET ) & DSR_NOT_FAULT) == DSR_NOT_FAULT ) { WRITE_PORT_UCHAR( Controller+DCR_OFFSET, (UCHAR)DCR_NOT_INIT ); if ( (READ_PORT_UCHAR( Controller+DSR_OFFSET ) & DSR_NOT_FAULT) != DSR_NOT_FAULT ) { // A device was found return TRUE; } } // No device is there return FALSE; } // end PptLegacyZipCheckDevice() PCHAR ParBuildLegacyZipDeviceId() { ULONG size = sizeof(PAR_LGZIP_PSEUDO_1284_ID_STRING) + sizeof(NULL); PCHAR id = ExAllocatePool(PagedPool, size); if( id ) { RtlZeroMemory( id, size ); RtlCopyMemory( id, ParLegacyZipPseudoId, size - sizeof(NULL) ); return id; } else { return NULL; } } PCHAR Par3QueryLegacyZipDeviceId( IN PDEVICE_EXTENSION Extension, OUT PCHAR CallerDeviceIdBuffer, OPTIONAL IN ULONG CallerBufferSize, OUT PULONG DeviceIdSize, IN BOOLEAN bReturnRawString // TRUE == include the 2 size bytes in the returned string // FALSE == discard the 2 size bytes ) { USHORT deviceIdSize; PCHAR deviceIdBuffer; UNREFERENCED_PARAMETER( Extension ); // initialize returned size in case we have an error *DeviceIdSize = 0; deviceIdBuffer = ParBuildLegacyZipDeviceId(); if( !deviceIdBuffer ) { // error, likely out of resources return NULL; } deviceIdSize = (USHORT) strlen(deviceIdBuffer); *DeviceIdSize = deviceIdSize; if( (NULL != CallerDeviceIdBuffer) && (CallerBufferSize >= deviceIdSize) ) { // caller supplied buffer is large enough, use it RtlZeroMemory( CallerDeviceIdBuffer, CallerBufferSize ); RtlCopyMemory( CallerDeviceIdBuffer, deviceIdBuffer, deviceIdSize ); ExFreePool( deviceIdBuffer ); return CallerDeviceIdBuffer; } else { // caller buffer too small, return pointer to our buffer return deviceIdBuffer; } } PDEVICE_OBJECT ParCreateLegacyZipPdo( IN PDEVICE_OBJECT LegacyPodo, UCHAR Dot3Id ) /*++ Routine Description: Create PDO for legacy Zip Drive LegacyPodo - points to the Legacy PODO for the port Return Value: PDEVICE_OBJECT - on success, points to the PDO we create NULL - otherwise --*/ { PDEVICE_EXTENSION legacyExt = LegacyPodo->DeviceExtension; PDRIVER_OBJECT driverObject = LegacyPodo->DriverObject; PDEVICE_OBJECT fdo = legacyExt->ParClassFdo; UNICODE_STRING className = {0,0,NULL}; NTSTATUS status; PCHAR deviceIdString = NULL; ULONG deviceIdLength = 0; PDEVICE_OBJECT newDevObj = NULL; PDEVICE_EXTENSION newDevExt; ULONG idTry = 1; ULONG maxIdTries = 3; BOOLEAN useModifiedClassName = FALSE; UNICODE_STRING modifiedClassName; UNICODE_STRING suffix; UNICODE_STRING dash; WCHAR suffixBuffer[10]; ULONG number = 0; ULONG maxNumber = 256; ULONG newLength; PAGED_CODE(); // // Query for PnP device // while( (NULL == deviceIdString) && (idTry <= maxIdTries) ) { if( Dot3Id == DOT3_LEGACY_ZIP_ID) { ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - calling ParBuildLegacyZipDeviceId()\n")); deviceIdString = ParBuildLegacyZipDeviceId(); if(deviceIdString) { deviceIdLength = strlen( deviceIdString ); } } else{ ASSERT(FALSE); // should never get here deviceIdString = Par3QueryDeviceId(legacyExt, NULL, 0, &deviceIdLength, FALSE, FALSE); } if( NULL == deviceIdString ) { ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - no 1284 ID on try %d\n", idTry) ); KeStallExecutionProcessor(1); ++idTry; } else { ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - devIdString=<%s> on try %d\n", deviceIdString, idTry) ); } } if( !deviceIdString ) { ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - no 1284 ID, bail out\n") ); return NULL; } // // Found PnP Device, create a PDO to represent the device // - create classname // - create device object // - initialize device object and extension // - create symbolic link // - register for PnP TargetDeviceChange notification // // // Create a class name of the form \Device\ParallelN, // ParMakeDotClassNameFromBaseClassName(&legacyExt->ClassName, Dot3Id, &className); if( !className.Buffer ) { // unable to construct ClassName ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - unable to construct ClassName for device\n") ); ExFreePool(deviceIdString); return NULL; } // // create device object // status = ParCreateDevice(driverObject, sizeof(DEVICE_EXTENSION), &className, FILE_DEVICE_PARALLEL_PORT, 0, TRUE, &newDevObj); /// if( status == STATUS_OBJECT_NAME_COLLISION ) { // // old name is still in use, appending a suffix and try again // ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - ParCreateDevice FAILED due to name Collision on <%wZ> - retry\n", &className)); useModifiedClassName = TRUE; suffix.Length = 0; suffix.MaximumLength = sizeof(suffixBuffer); suffix.Buffer = suffixBuffer; RtlInitUnicodeString( &dash, (PWSTR)L"-" ); newLength = className.MaximumLength + 5*sizeof(WCHAR); // L"-XXX" suffix modifiedClassName.Length = 0; modifiedClassName.MaximumLength = (USHORT)newLength; modifiedClassName.Buffer = ExAllocatePool(PagedPool, newLength); if( NULL == modifiedClassName.Buffer ) { ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - ParCreateDevice FAILED - no PagedPool avail\n")); ExFreePool(deviceIdString); RtlFreeUnicodeString( &className ); return NULL; } while( ( status == STATUS_OBJECT_NAME_COLLISION ) && ( number <= maxNumber ) ) { status = RtlIntegerToUnicodeString(number, 10, &suffix); if ( !NT_SUCCESS(status) ) { ExFreePool(deviceIdString); RtlFreeUnicodeString( &className ); RtlFreeUnicodeString( &modifiedClassName ); return NULL; } RtlCopyUnicodeString( &modifiedClassName, &className ); RtlAppendUnicodeStringToString( &modifiedClassName, &dash ); RtlAppendUnicodeStringToString( &modifiedClassName, &suffix ); ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - trying ParCreateDevice with className <%wZ>\n", &modifiedClassName)); status = ParCreateDevice(driverObject, sizeof(DEVICE_EXTENSION), &modifiedClassName, FILE_DEVICE_PARALLEL_PORT, 0, TRUE, &newDevObj); if( NT_SUCCESS( status ) ) { ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - ParCreateDevice returned SUCCESS with className <%wZ>\n", &modifiedClassName)); } else { ++number; } } } /// if( useModifiedClassName ) { // copy modifiedClassName to className RtlFreeUnicodeString( &className ); className = modifiedClassName; ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - copy useModifiedClassName to className - className=<%wZ>\n", &className)); } if( !NT_SUCCESS(status) ) { // unable to create device object, bail out ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - unable to create device object " "className=<%wZ>, bail out - status=%x\n", &className, status) ); ExFreePool(deviceIdString); RtlFreeUnicodeString(&className); ParLogError(fdo->DriverObject, NULL, PhysicalZero, PhysicalZero, 0, 0, 0, 9, STATUS_SUCCESS, PAR_INSUFFICIENT_RESOURCES); return NULL; } else { ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - device created <%wZ>\n", &className)); } // // device object created // newDevExt = newDevObj->DeviceExtension; // // initialize device object and extension // ParInitCommonDOPre(newDevObj, fdo, &className); status = ParInitPdo(newDevObj, (PUCHAR)deviceIdString, deviceIdLength, LegacyPodo, Dot3Id); if( !NT_SUCCESS( status ) ) { // initialization failed, clean up and bail out ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - call to ParInitPdo failed, bail out\n") ); ParAcquireListMutexAndKillDeviceObject(fdo, newDevObj); return NULL; } ParInitCommonDOPost(newDevObj); // // create symbolic link // if( newDevExt->SymbolicLinkName.Buffer ) { ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - ready to create symlink - SymbolicLinkName <%wZ>, ClassName <%wZ>\n", &newDevExt->SymbolicLinkName, &newDevExt->ClassName) ); ParDump2(PARPNP1, (" - Length=%hd, MaximumLength=%hd\n", newDevExt->ClassName.Length, newDevExt->ClassName.MaximumLength) ); ASSERT(newDevExt->ClassName.Length < 100); PAGED_CODE(); status = IoCreateUnprotectedSymbolicLink(&newDevExt->SymbolicLinkName, &newDevExt->ClassName); if ( NT_SUCCESS(status) ) { // note this in our extension for later cleanup ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - SymbolicLinkName -> ClassName = <%wZ> -> <%wZ>\n", &newDevExt->SymbolicLinkName, &newDevExt->ClassName) ); newDevExt->CreatedSymbolicLink = TRUE; // Write symbolic link map info to the registry. status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, (PWSTR)L"PARALLEL PORTS", newDevExt->ClassName.Buffer, REG_SZ, newDevExt->SymbolicLinkName.Buffer, newDevExt->SymbolicLinkName.Length + sizeof(WCHAR)); if (!NT_SUCCESS(status)) { // unable to write map info to registry - continue anyway ParLogError(newDevObj->DriverObject, newDevObj, newDevExt->OriginalController, PhysicalZero, 0, 0, 0, 6, status, PAR_NO_DEVICE_MAP_CREATED); } } else { // unable to create the symbolic link. ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - unable to create SymbolicLink - status = %x\n",status)); newDevExt->CreatedSymbolicLink = FALSE; RtlFreeUnicodeString(&newDevExt->SymbolicLinkName); ParLogError(newDevObj->DriverObject, newDevObj, newDevExt->OriginalController, PhysicalZero, 0, 0, 0, 5, status, PAR_NO_SYMLINK_CREATED); } } else { // extension does not contain a symbolic link name for us to use ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - extension does not contain a symbolic link for us to use\n")); newDevExt->CreatedSymbolicLink = FALSE; } // End-Of-Chain PDO - register for PnP TargetDeviceChange notification status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange, 0, (PVOID)newDevExt->PortDeviceFileObject, driverObject, (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE) ParPnpNotifyTargetDeviceChange, (PVOID)newDevObj, &newDevExt->NotificationHandle); if( !NT_SUCCESS(status) ) { // PnP registration for TargetDeviceChange notification failed, // clean up and bail out ParDump2(PARPNP1, ("ppa3x::ParCreateLegacyZipPdo - PnP registration failed, killing PDO\n") ); ParAcquireListMutexAndKillDeviceObject(fdo, newDevObj); return NULL; } return newDevObj; } PDEVICE_OBJECT ParCreateAddLegacyZipPdo( IN PDEVICE_OBJECT LegacyPodo ) /*++ Create a new PDO for the legacy Zip and add the PDO to the list of PDOs --*/ { PDEVICE_OBJECT newPdo = ParCreateLegacyZipPdo( LegacyPodo, DOT3_LEGACY_ZIP_ID ); if( newPdo ) { ParAddDevObjToFdoList( newPdo ); } return newPdo; } NTSTATUS ParSelectLegacyZip( IN PDEVICE_OBJECT PortDeviceObject ) // // Select Legacy Zip Drive // // Note: Caller must have already Acquired the Port prior to calling this function. // // Returns: STATUS_SUCCESS if drive selected, !STATUS_SUCCESS otherwise // { PARALLEL_1284_COMMAND par1284Command; NTSTATUS status; ParDump2(PARLGZIP, ("rescan::ParSelectLegacyZip - Enter\n")); par1284Command.ID = 0; par1284Command.Port = 0; par1284Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT | PAR_LEGACY_ZIP_DRIVE; status = ParBuildSendInternalIoctl(IOCTL_INTERNAL_SELECT_DEVICE, PortDeviceObject, &par1284Command, sizeof(PARALLEL_1284_COMMAND), NULL, 0, NULL); ParDump2(PARLGZIP, ("rescan::ParSelectLegacyZip - returning status = %x\n", status)); return status; } NTSTATUS ParDeselectLegacyZip( IN PDEVICE_OBJECT PortDeviceObject ) // // Select Legacy Zip Drive // // Note: This function does not Release the port so the Caller still has // the port after this function returns. // // Returns: STATUS_SUCCESS if drive deselected, !STATUS_SUCCESS otherwise // (we don't expect this call to ever fail, but check just // in case) // { PARALLEL_1284_COMMAND par1284Command; NTSTATUS status; ParDump2(PARLGZIP, ("rescan::ParDeselectLegacyZip - Enter\n")); par1284Command.ID = 0; par1284Command.Port = 0; par1284Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT | PAR_LEGACY_ZIP_DRIVE; status = ParBuildSendInternalIoctl(IOCTL_INTERNAL_DESELECT_DEVICE, PortDeviceObject, &par1284Command, sizeof(PARALLEL_1284_COMMAND), NULL, 0, NULL); ParDump2(PARLGZIP, ("rescan::ParDeselectLegacyZip - returning status = %x\n", status)); return status; } BOOLEAN ParZipPresent( PDEVICE_OBJECT LegacyPodo ) // // Legacy Zip is present if we can SELECT it // { BOOLEAN zipPresent = FALSE; PDEVICE_EXTENSION legacyExt = LegacyPodo->DeviceExtension; PDEVICE_OBJECT portDeviceObject = legacyExt->PortDeviceObject; if( NT_SUCCESS( ParSelectLegacyZip( portDeviceObject ) ) ) { ParDeselectLegacyZip( portDeviceObject ); zipPresent = TRUE; } return zipPresent; } VOID ParRescanLegacyZip( IN PPAR_DEVOBJ_STRUCT CurrentNode ) // // Rescan for change in Legacy Zip Drive, update PDO list if change detected // { BOOLEAN hadZip; BOOLEAN foundZip; PDEVICE_OBJECT zipPdo; ParDump2(PARLGZIP, ("rescan::ParRescanLegacyZip - Enter\n")); if( !ParEnableLegacyZip ) { // // legacy zip detection is disabled // ParDump2(PARLGZIP, ("rescan::ParRescanLegacyZip - !ParEnableLegacyZip\n")); // // if we had a Legacy Zip then automatically mark it as hardware gone // zipPdo = CurrentNode->LegacyZipPdo; if( zipPdo ) { // we should never get here, but handle it if we do ParMarkPdoHardwareGone( zipPdo->DeviceExtension ); } return; } // // Check for presence of Legacy Zip - update PDO list if we detect a change // hadZip = (NULL != CurrentNode->LegacyZipPdo); foundZip = ParZipPresent( CurrentNode->LegacyPodo ); ParDump2(PARLGZIP, ("rescan::ParRescanLegacyZip - hadZip=%s, foundZip=%s\n", hadZip?"TRUE":"FALSE", foundZip?"TRUE":"FALSE")); if( foundZip && !hadZip ) { // we found a new Zip - create a PDO for it ParDump2(PARLGZIP, ("rescan::ParRescanLegacyZip - Found new Legacy Zip\n")); ParCreateAddLegacyZipPdo( CurrentNode->LegacyPodo ); } else if( !foundZip && hadZip ) { // our Zip went away - mark PDO as hardware gone ParDump2(PARLGZIP, ("rescan::ParRescanLegacyZip - Had a Legacy Zip but now it's gone\n")); zipPdo = CurrentNode->LegacyZipPdo; ParMarkPdoHardwareGone( zipPdo->DeviceExtension ); } return; }