Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5870 lines
188 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. floppy.c
  5. Abstract:
  6. This is Intel 82077 (aka MIPS) floppy diskette driver for NT.
  7. Environment:
  8. Kernel mode only.
  9. --*/
  10. //
  11. // Include files.
  12. //
  13. #include "stdio.h"
  14. #include "ntddk.h" // various NT definitions
  15. #include "ntdddisk.h" // disk device driver I/O control codes
  16. #include "ntddfdc.h" // fdc I/O control codes and parameters
  17. #include "initguid.h"
  18. #include "ntddstor.h"
  19. #include "mountdev.h"
  20. #include "acpiioct.h"
  21. #include <flo_data.h> // this driver's data declarations
  22. //
  23. // This is the actual definition of FloppyDebugLevel.
  24. // Note that it is only defined if this is a "debug"
  25. // build.
  26. //
  27. #if DBG
  28. extern ULONG FloppyDebugLevel = 0;
  29. #endif
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(INIT,DriverEntry)
  32. #pragma alloc_text(PAGE,FloppyAddDevice)
  33. #pragma alloc_text(PAGE,FloppyPnp)
  34. #pragma alloc_text(PAGE,FloppyPower)
  35. #pragma alloc_text(PAGE,FlConfigCallBack)
  36. #pragma alloc_text(PAGE,FlInitializeControllerHardware)
  37. #pragma alloc_text(PAGE,FlInterpretError)
  38. #pragma alloc_text(PAGE,FlDatarateSpecifyConfigure)
  39. #pragma alloc_text(PAGE,FlRecalibrateDrive)
  40. #pragma alloc_text(PAGE,FlDetermineMediaType)
  41. #pragma alloc_text(PAGE,FlCheckBootSector)
  42. #pragma alloc_text(PAGE,FlConsolidateMediaTypeWithBootSector)
  43. #pragma alloc_text(PAGE,FlIssueCommand)
  44. #pragma alloc_text(PAGE,FlReadWriteTrack)
  45. #pragma alloc_text(PAGE,FlReadWrite)
  46. #pragma alloc_text(PAGE,FlFormat)
  47. #pragma alloc_text(PAGE,FlFinishOperation)
  48. #pragma alloc_text(PAGE,FlStartDrive)
  49. #pragma alloc_text(PAGE,FloppyThread)
  50. #pragma alloc_text(PAGE,FlAllocateIoBuffer)
  51. #pragma alloc_text(PAGE,FlFreeIoBuffer)
  52. #pragma alloc_text(PAGE,FloppyCreateClose)
  53. #pragma alloc_text(PAGE,FloppyDeviceControl)
  54. #pragma alloc_text(PAGE,FloppyReadWrite)
  55. #pragma alloc_text(PAGE,FlCheckFormatParameters)
  56. #pragma alloc_text(PAGE,FlFdcDeviceIo)
  57. #pragma alloc_text(PAGE,FloppySystemControl)
  58. #endif
  59. #ifdef POOL_TAGGING
  60. #ifdef ExAllocatePool
  61. #undef ExAllocatePool
  62. #endif
  63. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'polF')
  64. #endif
  65. // #define KEEP_COUNTERS 1
  66. #ifdef KEEP_COUNTERS
  67. ULONG FloppyUsedSeek = 0;
  68. ULONG FloppyNoSeek = 0;
  69. #endif
  70. //
  71. // Used for paging the driver.
  72. //
  73. ULONG PagingReferenceCount = 0;
  74. PFAST_MUTEX PagingMutex = NULL;
  75. NTSTATUS
  76. DriverEntry(
  77. IN PDRIVER_OBJECT DriverObject,
  78. IN PUNICODE_STRING RegistryPath
  79. )
  80. /*++
  81. Routine Description:
  82. This routine is the driver's entry point, called by the I/O system
  83. to load the driver. The driver's entry points are initialized and
  84. a mutex to control paging is initialized.
  85. In DBG mode, this routine also examines the registry for special
  86. debug parameters.
  87. Arguments:
  88. DriverObject - a pointer to the object that represents this device
  89. driver.
  90. RegistryPath - a pointer to this driver's key in the Services tree.
  91. Return Value:
  92. STATUS_SUCCESS unless we can't allocate a mutex.
  93. --*/
  94. {
  95. NTSTATUS ntStatus = STATUS_SUCCESS;
  96. #if DBG
  97. //
  98. // We use this to query into the registry as to whether we
  99. // should break at driver entry.
  100. //
  101. RTL_QUERY_REGISTRY_TABLE paramTable[3];
  102. ULONG zero = 0;
  103. ULONG one = 1;
  104. ULONG debugLevel = 0;
  105. ULONG shouldBreak = 0;
  106. ULONG notConfigurable = 0;
  107. PWCHAR path;
  108. ULONG pathLength;
  109. //
  110. // Since the registry path parameter is a "counted" UNICODE string, it
  111. // might not be zero terminated. For a very short time allocate memory
  112. // to hold the registry path zero terminated so that we can use it to
  113. // delve into the registry.
  114. //
  115. // NOTE NOTE!!!! This is not an architected way of breaking into
  116. // a driver. It happens to work for this driver because the author
  117. // likes to do things this way.
  118. //
  119. pathLength = RegistryPath->Length + sizeof(WCHAR);
  120. if ( path = ExAllocatePool(PagedPool, pathLength) ) {
  121. RtlZeroMemory( &paramTable[0], sizeof(paramTable) );
  122. RtlZeroMemory( path, pathLength);
  123. RtlMoveMemory( path, RegistryPath->Buffer, RegistryPath->Length );
  124. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  125. paramTable[0].Name = L"BreakOnEntry";
  126. paramTable[0].EntryContext = &shouldBreak;
  127. paramTable[0].DefaultType = REG_DWORD;
  128. paramTable[0].DefaultData = &zero;
  129. paramTable[0].DefaultLength = sizeof(ULONG);
  130. paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  131. paramTable[1].Name = L"DebugLevel";
  132. paramTable[1].EntryContext = &debugLevel;
  133. paramTable[1].DefaultType = REG_DWORD;
  134. paramTable[1].DefaultData = &zero;
  135. paramTable[1].DefaultLength = sizeof(ULONG);
  136. if (!NT_SUCCESS(RtlQueryRegistryValues(
  137. RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  138. path,
  139. &paramTable[0],
  140. NULL,
  141. NULL))) {
  142. shouldBreak = 0;
  143. debugLevel = 0;
  144. }
  145. ExFreePool( path );
  146. }
  147. FloppyDebugLevel = debugLevel;
  148. if ( shouldBreak ) {
  149. DbgBreakPoint();
  150. }
  151. #endif
  152. FloppyDump(FLOPSHOW, ("Floppy: DriverEntry\n") );
  153. //
  154. // Initialize the driver object with this driver's entry points.
  155. //
  156. DriverObject->MajorFunction[IRP_MJ_CREATE] = FloppyCreateClose;
  157. DriverObject->MajorFunction[IRP_MJ_CLOSE] = FloppyCreateClose;
  158. DriverObject->MajorFunction[IRP_MJ_READ] = FloppyReadWrite;
  159. DriverObject->MajorFunction[IRP_MJ_WRITE] = FloppyReadWrite;
  160. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FloppyDeviceControl;
  161. DriverObject->MajorFunction[IRP_MJ_PNP] = FloppyPnp;
  162. DriverObject->MajorFunction[IRP_MJ_POWER] = FloppyPower;
  163. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = FloppySystemControl;
  164. DriverObject->DriverUnload = FloppyUnload;
  165. DriverObject->DriverExtension->AddDevice = FloppyAddDevice;
  166. //
  167. // Allocate and initialize a mutex for paging the driver.
  168. //
  169. PagingMutex = ExAllocatePool( NonPagedPool, sizeof(FAST_MUTEX) );
  170. if ( PagingMutex == NULL ) {
  171. return STATUS_INSUFFICIENT_RESOURCES;
  172. }
  173. ExInitializeFastMutex(PagingMutex);
  174. //
  175. // Now page out the driver and wait for a call to FloppyAddDevice.
  176. //
  177. MmPageEntireDriver(DriverEntry);
  178. DriveMediaLimits = &_DriveMediaLimits[0];
  179. DriveMediaConstants = &_DriveMediaConstants[0];
  180. return ntStatus;
  181. }
  182. VOID
  183. FloppyUnload(
  184. IN PDRIVER_OBJECT DriverObject
  185. )
  186. /*++
  187. Routine Description:
  188. Unload the driver from the system. The paging mutex is freed before
  189. final unload.
  190. Arguments:
  191. DriverObject - a pointer to the object that represents this device
  192. driver.
  193. Return Value:
  194. none
  195. --*/
  196. {
  197. FloppyDump( FLOPSHOW, ("FloppyUnload:\n"));
  198. //
  199. // The device object(s) should all be gone by now.
  200. //
  201. ASSERT( DriverObject->DeviceObject == NULL );
  202. //
  203. // Free the paging mutex that was allocated in DriverEntry.
  204. //
  205. if (PagingMutex != NULL) {
  206. ExFreePool(PagingMutex);
  207. PagingMutex = NULL;
  208. }
  209. return;
  210. }
  211. NTSTATUS
  212. FloppyAddDevice(
  213. IN PDRIVER_OBJECT DriverObject,
  214. IN OUT PDEVICE_OBJECT PhysicalDeviceObject
  215. )
  216. /*++
  217. Routine Description:
  218. This routine is the driver's pnp add device entry point. It is
  219. called by the pnp manager to initialize the driver.
  220. Add device creates and initializes a device object for this FDO and
  221. attaches to the underlying PDO.
  222. Arguments:
  223. DriverObject - a pointer to the object that represents this device
  224. driver.
  225. PhysicalDeviceObject - a pointer to the underlying PDO to which this
  226. new device will attach.
  227. Return Value:
  228. If we successfully create a device object, STATUS_SUCCESS is
  229. returned. Otherwise, return the appropriate error code.
  230. --*/
  231. {
  232. NTSTATUS ntStatus;
  233. PDEVICE_OBJECT deviceObject;
  234. PDISKETTE_EXTENSION disketteExtension;
  235. FDC_INFO fdcInfo;
  236. UCHAR arcNameBuffer[256];
  237. STRING arcNameString;
  238. WCHAR deviceNameBuffer[20];
  239. UNICODE_STRING deviceName;
  240. ntStatus = STATUS_SUCCESS;
  241. FloppyDump( FLOPSHOW, ("FloppyAddDevice: CreateDeviceObject\n"));
  242. //
  243. // Get some device information from the underlying PDO.
  244. //
  245. fdcInfo.BufferCount = 0;
  246. fdcInfo.BufferSize = 0;
  247. ntStatus = FlFdcDeviceIo( PhysicalDeviceObject,
  248. IOCTL_DISK_INTERNAL_GET_FDC_INFO,
  249. &fdcInfo );
  250. if ( NT_SUCCESS(ntStatus) ) {
  251. USHORT i = 0;
  252. //
  253. // Create a device. We will use the first available device name for
  254. // this device.
  255. //
  256. do {
  257. swprintf( deviceNameBuffer, L"\\Device\\Floppy%d", i++ );
  258. RtlInitUnicodeString( &deviceName, deviceNameBuffer );
  259. ntStatus = IoCreateDevice( DriverObject,
  260. sizeof( DISKETTE_EXTENSION ),
  261. &deviceName,
  262. FILE_DEVICE_DISK,
  263. (FILE_REMOVABLE_MEDIA |
  264. FILE_FLOPPY_DISKETTE |
  265. FILE_DEVICE_SECURE_OPEN),
  266. FALSE,
  267. &deviceObject );
  268. } while ( ntStatus == STATUS_OBJECT_NAME_COLLISION );
  269. if ( NT_SUCCESS(ntStatus) ) {
  270. disketteExtension = (PDISKETTE_EXTENSION)deviceObject->DeviceExtension;
  271. //
  272. // Save the device name.
  273. //
  274. FloppyDump( FLOPSHOW | FLOPPNP,
  275. ("FloppyAddDevice - Device Object Name - %S\n", deviceNameBuffer) );
  276. disketteExtension->DeviceName.Buffer = ExAllocatePool( PagedPool | POOL_COLD_ALLOCATION, deviceName.Length );
  277. if ( disketteExtension->DeviceName.Buffer == NULL ) {
  278. IoDeleteDevice( deviceObject );
  279. return STATUS_INSUFFICIENT_RESOURCES;
  280. }
  281. disketteExtension->DeviceName.Length = 0;
  282. disketteExtension->DeviceName.MaximumLength = deviceName.Length;
  283. RtlCopyUnicodeString( &disketteExtension->DeviceName, &deviceName );
  284. IoGetConfigurationInformation()->FloppyCount++;
  285. //
  286. // Create a symbolic link from the disk name to the corresponding
  287. // ARC name, to be used if we're booting off the disk. This will
  288. // if it's not system initialization time; that's fine. The ARC
  289. // name looks something like \ArcName\multi(0)disk(0)rdisk(0).
  290. //
  291. sprintf( arcNameBuffer,
  292. "%s(%d)disk(%d)fdisk(%d)",
  293. "\\ArcName\\multi",
  294. fdcInfo.BusNumber,
  295. fdcInfo.ControllerNumber,
  296. fdcInfo.PeripheralNumber );
  297. RtlInitString( &arcNameString, arcNameBuffer );
  298. ntStatus = RtlAnsiStringToUnicodeString( &disketteExtension->ArcName,
  299. &arcNameString,
  300. TRUE );
  301. if ( NT_SUCCESS( ntStatus ) ) {
  302. IoAssignArcName( &disketteExtension->ArcName, &deviceName );
  303. }
  304. deviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
  305. if ( deviceObject->AlignmentRequirement < FILE_WORD_ALIGNMENT ) {
  306. deviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
  307. }
  308. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  309. disketteExtension->DriverObject = DriverObject;
  310. // Set the PDO for use with PlugPlay functions
  311. disketteExtension->UnderlyingPDO = PhysicalDeviceObject;
  312. FloppyDump( FLOPSHOW,
  313. ("FloppyAddDevice: Attaching %p to %p\n",
  314. deviceObject,
  315. PhysicalDeviceObject));
  316. disketteExtension->TargetObject =
  317. IoAttachDeviceToDeviceStack( deviceObject,
  318. PhysicalDeviceObject );
  319. FloppyDump( FLOPSHOW,
  320. ("FloppyAddDevice: TargetObject = %p\n",
  321. disketteExtension->TargetObject) );
  322. KeInitializeSemaphore( &disketteExtension->RequestSemaphore,
  323. 0L,
  324. MAXLONG );
  325. ExInitializeFastMutex( &disketteExtension->PowerDownMutex );
  326. KeInitializeSpinLock( &disketteExtension->ListSpinLock );
  327. ExInitializeFastMutex( &disketteExtension->ThreadReferenceMutex );
  328. ExInitializeFastMutex( &disketteExtension->HoldNewReqMutex );
  329. InitializeListHead( &disketteExtension->ListEntry );
  330. disketteExtension->ThreadReferenceCount = -1;
  331. disketteExtension->IsStarted = FALSE;
  332. disketteExtension->IsRemoved = FALSE;
  333. disketteExtension->HoldNewRequests = FALSE;
  334. InitializeListHead( &disketteExtension->NewRequestQueue );
  335. KeInitializeSpinLock( &disketteExtension->NewRequestQueueSpinLock );
  336. KeInitializeSpinLock( &disketteExtension->FlCancelSpinLock );
  337. KeInitializeEvent(&disketteExtension->QueryPowerEvent,
  338. SynchronizationEvent,
  339. FALSE);
  340. disketteExtension->FloppyControllerAllocated = FALSE;
  341. disketteExtension->ReleaseFdcWithMotorRunning = FALSE;
  342. disketteExtension->DeviceObject = deviceObject;
  343. disketteExtension->IsReadOnly = FALSE;
  344. disketteExtension->MediaType = Undetermined;
  345. disketteExtension->ControllerConfigurable = TRUE;
  346. }
  347. }
  348. return ntStatus;
  349. }
  350. NTSTATUS
  351. FloppySystemControl(
  352. IN PDEVICE_OBJECT DeviceObject,
  353. IN PIRP Irp
  354. )
  355. /*+++
  356. Routine Description ;
  357. This is the dispatch routine for IRP_MJ_SYSTEM_CONTROL IRPs.
  358. Currently we don't handle it. Just pass it down to the lower
  359. device.
  360. Arguments:
  361. DeviceObject - a pointer to the object that represents the device
  362. Irp - a pointer to the I/O Request Packet for this request.
  363. Return Value :
  364. Status returned by lower device.
  365. --*/
  366. {
  367. PDISKETTE_EXTENSION disketteExtension = DeviceObject->DeviceExtension;
  368. IoSkipCurrentIrpStackLocation(Irp);
  369. return IoCallDriver(disketteExtension->TargetObject, Irp);
  370. }
  371. NTSTATUS
  372. FlConfigCallBack(
  373. IN PVOID Context,
  374. IN PUNICODE_STRING PathName,
  375. IN INTERFACE_TYPE BusType,
  376. IN ULONG BusNumber,
  377. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  378. IN CONFIGURATION_TYPE ControllerType,
  379. IN ULONG ControllerNumber,
  380. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  381. IN CONFIGURATION_TYPE PeripheralType,
  382. IN ULONG PeripheralNumber,
  383. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  384. )
  385. /*++
  386. Routine Description:
  387. This routine is used to acquire all of the configuration
  388. information for each floppy disk controller and the
  389. peripheral driver attached to that controller.
  390. Arguments:
  391. Context - Pointer to the confuration information we are building
  392. up.
  393. PathName - unicode registry path. Not Used.
  394. BusType - Internal, Isa, ...
  395. BusNumber - Which bus if we are on a multibus system.
  396. BusInformation - Configuration information about the bus. Not Used.
  397. ControllerType - Should always be DiskController.
  398. ControllerNumber - Which controller if there is more than one
  399. controller in the system.
  400. ControllerInformation - Array of pointers to the three pieces of
  401. registry information.
  402. PeripheralType - Should always be FloppyDiskPeripheral.
  403. PeripheralNumber - Which floppy if this controller is maintaining
  404. more than one.
  405. PeripheralInformation - Arrya of pointers to the three pieces of
  406. registry information.
  407. Return Value:
  408. STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
  409. if it couldn't map the base csr or acquire the adapter object, or
  410. all of the resource information couldn't be acquired.
  411. --*/
  412. {
  413. //
  414. // So we don't have to typecast the context.
  415. //
  416. PDISKETTE_EXTENSION disketteExtension = Context;
  417. //
  418. // Simple iteration variable.
  419. //
  420. ULONG i;
  421. PCM_FULL_RESOURCE_DESCRIPTOR peripheralData;
  422. NTSTATUS ntStatus;
  423. ASSERT(ControllerType == DiskController);
  424. ASSERT(PeripheralType == FloppyDiskPeripheral);
  425. //
  426. // Check if the infprmation from the registry for this device
  427. // is valid.
  428. //
  429. if (!(((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) +
  430. PeripheralInformation[IoQueryDeviceConfigurationData]->DataLength)) {
  431. ASSERT(FALSE);
  432. return STATUS_INVALID_PARAMETER;
  433. }
  434. peripheralData = (PCM_FULL_RESOURCE_DESCRIPTOR)
  435. (((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) +
  436. PeripheralInformation[IoQueryDeviceConfigurationData]->DataOffset);
  437. //
  438. // With Version 2.0 or greater for this resource list, we will get
  439. // the full int13 information for the drive. So get that if available.
  440. //
  441. // Otherwise, the only thing that we want out of the peripheral information
  442. // is the maximum drive capacity.
  443. //
  444. // Drop any information on the floor other than the
  445. // device specfic floppy information.
  446. //
  447. for ( i = 0; i < peripheralData->PartialResourceList.Count; i++ ) {
  448. PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
  449. &peripheralData->PartialResourceList.PartialDescriptors[i];
  450. if ( partial->Type == CmResourceTypeDeviceSpecific ) {
  451. //
  452. // Point to right after this partial. This will take
  453. // us to the beginning of the "real" device specific.
  454. //
  455. PCM_FLOPPY_DEVICE_DATA fDeviceData;
  456. UCHAR driveType;
  457. PDRIVE_MEDIA_CONSTANTS biosDriveMediaConstants =
  458. &(disketteExtension->BiosDriveMediaConstants);
  459. fDeviceData = (PCM_FLOPPY_DEVICE_DATA)(partial + 1);
  460. //
  461. // Get the driver density
  462. //
  463. switch ( fDeviceData->MaxDensity ) {
  464. case 360: driveType = DRIVE_TYPE_0360; break;
  465. case 1200: driveType = DRIVE_TYPE_1200; break;
  466. case 1185: driveType = DRIVE_TYPE_1200; break;
  467. case 1423: driveType = DRIVE_TYPE_1440; break;
  468. case 1440: driveType = DRIVE_TYPE_1440; break;
  469. case 2880: driveType = DRIVE_TYPE_2880; break;
  470. default:
  471. FloppyDump(
  472. FLOPDBGP,
  473. ("Floppy: Bad DriveCapacity!\n"
  474. "------ density is %d\n",
  475. fDeviceData->MaxDensity)
  476. );
  477. driveType = DRIVE_TYPE_1200;
  478. FloppyDump(
  479. FLOPDBGP,
  480. ("Floppy: run a setup program to set the floppy\n"
  481. "------ drive type; assuming 1.2mb\n"
  482. "------ (type is %x)\n",fDeviceData->MaxDensity)
  483. );
  484. break;
  485. }
  486. disketteExtension->DriveType = driveType;
  487. //
  488. // Pick up all the default from our own table and override
  489. // with the BIOS information
  490. //
  491. *biosDriveMediaConstants = DriveMediaConstants[
  492. DriveMediaLimits[driveType].HighestDriveMediaType];
  493. //
  494. // If the version is high enough, get the rest of the
  495. // information. DeviceSpecific information with a version >= 2
  496. // should have this information
  497. //
  498. if ( fDeviceData->Version >= 2 ) {
  499. // biosDriveMediaConstants->MediaType =
  500. biosDriveMediaConstants->StepRateHeadUnloadTime =
  501. fDeviceData->StepRateHeadUnloadTime;
  502. biosDriveMediaConstants->HeadLoadTime =
  503. fDeviceData->HeadLoadTime;
  504. biosDriveMediaConstants->MotorOffTime =
  505. fDeviceData->MotorOffTime;
  506. biosDriveMediaConstants->SectorLengthCode =
  507. fDeviceData->SectorLengthCode;
  508. // biosDriveMediaConstants->BytesPerSector =
  509. if (fDeviceData->SectorPerTrack == 0) {
  510. // This is not a valid sector per track value.
  511. // We don't recognize this drive. This bogus
  512. // value is often returned by SCSI floppies.
  513. return STATUS_SUCCESS;
  514. }
  515. if (fDeviceData->MaxDensity == 0 ) {
  516. //
  517. // This values are returned by the LS-120 atapi drive.
  518. // BIOS function 8, in int 13 is returned in bl, which
  519. // is mapped to this field. The LS-120 returns 0x10
  520. // which is mapped to 0. Thats why we wont pick it up
  521. // as a normal floppy.
  522. //
  523. return STATUS_SUCCESS;
  524. }
  525. biosDriveMediaConstants->SectorsPerTrack =
  526. fDeviceData->SectorPerTrack;
  527. biosDriveMediaConstants->ReadWriteGapLength =
  528. fDeviceData->ReadWriteGapLength;
  529. biosDriveMediaConstants->FormatGapLength =
  530. fDeviceData->FormatGapLength;
  531. biosDriveMediaConstants->FormatFillCharacter =
  532. fDeviceData->FormatFillCharacter;
  533. biosDriveMediaConstants->HeadSettleTime =
  534. fDeviceData->HeadSettleTime;
  535. biosDriveMediaConstants->MotorSettleTimeRead =
  536. fDeviceData->MotorSettleTime * 1000 / 8;
  537. biosDriveMediaConstants->MotorSettleTimeWrite =
  538. fDeviceData->MotorSettleTime * 1000 / 8;
  539. if (fDeviceData->MaximumTrackValue == 0) {
  540. // This is not a valid maximum track value.
  541. // We don't recognize this drive. This bogus
  542. // value is often returned by SCSI floppies.
  543. return STATUS_SUCCESS;
  544. }
  545. biosDriveMediaConstants->MaximumTrack =
  546. fDeviceData->MaximumTrackValue;
  547. biosDriveMediaConstants->DataLength =
  548. fDeviceData->DataTransferLength;
  549. }
  550. }
  551. }
  552. return STATUS_SUCCESS;
  553. }
  554. NTSTATUS
  555. FlAcpiConfigureFloppy(
  556. PDISKETTE_EXTENSION DisketteExtension,
  557. PFDC_INFO FdcInfo
  558. )
  559. /*++
  560. Routine Description:
  561. Arguments:
  562. Return Value:
  563. --*/
  564. {
  565. UCHAR driveType;
  566. PDRIVE_MEDIA_CONSTANTS biosDriveMediaConstants =
  567. &(DisketteExtension->BiosDriveMediaConstants);
  568. if ( !FdcInfo->AcpiFdiSupported ) {
  569. return STATUS_UNSUCCESSFUL;
  570. }
  571. //
  572. // Get the driver density
  573. //
  574. // JB:TBD - review this drive type list.
  575. //
  576. switch ( (ACPI_FDI_DEVICE_TYPE)FdcInfo->AcpiFdiData.DeviceType ) {
  577. case Form525Capacity360: driveType = DRIVE_TYPE_0360; break;
  578. case Form525Capacity1200: driveType = DRIVE_TYPE_1200; break;
  579. case Form35Capacity720: driveType = DRIVE_TYPE_0720; break;
  580. case Form35Capacity1440: driveType = DRIVE_TYPE_1440; break;
  581. case Form35Capacity2880: driveType = DRIVE_TYPE_2880; break;
  582. default: driveType = DRIVE_TYPE_1200; break;
  583. }
  584. DisketteExtension->DriveType = driveType;
  585. //
  586. // Pick up all the default from our own table and override
  587. // with the BIOS information
  588. //
  589. *biosDriveMediaConstants = DriveMediaConstants[
  590. DriveMediaLimits[driveType].HighestDriveMediaType];
  591. biosDriveMediaConstants->StepRateHeadUnloadTime = (UCHAR) FdcInfo->AcpiFdiData.StepRateHeadUnloadTime;
  592. biosDriveMediaConstants->HeadLoadTime = (UCHAR) FdcInfo->AcpiFdiData.HeadLoadTime;
  593. biosDriveMediaConstants->MotorOffTime = (UCHAR) FdcInfo->AcpiFdiData.MotorOffTime;
  594. biosDriveMediaConstants->SectorLengthCode = (UCHAR) FdcInfo->AcpiFdiData.SectorLengthCode;
  595. biosDriveMediaConstants->SectorsPerTrack = (UCHAR) FdcInfo->AcpiFdiData.SectorPerTrack;
  596. biosDriveMediaConstants->ReadWriteGapLength = (UCHAR) FdcInfo->AcpiFdiData.ReadWriteGapLength;
  597. biosDriveMediaConstants->FormatGapLength = (UCHAR) FdcInfo->AcpiFdiData.FormatGapLength;
  598. biosDriveMediaConstants->FormatFillCharacter = (UCHAR) FdcInfo->AcpiFdiData.FormatFillCharacter;
  599. biosDriveMediaConstants->HeadSettleTime = (UCHAR) FdcInfo->AcpiFdiData.HeadSettleTime;
  600. biosDriveMediaConstants->MotorSettleTimeRead = (UCHAR) FdcInfo->AcpiFdiData.MotorSettleTime * 1000 / 8;
  601. biosDriveMediaConstants->MotorSettleTimeWrite = (USHORT) FdcInfo->AcpiFdiData.MotorSettleTime * 1000 / 8;
  602. biosDriveMediaConstants->MaximumTrack = (UCHAR) FdcInfo->AcpiFdiData.MaxCylinderNumber;
  603. biosDriveMediaConstants->DataLength = (UCHAR) FdcInfo->AcpiFdiData.DataTransferLength;
  604. return STATUS_SUCCESS;
  605. }
  606. NTSTATUS
  607. FlQueueIrpToThread(
  608. IN OUT PIRP Irp,
  609. IN OUT PDISKETTE_EXTENSION DisketteExtension
  610. )
  611. /*++
  612. Routine Description:
  613. This routine queues the given irp to be serviced by the controller's
  614. thread. If the thread is down then this routine creates the thread.
  615. Arguments:
  616. Irp - Supplies the IRP to queue to the controller's thread.
  617. ControllerData - Supplies the controller data.
  618. Return Value:
  619. May return an error if PsCreateSystemThread fails.
  620. Otherwise returns STATUS_PENDING and marks the IRP pending.
  621. --*/
  622. {
  623. KIRQL oldIrql;
  624. NTSTATUS status;
  625. HANDLE threadHandle;
  626. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  627. //
  628. // Verify if the system is powering down. If so we fail
  629. // the irps.
  630. //
  631. ExAcquireFastMutex(&DisketteExtension->PowerDownMutex);
  632. if (DisketteExtension->PoweringDown == TRUE) {
  633. ExReleaseFastMutex(&DisketteExtension->PowerDownMutex);
  634. FloppyDump( FLOPDBGP,
  635. ("Queue IRP: Bailing out since power irp is waiting.\n"));
  636. Irp->IoStatus.Status = STATUS_POWER_STATE_INVALID;
  637. Irp->IoStatus.Information = 0;
  638. return STATUS_POWER_STATE_INVALID;
  639. }
  640. ExReleaseFastMutex(&DisketteExtension->PowerDownMutex);
  641. FloppyDump( FLOPSHOW, ("Queue IRP: No power irp waiting.\n"));
  642. ExAcquireFastMutex(&DisketteExtension->ThreadReferenceMutex);
  643. if (++(DisketteExtension->ThreadReferenceCount) == 0) {
  644. OBJECT_ATTRIBUTES ObjAttributes;
  645. DisketteExtension->ThreadReferenceCount++;
  646. FloppyResetDriverPaging();
  647. //
  648. // Create the thread.
  649. //
  650. ASSERT(DisketteExtension->FloppyThread == NULL);
  651. InitializeObjectAttributes(&ObjAttributes, NULL,
  652. OBJ_KERNEL_HANDLE,
  653. NULL,
  654. NULL);
  655. status = PsCreateSystemThread(&threadHandle,
  656. (ACCESS_MASK) 0L,
  657. &ObjAttributes,
  658. (HANDLE) 0L,
  659. NULL,
  660. FloppyThread,
  661. DisketteExtension);
  662. if (!NT_SUCCESS(status)) {
  663. DisketteExtension->ThreadReferenceCount = -1;
  664. FloppyPageEntireDriver();
  665. ExReleaseFastMutex(&DisketteExtension->ThreadReferenceMutex);
  666. return status;
  667. }
  668. status = ObReferenceObjectByHandle( threadHandle,
  669. SYNCHRONIZE,
  670. NULL,
  671. KernelMode,
  672. &DisketteExtension->FloppyThread,
  673. NULL );
  674. ZwClose(threadHandle);
  675. if (!NT_SUCCESS(status)) {
  676. DisketteExtension->ThreadReferenceCount = -1;
  677. DisketteExtension->FloppyThread = NULL;
  678. FloppyPageEntireDriver();
  679. ExReleaseFastMutex(&DisketteExtension->ThreadReferenceMutex);
  680. return status;
  681. }
  682. ExReleaseFastMutex(&DisketteExtension->ThreadReferenceMutex);
  683. } else {
  684. ExReleaseFastMutex(&DisketteExtension->ThreadReferenceMutex);
  685. }
  686. IoMarkIrpPending(Irp);
  687. ExInterlockedInsertTailList(
  688. &DisketteExtension->ListEntry,
  689. &Irp->Tail.Overlay.ListEntry,
  690. &DisketteExtension->ListSpinLock );
  691. KeReleaseSemaphore(
  692. &DisketteExtension->RequestSemaphore,
  693. (KPRIORITY) 0,
  694. 1,
  695. FALSE );
  696. return STATUS_PENDING;
  697. }
  698. NTSTATUS
  699. FloppyCreateClose(
  700. IN PDEVICE_OBJECT DeviceObject,
  701. IN PIRP Irp
  702. )
  703. /*++
  704. Routine Description:
  705. This routine is called only rarely by the I/O system; it's mainly
  706. for layered drivers to call. All it does is complete the IRP
  707. successfully.
  708. Arguments:
  709. DeviceObject - a pointer to the object that represents the device
  710. that I/O is to be done on.
  711. Irp - a pointer to the I/O Request Packet for this request.
  712. Return Value:
  713. Always returns STATUS_SUCCESS, since this is a null operation.
  714. --*/
  715. {
  716. UNREFERENCED_PARAMETER( DeviceObject );
  717. FloppyDump(FLOPSHOW, ("FloppyCreateClose...\n"));
  718. //
  719. // Null operation. Do not give an I/O boost since
  720. // no I/O was actually done. IoStatus.Information should be
  721. // FILE_OPENED for an open; it's undefined for a close.
  722. //
  723. Irp->IoStatus.Status = STATUS_SUCCESS;
  724. Irp->IoStatus.Information = FILE_OPENED;
  725. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  726. return STATUS_SUCCESS;
  727. }
  728. NTSTATUS
  729. FloppyDeviceControl(
  730. IN PDEVICE_OBJECT DeviceObject,
  731. IN PIRP Irp
  732. )
  733. /*++
  734. Routine Description:
  735. This routine is called by the I/O system to perform a device I/O
  736. control function.
  737. Arguments:
  738. DeviceObject - a pointer to the object that represents the device
  739. that I/O is to be done on.
  740. Irp - a pointer to the I/O Request Packet for this request.
  741. Return Value:
  742. STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
  743. STATUS_INVALID_DEVICE_REQUEST otherwise.
  744. --*/
  745. {
  746. PIO_STACK_LOCATION irpSp;
  747. PDISKETTE_EXTENSION disketteExtension;
  748. PDISK_GEOMETRY outputBuffer;
  749. NTSTATUS ntStatus;
  750. ULONG outputBufferLength;
  751. UCHAR i;
  752. DRIVE_MEDIA_TYPE lowestDriveMediaType;
  753. DRIVE_MEDIA_TYPE highestDriveMediaType;
  754. ULONG formatExParametersSize;
  755. PFORMAT_EX_PARAMETERS formatExParameters;
  756. FloppyDump( FLOPSHOW, ("FloppyDeviceControl...\n") );
  757. disketteExtension = DeviceObject->DeviceExtension;
  758. irpSp = IoGetCurrentIrpStackLocation( Irp );
  759. Irp->IoStatus.Information = 0;
  760. //
  761. // We need to check if we are currently holding requests.
  762. //
  763. ExAcquireFastMutex(&(disketteExtension->HoldNewReqMutex));
  764. if (disketteExtension->HoldNewRequests) {
  765. //
  766. // Queue request only if this is not an ACPI exec method. There is
  767. // a nasty recursion with ACPI and fdc/flpy that requires that these
  768. // requests get through in order to avoid a deadlock.
  769. //
  770. if (irpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_ACPI_ASYNC_EVAL_METHOD) {
  771. ntStatus = FloppyQueueRequest( disketteExtension, Irp );
  772. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  773. return ntStatus;
  774. }
  775. }
  776. //
  777. // If the device has been removed we will just fail this request outright.
  778. //
  779. if ( disketteExtension->IsRemoved ) {
  780. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  781. Irp->IoStatus.Information = 0;
  782. Irp->IoStatus.Status = STATUS_DELETE_PENDING;
  783. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  784. return STATUS_DELETE_PENDING;
  785. }
  786. //
  787. // If the device hasn't been started we will let the IOCTL through. This
  788. // is another hack for ACPI.
  789. //
  790. if (!disketteExtension->IsStarted) {
  791. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  792. IoSkipCurrentIrpStackLocation( Irp );
  793. return IoCallDriver( disketteExtension->TargetObject, Irp );
  794. }
  795. switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
  796. case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: {
  797. PMOUNTDEV_NAME mountName;
  798. FloppyDump( FLOPSHOW, ("FloppyDeviceControl: IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n") );
  799. ASSERT(disketteExtension->DeviceName.Buffer);
  800. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  801. sizeof(MOUNTDEV_NAME) ) {
  802. ntStatus = STATUS_INVALID_PARAMETER;
  803. break;
  804. }
  805. mountName = Irp->AssociatedIrp.SystemBuffer;
  806. mountName->NameLength = disketteExtension->DeviceName.Length;
  807. if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  808. sizeof(USHORT) + mountName->NameLength) {
  809. ntStatus = STATUS_BUFFER_OVERFLOW;
  810. Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
  811. break;
  812. }
  813. RtlCopyMemory( mountName->Name, disketteExtension->DeviceName.Buffer,
  814. mountName->NameLength);
  815. ntStatus = STATUS_SUCCESS;
  816. Irp->IoStatus.Information = sizeof(USHORT) + mountName->NameLength;
  817. break;
  818. }
  819. case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: {
  820. PMOUNTDEV_UNIQUE_ID uniqueId;
  821. FloppyDump( FLOPSHOW, ("FloppyDeviceControl: IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n") );
  822. if ( !disketteExtension->InterfaceString.Buffer ||
  823. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  824. sizeof(MOUNTDEV_UNIQUE_ID)) {
  825. ntStatus = STATUS_INVALID_PARAMETER;
  826. break;
  827. }
  828. uniqueId = Irp->AssociatedIrp.SystemBuffer;
  829. uniqueId->UniqueIdLength =
  830. disketteExtension->InterfaceString.Length;
  831. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  832. sizeof(USHORT) + uniqueId->UniqueIdLength) {
  833. ntStatus = STATUS_BUFFER_OVERFLOW;
  834. Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
  835. break;
  836. }
  837. RtlCopyMemory( uniqueId->UniqueId,
  838. disketteExtension->InterfaceString.Buffer,
  839. uniqueId->UniqueIdLength );
  840. ntStatus = STATUS_SUCCESS;
  841. Irp->IoStatus.Information = sizeof(USHORT) +
  842. uniqueId->UniqueIdLength;
  843. break;
  844. }
  845. case IOCTL_DISK_FORMAT_TRACKS:
  846. case IOCTL_DISK_FORMAT_TRACKS_EX:
  847. //
  848. // Make sure that we got all the necessary format parameters.
  849. //
  850. if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
  851. sizeof( FORMAT_PARAMETERS ) ) {
  852. FloppyDump(FLOPDBGP, ("Floppy: invalid FORMAT buffer length\n"));
  853. ntStatus = STATUS_INVALID_PARAMETER;
  854. break;
  855. }
  856. //
  857. // Make sure the parameters we got are reasonable.
  858. //
  859. if ( !FlCheckFormatParameters(
  860. disketteExtension,
  861. (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer ) ) {
  862. FloppyDump(FLOPDBGP, ("Floppy: invalid FORMAT parameters\n"));
  863. ntStatus = STATUS_INVALID_PARAMETER;
  864. break;
  865. }
  866. //
  867. // If this is an EX request then make a couple of extra checks
  868. //
  869. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  870. IOCTL_DISK_FORMAT_TRACKS_EX) {
  871. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  872. sizeof(FORMAT_EX_PARAMETERS)) {
  873. ntStatus = STATUS_INVALID_PARAMETER;
  874. break;
  875. }
  876. formatExParameters = (PFORMAT_EX_PARAMETERS)
  877. Irp->AssociatedIrp.SystemBuffer;
  878. formatExParametersSize =
  879. FIELD_OFFSET(FORMAT_EX_PARAMETERS, SectorNumber) +
  880. formatExParameters->SectorsPerTrack*sizeof(USHORT);
  881. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  882. formatExParametersSize ||
  883. formatExParameters->FormatGapLength >= 0x100 ||
  884. formatExParameters->SectorsPerTrack >= 0x100) {
  885. ntStatus = STATUS_INVALID_PARAMETER;
  886. break;
  887. }
  888. }
  889. //
  890. // Fall through to queue the request.
  891. //
  892. case IOCTL_DISK_CHECK_VERIFY:
  893. case IOCTL_STORAGE_CHECK_VERIFY:
  894. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  895. case IOCTL_DISK_IS_WRITABLE:
  896. //
  897. // The thread must know which diskette to operate on, but the
  898. // request list only passes the IRP. So we'll stick a pointer
  899. // to the diskette extension in Type3InputBuffer, which is
  900. // a field that isn't used for floppy ioctls.
  901. //
  902. //
  903. // Add the request to the queue, and wake up the thread to
  904. // process it.
  905. //
  906. // irpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID)
  907. // disketteExtension;
  908. FloppyDump(
  909. FLOPIRPPATH,
  910. ("Floppy: Enqueing up IRP: %p\n",Irp)
  911. );
  912. ntStatus = FlQueueIrpToThread(Irp, disketteExtension);
  913. break;
  914. case IOCTL_DISK_GET_MEDIA_TYPES:
  915. case IOCTL_STORAGE_GET_MEDIA_TYPES: {
  916. FloppyDump(FLOPSHOW, ("Floppy: IOCTL_DISK_GET_MEDIA_TYPES called\n"));
  917. lowestDriveMediaType = DriveMediaLimits[
  918. disketteExtension->DriveType].LowestDriveMediaType;
  919. highestDriveMediaType = DriveMediaLimits[
  920. disketteExtension->DriveType].HighestDriveMediaType;
  921. outputBufferLength =
  922. irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  923. //
  924. // Make sure that the input buffer has enough room to return
  925. // at least one descriptions of a supported media type.
  926. //
  927. if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) ) ) {
  928. FloppyDump(FLOPDBGP, ("Floppy: invalid GET_MEDIA_TYPES buffer size\n"));
  929. ntStatus = STATUS_BUFFER_TOO_SMALL;
  930. break;
  931. }
  932. //
  933. // Assume success, although we might modify it to a buffer
  934. // overflow warning below (if the buffer isn't big enough
  935. // to hold ALL of the media descriptions).
  936. //
  937. ntStatus = STATUS_SUCCESS;
  938. if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) *
  939. ( highestDriveMediaType - lowestDriveMediaType + 1 ) ) ) {
  940. //
  941. // The buffer is too small for all of the descriptions;
  942. // calculate what CAN fit in the buffer.
  943. //
  944. FloppyDump(FLOPDBGP, ("Floppy: GET_MEDIA_TYPES buffer size too small\n"));
  945. ntStatus = STATUS_BUFFER_OVERFLOW;
  946. highestDriveMediaType =
  947. (DRIVE_MEDIA_TYPE)( ( lowestDriveMediaType - 1 ) +
  948. ( outputBufferLength /
  949. sizeof( DISK_GEOMETRY ) ) );
  950. }
  951. outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
  952. for (i = (UCHAR)lowestDriveMediaType;
  953. i <= (UCHAR)highestDriveMediaType;
  954. i++) {
  955. outputBuffer->MediaType = DriveMediaConstants[i].MediaType;
  956. outputBuffer->Cylinders.LowPart =
  957. DriveMediaConstants[i].MaximumTrack + 1;
  958. outputBuffer->Cylinders.HighPart = 0;
  959. outputBuffer->TracksPerCylinder =
  960. DriveMediaConstants[i].NumberOfHeads;
  961. outputBuffer->SectorsPerTrack =
  962. DriveMediaConstants[i].SectorsPerTrack;
  963. outputBuffer->BytesPerSector =
  964. DriveMediaConstants[i].BytesPerSector;
  965. FloppyDump(
  966. FLOPSHOW,
  967. ("Floppy: media types supported [%d]\n"
  968. "------- Cylinders low: 0x%x\n"
  969. "------- Cylinders high: 0x%x\n"
  970. "------- Track/Cyl: 0x%x\n"
  971. "------- Sectors/Track: 0x%x\n"
  972. "------- Bytes/Sector: 0x%x\n"
  973. "------- Media Type: %d\n",
  974. i,
  975. outputBuffer->Cylinders.LowPart,
  976. outputBuffer->Cylinders.HighPart,
  977. outputBuffer->TracksPerCylinder,
  978. outputBuffer->SectorsPerTrack,
  979. outputBuffer->BytesPerSector,
  980. outputBuffer->MediaType)
  981. );
  982. outputBuffer++;
  983. Irp->IoStatus.Information += sizeof( DISK_GEOMETRY );
  984. }
  985. break;
  986. }
  987. default: {
  988. //
  989. // We pass down IOCTL's because ACPI uses this as a communications
  990. // method. ACPI *should* have used a PNP Interface mechanism, but
  991. // it's too late now.
  992. //
  993. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  994. IoSkipCurrentIrpStackLocation( Irp );
  995. ntStatus = IoCallDriver( disketteExtension->TargetObject, Irp );
  996. return ntStatus;
  997. }
  998. }
  999. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  1000. if ( ntStatus != STATUS_PENDING ) {
  1001. Irp->IoStatus.Status = ntStatus;
  1002. if (!NT_SUCCESS( ntStatus ) &&
  1003. IoIsErrorUserInduced( ntStatus )) {
  1004. IoSetHardErrorOrVerifyDevice( Irp, DeviceObject );
  1005. }
  1006. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1007. }
  1008. return ntStatus;
  1009. }
  1010. NTSTATUS
  1011. FloppyPnp(
  1012. IN PDEVICE_OBJECT DeviceObject,
  1013. IN PIRP Irp
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. Arguments:
  1018. DeviceObject - a pointer to the object that represents the device
  1019. that I/O is to be done on.
  1020. Irp - a pointer to the I/O Request Packet for this request.
  1021. Return Value:
  1022. --*/
  1023. {
  1024. PIO_STACK_LOCATION irpSp;
  1025. PDISKETTE_EXTENSION disketteExtension;
  1026. NTSTATUS ntStatus = STATUS_SUCCESS;
  1027. ULONG i;
  1028. FloppyDump( FLOPSHOW, ("FloppyPnp:\n") );
  1029. //
  1030. // Lock down the driver if it is not already locked.
  1031. //
  1032. FloppyResetDriverPaging();
  1033. disketteExtension = DeviceObject->DeviceExtension;
  1034. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1035. if ( disketteExtension->IsRemoved ) {
  1036. //
  1037. // Since the device is stopped, but we don't hold IRPs,
  1038. // this is a surprise removal. Just fail it.
  1039. //
  1040. Irp->IoStatus.Information = 0;
  1041. Irp->IoStatus.Status = STATUS_DELETE_PENDING;
  1042. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  1043. return STATUS_DELETE_PENDING;
  1044. }
  1045. switch ( irpSp->MinorFunction ) {
  1046. case IRP_MN_START_DEVICE:
  1047. ntStatus = FloppyStartDevice( DeviceObject, Irp );
  1048. break;
  1049. case IRP_MN_QUERY_STOP_DEVICE:
  1050. case IRP_MN_QUERY_REMOVE_DEVICE:
  1051. if ( irpSp->MinorFunction == IRP_MN_QUERY_STOP_DEVICE ) {
  1052. FloppyDump( FLOPPNP,("FloppyPnp: IRP_MN_QUERY_STOP_DEVICE - Irp: %p\n", Irp) );
  1053. } else {
  1054. FloppyDump( FLOPPNP,("FloppyPnp: IRP_MN_QUERY_REMOVE_DEVICE - Irp: %p\n", Irp) );
  1055. }
  1056. if ( !disketteExtension->IsStarted ) {
  1057. //
  1058. // If we aren't started, we'll just pass the irp down.
  1059. //
  1060. Irp->IoStatus.Status = STATUS_SUCCESS;
  1061. IoSkipCurrentIrpStackLocation (Irp);
  1062. ntStatus = IoCallDriver( disketteExtension->TargetObject, Irp );
  1063. return ntStatus;
  1064. }
  1065. //
  1066. // Hold all new requests.
  1067. //
  1068. ExAcquireFastMutex(&(disketteExtension->HoldNewReqMutex));
  1069. disketteExtension->HoldNewRequests = TRUE;
  1070. //
  1071. // Queue this irp to the floppy thread, this will shutdown the
  1072. // floppy thread without waiting for the typical 3 second motor
  1073. // timeout.
  1074. //
  1075. ntStatus = FlQueueIrpToThread( Irp, disketteExtension );
  1076. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  1077. //
  1078. // Wait for the floppy thread to finish. This could take a few hundred
  1079. // milliseconds if the motor needs to be shut down.
  1080. //
  1081. if ( ntStatus == STATUS_PENDING ) {
  1082. ASSERT(disketteExtension->FloppyThread != NULL);
  1083. FlTerminateFloppyThread(disketteExtension);
  1084. Irp->IoStatus.Status = STATUS_SUCCESS;
  1085. IoSkipCurrentIrpStackLocation( Irp );
  1086. IoCallDriver( disketteExtension->TargetObject, Irp );
  1087. ntStatus = STATUS_PENDING;
  1088. } else {
  1089. //
  1090. // We failed to either start the thread or get a pointer to the
  1091. // thread object. Either way veto the Query.
  1092. //
  1093. ntStatus = STATUS_UNSUCCESSFUL;
  1094. Irp->IoStatus.Status = ntStatus;
  1095. Irp->IoStatus.Information = 0;
  1096. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  1097. }
  1098. break;
  1099. case IRP_MN_CANCEL_STOP_DEVICE:
  1100. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1101. if ( irpSp->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE ) {
  1102. FloppyDump( FLOPPNP,("FloppyPnp: IRP_MN_CANCEL_STOP_DEVICE - Irp: %p\n", Irp) );
  1103. } else {
  1104. FloppyDump( FLOPPNP,("FloppyPnp: IRP_MN_CANCEL_REMOVE_DEVICE - Irp: %p\n", Irp) );
  1105. }
  1106. if ( !disketteExtension->IsStarted ) {
  1107. //
  1108. // Nothing to do, just pass the irp down:
  1109. // no need to start the device
  1110. //
  1111. // Set Status to SUCCESS before passing the irp down
  1112. //
  1113. Irp->IoStatus.Status = STATUS_SUCCESS;
  1114. IoSkipCurrentIrpStackLocation (Irp);
  1115. ntStatus = IoCallDriver( disketteExtension->TargetObject, Irp );
  1116. } else {
  1117. KEVENT doneEvent;
  1118. //
  1119. // Set the status to STATUS_SUCCESS
  1120. //
  1121. Irp->IoStatus.Status = STATUS_SUCCESS;
  1122. //
  1123. // We need to wait for the lower drivers to do their job.
  1124. //
  1125. IoCopyCurrentIrpStackLocationToNext (Irp);
  1126. //
  1127. // Clear the event: it will be set in the completion
  1128. // routine.
  1129. //
  1130. KeInitializeEvent( &doneEvent,
  1131. SynchronizationEvent,
  1132. FALSE);
  1133. IoSetCompletionRoutine( Irp,
  1134. FloppyPnpComplete,
  1135. &doneEvent,
  1136. TRUE, TRUE, TRUE );
  1137. ntStatus = IoCallDriver( disketteExtension->TargetObject, Irp );
  1138. if ( ntStatus == STATUS_PENDING ) {
  1139. KeWaitForSingleObject( &doneEvent,
  1140. Executive,
  1141. KernelMode,
  1142. FALSE,
  1143. NULL );
  1144. ntStatus = Irp->IoStatus.Status;
  1145. }
  1146. ExAcquireFastMutex(&(disketteExtension->HoldNewReqMutex));
  1147. disketteExtension->HoldNewRequests = FALSE;
  1148. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  1149. //
  1150. // Process the queued requests
  1151. //
  1152. FloppyProcessQueuedRequests( disketteExtension );
  1153. //
  1154. // We must now complete the IRP, since we stopped it in the
  1155. // completetion routine with MORE_PROCESSING_REQUIRED.
  1156. //
  1157. Irp->IoStatus.Status = ntStatus;
  1158. Irp->IoStatus.Information = 0;
  1159. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  1160. }
  1161. break;
  1162. case IRP_MN_STOP_DEVICE:
  1163. FloppyDump( FLOPPNP,("FloppyPnp: IRP_MN_STOP_DEVICE - Irp: %p\n", Irp) );
  1164. disketteExtension->IsStarted = FALSE;
  1165. Irp->IoStatus.Status = STATUS_SUCCESS;
  1166. IoSkipCurrentIrpStackLocation( Irp );
  1167. ntStatus = IoCallDriver( disketteExtension->TargetObject, Irp );
  1168. break;
  1169. case IRP_MN_REMOVE_DEVICE:
  1170. FloppyDump( FLOPPNP,("FloppyPnp: IRP_MN_REMOVE_DEVICE - Irp: %p\n", Irp) );
  1171. FlTerminateFloppyThread(disketteExtension);
  1172. //
  1173. // We need to mark the fact that we don't hold requests first, since
  1174. // we asserted earlier that we are holding requests only if
  1175. // we're not removed.
  1176. //
  1177. ExAcquireFastMutex(&(disketteExtension->HoldNewReqMutex));
  1178. disketteExtension->HoldNewRequests = FALSE;
  1179. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  1180. disketteExtension->IsStarted = FALSE;
  1181. disketteExtension->IsRemoved = TRUE;
  1182. //
  1183. // Here we either have completed all the requests in a personal
  1184. // queue when IRP_MN_QUERY_REMOVE was received, or will have to
  1185. // fail all of them if this is a surprise removal.
  1186. // Note that fdoData->IsRemoved is TRUE, so pSD_ProcessQueuedRequests
  1187. // will simply flush the queue, completing each IRP with
  1188. // STATUS_DELETE_PENDING
  1189. //
  1190. FloppyProcessQueuedRequests( disketteExtension );
  1191. //
  1192. // Forward this Irp to the underlying PDO
  1193. //
  1194. IoSkipCurrentIrpStackLocation( Irp );
  1195. Irp->IoStatus.Status = STATUS_SUCCESS;
  1196. ntStatus = IoCallDriver( disketteExtension->TargetObject, Irp );
  1197. //
  1198. // Send notification that we are going away.
  1199. //
  1200. if ( disketteExtension->InterfaceString.Buffer != NULL ) {
  1201. IoSetDeviceInterfaceState( &disketteExtension->InterfaceString,
  1202. FALSE);
  1203. RtlFreeUnicodeString( &disketteExtension->InterfaceString );
  1204. RtlInitUnicodeString( &disketteExtension->InterfaceString, NULL );
  1205. }
  1206. if ( disketteExtension->FloppyInterfaceString.Buffer != NULL ) {
  1207. IoSetDeviceInterfaceState( &disketteExtension->FloppyInterfaceString,
  1208. FALSE);
  1209. RtlFreeUnicodeString( &disketteExtension->FloppyInterfaceString );
  1210. RtlInitUnicodeString( &disketteExtension->FloppyInterfaceString, NULL );
  1211. }
  1212. RtlFreeUnicodeString( &disketteExtension->DeviceName );
  1213. RtlInitUnicodeString( &disketteExtension->DeviceName, NULL );
  1214. if ( disketteExtension->ArcName.Length != 0 ) {
  1215. IoDeassignArcName( &disketteExtension->ArcName );
  1216. RtlFreeUnicodeString( &disketteExtension->ArcName );
  1217. RtlInitUnicodeString( &disketteExtension->ArcName, NULL );
  1218. }
  1219. //
  1220. // Detatch from the undelying device.
  1221. //
  1222. IoDetachDevice( disketteExtension->TargetObject );
  1223. //
  1224. // And delete the device.
  1225. //
  1226. IoDeleteDevice( DeviceObject );
  1227. IoGetConfigurationInformation()->FloppyCount--;
  1228. break;
  1229. default:
  1230. FloppyDump( FLOPPNP, ("FloppyPnp: Unsupported PNP Request %x - Irp: %p\n",irpSp->MinorFunction, Irp) );
  1231. IoSkipCurrentIrpStackLocation( Irp );
  1232. ntStatus = IoCallDriver( disketteExtension->TargetObject, Irp );
  1233. }
  1234. //
  1235. // Page out the driver if it is not busy elsewhere.
  1236. //
  1237. FloppyPageEntireDriver();
  1238. return ntStatus;
  1239. }
  1240. NTSTATUS
  1241. FloppyStartDevice(
  1242. IN PDEVICE_OBJECT DeviceObject,
  1243. IN PIRP Irp
  1244. )
  1245. {
  1246. NTSTATUS ntStatus;
  1247. NTSTATUS pnpStatus;
  1248. KEVENT doneEvent;
  1249. FDC_INFO fdcInfo;
  1250. CONFIGURATION_TYPE Dc = DiskController;
  1251. CONFIGURATION_TYPE Fp = FloppyDiskPeripheral;
  1252. PDISKETTE_EXTENSION disketteExtension = (PDISKETTE_EXTENSION)DeviceObject->DeviceExtension;
  1253. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  1254. FloppyDump( FLOPSHOW,("FloppyStartDevice: Irp: %p\n", Irp) );
  1255. FloppyDump( FLOPSHOW, (" AllocatedResources = %08x\n",irpSp->Parameters.StartDevice.AllocatedResources));
  1256. FloppyDump( FLOPSHOW, (" AllocatedResourcesTranslated = %08x\n",irpSp->Parameters.StartDevice.AllocatedResourcesTranslated));
  1257. //
  1258. // First we must pass this Irp on to the PDO.
  1259. //
  1260. KeInitializeEvent( &doneEvent, NotificationEvent, FALSE );
  1261. IoCopyCurrentIrpStackLocationToNext( Irp );
  1262. IoSetCompletionRoutine( Irp,
  1263. FloppyPnpComplete,
  1264. &doneEvent,
  1265. TRUE, TRUE, TRUE );
  1266. ntStatus = IoCallDriver( disketteExtension->TargetObject, Irp );
  1267. if ( ntStatus == STATUS_PENDING ) {
  1268. ntStatus = KeWaitForSingleObject( &doneEvent,
  1269. Executive,
  1270. KernelMode,
  1271. FALSE,
  1272. NULL );
  1273. ASSERT( ntStatus == STATUS_SUCCESS );
  1274. ntStatus = Irp->IoStatus.Status;
  1275. }
  1276. fdcInfo.BufferCount = 0;
  1277. fdcInfo.BufferSize = 0;
  1278. ntStatus = FlFdcDeviceIo( disketteExtension->TargetObject,
  1279. IOCTL_DISK_INTERNAL_GET_FDC_INFO,
  1280. &fdcInfo );
  1281. if ( NT_SUCCESS(ntStatus) ) {
  1282. disketteExtension->MaxTransferSize = fdcInfo.MaxTransferSize;
  1283. if ( (fdcInfo.AcpiBios) &&
  1284. (fdcInfo.AcpiFdiSupported) ) {
  1285. ntStatus = FlAcpiConfigureFloppy( disketteExtension, &fdcInfo );
  1286. if ( disketteExtension->DriveType == DRIVE_TYPE_2880 ) {
  1287. disketteExtension->PerpendicularMode |= 1 << fdcInfo.PeripheralNumber;
  1288. }
  1289. } else {
  1290. INTERFACE_TYPE InterfaceType;
  1291. if ( disketteExtension->DriveType == DRIVE_TYPE_2880 ) {
  1292. disketteExtension->PerpendicularMode |= 1 << fdcInfo.PeripheralNumber;
  1293. }
  1294. //
  1295. // Query the registry till we find the correct interface type,
  1296. // since we do not know what type of interface we are on.
  1297. //
  1298. for ( InterfaceType = 0;
  1299. InterfaceType < MaximumInterfaceType;
  1300. InterfaceType++ ) {
  1301. fdcInfo.BusType = InterfaceType;
  1302. ntStatus = IoQueryDeviceDescription( &fdcInfo.BusType,
  1303. &fdcInfo.BusNumber,
  1304. &Dc,
  1305. &fdcInfo.ControllerNumber,
  1306. &Fp,
  1307. &fdcInfo.PeripheralNumber,
  1308. FlConfigCallBack,
  1309. disketteExtension );
  1310. if (NT_SUCCESS(ntStatus)) {
  1311. //
  1312. // We found the interface we are on.
  1313. //
  1314. FloppyDump(FLOPSHOW,
  1315. ("Interface Type is %x\n", InterfaceType));
  1316. break;
  1317. }
  1318. }
  1319. }
  1320. if ( NT_SUCCESS(ntStatus) ) {
  1321. disketteExtension->DeviceUnit = (UCHAR)fdcInfo.PeripheralNumber;
  1322. disketteExtension->DriveOnValue =
  1323. (UCHAR)(fdcInfo.PeripheralNumber | ( DRVCTL_DRIVE_0 << fdcInfo.PeripheralNumber ));
  1324. pnpStatus = IoRegisterDeviceInterface( disketteExtension->UnderlyingPDO,
  1325. (LPGUID)&MOUNTDEV_MOUNTED_DEVICE_GUID,
  1326. NULL,
  1327. &disketteExtension->InterfaceString );
  1328. if ( NT_SUCCESS(pnpStatus) ) {
  1329. pnpStatus = IoSetDeviceInterfaceState( &disketteExtension->InterfaceString,
  1330. TRUE );
  1331. //
  1332. // Register Floppy Class GUID
  1333. //
  1334. pnpStatus = IoRegisterDeviceInterface( disketteExtension->UnderlyingPDO,
  1335. (LPGUID)&FloppyClassGuid,
  1336. NULL,
  1337. &disketteExtension->FloppyInterfaceString );
  1338. if ( NT_SUCCESS(pnpStatus) ) {
  1339. pnpStatus = IoSetDeviceInterfaceState( &disketteExtension->FloppyInterfaceString,
  1340. TRUE );
  1341. }
  1342. }
  1343. disketteExtension->IsStarted = TRUE;
  1344. ExAcquireFastMutex(&(disketteExtension->HoldNewReqMutex));
  1345. disketteExtension->HoldNewRequests = FALSE;
  1346. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  1347. FloppyProcessQueuedRequests( disketteExtension );
  1348. }
  1349. }
  1350. Irp->IoStatus.Status = ntStatus;
  1351. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1352. return ntStatus;
  1353. }
  1354. NTSTATUS
  1355. FloppyPnpComplete (
  1356. IN PDEVICE_OBJECT DeviceObject,
  1357. IN PIRP Irp,
  1358. IN PVOID Context
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. A completion routine for use when calling the lower device objects to
  1363. which our bus (FDO) is attached.
  1364. --*/
  1365. {
  1366. KeSetEvent ((PKEVENT) Context, 1, FALSE);
  1367. // No special priority
  1368. // No Wait
  1369. return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
  1370. }
  1371. VOID
  1372. FlTerminateFloppyThread(
  1373. PDISKETTE_EXTENSION DisketteExtension
  1374. )
  1375. {
  1376. if (DisketteExtension->FloppyThread != NULL) {
  1377. KeWaitForSingleObject( DisketteExtension->FloppyThread,
  1378. Executive,
  1379. KernelMode,
  1380. FALSE,
  1381. NULL );
  1382. //
  1383. // Make sure again FloppyThread is not NULL.
  1384. //
  1385. if (DisketteExtension->FloppyThread != NULL) {
  1386. ObDereferenceObject(DisketteExtension->FloppyThread);
  1387. }
  1388. DisketteExtension->FloppyThread = NULL;
  1389. }
  1390. }
  1391. NTSTATUS
  1392. FloppyPower(
  1393. IN PDEVICE_OBJECT DeviceObject,
  1394. IN PIRP Irp
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. Arguments:
  1399. DeviceObject - a pointer to the object that represents the device
  1400. that I/O is to be done on.
  1401. Irp - a pointer to the I/O Request Packet for this request.
  1402. Return Value:
  1403. --*/
  1404. {
  1405. PDISKETTE_EXTENSION disketteExtension;
  1406. NTSTATUS ntStatus = Irp->IoStatus.Status;
  1407. PIO_STACK_LOCATION irpSp;
  1408. POWER_STATE_TYPE type;
  1409. POWER_STATE state;
  1410. BOOLEAN WaitForCompletion = TRUE;
  1411. FloppyDump( FLOPSHOW, ("FloppyPower:\n"));
  1412. disketteExtension = DeviceObject->DeviceExtension;
  1413. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1414. type = irpSp->Parameters.Power.Type;
  1415. state = irpSp->Parameters.Power.State;
  1416. switch(irpSp->MinorFunction) {
  1417. case IRP_MN_QUERY_POWER: {
  1418. FloppyDump( FLOPDBGP,
  1419. ("IRP_MN_QUERY_POWER : Type - %d, State %d\n",
  1420. type, state));
  1421. if ((type == SystemPowerState) &&
  1422. (state.SystemState > PowerSystemHibernate)) {
  1423. //
  1424. // This is a shutdown request. Pass that.
  1425. //
  1426. ntStatus = STATUS_SUCCESS;
  1427. break;
  1428. }
  1429. //
  1430. // If there are no requests being processed or queued up
  1431. // for floppy, ThreadReferenceCount will be -1. It can be 0 if
  1432. // there was only one request and that has been dequeued and is
  1433. // currently being processed.
  1434. //
  1435. ExAcquireFastMutex(&disketteExtension->ThreadReferenceMutex);
  1436. if (disketteExtension->ThreadReferenceCount > 0) {
  1437. ExReleaseFastMutex(&disketteExtension->ThreadReferenceMutex);
  1438. FloppyDump(FLOPDBGP,
  1439. ("Floppy: Requests pending. Cannot powerdown!\n"));
  1440. PoStartNextPowerIrp(Irp);
  1441. Irp->IoStatus.Information = 0;
  1442. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  1443. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1444. return STATUS_DEVICE_BUSY;
  1445. } else if ((disketteExtension->ThreadReferenceCount == 0) &&
  1446. ((disketteExtension->FloppyThread) != NULL)) {
  1447. FloppyDump(FLOPDBGP,
  1448. ("Ref count 0. No request pending.\n"));
  1449. ExReleaseFastMutex(&disketteExtension->ThreadReferenceMutex);
  1450. ExAcquireFastMutex(&disketteExtension->PowerDownMutex);
  1451. disketteExtension->ReceivedQueryPower = TRUE;
  1452. ExReleaseFastMutex(&disketteExtension->PowerDownMutex);
  1453. KeWaitForSingleObject(&disketteExtension->QueryPowerEvent,
  1454. Executive,
  1455. KernelMode,
  1456. FALSE,
  1457. NULL);
  1458. } else {
  1459. FloppyDump(FLOPDBGP,
  1460. ("No IRPs pending. Let system hibernate"));
  1461. ExReleaseFastMutex(&disketteExtension->ThreadReferenceMutex);
  1462. }
  1463. ntStatus = STATUS_SUCCESS;
  1464. break;
  1465. }
  1466. case IRP_MN_SET_POWER: {
  1467. //
  1468. // Indicate that we are going to power down or power up
  1469. // so that FloppyThread can process queued requests
  1470. // accordingly.
  1471. //
  1472. if (type == SystemPowerState) {
  1473. ExAcquireFastMutex(&disketteExtension->PowerDownMutex);
  1474. if (state.SystemState == PowerSystemWorking) {
  1475. FloppyDump( FLOPDBGP, ("Powering Up\n"));
  1476. disketteExtension->PoweringDown = FALSE;
  1477. WaitForCompletion = FALSE;
  1478. } else {
  1479. FloppyDump( FLOPDBGP, ("Powering down\n"));
  1480. WaitForCompletion = TRUE;
  1481. disketteExtension->PoweringDown = TRUE;
  1482. }
  1483. ExReleaseFastMutex(&disketteExtension->PowerDownMutex);
  1484. //
  1485. // Wait till FloppyThread signals that it is done with
  1486. // the queued requests.
  1487. //
  1488. if ((disketteExtension->FloppyThread != NULL) &&
  1489. (WaitForCompletion == TRUE)) {
  1490. KeWaitForSingleObject( disketteExtension->FloppyThread,
  1491. Executive,
  1492. KernelMode,
  1493. FALSE,
  1494. NULL );
  1495. }
  1496. }
  1497. FloppyDump( FLOPSHOW, ("Processing power irp : %p\n", Irp));
  1498. ntStatus = STATUS_SUCCESS;
  1499. break;
  1500. }
  1501. default: {
  1502. break;
  1503. }
  1504. }
  1505. PoStartNextPowerIrp( Irp );
  1506. IoSkipCurrentIrpStackLocation( Irp );
  1507. ntStatus = PoCallDriver( disketteExtension->TargetObject, Irp );
  1508. return ntStatus;
  1509. }
  1510. NTSTATUS
  1511. FloppyReadWrite(
  1512. IN PDEVICE_OBJECT DeviceObject,
  1513. IN PIRP Irp
  1514. )
  1515. /*++
  1516. Routine Description:
  1517. This routine is called by the I/O system to read or write to a
  1518. device that we control.
  1519. Arguments:
  1520. DeviceObject - a pointer to the object that represents the device
  1521. that I/O is to be done on.
  1522. Irp - a pointer to the I/O Request Packet for this request.
  1523. Return Value:
  1524. STATUS_INVALID_PARAMETER if parameters are invalid,
  1525. STATUS_PENDING otherwise.
  1526. --*/
  1527. {
  1528. PIO_STACK_LOCATION irpSp;
  1529. NTSTATUS ntStatus;
  1530. PDISKETTE_EXTENSION disketteExtension;
  1531. FloppyDump( FLOPSHOW, ("FloppyReadWrite...\n") );
  1532. disketteExtension = DeviceObject->DeviceExtension;
  1533. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1534. //
  1535. // This IRP was sent to the function driver.
  1536. // We need to check if we are currently holding requests.
  1537. //
  1538. ExAcquireFastMutex(&(disketteExtension->HoldNewReqMutex));
  1539. if ( disketteExtension->HoldNewRequests ) {
  1540. ntStatus = FloppyQueueRequest( disketteExtension, Irp );
  1541. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  1542. return ntStatus;
  1543. }
  1544. //
  1545. // If the device is not active (not started yet or removed) we will
  1546. // just fail this request outright.
  1547. //
  1548. if ( disketteExtension->IsRemoved || !disketteExtension->IsStarted) {
  1549. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  1550. if ( disketteExtension->IsRemoved) {
  1551. ntStatus = STATUS_DELETE_PENDING;
  1552. } else {
  1553. ntStatus = STATUS_UNSUCCESSFUL;
  1554. }
  1555. Irp->IoStatus.Information = 0;
  1556. Irp->IoStatus.Status = ntStatus;
  1557. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1558. return ntStatus;
  1559. }
  1560. if ( (disketteExtension->MediaType > Unknown) &&
  1561. ((irpSp->Parameters.Read.ByteOffset.LowPart +
  1562. irpSp->Parameters.Read.Length > disketteExtension->ByteCapacity) ||
  1563. ((irpSp->Parameters.Read.Length &
  1564. (disketteExtension->BytesPerSector - 1)) != 0 ))) {
  1565. FloppyDump( FLOPDBGP,
  1566. ("Floppy: Invalid Parameter, rejecting request\n") );
  1567. FloppyDump( FLOPWARN,
  1568. ("Floppy: Starting offset = %lx\n"
  1569. "------ I/O Length = %lx\n"
  1570. "------ ByteCapacity = %lx\n"
  1571. "------ BytesPerSector = %lx\n",
  1572. irpSp->Parameters.Read.ByteOffset.LowPart,
  1573. irpSp->Parameters.Read.Length,
  1574. disketteExtension->ByteCapacity,
  1575. disketteExtension->BytesPerSector) );
  1576. ntStatus = STATUS_INVALID_PARAMETER;
  1577. } else {
  1578. //
  1579. // verify that user is really expecting some I/O operation to
  1580. // occur.
  1581. //
  1582. if (irpSp->Parameters.Read.Length) {
  1583. //
  1584. // Queue request to thread.
  1585. //
  1586. FloppyDump( FLOPIRPPATH,
  1587. ("Floppy: Enqueing up IRP: %p\n",Irp) );
  1588. ntStatus = FlQueueIrpToThread(Irp, disketteExtension);
  1589. } else {
  1590. //
  1591. // Complete this zero length request with no boost.
  1592. //
  1593. Irp->IoStatus.Information = 0;
  1594. Irp->IoStatus.Status = STATUS_SUCCESS;
  1595. FloppyDump(FLOPDBGP,
  1596. ("Zero length r/w request. Completing IRP.\n"));
  1597. ntStatus = STATUS_SUCCESS;
  1598. }
  1599. }
  1600. ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
  1601. if ( ntStatus != STATUS_PENDING ) {
  1602. Irp->IoStatus.Status = ntStatus;
  1603. FloppyDump(FLOPDBGP,
  1604. ("Completing request. NTStatus %x\n",
  1605. ntStatus));
  1606. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1607. }
  1608. return ntStatus;
  1609. }
  1610. NTSTATUS
  1611. FlInterpretError(
  1612. IN UCHAR StatusRegister1,
  1613. IN UCHAR StatusRegister2
  1614. )
  1615. /*++
  1616. Routine Description:
  1617. This routine is called when the floppy controller returns an error.
  1618. Status registers 1 and 2 are passed in, and this returns an appropriate
  1619. error status.
  1620. Arguments:
  1621. StatusRegister1 - the controller's status register #1.
  1622. StatusRegister2 - the controller's status register #2.
  1623. Return Value:
  1624. An NTSTATUS error determined from the status registers.
  1625. --*/
  1626. {
  1627. if ( ( StatusRegister1 & STREG1_CRC_ERROR ) ||
  1628. ( StatusRegister2 & STREG2_CRC_ERROR ) ) {
  1629. FloppyDump(
  1630. FLOPSHOW,
  1631. ("FlInterpretError: STATUS_CRC_ERROR\n")
  1632. );
  1633. return STATUS_CRC_ERROR;
  1634. }
  1635. if ( StatusRegister1 & STREG1_DATA_OVERRUN ) {
  1636. FloppyDump(
  1637. FLOPSHOW,
  1638. ("FlInterpretError: STATUS_DATA_OVERRUN\n")
  1639. );
  1640. return STATUS_DATA_OVERRUN;
  1641. }
  1642. if ( ( StatusRegister1 & STREG1_SECTOR_NOT_FOUND ) ||
  1643. ( StatusRegister1 & STREG1_END_OF_DISKETTE ) ) {
  1644. FloppyDump(
  1645. FLOPSHOW,
  1646. ("FlInterpretError: STATUS_NONEXISTENT_SECTOR\n")
  1647. );
  1648. return STATUS_NONEXISTENT_SECTOR;
  1649. }
  1650. if ( ( StatusRegister2 & STREG2_DATA_NOT_FOUND ) ||
  1651. ( StatusRegister2 & STREG2_BAD_CYLINDER ) ||
  1652. ( StatusRegister2 & STREG2_DELETED_DATA ) ) {
  1653. FloppyDump(
  1654. FLOPSHOW,
  1655. ("FlInterpretError: STATUS_DEVICE_DATA_ERROR\n")
  1656. );
  1657. return STATUS_DEVICE_DATA_ERROR;
  1658. }
  1659. if ( StatusRegister1 & STREG1_WRITE_PROTECTED ) {
  1660. FloppyDump(
  1661. FLOPSHOW,
  1662. ("FlInterpretError: STATUS_MEDIA_WRITE_PROTECTED\n")
  1663. );
  1664. return STATUS_MEDIA_WRITE_PROTECTED;
  1665. }
  1666. if ( StatusRegister1 & STREG1_ID_NOT_FOUND ) {
  1667. FloppyDump(
  1668. FLOPSHOW,
  1669. ("FlInterpretError: STATUS_FLOPPY_ID_MARK_NOT_FOUND\n")
  1670. );
  1671. return STATUS_FLOPPY_ID_MARK_NOT_FOUND;
  1672. }
  1673. if ( StatusRegister2 & STREG2_WRONG_CYLINDER ) {
  1674. FloppyDump(
  1675. FLOPSHOW,
  1676. ("FlInterpretError: STATUS_FLOPPY_WRONG_CYLINDER\n")
  1677. );
  1678. return STATUS_FLOPPY_WRONG_CYLINDER;
  1679. }
  1680. //
  1681. // There's other error bits, but no good status values to map them
  1682. // to. Just return a generic one.
  1683. //
  1684. FloppyDump(
  1685. FLOPSHOW,
  1686. ("FlInterpretError: STATUS_FLOPPY_UNKNOWN_ERROR\n")
  1687. );
  1688. return STATUS_FLOPPY_UNKNOWN_ERROR;
  1689. }
  1690. VOID
  1691. FlFinishOperation(
  1692. IN OUT PIRP Irp,
  1693. IN PDISKETTE_EXTENSION DisketteExtension
  1694. )
  1695. /*++
  1696. Routine Description:
  1697. This routine is called by FloppyThread at the end of any operation
  1698. whether it succeeded or not.
  1699. If the packet is failing due to a hardware error, this routine will
  1700. reinitialize the hardware and retry once.
  1701. When the packet is done, this routine will start the timer to turn
  1702. off the motor, and complete the IRP.
  1703. Arguments:
  1704. Irp - a pointer to the IO Request Packet being processed.
  1705. DisketteExtension - a pointer to the diskette extension for the
  1706. diskette on which the operation occurred.
  1707. Return Value:
  1708. None.
  1709. --*/
  1710. {
  1711. NTSTATUS ntStatus;
  1712. FloppyDump(
  1713. FLOPSHOW,
  1714. ("Floppy: FloppyFinishOperation...\n")
  1715. );
  1716. //
  1717. // See if this packet is being failed due to a hardware error.
  1718. //
  1719. if ( ( Irp->IoStatus.Status != STATUS_SUCCESS ) &&
  1720. ( DisketteExtension->HardwareFailed ) ) {
  1721. DisketteExtension->HardwareFailCount++;
  1722. if ( DisketteExtension->HardwareFailCount <
  1723. HARDWARE_RESET_RETRY_COUNT ) {
  1724. //
  1725. // This is our first time through (that is, we're not retrying
  1726. // the packet after a hardware failure). If it failed this first
  1727. // time because of a hardware problem, set the HardwareFailed flag
  1728. // and put the IRP at the beginning of the request queue.
  1729. //
  1730. ntStatus = FlInitializeControllerHardware( DisketteExtension );
  1731. if ( NT_SUCCESS( ntStatus ) ) {
  1732. FloppyDump(
  1733. FLOPINFO,
  1734. ("Floppy: packet failed; hardware reset. Retry.\n")
  1735. );
  1736. //
  1737. // Force media to be redetermined, in case we messed up
  1738. // and to make sure FlDatarateSpecifyConfigure() gets
  1739. // called.
  1740. //
  1741. DisketteExtension->MediaType = Undetermined;
  1742. FloppyDump(
  1743. FLOPIRPPATH,
  1744. ("Floppy: irp %x failed - back on the queue with it\n",
  1745. Irp)
  1746. );
  1747. ExAcquireFastMutex(&DisketteExtension->ThreadReferenceMutex);
  1748. ASSERT(DisketteExtension->ThreadReferenceCount >= 0);
  1749. (DisketteExtension->ThreadReferenceCount)++;
  1750. ExReleaseFastMutex(&DisketteExtension->ThreadReferenceMutex);
  1751. ExInterlockedInsertHeadList(
  1752. &DisketteExtension->ListEntry,
  1753. &Irp->Tail.Overlay.ListEntry,
  1754. &DisketteExtension->ListSpinLock );
  1755. return;
  1756. }
  1757. FloppyDump(
  1758. FLOPDBGP,
  1759. ("Floppy: packet AND hardware reset failed.\n")
  1760. );
  1761. }
  1762. }
  1763. //
  1764. // If we didn't already RETURN, we're done with this packet so
  1765. // reset the HardwareFailCount for the next packet.
  1766. //
  1767. DisketteExtension->HardwareFailCount = 0;
  1768. //
  1769. // If this request was unsuccessful and the error is one that can be
  1770. // remedied by the user, save the Device Object so that the file system,
  1771. // after reaching its original entry point, can know the real device.
  1772. //
  1773. if ( !NT_SUCCESS( Irp->IoStatus.Status ) &&
  1774. IoIsErrorUserInduced( Irp->IoStatus.Status ) ) {
  1775. IoSetHardErrorOrVerifyDevice( Irp, DisketteExtension->DeviceObject );
  1776. }
  1777. //
  1778. // Even if the operation failed, it probably had to wait for the drive
  1779. // to spin up or somesuch so we'll always complete the request with the
  1780. // standard priority boost.
  1781. //
  1782. if ( ( Irp->IoStatus.Status != STATUS_SUCCESS ) &&
  1783. ( Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED ) &&
  1784. ( Irp->IoStatus.Status != STATUS_NO_MEDIA_IN_DEVICE ) ) {
  1785. FloppyDump(
  1786. FLOPDBGP,
  1787. ("Floppy: IRP failed with error %lx\n", Irp->IoStatus.Status)
  1788. );
  1789. } else {
  1790. FloppyDump(
  1791. FLOPINFO,
  1792. ("Floppy: IoStatus.Status = %x\n", Irp->IoStatus.Status)
  1793. );
  1794. }
  1795. FloppyDump(
  1796. FLOPINFO,
  1797. ("Floppy: IoStatus.Information = %x\n", Irp->IoStatus.Information)
  1798. );
  1799. FloppyDump(
  1800. FLOPIRPPATH,
  1801. ("Floppy: Finishing up IRP: %p\n",Irp)
  1802. );
  1803. //
  1804. // In order to get explorer to request a format of unformatted media
  1805. // the STATUS_UNRECOGNIZED_MEDIA error must be translated to a generic
  1806. // STATUS_UNSUCCESSFUL error.
  1807. //
  1808. // if ( Irp->IoStatus.Status == STATUS_UNRECOGNIZED_MEDIA ) {
  1809. // Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  1810. // }
  1811. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  1812. }
  1813. NTSTATUS
  1814. FlStartDrive(
  1815. IN OUT PDISKETTE_EXTENSION DisketteExtension,
  1816. IN PIRP Irp,
  1817. IN BOOLEAN WriteOperation,
  1818. IN BOOLEAN SetUpMedia,
  1819. IN BOOLEAN IgnoreChange
  1820. )
  1821. /*++
  1822. Routine Description:
  1823. This routine is called at the beginning of every operation. It cancels
  1824. the motor timer if it's on, turns the motor on and waits for it to
  1825. spin up if it was off, resets the disk change line and returns
  1826. VERIFY_REQUIRED if the disk has been changed, determines the diskette
  1827. media type if it's not known and SetUpMedia=TRUE, and makes sure that
  1828. the disk isn't write protected if WriteOperation = TRUE.
  1829. Arguments:
  1830. DisketteExtension - a pointer to our data area for the drive being
  1831. started.
  1832. Irp - Supplies the I/O request packet.
  1833. WriteOperation - TRUE if the diskette will be written to, FALSE
  1834. otherwise.
  1835. SetUpMedia - TRUE if the media type of the diskette in the drive
  1836. should be determined.
  1837. IgnoreChange - Do not return VERIFY_REQUIRED eventhough we are mounting
  1838. for the first time.
  1839. Return Value:
  1840. STATUS_SUCCESS if the drive is started properly; appropriate error
  1841. propogated otherwise.
  1842. --*/
  1843. {
  1844. LARGE_INTEGER delay;
  1845. BOOLEAN motorStarted;
  1846. BOOLEAN diskChanged;
  1847. UCHAR driveStatus;
  1848. NTSTATUS ntStatus = STATUS_SUCCESS;
  1849. FDC_ENABLE_PARMS fdcEnableParms;
  1850. FDC_DISK_CHANGE_PARMS fdcDiskChangeParms;
  1851. FloppyDump(
  1852. FLOPSHOW,
  1853. ("Floppy: FloppyStartDrive...\n")
  1854. );
  1855. //
  1856. // IMPORTANT
  1857. // NOTE
  1858. // COMMENT
  1859. //
  1860. // Here we will copy the BIOS floppy configuration on top of the
  1861. // highest media value in our global array so that any type of processing
  1862. // that will recalibrate the drive can have it done here.
  1863. // An optimization would be to only do it when we will try to recalibrate
  1864. // the driver or media in it.
  1865. // At this point, we ensure that on any processing of a command we
  1866. // are going to have the real values inthe first entry of the array for
  1867. // driver constants.
  1868. //
  1869. DriveMediaConstants[DriveMediaLimits[DisketteExtension->DriveType].
  1870. HighestDriveMediaType] = DisketteExtension->BiosDriveMediaConstants;
  1871. if ((DisketteExtension->MediaType == Undetermined) ||
  1872. (DisketteExtension->MediaType == Unknown)) {
  1873. DisketteExtension->DriveMediaConstants = DriveMediaConstants[0];
  1874. }
  1875. //
  1876. // Grab the timer spin lock and cancel the timer, since we want the
  1877. // motor to run for the whole operation. If the proper drive is
  1878. // already running, great; if not, start the motor and wait for it
  1879. // to spin up.
  1880. //
  1881. fdcEnableParms.DriveOnValue = DisketteExtension->DriveOnValue;
  1882. if ( WriteOperation ) {
  1883. fdcEnableParms.TimeToWait =
  1884. DisketteExtension->DriveMediaConstants.MotorSettleTimeWrite;
  1885. } else {
  1886. fdcEnableParms.TimeToWait =
  1887. DisketteExtension->DriveMediaConstants.MotorSettleTimeRead;
  1888. }
  1889. ntStatus = FlFdcDeviceIo( DisketteExtension->TargetObject,
  1890. IOCTL_DISK_INTERNAL_ENABLE_FDC_DEVICE,
  1891. &fdcEnableParms );
  1892. motorStarted = fdcEnableParms.MotorStarted;
  1893. if (NT_SUCCESS(ntStatus)) {
  1894. fdcDiskChangeParms.DriveOnValue = DisketteExtension->DriveOnValue;
  1895. ntStatus = FlFdcDeviceIo( DisketteExtension->TargetObject,
  1896. IOCTL_DISK_INTERNAL_GET_FDC_DISK_CHANGE,
  1897. &fdcDiskChangeParms );
  1898. driveStatus = fdcDiskChangeParms.DriveStatus;
  1899. }
  1900. if (!NT_SUCCESS(ntStatus)) {
  1901. return ntStatus;
  1902. }
  1903. //
  1904. // Support for 360K drives:
  1905. // They have no change line, so we will assume a power up of the motor
  1906. // to be equivalent to a change of floppy (we assume noone will
  1907. // change the floppy while it is turning.
  1908. // So force a VERIFY here (unless the file system explicitly turned
  1909. // it off).
  1910. //
  1911. if ( ((DisketteExtension->DriveType == DRIVE_TYPE_0360) &&
  1912. motorStarted) ||
  1913. ((DisketteExtension->DriveType != DRIVE_TYPE_0360) &&
  1914. driveStatus & DSKCHG_DISKETTE_REMOVED) ) {
  1915. FloppyDump(
  1916. FLOPSHOW,
  1917. ("Floppy: disk changed...\n")
  1918. );
  1919. DisketteExtension->MediaType = Undetermined;
  1920. //
  1921. // If the volume is mounted, we must tell the filesystem to
  1922. // verify that the media in the drive is the same volume.
  1923. //
  1924. if ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED ) {
  1925. if (Irp) {
  1926. IoSetHardErrorOrVerifyDevice( Irp,
  1927. DisketteExtension->DeviceObject );
  1928. }
  1929. DisketteExtension->DeviceObject->Flags |= DO_VERIFY_VOLUME;
  1930. }
  1931. //
  1932. // Only go through the device reset if we did get the flag set
  1933. // We really only want to go throught here if the diskette changed,
  1934. // but on 360 it will always say the diskette has changed.
  1935. // So based on our previous test, only proceed if it is NOT
  1936. // a 360K driver
  1937. if (DisketteExtension->DriveType != DRIVE_TYPE_0360) {
  1938. //
  1939. // Now seek twice to reset the "disk changed" line. First
  1940. // seek to 1.
  1941. //
  1942. // Normally we'd do a READ ID after a seek. However, we don't
  1943. // even know if this disk is formatted. We're not really
  1944. // trying to get anywhere; we're just doing this to reset the
  1945. // "disk changed" line so we'll skip the READ ID.
  1946. //
  1947. DisketteExtension->FifoBuffer[0] = COMMND_SEEK;
  1948. DisketteExtension->FifoBuffer[1] = DisketteExtension->DeviceUnit;
  1949. DisketteExtension->FifoBuffer[2] = 1;
  1950. ntStatus = FlIssueCommand( DisketteExtension,
  1951. DisketteExtension->FifoBuffer,
  1952. DisketteExtension->FifoBuffer,
  1953. NULL,
  1954. 0,
  1955. 0 );
  1956. if ( !NT_SUCCESS( ntStatus ) ) {
  1957. FloppyDump( FLOPWARN,
  1958. ("Floppy: seek to 1 returned %x\n", ntStatus) );
  1959. return ntStatus;
  1960. } else {
  1961. if (!( DisketteExtension->FifoBuffer[0] & STREG0_SEEK_COMPLETE)
  1962. || ( DisketteExtension->FifoBuffer[1] != 1 ) ) {
  1963. FloppyDump(
  1964. FLOPWARN,
  1965. ("Floppy: Seek to 1 had bad return registers\n")
  1966. );
  1967. DisketteExtension->HardwareFailed = TRUE;
  1968. return STATUS_FLOPPY_BAD_REGISTERS;
  1969. }
  1970. }
  1971. //
  1972. // Seek back to 0. We can once again skip the READ ID.
  1973. //
  1974. DisketteExtension->FifoBuffer[0] = COMMND_SEEK;
  1975. DisketteExtension->FifoBuffer[1] = DisketteExtension->DeviceUnit;
  1976. DisketteExtension->FifoBuffer[2] = 0;
  1977. //
  1978. // Floppy drives use by Toshiba systems require a delay
  1979. // when this operation is performed.
  1980. //
  1981. delay.LowPart = (ULONG) -900;
  1982. delay.HighPart = -1;
  1983. KeDelayExecutionThread( KernelMode, FALSE, &delay );
  1984. ntStatus = FlIssueCommand( DisketteExtension,
  1985. DisketteExtension->FifoBuffer,
  1986. DisketteExtension->FifoBuffer,
  1987. NULL,
  1988. 0,
  1989. 0 );
  1990. //
  1991. // Again, for Toshiba floppy drives, a delay is required.
  1992. //
  1993. delay.LowPart = (ULONG) -5;
  1994. delay.HighPart = -1;
  1995. KeDelayExecutionThread( KernelMode, FALSE, &delay );
  1996. if ( !NT_SUCCESS( ntStatus ) ) {
  1997. FloppyDump( FLOPWARN,
  1998. ("Floppy: seek to 0 returned %x\n", ntStatus) );
  1999. return ntStatus;
  2000. } else {
  2001. if (!(DisketteExtension->FifoBuffer[0] & STREG0_SEEK_COMPLETE)
  2002. || ( DisketteExtension->FifoBuffer[1] != 0 ) ) {
  2003. FloppyDump(
  2004. FLOPWARN,
  2005. ("Floppy: Seek to 0 had bad return registers\n")
  2006. );
  2007. DisketteExtension->HardwareFailed = TRUE;
  2008. return STATUS_FLOPPY_BAD_REGISTERS;
  2009. }
  2010. }
  2011. ntStatus = FlFdcDeviceIo( DisketteExtension->TargetObject,
  2012. IOCTL_DISK_INTERNAL_GET_FDC_DISK_CHANGE,
  2013. &fdcDiskChangeParms );
  2014. driveStatus = fdcDiskChangeParms.DriveStatus;
  2015. if (!NT_SUCCESS(ntStatus)) {
  2016. return ntStatus;
  2017. }
  2018. if ( driveStatus & DSKCHG_DISKETTE_REMOVED ) {
  2019. //
  2020. // If "disk changed" is still set after the double seek, the
  2021. // drive door must be opened.
  2022. //
  2023. FloppyDump(
  2024. FLOPINFO,
  2025. ("Floppy: close the door!\n")
  2026. );
  2027. //
  2028. // Turn off the flag for now so that we will not get so many
  2029. // gratuitous verifys. It will be set again the next time.
  2030. //
  2031. if(DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED) {
  2032. DisketteExtension->DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
  2033. }
  2034. return STATUS_NO_MEDIA_IN_DEVICE;
  2035. }
  2036. }
  2037. //
  2038. // IgnoreChange indicates the file system is in the process
  2039. // of performing a verify so do not return verify required.
  2040. //
  2041. if ( IgnoreChange == FALSE ) {
  2042. if ( DisketteExtension->DeviceObject->Vpb->Flags & VPB_MOUNTED ) {
  2043. //
  2044. // Drive WAS mounted, but door was opened since the last time
  2045. // we checked so tell the file system to verify the diskette.
  2046. //
  2047. FloppyDump(
  2048. FLOPSHOW,
  2049. ("Floppy: start drive - verify required because door opened\n")
  2050. );
  2051. return STATUS_VERIFY_REQUIRED;
  2052. } else {
  2053. return STATUS_IO_DEVICE_ERROR;
  2054. }
  2055. }
  2056. }
  2057. if ( SetUpMedia ) {
  2058. if ( DisketteExtension->MediaType == Undetermined ) {
  2059. ntStatus = FlDetermineMediaType( DisketteExtension );
  2060. } else {
  2061. if ( DisketteExtension->MediaType == Unknown ) {
  2062. //
  2063. // We've already tried to determine the media type and
  2064. // failed. It's probably not formatted.
  2065. //
  2066. FloppyDump(
  2067. FLOPSHOW,
  2068. ("Floppy - start drive - media type was unknown\n")
  2069. );
  2070. return STATUS_UNRECOGNIZED_MEDIA;
  2071. } else {
  2072. if ( DisketteExtension->DriveMediaType !=
  2073. DisketteExtension->LastDriveMediaType ) {
  2074. //
  2075. // Last drive/media combination accessed by the
  2076. // controller was different, so set up the controller.
  2077. //
  2078. ntStatus = FlDatarateSpecifyConfigure( DisketteExtension );
  2079. if (!NT_SUCCESS(ntStatus)) {
  2080. FloppyDump(
  2081. FLOPWARN,
  2082. ("Floppy: start drive - bad status from datarate"
  2083. "------ specify %x\n",
  2084. ntStatus)
  2085. );
  2086. }
  2087. }
  2088. }
  2089. }
  2090. }
  2091. //
  2092. // If this is a WRITE, check the drive to make sure it's not write
  2093. // protected. If so, return an error.
  2094. //
  2095. if ( ( WriteOperation ) && ( NT_SUCCESS( ntStatus ) ) ) {
  2096. DisketteExtension->FifoBuffer[0] = COMMND_SENSE_DRIVE_STATUS;
  2097. DisketteExtension->FifoBuffer[1] = DisketteExtension->DeviceUnit;
  2098. ntStatus = FlIssueCommand( DisketteExtension,
  2099. DisketteExtension->FifoBuffer,
  2100. DisketteExtension->FifoBuffer,
  2101. NULL,
  2102. 0,
  2103. 0 );
  2104. if ( !NT_SUCCESS( ntStatus ) ) {
  2105. FloppyDump(
  2106. FLOPWARN,
  2107. ("Floppy: SENSE_DRIVE returned %x\n", ntStatus)
  2108. );
  2109. return ntStatus;
  2110. }
  2111. if ( DisketteExtension->FifoBuffer[0] & STREG3_WRITE_PROTECTED ) {
  2112. FloppyDump(
  2113. FLOPSHOW,
  2114. ("Floppy: start drive - media is write protected\n")
  2115. );
  2116. return STATUS_MEDIA_WRITE_PROTECTED;
  2117. }
  2118. }
  2119. return ntStatus;
  2120. }
  2121. NTSTATUS
  2122. FlDatarateSpecifyConfigure(
  2123. IN PDISKETTE_EXTENSION DisketteExtension
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. This routine is called to set up the controller every time a new type
  2128. of diskette is to be accessed. It issues the CONFIGURE command if
  2129. it's available, does a SPECIFY, sets the data rate, and RECALIBRATEs
  2130. the drive.
  2131. The caller must set DisketteExtension->DriveMediaType before calling
  2132. this routine.
  2133. Arguments:
  2134. DisketteExtension - pointer to our data area for the drive to be
  2135. prepared.
  2136. Return Value:
  2137. STATUS_SUCCESS if the controller is properly prepared; appropriate
  2138. error propogated otherwise.
  2139. --*/
  2140. {
  2141. NTSTATUS ntStatus = STATUS_SUCCESS;
  2142. //
  2143. // If the controller has a CONFIGURE command, use it to enable implied
  2144. // seeks. If it doesn't, we'll find out here the first time through.
  2145. //
  2146. if ( DisketteExtension->ControllerConfigurable ) {
  2147. DisketteExtension->FifoBuffer[0] = COMMND_CONFIGURE;
  2148. DisketteExtension->FifoBuffer[1] = 0;
  2149. DisketteExtension->FifoBuffer[2] = COMMND_CONFIGURE_FIFO_THRESHOLD;
  2150. DisketteExtension->FifoBuffer[2] += COMMND_CONFIGURE_DISABLE_POLLING;
  2151. if (!DisketteExtension->DriveMediaConstants.CylinderShift) {
  2152. DisketteExtension->FifoBuffer[2] += COMMND_CONFIGURE_IMPLIED_SEEKS;
  2153. }
  2154. DisketteExtension->FifoBuffer[3] = 0;
  2155. ntStatus = FlIssueCommand( DisketteExtension,
  2156. DisketteExtension->FifoBuffer,
  2157. DisketteExtension->FifoBuffer,
  2158. NULL,
  2159. 0,
  2160. 0 );
  2161. if ( ntStatus == STATUS_DEVICE_NOT_READY ) {
  2162. DisketteExtension->ControllerConfigurable = FALSE;
  2163. ntStatus = STATUS_SUCCESS;
  2164. }
  2165. }
  2166. //
  2167. // Issue SPECIFY command to program the head load and unload
  2168. // rates, the drive step rate, and the DMA data transfer mode.
  2169. //
  2170. if ( NT_SUCCESS( ntStatus ) ||
  2171. ntStatus == STATUS_DEVICE_NOT_READY ) {
  2172. DisketteExtension->FifoBuffer[0] = COMMND_SPECIFY;
  2173. DisketteExtension->FifoBuffer[1] =
  2174. DisketteExtension->DriveMediaConstants.StepRateHeadUnloadTime;
  2175. DisketteExtension->FifoBuffer[2] =
  2176. DisketteExtension->DriveMediaConstants.HeadLoadTime;
  2177. ntStatus = FlIssueCommand( DisketteExtension,
  2178. DisketteExtension->FifoBuffer,
  2179. DisketteExtension->FifoBuffer,
  2180. NULL,
  2181. 0,
  2182. 0 );
  2183. if ( NT_SUCCESS( ntStatus ) ) {
  2184. //
  2185. // Program the data rate
  2186. //
  2187. ntStatus = FlFdcDeviceIo( DisketteExtension->TargetObject,
  2188. IOCTL_DISK_INTERNAL_SET_FDC_DATA_RATE,
  2189. &DisketteExtension->
  2190. DriveMediaConstants.DataTransferRate );
  2191. //
  2192. // Recalibrate the drive, now that we've changed all its
  2193. // parameters.
  2194. //
  2195. if (NT_SUCCESS(ntStatus)) {
  2196. ntStatus = FlRecalibrateDrive( DisketteExtension );
  2197. }
  2198. } else {
  2199. FloppyDump(
  2200. FLOPINFO,
  2201. ("Floppy: Failed specify %x\n", ntStatus)
  2202. );
  2203. }
  2204. } else {
  2205. FloppyDump(
  2206. FLOPINFO,
  2207. ("Floppy: Failed configuration %x\n", ntStatus)
  2208. );
  2209. }
  2210. if ( NT_SUCCESS( ntStatus ) ) {
  2211. DisketteExtension->LastDriveMediaType =
  2212. DisketteExtension->DriveMediaType;
  2213. } else {
  2214. DisketteExtension->LastDriveMediaType = Unknown;
  2215. FloppyDump(
  2216. FLOPINFO,
  2217. ("Floppy: Failed recalibrate %x\n", ntStatus)
  2218. );
  2219. }
  2220. return ntStatus;
  2221. }
  2222. NTSTATUS
  2223. FlRecalibrateDrive(
  2224. IN PDISKETTE_EXTENSION DisketteExtension
  2225. )
  2226. /*++
  2227. Routine Description:
  2228. This routine recalibrates a drive. It is called whenever we're
  2229. setting up to access a new diskette, and after certain errors. It
  2230. will actually recalibrate twice, since many controllers stop after
  2231. 77 steps and many disks have 80 tracks.
  2232. Arguments:
  2233. DisketteExtension - pointer to our data area for the drive to be
  2234. recalibrated.
  2235. Return Value:
  2236. STATUS_SUCCESS if the drive is successfully recalibrated; appropriate
  2237. error is propogated otherwise.
  2238. --*/
  2239. {
  2240. NTSTATUS ntStatus;
  2241. UCHAR recalibrateCount;
  2242. recalibrateCount = 0;
  2243. do {
  2244. //
  2245. // Issue the recalibrate command
  2246. //
  2247. DisketteExtension->FifoBuffer[0] = COMMND_RECALIBRATE;
  2248. DisketteExtension->FifoBuffer[1] = DisketteExtension->DeviceUnit;
  2249. ntStatus = FlIssueCommand( DisketteExtension,
  2250. DisketteExtension->FifoBuffer,
  2251. DisketteExtension->FifoBuffer,
  2252. NULL,
  2253. 0,
  2254. 0 );
  2255. if ( !NT_SUCCESS( ntStatus ) ) {
  2256. FloppyDump(
  2257. FLOPWARN,
  2258. ("Floppy: recalibrate returned %x\n", ntStatus)
  2259. );
  2260. }
  2261. if ( NT_SUCCESS( ntStatus ) ) {
  2262. if ( !( DisketteExtension->FifoBuffer[0] & STREG0_SEEK_COMPLETE ) ||
  2263. ( DisketteExtension->FifoBuffer[1] != 0 ) ) {
  2264. FloppyDump(
  2265. FLOPWARN,
  2266. ("Floppy: recalibrate had bad registers\n")
  2267. );
  2268. DisketteExtension->HardwareFailed = TRUE;
  2269. ntStatus = STATUS_FLOPPY_BAD_REGISTERS;
  2270. }
  2271. }
  2272. recalibrateCount++;
  2273. } while ( ( !NT_SUCCESS( ntStatus ) ) && ( recalibrateCount < 2 ) );
  2274. FloppyDump( FLOPSHOW,
  2275. ("Floppy: FloppyRecalibrateDrive: status %x, count %d\n",
  2276. ntStatus, recalibrateCount)
  2277. );
  2278. return ntStatus;
  2279. }
  2280. NTSTATUS
  2281. FlDetermineMediaType(
  2282. IN OUT PDISKETTE_EXTENSION DisketteExtension
  2283. )
  2284. /*++
  2285. Routine Description:
  2286. This routine is called by FlStartDrive() when the media type is
  2287. unknown. It assumes the largest media supported by the drive is
  2288. available, and keeps trying lower values until it finds one that
  2289. works.
  2290. Arguments:
  2291. DisketteExtension - pointer to our data area for the drive whose
  2292. media is to checked.
  2293. Return Value:
  2294. STATUS_SUCCESS if the type of the media is determined; appropriate
  2295. error propogated otherwise.
  2296. --*/
  2297. {
  2298. NTSTATUS ntStatus;
  2299. PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
  2300. BOOLEAN mediaTypesExhausted;
  2301. ULONG retries = 0;
  2302. USHORT sectorLengthCode;
  2303. PBOOT_SECTOR_INFO bootSector;
  2304. LARGE_INTEGER offset;
  2305. PIRP irp;
  2306. FloppyDump(
  2307. FLOPSHOW,
  2308. ("FlDetermineMediaType...\n")
  2309. );
  2310. DisketteExtension->IsReadOnly = FALSE;
  2311. //
  2312. // Try up to three times for read the media id.
  2313. //
  2314. for ( retries = 0; retries < 3; retries++ ) {
  2315. if (retries) {
  2316. //
  2317. // We're retrying the media determination because
  2318. // some controllers don't always want to work
  2319. // at setup. First we'll reset the device to give
  2320. // it a better chance of working.
  2321. //
  2322. FloppyDump(
  2323. FLOPINFO,
  2324. ("FlDetermineMediaType: Resetting controller\n")
  2325. );
  2326. FlInitializeControllerHardware( DisketteExtension );
  2327. }
  2328. //
  2329. // Assume that the largest supported media is in the drive. If that
  2330. // turns out to be untrue, we'll try successively smaller media types
  2331. // until we find what's really in there (or we run out and decide
  2332. // that the media isn't formatted).
  2333. //
  2334. DisketteExtension->DriveMediaType =
  2335. DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType;
  2336. DisketteExtension->DriveMediaConstants =
  2337. DriveMediaConstants[DisketteExtension->DriveMediaType];
  2338. mediaTypesExhausted = FALSE;
  2339. do {
  2340. ntStatus = FlDatarateSpecifyConfigure( DisketteExtension );
  2341. if ( !NT_SUCCESS( ntStatus ) ) {
  2342. //
  2343. // The SPECIFY or CONFIGURE commands resulted in an error.
  2344. // Force ourselves out of this loop and return error.
  2345. //
  2346. FloppyDump(
  2347. FLOPINFO,
  2348. ("FlDetermineMediaType: DatarateSpecify failed %x\n", ntStatus)
  2349. );
  2350. mediaTypesExhausted = TRUE;
  2351. } else {
  2352. //
  2353. // Use the media constants table when trying to determine
  2354. // media type.
  2355. //
  2356. driveMediaConstants =
  2357. &DriveMediaConstants[DisketteExtension->DriveMediaType];
  2358. //
  2359. // Now try to read the ID from wherever we're at.
  2360. //
  2361. DisketteExtension->FifoBuffer[1] = (UCHAR)
  2362. ( DisketteExtension->DeviceUnit |
  2363. ( ( driveMediaConstants->NumberOfHeads - 1 ) << 2 ) );
  2364. DisketteExtension->FifoBuffer[0] =
  2365. COMMND_READ_ID + COMMND_OPTION_MFM;
  2366. ntStatus = FlIssueCommand( DisketteExtension,
  2367. DisketteExtension->FifoBuffer,
  2368. DisketteExtension->FifoBuffer,
  2369. NULL,
  2370. 0,
  2371. 0 );
  2372. if ((!NT_SUCCESS( ntStatus)) ||
  2373. ((DisketteExtension->FifoBuffer[0]&(~STREG0_SEEK_COMPLETE)) !=
  2374. (UCHAR)( ( DisketteExtension->DeviceUnit ) |
  2375. ((driveMediaConstants->NumberOfHeads - 1 ) << 2 ))) ||
  2376. ( DisketteExtension->FifoBuffer[1] != 0 ) ||
  2377. ( DisketteExtension->FifoBuffer[2] != 0 )) {
  2378. FloppyDump(
  2379. FLOPINFO,
  2380. ("Floppy: READID failed trying lower media\n"
  2381. "------ status = %x\n"
  2382. "------ SR0 = %x\n"
  2383. "------ SR1 = %x\n"
  2384. "------ SR2 = %x\n",
  2385. ntStatus,
  2386. DisketteExtension->FifoBuffer[0],
  2387. DisketteExtension->FifoBuffer[1],
  2388. DisketteExtension->FifoBuffer[2])
  2389. );
  2390. DisketteExtension->DriveMediaType--;
  2391. DisketteExtension->DriveMediaConstants =
  2392. DriveMediaConstants[DisketteExtension->DriveMediaType];
  2393. if (ntStatus != STATUS_DEVICE_NOT_READY) {
  2394. ntStatus = STATUS_UNRECOGNIZED_MEDIA;
  2395. }
  2396. //
  2397. // Next comparison must be signed, for when
  2398. // LowestDriveMediaType = 0.
  2399. //
  2400. if ( (CHAR)( DisketteExtension->DriveMediaType ) <
  2401. (CHAR)( DriveMediaLimits[DisketteExtension->DriveType].
  2402. LowestDriveMediaType ) ) {
  2403. DisketteExtension->MediaType = Unknown;
  2404. mediaTypesExhausted = TRUE;
  2405. FloppyDump(
  2406. FLOPINFO,
  2407. ("Floppy: Unrecognized media.\n")
  2408. );
  2409. }
  2410. }
  2411. }
  2412. } while ( ( !NT_SUCCESS( ntStatus ) ) && !( mediaTypesExhausted ) );
  2413. if (NT_SUCCESS(ntStatus)) {
  2414. //
  2415. // We determined the media type. Time to move on.
  2416. //
  2417. FloppyDump(
  2418. FLOPINFO,
  2419. ("Floppy: Determined media type %d\n", retries)
  2420. );
  2421. break;
  2422. }
  2423. }
  2424. if ( (!NT_SUCCESS( ntStatus )) || mediaTypesExhausted) {
  2425. FloppyDump(
  2426. FLOPINFO,
  2427. ("Floppy: failed determine types status = %x %s\n",
  2428. ntStatus,
  2429. mediaTypesExhausted ? "media types exhausted" : "")
  2430. );
  2431. return ntStatus;
  2432. }
  2433. DisketteExtension->MediaType = driveMediaConstants->MediaType;
  2434. DisketteExtension->BytesPerSector = driveMediaConstants->BytesPerSector;
  2435. DisketteExtension->ByteCapacity =
  2436. ( driveMediaConstants->BytesPerSector ) *
  2437. driveMediaConstants->SectorsPerTrack *
  2438. ( 1 + driveMediaConstants->MaximumTrack ) *
  2439. driveMediaConstants->NumberOfHeads;
  2440. FloppyDump(
  2441. FLOPINFO,
  2442. ("FlDetermineMediaType: MediaType is %x, bytes per sector %d, capacity %d\n",
  2443. DisketteExtension->MediaType,
  2444. DisketteExtension->BytesPerSector,
  2445. DisketteExtension->ByteCapacity)
  2446. );
  2447. //
  2448. // Structure copy the media constants into the diskette extension.
  2449. //
  2450. DisketteExtension->DriveMediaConstants =
  2451. DriveMediaConstants[DisketteExtension->DriveMediaType];
  2452. //
  2453. // Check the boot sector for any overriding geometry information.
  2454. //
  2455. FlCheckBootSector(DisketteExtension);
  2456. return ntStatus;
  2457. }
  2458. VOID
  2459. FlAllocateIoBuffer(
  2460. IN OUT PDISKETTE_EXTENSION DisketteExtension,
  2461. IN ULONG BufferSize
  2462. )
  2463. /*++
  2464. Routine Description:
  2465. This routine allocates a PAGE_SIZE io buffer.
  2466. Arguments:
  2467. ControllerData - Supplies the controller data.
  2468. BufferSize - Supplies the number of bytes to allocate.
  2469. Return Value:
  2470. None.
  2471. --*/
  2472. {
  2473. BOOLEAN allocateContiguous;
  2474. LARGE_INTEGER maxDmaAddress;
  2475. if (DisketteExtension->IoBuffer) {
  2476. if (DisketteExtension->IoBufferSize >= BufferSize) {
  2477. return;
  2478. }
  2479. FlFreeIoBuffer(DisketteExtension);
  2480. }
  2481. if (BufferSize > DisketteExtension->MaxTransferSize ) {
  2482. allocateContiguous = TRUE;
  2483. } else {
  2484. allocateContiguous = FALSE;
  2485. }
  2486. if (allocateContiguous) {
  2487. maxDmaAddress.QuadPart = MAXIMUM_DMA_ADDRESS;
  2488. DisketteExtension->IoBuffer = MmAllocateContiguousMemory(BufferSize,
  2489. maxDmaAddress);
  2490. } else {
  2491. DisketteExtension->IoBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
  2492. BufferSize);
  2493. }
  2494. if (!DisketteExtension->IoBuffer) {
  2495. return;
  2496. }
  2497. DisketteExtension->IoBufferMdl = IoAllocateMdl(DisketteExtension->IoBuffer,
  2498. BufferSize, FALSE, FALSE, NULL);
  2499. if (!DisketteExtension->IoBufferMdl) {
  2500. if (allocateContiguous) {
  2501. MmFreeContiguousMemory(DisketteExtension->IoBuffer);
  2502. } else {
  2503. ExFreePool(DisketteExtension->IoBuffer);
  2504. }
  2505. DisketteExtension->IoBuffer = NULL;
  2506. return;
  2507. }
  2508. try {
  2509. MmProbeAndLockPages(DisketteExtension->IoBufferMdl, KernelMode,
  2510. IoModifyAccess);
  2511. } except(EXCEPTION_EXECUTE_HANDLER) {
  2512. FloppyDump(FLOPWARN,
  2513. ("MmProbeAndLockPages failed. Status = %x\n",
  2514. GetExceptionCode())
  2515. );
  2516. if (allocateContiguous) {
  2517. MmFreeContiguousMemory(DisketteExtension->IoBuffer);
  2518. } else {
  2519. ExFreePool(DisketteExtension->IoBuffer);
  2520. }
  2521. DisketteExtension->IoBuffer = NULL;
  2522. return;
  2523. }
  2524. DisketteExtension->IoBufferSize = BufferSize;
  2525. }
  2526. VOID
  2527. FlFreeIoBuffer(
  2528. IN OUT PDISKETTE_EXTENSION DisketteExtension
  2529. )
  2530. /*++
  2531. Routine Description:
  2532. This routine free's the controller's IoBuffer.
  2533. Arguments:
  2534. DisketteExtension - Supplies the controller data.
  2535. Return Value:
  2536. None.
  2537. --*/
  2538. {
  2539. BOOLEAN contiguousBuffer;
  2540. if (!DisketteExtension->IoBuffer) {
  2541. return;
  2542. }
  2543. if (DisketteExtension->IoBufferSize >
  2544. DisketteExtension->MaxTransferSize) {
  2545. contiguousBuffer = TRUE;
  2546. } else {
  2547. contiguousBuffer = FALSE;
  2548. }
  2549. DisketteExtension->IoBufferSize = 0;
  2550. MmUnlockPages(DisketteExtension->IoBufferMdl);
  2551. IoFreeMdl(DisketteExtension->IoBufferMdl);
  2552. DisketteExtension->IoBufferMdl = NULL;
  2553. if (contiguousBuffer) {
  2554. MmFreeContiguousMemory(DisketteExtension->IoBuffer);
  2555. } else {
  2556. ExFreePool(DisketteExtension->IoBuffer);
  2557. }
  2558. DisketteExtension->IoBuffer = NULL;
  2559. }
  2560. VOID
  2561. FloppyThread(
  2562. PVOID Context
  2563. )
  2564. /*++
  2565. Routine Description:
  2566. This is the code executed by the system thread created when the
  2567. floppy driver initializes. This thread loops forever (or until a
  2568. flag is set telling the thread to kill itself) processing packets
  2569. put into the queue by the dispatch routines.
  2570. For each packet, this thread calls appropriate routines to process
  2571. the request, and then calls FlFinishOperation() to complete the
  2572. packet.
  2573. Arguments:
  2574. Context - a pointer to our data area for the controller being
  2575. supported (there is one thread per controller).
  2576. Return Value:
  2577. None.
  2578. --*/
  2579. {
  2580. PIRP irp;
  2581. PIO_STACK_LOCATION irpSp;
  2582. PLIST_ENTRY request;
  2583. PDISKETTE_EXTENSION disketteExtension = Context;
  2584. NTSTATUS ntStatus = STATUS_SUCCESS;
  2585. NTSTATUS waitStatus;
  2586. LARGE_INTEGER queueWait;
  2587. LARGE_INTEGER acquireWait;
  2588. ULONG inx;
  2589. //
  2590. // Set thread priority to lowest realtime level.
  2591. //
  2592. KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
  2593. queueWait.QuadPart = -(1 * 1000 * 10000);
  2594. acquireWait.QuadPart = -(15 * 1000 * 10000);
  2595. do {
  2596. //
  2597. // Wait for a request from the dispatch routines.
  2598. // KeWaitForSingleObject won't return error here - this thread
  2599. // isn't alertable and won't take APCs, and we're not passing in
  2600. // a timeout.
  2601. //
  2602. for (inx = 0; inx < 3; inx++) {
  2603. waitStatus = KeWaitForSingleObject(
  2604. (PVOID) &disketteExtension->RequestSemaphore,
  2605. Executive,
  2606. KernelMode,
  2607. FALSE,
  2608. &queueWait );
  2609. if (waitStatus == STATUS_TIMEOUT) {
  2610. ExAcquireFastMutex(&disketteExtension->PowerDownMutex);
  2611. if (disketteExtension->ReceivedQueryPower == TRUE) {
  2612. ExReleaseFastMutex(&disketteExtension->PowerDownMutex);
  2613. break;
  2614. } else {
  2615. ExReleaseFastMutex(&disketteExtension->PowerDownMutex);
  2616. }
  2617. } else {
  2618. break;
  2619. }
  2620. }
  2621. if (waitStatus == STATUS_TIMEOUT) {
  2622. if (disketteExtension->FloppyControllerAllocated) {
  2623. FloppyDump(FLOPSHOW,
  2624. ("Floppy: Timed Out - Turning off the motor\n")
  2625. );
  2626. FlFdcDeviceIo( disketteExtension->TargetObject,
  2627. IOCTL_DISK_INTERNAL_DISABLE_FDC_DEVICE,
  2628. NULL );
  2629. FlFdcDeviceIo( disketteExtension->TargetObject,
  2630. IOCTL_DISK_INTERNAL_RELEASE_FDC,
  2631. disketteExtension->DeviceObject );
  2632. disketteExtension->FloppyControllerAllocated = FALSE;
  2633. }
  2634. ExAcquireFastMutex(&disketteExtension->ThreadReferenceMutex);
  2635. if (disketteExtension->ThreadReferenceCount == 0) {
  2636. disketteExtension->ThreadReferenceCount = -1;
  2637. ASSERT(disketteExtension->FloppyThread != NULL);
  2638. //
  2639. // FloppyThread could be NULL in the unlikely event the
  2640. // ObReferenceObjectByHandle failed when we created the
  2641. // thread.
  2642. //
  2643. if (disketteExtension->FloppyThread != NULL) {
  2644. ObDereferenceObject(disketteExtension->FloppyThread);
  2645. disketteExtension->FloppyThread = NULL;
  2646. }
  2647. ExReleaseFastMutex(&disketteExtension->ThreadReferenceMutex);
  2648. FloppyPageEntireDriver();
  2649. FloppyDump(FLOPDBGP,
  2650. ("Floppy: Terminating thread in FloppyThread.\n")
  2651. );
  2652. ExAcquireFastMutex(&disketteExtension->PowerDownMutex);
  2653. if (disketteExtension->ReceivedQueryPower == TRUE) {
  2654. disketteExtension->ReceivedQueryPower = FALSE;
  2655. KeSetEvent(&disketteExtension->QueryPowerEvent,
  2656. IO_NO_INCREMENT,
  2657. FALSE);
  2658. }
  2659. ExReleaseFastMutex(&disketteExtension->PowerDownMutex);
  2660. PsTerminateSystemThread( STATUS_SUCCESS );
  2661. }
  2662. ExReleaseFastMutex(&disketteExtension->ThreadReferenceMutex);
  2663. continue;
  2664. }
  2665. while (request = ExInterlockedRemoveHeadList(
  2666. &disketteExtension->ListEntry,
  2667. &disketteExtension->ListSpinLock)) {
  2668. ExAcquireFastMutex(&disketteExtension->ThreadReferenceMutex);
  2669. ASSERT(disketteExtension->ThreadReferenceCount > 0);
  2670. (disketteExtension->ThreadReferenceCount)--;
  2671. ExReleaseFastMutex(&disketteExtension->ThreadReferenceMutex);
  2672. disketteExtension->HardwareFailed = FALSE;
  2673. irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry );
  2674. //
  2675. // Verify if the system is powering down. If so we fail
  2676. // the irps.
  2677. //
  2678. ExAcquireFastMutex(&disketteExtension->PowerDownMutex);
  2679. if (disketteExtension->PoweringDown == TRUE) {
  2680. ExReleaseFastMutex(&disketteExtension->PowerDownMutex);
  2681. FloppyDump( FLOPDBGP,
  2682. ("Bailing out since power irp is waiting.\n"));
  2683. irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry );
  2684. irp->IoStatus.Status = STATUS_POWER_STATE_INVALID;
  2685. irp->IoStatus.Information = 0;
  2686. IoCompleteRequest(irp, IO_NO_INCREMENT);
  2687. continue;
  2688. }
  2689. ExReleaseFastMutex(&disketteExtension->PowerDownMutex);
  2690. FloppyDump( FLOPSHOW, ("No power irp waiting.\n"));
  2691. irpSp = IoGetCurrentIrpStackLocation( irp );
  2692. FloppyDump(
  2693. FLOPIRPPATH,
  2694. ("Floppy: Starting up IRP: %p for extension %p\n",
  2695. irp,irpSp->Parameters.Others.Argument4)
  2696. );
  2697. switch ( irpSp->MajorFunction ) {
  2698. case IRP_MJ_PNP:
  2699. FloppyDump( FLOPSHOW, ("FloppyThread: IRP_MN_QUERY_REMOVE_DEVICE\n") );
  2700. if ( irpSp->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE ||
  2701. irpSp->MinorFunction == IRP_MN_QUERY_STOP_DEVICE ) {
  2702. if ( disketteExtension->FloppyControllerAllocated ) {
  2703. FlFdcDeviceIo( disketteExtension->TargetObject,
  2704. IOCTL_DISK_INTERNAL_DISABLE_FDC_DEVICE,
  2705. NULL );
  2706. FlFdcDeviceIo( disketteExtension->TargetObject,
  2707. IOCTL_DISK_INTERNAL_RELEASE_FDC,
  2708. disketteExtension->DeviceObject );
  2709. disketteExtension->FloppyControllerAllocated = FALSE;
  2710. }
  2711. ExAcquireFastMutex( &disketteExtension->ThreadReferenceMutex );
  2712. ASSERT(disketteExtension->ThreadReferenceCount == 0);
  2713. disketteExtension->ThreadReferenceCount = -1;
  2714. ExReleaseFastMutex(&disketteExtension->ThreadReferenceMutex);
  2715. FloppyPageEntireDriver();
  2716. PsTerminateSystemThread( STATUS_SUCCESS );
  2717. } else {
  2718. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  2719. }
  2720. break;
  2721. case IRP_MJ_READ:
  2722. case IRP_MJ_WRITE: {
  2723. //
  2724. // Get the diskette extension from where it was hidden
  2725. // in the IRP.
  2726. //
  2727. // disketteExtension = (PDISKETTE_EXTENSION)
  2728. // irpSp->Parameters.Others.Argument4;
  2729. if (!disketteExtension->FloppyControllerAllocated) {
  2730. ntStatus = FlFdcDeviceIo(
  2731. disketteExtension->TargetObject,
  2732. IOCTL_DISK_INTERNAL_ACQUIRE_FDC,
  2733. &acquireWait );
  2734. if (NT_SUCCESS(ntStatus)) {
  2735. disketteExtension->FloppyControllerAllocated = TRUE;
  2736. } else {
  2737. break;
  2738. }
  2739. }
  2740. //
  2741. // Until the file system clears the DO_VERIFY_VOLUME
  2742. // flag, we should return all requests with error.
  2743. //
  2744. if (( disketteExtension->DeviceObject->Flags &
  2745. DO_VERIFY_VOLUME ) &&
  2746. !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME))
  2747. {
  2748. FloppyDump(
  2749. FLOPINFO,
  2750. ("Floppy: clearing queue; verify required\n")
  2751. );
  2752. //
  2753. // The disk changed, and we set this bit. Fail
  2754. // all current IRPs for this device; when all are
  2755. // returned, the file system will clear
  2756. // DO_VERIFY_VOLUME.
  2757. //
  2758. ntStatus = STATUS_VERIFY_REQUIRED;
  2759. } else {
  2760. ntStatus = FlReadWrite( disketteExtension, irp, FALSE );
  2761. }
  2762. break;
  2763. }
  2764. case IRP_MJ_DEVICE_CONTROL: {
  2765. // disketteExtension = (PDISKETTE_EXTENSION)
  2766. // irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  2767. if (!disketteExtension->FloppyControllerAllocated) {
  2768. ntStatus = FlFdcDeviceIo(
  2769. disketteExtension->TargetObject,
  2770. IOCTL_DISK_INTERNAL_ACQUIRE_FDC,
  2771. &acquireWait );
  2772. if (NT_SUCCESS(ntStatus)) {
  2773. disketteExtension->FloppyControllerAllocated = TRUE;
  2774. } else {
  2775. break;
  2776. }
  2777. }
  2778. //
  2779. // Until the file system clears the DO_VERIFY_VOLUME
  2780. // flag, we should return all requests with error.
  2781. //
  2782. if (( disketteExtension->DeviceObject->Flags &
  2783. DO_VERIFY_VOLUME ) &&
  2784. !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME))
  2785. {
  2786. FloppyDump(
  2787. FLOPINFO,
  2788. ("Floppy: clearing queue; verify required\n")
  2789. );
  2790. //
  2791. // The disk changed, and we set this bit. Fail
  2792. // all current IRPs; when all are returned, the
  2793. // file system will clear DO_VERIFY_VOLUME.
  2794. //
  2795. ntStatus = STATUS_VERIFY_REQUIRED;
  2796. } else {
  2797. switch (
  2798. irpSp->Parameters.DeviceIoControl.IoControlCode ) {
  2799. case IOCTL_STORAGE_CHECK_VERIFY:
  2800. case IOCTL_DISK_CHECK_VERIFY: {
  2801. //
  2802. // Just start the drive; it will
  2803. // automatically check whether or not the
  2804. // disk has been changed.
  2805. //
  2806. FloppyDump(
  2807. FLOPSHOW,
  2808. ("Floppy: IOCTL_DISK_CHECK_VERIFY called\n")
  2809. );
  2810. //
  2811. // IgnoreChange should be TRUE if
  2812. // SL_OVERRIDE_VERIFY_VOLUME flag is set
  2813. // in the irp. Else, IgnoreChange should
  2814. // be FALSE
  2815. //
  2816. ntStatus = FlStartDrive(
  2817. disketteExtension,
  2818. irp,
  2819. FALSE,
  2820. FALSE,
  2821. (BOOLEAN)!!(irpSp->Flags &
  2822. SL_OVERRIDE_VERIFY_VOLUME));
  2823. break;
  2824. }
  2825. case IOCTL_DISK_IS_WRITABLE: {
  2826. //
  2827. // Start the drive with the WriteOperation
  2828. // flag set to TRUE.
  2829. //
  2830. FloppyDump(
  2831. FLOPSHOW,
  2832. ("Floppy: IOCTL_DISK_IS_WRITABLE called\n")
  2833. );
  2834. if (disketteExtension->IsReadOnly) {
  2835. ntStatus = STATUS_INVALID_PARAMETER;
  2836. } else {
  2837. ntStatus = FlStartDrive(
  2838. disketteExtension,
  2839. irp,
  2840. TRUE,
  2841. FALSE,
  2842. TRUE);
  2843. }
  2844. break;
  2845. }
  2846. case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
  2847. FloppyDump(
  2848. FLOPSHOW,
  2849. ("Floppy: IOCTL_DISK_GET_DRIVE_GEOMETRY\n")
  2850. );
  2851. //
  2852. // If there's enough room to write the
  2853. // data, start the drive to make sure we
  2854. // know what type of media is in the drive.
  2855. //
  2856. if ( irpSp->Parameters.DeviceIoControl.
  2857. OutputBufferLength <
  2858. sizeof( DISK_GEOMETRY ) ) {
  2859. ntStatus = STATUS_INVALID_PARAMETER;
  2860. } else {
  2861. ntStatus = FlStartDrive(
  2862. disketteExtension,
  2863. irp,
  2864. FALSE,
  2865. TRUE,
  2866. (BOOLEAN)!!(irpSp->Flags &
  2867. SL_OVERRIDE_VERIFY_VOLUME));
  2868. }
  2869. //
  2870. // If the media wasn't formatted, FlStartDrive
  2871. // returned STATUS_UNRECOGNIZED_MEDIA.
  2872. //
  2873. if ( NT_SUCCESS( ntStatus ) ||
  2874. ( ntStatus == STATUS_UNRECOGNIZED_MEDIA )) {
  2875. PDISK_GEOMETRY outputBuffer =
  2876. (PDISK_GEOMETRY)
  2877. irp->AssociatedIrp.SystemBuffer;
  2878. // Always return the media type, even if
  2879. // it's unknown.
  2880. //
  2881. ntStatus = STATUS_SUCCESS;
  2882. outputBuffer->MediaType =
  2883. disketteExtension->MediaType;
  2884. //
  2885. // The rest of the fields only have meaning
  2886. // if the media type is known.
  2887. //
  2888. if ( disketteExtension->MediaType ==
  2889. Unknown ) {
  2890. FloppyDump(
  2891. FLOPSHOW,
  2892. ("Floppy: geometry unknown\n")
  2893. );
  2894. //
  2895. // Just zero out everything. The
  2896. // caller shouldn't look at it.
  2897. //
  2898. outputBuffer->Cylinders.LowPart = 0;
  2899. outputBuffer->Cylinders.HighPart = 0;
  2900. outputBuffer->TracksPerCylinder = 0;
  2901. outputBuffer->SectorsPerTrack = 0;
  2902. outputBuffer->BytesPerSector = 0;
  2903. } else {
  2904. //
  2905. // Return the geometry of the current
  2906. // media.
  2907. //
  2908. FloppyDump(
  2909. FLOPSHOW,
  2910. ("Floppy: geomentry is known\n")
  2911. );
  2912. outputBuffer->Cylinders.LowPart =
  2913. disketteExtension->
  2914. DriveMediaConstants.MaximumTrack + 1;
  2915. outputBuffer->Cylinders.HighPart = 0;
  2916. outputBuffer->TracksPerCylinder =
  2917. disketteExtension->
  2918. DriveMediaConstants.NumberOfHeads;
  2919. outputBuffer->SectorsPerTrack =
  2920. disketteExtension->
  2921. DriveMediaConstants.SectorsPerTrack;
  2922. outputBuffer->BytesPerSector =
  2923. disketteExtension->
  2924. DriveMediaConstants.BytesPerSector;
  2925. }
  2926. FloppyDump(
  2927. FLOPSHOW,
  2928. ("Floppy: Geometry\n"
  2929. "------- Cylinders low: 0x%x\n"
  2930. "------- Cylinders high: 0x%x\n"
  2931. "------- Track/Cyl: 0x%x\n"
  2932. "------- Sectors/Track: 0x%x\n"
  2933. "------- Bytes/Sector: 0x%x\n"
  2934. "------- Media Type: %d\n",
  2935. outputBuffer->Cylinders.LowPart,
  2936. outputBuffer->Cylinders.HighPart,
  2937. outputBuffer->TracksPerCylinder,
  2938. outputBuffer->SectorsPerTrack,
  2939. outputBuffer->BytesPerSector,
  2940. outputBuffer->MediaType)
  2941. );
  2942. }
  2943. irp->IoStatus.Information =
  2944. sizeof( DISK_GEOMETRY );
  2945. break;
  2946. }
  2947. case IOCTL_DISK_FORMAT_TRACKS_EX:
  2948. case IOCTL_DISK_FORMAT_TRACKS: {
  2949. FloppyDump(
  2950. FLOPSHOW,
  2951. ("Floppy: IOCTL_DISK_FORMAT_TRACKS\n")
  2952. );
  2953. //
  2954. // Start the drive, and make sure it's not
  2955. // write protected.
  2956. //
  2957. ntStatus = FlStartDrive(
  2958. disketteExtension,
  2959. irp,
  2960. TRUE,
  2961. FALSE,
  2962. FALSE );
  2963. //
  2964. // Note that FlStartDrive could have returned
  2965. // STATUS_UNRECOGNIZED_MEDIA if the drive
  2966. // wasn't formatted.
  2967. //
  2968. if ( NT_SUCCESS( ntStatus ) ||
  2969. ( ntStatus == STATUS_UNRECOGNIZED_MEDIA)) {
  2970. //
  2971. // We need a single page to do FORMATs.
  2972. // If we already allocated a buffer,
  2973. // we'll use that. If not, let's
  2974. // allocate a single page. Note that
  2975. // we'd have to do this anyway if there's
  2976. // not enough map registers.
  2977. //
  2978. FlAllocateIoBuffer( disketteExtension,
  2979. PAGE_SIZE);
  2980. if (disketteExtension->IoBuffer) {
  2981. ntStatus = FlFormat(disketteExtension,
  2982. irp);
  2983. } else {
  2984. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2985. }
  2986. }
  2987. break;
  2988. } //end of case format
  2989. } //end of switch controlcode
  2990. }
  2991. break;
  2992. } //end of case IOCTL
  2993. default: {
  2994. FloppyDump(
  2995. FLOPDBGP,
  2996. ("Floppy: bad majorfunction %x\n",irpSp->MajorFunction)
  2997. );
  2998. ntStatus = STATUS_NOT_IMPLEMENTED;
  2999. }
  3000. } //end of switch on majorfunction
  3001. if (ntStatus == STATUS_DEVICE_BUSY) {
  3002. // If the status is DEVICE_BUSY then this indicates that the
  3003. // qic117 has control of the controller. Therefore complete
  3004. // all remaining requests with STATUS_DEVICE_BUSY.
  3005. for (;;) {
  3006. disketteExtension->HardwareFailed = FALSE;
  3007. irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  3008. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  3009. request = ExInterlockedRemoveHeadList(
  3010. &disketteExtension->ListEntry,
  3011. &disketteExtension->ListSpinLock );
  3012. if (!request) {
  3013. break;
  3014. }
  3015. ExAcquireFastMutex(
  3016. &disketteExtension->ThreadReferenceMutex);
  3017. ASSERT(disketteExtension->ThreadReferenceCount > 0);
  3018. (disketteExtension->ThreadReferenceCount)--;
  3019. ExReleaseFastMutex(
  3020. &disketteExtension->ThreadReferenceMutex);
  3021. irp = CONTAINING_RECORD( request,
  3022. IRP,
  3023. Tail.Overlay.ListEntry);
  3024. }
  3025. } else {
  3026. //
  3027. // All operations leave a final status in ntStatus. Copy it
  3028. // to the IRP, and then complete the operation.
  3029. //
  3030. irp->IoStatus.Status = ntStatus;
  3031. //
  3032. // If we'd allocated an I/O buffer free it now
  3033. //
  3034. if (disketteExtension->IoBuffer) {
  3035. FlFreeIoBuffer(disketteExtension);
  3036. }
  3037. FlFinishOperation( irp, disketteExtension );
  3038. }
  3039. } // while there are packets to process
  3040. } while ( TRUE );
  3041. }
  3042. VOID
  3043. FlConsolidateMediaTypeWithBootSector(
  3044. IN OUT PDISKETTE_EXTENSION DisketteExtension,
  3045. IN PBOOT_SECTOR_INFO BootSector
  3046. )
  3047. /*++
  3048. Routine Description:
  3049. This routine adjusts the DisketteExtension data according
  3050. to the BPB values if this is appropriate.
  3051. Arguments:
  3052. DisketteExtension - Supplies the diskette extension.
  3053. BootSector - Supplies the boot sector information.
  3054. Return Value:
  3055. None.
  3056. --*/
  3057. {
  3058. USHORT bpbNumberOfSectors, bpbNumberOfHeads;
  3059. USHORT bpbSectorsPerTrack, bpbBytesPerSector;
  3060. USHORT bpbMediaByte, bpbMaximumTrack;
  3061. MEDIA_TYPE bpbMediaType;
  3062. ULONG i, n;
  3063. PDRIVE_MEDIA_CONSTANTS readidDriveMediaConstants;
  3064. BOOLEAN changeToBpbMedia;
  3065. FloppyDump(
  3066. FLOPSHOW,
  3067. ("Floppy: First sector read: media descriptor is: 0x%x\n",
  3068. BootSector->MediaByte[0])
  3069. );
  3070. if (BootSector->JumpByte[0] != 0xeb &&
  3071. BootSector->JumpByte[0] != 0xe9) {
  3072. // This is not a formatted floppy so ignore the BPB.
  3073. return;
  3074. }
  3075. bpbNumberOfSectors = BootSector->NumberOfSectors[1]*0x100 +
  3076. BootSector->NumberOfSectors[0];
  3077. bpbNumberOfHeads = BootSector->NumberOfHeads[1]*0x100 +
  3078. BootSector->NumberOfHeads[0];
  3079. bpbSectorsPerTrack = BootSector->SectorsPerTrack[1]*0x100 +
  3080. BootSector->SectorsPerTrack[0];
  3081. bpbBytesPerSector = BootSector->BytesPerSector[1]*0x100 +
  3082. BootSector->BytesPerSector[0];
  3083. bpbMediaByte = BootSector->MediaByte[0];
  3084. if (!bpbNumberOfHeads || !bpbSectorsPerTrack) {
  3085. // Invalid BPB, avoid dividing by zero.
  3086. return;
  3087. }
  3088. bpbMaximumTrack =
  3089. bpbNumberOfSectors/bpbNumberOfHeads/bpbSectorsPerTrack - 1;
  3090. // First figure out if this BPB specifies a known media type
  3091. // independantly of the current drive type.
  3092. bpbMediaType = Unknown;
  3093. for (i = 0; i < NUMBER_OF_DRIVE_MEDIA_COMBINATIONS; i++) {
  3094. if (bpbBytesPerSector == DriveMediaConstants[i].BytesPerSector &&
  3095. bpbSectorsPerTrack == DriveMediaConstants[i].SectorsPerTrack &&
  3096. bpbMaximumTrack == DriveMediaConstants[i].MaximumTrack &&
  3097. bpbNumberOfHeads == DriveMediaConstants[i].NumberOfHeads &&
  3098. bpbMediaByte == DriveMediaConstants[i].MediaByte) {
  3099. bpbMediaType = DriveMediaConstants[i].MediaType;
  3100. break;
  3101. }
  3102. }
  3103. //
  3104. // If DriveType is 3.5", we change 5.25" to 3.5".
  3105. // The following media's BPB is the same between 5.25" and 3.5",
  3106. // so 5.25" media types are always found first.
  3107. //
  3108. if (DisketteExtension->DriveType == DRIVE_TYPE_1440) {
  3109. switch (bpbMediaType) {
  3110. case F5_640_512: bpbMediaType = F3_640_512; break;
  3111. case F5_720_512: bpbMediaType = F3_720_512; break;
  3112. case F5_1Pt2_512: bpbMediaType = F3_1Pt2_512; break;
  3113. case F5_1Pt23_1024: bpbMediaType = F3_1Pt23_1024; break;
  3114. default: break;
  3115. }
  3116. }
  3117. FloppyDump(
  3118. FLOPSHOW,
  3119. ("FLOPPY: After switch media type is: %x\n",bpbMediaType)
  3120. );
  3121. FloppyDump(
  3122. FLOPINFO,
  3123. ("FloppyBpb: Media type ")
  3124. );
  3125. if (bpbMediaType == DisketteExtension->MediaType) {
  3126. // No conflict between BPB and readId result.
  3127. changeToBpbMedia = FALSE;
  3128. FloppyDump(
  3129. FLOPINFO,
  3130. ("is same\n")
  3131. );
  3132. } else {
  3133. // There is a conflict between the BPB and the readId
  3134. // media type. If the new parameters are acceptable
  3135. // then go with them.
  3136. readidDriveMediaConstants = &(DisketteExtension->DriveMediaConstants);
  3137. if (bpbBytesPerSector == readidDriveMediaConstants->BytesPerSector &&
  3138. bpbSectorsPerTrack < 0x100 &&
  3139. bpbMaximumTrack == readidDriveMediaConstants->MaximumTrack &&
  3140. bpbNumberOfHeads <= readidDriveMediaConstants->NumberOfHeads) {
  3141. changeToBpbMedia = TRUE;
  3142. } else {
  3143. changeToBpbMedia = FALSE;
  3144. }
  3145. FloppyDump( FLOPINFO,
  3146. ("%s",
  3147. changeToBpbMedia ?
  3148. "will change to Bpb\n" : "will not change\n")
  3149. );
  3150. // If we didn't derive a new media type from the BPB then
  3151. // just use the one from readId. Also override any
  3152. // skew compensation since we don't really know anything
  3153. // about this new media type.
  3154. if (bpbMediaType == Unknown) {
  3155. bpbMediaType = readidDriveMediaConstants->MediaType;
  3156. DisketteExtension->DriveMediaConstants.SkewDelta = 0;
  3157. }
  3158. }
  3159. if (changeToBpbMedia) {
  3160. // Change the DriveMediaType only if this new media type
  3161. // falls in line with what is supported by the drive.
  3162. i = DriveMediaLimits[DisketteExtension->DriveType].LowestDriveMediaType;
  3163. n = DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType;
  3164. for (; i <= n; i++) {
  3165. if (bpbMediaType == DriveMediaConstants[i].MediaType) {
  3166. DisketteExtension->DriveMediaType = i;
  3167. break;
  3168. }
  3169. }
  3170. DisketteExtension->MediaType = bpbMediaType;
  3171. DisketteExtension->ByteCapacity = bpbNumberOfSectors*bpbBytesPerSector;
  3172. DisketteExtension->DriveMediaConstants.SectorsPerTrack =
  3173. (UCHAR) bpbSectorsPerTrack;
  3174. DisketteExtension->DriveMediaConstants.NumberOfHeads =
  3175. (UCHAR) bpbNumberOfHeads;
  3176. // If the MSDMF3. signature is there then make this floppy
  3177. // read-only.
  3178. if (RtlCompareMemory(BootSector->OemData, "MSDMF3.", 7) == 7) {
  3179. DisketteExtension->IsReadOnly = TRUE;
  3180. }
  3181. }
  3182. }
  3183. VOID
  3184. FlCheckBootSector(
  3185. IN OUT PDISKETTE_EXTENSION DisketteExtension
  3186. )
  3187. /*++
  3188. Routine Description:
  3189. This routine reads the boot sector and then figures
  3190. out whether or not the boot sector contains new geometry
  3191. information.
  3192. Arguments:
  3193. DisketteExtension - Supplies the diskette extension.
  3194. Return Value:
  3195. None.
  3196. --*/
  3197. {
  3198. PBOOT_SECTOR_INFO bootSector;
  3199. LARGE_INTEGER offset;
  3200. PIRP irp;
  3201. NTSTATUS status;
  3202. // Set up the IRP to read the boot sector.
  3203. bootSector = ExAllocatePool(NonPagedPoolCacheAligned, BOOT_SECTOR_SIZE);
  3204. if (!bootSector) {
  3205. return;
  3206. }
  3207. offset.LowPart = offset.HighPart = 0;
  3208. irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
  3209. DisketteExtension->DeviceObject,
  3210. bootSector,
  3211. BOOT_SECTOR_SIZE,
  3212. &offset,
  3213. NULL);
  3214. if (!irp) {
  3215. ExFreePool(bootSector);
  3216. return;
  3217. }
  3218. irp->CurrentLocation--;
  3219. irp->Tail.Overlay.CurrentStackLocation = IoGetNextIrpStackLocation(irp);
  3220. // Allocate an adapter channel, do read, free adapter channel.
  3221. status = FlReadWrite(DisketteExtension, irp, TRUE);
  3222. MmUnlockPages(irp->MdlAddress);
  3223. IoFreeMdl(irp->MdlAddress);
  3224. IoFreeIrp(irp);
  3225. ExFreePool(bootSector);
  3226. }
  3227. NTSTATUS
  3228. FlReadWriteTrack(
  3229. IN OUT PDISKETTE_EXTENSION DisketteExtension,
  3230. IN OUT PMDL IoMdl,
  3231. IN OUT ULONG IoOffset,
  3232. IN BOOLEAN WriteOperation,
  3233. IN UCHAR Cylinder,
  3234. IN UCHAR Head,
  3235. IN UCHAR Sector,
  3236. IN UCHAR NumberOfSectors,
  3237. IN BOOLEAN NeedSeek
  3238. )
  3239. /*++
  3240. Routine Description:
  3241. This routine reads a portion of a track. It transfers the to or from the
  3242. device from or to the given IoBuffer and IoMdl.
  3243. Arguments:
  3244. DisketteExtension - Supplies the diskette extension.
  3245. IoMdl - Supplies the Mdl for transfering from/to the device.
  3246. IoBuffer - Supplies the buffer to transfer from/to the device.
  3247. WriteOperation - Supplies whether or not this is a write operation.
  3248. Cylinder - Supplies the cylinder number for this track.
  3249. Head - Supplies the head number for this track.
  3250. Sector - Supplies the starting sector of the transfer.
  3251. NumberOfSectors - Supplies the number of sectors to transfer.
  3252. NeedSeek - Supplies whether or not we need to do a seek.
  3253. Return Value:
  3254. An NTSTATUS code.
  3255. --*/
  3256. {
  3257. PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
  3258. ULONG byteToSectorShift;
  3259. ULONG transferBytes;
  3260. LARGE_INTEGER headSettleTime;
  3261. NTSTATUS status;
  3262. ULONG seekRetry, ioRetry;
  3263. BOOLEAN recalibrateDrive = FALSE;
  3264. UCHAR i;
  3265. FloppyDump( FLOPSHOW,
  3266. ("\nFlReadWriteTrack:%sseek for %s at chs %d/%d/%d for %d sectors\n",
  3267. NeedSeek ? " need " : " ",
  3268. WriteOperation ? "write" : "read",
  3269. Cylinder,
  3270. Head,
  3271. Sector,
  3272. NumberOfSectors) );
  3273. driveMediaConstants = &DisketteExtension->DriveMediaConstants;
  3274. byteToSectorShift = SECTORLENGTHCODE_TO_BYTESHIFT +
  3275. driveMediaConstants->SectorLengthCode;
  3276. transferBytes = ((ULONG) NumberOfSectors)<<byteToSectorShift;
  3277. headSettleTime.LowPart = -(10*1000*driveMediaConstants->HeadSettleTime);
  3278. headSettleTime.HighPart = -1;
  3279. for (seekRetry = 0, ioRetry = 0; seekRetry < 3; seekRetry++) {
  3280. if (recalibrateDrive) {
  3281. // Something failed, so recalibrate the drive.
  3282. FloppyDump(
  3283. FLOPINFO,
  3284. ("FlReadWriteTrack: performing recalibrate\n")
  3285. );
  3286. FlRecalibrateDrive(DisketteExtension);
  3287. }
  3288. // Do a seek if we have to.
  3289. if (recalibrateDrive ||
  3290. (NeedSeek &&
  3291. (!DisketteExtension->ControllerConfigurable ||
  3292. driveMediaConstants->CylinderShift != 0))) {
  3293. DisketteExtension->FifoBuffer[0] = COMMND_SEEK;
  3294. DisketteExtension->FifoBuffer[1] = (Head<<2) |
  3295. DisketteExtension->DeviceUnit;
  3296. DisketteExtension->FifoBuffer[2] = Cylinder<<
  3297. driveMediaConstants->CylinderShift;
  3298. status = FlIssueCommand( DisketteExtension,
  3299. DisketteExtension->FifoBuffer,
  3300. DisketteExtension->FifoBuffer,
  3301. NULL,
  3302. 0,
  3303. 0 );
  3304. if (NT_SUCCESS(status)) {
  3305. // Check the completion state of the controller.
  3306. if (!(DisketteExtension->FifoBuffer[0]&STREG0_SEEK_COMPLETE) ||
  3307. DisketteExtension->FifoBuffer[1] !=
  3308. Cylinder<<driveMediaConstants->CylinderShift) {
  3309. DisketteExtension->HardwareFailed = TRUE;
  3310. status = STATUS_FLOPPY_BAD_REGISTERS;
  3311. }
  3312. if (NT_SUCCESS(status)) {
  3313. // Delay after doing seek.
  3314. KeDelayExecutionThread(KernelMode, FALSE, &headSettleTime);
  3315. // SEEKs should always be followed by a READID.
  3316. DisketteExtension->FifoBuffer[0] =
  3317. COMMND_READ_ID + COMMND_OPTION_MFM;
  3318. DisketteExtension->FifoBuffer[1] =
  3319. (Head<<2) | DisketteExtension->DeviceUnit;
  3320. status = FlIssueCommand( DisketteExtension,
  3321. DisketteExtension->FifoBuffer,
  3322. DisketteExtension->FifoBuffer,
  3323. NULL,
  3324. 0,
  3325. 0 );
  3326. if (NT_SUCCESS(status)) {
  3327. if (DisketteExtension->FifoBuffer[0] !=
  3328. ((Head<<2) | DisketteExtension->DeviceUnit) ||
  3329. DisketteExtension->FifoBuffer[1] != 0 ||
  3330. DisketteExtension->FifoBuffer[2] != 0 ||
  3331. DisketteExtension->FifoBuffer[3] != Cylinder) {
  3332. DisketteExtension->HardwareFailed = TRUE;
  3333. status = FlInterpretError(
  3334. DisketteExtension->FifoBuffer[1],
  3335. DisketteExtension->FifoBuffer[2]);
  3336. }
  3337. } else {
  3338. FloppyDump(
  3339. FLOPINFO,
  3340. ("FlReadWriteTrack: Read ID failed %x\n", status)
  3341. );
  3342. }
  3343. }
  3344. } else {
  3345. FloppyDump(
  3346. FLOPINFO,
  3347. ("FlReadWriteTrack: SEEK failed %x\n", status)
  3348. );
  3349. }
  3350. } else {
  3351. status = STATUS_SUCCESS;
  3352. }
  3353. if (!NT_SUCCESS(status)) {
  3354. // The seek failed so try again.
  3355. FloppyDump(
  3356. FLOPINFO,
  3357. ("FlReadWriteTrack: setup failure %x - recalibrating\n", status)
  3358. );
  3359. recalibrateDrive = TRUE;
  3360. continue;
  3361. }
  3362. for (;; ioRetry++) {
  3363. //
  3364. // Issue the READ or WRITE command
  3365. //
  3366. DisketteExtension->FifoBuffer[1] = (Head<<2) |
  3367. DisketteExtension->DeviceUnit;
  3368. DisketteExtension->FifoBuffer[2] = Cylinder;
  3369. DisketteExtension->FifoBuffer[3] = Head;
  3370. DisketteExtension->FifoBuffer[4] = Sector + 1;
  3371. DisketteExtension->FifoBuffer[5] =
  3372. driveMediaConstants->SectorLengthCode;
  3373. DisketteExtension->FifoBuffer[6] = Sector + NumberOfSectors;
  3374. DisketteExtension->FifoBuffer[7] =
  3375. driveMediaConstants->ReadWriteGapLength;
  3376. DisketteExtension->FifoBuffer[8] = driveMediaConstants->DataLength;
  3377. if (WriteOperation) {
  3378. DisketteExtension->FifoBuffer[0] =
  3379. COMMND_WRITE_DATA + COMMND_OPTION_MFM;
  3380. } else {
  3381. DisketteExtension->FifoBuffer[0] =
  3382. COMMND_READ_DATA + COMMND_OPTION_MFM;
  3383. }
  3384. FloppyDump(FLOPINFO,
  3385. ("FlReadWriteTrack: Params - %x,%x,%x,%x,%x,%x,%x,%x\n",
  3386. DisketteExtension->FifoBuffer[1],
  3387. DisketteExtension->FifoBuffer[2],
  3388. DisketteExtension->FifoBuffer[3],
  3389. DisketteExtension->FifoBuffer[4],
  3390. DisketteExtension->FifoBuffer[5],
  3391. DisketteExtension->FifoBuffer[6],
  3392. DisketteExtension->FifoBuffer[7],
  3393. DisketteExtension->FifoBuffer[8])
  3394. );
  3395. status = FlIssueCommand( DisketteExtension,
  3396. DisketteExtension->FifoBuffer,
  3397. DisketteExtension->FifoBuffer,
  3398. IoMdl,
  3399. IoOffset,
  3400. transferBytes );
  3401. if (NT_SUCCESS(status)) {
  3402. if ((DisketteExtension->FifoBuffer[0] & STREG0_END_MASK) !=
  3403. STREG0_END_NORMAL) {
  3404. DisketteExtension->HardwareFailed = TRUE;
  3405. status = FlInterpretError(DisketteExtension->FifoBuffer[1],
  3406. DisketteExtension->FifoBuffer[2]);
  3407. } else {
  3408. //
  3409. // The floppy controller may return no errors but not have
  3410. // read all of the requested data. If this is the case,
  3411. // record it as an error and retru the operation.
  3412. //
  3413. if (DisketteExtension->FifoBuffer[5] != 1) {
  3414. DisketteExtension->HardwareFailed = TRUE;
  3415. status = STATUS_FLOPPY_UNKNOWN_ERROR;
  3416. }
  3417. }
  3418. } else {
  3419. FloppyDump( FLOPINFO,
  3420. ("FlReadWriteTrack: %s command failed %x\n",
  3421. WriteOperation ? "write" : "read",
  3422. status) );
  3423. }
  3424. if (NT_SUCCESS(status)) {
  3425. break;
  3426. }
  3427. if (ioRetry >= 2) {
  3428. FloppyDump(FLOPINFO,
  3429. ("FlReadWriteTrack: too many retries - failing\n"));
  3430. break;
  3431. }
  3432. }
  3433. if (NT_SUCCESS(status)) {
  3434. break;
  3435. }
  3436. // We failed quite a bit so make seeks mandatory.
  3437. recalibrateDrive = TRUE;
  3438. }
  3439. if (!NT_SUCCESS(status) && NumberOfSectors > 1) {
  3440. // Retry one sector at a time.
  3441. FloppyDump( FLOPINFO,
  3442. ("FlReadWriteTrack: Attempting sector at a time\n") );
  3443. for (i = 0; i < NumberOfSectors; i++) {
  3444. status = FlReadWriteTrack( DisketteExtension,
  3445. IoMdl,
  3446. IoOffset+(((ULONG)i)<<byteToSectorShift),
  3447. WriteOperation,
  3448. Cylinder,
  3449. Head,
  3450. (UCHAR) (Sector + i),
  3451. 1,
  3452. FALSE );
  3453. if (!NT_SUCCESS(status)) {
  3454. FloppyDump( FLOPINFO,
  3455. ("FlReadWriteTrack: failed sector %d status %x\n",
  3456. i,
  3457. status) );
  3458. DisketteExtension->HardwareFailed = TRUE;
  3459. break;
  3460. }
  3461. }
  3462. }
  3463. return status;
  3464. }
  3465. NTSTATUS
  3466. FlReadWrite(
  3467. IN OUT PDISKETTE_EXTENSION DisketteExtension,
  3468. IN OUT PIRP Irp,
  3469. IN BOOLEAN DriveStarted
  3470. )
  3471. /*++
  3472. Routine Description:
  3473. This routine is called by the floppy thread to read/write data
  3474. to/from the diskette. It breaks the request into pieces called
  3475. "transfers" (their size depends on the buffer size, where the end of
  3476. the track is, etc) and retries each transfer until it succeeds or
  3477. the retry count is exceeded.
  3478. Arguments:
  3479. DisketteExtension - a pointer to our data area for the drive to be
  3480. accessed.
  3481. Irp - a pointer to the IO Request Packet.
  3482. DriveStarted - indicated whether or not the drive has been started.
  3483. Return Value:
  3484. STATUS_SUCCESS if the packet was successfully read or written; the
  3485. appropriate error is propogated otherwise.
  3486. --*/
  3487. {
  3488. PIO_STACK_LOCATION irpSp;
  3489. BOOLEAN writeOperation;
  3490. NTSTATUS status;
  3491. PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
  3492. ULONG byteToSectorShift;
  3493. ULONG currentSector, firstSector, lastSector;
  3494. ULONG trackSize;
  3495. UCHAR sectorsPerTrack, numberOfHeads;
  3496. UCHAR currentHead, currentCylinder, trackSector;
  3497. PCHAR userBuffer;
  3498. UCHAR skew, skewDelta;
  3499. UCHAR numTransferSectors;
  3500. PMDL mdl;
  3501. PCHAR ioBuffer;
  3502. ULONG ioOffset;
  3503. irpSp = IoGetCurrentIrpStackLocation(Irp);
  3504. FloppyDump(
  3505. FLOPSHOW,
  3506. ("FlReadWrite: for %s at offset %x size %x ",
  3507. irpSp->MajorFunction == IRP_MJ_WRITE ? "write" : "read",
  3508. irpSp->Parameters.Read.ByteOffset.LowPart,
  3509. irpSp->Parameters.Read.Length)
  3510. );
  3511. // Check for valid operation on this device.
  3512. if (irpSp->MajorFunction == IRP_MJ_WRITE) {
  3513. if (DisketteExtension->IsReadOnly) {
  3514. FloppyDump( FLOPSHOW, ("is read-only\n") );
  3515. return STATUS_INVALID_PARAMETER;
  3516. }
  3517. writeOperation = TRUE;
  3518. } else {
  3519. writeOperation = FALSE;
  3520. }
  3521. FloppyDump( FLOPSHOW, ("\n") );
  3522. // Start up the drive.
  3523. if (DriveStarted) {
  3524. status = STATUS_SUCCESS;
  3525. } else {
  3526. status = FlStartDrive( DisketteExtension,
  3527. Irp,
  3528. writeOperation,
  3529. TRUE,
  3530. (BOOLEAN)
  3531. !!(irpSp->Flags&SL_OVERRIDE_VERIFY_VOLUME));
  3532. }
  3533. if (!NT_SUCCESS(status)) {
  3534. FloppyDump(
  3535. FLOPSHOW,
  3536. ("FlReadWrite: error on start %x\n", status)
  3537. );
  3538. return status;
  3539. }
  3540. if (DisketteExtension->MediaType == Unknown) {
  3541. FloppyDump( FLOPSHOW, ("not recognized\n") );
  3542. return STATUS_UNRECOGNIZED_MEDIA;
  3543. }
  3544. // The drive has started up with a recognized media.
  3545. // Gather some relavant parameters.
  3546. driveMediaConstants = &DisketteExtension->DriveMediaConstants;
  3547. byteToSectorShift = SECTORLENGTHCODE_TO_BYTESHIFT +
  3548. driveMediaConstants->SectorLengthCode;
  3549. firstSector = irpSp->Parameters.Read.ByteOffset.LowPart>>
  3550. byteToSectorShift;
  3551. lastSector = firstSector + (irpSp->Parameters.Read.Length>>
  3552. byteToSectorShift);
  3553. sectorsPerTrack = driveMediaConstants->SectorsPerTrack;
  3554. numberOfHeads = driveMediaConstants->NumberOfHeads;
  3555. userBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,
  3556. HighPagePriority);
  3557. if (userBuffer == NULL) {
  3558. FloppyDump(FLOPWARN,
  3559. ("MmGetSystemAddressForMdlSafe returned NULL in FlReadWrite\n")
  3560. );
  3561. return STATUS_INSUFFICIENT_RESOURCES;
  3562. }
  3563. trackSize = ((ULONG) sectorsPerTrack)<<byteToSectorShift;
  3564. skew = 0;
  3565. skewDelta = driveMediaConstants->SkewDelta;
  3566. for (currentSector = firstSector;
  3567. currentSector < lastSector;
  3568. currentSector += numTransferSectors) {
  3569. // Compute cylinder, head and sector from absolute sector.
  3570. currentCylinder = (UCHAR) (currentSector/sectorsPerTrack/numberOfHeads);
  3571. trackSector = (UCHAR) (currentSector%sectorsPerTrack);
  3572. currentHead = (UCHAR) (currentSector/sectorsPerTrack%numberOfHeads);
  3573. numTransferSectors = sectorsPerTrack - trackSector;
  3574. if (lastSector - currentSector < numTransferSectors) {
  3575. numTransferSectors = (UCHAR) (lastSector - currentSector);
  3576. }
  3577. //
  3578. // If we're using a temporary IO buffer because of
  3579. // insufficient registers in the DMA and we're
  3580. // doing a write then copy the write buffer to
  3581. // the contiguous buffer.
  3582. //
  3583. if (trackSize > DisketteExtension->MaxTransferSize) {
  3584. FloppyDump(FLOPSHOW,
  3585. ("FlReadWrite allocating an IoBuffer\n")
  3586. );
  3587. FlAllocateIoBuffer(DisketteExtension, trackSize);
  3588. if (!DisketteExtension->IoBuffer) {
  3589. FloppyDump(
  3590. FLOPSHOW,
  3591. ("FlReadWrite: no resources\n")
  3592. );
  3593. return STATUS_INSUFFICIENT_RESOURCES;
  3594. }
  3595. mdl = DisketteExtension->IoBufferMdl;
  3596. ioBuffer = DisketteExtension->IoBuffer;
  3597. ioOffset = 0;
  3598. if (writeOperation) {
  3599. RtlMoveMemory(ioBuffer,
  3600. userBuffer + ((currentSector - firstSector)<<
  3601. byteToSectorShift),
  3602. ((ULONG) numTransferSectors)<<byteToSectorShift);
  3603. }
  3604. } else {
  3605. mdl = Irp->MdlAddress;
  3606. ioOffset = (currentSector - firstSector) << byteToSectorShift;
  3607. }
  3608. //
  3609. // Transfer the track.
  3610. // Do what we can to avoid missing revs.
  3611. //
  3612. // Alter the skew to be in the range of what
  3613. // we're transfering.
  3614. if (skew >= numTransferSectors + trackSector) {
  3615. skew = 0;
  3616. }
  3617. if (skew < trackSector) {
  3618. skew = trackSector;
  3619. }
  3620. // Go from skew to the end of the irp.
  3621. status = FlReadWriteTrack(
  3622. DisketteExtension,
  3623. mdl,
  3624. ioOffset + (((ULONG) skew - trackSector)<<byteToSectorShift),
  3625. writeOperation,
  3626. currentCylinder,
  3627. currentHead,
  3628. skew,
  3629. (UCHAR) (numTransferSectors + trackSector - skew),
  3630. TRUE);
  3631. // Go from start of irp to skew.
  3632. if (NT_SUCCESS(status) && skew > trackSector) {
  3633. status = FlReadWriteTrack( DisketteExtension,
  3634. mdl,
  3635. ioOffset,
  3636. writeOperation,
  3637. currentCylinder,
  3638. currentHead,
  3639. trackSector,
  3640. (UCHAR) (skew - trackSector),
  3641. FALSE);
  3642. } else {
  3643. skew = (numTransferSectors + trackSector)%sectorsPerTrack;
  3644. }
  3645. if (!NT_SUCCESS(status)) {
  3646. break;
  3647. }
  3648. //
  3649. // If we used the temporary IO buffer to do the
  3650. // read then copy the contents back to the IRPs buffer.
  3651. //
  3652. if (!writeOperation &&
  3653. trackSize > DisketteExtension->MaxTransferSize) {
  3654. RtlMoveMemory( userBuffer + ((currentSector - firstSector) <<
  3655. byteToSectorShift),
  3656. ioBuffer,
  3657. ((ULONG) numTransferSectors)<<byteToSectorShift);
  3658. }
  3659. //
  3660. // Increment the skew. Do this even if just switching sides
  3661. // for National Super I/O chips.
  3662. //
  3663. skew = (skew + skewDelta)%sectorsPerTrack;
  3664. }
  3665. Irp->IoStatus.Information =
  3666. (currentSector - firstSector) << byteToSectorShift;
  3667. // If the read was successful then consolidate the
  3668. // boot sector with the determined density.
  3669. if (NT_SUCCESS(status) && firstSector == 0) {
  3670. FlConsolidateMediaTypeWithBootSector(DisketteExtension,
  3671. (PBOOT_SECTOR_INFO) userBuffer);
  3672. }
  3673. FloppyDump( FLOPSHOW,
  3674. ("FlReadWrite: completed status %x information %d\n",
  3675. status, Irp->IoStatus.Information)
  3676. );
  3677. return status;
  3678. }
  3679. NTSTATUS
  3680. FlFormat(
  3681. IN PDISKETTE_EXTENSION DisketteExtension,
  3682. IN PIRP Irp
  3683. )
  3684. /*++
  3685. Routine Description:
  3686. This routine is called by the floppy thread to format some tracks on
  3687. the diskette. This won't take TOO long because the FORMAT utility
  3688. is written to only format a few tracks at a time so that it can keep
  3689. a display of what percentage of the disk has been formatted.
  3690. Arguments:
  3691. DisketteExtension - pointer to our data area for the diskette to be
  3692. formatted.
  3693. Irp - pointer to the IO Request Packet.
  3694. Return Value:
  3695. STATUS_SUCCESS if the tracks were formatted; appropriate error
  3696. propogated otherwise.
  3697. --*/
  3698. {
  3699. LARGE_INTEGER headSettleTime;
  3700. PIO_STACK_LOCATION irpSp;
  3701. PBAD_TRACK_NUMBER badTrackBuffer;
  3702. PFORMAT_PARAMETERS formatParameters;
  3703. PFORMAT_EX_PARAMETERS formatExParameters;
  3704. PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
  3705. NTSTATUS ntStatus;
  3706. ULONG badTrackBufferLength;
  3707. DRIVE_MEDIA_TYPE driveMediaType;
  3708. UCHAR driveStatus;
  3709. UCHAR numberOfBadTracks = 0;
  3710. UCHAR currentTrack;
  3711. UCHAR endTrack;
  3712. UCHAR whichSector;
  3713. UCHAR retryCount;
  3714. BOOLEAN bufferOverflow = FALSE;
  3715. FDC_DISK_CHANGE_PARMS fdcDiskChangeParms;
  3716. FloppyDump(
  3717. FLOPSHOW,
  3718. ("Floppy: FlFormat...\n")
  3719. );
  3720. irpSp = IoGetCurrentIrpStackLocation( Irp );
  3721. formatParameters = (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
  3722. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  3723. IOCTL_DISK_FORMAT_TRACKS_EX) {
  3724. formatExParameters =
  3725. (PFORMAT_EX_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
  3726. } else {
  3727. formatExParameters = NULL;
  3728. }
  3729. FloppyDump(
  3730. FLOPFORMAT,
  3731. ("Floppy: Format Params - MediaType: %d\n"
  3732. "------ Start Cyl: %x\n"
  3733. "------ End Cyl: %x\n"
  3734. "------ Start Hd: %d\n"
  3735. "------ End Hd: %d\n",
  3736. formatParameters->MediaType,
  3737. formatParameters->StartCylinderNumber,
  3738. formatParameters->EndCylinderNumber,
  3739. formatParameters->StartHeadNumber,
  3740. formatParameters->EndHeadNumber)
  3741. );
  3742. badTrackBufferLength =
  3743. irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  3744. //
  3745. // Figure out which entry in the DriveMediaConstants table to use.
  3746. // We know we'll find one, or FlCheckFormatParameters() would have
  3747. // rejected the request.
  3748. //
  3749. driveMediaType =
  3750. DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType;
  3751. while ( ( DriveMediaConstants[driveMediaType].MediaType !=
  3752. formatParameters->MediaType ) &&
  3753. ( driveMediaType > DriveMediaLimits[DisketteExtension->DriveType].
  3754. LowestDriveMediaType ) ) {
  3755. driveMediaType--;
  3756. }
  3757. driveMediaConstants = &DriveMediaConstants[driveMediaType];
  3758. //
  3759. // Set some values in the diskette extension to indicate what we
  3760. // know about the media type.
  3761. //
  3762. DisketteExtension->MediaType = formatParameters->MediaType;
  3763. DisketteExtension->DriveMediaType = driveMediaType;
  3764. DisketteExtension->DriveMediaConstants =
  3765. DriveMediaConstants[driveMediaType];
  3766. if (formatExParameters) {
  3767. DisketteExtension->DriveMediaConstants.SectorsPerTrack =
  3768. (UCHAR) formatExParameters->SectorsPerTrack;
  3769. DisketteExtension->DriveMediaConstants.FormatGapLength =
  3770. (UCHAR) formatExParameters->FormatGapLength;
  3771. }
  3772. driveMediaConstants = &(DisketteExtension->DriveMediaConstants);
  3773. DisketteExtension->BytesPerSector = driveMediaConstants->BytesPerSector;
  3774. DisketteExtension->ByteCapacity =
  3775. ( driveMediaConstants->BytesPerSector ) *
  3776. driveMediaConstants->SectorsPerTrack *
  3777. ( 1 + driveMediaConstants->MaximumTrack ) *
  3778. driveMediaConstants->NumberOfHeads;
  3779. currentTrack = (UCHAR)( ( formatParameters->StartCylinderNumber *
  3780. driveMediaConstants->NumberOfHeads ) +
  3781. formatParameters->StartHeadNumber );
  3782. endTrack = (UCHAR)( ( formatParameters->EndCylinderNumber *
  3783. driveMediaConstants->NumberOfHeads ) +
  3784. formatParameters->EndHeadNumber );
  3785. FloppyDump(
  3786. FLOPFORMAT,
  3787. ("Floppy: Format - Starting/ending tracks: %x/%x\n",
  3788. currentTrack,
  3789. endTrack)
  3790. );
  3791. //
  3792. // Set the data rate (which depends on the drive/media
  3793. // type).
  3794. //
  3795. if ( DisketteExtension->LastDriveMediaType != driveMediaType ) {
  3796. ntStatus = FlDatarateSpecifyConfigure( DisketteExtension );
  3797. if ( !NT_SUCCESS( ntStatus ) ) {
  3798. return ntStatus;
  3799. }
  3800. }
  3801. //
  3802. // Since we're doing a format, make this drive writable.
  3803. //
  3804. DisketteExtension->IsReadOnly = FALSE;
  3805. //
  3806. // Format each track.
  3807. //
  3808. do {
  3809. //
  3810. // Seek to proper cylinder
  3811. //
  3812. DisketteExtension->FifoBuffer[0] = COMMND_SEEK;
  3813. DisketteExtension->FifoBuffer[1] = DisketteExtension->DeviceUnit;
  3814. DisketteExtension->FifoBuffer[2] = (UCHAR)( ( currentTrack /
  3815. driveMediaConstants->NumberOfHeads ) <<
  3816. driveMediaConstants->CylinderShift );
  3817. FloppyDump(
  3818. FLOPFORMAT,
  3819. ("Floppy: Format seek to cylinder: %x\n",
  3820. DisketteExtension->FifoBuffer[1])
  3821. );
  3822. ntStatus = FlIssueCommand( DisketteExtension,
  3823. DisketteExtension->FifoBuffer,
  3824. DisketteExtension->FifoBuffer,
  3825. NULL,
  3826. 0,
  3827. 0 );
  3828. if ( NT_SUCCESS( ntStatus ) ) {
  3829. if ( ( DisketteExtension->FifoBuffer[0] & STREG0_SEEK_COMPLETE ) &&
  3830. ( DisketteExtension->FifoBuffer[1] == (UCHAR)( ( currentTrack /
  3831. driveMediaConstants->NumberOfHeads ) <<
  3832. driveMediaConstants->CylinderShift ) ) ) {
  3833. //
  3834. // Must delay HeadSettleTime milliseconds before
  3835. // doing anything after a SEEK.
  3836. //
  3837. headSettleTime.LowPart = - ( 10 * 1000 *
  3838. driveMediaConstants->HeadSettleTime );
  3839. headSettleTime.HighPart = -1;
  3840. KeDelayExecutionThread(
  3841. KernelMode,
  3842. FALSE,
  3843. &headSettleTime );
  3844. //
  3845. // Read ID. Note that we don't bother checking the return
  3846. // registers, because if this media wasn't formatted we'd
  3847. // get an error.
  3848. //
  3849. DisketteExtension->FifoBuffer[0] =
  3850. COMMND_READ_ID + COMMND_OPTION_MFM;
  3851. DisketteExtension->FifoBuffer[1] =
  3852. DisketteExtension->DeviceUnit;
  3853. ntStatus = FlIssueCommand( DisketteExtension,
  3854. DisketteExtension->FifoBuffer,
  3855. DisketteExtension->FifoBuffer,
  3856. NULL,
  3857. 0,
  3858. 0 );
  3859. } else {
  3860. FloppyDump(
  3861. FLOPWARN,
  3862. ("Floppy: format's seek returned bad registers\n"
  3863. "------ Statusreg0 = %x\n"
  3864. "------ Statusreg1 = %x\n",
  3865. DisketteExtension->FifoBuffer[0],
  3866. DisketteExtension->FifoBuffer[1])
  3867. );
  3868. DisketteExtension->HardwareFailed = TRUE;
  3869. ntStatus = STATUS_FLOPPY_BAD_REGISTERS;
  3870. }
  3871. }
  3872. if ( !NT_SUCCESS( ntStatus ) ) {
  3873. FloppyDump(
  3874. FLOPWARN,
  3875. ("Floppy: format's seek/readid returned %x\n", ntStatus)
  3876. );
  3877. return ntStatus;
  3878. }
  3879. //
  3880. // Fill the buffer with the format of this track.
  3881. //
  3882. for (whichSector = 0;
  3883. whichSector < driveMediaConstants->SectorsPerTrack;
  3884. whichSector++) {
  3885. DisketteExtension->IoBuffer[whichSector*4] =
  3886. currentTrack/driveMediaConstants->NumberOfHeads;
  3887. DisketteExtension->IoBuffer[whichSector*4 + 1] =
  3888. currentTrack%driveMediaConstants->NumberOfHeads;
  3889. if (formatExParameters) {
  3890. DisketteExtension->IoBuffer[whichSector*4 + 2] =
  3891. (UCHAR) formatExParameters->SectorNumber[whichSector];
  3892. } else {
  3893. DisketteExtension->IoBuffer[whichSector*4 + 2] =
  3894. whichSector + 1;
  3895. }
  3896. DisketteExtension->IoBuffer[whichSector*4 + 3] =
  3897. driveMediaConstants->SectorLengthCode;
  3898. FloppyDump(
  3899. FLOPFORMAT,
  3900. ("Floppy - Format table entry %x - %x/%x/%x/%x\n",
  3901. whichSector,
  3902. DisketteExtension->IoBuffer[whichSector*4],
  3903. DisketteExtension->IoBuffer[whichSector*4 + 1],
  3904. DisketteExtension->IoBuffer[whichSector*4 + 2],
  3905. DisketteExtension->IoBuffer[whichSector*4 + 3])
  3906. );
  3907. }
  3908. //
  3909. // Retry until success or too many retries.
  3910. //
  3911. retryCount = 0;
  3912. do {
  3913. ULONG length;
  3914. length = driveMediaConstants->BytesPerSector;
  3915. //
  3916. // Issue command to format track
  3917. //
  3918. DisketteExtension->FifoBuffer[0] =
  3919. COMMND_FORMAT_TRACK + COMMND_OPTION_MFM;
  3920. DisketteExtension->FifoBuffer[1] = (UCHAR)
  3921. ( ( ( currentTrack % driveMediaConstants->NumberOfHeads ) << 2 )
  3922. | DisketteExtension->DeviceUnit );
  3923. DisketteExtension->FifoBuffer[2] =
  3924. driveMediaConstants->SectorLengthCode;
  3925. DisketteExtension->FifoBuffer[3] =
  3926. driveMediaConstants->SectorsPerTrack;
  3927. DisketteExtension->FifoBuffer[4] =
  3928. driveMediaConstants->FormatGapLength;
  3929. DisketteExtension->FifoBuffer[5] =
  3930. driveMediaConstants->FormatFillCharacter;
  3931. FloppyDump(
  3932. FLOPFORMAT,
  3933. ("Floppy: format command parameters\n"
  3934. "------ Head/Unit: %x\n"
  3935. "------ Bytes/Sector: %x\n"
  3936. "------ Sectors/Cylinder: %x\n"
  3937. "------ Gap 3: %x\n"
  3938. "------ Filler Byte: %x\n",
  3939. DisketteExtension->FifoBuffer[1],
  3940. DisketteExtension->FifoBuffer[2],
  3941. DisketteExtension->FifoBuffer[3],
  3942. DisketteExtension->FifoBuffer[4],
  3943. DisketteExtension->FifoBuffer[5])
  3944. );
  3945. ntStatus = FlIssueCommand( DisketteExtension,
  3946. DisketteExtension->FifoBuffer,
  3947. DisketteExtension->FifoBuffer,
  3948. DisketteExtension->IoBufferMdl,
  3949. 0,
  3950. length );
  3951. if ( !NT_SUCCESS( ntStatus ) ) {
  3952. FloppyDump(
  3953. FLOPDBGP,
  3954. ("Floppy: format returned %x\n", ntStatus)
  3955. );
  3956. }
  3957. if ( NT_SUCCESS( ntStatus ) ) {
  3958. //
  3959. // Check the return bytes from the controller.
  3960. //
  3961. if ( ( DisketteExtension->FifoBuffer[0] &
  3962. ( STREG0_DRIVE_FAULT |
  3963. STREG0_END_INVALID_COMMAND |
  3964. STREG0_END_ERROR
  3965. ) )
  3966. || ( DisketteExtension->FifoBuffer[1] &
  3967. STREG1_DATA_OVERRUN ) ||
  3968. ( DisketteExtension->FifoBuffer[2] != 0 ) ) {
  3969. FloppyDump(
  3970. FLOPWARN,
  3971. ("Floppy: format had bad registers\n"
  3972. "------ Streg0 = %x\n"
  3973. "------ Streg1 = %x\n"
  3974. "------ Streg2 = %x\n",
  3975. DisketteExtension->FifoBuffer[0],
  3976. DisketteExtension->FifoBuffer[1],
  3977. DisketteExtension->FifoBuffer[2])
  3978. );
  3979. DisketteExtension->HardwareFailed = TRUE;
  3980. ntStatus = FlInterpretError(
  3981. DisketteExtension->FifoBuffer[1],
  3982. DisketteExtension->FifoBuffer[2] );
  3983. }
  3984. }
  3985. } while ( ( !NT_SUCCESS( ntStatus ) ) &&
  3986. ( retryCount++ < RECALIBRATE_RETRY_COUNT ) );
  3987. if ( !NT_SUCCESS( ntStatus ) ) {
  3988. ntStatus = FlFdcDeviceIo( DisketteExtension->TargetObject,
  3989. IOCTL_DISK_INTERNAL_GET_FDC_DISK_CHANGE,
  3990. &fdcDiskChangeParms );
  3991. driveStatus = fdcDiskChangeParms.DriveStatus;
  3992. if ( (DisketteExtension->DriveType != DRIVE_TYPE_0360) &&
  3993. driveStatus & DSKCHG_DISKETTE_REMOVED ) {
  3994. //
  3995. // The user apparently popped the floppy. Return error
  3996. // rather than logging bad track.
  3997. //
  3998. return STATUS_NO_MEDIA_IN_DEVICE;
  3999. }
  4000. //
  4001. // Log the bad track.
  4002. //
  4003. FloppyDump(
  4004. FLOPDBGP,
  4005. ("Floppy: track %x is bad\n", currentTrack)
  4006. );
  4007. if (badTrackBufferLength >= (ULONG) ((numberOfBadTracks + 1) * sizeof(BAD_TRACK_NUMBER))) {
  4008. badTrackBuffer = (PBAD_TRACK_NUMBER) Irp->AssociatedIrp.SystemBuffer;
  4009. badTrackBuffer[numberOfBadTracks] = ( BAD_TRACK_NUMBER ) currentTrack;
  4010. Irp->IoStatus.Information += sizeof(BAD_TRACK_NUMBER);
  4011. } else {
  4012. bufferOverflow = TRUE;
  4013. }
  4014. numberOfBadTracks++;
  4015. }
  4016. currentTrack++;
  4017. } while ( currentTrack <= endTrack );
  4018. if ( ( NT_SUCCESS( ntStatus ) ) && ( bufferOverflow ) ) {
  4019. ntStatus = STATUS_BUFFER_OVERFLOW;
  4020. }
  4021. return ntStatus;
  4022. }
  4023. BOOLEAN
  4024. FlCheckFormatParameters(
  4025. IN PDISKETTE_EXTENSION DisketteExtension,
  4026. IN PFORMAT_PARAMETERS FormatParameters
  4027. )
  4028. /*++
  4029. Routine Description:
  4030. This routine checks the supplied format parameters to make sure that
  4031. they'll work on the drive to be formatted.
  4032. Arguments:
  4033. DisketteExtension - a pointer to our data area for the diskette to
  4034. be formatted.
  4035. FormatParameters - a pointer to the caller's parameters for the FORMAT.
  4036. Return Value:
  4037. TRUE if parameters are OK.
  4038. FALSE if the parameters are bad.
  4039. --*/
  4040. {
  4041. PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
  4042. DRIVE_MEDIA_TYPE driveMediaType;
  4043. //
  4044. // Figure out which entry in the DriveMediaConstants table to use.
  4045. //
  4046. driveMediaType =
  4047. DriveMediaLimits[DisketteExtension->DriveType].HighestDriveMediaType;
  4048. while ((DriveMediaConstants[driveMediaType].MediaType !=
  4049. FormatParameters->MediaType ) &&
  4050. (driveMediaType > DriveMediaLimits[DisketteExtension->DriveType].
  4051. LowestDriveMediaType)) {
  4052. driveMediaType--;
  4053. }
  4054. if ( DriveMediaConstants[driveMediaType].MediaType !=
  4055. FormatParameters->MediaType ) {
  4056. return FALSE;
  4057. } else {
  4058. driveMediaConstants = &DriveMediaConstants[driveMediaType];
  4059. if ( ( FormatParameters->StartHeadNumber >
  4060. (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
  4061. ( FormatParameters->EndHeadNumber >
  4062. (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
  4063. ( FormatParameters->StartCylinderNumber >
  4064. driveMediaConstants->MaximumTrack ) ||
  4065. ( FormatParameters->EndCylinderNumber >
  4066. driveMediaConstants->MaximumTrack ) ||
  4067. ( FormatParameters->EndCylinderNumber <
  4068. FormatParameters->StartCylinderNumber ) ) {
  4069. return FALSE;
  4070. }
  4071. }
  4072. return TRUE;
  4073. }
  4074. NTSTATUS
  4075. FlIssueCommand(
  4076. IN OUT PDISKETTE_EXTENSION DisketteExtension,
  4077. IN PUCHAR FifoInBuffer,
  4078. OUT PUCHAR FifoOutBuffer,
  4079. IN PMDL IoMdl,
  4080. IN OUT ULONG IoOffset,
  4081. IN ULONG TransferBytes
  4082. )
  4083. /*++
  4084. Routine Description:
  4085. This routine sends the command and all parameters to the controller,
  4086. waits for the command to interrupt if necessary, and reads the result
  4087. bytes from the controller, if any.
  4088. Before calling this routine, the caller should put the parameters for
  4089. the command in ControllerData->FifoBuffer[]. The result bytes will
  4090. be returned in the same place.
  4091. This routine runs off the CommandTable. For each command, this says
  4092. how many parameters there are, whether or not there is an interrupt
  4093. to wait for, and how many result bytes there are. Note that commands
  4094. without result bytes actually have two, since the ISR will issue a
  4095. SENSE INTERRUPT STATUS command on their behalf.
  4096. Arguments:
  4097. Command - a byte specifying the command to be sent to the controller.
  4098. FloppyExtension - a pointer to our data area for the drive being
  4099. accessed (any drive if a controller command is being given).
  4100. Return Value:
  4101. STATUS_SUCCESS if the command was sent and bytes received properly;
  4102. appropriate error propogated otherwise.
  4103. --*/
  4104. {
  4105. NTSTATUS ntStatus;
  4106. UCHAR i;
  4107. PIRP irp;
  4108. KEVENT DoneEvent;
  4109. IO_STATUS_BLOCK IoStatus;
  4110. PIO_STACK_LOCATION irpSp;
  4111. ISSUE_FDC_COMMAND_PARMS issueCommandParms;
  4112. //
  4113. // Set the command parameters
  4114. //
  4115. issueCommandParms.FifoInBuffer = FifoInBuffer;
  4116. issueCommandParms.FifoOutBuffer = FifoOutBuffer;
  4117. issueCommandParms.IoHandle = (PVOID)IoMdl;
  4118. issueCommandParms.IoOffset = IoOffset;
  4119. issueCommandParms.TransferBytes = TransferBytes;
  4120. issueCommandParms.TimeOut = FDC_TIMEOUT;
  4121. FloppyDump( FLOPSHOW,
  4122. ("Floppy: FloppyIssueCommand %2x...\n",
  4123. DisketteExtension->FifoBuffer[0])
  4124. );
  4125. ntStatus = FlFdcDeviceIo( DisketteExtension->TargetObject,
  4126. IOCTL_DISK_INTERNAL_ISSUE_FDC_COMMAND,
  4127. &issueCommandParms );
  4128. //
  4129. // If it appears like the floppy controller is not responding
  4130. // set the HardwareFailed flag which will force a reset.
  4131. //
  4132. if ( ntStatus == STATUS_DEVICE_NOT_READY ||
  4133. ntStatus == STATUS_FLOPPY_BAD_REGISTERS ) {
  4134. DisketteExtension->HardwareFailed = TRUE;
  4135. }
  4136. return ntStatus;
  4137. }
  4138. NTSTATUS
  4139. FlInitializeControllerHardware(
  4140. IN OUT PDISKETTE_EXTENSION DisketteExtension
  4141. )
  4142. /*++
  4143. Routine Description:
  4144. This routine is called to reset and initialize the floppy controller device.
  4145. Arguments:
  4146. disketteExtension - Supplies the diskette extension.
  4147. Return Value:
  4148. --*/
  4149. {
  4150. NTSTATUS ntStatus;
  4151. ntStatus = FlFdcDeviceIo( DisketteExtension->TargetObject,
  4152. IOCTL_DISK_INTERNAL_RESET_FDC,
  4153. NULL );
  4154. if (NT_SUCCESS(ntStatus)) {
  4155. if ( DisketteExtension->PerpendicularMode != 0 ) {
  4156. DisketteExtension->FifoBuffer[0] = COMMND_PERPENDICULAR_MODE;
  4157. DisketteExtension->FifoBuffer[1] =
  4158. (UCHAR) (COMMND_PERPENDICULAR_MODE_OW |
  4159. (DisketteExtension->PerpendicularMode << 2));
  4160. ntStatus = FlIssueCommand( DisketteExtension,
  4161. DisketteExtension->FifoBuffer,
  4162. DisketteExtension->FifoBuffer,
  4163. NULL,
  4164. 0,
  4165. 0 );
  4166. }
  4167. }
  4168. return ntStatus;
  4169. }
  4170. NTSTATUS
  4171. FlFdcDeviceIo(
  4172. IN PDEVICE_OBJECT DeviceObject,
  4173. IN ULONG Ioctl,
  4174. IN OUT PVOID Data
  4175. )
  4176. {
  4177. NTSTATUS ntStatus;
  4178. PIRP irp;
  4179. PIO_STACK_LOCATION irpStack;
  4180. KEVENT doneEvent;
  4181. IO_STATUS_BLOCK ioStatus;
  4182. FloppyDump(FLOPINFO,("Calling Fdc Device with %x\n", Ioctl));
  4183. KeInitializeEvent( &doneEvent,
  4184. NotificationEvent,
  4185. FALSE);
  4186. //
  4187. // Create an IRP for enabler
  4188. //
  4189. irp = IoBuildDeviceIoControlRequest( Ioctl,
  4190. DeviceObject,
  4191. NULL,
  4192. 0,
  4193. NULL,
  4194. 0,
  4195. TRUE,
  4196. &doneEvent,
  4197. &ioStatus );
  4198. if (irp == NULL) {
  4199. FloppyDump(FLOPDBGP,("FlFloppyDeviceIo: Can't allocate Irp\n"));
  4200. //
  4201. // If an Irp can't be allocated, then this call will
  4202. // simply return. This will leave the queue frozen for
  4203. // this device, which means it can no longer be accessed.
  4204. //
  4205. return STATUS_INSUFFICIENT_RESOURCES;
  4206. }
  4207. irpStack = IoGetNextIrpStackLocation(irp);
  4208. irpStack->Parameters.DeviceIoControl.Type3InputBuffer = Data;
  4209. //
  4210. // Call the driver and request the operation
  4211. //
  4212. ntStatus = IoCallDriver(DeviceObject, irp);
  4213. if ( ntStatus == STATUS_PENDING ) {
  4214. //
  4215. // Now wait for operation to complete (should already be done, but
  4216. // maybe not)
  4217. //
  4218. KeWaitForSingleObject( &doneEvent,
  4219. Executive,
  4220. KernelMode,
  4221. FALSE,
  4222. NULL );
  4223. ntStatus = ioStatus.Status;
  4224. }
  4225. return ntStatus;
  4226. }
  4227. NTSTATUS
  4228. FloppyQueueRequest (
  4229. IN OUT PDISKETTE_EXTENSION DisketteExtension,
  4230. IN PIRP Irp
  4231. )
  4232. /*++
  4233. Routine Description:
  4234. Queues the Irp in the device queue. This routine will be called whenever
  4235. the device receives IRP_MN_QUERY_STOP_DEVICE or IRP_MN_QUERY_REMOVE_DEVICE
  4236. Arguments:
  4237. FdoData - pointer to the device's extension.
  4238. Irp - the request to be queued.
  4239. Return Value:
  4240. NT status code.
  4241. --*/
  4242. {
  4243. KIRQL oldIrql;
  4244. NTSTATUS ntStatus;
  4245. //
  4246. // Reset driver paging
  4247. //
  4248. FloppyResetDriverPaging();
  4249. //
  4250. // Check if we are allowed to queue requests.
  4251. //
  4252. ASSERT( DisketteExtension->HoldNewRequests );
  4253. //
  4254. // Preparing for dealing with cancelling stuff.
  4255. // We don't know how long the irp will be in the
  4256. // queue. So we need to handle cancel.
  4257. // Since we use our own queue, we don't need to use
  4258. // the cancel spin lock.
  4259. //
  4260. KeAcquireSpinLock(&DisketteExtension->FlCancelSpinLock, &oldIrql);
  4261. IoSetCancelRoutine(Irp, FloppyCancelQueuedRequest);
  4262. //
  4263. // Check if the irp was already canceled
  4264. //
  4265. if ((Irp->Cancel) && (IoSetCancelRoutine(Irp, NULL))) {
  4266. //
  4267. // Already canceled
  4268. //
  4269. Irp->IoStatus.Status = STATUS_CANCELLED;
  4270. Irp->IoStatus.Information = 0;
  4271. KeReleaseSpinLock(&DisketteExtension->FlCancelSpinLock, oldIrql);
  4272. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  4273. FloppyPageEntireDriver();
  4274. ntStatus = STATUS_CANCELLED;
  4275. } else {
  4276. //
  4277. // Queue the Irp and set a cancel routine
  4278. //
  4279. Irp->IoStatus.Status = STATUS_PENDING;
  4280. IoMarkIrpPending(Irp);
  4281. ExInterlockedInsertTailList( &DisketteExtension->NewRequestQueue,
  4282. &Irp->Tail.Overlay.ListEntry,
  4283. &DisketteExtension->NewRequestQueueSpinLock);
  4284. KeReleaseSpinLock(&DisketteExtension->FlCancelSpinLock, oldIrql);
  4285. ntStatus = STATUS_PENDING;
  4286. }
  4287. return ntStatus;
  4288. }
  4289. VOID
  4290. FloppyCancelQueuedRequest (
  4291. IN PDEVICE_OBJECT DeviceObject,
  4292. IN PIRP Irp
  4293. )
  4294. /*++
  4295. Routine Description:
  4296. The cancel routine. Will remove the IRP from the queue and will complete it.
  4297. The cancel spin lock is already acquired when this routine is called.
  4298. Arguments:
  4299. DeviceObject - pointer to the device object.
  4300. Irp - pointer to the IRP to be cancelled.
  4301. Return Value:
  4302. VOID.
  4303. --*/
  4304. {
  4305. PDISKETTE_EXTENSION disketteExtension = DeviceObject->DeviceExtension;
  4306. KIRQL oldIrql;
  4307. FloppyDump(FLOPDBGP, ("Floppy Cancel called.\n"));
  4308. KeAcquireSpinLock(&disketteExtension->FlCancelSpinLock, &oldIrql);
  4309. Irp->IoStatus.Status = STATUS_CANCELLED;
  4310. Irp->IoStatus.Information = 0;
  4311. //
  4312. // Make sure the IRP wasn't removed in Process routine.
  4313. //
  4314. if (Irp->Tail.Overlay.ListEntry.Flink) {
  4315. RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
  4316. }
  4317. KeReleaseSpinLock(&disketteExtension->FlCancelSpinLock, oldIrql);
  4318. IoReleaseCancelSpinLock(Irp->CancelIrql);
  4319. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4320. FloppyPageEntireDriver();
  4321. return;
  4322. }
  4323. VOID
  4324. FloppyProcessQueuedRequests (
  4325. IN OUT PDISKETTE_EXTENSION DisketteExtension
  4326. )
  4327. /*++
  4328. Routine Description:
  4329. Removes an dprocesses the entries in the queue. If this routine is called
  4330. when processing IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE
  4331. or IRP_MN_START_DEVICE, the requests are passed to the next lower driver.
  4332. If the routine is called when IRP_MN_REMOVE_DEVICE is received, the IRPs
  4333. are completed with STATUS_DELETE_PENDING.
  4334. Arguments:
  4335. Return Value:
  4336. VOID.
  4337. --*/
  4338. {
  4339. KIRQL oldIrql;
  4340. PLIST_ENTRY headOfList;
  4341. PIRP currentIrp;
  4342. PIO_STACK_LOCATION irpSp;
  4343. //
  4344. // We need to dequeue all the entries in the queue, to reset the cancel
  4345. // routine for each of them and then to process then:
  4346. // - if the device is active, we will send them down
  4347. // - else we will complete them with STATUS_DELETE_PENDING
  4348. // (it is a surprise removal and we need to dispose the queue)
  4349. //
  4350. KeAcquireSpinLock(&DisketteExtension->FlCancelSpinLock,
  4351. &oldIrql);
  4352. while ((headOfList = ExInterlockedRemoveHeadList(
  4353. &DisketteExtension->NewRequestQueue,
  4354. &DisketteExtension->NewRequestQueueSpinLock)) != NULL) {
  4355. currentIrp = CONTAINING_RECORD( headOfList,
  4356. IRP,
  4357. Tail.Overlay.ListEntry);
  4358. if (IoSetCancelRoutine( currentIrp, NULL)) {
  4359. irpSp = IoGetCurrentIrpStackLocation( currentIrp );
  4360. } else {
  4361. //
  4362. // Cancel routine is already running for this IRP.
  4363. // Set the IRP field so that it won't be removed
  4364. // in the cancel routine again.
  4365. //
  4366. currentIrp->Tail.Overlay.ListEntry.Flink = NULL;
  4367. currentIrp = NULL;
  4368. }
  4369. KeReleaseSpinLock(&DisketteExtension->FlCancelSpinLock,
  4370. oldIrql);
  4371. if (currentIrp) {
  4372. if ( DisketteExtension->IsRemoved ) {
  4373. //
  4374. // The device was removed, we need to fail the request
  4375. //
  4376. currentIrp->IoStatus.Information = 0;
  4377. currentIrp->IoStatus.Status = STATUS_DELETE_PENDING;
  4378. IoCompleteRequest (currentIrp, IO_NO_INCREMENT);
  4379. } else {
  4380. switch ( irpSp->MajorFunction ) {
  4381. case IRP_MJ_READ:
  4382. case IRP_MJ_WRITE:
  4383. (VOID)FloppyReadWrite( DisketteExtension->DeviceObject, currentIrp );
  4384. break;
  4385. case IRP_MJ_DEVICE_CONTROL:
  4386. (VOID)FloppyDeviceControl( DisketteExtension->DeviceObject, currentIrp);
  4387. break;
  4388. default:
  4389. currentIrp->IoStatus.Information = 0;
  4390. currentIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  4391. IoCompleteRequest (currentIrp, IO_NO_INCREMENT);
  4392. }
  4393. }
  4394. }
  4395. if (currentIrp) {
  4396. //
  4397. // Page out the driver if it's no more needed.
  4398. //
  4399. FloppyPageEntireDriver();
  4400. }
  4401. KeAcquireSpinLock(&DisketteExtension->FlCancelSpinLock,
  4402. &oldIrql);
  4403. }
  4404. KeReleaseSpinLock(&DisketteExtension->FlCancelSpinLock,
  4405. oldIrql);
  4406. return;
  4407. }