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.

7783 lines
240 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Copyright (c) 1996 Colorado Software Architects
  4. Module Name:
  5. fdc.c
  6. Abstract:
  7. This is the NEC PD756 (aka AT, aka IS1A, aka ix86) and Intel 82077
  8. (aka MIPS) floppy diskette driver for NT.
  9. Environment:
  10. Kernel mode only.
  11. --*/
  12. //
  13. // Include files.
  14. //
  15. #include "stdio.h"
  16. #include "ntddk.h"
  17. #include "ntdddisk.h" // disk device driver I/O control codes
  18. #include "ntddfdc.h" // fdc I/O control codes and parameters
  19. #include <fdc_data.h> // this driver's data declarations
  20. #include <flpyenbl.h>
  21. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  22. #define MIN(a,b) ((a) > (b) ? (b) : (a))
  23. COMMAND_TABLE CommandTable[] = {
  24. { 0x06, 8, 1, 7, TRUE, TRUE, FDC_READ_DATA }, // Read Data
  25. { 0x0C, 0, 0, 0, FALSE, FALSE, FDC_NO_DATA }, // Not Implemented (MIPS)
  26. { 0x05, 8, 1, 7, TRUE, TRUE, FDC_WRITE_DATA }, // Write Data
  27. { 0x09, 0, 0, 0, FALSE, FALSE, FDC_NO_DATA }, // Not Implemented
  28. { 0x02, 8, 1, 7, TRUE, TRUE, FDC_READ_DATA }, // Read Track
  29. { 0x16, 8, 1, 7, TRUE, FALSE, FDC_NO_DATA }, // Verify
  30. { 0x10, 0, 0, 1, FALSE, FALSE, FDC_NO_DATA }, // Version
  31. { 0x0D, 5, 1, 7, TRUE, TRUE, FDC_WRITE_DATA }, // Format Track
  32. { 0x11, 8, 1, 7, TRUE, FALSE, FDC_READ_DATA }, // Scan Equal
  33. { 0x19, 8, 1, 7, TRUE, FALSE, FDC_READ_DATA }, // Scan Low Or Equal
  34. { 0x1D, 8, 1, 7, TRUE, FALSE, FDC_READ_DATA }, // Scan High Or Equal
  35. { 0x07, 1, 0, 2, TRUE, TRUE, FDC_NO_DATA }, // Recalibrate
  36. { 0x08, 0, 0, 2, FALSE, TRUE, FDC_NO_DATA }, // Sense Interrupt Status
  37. { 0x03, 2, 0, 0, FALSE, TRUE, FDC_NO_DATA }, // Specify
  38. { 0x04, 1, 0, 1, FALSE, TRUE, FDC_NO_DATA }, // Sense Drive Status
  39. { 0x8E, 6, 0, 0, FALSE, FALSE, FDC_NO_DATA }, // Drive Specification Command
  40. { 0x0F, 2, 0, 2, TRUE, TRUE, FDC_NO_DATA }, // Seek
  41. { 0x13, 3, 0, 0, FALSE, FALSE, FDC_NO_DATA }, // Configure
  42. { 0x8F, 2, 0, 2, TRUE, FALSE, FDC_NO_DATA }, // Relative Seek
  43. { 0x0E, 0, 0, 10, FALSE, FALSE, FDC_NO_DATA }, // Dumpreg
  44. { 0x0A, 1, 1, 7, TRUE, TRUE, FDC_NO_DATA }, // Read ID
  45. { 0x12, 1, 0, 0, FALSE, FALSE, FDC_NO_DATA }, // Perpendicular Mode
  46. { 0x14, 0, 0, 1, FALSE, FALSE, FDC_NO_DATA }, // Lock
  47. { 0x18, 0, 0, 1, FALSE, FALSE, FDC_NO_DATA }, // Part ID
  48. { 0x17, 1, 0, 1, FALSE, FALSE, FDC_NO_DATA }, // Powerdown Mode
  49. { 0x33, 1, 0, 0, FALSE, FALSE, FDC_NO_DATA }, // Option
  50. { 0x2E, 0, 0, 16, FALSE, FALSE, FDC_NO_DATA }, // Save
  51. { 0x4E, 16, 0, 0, FALSE, FALSE, FDC_NO_DATA }, // Restore
  52. { 0xAD, 5, 1, 7, TRUE, TRUE, FDC_WRITE_DATA } // Format And Write
  53. };
  54. //
  55. // This is the actual definition of FdcDebugLevel.
  56. // Note that it is only defined if this is a "debug"
  57. // build.
  58. //
  59. #if DBG
  60. extern ULONG FdcDebugLevel = 0;
  61. #endif
  62. #ifdef ALLOC_PRAGMA
  63. #pragma alloc_text(INIT,DriverEntry)
  64. #endif
  65. #ifdef POOL_TAGGING
  66. #ifdef ExAllocatePool
  67. #undef ExAllocatePool
  68. #endif
  69. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'polF')
  70. #endif
  71. BOOLEAN FdcInSetupMode;
  72. //
  73. // Used for paging the driver.
  74. //
  75. ULONG PagingReferenceCount = 0;
  76. PFAST_MUTEX PagingMutex = NULL;
  77. ULONG NumberOfBuffers = 0;
  78. ULONG BufferSize = 0;
  79. ULONG Model30 = 0;
  80. ULONG NotConfigurable = 0;
  81. // Feb.9.1998 KIADP011 Get base address of configuration ports
  82. // and device identifier
  83. #ifdef TOSHIBAJ
  84. ULONG SmcConfigBase;
  85. ULONG SmcConfigID;
  86. PUCHAR TranslatedConfigBase = NULL;
  87. #endif
  88. NTSTATUS
  89. DriverEntry(
  90. IN PDRIVER_OBJECT DriverObject,
  91. IN PUNICODE_STRING RegistryPath
  92. )
  93. /*++
  94. Routine Description:
  95. This routine is the driver's entry point, called by the I/O system
  96. to load the driver. This routine can be called any number of times,
  97. as long as the IO system and the configuration manager conspire to
  98. give it an unmanaged controller to support at each call. It could
  99. also be called a single time and given all of the controllers at
  100. once.
  101. It initializes the passed-in driver object, calls the configuration
  102. manager to learn about the devices that it is to support, and for
  103. each controller to be supported it calls a routine to initialize the
  104. controller (and all drives attached to it).
  105. Arguments:
  106. DriverObject - a pointer to the object that represents this device
  107. driver.
  108. Return Value:
  109. If we successfully initialize at least one drive, STATUS_SUCCESS is
  110. returned.
  111. If we don't (because the configuration manager returns an error, or
  112. the configuration manager says that there are no controllers or
  113. drives to support, or no controllers or drives can be successfully
  114. initialized), then the last error encountered is propogated.
  115. --*/
  116. {
  117. NTSTATUS ntStatus;
  118. //
  119. // We use this to query into the registry as to whether we
  120. // should break at driver entry.
  121. //
  122. RTL_QUERY_REGISTRY_TABLE paramTable[6];
  123. ULONG zero = 0;
  124. ULONG one = 1;
  125. ULONG debugLevel = 0;
  126. ULONG shouldBreak = 0;
  127. ULONG setupMode;
  128. PWCHAR path;
  129. UNICODE_STRING parameters;
  130. UNICODE_STRING systemPath;
  131. UNICODE_STRING identifier;
  132. UNICODE_STRING thinkpad, ps2e;
  133. ULONG pathLength;
  134. RtlInitUnicodeString(&parameters, L"\\Parameters");
  135. RtlInitUnicodeString(&systemPath,
  136. L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\System");
  137. RtlInitUnicodeString(&thinkpad, L"IBM THINKPAD 750");
  138. RtlInitUnicodeString(&ps2e, L"IBM PS2E");
  139. pathLength = RegistryPath->Length + parameters.Length + sizeof(WCHAR);
  140. if (pathLength < systemPath.Length + sizeof(WCHAR)) {
  141. pathLength = systemPath.Length + sizeof(WCHAR);
  142. }
  143. //
  144. // Since the registry path parameter is a "counted" UNICODE string, it
  145. // might not be zero terminated. For a very short time allocate memory
  146. // to hold the registry path zero terminated so that we can use it to
  147. // delve into the registry.
  148. //
  149. // NOTE NOTE!!!! This is not an architected way of breaking into
  150. // a driver. It happens to work for this driver because the author
  151. // likes to do things this way.
  152. //
  153. NumberOfBuffers = 3;
  154. BufferSize = 0x8000;
  155. if (path = ExAllocatePool(PagedPool, pathLength)) {
  156. RtlZeroMemory(&paramTable[0],
  157. sizeof(paramTable));
  158. RtlZeroMemory(path, pathLength);
  159. RtlMoveMemory(path,
  160. RegistryPath->Buffer,
  161. RegistryPath->Length);
  162. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  163. paramTable[0].Name = L"BreakOnEntry";
  164. paramTable[0].EntryContext = &shouldBreak;
  165. paramTable[0].DefaultType = REG_DWORD;
  166. paramTable[0].DefaultData = &zero;
  167. paramTable[0].DefaultLength = sizeof(ULONG);
  168. paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  169. paramTable[1].Name = L"DebugLevel";
  170. paramTable[1].EntryContext = &debugLevel;
  171. paramTable[1].DefaultType = REG_DWORD;
  172. paramTable[1].DefaultData = &zero;
  173. paramTable[1].DefaultLength = sizeof(ULONG);
  174. paramTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  175. paramTable[2].Name = L"NumberOfBuffers";
  176. paramTable[2].EntryContext = &NumberOfBuffers;
  177. paramTable[2].DefaultType = REG_DWORD;
  178. paramTable[2].DefaultData = &NumberOfBuffers;
  179. paramTable[2].DefaultLength = sizeof(ULONG);
  180. paramTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
  181. paramTable[3].Name = L"BufferSize";
  182. paramTable[3].EntryContext = &BufferSize;
  183. paramTable[3].DefaultType = REG_DWORD;
  184. paramTable[3].DefaultData = &BufferSize;
  185. paramTable[3].DefaultLength = sizeof(ULONG);
  186. paramTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
  187. paramTable[4].Name = L"SetupDone";
  188. paramTable[4].EntryContext = &setupMode;
  189. paramTable[4].DefaultType = REG_DWORD;
  190. paramTable[4].DefaultData = &zero;
  191. paramTable[4].DefaultLength = sizeof(ULONG);
  192. if (!NT_SUCCESS(RtlQueryRegistryValues(
  193. RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  194. path,
  195. &paramTable[0],
  196. NULL,
  197. NULL))) {
  198. shouldBreak = 0;
  199. debugLevel = 0;
  200. }
  201. FdcInSetupMode = !(BOOLEAN)setupMode;
  202. FdcDump( FDCSHOW, ("FdcDriverEntry: FdcInSetupMode = %x\n",FdcInSetupMode) );
  203. if ( FdcInSetupMode ) {
  204. OBJECT_ATTRIBUTES keyAttributes;
  205. HANDLE keyHandle;
  206. UNICODE_STRING value;
  207. RtlInitUnicodeString( &value, L"SetupDone" );
  208. setupMode = 1;
  209. InitializeObjectAttributes( &keyAttributes,
  210. RegistryPath,
  211. OBJ_CASE_INSENSITIVE,
  212. NULL,
  213. NULL );
  214. ntStatus = ZwOpenKey( &keyHandle,
  215. KEY_ALL_ACCESS,
  216. &keyAttributes );
  217. if ( NT_SUCCESS(ntStatus) ) {
  218. FdcDump( FDCSHOW, ("FdcDriverEntry: Set SetupMode Value in Registry\n") );
  219. ZwSetValueKey( keyHandle,
  220. &value,
  221. 0,
  222. REG_DWORD,
  223. &setupMode,
  224. sizeof(ULONG) );
  225. ZwClose( keyHandle);
  226. }
  227. }
  228. //
  229. // Determine whether or not this type of system has a
  230. // model 30 floppy controller.
  231. //
  232. RtlZeroMemory(paramTable, sizeof(paramTable));
  233. RtlZeroMemory(path, pathLength);
  234. RtlMoveMemory(path,
  235. systemPath.Buffer,
  236. systemPath.Length);
  237. RtlZeroMemory(&identifier, sizeof(UNICODE_STRING));
  238. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |
  239. RTL_QUERY_REGISTRY_REQUIRED;
  240. paramTable[0].Name = L"Identifier";
  241. paramTable[0].EntryContext = &identifier;
  242. if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  243. path,
  244. paramTable,
  245. NULL,
  246. NULL))) {
  247. if (identifier.Length == thinkpad.Length &&
  248. RtlCompareMemory(identifier.Buffer, thinkpad.Buffer,
  249. thinkpad.Length) == thinkpad.Length) {
  250. Model30 = 1;
  251. } else if (identifier.Length == ps2e.Length &&
  252. RtlCompareMemory(identifier.Buffer, ps2e.Buffer,
  253. ps2e.Length) == ps2e.Length) {
  254. Model30 = 1;
  255. } else {
  256. Model30 = 0;
  257. }
  258. } else {
  259. Model30 = 0;
  260. }
  261. //
  262. // This part gets from the parameters part of the registry
  263. // to see if the controller configuration needs to be disabled.
  264. // Doing this lets SMC 661, and 662 work. On hardware that
  265. // works normally, this change will show a slowdown of up
  266. // to 40%. So defining this variable is not recommended
  267. // unless things don't work without it.
  268. //
  269. //
  270. // Also check the model30 value in the parameters section
  271. // that is used to override the decision above.
  272. //
  273. RtlZeroMemory(&paramTable[0],
  274. sizeof(paramTable));
  275. RtlZeroMemory(path,
  276. RegistryPath->Length+parameters.Length+sizeof(WCHAR));
  277. RtlMoveMemory(path,
  278. RegistryPath->Buffer,
  279. RegistryPath->Length);
  280. RtlMoveMemory((PCHAR) path + RegistryPath->Length,
  281. parameters.Buffer,
  282. parameters.Length);
  283. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  284. paramTable[0].Name = L"NotConfigurable";
  285. paramTable[0].EntryContext = &NotConfigurable;
  286. paramTable[0].DefaultType = REG_DWORD;
  287. paramTable[0].DefaultData = &zero;
  288. paramTable[0].DefaultLength = sizeof(ULONG);
  289. paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  290. paramTable[1].Name = L"Model30";
  291. paramTable[1].EntryContext = &Model30;
  292. paramTable[1].DefaultType = REG_DWORD;
  293. paramTable[1].DefaultData = Model30 ? &one : &zero;
  294. paramTable[1].DefaultLength = sizeof(ULONG);
  295. if (!NT_SUCCESS(RtlQueryRegistryValues(
  296. RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  297. path,
  298. &paramTable[0],
  299. NULL,
  300. NULL))) {
  301. NotConfigurable = 0;
  302. }
  303. #ifdef TOSHIBAJ
  304. // Feb.9.1998 KIADP011 Get base address and identifier
  305. RtlZeroMemory(&paramTable[0],
  306. sizeof(paramTable));
  307. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  308. paramTable[0].Name = L"ConfigurationBase";
  309. paramTable[0].EntryContext = &SmcConfigBase;
  310. paramTable[0].DefaultType = REG_DWORD;
  311. paramTable[0].DefaultData = &zero;
  312. paramTable[0].DefaultLength = sizeof(ULONG);
  313. paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  314. paramTable[1].Name = L"ControllerID";
  315. paramTable[1].EntryContext = &SmcConfigID;
  316. paramTable[1].DefaultType = REG_DWORD;
  317. paramTable[1].DefaultData = &zero;
  318. paramTable[1].DefaultLength = sizeof(ULONG);
  319. if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  320. path,
  321. &paramTable[0],
  322. NULL,
  323. NULL))) {
  324. SmcConfigBase = 0;
  325. SmcConfigID = 0;
  326. }
  327. #endif
  328. }
  329. //
  330. // We don't need that path anymore.
  331. //
  332. if (path) {
  333. ExFreePool(path);
  334. }
  335. #if DBG
  336. FdcDebugLevel = debugLevel;
  337. #endif
  338. if (shouldBreak) {
  339. DbgBreakPoint();
  340. }
  341. FdcDump(FDCSHOW,
  342. ("Fdc: DriverEntry...\n"));
  343. //
  344. // Initialize the driver object with this driver's entry points.
  345. //
  346. DriverObject->MajorFunction[IRP_MJ_CREATE] =
  347. DriverObject->MajorFunction[IRP_MJ_CLOSE] = FdcCreateClose;
  348. DriverObject->MajorFunction[IRP_MJ_POWER] = FdcPower;
  349. DriverObject->MajorFunction[IRP_MJ_PNP] = FdcPnp;
  350. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  351. FdcInternalDeviceControl;
  352. DriverObject->DriverStartIo = FdcStartIo;
  353. DriverObject->DriverExtension->AddDevice = FdcAddDevice;
  354. FDC_PAGE_INITIALIZE_DRIVER_WITH_MUTEX;
  355. return STATUS_SUCCESS;
  356. }
  357. NTSTATUS
  358. FdcAddDevice(
  359. IN PDRIVER_OBJECT DriverObject,
  360. IN OUT PDEVICE_OBJECT BusPhysicalDeviceObject
  361. )
  362. /*++
  363. Routine Description.
  364. A floppy controller device has been enumerated by the root/firmware
  365. enumerator. Create an FDO and attach it to this PDO.
  366. Arguments:
  367. BusDeviceObject - Device object representing the floppy controller. That
  368. to which we attach a new FDO.
  369. DriverObject - This driver.
  370. Return Value:
  371. STATUS_SUCCESS if the device is successfully created.
  372. --*/
  373. {
  374. NTSTATUS ntStatus = STATUS_SUCCESS;
  375. PDEVICE_OBJECT deviceObject;
  376. PFDC_FDO_EXTENSION fdoExtension;
  377. UNICODE_STRING deviceName;
  378. FdcDump( FDCSHOW, ("FdcAddDevice: CreateDeviceObject\n"));
  379. //
  380. // Create the FDO device.
  381. //
  382. // JB:TBD - Still need to resolve device naming. For the time being,
  383. // this device is unnamed (per the gameport example).
  384. //
  385. ntStatus = IoCreateDevice( DriverObject,
  386. sizeof( FDC_FDO_EXTENSION ),
  387. NULL,
  388. FILE_DEVICE_CONTROLLER,
  389. FILE_DEVICE_SECURE_OPEN,
  390. TRUE,
  391. &deviceObject );
  392. if ( NT_SUCCESS(ntStatus) ) {
  393. //
  394. // Initialize the fdoExtension for this device.
  395. //
  396. fdoExtension = deviceObject->DeviceExtension;
  397. fdoExtension->IsFDO = TRUE;
  398. fdoExtension->DriverObject = DriverObject;
  399. fdoExtension->Self = deviceObject;
  400. fdoExtension->OutstandingRequests = 1;
  401. fdoExtension->TapeEnumerationPending = FALSE;
  402. KeInitializeEvent( &fdoExtension->TapeEnumerationEvent,
  403. SynchronizationEvent,
  404. TRUE );
  405. KeInitializeEvent( &fdoExtension->RemoveEvent,
  406. SynchronizationEvent,
  407. FALSE );
  408. InitializeListHead( &fdoExtension->PDOs );
  409. //
  410. // Initialize a queue for power management.
  411. //
  412. InitializeListHead( &fdoExtension->PowerQueue );
  413. KeInitializeSpinLock( &fdoExtension->PowerQueueSpinLock );
  414. //
  415. // Initialize a variable to hold the last motor settle
  416. // time that we have seen. We will use this when we turn
  417. // the floppy motor back on after a power event.
  418. //
  419. fdoExtension->LastMotorSettleTime.QuadPart = 0;
  420. //
  421. // Set the PDO for use with PlugPlay functions
  422. //
  423. fdoExtension->UnderlyingPDO = BusPhysicalDeviceObject;
  424. //
  425. // Now attach to the PDO so that we have a target for PnP and
  426. // Power irps that we need to pass on.
  427. //
  428. FdcDump( FDCSHOW, ("AddDevice: Attaching %p to %p\n",
  429. deviceObject,
  430. BusPhysicalDeviceObject));
  431. fdoExtension->TargetObject = IoAttachDeviceToDeviceStack( deviceObject,
  432. BusPhysicalDeviceObject );
  433. deviceObject->Flags |= DO_DIRECT_IO;
  434. deviceObject->Flags |= DO_POWER_PAGABLE;
  435. if ( deviceObject->AlignmentRequirement < FILE_WORD_ALIGNMENT ) {
  436. deviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
  437. }
  438. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  439. }
  440. return ntStatus;
  441. }
  442. NTSTATUS
  443. FdcPnp (
  444. IN PDEVICE_OBJECT DeviceObject,
  445. IN PIRP Irp
  446. )
  447. /*++
  448. Routine Description:
  449. Determine if this Pnp request is directed towards an FDO or a PDO and
  450. pass the Irp on the the appropriate routine.
  451. Arguments:
  452. DeviceObject - a pointer to the object that represents the device
  453. that I/O is to be done on.
  454. Irp - a pointer to the I/O Request Packet for this request.
  455. Return Value:
  456. --*/
  457. {
  458. PIO_STACK_LOCATION irpSp;
  459. NTSTATUS ntStatus = STATUS_SUCCESS;
  460. PFDC_EXTENSION_HEADER extensionHeader;
  461. KIRQL oldIrq;
  462. irpSp = IoGetCurrentIrpStackLocation( Irp );
  463. extensionHeader = (PFDC_EXTENSION_HEADER)DeviceObject->DeviceExtension;
  464. //
  465. // Lock down the driver code in memory if it is not already.
  466. //
  467. FDC_PAGE_RESET_DRIVER_WITH_MUTEX;
  468. if ( extensionHeader->IsFDO ) {
  469. ntStatus = FdcFdoPnp( DeviceObject, Irp );
  470. } else {
  471. ntStatus = FdcPdoPnp( DeviceObject, Irp );
  472. }
  473. //
  474. // Page out the driver if it is not busy elsewhere.
  475. //
  476. FDC_PAGE_ENTIRE_DRIVER_WITH_MUTEX;
  477. return ntStatus;
  478. }
  479. NTSTATUS
  480. FdcFdoPnp(
  481. IN PDEVICE_OBJECT DeviceObject,
  482. IN PIRP Irp
  483. )
  484. /*++
  485. Routine Description:
  486. This routine is called by the I/O system to perform Plug-and-Play
  487. functions. This routine handles messages to the FDO which is part
  488. of the bus DevNode.
  489. Arguments:
  490. DeviceObject - a pointer to the object that represents the device
  491. that I/O is to be done on.
  492. Irp - a pointer to the I/O Request Packet for this request.
  493. Return Value:
  494. STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
  495. STATUS_INVALID_DEVICE_REQUEST otherwise.
  496. --*/
  497. {
  498. PFDC_FDO_EXTENSION fdoExtension;
  499. NTSTATUS ntStatus;
  500. PIO_STACK_LOCATION irpSp;
  501. KEVENT doneEvent;
  502. fdoExtension = DeviceObject->DeviceExtension;
  503. irpSp = IoGetCurrentIrpStackLocation( Irp );
  504. ntStatus = STATUS_SUCCESS;
  505. //
  506. // Incerement our queued request counter.
  507. //
  508. InterlockedIncrement( &fdoExtension->OutstandingRequests);
  509. if ( fdoExtension->Removed ) {
  510. Irp->IoStatus.Information = 0;
  511. Irp->IoStatus.Status = STATUS_DELETE_PENDING;
  512. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  513. if ( InterlockedDecrement( &fdoExtension->OutstandingRequests ) == 0 ) {
  514. KeSetEvent( &fdoExtension->RemoveEvent, 0, FALSE );
  515. }
  516. return STATUS_DELETE_PENDING;
  517. }
  518. switch (irpSp->MinorFunction) {
  519. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  520. ntStatus = FdcFilterResourceRequirements( DeviceObject, Irp );
  521. break;
  522. case IRP_MN_START_DEVICE:
  523. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_START_DEVICE - Irp: %p\n", Irp) );
  524. //
  525. // First we must pass this Irp on to the underlying PDO.
  526. //
  527. KeInitializeEvent( &doneEvent, NotificationEvent, FALSE );
  528. IoCopyCurrentIrpStackLocationToNext( Irp );
  529. IoSetCompletionRoutine( Irp,
  530. FdcPnpComplete,
  531. &doneEvent,
  532. TRUE,
  533. TRUE,
  534. TRUE );
  535. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  536. if ( ntStatus == STATUS_PENDING ) {
  537. ntStatus = KeWaitForSingleObject( &doneEvent,
  538. Executive,
  539. KernelMode,
  540. FALSE,
  541. NULL );
  542. ASSERT( ntStatus == STATUS_SUCCESS );
  543. ntStatus = Irp->IoStatus.Status;
  544. }
  545. //
  546. // Try to start the floppy disk controller.
  547. //
  548. if ( NT_SUCCESS(ntStatus) ) {
  549. ntStatus = FdcStartDevice( DeviceObject, Irp );
  550. }
  551. Irp->IoStatus.Status = ntStatus;
  552. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_START_DEVICE %08x %08x\n",Irp->IoStatus.Status,Irp->IoStatus.Information) );
  553. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  554. break;
  555. case IRP_MN_QUERY_REMOVE_DEVICE:
  556. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_QUERY_REMOVE_DEVICE - Irp: %p\n", Irp) );
  557. //
  558. // If the controller is in use (acquired) then we will not allow
  559. // the device to be removed.
  560. //
  561. KeWaitForSingleObject( &fdoExtension->TapeEnumerationEvent,
  562. Executive,
  563. KernelMode,
  564. FALSE,
  565. NULL );
  566. if ( fdoExtension->ControllerInUse ||
  567. fdoExtension->TapeEnumerationPending ) {
  568. ntStatus = STATUS_DEVICE_BUSY;
  569. Irp->IoStatus.Status = ntStatus;
  570. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  571. } else {
  572. //
  573. // If the controller was not in use we will set it so now
  574. // so that any other attempted accesses to the fdc will have
  575. fdoExtension->ControllerInUse = TRUE;
  576. IoSkipCurrentIrpStackLocation( Irp );
  577. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  578. }
  579. break;
  580. case IRP_MN_REMOVE_DEVICE:
  581. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_REMOVE_DEVICE - Irp: %p\n", Irp) );
  582. IoSkipCurrentIrpStackLocation( Irp );
  583. IoCallDriver( fdoExtension->TargetObject, Irp );
  584. if ( fdoExtension->FdcEnablerFileObject != NULL ) {
  585. ObDereferenceObject( fdoExtension->FdcEnablerFileObject );
  586. }
  587. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_REMOVE_DEVICE - Detach from device %p\n", fdoExtension->TargetObject) );
  588. IoDetachDevice( fdoExtension->TargetObject );
  589. //
  590. // Close the named synchronization event we opened at start time.
  591. //
  592. ZwClose( fdoExtension->AcquireEventHandle );
  593. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_REMOVE_DEVICE - Delete device %p\n", fdoExtension->Self) );
  594. IoDeleteDevice( fdoExtension->Self );
  595. ntStatus = STATUS_SUCCESS;
  596. break;
  597. case IRP_MN_CANCEL_REMOVE_DEVICE:
  598. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_CANCEL_REMOVE_DEVICE - Irp: %p\n", Irp) );
  599. fdoExtension->ControllerInUse = FALSE;
  600. IoSkipCurrentIrpStackLocation( Irp );
  601. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  602. break;
  603. case IRP_MN_QUERY_STOP_DEVICE:
  604. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_QUERY_STOP_DEVICE - Irp: %p\n", Irp) );
  605. if ( fdoExtension->ControllerInUse ||
  606. fdoExtension->TapeEnumerationPending ) {
  607. ntStatus = STATUS_DEVICE_BUSY;
  608. Irp->IoStatus.Status = ntStatus;
  609. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  610. } else {
  611. fdoExtension->ControllerInUse = TRUE;
  612. IoSkipCurrentIrpStackLocation( Irp );
  613. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  614. }
  615. break;
  616. case IRP_MN_STOP_DEVICE:
  617. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_STOP_DEVICE - Irp: %p\n", Irp) );
  618. IoSkipCurrentIrpStackLocation( Irp );
  619. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  620. break;
  621. case IRP_MN_CANCEL_STOP_DEVICE:
  622. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_CANCEL_STOP_DEVICE - Irp: %p\n", Irp) );
  623. fdoExtension->ControllerInUse = FALSE;
  624. IoSkipCurrentIrpStackLocation( Irp );
  625. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  626. break;
  627. case IRP_MN_QUERY_DEVICE_RELATIONS:
  628. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_QUERY_DEVICE_RELATIONS - Irp: %p\n", Irp) );
  629. ntStatus = FdcQueryDeviceRelations( DeviceObject, Irp );
  630. break;
  631. default:
  632. FdcDump( FDCSHOW, ("FdcFdoPnp: Unsupported PNP Request %x\n",irpSp->MinorFunction) );
  633. IoSkipCurrentIrpStackLocation( Irp );
  634. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  635. break;
  636. }
  637. if ( InterlockedDecrement( &fdoExtension->OutstandingRequests ) == 0 ) {
  638. KeSetEvent( &fdoExtension->RemoveEvent, 0, FALSE );
  639. }
  640. return ntStatus;
  641. }
  642. NTSTATUS
  643. FdcPnpComplete (
  644. IN PDEVICE_OBJECT DeviceObject,
  645. IN PIRP Irp,
  646. IN PVOID Context
  647. )
  648. /*++
  649. Routine Description:
  650. A completion routine for use when calling the lower device objects to
  651. which our bus (FDO) is attached. We use this completion routine when
  652. we must post-process the irp after we are sure that the PDO is done
  653. with it.
  654. Arguments:
  655. DeviceObject - a pointer to our FDO
  656. Irp - a pointer to the completed Irp
  657. Context - an event that we will set indicating the irp is completed.
  658. Return Value:
  659. STATUS_MORE_PROCESSING_REQUIRED so that control will be returned to
  660. our calling routine.
  661. --*/
  662. {
  663. if ( Irp->PendingReturned ) {
  664. IoMarkIrpPending( Irp );
  665. }
  666. KeSetEvent( (PKEVENT)Context, 1, FALSE );
  667. return STATUS_MORE_PROCESSING_REQUIRED;
  668. }
  669. NTSTATUS
  670. FdcPdoPnp(
  671. IN PDEVICE_OBJECT DeviceObject,
  672. IN PIRP Irp
  673. )
  674. /*++
  675. Routine Description:
  676. This routine is called by the I/O system to perform Plug-and-Play
  677. functions. This routine handles messages to the PDO which is part
  678. of the bus DevNode.
  679. Arguments:
  680. DeviceObject - a pointer to the object that represents the device
  681. that I/O is to be done on.
  682. Irp - a pointer to the I/O Request Packet for this request.
  683. Return Value:
  684. --*/
  685. {
  686. PFDC_PDO_EXTENSION pdoExtension;
  687. NTSTATUS ntStatus;
  688. PIO_STACK_LOCATION irpSp;
  689. KEVENT doneEvent;
  690. pdoExtension = DeviceObject->DeviceExtension;
  691. irpSp = IoGetCurrentIrpStackLocation( Irp );
  692. ntStatus = Irp->IoStatus.Status;
  693. switch ( irpSp->MinorFunction ) {
  694. case IRP_MN_QUERY_CAPABILITIES: {
  695. PDEVICE_CAPABILITIES deviceCapabilities;
  696. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_QUERY_CAPABILITIES - Irp: %p\n", Irp) );
  697. deviceCapabilities = irpSp->Parameters.DeviceCapabilities.Capabilities;
  698. //
  699. // Fill in the device capabilities structure and return it. The
  700. // capabilities structure is in irpSp->Parameters.DeviceCapabilities.Capabilities;
  701. //
  702. // The size and Version should already be set appropraitely.
  703. //
  704. ASSERT( deviceCapabilities->Version == 1 );
  705. ASSERT( deviceCapabilities->Size == sizeof(DEVICE_CAPABILITIES) );
  706. //
  707. // JB:TBD - not sure how to set these flags.
  708. //
  709. deviceCapabilities->LockSupported = FALSE; // No locking.
  710. deviceCapabilities->EjectSupported = FALSE; // No ejection mechanism.
  711. deviceCapabilities->Removable = FALSE; // Device is not removable (what about external laptop drives?)
  712. deviceCapabilities->DockDevice = FALSE; // Device is not a docking device (this probably should be TRUE)
  713. deviceCapabilities->UniqueID = FALSE; // ???
  714. deviceCapabilities->SilentInstall = TRUE; // ???
  715. deviceCapabilities->RawDeviceOK = FALSE; // ???
  716. // deviceCapabilities->Address;
  717. // deviceCapabilities->UINumber;
  718. //
  719. // deviceCapabilities->DeviceState[PowerSystemMaximum];
  720. // deviceCapabilities->SystemWake;
  721. // deviceCapabilities->DeviceWake;
  722. //
  723. // deviceCapabilities->D1Latency;
  724. // deviceCapabilities->D2Latency;
  725. // deviceCapabilities->D3Latency;
  726. ntStatus = STATUS_SUCCESS;
  727. break;
  728. }
  729. case IRP_MN_QUERY_ID:
  730. //
  731. // Query the IDs of the device
  732. //
  733. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_QUERY_ID - Irp: %p\n", Irp) );
  734. FdcDump( FDCSHOW, ("FdcPdoPnp: IdType %x\n", irpSp->Parameters.QueryId.IdType) );
  735. ntStatus = STATUS_SUCCESS;
  736. switch ( irpSp->Parameters.QueryId.IdType) {
  737. case BusQueryDeviceID:
  738. // return a WCHAR (null terminated) string describing the device
  739. // For symplicity we make it exactly the same as the Hardware ID.
  740. case BusQueryHardwareIDs: {
  741. UCHAR idString[25];
  742. ANSI_STRING ansiId;
  743. UNICODE_STRING uniId;
  744. PWCHAR buffer;
  745. ULONG length;
  746. RtlZeroMemory( idString, 25 );
  747. switch ( pdoExtension->DeviceType ) {
  748. case FloppyDiskDevice:
  749. // return a multi WCHAR (null terminated) string (null terminated)
  750. // array for use in matching hardare ids in inf files;
  751. //
  752. sprintf( idString, "FDC\\PNP07%02X", pdoExtension->Instance );
  753. break;
  754. case FloppyTapeDevice:
  755. //
  756. // Examine the tape vendor id and build the id string
  757. // appropriately.
  758. //
  759. if ( pdoExtension->TapeVendorId == -1 ) {
  760. strcpy( idString, "FDC\\QICLEGACY" );
  761. } else {
  762. sprintf( idString, "FDC\\QIC%04X", (USHORT)pdoExtension->TapeVendorId );
  763. }
  764. break;
  765. case FloppyControllerDevice:
  766. sprintf( idString, "FDC\\ENABLER" );
  767. break;
  768. }
  769. //
  770. // Allocate enough memory for the string and 2 null characters since
  771. // this is a multisz type.
  772. //
  773. length = strlen( idString ) * sizeof (WCHAR) + 2 * sizeof(WCHAR);
  774. buffer = ExAllocatePool (PagedPool, length);
  775. if ( buffer == NULL ) {
  776. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  777. break;
  778. }
  779. RtlZeroMemory( buffer, length );
  780. ansiId.Length = ansiId.MaximumLength = (USHORT) strlen( idString );
  781. ansiId.Buffer = idString;
  782. uniId.Length = 0;
  783. uniId.MaximumLength = (USHORT)length;
  784. uniId.Buffer = buffer;
  785. RtlAnsiStringToUnicodeString( &uniId, &ansiId, FALSE );
  786. Irp->IoStatus.Information = (UINT_PTR) buffer;
  787. break;
  788. }
  789. case BusQueryCompatibleIDs:{
  790. PWCHAR buffer = NULL;
  791. USHORT length;
  792. //
  793. // Build an instance ID. This is what PnP uses to tell if it has
  794. // seen this thing before or not. Build it from the first hardware
  795. // id and the port number.
  796. //
  797. switch ( pdoExtension->DeviceType ) {
  798. case FloppyDiskDevice:
  799. length = FDC_FLOPPY_COMPATIBLE_IDS_LENGTH * sizeof (WCHAR);
  800. buffer = ExAllocatePool( PagedPool, length );
  801. if ( buffer == NULL ) {
  802. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  803. } else {
  804. RtlCopyMemory( buffer, FDC_FLOPPY_COMPATIBLE_IDS, length );
  805. buffer[7] = L'0' + pdoExtension->Instance;
  806. }
  807. break;
  808. case FloppyTapeDevice:
  809. if ( pdoExtension->TapeVendorId != -1 ) {
  810. length = FDC_TAPE_COMPATIBLE_IDS_LENGTH * sizeof (WCHAR);
  811. buffer = ExAllocatePool( PagedPool, length );
  812. if ( buffer == NULL ) {
  813. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  814. } else {
  815. RtlCopyMemory( buffer, FDC_TAPE_COMPATIBLE_IDS, length );
  816. }
  817. }
  818. break;
  819. case FloppyControllerDevice:
  820. length = FDC_CONTROLLER_COMPATIBLE_IDS_LENGTH * sizeof (WCHAR);
  821. buffer = ExAllocatePool( PagedPool, length );
  822. if ( buffer == NULL ) {
  823. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  824. } else {
  825. RtlCopyMemory( buffer, FDC_CONTROLLER_COMPATIBLE_IDS, length );
  826. }
  827. break;
  828. }
  829. Irp->IoStatus.Information = (UINT_PTR)buffer;
  830. break;
  831. }
  832. case BusQueryInstanceID: {
  833. PWCHAR idString = L"0";
  834. PWCHAR buffer;
  835. //
  836. // Build an instance ID. This is what PnP uses to tell if it has
  837. // seen this thing before or not. Build it from the first hardware
  838. // id and the port number.
  839. buffer = ExAllocatePool( NonPagedPool, 4 );
  840. if ( buffer == NULL ) {
  841. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  842. } else {
  843. buffer[0] = L'0' + pdoExtension->Instance;
  844. buffer[1] = 0;
  845. Irp->IoStatus.Information = (UINT_PTR)buffer;
  846. }
  847. break;
  848. }
  849. }
  850. break;
  851. case IRP_MN_START_DEVICE:
  852. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_START_DEVICE - Irp: %p\n", Irp) );
  853. ntStatus = STATUS_SUCCESS;
  854. break;
  855. case IRP_MN_QUERY_STOP_DEVICE:
  856. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_QUERY_STOP_DEVICE - Irp: %p\n", Irp) );
  857. ntStatus = STATUS_SUCCESS;
  858. break;
  859. case IRP_MN_STOP_DEVICE:
  860. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_STOP_DEVICE - Irp: %p\n", Irp) );
  861. ntStatus = STATUS_SUCCESS;
  862. break;
  863. case IRP_MN_CANCEL_STOP_DEVICE:
  864. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_CANCEL_STOP_DEVICE - Irp: %p\n", Irp) );
  865. ntStatus = STATUS_SUCCESS;
  866. break;
  867. case IRP_MN_QUERY_REMOVE_DEVICE:
  868. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_QUERY_REMOVE_DEVICE - Irp: %p\n", Irp) );
  869. ntStatus = STATUS_DEVICE_BUSY;
  870. break;
  871. case IRP_MN_REMOVE_DEVICE:
  872. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_REMOVE_DEVICE - Irp: %p\n", Irp) );
  873. pdoExtension->Removed = TRUE;
  874. IoDeleteDevice( DeviceObject );
  875. ntStatus = STATUS_SUCCESS;
  876. break;
  877. case IRP_MN_CANCEL_REMOVE_DEVICE:
  878. FdcDump( FDCSHOW, ("FdcPdoPnp: IRP_MN_CANCEL_REMOVE_DEVICE - Irp: %p\n", Irp) );
  879. ntStatus = STATUS_SUCCESS;
  880. break;
  881. default:
  882. FdcDump( FDCSHOW, ("FdcPdoPnp: Unsupported PNP Request %x\n",irpSp->MinorFunction) );
  883. // this is a leaf node
  884. // status = STATUS_NOT_IMPLEMENTED
  885. // For PnP requests to the PDO that we do not understand we should
  886. // return the IRP WITHOUT setting the status or information fields.
  887. // They may have already been set by a filter (eg acpi).
  888. break;
  889. }
  890. Irp->IoStatus.Status = ntStatus;
  891. FdcDump( FDCSHOW, ("FdcPdoPnp: Return Status - %08x\n", ntStatus) );
  892. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  893. return ntStatus;
  894. }
  895. NTSTATUS
  896. FdcPower(
  897. IN PDEVICE_OBJECT DeviceObject,
  898. IN PIRP Irp
  899. )
  900. /*++
  901. Routine Description:
  902. This routine is called by the I/O system to perform Power functions
  903. Arguments:
  904. DeviceObject - a pointer to the object that represents the device.
  905. Irp - a pointer to the I/O Request Packet for this request.
  906. Return Value:
  907. --*/
  908. {
  909. PFDC_FDO_EXTENSION fdoExtension;
  910. NTSTATUS ntStatus = STATUS_SUCCESS;
  911. PIO_STACK_LOCATION irpSp;
  912. KIRQL oldIrql;
  913. KEVENT doneEvent;
  914. fdoExtension = DeviceObject->DeviceExtension;
  915. irpSp = IoGetCurrentIrpStackLocation( Irp );
  916. FdcDump( FDCSHOW, ("FdcPower:\n"));
  917. if ( fdoExtension->IsFDO ) {
  918. if ( fdoExtension->Removed ) {
  919. ntStatus = STATUS_DELETE_PENDING;
  920. PoStartNextPowerIrp( Irp );
  921. Irp->IoStatus.Information = 0;
  922. Irp->IoStatus.Status = ntStatus;
  923. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  924. } else {
  925. switch ( irpSp->MinorFunction ) {
  926. case IRP_MN_WAIT_WAKE:
  927. case IRP_MN_POWER_SEQUENCE:
  928. case IRP_MN_QUERY_POWER:
  929. //
  930. // Just forward this irp to the underlying device.
  931. //
  932. PoStartNextPowerIrp( Irp );
  933. IoSkipCurrentIrpStackLocation( Irp );
  934. ntStatus = PoCallDriver(fdoExtension->TargetObject, Irp );
  935. break;
  936. case IRP_MN_SET_POWER:
  937. //
  938. // Lock down the driver code in memory if it is not already.
  939. //
  940. FDC_PAGE_RESET_DRIVER_WITH_MUTEX;
  941. if ( irpSp->Parameters.Power.Type == SystemPowerState ) {
  942. //
  943. // If we are transitioning to a 'sleep' state start queueing
  944. // irps.
  945. //
  946. if ( fdoExtension->CurrentPowerState <= PowerSystemWorking &&
  947. irpSp->Parameters.Power.State.SystemState > PowerSystemWorking ) {
  948. //
  949. // If the device queue is not empty, wait for it now.
  950. //
  951. fdoExtension->CurrentPowerState = irpSp->Parameters.Power.State.SystemState;
  952. // KeWaitForSingleObject( &fdoExtension->RemoveEvent,
  953. // Executive,
  954. // KernelMode,
  955. // FALSE,
  956. // NULL );
  957. //
  958. // Make sure that the motors are turned off
  959. //
  960. if (!IsNEC_98) {
  961. WRITE_CONTROLLER(
  962. fdoExtension->ControllerAddress.DriveControl,
  963. (UCHAR)(fdoExtension->DriveControlImage & ~DRVCTL_MOTOR_MASK) );
  964. } // (!IsNEC_98)
  965. //
  966. // Now forward this irp to the underlying PDO.
  967. //
  968. PoStartNextPowerIrp( Irp );
  969. IoSkipCurrentIrpStackLocation( Irp );
  970. ntStatus = PoCallDriver(fdoExtension->TargetObject, Irp );
  971. //
  972. // Otherwise, if we are transitioning from a non-working state
  973. // back to a working state turn the motor back on if it was on.
  974. //
  975. } else if ( fdoExtension->CurrentPowerState > PowerSystemWorking &&
  976. irpSp->Parameters.Power.State.SystemState <= PowerSystemWorking ) {
  977. //
  978. // Pass this irp down to the PDO before proceeding.
  979. //
  980. KeInitializeEvent( &doneEvent, NotificationEvent, FALSE );
  981. IoCopyCurrentIrpStackLocationToNext(Irp);
  982. IoSetCompletionRoutine( Irp,
  983. FdcPnpComplete,
  984. &doneEvent,
  985. TRUE,
  986. TRUE,
  987. TRUE );
  988. ntStatus = PoCallDriver( fdoExtension->TargetObject, Irp );
  989. if ( ntStatus == STATUS_PENDING ) {
  990. KeWaitForSingleObject( &doneEvent, Executive, KernelMode, FALSE, NULL );
  991. }
  992. if ( fdoExtension->DriveControlImage & DRVCTL_MOTOR_MASK ) {
  993. WRITE_CONTROLLER(
  994. fdoExtension->ControllerAddress.DriveControl,
  995. fdoExtension->DriveControlImage );
  996. if ( fdoExtension->LastMotorSettleTime.QuadPart > 0) {
  997. KeDelayExecutionThread( KernelMode,
  998. FALSE,
  999. &fdoExtension->LastMotorSettleTime );
  1000. }
  1001. }
  1002. fdoExtension->CurrentPowerState = irpSp->Parameters.Power.State.SystemState;
  1003. //
  1004. // Set a flag to simulate a disk change event so that
  1005. // we will be sure to touch the floppy drive hardware
  1006. // the next time it is accessed in case it was removed.
  1007. //
  1008. fdoExtension->WakeUp = TRUE;
  1009. PoStartNextPowerIrp( Irp );
  1010. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1011. } else {
  1012. //
  1013. // We must just be changing non-working states. We
  1014. // ignore this activity but pass the irp on to the
  1015. // underlying device.
  1016. //
  1017. PoStartNextPowerIrp( Irp );
  1018. IoSkipCurrentIrpStackLocation( Irp );
  1019. ntStatus = PoCallDriver(fdoExtension->TargetObject, Irp );
  1020. }
  1021. } else {
  1022. //
  1023. // We only handle system power states so if this is a
  1024. // device state irp just forward it to the underlying
  1025. // device.
  1026. //
  1027. PoStartNextPowerIrp( Irp );
  1028. IoSkipCurrentIrpStackLocation( Irp );
  1029. ntStatus = PoCallDriver(fdoExtension->TargetObject, Irp );
  1030. }
  1031. //
  1032. // Page out the driver if it is not busy elsewhere.
  1033. //
  1034. FDC_PAGE_ENTIRE_DRIVER_WITH_MUTEX;
  1035. break;
  1036. }
  1037. }
  1038. } else {
  1039. //
  1040. // We are not yet doing any power management on the floppy controller.
  1041. //
  1042. switch (irpSp->MinorFunction) {
  1043. case IRP_MN_WAIT_WAKE:
  1044. break;
  1045. case IRP_MN_POWER_SEQUENCE:
  1046. break;
  1047. case IRP_MN_SET_POWER:
  1048. break;
  1049. case IRP_MN_QUERY_POWER:
  1050. break;
  1051. }
  1052. PoStartNextPowerIrp( Irp );
  1053. Irp->IoStatus.Status = ntStatus;
  1054. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1055. }
  1056. return ntStatus;
  1057. }
  1058. NTSTATUS
  1059. FdcStartDevice(
  1060. IN PDEVICE_OBJECT DeviceObject,
  1061. IN PIRP Irp
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine attempts to start the floppy controller device. Starting
  1066. the floppy controller consists primarily of resetting it and configuring
  1067. it, mostly just to make sure that it is there.
  1068. Arguments:
  1069. DeviceObject - a pointer to the device object being started.
  1070. Irp - a pointer to the start device Irp.
  1071. Return Value:
  1072. --*/
  1073. {
  1074. NTSTATUS ntStatus = STATUS_SUCCESS;
  1075. PFDC_FDO_EXTENSION fdoExtension;
  1076. PIO_STACK_LOCATION irpSp;
  1077. BOOLEAN foundPortA = FALSE;
  1078. BOOLEAN foundPortB = FALSE;
  1079. BOOLEAN foundDma = FALSE;
  1080. BOOLEAN foundInterrupt = FALSE;
  1081. ULONG currentBase = 0xFFFFFFFF;
  1082. PCM_RESOURCE_LIST translatedResources;
  1083. PCM_FULL_RESOURCE_DESCRIPTOR fullList;
  1084. PCM_PARTIAL_RESOURCE_LIST partialList;
  1085. PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
  1086. ULONG i;
  1087. ULONG startOffset;
  1088. ULONG currentOffset;
  1089. UCHAR ioPortMap;
  1090. #ifdef TOSHIBAJ
  1091. BOOLEAN foundConfigIndex = FALSE;
  1092. BOOLEAN foundConfigData = FALSE;
  1093. #endif
  1094. fdoExtension = DeviceObject->DeviceExtension;
  1095. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1096. //
  1097. // Ask the PDO if it is a tape enabler device and, if so, what
  1098. // is the enabler device object.
  1099. //
  1100. FdcGetEnablerDevice( fdoExtension );
  1101. if ( fdoExtension->FdcEnablerSupported ) {
  1102. INTERFACE_TYPE InterfaceType;
  1103. //
  1104. // This is a tape enabler card so we need to get the resources
  1105. // 'the old-fashinoed way'.
  1106. //
  1107. for ( InterfaceType = 0;
  1108. InterfaceType < MaximumInterfaceType;
  1109. InterfaceType++ ) {
  1110. CONFIGURATION_TYPE Dc = DiskController;
  1111. ntStatus = IoQueryDeviceDescription( &InterfaceType,
  1112. NULL,
  1113. &Dc,
  1114. NULL,
  1115. NULL,
  1116. NULL,
  1117. FdcFdoConfigCallBack,
  1118. fdoExtension );
  1119. if (!NT_SUCCESS(ntStatus) && (ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)) {
  1120. return ntStatus;
  1121. }
  1122. }
  1123. if ( fdoExtension->FdcEnablerDeviceObject == NULL ) {
  1124. ntStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  1125. } else {
  1126. ntStatus = STATUS_SUCCESS;
  1127. }
  1128. } else {
  1129. //
  1130. // Now that the PDO is done with the Irp we can have our way with
  1131. // it.
  1132. //
  1133. FdcDump( FDCSHOW, ("AllocatedResources = %08x\n",irpSp->Parameters.StartDevice.AllocatedResources));
  1134. FdcDump( FDCSHOW, ("AllocatedResourcesTranslated = %08x\n",irpSp->Parameters.StartDevice.AllocatedResourcesTranslated));
  1135. if ( irpSp->Parameters.StartDevice.AllocatedResources == NULL ||
  1136. irpSp->Parameters.StartDevice.AllocatedResourcesTranslated == NULL ) {
  1137. return STATUS_INSUFFICIENT_RESOURCES;
  1138. }
  1139. //
  1140. // Set up the resource information that we will use to access the
  1141. // controller hardware. We always expect only 1 full set of resources.
  1142. // In that list we expect a DMA channel, an Interrupt vector, and 2 I/O Port
  1143. // ranges. If we don't see all the required resources we will woof.
  1144. //
  1145. translatedResources = irpSp->Parameters.StartDevice.AllocatedResourcesTranslated;
  1146. ASSERT( translatedResources->Count == 1 );
  1147. fullList = &translatedResources->List[0];
  1148. partialList = &translatedResources->List[0].PartialResourceList;
  1149. //
  1150. // Enumerate the list of resources, adding them into our context as we go.
  1151. //
  1152. RtlZeroMemory( &fdoExtension->ControllerAddress, sizeof(CONTROLLER) );
  1153. for ( i = 0; i < partialList->Count; i++ ) {
  1154. partial = &partialList->PartialDescriptors[i];
  1155. switch ( partial->Type ) {
  1156. case CmResourceTypePort: {
  1157. if (IsNEC_98) {
  1158. if ( partial->u.Port.Length == 1 ) {
  1159. if (!fdoExtension->ControllerAddress.Status) {
  1160. fdoExtension->ControllerAddress.Status
  1161. = (PUCHAR)partial->u.Port.Start.LowPart;
  1162. } else if (!fdoExtension->ControllerAddress.Fifo) {
  1163. fdoExtension->ControllerAddress.Fifo
  1164. = (PUCHAR)partial->u.Port.Start.LowPart;
  1165. } else if (!fdoExtension->ControllerAddress.DriveControl) {
  1166. fdoExtension->ControllerAddress.DriveControl
  1167. = (PUCHAR)partial->u.Port.Start.LowPart;
  1168. } else if (!fdoExtension->ControllerAddress.ModeChange) {
  1169. fdoExtension->ControllerAddress.ModeChange
  1170. = (PUCHAR)partial->u.Port.Start.LowPart;
  1171. } else if (!fdoExtension->ControllerAddress.ModeChangeEx) {
  1172. fdoExtension->ControllerAddress.ModeChangeEx
  1173. = (PUCHAR)partial->u.Port.Start.LowPart;
  1174. }
  1175. }
  1176. break;
  1177. }
  1178. //
  1179. // If we get a base address that is lower than anything we have seen
  1180. // before, we assume that we have been working with aliased addresses
  1181. // and start over with the new base address.
  1182. //
  1183. if ( (partial->u.Port.Start.LowPart & 0xFFFFFFF8) < currentBase ) {
  1184. #ifdef TOSHIBAJ
  1185. // Skip the descriptor including config ports only.
  1186. if ( !TranslatedConfigBase
  1187. || ((partial->u.Port.Start.LowPart & 0xFFFFFFF8) != (ULONG)TranslatedConfigBase)
  1188. || ((partial->u.Port.Start.LowPart & 0x7) + partial->u.Port.Length > 2) ) {
  1189. RtlZeroMemory( &fdoExtension->ControllerAddress, sizeof(CONTROLLER) );
  1190. currentBase = partial->u.Port.Start.LowPart & 0xFFFFFFF8;
  1191. FdcDump( FDCINFO,
  1192. ("FdcStartDevice: Current base %04x\n", currentBase) );
  1193. }
  1194. #else
  1195. RtlZeroMemory( &fdoExtension->ControllerAddress, sizeof(CONTROLLER) );
  1196. currentBase = partial->u.Port.Start.LowPart & 0xFFFFFFF8;
  1197. #endif
  1198. }
  1199. //
  1200. // We only use resources that are associated with the current (lowest)
  1201. // base addressed. All others are assumed to be aliased and are not
  1202. // used.
  1203. //
  1204. if ( (partial->u.Port.Start.LowPart & 0xFFFFFFF8) == currentBase ) {
  1205. FdcDump( FDCINFO,
  1206. ("FdcStartDevice: Adding - %04x, Length - %04x\n",
  1207. partial->u.Port.Start.LowPart,
  1208. partial->u.Port.Length) );
  1209. startOffset = partial->u.Port.Start.LowPart & 0x07;
  1210. if ( (partial->Flags & CM_RESOURCE_PORT_IO) == CM_RESOURCE_PORT_MEMORY ) {
  1211. fdoExtension->ControllerAddress.Address[startOffset] =
  1212. MmMapIoSpace( partial->u.Port.Start,
  1213. partial->u.Port.Length,
  1214. FALSE );
  1215. FdcDump( FDCINFO, ("FdcStartDevice: Mapped IoPort\n") );
  1216. } else {
  1217. fdoExtension->ControllerAddress.Address[startOffset] = (PUCHAR)partial->u.Port.Start.LowPart;
  1218. }
  1219. currentOffset = 1;
  1220. while ( currentOffset < partial->u.Port.Length ) {
  1221. fdoExtension->ControllerAddress.Address[startOffset + currentOffset] =
  1222. fdoExtension->ControllerAddress.Address[startOffset] + currentOffset;
  1223. ++currentOffset;
  1224. }
  1225. }
  1226. #ifdef TOSHIBAJ
  1227. // Are there configuration ports in a descriptor ?
  1228. if ( TranslatedConfigBase
  1229. && (partial->u.Port.Start.LowPart <= (ULONG)TranslatedConfigBase)
  1230. && (partial->u.Port.Start.LowPart + partial->u.Port.Length > (ULONG)TranslatedConfigBase) ) {
  1231. foundConfigIndex = TRUE;
  1232. FdcDump( FDCINFO,
  1233. ("FdcStartDevice: Configration index port in %04x (length %04x)\n",
  1234. partial->u.Port.Start.LowPart,
  1235. partial->u.Port.Length) );
  1236. }
  1237. if ( TranslatedConfigBase
  1238. && (partial->u.Port.Start.LowPart <= (ULONG)TranslatedConfigBase + 1)
  1239. && (partial->u.Port.Start.LowPart + partial->u.Port.Length > (ULONG)TranslatedConfigBase + 1) ) {
  1240. foundConfigData = TRUE;
  1241. FdcDump( FDCINFO,
  1242. ("FdcStartDevice: Configration data port in %04x (length %04x)\n",
  1243. partial->u.Port.Start.LowPart,
  1244. partial->u.Port.Length) );
  1245. }
  1246. if (foundConfigIndex && foundConfigData) {
  1247. fdoExtension->ConfigBase = (PUCHAR)SmcConfigBase;
  1248. fdoExtension->Available3Mode = TRUE;
  1249. }
  1250. #endif
  1251. break;
  1252. }
  1253. case CmResourceTypeDma: {
  1254. DEVICE_DESCRIPTION deviceDesc = {0};
  1255. FdcDump( FDCINFO, ("FdcStartDevice: DMA - %04x\n", partial->u.Dma.Channel) );
  1256. foundDma = TRUE;
  1257. deviceDesc.Version = DEVICE_DESCRIPTION_VERSION1;
  1258. if ( partial->u.Dma.Channel > 3 ) {
  1259. deviceDesc.DmaWidth = Width16Bits;
  1260. } else {
  1261. deviceDesc.DmaWidth = Width8Bits;
  1262. }
  1263. deviceDesc.DemandMode = TRUE;
  1264. deviceDesc.MaximumLength = MAX_BYTES_PER_SECTOR * MAX_SECTORS_PER_TRACK;
  1265. deviceDesc.IgnoreCount = TRUE;
  1266. //
  1267. // Always ask for one more page than maximum transfer size.
  1268. //
  1269. deviceDesc.MaximumLength += PAGE_SIZE;
  1270. deviceDesc.DmaChannel = partial->u.Dma.Channel;
  1271. deviceDesc.InterfaceType = fullList->InterfaceType;
  1272. deviceDesc.DmaSpeed = DEFAULT_DMA_SPEED;
  1273. deviceDesc.AutoInitialize = FALSE;
  1274. fdoExtension->AdapterObject =
  1275. HalGetAdapter( &deviceDesc,
  1276. &fdoExtension->NumberOfMapRegisters );
  1277. if (!fdoExtension->AdapterObject) {
  1278. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1279. }
  1280. //
  1281. // Here we can get another adapter object for formatting. It
  1282. // should look the same as the previous one except AutoInitialize
  1283. // will be true.
  1284. //
  1285. break;
  1286. }
  1287. case CmResourceTypeInterrupt: {
  1288. FdcDump( FDCINFO, ("FdcStartDevice: IRQ - %04x\n", partial->u.Interrupt.Vector) );
  1289. foundInterrupt = TRUE;
  1290. if ( partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
  1291. fdoExtension->InterruptMode = Latched;
  1292. } else {
  1293. fdoExtension->InterruptMode = LevelSensitive;
  1294. }
  1295. if (IsNEC_98) {
  1296. //
  1297. // NOTENOTE: Invalid Interrupt Level and Vector.
  1298. //
  1299. partial->u.Interrupt.Level = 0x0b;
  1300. partial->u.Interrupt.Vector = 0x13;
  1301. //
  1302. // We get the Vector with HalGetInterruptVector().
  1303. //
  1304. fdoExtension->ControllerVector =
  1305. HalGetInterruptVector( fullList->InterfaceType,
  1306. fullList->BusNumber,
  1307. partial->u.Interrupt.Level,
  1308. partial->u.Interrupt.Vector,
  1309. &fdoExtension->ControllerIrql,
  1310. &fdoExtension->ProcessorMask );
  1311. FdcDump( FDCSHOW,
  1312. ("Resource Requirements - ControllerVector = 0x%x\n",
  1313. fdoExtension->ControllerVector) );
  1314. } else {
  1315. fdoExtension->ControllerVector = partial->u.Interrupt.Vector;
  1316. fdoExtension->ProcessorMask = partial->u.Interrupt.Affinity;
  1317. fdoExtension->ControllerIrql = (KIRQL)partial->u.Interrupt.Level;
  1318. }
  1319. fdoExtension->SharableVector = TRUE;
  1320. fdoExtension->SaveFloatState = FALSE;
  1321. break;
  1322. }
  1323. default:
  1324. break;
  1325. }
  1326. }
  1327. FdcDump( FDCINFO, ("FdcStartDevice: ControllerAddress.StatusA = %08x\n"
  1328. "FdcStartDevice: ControllerAddress.StatusB = %08x\n"
  1329. "FdcStartDevice: ControllerAddress.DriveControl = %08x\n"
  1330. "FdcStartDevice: ControllerAddress.Tape = %08x\n"
  1331. "FdcStartDevice: ControllerAddress.Status = %08x\n"
  1332. "FdcStartDevice: ControllerAddress.Fifo = %08x\n"
  1333. "FdcStartDevice: ControllerAddress.DRDC = %08x\n",
  1334. fdoExtension->ControllerAddress.StatusA,
  1335. fdoExtension->ControllerAddress.StatusB,
  1336. fdoExtension->ControllerAddress.DriveControl,
  1337. fdoExtension->ControllerAddress.Tape,
  1338. fdoExtension->ControllerAddress.Status,
  1339. fdoExtension->ControllerAddress.Fifo,
  1340. fdoExtension->ControllerAddress.DRDC) );
  1341. if (IsNEC_98) {
  1342. FdcDump( FDCINFO, ("FdcStartDevice: ControllerAddress.ModeChange = %08x\n"
  1343. "FdcStartDevice: ControllerAddress.ModeChangeEx = %08x\n",
  1344. fdoExtension->ControllerAddress.ModeChange,
  1345. fdoExtension->ControllerAddress.ModeChangeEx) );
  1346. }
  1347. if ( !foundDma ||
  1348. !foundInterrupt ||
  1349. fdoExtension->ControllerAddress.DriveControl == NULL ||
  1350. // fdoExtension->ControllerAddress.Tape == NULL ||
  1351. fdoExtension->ControllerAddress.Status == NULL ||
  1352. fdoExtension->ControllerAddress.Fifo == NULL ||
  1353. ((!IsNEC_98) ? (fdoExtension->ControllerAddress.DRDC.DataRate == NULL)
  1354. : ((fdoExtension->ControllerAddress.ModeChange == NULL) ||
  1355. (fdoExtension->ControllerAddress.ModeChangeEx == NULL)) )
  1356. ) {
  1357. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1358. }
  1359. if ( NT_SUCCESS(ntStatus) ) {
  1360. //
  1361. // Set up the bus information since we know it now.
  1362. //
  1363. fdoExtension->BusType = fullList->InterfaceType;
  1364. fdoExtension->BusNumber = fullList->BusNumber;
  1365. }
  1366. }
  1367. if ( NT_SUCCESS(ntStatus) ) {
  1368. ntStatus = FdcInitializeDeviceObject( DeviceObject );
  1369. //
  1370. // Connect the interrupt for the reset operation.
  1371. //
  1372. ntStatus = IoConnectInterrupt( &fdoExtension->InterruptObject,
  1373. FdcInterruptService,
  1374. fdoExtension,
  1375. NULL,
  1376. fdoExtension->ControllerVector,
  1377. fdoExtension->ControllerIrql,
  1378. fdoExtension->ControllerIrql,
  1379. fdoExtension->InterruptMode,
  1380. fdoExtension->SharableVector,
  1381. fdoExtension->ProcessorMask,
  1382. fdoExtension->SaveFloatState );
  1383. FdcDump( FDCINFO, ("FdcStartDevice: IoConnectInterrupt - %08x\n", ntStatus) );
  1384. fdoExtension->CurrentInterrupt = FALSE;
  1385. if ( NT_SUCCESS(ntStatus) ) {
  1386. //
  1387. // Initialize (Reset) the controller hardware. This will make
  1388. // sure that the controller is really there and leave it in an
  1389. // appropriate state for the rest of the system startup.
  1390. //
  1391. fdoExtension->AllowInterruptProcessing =
  1392. fdoExtension->CurrentInterrupt = TRUE;
  1393. //
  1394. // Acquire the Fdc Enabler card if there is one
  1395. //
  1396. if (fdoExtension->FdcEnablerSupported) {
  1397. LARGE_INTEGER acquireTimeOut;
  1398. acquireTimeOut.QuadPart = -(ONE_SECOND * 15);
  1399. ntStatus = FcFdcEnabler( fdoExtension->FdcEnablerDeviceObject,
  1400. // IOCTL_ACQUIRE_FDC, // For spelling miss in flpyenbl.h
  1401. IOCTL_AQUIRE_FDC,
  1402. &acquireTimeOut);
  1403. }
  1404. if ( NT_SUCCESS(ntStatus) ) {
  1405. ntStatus = FcInitializeControllerHardware( fdoExtension,
  1406. DeviceObject );
  1407. FdcDump( FDCINFO, ("FdcStartDevice: FcInitializeControllerHardware - %08x\n", ntStatus) );
  1408. //
  1409. // Free the tape accelerator card if it was used.
  1410. //
  1411. if (fdoExtension->FdcEnablerSupported) {
  1412. FcFdcEnabler( fdoExtension->FdcEnablerDeviceObject,
  1413. IOCTL_RELEASE_FDC,
  1414. NULL);
  1415. }
  1416. fdoExtension->CurrentInterrupt = FALSE;
  1417. }
  1418. if ( NT_SUCCESS( ntStatus ) ) {
  1419. fdoExtension->HardwareFailed = FALSE;
  1420. ntStatus = FcGetFdcInformation ( fdoExtension );
  1421. } else {
  1422. fdoExtension->HardwareFailed = TRUE;
  1423. }
  1424. if (IsNEC_98) {
  1425. //
  1426. // NEC98's FDD driver can't not disconnect interrupt,
  1427. // and can't not page out this driver. Because when a FD is inserted in FDD or
  1428. // is ejected from FDD, then H/W calls FDD driver's interrupt routine.
  1429. //
  1430. } else { // (IsNEC_98)
  1431. IoDisconnectInterrupt(fdoExtension->InterruptObject);
  1432. } // (IsNEC_98)
  1433. }
  1434. }
  1435. Irp->IoStatus.Information = 0;
  1436. return ntStatus;
  1437. }
  1438. NTSTATUS
  1439. FdcInitializeDeviceObject(
  1440. IN PDEVICE_OBJECT DeviceObject
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. This routine initializes the DeviceObject resources. DeviceObject resources
  1445. only need to be initialized once, regardless of how many times this device
  1446. is started.
  1447. Arguments:
  1448. DeviceObject - a pointer to the device object being started.
  1449. Return Value:
  1450. --*/
  1451. {
  1452. NTSTATUS ntStatus = STATUS_SUCCESS;
  1453. PFDC_FDO_EXTENSION fdoExtension;
  1454. UNICODE_STRING unicodeEvent;
  1455. USHORT motorControlData;
  1456. fdoExtension = DeviceObject->DeviceExtension;
  1457. if ( !fdoExtension->DeviceObjectInitialized ) {
  1458. //
  1459. // Set the time to wait for an interrupt before timing out to a
  1460. // few seconds.
  1461. //
  1462. fdoExtension->InterruptDelay.QuadPart = -(ONE_SECOND * 4);
  1463. //
  1464. // Set the minimum time that we can delay (10ms according to system
  1465. // rules). This will be used when we have to delay to, say, wait
  1466. // for the FIFO - the FIFO should become ready is well under 10ms.
  1467. //
  1468. fdoExtension->Minimum10msDelay.QuadPart = -(10 * 1000 * 10);
  1469. if (IsNEC_98) {
  1470. //
  1471. // Set initialize data to move state
  1472. //
  1473. fdoExtension->ResultStatus0[0] = 0xc0;
  1474. fdoExtension->ResultStatus0[1] = 0xc1;
  1475. fdoExtension->ResultStatus0[2] = 0xc2;
  1476. fdoExtension->ResultStatus0[3] = 0xc3;
  1477. //
  1478. // Reset high
  1479. //
  1480. READ_CONTROLLER(fdoExtension->ControllerAddress.DriveControl);
  1481. //
  1482. // Initialize motor running status.
  1483. // 0 - stop
  1484. // 1 - just run
  1485. // 2 - be running
  1486. //
  1487. fdoExtension->MotorRunning = 0;
  1488. //
  1489. // Get BIOS common area date.
  1490. //
  1491. {
  1492. ULONG nodeNumber;
  1493. CHAR AnsiBuffer[512];
  1494. ANSI_STRING AnsiString;
  1495. UNICODE_STRING registryPath;
  1496. ULONG Configuration;
  1497. RTL_QUERY_REGISTRY_TABLE paramTable[2];
  1498. PUCHAR ConfigurationData1;
  1499. ConfigurationData1 = ExAllocatePool(NonPagedPoolCacheAligned, 1192);
  1500. if (ConfigurationData1 == NULL) {
  1501. return STATUS_INSUFFICIENT_RESOURCES;
  1502. }
  1503. RtlZeroMemory(ConfigurationData1, 1192);
  1504. paramTable[0].QueryRoutine = NULL;
  1505. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1506. paramTable[0].Name = L"Configuration Data";
  1507. paramTable[0].EntryContext = ConfigurationData1;
  1508. paramTable[0].DefaultType = REG_DWORD;
  1509. paramTable[0].DefaultData = (PVOID)&Configuration;
  1510. paramTable[0].DefaultLength = 0;
  1511. paramTable[1].QueryRoutine = NULL;
  1512. paramTable[1].Flags = 0;
  1513. paramTable[1].Name = NULL;
  1514. paramTable[1].EntryContext = NULL;
  1515. paramTable[1].DefaultType = REG_NONE;
  1516. paramTable[1].DefaultData = NULL;
  1517. paramTable[1].DefaultLength = 0;
  1518. ((PULONG)ConfigurationData1)[0] = 1192;
  1519. nodeNumber = FdcFindIsaBusNode();
  1520. if ( nodeNumber != -1 ) {
  1521. //
  1522. // Build path buffer...
  1523. //
  1524. sprintf(AnsiBuffer,ISA_BUS_NODE,nodeNumber);
  1525. RtlInitAnsiString(&AnsiString,AnsiBuffer);
  1526. ntStatus = RtlAnsiStringToUnicodeString(&registryPath,&AnsiString,TRUE);
  1527. if (!(NT_SUCCESS(ntStatus))) {
  1528. ExFreePool(ConfigurationData1);
  1529. return ntStatus;
  1530. }
  1531. ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  1532. registryPath.Buffer,
  1533. paramTable,
  1534. NULL,
  1535. NULL);
  1536. RtlFreeUnicodeString(&registryPath);
  1537. }
  1538. if (!(NT_SUCCESS(ntStatus))) {
  1539. ExFreePool(ConfigurationData1);
  1540. return ntStatus;
  1541. }
  1542. //
  1543. // Set disk dirve existing bit.
  1544. //
  1545. fdoExtension->FloppyEquip = (UCHAR)(FdcGet0Seg(ConfigurationData1, 0x55c) & 0x0F);
  1546. //
  1547. // Reset high
  1548. //
  1549. READ_CONTROLLER(fdoExtension->ControllerAddress.DriveControl);
  1550. motorControlData = READ_CONTROLLER(fdoExtension->ControllerAddress.ModeChange);
  1551. motorControlData &= 0x03;
  1552. motorControlData |= 0x04;
  1553. //
  1554. // Motor control.
  1555. //
  1556. WRITE_CONTROLLER(fdoExtension->ControllerAddress.ModeChange, motorControlData);
  1557. ExFreePool(ConfigurationData1);
  1558. }
  1559. } // (IsNEC_98)
  1560. //
  1561. // Initialize the DPC structure in the device object, so that
  1562. // the ISR can queue DPCs.
  1563. //
  1564. IoInitializeDpcRequest( fdoExtension->Self, FdcDeferredProcedure );
  1565. //
  1566. // Occasionally during stress we've seen the device lock up.
  1567. // We create a dpc so that we can log that the device lock up
  1568. // occured and that we reset the device.
  1569. //
  1570. KeInitializeDpc( &fdoExtension->LogErrorDpc,
  1571. FcLogErrorDpc,
  1572. fdoExtension );
  1573. //
  1574. // Assume there is a CONFIGURE command until found otherwise.
  1575. // Other Booleans were zero-initialized to FALSE.
  1576. //
  1577. fdoExtension->ControllerConfigurable = NotConfigurable ? FALSE : TRUE;
  1578. fdoExtension->Model30 = Model30 ? TRUE : FALSE;
  1579. fdoExtension->AllowInterruptProcessing = TRUE;
  1580. fdoExtension->CurrentInterrupt = TRUE;
  1581. fdoExtension->ControllerInUse = FALSE;
  1582. fdoExtension->CurrentIrp = NULL;
  1583. //
  1584. // Start the timer
  1585. //
  1586. fdoExtension->InterruptTimer = CANCEL_TIMER;
  1587. IoInitializeTimer( DeviceObject, FdcCheckTimer, fdoExtension );
  1588. //
  1589. // Initialize events to signal interrupts and adapter object
  1590. // allocation
  1591. //
  1592. KeInitializeEvent( &fdoExtension->InterruptEvent,
  1593. SynchronizationEvent,
  1594. FALSE);
  1595. KeInitializeEvent( &fdoExtension->AllocateAdapterChannelEvent,
  1596. NotificationEvent,
  1597. FALSE );
  1598. fdoExtension->AdapterChannelRefCount = 0;
  1599. RtlInitUnicodeString( &unicodeEvent, L"\\Device\\FloppyControllerEvent0" );
  1600. fdoExtension->AcquireEvent = IoCreateSynchronizationEvent( &unicodeEvent,
  1601. &fdoExtension->AcquireEventHandle);
  1602. KeInitializeEvent( &fdoExtension->SynchEvent,
  1603. SynchronizationEvent,
  1604. FALSE);
  1605. }
  1606. fdoExtension->DeviceObjectInitialized = TRUE;
  1607. return ntStatus;
  1608. }
  1609. NTSTATUS
  1610. FdcFdoConfigCallBack(
  1611. IN PVOID Context,
  1612. IN PUNICODE_STRING PathName,
  1613. IN INTERFACE_TYPE BusType,
  1614. IN ULONG BusNumber,
  1615. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  1616. IN CONFIGURATION_TYPE ControllerType,
  1617. IN ULONG ControllerNumber,
  1618. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  1619. IN CONFIGURATION_TYPE PeripheralType,
  1620. IN ULONG PeripheralNumber,
  1621. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  1622. )
  1623. /*++
  1624. Routine Description:
  1625. This routine is used to acquire all of the configuration
  1626. information for a tape enabler if we ever find one.
  1627. Arguments:
  1628. Context - Pointer to our FDO extension
  1629. PathName - unicode registry path. Not Used.
  1630. BusType - Internal, Isa, ...
  1631. BusNumber - Which bus if we are on a multibus system.
  1632. BusInformation - Configuration information about the bus. Not Used.
  1633. ControllerType - Should always be DiskController.
  1634. ControllerNumber - Which controller if there is more than one
  1635. controller in the system.
  1636. ControllerInformation - Array of pointers to the three pieces of
  1637. registry information.
  1638. PeripheralType - Should always be FloppyDiskPeripheral.
  1639. PeripheralNumber - Which floppy if this controller is maintaining
  1640. more than one.
  1641. PeripheralInformation - Arrya of pointers to the three pieces of
  1642. registry information.
  1643. Return Value:
  1644. STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
  1645. if it couldn't map the base csr or acquire the adapter object, or
  1646. all of the resource information couldn't be acquired.
  1647. --*/
  1648. {
  1649. PFDC_FDO_EXTENSION fdoExtension = (PFDC_FDO_EXTENSION)Context;
  1650. NTSTATUS ntStatus;
  1651. UNICODE_STRING pdoName;
  1652. PDEVICE_OBJECT newPdo;
  1653. PFDC_PDO_EXTENSION pdoExtension;
  1654. RTL_QUERY_REGISTRY_TABLE paramTable[2];
  1655. ULONG apiSupported;
  1656. WCHAR idstr[200];
  1657. UNICODE_STRING str;
  1658. USHORT i;
  1659. BOOLEAN foundPort = FALSE;
  1660. BOOLEAN foundInterrupt = FALSE;
  1661. BOOLEAN foundDma = FALSE;
  1662. FdcDump( FDCSHOW, ("FdcFdoConfigCallBack:\n") );
  1663. //
  1664. // The first thing to do is to go out and look for an enabler. We
  1665. // know we are dealing with one if there is a registry value called
  1666. // APISupported.
  1667. //
  1668. str.Length = 0;
  1669. str.MaximumLength = 200;
  1670. str.Buffer = idstr;
  1671. RtlZeroMemory( &paramTable[0], sizeof(paramTable) );
  1672. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1673. paramTable[0].Name = L"APISupported";
  1674. paramTable[0].EntryContext = &str;
  1675. paramTable[0].DefaultType = REG_SZ;
  1676. paramTable[0].DefaultData = L"";
  1677. paramTable[0].DefaultLength = sizeof(WCHAR);
  1678. ntStatus = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  1679. PathName->Buffer,
  1680. &paramTable[0],
  1681. NULL,
  1682. NULL);
  1683. if ( !NT_SUCCESS( ntStatus ) ) {
  1684. str.Buffer[0] = 0;
  1685. }
  1686. if ( str.Buffer[0] != 0 ) {
  1687. FdcDump(FDCINFO,
  1688. ("FdcFdoConfigCallBack: Got registry setting for EnablerAPI = %ls\n",
  1689. (ULONG_PTR)str.Buffer) );
  1690. ntStatus = IoGetDeviceObjectPointer( &str,
  1691. FILE_READ_ACCESS,
  1692. &fdoExtension->FdcEnablerFileObject,
  1693. &fdoExtension->FdcEnablerDeviceObject);
  1694. }
  1695. if ( fdoExtension->FdcEnablerDeviceObject != NULL ) {
  1696. PCM_FULL_RESOURCE_DESCRIPTOR controllerData =
  1697. (PCM_FULL_RESOURCE_DESCRIPTOR)
  1698. (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
  1699. ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
  1700. //
  1701. // We have the pointer. Save off the interface type and
  1702. // the busnumber for use when we call the Hal and the
  1703. // Io System.
  1704. //
  1705. fdoExtension->BusType = BusType;
  1706. fdoExtension->BusNumber = BusNumber;
  1707. fdoExtension->SharableVector = TRUE;
  1708. fdoExtension->SaveFloatState = FALSE;
  1709. //
  1710. // We need to get the following information out of the partial
  1711. // resource descriptors.
  1712. //
  1713. // The irql and vector.
  1714. //
  1715. // The dma channel.
  1716. //
  1717. // The base address and span covered by the floppy controllers
  1718. // registers.
  1719. //
  1720. // It is not defined how these appear in the partial resource
  1721. // lists, so we will just loop over all of them. If we find
  1722. // something we don't recognize, we drop that information on
  1723. // the floor. When we have finished going through all the
  1724. // partial information, we validate that we got the above
  1725. // three.
  1726. //
  1727. for ( i = 0;
  1728. i < controllerData->PartialResourceList.Count;
  1729. i++ ) {
  1730. PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
  1731. &controllerData->PartialResourceList.PartialDescriptors[i];
  1732. switch ( partial->Type ) {
  1733. case CmResourceTypePort: {
  1734. foundPort = TRUE;
  1735. //
  1736. // Save of the pointer to the partial so
  1737. // that we can later use it to report resources
  1738. // and we can also use this later in the routine
  1739. // to make sure that we got all of our resources.
  1740. //
  1741. fdoExtension->SpanOfControllerAddress = partial->u.Port.Length;
  1742. fdoExtension->ControllerAddress.StatusA =
  1743. FdcGetControllerBase(
  1744. BusType,
  1745. BusNumber,
  1746. partial->u.Port.Start,
  1747. fdoExtension->SpanOfControllerAddress,
  1748. (BOOLEAN)!!partial->Flags );
  1749. if ( fdoExtension->ControllerAddress.StatusA == NULL ) {
  1750. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1751. } else {
  1752. fdoExtension->ControllerAddress.StatusB = fdoExtension->ControllerAddress.StatusA + 1;
  1753. fdoExtension->ControllerAddress.DriveControl = fdoExtension->ControllerAddress.StatusA + 2;
  1754. fdoExtension->ControllerAddress.Tape = fdoExtension->ControllerAddress.StatusA + 3;
  1755. fdoExtension->ControllerAddress.Status = fdoExtension->ControllerAddress.StatusA + 4;
  1756. fdoExtension->ControllerAddress.Fifo = fdoExtension->ControllerAddress.StatusA + 5;
  1757. fdoExtension->ControllerAddress.DRDC.DataRate = fdoExtension->ControllerAddress.StatusA + 7;
  1758. }
  1759. break;
  1760. }
  1761. case CmResourceTypeInterrupt: {
  1762. foundInterrupt = TRUE;
  1763. if ( partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED ) {
  1764. fdoExtension->InterruptMode = Latched;
  1765. } else {
  1766. fdoExtension->InterruptMode = LevelSensitive;
  1767. }
  1768. fdoExtension->ControllerVector =
  1769. HalGetInterruptVector(
  1770. BusType,
  1771. BusNumber,
  1772. partial->u.Interrupt.Level,
  1773. partial->u.Interrupt.Vector,
  1774. &fdoExtension->ControllerIrql,
  1775. &fdoExtension->ProcessorMask
  1776. );
  1777. break;
  1778. }
  1779. case CmResourceTypeDma: {
  1780. DEVICE_DESCRIPTION deviceDesc = {0};
  1781. //
  1782. // Use IgnoreCount equal to TRUE to fix PS/1000.
  1783. //
  1784. foundDma = TRUE;
  1785. deviceDesc.Version = DEVICE_DESCRIPTION_VERSION1;
  1786. if ( partial->u.Dma.Channel > 3 ) {
  1787. deviceDesc.DmaWidth = Width16Bits;
  1788. } else {
  1789. deviceDesc.DmaWidth = Width8Bits;
  1790. }
  1791. deviceDesc.DemandMode = TRUE;
  1792. deviceDesc.MaximumLength = MAX_BYTES_PER_SECTOR * MAX_SECTORS_PER_TRACK;
  1793. deviceDesc.IgnoreCount = TRUE;
  1794. deviceDesc.DmaChannel = partial->u.Dma.Channel;
  1795. deviceDesc.InterfaceType = BusType;
  1796. deviceDesc.DmaSpeed = DEFAULT_DMA_SPEED;
  1797. fdoExtension->AdapterObject =
  1798. HalGetAdapter(
  1799. &deviceDesc,
  1800. &fdoExtension->NumberOfMapRegisters
  1801. );
  1802. if ( fdoExtension->AdapterObject == NULL ) {
  1803. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1804. }
  1805. break;
  1806. }
  1807. default:
  1808. break;
  1809. }
  1810. }
  1811. //
  1812. // If we didn't get all the information then we return
  1813. // insufficient resources.
  1814. //
  1815. if ( !foundPort || !foundInterrupt || !foundDma ) {
  1816. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1817. }
  1818. }
  1819. return ntStatus;
  1820. }
  1821. PVOID
  1822. FdcGetControllerBase(
  1823. IN INTERFACE_TYPE BusType,
  1824. IN ULONG BusNumber,
  1825. PHYSICAL_ADDRESS IoAddress,
  1826. ULONG NumberOfBytes,
  1827. BOOLEAN InIoSpace
  1828. )
  1829. /*++
  1830. Routine Description:
  1831. This routine maps an IO address to system address space.
  1832. Arguments:
  1833. BusType - what type of bus - eisa, mca, isa
  1834. IoBusNumber - which IO bus (for machines with multiple buses).
  1835. IoAddress - base device address to be mapped.
  1836. NumberOfBytes - number of bytes for which address is valid.
  1837. InIoSpace - indicates an IO address.
  1838. Return Value:
  1839. Mapped address
  1840. --*/
  1841. {
  1842. PHYSICAL_ADDRESS cardAddress;
  1843. ULONG addressSpace = InIoSpace;
  1844. PVOID Address;
  1845. if ( !HalTranslateBusAddress( BusType,
  1846. BusNumber,
  1847. IoAddress,
  1848. &addressSpace,
  1849. &cardAddress ) ){
  1850. return NULL;
  1851. }
  1852. //
  1853. // Map the device base address into the virtual address space
  1854. // if the address is in memory space.
  1855. //
  1856. if ( !addressSpace ) {
  1857. Address = MmMapIoSpace( cardAddress,
  1858. NumberOfBytes,
  1859. FALSE );
  1860. } else {
  1861. Address = (PCONTROLLER)cardAddress.LowPart;
  1862. }
  1863. return Address;
  1864. }
  1865. NTSTATUS
  1866. FcInitializeControllerHardware(
  1867. IN PFDC_FDO_EXTENSION FdoExtension,
  1868. IN PDEVICE_OBJECT DeviceObject
  1869. )
  1870. /*++
  1871. Routine Description:
  1872. This routine is called at initialization time by FcInitializeDevice()
  1873. - once for each controller that we have to support.
  1874. When this routine is called, the controller data structures have all
  1875. been allocated.
  1876. Arguments:
  1877. ControllerData - the completed data structure associated with the
  1878. controller hardware being initialized.
  1879. DeviceObject - a pointer to a device object; this routine will cause
  1880. an interrupt, and the ISR requires CurrentDeviceObject to be filled
  1881. in.
  1882. Return Value:
  1883. STATUS_SUCCESS if this controller appears to have been reset properly,
  1884. error otherwise.
  1885. --*/
  1886. {
  1887. NTSTATUS ntStatus = STATUS_SUCCESS;
  1888. UCHAR statusRegister0;
  1889. UCHAR cylinder;
  1890. UCHAR driveNumber;
  1891. UCHAR retrycnt;
  1892. FdcDump( FDCSHOW, ("Fdc: FcInitializeControllerHardware...\n") );
  1893. for (retrycnt = 0; ; retrycnt++) {
  1894. //
  1895. // Reset the controller. This will cause an interrupt. Reset
  1896. // CurrentDeviceObject until after the 10ms wait, in case any
  1897. // stray interrupts come in.
  1898. //
  1899. DISABLE_CONTROLLER_IMAGE (FdoExtension);
  1900. WRITE_CONTROLLER(
  1901. FdoExtension->ControllerAddress.DriveControl,
  1902. FdoExtension->DriveControlImage );
  1903. KeStallExecutionProcessor( 10 );
  1904. FdoExtension->CurrentDeviceObject = DeviceObject;
  1905. FdoExtension->AllowInterruptProcessing = TRUE;
  1906. FdoExtension->CommandHasResultPhase = FALSE;
  1907. KeResetEvent( &FdoExtension->InterruptEvent );
  1908. ENABLE_CONTROLLER_IMAGE (FdoExtension);
  1909. WRITE_CONTROLLER(
  1910. FdoExtension->ControllerAddress.DriveControl,
  1911. FdoExtension->DriveControlImage );
  1912. if (IsNEC_98) {
  1913. //
  1914. // NEC98 don't have to wait for interrupt.
  1915. //
  1916. ntStatus = STATUS_SUCCESS;
  1917. } else { // (IsNEC_98)
  1918. //
  1919. // Wait for an interrupt. Note that STATUS_TIMEOUT and
  1920. // STATUS_SUCCESS are the only possible return codes, since we
  1921. // aren't alertable and won't get APCs.
  1922. //
  1923. ntStatus = KeWaitForSingleObject( &FdoExtension->InterruptEvent,
  1924. Executive,
  1925. KernelMode,
  1926. FALSE,
  1927. &FdoExtension->InterruptDelay );
  1928. } // (IsNEC_98)
  1929. if (ntStatus == STATUS_TIMEOUT) {
  1930. if (retrycnt >= 1) {
  1931. break;
  1932. }
  1933. // Retry reset after configure command to enable polling
  1934. // interrupt.
  1935. FdoExtension->FifoBuffer[0] = COMMND_CONFIGURE;
  1936. if (FdoExtension->Clock48MHz) {
  1937. FdoExtension->FifoBuffer[0] |= COMMND_OPTION_CLK48;
  1938. }
  1939. FdoExtension->FifoBuffer[1] = 0;
  1940. FdoExtension->FifoBuffer[2] = COMMND_CONFIGURE_FIFO_THRESHOLD;
  1941. FdoExtension->FifoBuffer[3] = 0;
  1942. ntStatus = FcIssueCommand( FdoExtension,
  1943. FdoExtension->FifoBuffer,
  1944. FdoExtension->FifoBuffer,
  1945. NULL,
  1946. 0,
  1947. 0 );
  1948. if (!NT_SUCCESS(ntStatus)) {
  1949. ntStatus = STATUS_TIMEOUT;
  1950. break;
  1951. }
  1952. KeStallExecutionProcessor( 500 );
  1953. } else {
  1954. break;
  1955. }
  1956. }
  1957. if ( ntStatus == STATUS_TIMEOUT ) {
  1958. //
  1959. // Change info to an error.
  1960. //
  1961. ntStatus = STATUS_IO_TIMEOUT;
  1962. FdoExtension->HardwareFailed = TRUE;
  1963. }
  1964. if ( !NT_SUCCESS( ntStatus ) ) {
  1965. FdcDump(FDCDBGP,("Fdc: controller didn't interrupt after reset\n"));
  1966. return ntStatus;
  1967. }
  1968. if (!IsNEC_98) {
  1969. ntStatus = FcFinishReset( FdoExtension );
  1970. } // (!IsNEC_98)
  1971. return ntStatus;
  1972. }
  1973. NTSTATUS
  1974. FcGetFdcInformation(
  1975. IN OUT PFDC_FDO_EXTENSION FdoExtension
  1976. )
  1977. /*++
  1978. Routine Description:
  1979. This routine will attempt to identify the type of Floppy Controller
  1980. Arguments:
  1981. FdoExtension - a pointer to our data area for the drive being
  1982. accessed (any drive if a controller command is being given).
  1983. Return Value:
  1984. --*/
  1985. {
  1986. NTSTATUS ntStatus;
  1987. FDC_INFORMATION fdcInfo;
  1988. if (FdoExtension->FdcEnablerSupported) {
  1989. fdcInfo.structSize = sizeof(fdcInfo);
  1990. ntStatus = FcFdcEnabler( FdoExtension->FdcEnablerDeviceObject,
  1991. IOCTL_GET_FDC_INFO,
  1992. &fdcInfo);
  1993. if ( NT_SUCCESS( ntStatus ) ) {
  1994. FdoExtension->FdcType = (UCHAR)fdcInfo.FloppyControllerType;
  1995. FdoExtension->Clock48MHz =
  1996. (fdcInfo.ClockRatesSupported == FDC_CLOCK_48MHZ);
  1997. FdoExtension->FdcSpeeds = (UCHAR)fdcInfo.SpeedsAvailable;
  1998. }
  1999. } else {
  2000. //
  2001. // First, assume that we don't know what kind of FDC is attached.
  2002. //
  2003. FdoExtension->FdcType = FDC_TYPE_UNKNOWN;
  2004. // Check for an enhanced type controller by issuing the version command.
  2005. FdoExtension->FifoBuffer[0] = COMMND_VERSION;
  2006. ntStatus = FcIssueCommand( FdoExtension,
  2007. FdoExtension->FifoBuffer,
  2008. FdoExtension->FifoBuffer,
  2009. NULL,
  2010. 0,
  2011. 0 );
  2012. if ( NT_SUCCESS( ntStatus ) ) {
  2013. if (FdoExtension->FifoBuffer[0] == VALID_NEC_FDC) {
  2014. FdoExtension->FdcType = FDC_TYPE_ENHANCED;
  2015. } else {
  2016. FdoExtension->FdcType = FDC_TYPE_NORMAL;
  2017. }
  2018. }
  2019. // Determine if the controller is a National 8477 by issuing the NSC
  2020. // command which is specific to National parts and returns 0x71. (This
  2021. // command happens to be the same as the Intel Part ID command so we
  2022. // will use it instead.) The lower four bits are subject to change by
  2023. // National and will reflect the version of the part in question. At
  2024. // this point we will only test the high four bits.
  2025. if ( FdoExtension->FdcType == FDC_TYPE_ENHANCED &&
  2026. NT_SUCCESS( ntStatus ) ) {
  2027. FdoExtension->FifoBuffer[0] = COMMND_PART_ID;
  2028. ntStatus = FcIssueCommand( FdoExtension,
  2029. FdoExtension->FifoBuffer,
  2030. FdoExtension->FifoBuffer,
  2031. NULL,
  2032. 0,
  2033. 0 );
  2034. if ( NT_SUCCESS( ntStatus ) ) {
  2035. if ( (FdoExtension->FifoBuffer[0] & NSC_MASK) ==
  2036. NSC_PRIMARY_VERSION) {
  2037. FdoExtension->FdcType = FDC_TYPE_NATIONAL;
  2038. }
  2039. }
  2040. }
  2041. // Determine if the controller is an 82077 by issuing the perpendicular
  2042. // mode command which at this time is only valid on 82077's.
  2043. if ( FdoExtension->FdcType == FDC_TYPE_ENHANCED &&
  2044. NT_SUCCESS( ntStatus ) ) {
  2045. FdoExtension->FifoBuffer[0] = COMMND_PERPENDICULAR_MODE;
  2046. FdoExtension->FifoBuffer[1] = COMMND_PERPENDICULAR_MODE_OW;
  2047. ntStatus = FcIssueCommand( FdoExtension,
  2048. FdoExtension->FifoBuffer,
  2049. FdoExtension->FifoBuffer,
  2050. NULL,
  2051. 0,
  2052. 0 );
  2053. if (ntStatus != STATUS_DEVICE_NOT_READY) {
  2054. FdoExtension->FdcType = FDC_TYPE_82077;
  2055. }
  2056. }
  2057. // Determine if the controller is an Intel 82078 by issuing the part id
  2058. // command which is specific to Intel 82078 parts.
  2059. if ( FdoExtension->FdcType == FDC_TYPE_82077 &&
  2060. NT_SUCCESS( ntStatus ) ) {
  2061. FdoExtension->FifoBuffer[0] = COMMND_PART_ID;
  2062. ntStatus = FcIssueCommand( FdoExtension,
  2063. FdoExtension->FifoBuffer,
  2064. FdoExtension->FifoBuffer,
  2065. NULL,
  2066. 0,
  2067. 0 );
  2068. if ( NT_SUCCESS( ntStatus ) ) {
  2069. if ((FdoExtension->FifoBuffer[0] & INTEL_MASK) ==
  2070. INTEL_64_PIN_VERSION) {
  2071. FdoExtension->FdcType = FDC_TYPE_82078_64;
  2072. } else {
  2073. if ((FdoExtension->FifoBuffer[0] & INTEL_MASK) ==
  2074. INTEL_44_PIN_VERSION) {
  2075. FdoExtension->FdcType = FDC_TYPE_82078_44;
  2076. }
  2077. }
  2078. }
  2079. }
  2080. switch (FdoExtension->FdcType) {
  2081. case FDC_TYPE_UNKNOWN :
  2082. case FDC_TYPE_NORMAL :
  2083. case FDC_TYPE_ENHANCED :
  2084. default:
  2085. FdoExtension->FdcSpeeds = FDC_SPEED_250KB |
  2086. FDC_SPEED_300KB |
  2087. FDC_SPEED_500KB;
  2088. break;
  2089. case FDC_TYPE_82077 :
  2090. case FDC_TYPE_82077AA :
  2091. case FDC_TYPE_82078_44 :
  2092. case FDC_TYPE_NATIONAL :
  2093. FdoExtension->FdcSpeeds = FDC_SPEED_250KB |
  2094. FDC_SPEED_300KB |
  2095. FDC_SPEED_500KB |
  2096. FDC_SPEED_1MB;
  2097. break;
  2098. case FDC_TYPE_82078_64 :
  2099. FdoExtension->FdcSpeeds = FDC_SPEED_250KB |
  2100. FDC_SPEED_300KB |
  2101. FDC_SPEED_500KB |
  2102. FDC_SPEED_1MB;
  2103. if ( FdoExtension->Clock48MHz ) {
  2104. FdoExtension->FdcSpeeds |= FDC_SPEED_2MB;
  2105. }
  2106. break;
  2107. }
  2108. }
  2109. FdcDump( FDCINFO, ("Fdc: FdcType - %x\n", FdoExtension->FdcType));
  2110. return ntStatus;
  2111. }
  2112. #define IO_PORT_REQ_MASK 0xbc
  2113. NTSTATUS
  2114. FdcFilterResourceRequirements(
  2115. IN PDEVICE_OBJECT DeviceObject,
  2116. IN PIRP Irp
  2117. )
  2118. /*++
  2119. Routine Description:
  2120. This routine examines the supplied resource list and adds resources if
  2121. necessary. The only resources that it is concerned with adding are io port
  2122. resources. Adding io port resources is necessary because of different bios
  2123. configurations and specifications.
  2124. The PC97(98) hardware specification defines only 3f2, 3f4, and 3f5 as
  2125. io port resources for standard floppy controllers (based on IBM PC floppy
  2126. controller configurations). In addition to these resources, fdc.sys
  2127. requires 3f7 for disk change detection and data rate programming and
  2128. optionally 3f3 for floppy tape support. In addition, some bioses define
  2129. aliased resources (e.g. 3f2 & 7f2, etc.)
  2130. This routine first forwards the irp to the underlying PDO. Upon return,
  2131. it examines the io resource list to determine if any additional resources
  2132. will be required. It maintains a linked list of all io port base addresses
  2133. that it encounters, assuming that they define aliased resources. N.B. - if
  2134. alternative lists are present in the io resource requirements list, only the
  2135. first list is examined. If additional resources are required a new io
  2136. resource list is created. The first io resource list in the new resource
  2137. requirements list will contain the original resources as well as the
  2138. additional resources required. If it was necessary to request the tape mode
  2139. register (3f3), i.e. 3f3 was not in the original list, a second list is
  2140. generated that is identical to the first new list except that 3f3 is excluded.
  2141. This list is for the case where the tape mode register is not available.
  2142. Finally, the original list(s) is(are) copied to the end of the new list and
  2143. are treated as alternative io resource lists.
  2144. Arguments:
  2145. DeviceObject - a pointer to the device object being started.
  2146. Irp - a pointer to the start device Irp.
  2147. Return Value:
  2148. --*/
  2149. {
  2150. NTSTATUS ntStatus;
  2151. PFDC_FDO_EXTENSION fdoExtension;
  2152. PIO_STACK_LOCATION irpSp;
  2153. KEVENT doneEvent;
  2154. PIO_RESOURCE_REQUIREMENTS_LIST resourceRequirementsIn;
  2155. PIO_RESOURCE_REQUIREMENTS_LIST resourceRequirementsOut;
  2156. ULONG listSize;
  2157. ULONG i,j;
  2158. PIO_RESOURCE_LIST ioResourceListIn;
  2159. PIO_RESOURCE_LIST ioResourceListOut;
  2160. PIO_RESOURCE_DESCRIPTOR ioResourceDescriptorIn;
  2161. PIO_RESOURCE_DESCRIPTOR ioResourceDescriptorOut;
  2162. LIST_ENTRY ioPortList;
  2163. PLIST_ENTRY links;
  2164. PIO_PORT_INFO ioPortInfo;
  2165. BOOLEAN foundBase;
  2166. ULONG newDescriptors;
  2167. BOOLEAN interruptResource = FALSE;
  2168. BOOLEAN dmaResource = FALSE;
  2169. UCHAR newPortMask;
  2170. BOOLEAN requestTapeModeRegister = FALSE;
  2171. USHORT in,out;
  2172. #ifdef TOSHIBAJ
  2173. BOOLEAN foundConfigPort = FALSE;
  2174. struct {
  2175. ULONG start;
  2176. ULONG length;
  2177. } configNewPort = {0, 0};
  2178. #endif
  2179. fdoExtension = DeviceObject->DeviceExtension;
  2180. irpSp = IoGetCurrentIrpStackLocation( Irp );
  2181. ntStatus = STATUS_SUCCESS;
  2182. InitializeListHead( &ioPortList );
  2183. FdcDump( FDCSHOW, ("FdcFdoPnp: IRP_MN_FILTER_RESOURCE_REQUIREMENTS - Irp: %p\n", Irp) );
  2184. //
  2185. // Pass this irp down to the PDO before proceeding.
  2186. //
  2187. KeInitializeEvent( &doneEvent, NotificationEvent, FALSE );
  2188. IoCopyCurrentIrpStackLocationToNext(Irp);
  2189. IoSetCompletionRoutine( Irp,
  2190. FdcPnpComplete,
  2191. &doneEvent,
  2192. TRUE,
  2193. TRUE,
  2194. TRUE );
  2195. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  2196. if ( ntStatus == STATUS_PENDING ) {
  2197. KeWaitForSingleObject( &doneEvent, Executive, KernelMode, FALSE, NULL );
  2198. }
  2199. //
  2200. // Modified resources are returned in Irp-IoStatus.Information, otherwise
  2201. // just use what's in the parameter list.
  2202. //
  2203. if ( Irp->IoStatus.Information == 0 ) {
  2204. Irp->IoStatus.Information = (UINT_PTR)irpSp->Parameters.FilterResourceRequirements.IoResourceRequirementList;
  2205. if ( Irp->IoStatus.Information == (UINT_PTR)NULL ) {
  2206. //
  2207. // NULL List, the PDO freed the incoming resource list but did not
  2208. // provide a new list. Complete the IRP with the PDO's status.
  2209. //
  2210. ntStatus = Irp->IoStatus.Status;
  2211. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  2212. return( ntStatus );
  2213. }
  2214. }
  2215. resourceRequirementsIn = (PIO_RESOURCE_REQUIREMENTS_LIST)Irp->IoStatus.Information;
  2216. FdcDump( FDCSHOW, ("Resource Requirements List = %p\n", resourceRequirementsIn) );
  2217. if (IsNEC_98) {
  2218. //
  2219. // It is not necessary to modify the resources.
  2220. //
  2221. ntStatus = STATUS_SUCCESS;
  2222. Irp->IoStatus.Status = ntStatus;
  2223. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  2224. return ntStatus;
  2225. }
  2226. //
  2227. // Make a pass through the resource list and determine what resources are
  2228. // already there as well as the base address for the io port and any
  2229. // alias ioports.
  2230. //
  2231. ioResourceListIn = resourceRequirementsIn->List;
  2232. ioResourceDescriptorIn = ioResourceListIn->Descriptors;
  2233. ntStatus = STATUS_SUCCESS;
  2234. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: examining %d resources\n", ioResourceListIn->Count));
  2235. for ( i = 0; i < ioResourceListIn->Count && NT_SUCCESS(ntStatus); i++ ) {
  2236. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: IoResourceDescritporIn = %p\n",ioResourceDescriptorIn));
  2237. switch ( ioResourceDescriptorIn->Type ) {
  2238. case CmResourceTypeInterrupt:
  2239. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Found Interrupt Resource\n"));
  2240. interruptResource = TRUE;
  2241. break;
  2242. case CmResourceTypeDma:
  2243. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Found Dma Resource \n"));
  2244. dmaResource = TRUE;
  2245. break;
  2246. case CmResourceTypePort:
  2247. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Found Port Resource\n"));
  2248. //
  2249. // For the ioPorts we will make a list containing each detected
  2250. // 'base' address as well as the currently allocated addresses
  2251. // on that base. Later we will use this to request additional
  2252. // resources if necessary.
  2253. //
  2254. // First, if this base isn't already in the list, create a new
  2255. // list entry for it.
  2256. //
  2257. foundBase = FALSE;
  2258. for ( links = ioPortList.Flink;
  2259. links != &ioPortList;
  2260. links = links->Flink) {
  2261. ioPortInfo = CONTAINING_RECORD(links, IO_PORT_INFO, ListEntry);
  2262. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Examining %p for match\n",ioPortInfo));
  2263. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Base Address = %08x\n",ioPortInfo->BaseAddress.LowPart));
  2264. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Desc Address = %08x\n",ioResourceDescriptorIn->u.Port.MinimumAddress.LowPart & 0xfffffff8));
  2265. if ( ioPortInfo->BaseAddress.LowPart ==
  2266. (ioResourceDescriptorIn->u.Port.MinimumAddress.LowPart & 0xfffffff8) ) {
  2267. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Found %08x in the ioPortList\n",ioResourceDescriptorIn->u.Port.MinimumAddress.LowPart));
  2268. foundBase = TRUE;
  2269. //
  2270. // Add these resources into the resource map for this base
  2271. // address.
  2272. //
  2273. for ( j = 0; j < ioResourceDescriptorIn->u.Port.Length; j++ ) {
  2274. ioPortInfo->Map |= 0x01 << ((ioResourceDescriptorIn->u.Port.MinimumAddress.LowPart & 0x07) + j);
  2275. }
  2276. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: New IoPortInfo->Map = %x\n",ioPortInfo->Map));
  2277. break;
  2278. }
  2279. }
  2280. if ( !foundBase ) {
  2281. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Creating new ioPortList entry for %08x\n",ioResourceDescriptorIn->u.Port.MinimumAddress.LowPart));
  2282. ioPortInfo = ExAllocatePool( PagedPool, sizeof(IO_PORT_INFO) );
  2283. if ( ioPortInfo == NULL ) {
  2284. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2285. } else {
  2286. RtlZeroMemory( ioPortInfo, sizeof(IO_PORT_INFO) );
  2287. ioPortInfo->BaseAddress = ioResourceDescriptorIn->u.Port.MinimumAddress;
  2288. ioPortInfo->BaseAddress.LowPart &= 0xfffffff8;
  2289. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Base Address = %08x\n",ioPortInfo->BaseAddress.LowPart));
  2290. for ( j = 0; j < ioResourceDescriptorIn->u.Port.Length; j++ ) {
  2291. ioPortInfo->Map |= 0x01 << ((ioResourceDescriptorIn->u.Port.MinimumAddress.LowPart & 0x07) + j);
  2292. }
  2293. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: New IoPortInfo->Map = %x\n",ioPortInfo->Map));
  2294. InsertTailList( &ioPortList, &ioPortInfo->ListEntry );
  2295. }
  2296. }
  2297. break;
  2298. default:
  2299. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Found unknown resource\n"));
  2300. break;
  2301. }
  2302. ioResourceDescriptorIn++;
  2303. }
  2304. //
  2305. // If we didn't see any io port resources, we will just return now
  2306. // since we can't be sure of what to ask for. The subsequent start
  2307. // device will surely fail. This also goes for the interrupt and
  2308. // dma resource.
  2309. //
  2310. if ( !NT_SUCCESS(ntStatus) ||
  2311. IsListEmpty( &ioPortList ) ||
  2312. !interruptResource ||
  2313. !dmaResource ) {
  2314. //
  2315. // Clean up the ioPortInfo list
  2316. //
  2317. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Bad Resources, Go directly to jail\n"));
  2318. while ( !IsListEmpty( &ioPortList ) ) {
  2319. links = RemoveHeadList( &ioPortList );
  2320. ioPortInfo = CONTAINING_RECORD(links, IO_PORT_INFO, ListEntry);
  2321. ExFreePool( ioPortInfo );
  2322. }
  2323. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  2324. return ntStatus;
  2325. }
  2326. #ifdef TOSHIBAJ
  2327. if (SmcConfigBase) {
  2328. PHYSICAL_ADDRESS configPort;
  2329. ULONG ioSpace;
  2330. // Map I/O port
  2331. configPort.QuadPart = 0;
  2332. configPort.LowPart = SmcConfigBase;
  2333. ioSpace = 1; // I/O port
  2334. if (HalTranslateBusAddress(resourceRequirementsIn->InterfaceType,
  2335. resourceRequirementsIn->BusNumber,
  2336. configPort,
  2337. &ioSpace,
  2338. &configPort)) {
  2339. TranslatedConfigBase = (PUCHAR)configPort.LowPart;
  2340. if (FcCheckConfigPort(TranslatedConfigBase)) {
  2341. FdcDump( FDCINFO,
  2342. ("FdcFilterResourceRequirements: Configuration port %x\n",
  2343. TranslatedConfigBase) );
  2344. } else {
  2345. SmcConfigBase = 0;
  2346. TranslatedConfigBase = NULL;
  2347. }
  2348. } else {
  2349. SmcConfigBase = 0;
  2350. TranslatedConfigBase = NULL;
  2351. }
  2352. }
  2353. #endif
  2354. //
  2355. // At this point, we know what resources we are currently assigned so
  2356. // we can determine what additional resources we need to request. We
  2357. // need to know the size of the list we need to create so first count
  2358. // the number of resource descriptors we will have to add to the current
  2359. // list.
  2360. //
  2361. newDescriptors = 0;
  2362. for ( links = ioPortList.Flink;
  2363. links != &ioPortList;
  2364. links = links->Flink) {
  2365. ioPortInfo = CONTAINING_RECORD(links, IO_PORT_INFO, ListEntry);
  2366. newPortMask = ~ioPortInfo->Map & IO_PORT_REQ_MASK;
  2367. if ( newPortMask & 0x08 ) {
  2368. requestTapeModeRegister = TRUE;
  2369. }
  2370. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Counting bits in %x\n",newPortMask));
  2371. while ( newPortMask > 0 ) {
  2372. if ( newPortMask & 0x01 ) {
  2373. newDescriptors++;
  2374. }
  2375. newPortMask >>= 1;
  2376. }
  2377. #ifdef TOSHIBAJ
  2378. // Are there configuration ports in assigned resources ?
  2379. if (SmcConfigBase && (ioPortInfo->BaseAddress.LowPart == SmcConfigBase)) {
  2380. foundConfigPort = TRUE;
  2381. if (!(ioPortInfo->Map & 0x01)) {
  2382. configNewPort.start = SmcConfigBase;
  2383. ++configNewPort.length;
  2384. }
  2385. if (!(ioPortInfo->Map & 0x02)) {
  2386. if (!configNewPort.start) {
  2387. configNewPort.start = SmcConfigBase + 1;
  2388. }
  2389. configNewPort.length++;
  2390. }
  2391. }
  2392. #endif
  2393. }
  2394. #ifdef TOSHIBAJ
  2395. // Deteremine the address and length of the additional descriptor
  2396. // for configuration ports.
  2397. if (SmcConfigBase && !foundConfigPort) {
  2398. configNewPort.start = SmcConfigBase;
  2399. configNewPort.length = 2;
  2400. }
  2401. if (configNewPort.start) {
  2402. newDescriptors++;
  2403. }
  2404. #endif
  2405. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Create %d new descriptors\n", newDescriptors) );
  2406. //
  2407. // If we need resources that were not in the list, we will need to
  2408. // allocate a new resource requirements list that includes these
  2409. // new resources.
  2410. //
  2411. if ( newDescriptors > 0 ) {
  2412. //
  2413. // Allocate and initialize a resource requirements list. Make it big
  2414. // enough to hold whatever was in the list to start with along with
  2415. // the new resource list.
  2416. //
  2417. listSize = resourceRequirementsIn->ListSize +
  2418. resourceRequirementsIn->ListSize +
  2419. newDescriptors * sizeof(IO_RESOURCE_DESCRIPTOR);
  2420. //
  2421. // If we will be requesting the tape mode register we will need to
  2422. // make an alternate list without it in case we cannot get it.
  2423. //
  2424. if ( requestTapeModeRegister ) {
  2425. listSize = listSize +
  2426. resourceRequirementsIn->ListSize +
  2427. newDescriptors * sizeof(IO_RESOURCE_DESCRIPTOR);
  2428. }
  2429. resourceRequirementsOut = ExAllocatePool( NonPagedPool, listSize );
  2430. if ( resourceRequirementsOut == NULL ) {
  2431. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2432. } else {
  2433. RtlZeroMemory( resourceRequirementsOut, listSize);
  2434. //
  2435. // Initialize the IO_RESOURCE_REQUIREMENTS_LIST header.
  2436. //
  2437. resourceRequirementsOut->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) -
  2438. sizeof(IO_RESOURCE_LIST);
  2439. resourceRequirementsOut->InterfaceType = resourceRequirementsIn->InterfaceType;
  2440. resourceRequirementsOut->BusNumber = resourceRequirementsIn->BusNumber;
  2441. resourceRequirementsOut->SlotNumber = resourceRequirementsIn->SlotNumber;
  2442. resourceRequirementsOut->Reserved[0] = resourceRequirementsIn->Reserved[0];
  2443. resourceRequirementsOut->Reserved[1] = resourceRequirementsIn->Reserved[1];
  2444. resourceRequirementsOut->Reserved[2] = resourceRequirementsIn->Reserved[2];
  2445. resourceRequirementsOut->AlternativeLists = resourceRequirementsIn->AlternativeLists + 1;
  2446. if ( requestTapeModeRegister ) {
  2447. ++resourceRequirementsOut->AlternativeLists;
  2448. }
  2449. //
  2450. // Copy the primary list from the incoming IO_RESOURCE_REQUIREMENTS_LIST
  2451. // to the new list.
  2452. //
  2453. ioResourceListIn = resourceRequirementsIn->List;
  2454. ioResourceListOut = resourceRequirementsOut->List;
  2455. listSize = sizeof(IO_RESOURCE_LIST) +
  2456. (ioResourceListIn->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR);
  2457. RtlCopyMemory( ioResourceListOut, ioResourceListIn, listSize );
  2458. resourceRequirementsOut->ListSize += listSize;
  2459. //
  2460. // Add any additional resources that we are requesting.
  2461. //
  2462. ioResourceDescriptorOut = (PIO_RESOURCE_DESCRIPTOR)((ULONG_PTR)resourceRequirementsOut +
  2463. resourceRequirementsOut->ListSize);
  2464. for ( links = ioPortList.Flink;
  2465. links != &ioPortList;
  2466. links = links->Flink) {
  2467. ioPortInfo = CONTAINING_RECORD(links, IO_PORT_INFO, ListEntry);
  2468. newPortMask = ~ioPortInfo->Map & IO_PORT_REQ_MASK;
  2469. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Add resource desc for each bit in %x\n",newPortMask));
  2470. i = 0;
  2471. while ( newPortMask != 0 ) {
  2472. if ( newPortMask & 0x01 ) {
  2473. ioResourceDescriptorOut->Option = IO_RESOURCE_PREFERRED;
  2474. ioResourceDescriptorOut->Type = CmResourceTypePort;
  2475. ioResourceDescriptorOut->ShareDisposition = CmResourceShareDeviceExclusive;
  2476. ioResourceDescriptorOut->Flags = CM_RESOURCE_PORT_IO;
  2477. ioResourceDescriptorOut->u.Port.Length = 1;
  2478. ioResourceDescriptorOut->u.Port.Alignment = 1;
  2479. ioResourceDescriptorOut->u.Port.MinimumAddress.QuadPart =
  2480. ioResourceDescriptorOut->u.Port.MaximumAddress.QuadPart =
  2481. ioPortInfo->BaseAddress.QuadPart + (ULONGLONG)i;
  2482. ++ioResourceListOut->Count;
  2483. resourceRequirementsOut->ListSize += sizeof(IO_RESOURCE_DESCRIPTOR);
  2484. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Add resource descriptor: %p\n",ioResourceDescriptorOut));
  2485. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->Option = %x\n",ioResourceDescriptorOut->Option ));
  2486. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->Type = %x\n",ioResourceDescriptorOut->Type ));
  2487. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->ShareDisposition = %x\n",ioResourceDescriptorOut->ShareDisposition));
  2488. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->Flags = %x\n",ioResourceDescriptorOut->Flags ));
  2489. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->u.Port.Length = %x\n",ioResourceDescriptorOut->u.Port.Length ));
  2490. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->u.Port.Alignment = %x\n",ioResourceDescriptorOut->u.Port.Alignment));
  2491. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->u.Port.MinimumAddress.LowPart = %08x\n",ioResourceDescriptorOut->u.Port.MinimumAddress.LowPart));
  2492. ioResourceDescriptorOut++;
  2493. }
  2494. newPortMask >>= 1;
  2495. i++;
  2496. }
  2497. }
  2498. #ifdef TOSHIBAJ
  2499. // Add the descriptor for configuration ports
  2500. if (configNewPort.start) {
  2501. ioResourceDescriptorOut->Option = IO_RESOURCE_PREFERRED;
  2502. ioResourceDescriptorOut->Type = CmResourceTypePort;
  2503. ioResourceDescriptorOut->ShareDisposition = CmResourceShareDeviceExclusive;
  2504. ioResourceDescriptorOut->Flags = CM_RESOURCE_PORT_IO;
  2505. ioResourceDescriptorOut->u.Port.Length = configNewPort.length;
  2506. ioResourceDescriptorOut->u.Port.Alignment = 1;
  2507. ioResourceDescriptorOut->u.Port.MinimumAddress.QuadPart =
  2508. ioResourceDescriptorOut->u.Port.MaximumAddress.QuadPart = 0;
  2509. ioResourceDescriptorOut->u.Port.MinimumAddress.LowPart =
  2510. configNewPort.start;
  2511. ioResourceDescriptorOut->u.Port.MaximumAddress.LowPart =
  2512. configNewPort.start + configNewPort.length - 1;
  2513. ++ioResourceListOut->Count;
  2514. resourceRequirementsOut->ListSize += sizeof(IO_RESOURCE_DESCRIPTOR);
  2515. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Add resource descriptor: %p\n",ioResourceDescriptorOut));
  2516. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->Option = %x\n",ioResourceDescriptorOut->Option ));
  2517. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->Type = %x\n",ioResourceDescriptorOut->Type ));
  2518. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->ShareDisposition = %x\n",ioResourceDescriptorOut->ShareDisposition));
  2519. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->Flags = %x\n",ioResourceDescriptorOut->Flags ));
  2520. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->u.Port.Length = %x\n",ioResourceDescriptorOut->u.Port.Length ));
  2521. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->u.Port.Alignment = %x\n",ioResourceDescriptorOut->u.Port.Alignment));
  2522. FdcDump( FDCSHOW, (" ioResourceDescriptorOut->u.Port.MinimumAddress.LowPart = %08x\n",ioResourceDescriptorOut->u.Port.MinimumAddress.LowPart));
  2523. ioResourceDescriptorOut++;
  2524. }
  2525. #endif
  2526. if ( requestTapeModeRegister ) {
  2527. ioResourceListIn = ioResourceListOut;
  2528. ioResourceListOut = (PIO_RESOURCE_LIST)ioResourceDescriptorOut;
  2529. ioResourceListOut->Version = ioResourceListIn->Version;
  2530. ioResourceListOut->Revision = ioResourceListIn->Revision;
  2531. ioResourceListOut->Count = 0;
  2532. resourceRequirementsOut->ListSize += sizeof(IO_RESOURCE_LIST) -
  2533. sizeof(IO_RESOURCE_DESCRIPTOR);
  2534. in = out = 0;
  2535. do {
  2536. if ( (ioResourceListIn->Descriptors[in].Type != CmResourceTypePort) ||
  2537. ((ioResourceListIn->Descriptors[in].u.Port.MinimumAddress.LowPart & 0x07) != 0x03) ) {
  2538. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Add %08x to alternate list\n", resourceRequirementsOut->List[0].Descriptors[out]));
  2539. ioResourceListOut->Descriptors[out++] = ioResourceListIn->Descriptors[in++];
  2540. ++ioResourceListOut->Count;
  2541. resourceRequirementsOut->ListSize += sizeof(IO_RESOURCE_DESCRIPTOR);
  2542. } else {
  2543. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Don't add %08x to alternate list\n", resourceRequirementsOut->List[0].Descriptors[out]));
  2544. in++;
  2545. }
  2546. } while ( in < ioResourceListIn->Count );
  2547. }
  2548. //
  2549. // Copy the original list(s) to the end of our new list.
  2550. //
  2551. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Copy %d existing resource list(s)\n",resourceRequirementsIn->AlternativeLists));
  2552. ioResourceListIn = resourceRequirementsIn->List;
  2553. ioResourceListOut = (PIO_RESOURCE_LIST)((ULONG_PTR)resourceRequirementsOut +
  2554. resourceRequirementsOut->ListSize);
  2555. for ( in = 0; in < resourceRequirementsIn->AlternativeLists; in++ ) {
  2556. FdcDump( FDCSHOW, ("FdcFilterResourceRequirements: Copy list %p\n",ioResourceListIn));
  2557. listSize = sizeof(IO_RESOURCE_LIST) +
  2558. (ioResourceListIn->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR);
  2559. RtlCopyMemory( ioResourceListOut, ioResourceListIn, listSize );
  2560. ioResourceListOut = (PIO_RESOURCE_LIST)((ULONG_PTR)ioResourceListOut + listSize);
  2561. ioResourceListIn = (PIO_RESOURCE_LIST)((ULONG_PTR)ioResourceListIn + listSize);
  2562. resourceRequirementsOut->ListSize += listSize;
  2563. }
  2564. FdcDump( FDCSHOW, ("Resource Requirements List = %p\n", resourceRequirementsOut) );
  2565. Irp->IoStatus.Information = (UINT_PTR)resourceRequirementsOut;
  2566. //
  2567. // Free the caller's list
  2568. //
  2569. ExFreePool( resourceRequirementsIn );
  2570. ntStatus = STATUS_SUCCESS;
  2571. }
  2572. }
  2573. //
  2574. // Clean up the ioPortInfo list
  2575. //
  2576. while ( !IsListEmpty( &ioPortList ) ) {
  2577. links = RemoveHeadList( &ioPortList );
  2578. ioPortInfo = CONTAINING_RECORD(links, IO_PORT_INFO, ListEntry);
  2579. ExFreePool( ioPortInfo );
  2580. }
  2581. Irp->IoStatus.Status = ntStatus;
  2582. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  2583. return ntStatus;
  2584. }
  2585. NTSTATUS
  2586. FdcQueryDeviceRelations(
  2587. IN PDEVICE_OBJECT DeviceObject,
  2588. IN PIRP Irp
  2589. )
  2590. /*++
  2591. Routine Description:
  2592. This routine will report any devices that have been enumerated on the
  2593. floppy controller. If we don't know of any devices yet we will
  2594. enumerate the registry hardware tree.
  2595. Arguments:
  2596. DeviceObject - a pointer to the device object being started.
  2597. Irp - a pointer to the start device Irp.
  2598. Return Value:
  2599. --*/
  2600. {
  2601. PFDC_FDO_EXTENSION fdoExtension;
  2602. PFDC_PDO_EXTENSION pdoExtension;
  2603. NTSTATUS ntStatus;
  2604. PIO_STACK_LOCATION irpSp;
  2605. ULONG relationCount;
  2606. ULONG relationLength;
  2607. PDEVICE_RELATIONS relations;
  2608. PLIST_ENTRY entry;
  2609. fdoExtension = DeviceObject->DeviceExtension;
  2610. irpSp = IoGetCurrentIrpStackLocation( Irp );
  2611. ntStatus = STATUS_SUCCESS;
  2612. FdcDump( FDCSHOW, ("FdcQueryDeviceRelations:\n"));
  2613. if ( irpSp->Parameters.QueryDeviceRelations.Type != BusRelations ) {
  2614. //
  2615. // We don't support this
  2616. //
  2617. FdcDump( FDCSHOW, ("FdcQueryDeviceRelations: Type = %d\n", irpSp->Parameters.QueryDeviceRelations.Type));
  2618. IoSkipCurrentIrpStackLocation( Irp );
  2619. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  2620. return ntStatus;
  2621. }
  2622. //
  2623. // Tell the plug and play system about all the PDOs.
  2624. //
  2625. // There might also be device relations below and above this FDO,
  2626. // so, be sure to propagate the relations from the upper drivers.
  2627. //
  2628. //
  2629. // The current number of PDOs
  2630. //
  2631. relationCount = ( Irp->IoStatus.Information == 0 ) ? 0 :
  2632. ((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Count;
  2633. //
  2634. // If we have not yet enumerated the hardware tree or all of our
  2635. // devices have been removed, enumerate it now.
  2636. //
  2637. if ( fdoExtension->NumPDOs == 0 ) {
  2638. INTERFACE_TYPE InterfaceType;
  2639. //
  2640. // Query the registry hardware tree to find out how many floppy
  2641. // drives were reported by the firmware.
  2642. //
  2643. for ( InterfaceType = 0;
  2644. InterfaceType < MaximumInterfaceType;
  2645. InterfaceType++ ) {
  2646. CONFIGURATION_TYPE Dc = DiskController;
  2647. CONFIGURATION_TYPE Fp = FloppyDiskPeripheral;
  2648. ntStatus = IoQueryDeviceDescription(&InterfaceType,
  2649. NULL,
  2650. &Dc,
  2651. NULL,
  2652. &Fp,
  2653. NULL,
  2654. FdcConfigCallBack,
  2655. fdoExtension );
  2656. if (!NT_SUCCESS(ntStatus) && (ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)) {
  2657. return ntStatus;
  2658. }
  2659. }
  2660. }
  2661. FdcDump( FDCSHOW, ("FdcQueryDeviceRelations: My relations count - %d\n", fdoExtension->NumPDOs));
  2662. relationLength = sizeof(DEVICE_RELATIONS) +
  2663. (relationCount + fdoExtension->NumPDOs) * sizeof (PDEVICE_OBJECT);
  2664. relations = (PDEVICE_RELATIONS) ExAllocatePool (NonPagedPool, relationLength);
  2665. if ( relations == NULL ) {
  2666. return STATUS_INSUFFICIENT_RESOURCES;
  2667. }
  2668. //
  2669. // Copy in the device objects so far
  2670. //
  2671. if ( relationCount ) {
  2672. RtlCopyMemory( relations->Objects,
  2673. ((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Objects,
  2674. relationCount * sizeof (PDEVICE_OBJECT));
  2675. }
  2676. relations->Count = relationCount + fdoExtension->NumPDOs;
  2677. //
  2678. // For each PDO on this bus add a pointer to the device relations
  2679. // buffer, being sure to take out a reference to that object.
  2680. // The PlugPlay system will dereference the object when it is done with
  2681. // it and free the device relations buffer.
  2682. //
  2683. for (entry = fdoExtension->PDOs.Flink;
  2684. entry != &fdoExtension->PDOs;
  2685. entry = entry->Flink, relationCount++) {
  2686. pdoExtension = CONTAINING_RECORD( entry, FDC_PDO_EXTENSION, PdoLink );
  2687. relations->Objects[relationCount] = pdoExtension->Self;
  2688. ObReferenceObject( pdoExtension->Self );
  2689. }
  2690. //
  2691. // Set up and pass the IRP further down the stack
  2692. //
  2693. Irp->IoStatus.Status = STATUS_SUCCESS;
  2694. if ( Irp->IoStatus.Information != 0) {
  2695. ExFreePool ((PVOID) Irp->IoStatus.Information);
  2696. }
  2697. Irp->IoStatus.Information = (UINT_PTR) relations;
  2698. IoSkipCurrentIrpStackLocation( Irp );
  2699. ntStatus = IoCallDriver( fdoExtension->TargetObject, Irp );
  2700. return ntStatus;
  2701. }
  2702. NTSTATUS
  2703. FdcConfigCallBack(
  2704. IN PVOID Context,
  2705. IN PUNICODE_STRING PathName,
  2706. IN INTERFACE_TYPE BusType,
  2707. IN ULONG BusNumber,
  2708. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  2709. IN CONFIGURATION_TYPE ControllerType,
  2710. IN ULONG ControllerNumber,
  2711. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  2712. IN CONFIGURATION_TYPE PeripheralType,
  2713. IN ULONG PeripheralNumber,
  2714. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  2715. )
  2716. /*++
  2717. Routine Description:
  2718. Arguments:
  2719. Context - Pointer to our FDO extension
  2720. PathName - unicode registry path. Not Used.
  2721. BusType - Internal, Isa, ...
  2722. BusNumber - Which bus if we are on a multibus system.
  2723. BusInformation - Configuration information about the bus. Not Used.
  2724. ControllerType - Should always be DiskController.
  2725. ControllerNumber - Which controller if there is more than one
  2726. controller in the system.
  2727. ControllerInformation - Array of pointers to the three pieces of
  2728. registry information.
  2729. PeripheralType - Should always be FloppyDiskPeripheral.
  2730. PeripheralNumber - Which floppy if this controller is maintaining
  2731. more than one.
  2732. PeripheralInformation - Arrya of pointers to the three pieces of
  2733. registry information.
  2734. Return Value:
  2735. STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
  2736. if it couldn't map the base csr or acquire the adapter object, or
  2737. all of the resource information couldn't be acquired.
  2738. --*/
  2739. {
  2740. PFDC_FDO_EXTENSION fdoExtension = (PFDC_FDO_EXTENSION)Context;
  2741. NTSTATUS ntStatus;
  2742. UNICODE_STRING pdoName;
  2743. WCHAR pdoNameBuffer[32];
  2744. PDEVICE_OBJECT newPdo;
  2745. PFDC_PDO_EXTENSION pdoExtension;
  2746. USHORT floppyCount;
  2747. FdcDump( FDCSHOW, ("FdcConfigCallBack:\n") );
  2748. //
  2749. // Verify that this floppy disk drive is on the current
  2750. // floppy disk controller.
  2751. //
  2752. {
  2753. USHORT i;
  2754. BOOLEAN thisController = FALSE;
  2755. PCM_FULL_RESOURCE_DESCRIPTOR controllerData =
  2756. (PCM_FULL_RESOURCE_DESCRIPTOR)
  2757. (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
  2758. ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);
  2759. for ( i = 0;
  2760. i < controllerData->PartialResourceList.Count;
  2761. i++ ) {
  2762. PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
  2763. &controllerData->PartialResourceList.PartialDescriptors[i];
  2764. FdcDump( FDCSHOW, ("FdcConfigCallBack: resource type = %x\n",partial->Type) );
  2765. switch (partial->Type) {
  2766. case CmResourceTypePort: {
  2767. PUCHAR address;
  2768. address = FdcGetControllerBase( BusType,
  2769. BusNumber,
  2770. partial->u.Port.Start,
  2771. partial->u.Port.Length,
  2772. (BOOLEAN)!!partial->Flags );
  2773. FdcDump( FDCSHOW, ("FdcConfigCallBack: DriveControl = %04x %04x\n",fdoExtension->ControllerAddress.DriveControl,address + (IsNEC_98 ? 4 : 2) ));
  2774. if ( fdoExtension->ControllerAddress.DriveControl == address + (IsNEC_98 ? 4 : 2)) {
  2775. thisController = TRUE;
  2776. }
  2777. }
  2778. break;
  2779. default:
  2780. break;
  2781. }
  2782. }
  2783. if ( !thisController ) {
  2784. return STATUS_SUCCESS;
  2785. }
  2786. }
  2787. floppyCount = (USHORT)(IoGetConfigurationInformation()->FloppyCount);
  2788. swprintf(pdoNameBuffer, L"\\Device\\FloppyPDO%d", floppyCount);
  2789. RtlInitUnicodeString(&pdoName, pdoNameBuffer);
  2790. ntStatus = IoCreateDevice( fdoExtension->Self->DriverObject,
  2791. sizeof(FDC_PDO_EXTENSION),
  2792. &pdoName,
  2793. FILE_DEVICE_DISK,
  2794. (FILE_REMOVABLE_MEDIA |
  2795. FILE_FLOPPY_DISKETTE |
  2796. FILE_DEVICE_SECURE_OPEN),
  2797. FALSE,
  2798. &newPdo);
  2799. if ( !NT_SUCCESS(ntStatus) ) {
  2800. FdcDump( FDCSHOW, ("FdcConfigCallBack: Error - %08x\n", ntStatus) );
  2801. return ntStatus;
  2802. }
  2803. FdcDump( FDCSHOW, ("FdcConfigCallBack: Created Device %d\n", floppyCount) );
  2804. IoGetConfigurationInformation()->FloppyCount += 1;
  2805. pdoExtension = (PFDC_PDO_EXTENSION) newPdo->DeviceExtension;
  2806. pdoExtension->TargetObject = fdoExtension->Self;
  2807. pdoExtension->IsFDO = FALSE;
  2808. pdoExtension->Self = newPdo;
  2809. pdoExtension->DeviceType = FloppyDiskDevice;
  2810. pdoExtension->ParentFdo = fdoExtension->Self;
  2811. pdoExtension->Instance = floppyCount + 1;
  2812. pdoExtension->Removed = FALSE; // no irp_mn_remove as of yet
  2813. fdoExtension->BusType = BusType;
  2814. fdoExtension->BusNumber = BusNumber;
  2815. fdoExtension->ControllerNumber = ControllerNumber;
  2816. pdoExtension->PeripheralNumber = PeripheralNumber;
  2817. newPdo->Flags |= DO_DIRECT_IO;
  2818. newPdo->Flags |= DO_POWER_PAGABLE;
  2819. newPdo->StackSize += fdoExtension->Self->StackSize;
  2820. newPdo->Flags &= ~DO_DEVICE_INITIALIZING;
  2821. InsertTailList(&fdoExtension->PDOs, &pdoExtension->PdoLink);
  2822. fdoExtension->NumPDOs++;
  2823. return STATUS_SUCCESS;
  2824. }
  2825. NTSTATUS
  2826. FdcCreateClose(
  2827. IN PDEVICE_OBJECT DeviceObject,
  2828. IN PIRP Irp
  2829. )
  2830. /*++
  2831. Routine Description:
  2832. This routine is called only rarely by the I/O system; it's mainly
  2833. for layered drivers to call. All it does is complete the IRP
  2834. successfully.
  2835. Arguments:
  2836. DeviceObject - a pointer to the object that represents the device
  2837. that I/O is to be done on.
  2838. Irp - a pointer to the I/O Request Packet for this request.
  2839. Return Value:
  2840. Always returns STATUS_SUCCESS, since this is a null operation.
  2841. --*/
  2842. {
  2843. UNREFERENCED_PARAMETER( DeviceObject );
  2844. FdcDump(
  2845. FDCSHOW,
  2846. ("FdcCreateClose...\n")
  2847. );
  2848. //
  2849. // Null operation. Do not give an I/O boost since
  2850. // no I/O was actually done. IoStatus.Information should be
  2851. // FILE_OPENED for an open; it's undefined for a close.
  2852. //
  2853. Irp->IoStatus.Status = STATUS_SUCCESS;
  2854. Irp->IoStatus.Information = FILE_OPENED;
  2855. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  2856. return STATUS_SUCCESS;
  2857. }
  2858. NTSTATUS
  2859. FdcInternalDeviceControl (
  2860. IN PDEVICE_OBJECT DeviceObject,
  2861. IN PIRP Irp
  2862. )
  2863. /*++
  2864. Routine Description:
  2865. Determine if this Pnp request is directed towards an FDO or a PDO and
  2866. pass the Irp on the the appropriate routine.
  2867. Arguments:
  2868. DeviceObject - a pointer to the object that represents the device
  2869. that I/O is to be done on.
  2870. Irp - a pointer to the I/O Request Packet for this request.
  2871. Return Value:
  2872. --*/
  2873. {
  2874. PIO_STACK_LOCATION irpSp;
  2875. NTSTATUS ntStatus = STATUS_SUCCESS;
  2876. PFDC_EXTENSION_HEADER extensionHeader;
  2877. KIRQL oldIrq;
  2878. irpSp = IoGetCurrentIrpStackLocation( Irp );
  2879. extensionHeader = (PFDC_EXTENSION_HEADER)DeviceObject->DeviceExtension;
  2880. if ( extensionHeader->IsFDO ) {
  2881. ntStatus = FdcFdoInternalDeviceControl( DeviceObject, Irp );
  2882. } else {
  2883. ntStatus = FdcPdoInternalDeviceControl( DeviceObject, Irp );
  2884. }
  2885. return ntStatus;
  2886. }
  2887. NTSTATUS
  2888. FdcPdoInternalDeviceControl(
  2889. IN PDEVICE_OBJECT DeviceObject,
  2890. IN PIRP Irp
  2891. )
  2892. /*++
  2893. Routine Description:
  2894. This routine is called by the I/O system to perform a device I/O
  2895. control function.
  2896. Most irps are put onto the driver queue (IoStartPacket). Some irps do not
  2897. require touching the hardware and are handled right here.
  2898. In some cases the irp cannot be put on the queue because it cannot be
  2899. completed at IRQL_DISPATCH_LEVEL. However, the driver queue must be empty
  2900. before the irp can be completed. In these cases, the queue is
  2901. 'synchronized' before completing the irp.
  2902. Arguments:
  2903. DeviceObject - a pointer to the object that represents the device
  2904. that I/O is to be done on.
  2905. Irp - a pointer to the I/O Request Packet for this request.
  2906. Return Value:
  2907. STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
  2908. STATUS_INVALID_DEVICE_REQUEST otherwise.
  2909. --*/
  2910. {
  2911. PFDC_PDO_EXTENSION pdoExtension;
  2912. PFDC_FDO_EXTENSION fdoExtension;
  2913. BOOLEAN isFDO;
  2914. NTSTATUS ntStatus;
  2915. PIO_STACK_LOCATION irpSp;
  2916. PIO_STACK_LOCATION nextIrpSp;
  2917. PISSUE_FDC_ADAPTER_BUFFER_PARMS adapterBufferParms;
  2918. pdoExtension = (PFDC_PDO_EXTENSION)DeviceObject->DeviceExtension;
  2919. fdoExtension = (PFDC_FDO_EXTENSION)pdoExtension->ParentFdo->DeviceExtension;
  2920. if ( pdoExtension->Removed) {
  2921. //
  2922. // This bus has received the PlugPlay remove IRP. It will no longer
  2923. // respond to external requests.
  2924. //
  2925. ntStatus = STATUS_DELETE_PENDING;
  2926. Irp->IoStatus.Status = ntStatus;
  2927. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  2928. return ntStatus;
  2929. }
  2930. irpSp = IoGetCurrentIrpStackLocation( Irp );
  2931. FdcDump( FDCSHOW,
  2932. ("FdcPdoInternalDeviceControl: %x\n",
  2933. irpSp->Parameters.DeviceIoControl.IoControlCode) );
  2934. switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
  2935. case IOCTL_DISK_INTERNAL_GET_ENABLER: {
  2936. if ( pdoExtension->DeviceType == FloppyControllerDevice ) {
  2937. *(PBOOLEAN)irpSp->Parameters.DeviceIoControl.Type3InputBuffer = TRUE;
  2938. } else {
  2939. *(PBOOLEAN)irpSp->Parameters.DeviceIoControl.Type3InputBuffer = FALSE;
  2940. }
  2941. ntStatus = STATUS_SUCCESS;
  2942. break;
  2943. }
  2944. case IOCTL_DISK_INTERNAL_GET_FDC_INFO:
  2945. FcReportFdcInformation( pdoExtension, fdoExtension, irpSp );
  2946. ntStatus = STATUS_SUCCESS;
  2947. break;
  2948. #ifdef TOSHIBAJ
  2949. case IOCTL_DISK_INTERNAL_ENABLE_3_MODE:
  2950. FdcDump(FDCSHOW,("IOCTL_Enable_3_MODE\n"));
  2951. ntStatus = FcFdcEnable3Mode( fdoExtension , Irp );
  2952. break;
  2953. case IOCTL_DISK_INTERNAL_AVAILABLE_3_MODE:
  2954. FdcDump(FDCSHOW,("IOCTL_Availabe_3_MODE\n"));
  2955. ntStatus = FcFdcAvailable3Mode( fdoExtension , Irp );
  2956. break;
  2957. #endif
  2958. default:
  2959. IoSkipCurrentIrpStackLocation( Irp );
  2960. //
  2961. // Call the driver and request the operation
  2962. //
  2963. return IoCallDriver( pdoExtension->TargetObject, Irp );
  2964. }
  2965. Irp->IoStatus.Status = ntStatus;
  2966. IoCompleteRequest( Irp, IO_DISK_INCREMENT );
  2967. return ntStatus;
  2968. }
  2969. NTSTATUS
  2970. FdcFdoInternalDeviceControl(
  2971. IN PDEVICE_OBJECT DeviceObject,
  2972. IN PIRP Irp
  2973. )
  2974. /*++
  2975. Routine Description:
  2976. This routine is called by the I/O system to perform a device I/O
  2977. control function.
  2978. Most irps are put onto the driver queue (IoStartPacket). Some irps do not
  2979. require touching the hardware and are handled right here.
  2980. In some cases the irp cannot be put on the queue because it cannot be
  2981. completed at IRQL_DISPATCH_LEVEL. However, the driver queue must be empty
  2982. before the irp can be completed. In these cases, the queue is
  2983. 'synchronized' before completing the irp.
  2984. Arguments:
  2985. DeviceObject - a pointer to the object that represents the device
  2986. that I/O is to be done on.
  2987. Irp - a pointer to the I/O Request Packet for this request.
  2988. Return Value:
  2989. STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
  2990. STATUS_INVALID_DEVICE_REQUEST otherwise.
  2991. --*/
  2992. {
  2993. PFDC_FDO_EXTENSION fdoExtension;
  2994. NTSTATUS ntStatus;
  2995. PIO_STACK_LOCATION irpSp;
  2996. PIO_STACK_LOCATION nextIrpSp;
  2997. PISSUE_FDC_ADAPTER_BUFFER_PARMS adapterBufferParms;
  2998. BOOLEAN powerQueueClear = FALSE;
  2999. PLIST_ENTRY deferredRequest;
  3000. PIRP currentIrp;
  3001. ULONG ioControlCode;
  3002. PFDC_DISK_CHANGE_PARMS fdcDiskChangeParms;
  3003. PUCHAR dataRate;
  3004. UCHAR tapeMode;
  3005. PUCHAR precomp;
  3006. PISSUE_FDC_COMMAND_PARMS issueCommandParms;
  3007. PSET_HD_BIT_PARMS setHdBitParams;
  3008. fdoExtension = (PFDC_FDO_EXTENSION)DeviceObject->DeviceExtension;
  3009. InterlockedIncrement( &fdoExtension->OutstandingRequests );
  3010. if ( fdoExtension->Removed ) {
  3011. //
  3012. // This device has received the PlugPlay remove IRP. It will no longer
  3013. // respond to external requests.
  3014. //
  3015. if ( InterlockedDecrement(&fdoExtension->OutstandingRequests ) == 0 ) {
  3016. KeSetEvent( &fdoExtension->RemoveEvent, 0, FALSE );
  3017. }
  3018. ntStatus = STATUS_DELETE_PENDING;
  3019. Irp->IoStatus.Status = ntStatus;
  3020. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  3021. return ntStatus;
  3022. }
  3023. //
  3024. // If we are in a non-working power state then just queue the irp
  3025. // for later execution.
  3026. //
  3027. if ( fdoExtension->CurrentPowerState > PowerSystemWorking ) {
  3028. ExInterlockedInsertTailList( &fdoExtension->PowerQueue,
  3029. &Irp->Tail.Overlay.ListEntry,
  3030. &fdoExtension->PowerQueueSpinLock );
  3031. ntStatus = STATUS_PENDING;
  3032. IoMarkIrpPending( Irp );
  3033. return ntStatus;
  3034. }
  3035. do {
  3036. deferredRequest = ExInterlockedRemoveHeadList( &fdoExtension->PowerQueue,
  3037. &fdoExtension->PowerQueueSpinLock );
  3038. if ( deferredRequest == NULL ) {
  3039. currentIrp = Irp;
  3040. powerQueueClear = TRUE;
  3041. } else {
  3042. currentIrp = CONTAINING_RECORD( deferredRequest, IRP, Tail.Overlay.ListEntry );
  3043. }
  3044. irpSp = IoGetCurrentIrpStackLocation( currentIrp );
  3045. FdcDump( FDCSHOW,
  3046. ("FdcFdoInternalDeviceControl: %x\n",
  3047. irpSp->Parameters.DeviceIoControl.IoControlCode) );
  3048. ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
  3049. //
  3050. // GET_ENABLER and GET_FDC_INFO are handled in the PDO, not the FDO.
  3051. //
  3052. if ( ioControlCode == IOCTL_DISK_INTERNAL_GET_ENABLER ||
  3053. ioControlCode == IOCTL_DISK_INTERNAL_GET_FDC_INFO ) {
  3054. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  3055. //
  3056. // If the controller is not acquired (in use) then then only
  3057. // operation that is allowed is to acquire the fdc.
  3058. //
  3059. } else if ( !fdoExtension->ControllerInUse &&
  3060. ioControlCode != IOCTL_DISK_INTERNAL_ACQUIRE_FDC ) {
  3061. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  3062. } else {
  3063. switch ( ioControlCode ) {
  3064. case IOCTL_DISK_INTERNAL_ACQUIRE_FDC:
  3065. //
  3066. // Try to Acquire the Fdc. If the Fdc is busy, this call will
  3067. // time out.
  3068. //
  3069. ntStatus = FcAcquireFdc(
  3070. fdoExtension,
  3071. (PLARGE_INTEGER)irpSp->
  3072. Parameters.DeviceIoControl.Type3InputBuffer );
  3073. //
  3074. // Return the device object of the last device that called this
  3075. // driver. This can be used to determine if any other drivers
  3076. // have messed with the fdc since it was last acquired.
  3077. //
  3078. if ( NT_SUCCESS(ntStatus) ) {
  3079. irpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  3080. fdoExtension->LastDeviceObject;
  3081. }
  3082. break;
  3083. case IOCTL_DISK_INTERNAL_ENABLE_FDC_DEVICE:
  3084. //
  3085. // Turn the motor on and select a floppy channel
  3086. //
  3087. ntStatus = FcTurnOnMotor( fdoExtension, irpSp );
  3088. break;
  3089. case IOCTL_DISK_INTERNAL_ISSUE_FDC_COMMAND:
  3090. issueCommandParms =
  3091. (PISSUE_FDC_COMMAND_PARMS)
  3092. irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3093. ntStatus = FcIssueCommand( fdoExtension,
  3094. issueCommandParms->FifoInBuffer,
  3095. issueCommandParms->FifoOutBuffer,
  3096. issueCommandParms->IoHandle,
  3097. issueCommandParms->IoOffset,
  3098. issueCommandParms->TransferBytes );
  3099. break;
  3100. case IOCTL_DISK_INTERNAL_ISSUE_FDC_COMMAND_QUEUED:
  3101. IoMarkIrpPending( Irp );
  3102. IoStartPacket( DeviceObject,
  3103. Irp,
  3104. NULL,
  3105. NULL );
  3106. ntStatus = STATUS_PENDING;
  3107. break;
  3108. case IOCTL_DISK_INTERNAL_RESET_FDC:
  3109. ntStatus = FcInitializeControllerHardware( fdoExtension,
  3110. DeviceObject );
  3111. break;
  3112. case IOCTL_DISK_INTERNAL_RELEASE_FDC:
  3113. ntStatus = FcReleaseFdc( fdoExtension );
  3114. //
  3115. // Save the DeviceObject of the releasing device. This is
  3116. // returned with the subsequent acquire fdc request and
  3117. // can be used to determine whether the floppy controller
  3118. // has been messed with between release and acquisition
  3119. //
  3120. if ( NT_SUCCESS(ntStatus) ) {
  3121. fdoExtension->LastDeviceObject =
  3122. irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3123. }
  3124. break;
  3125. case IOCTL_DISK_INTERNAL_GET_ADAPTER_BUFFER:
  3126. //
  3127. // Allocate an MDL for the passed in buffer.
  3128. //
  3129. adapterBufferParms = (PISSUE_FDC_ADAPTER_BUFFER_PARMS)
  3130. irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3131. adapterBufferParms->Handle =
  3132. IoAllocateMdl( adapterBufferParms->IoBuffer,
  3133. adapterBufferParms->TransferBytes,
  3134. FALSE,
  3135. FALSE,
  3136. NULL );
  3137. if ( adapterBufferParms->Handle == NULL ) {
  3138. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  3139. } else {
  3140. MmBuildMdlForNonPagedPool( adapterBufferParms->Handle );
  3141. ntStatus = STATUS_SUCCESS;
  3142. }
  3143. break;
  3144. case IOCTL_DISK_INTERNAL_FLUSH_ADAPTER_BUFFER:
  3145. //
  3146. // Free the MDL
  3147. //
  3148. adapterBufferParms = (PISSUE_FDC_ADAPTER_BUFFER_PARMS)
  3149. irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3150. if ( adapterBufferParms->Handle != NULL ) {
  3151. IoFreeMdl( adapterBufferParms->Handle );
  3152. }
  3153. ntStatus = STATUS_SUCCESS;
  3154. break;
  3155. case IOCTL_DISK_INTERNAL_FDC_START_READ:
  3156. case IOCTL_DISK_INTERNAL_FDC_START_WRITE:
  3157. ntStatus = STATUS_SUCCESS;
  3158. if ( fdoExtension->FdcEnablerSupported ) {
  3159. FDC_MODE_SELECT fdcModeSelect;
  3160. fdcModeSelect.structSize = sizeof(fdcModeSelect);
  3161. //
  3162. // Reading from the media means writing to DMA memory and
  3163. // visa-versa for writing to the media.
  3164. //
  3165. if ( irpSp->Parameters.DeviceIoControl.IoControlCode ==
  3166. IOCTL_DISK_INTERNAL_FDC_START_READ ) {
  3167. fdcModeSelect.DmaDirection = FDC_WRITE_TO_MEMORY;
  3168. } else {
  3169. fdcModeSelect.DmaDirection = FDC_READ_FROM_MEMORY;
  3170. }
  3171. ntStatus = FcFdcEnabler(
  3172. fdoExtension->FdcEnablerDeviceObject,
  3173. IOCTL_SET_FDC_MODE,
  3174. &fdcModeSelect);
  3175. }
  3176. break;
  3177. case IOCTL_DISK_INTERNAL_DISABLE_FDC_DEVICE:
  3178. ntStatus = FcTurnOffMotor( fdoExtension );
  3179. break;
  3180. case IOCTL_DISK_INTERNAL_GET_FDC_DISK_CHANGE:
  3181. FdcDump(FDCINFO, ("Fdc: Read Disk Change\n") );
  3182. fdcDiskChangeParms =
  3183. (PFDC_DISK_CHANGE_PARMS)irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3184. if (IsNEC_98) {
  3185. if((fdoExtension->ResultStatus0[fdcDiskChangeParms->DriveOnValue] &
  3186. STREG0_END_MASK) == STREG0_END_DRIVE_NOT_READY){
  3187. fdcDiskChangeParms->DriveStatus = DSKCHG_DISKETTE_REMOVED;
  3188. } else {
  3189. fdoExtension->ResultStatus0[fdcDiskChangeParms->DriveOnValue] = 0;
  3190. fdcDiskChangeParms->DriveStatus = DSKCHG_RESERVED;
  3191. }
  3192. } else { // (IsNEC_98)
  3193. fdcDiskChangeParms->DriveStatus = READ_CONTROLLER(
  3194. fdoExtension->ControllerAddress.DRDC.DiskChange );
  3195. //
  3196. // If we just waked up from hibernation, simulate a disk
  3197. // change event so the upper levels will be sure to check
  3198. // this disk.
  3199. //
  3200. if ( fdoExtension->WakeUp ) {
  3201. fdcDiskChangeParms->DriveStatus |= DSKCHG_DISKETTE_REMOVED;
  3202. fdoExtension->WakeUp = FALSE;
  3203. }
  3204. } // (IsNEC_98)
  3205. ntStatus = STATUS_SUCCESS;
  3206. break;
  3207. case IOCTL_DISK_INTERNAL_SET_FDC_DATA_RATE:
  3208. if (IsNEC_98) {
  3209. //
  3210. // NEC98 have no function and have no DRDC.DataRate register.
  3211. //
  3212. } else { // (IsNEC_98)
  3213. dataRate =
  3214. (PUCHAR)irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3215. FdcDump(FDCINFO, ("Fdc: Write Data Rate: %x\n", *dataRate) );
  3216. WRITE_CONTROLLER( fdoExtension->ControllerAddress.DRDC.DataRate,
  3217. *dataRate );
  3218. } // (IsNEC_98)
  3219. ntStatus = STATUS_SUCCESS;
  3220. break;
  3221. case IOCTL_DISK_INTERNAL_SET_FDC_TAPE_MODE:
  3222. if (IsNEC_98) {
  3223. //
  3224. // NEC98 have no Tape register.
  3225. //
  3226. } else { // (IsNEC_98)
  3227. tapeMode = READ_CONTROLLER( fdoExtension->ControllerAddress.Tape );
  3228. tapeMode &= 0xfc;
  3229. tapeMode |=
  3230. *((PUCHAR)irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  3231. FdcDump(FDCINFO,
  3232. ("Fdc: Write Tape Mode Register: %x\n", tapeMode)
  3233. );
  3234. WRITE_CONTROLLER(
  3235. fdoExtension->ControllerAddress.Tape,
  3236. tapeMode );
  3237. } // (IsNEC_98)
  3238. ntStatus = STATUS_SUCCESS;
  3239. break;
  3240. case IOCTL_DISK_INTERNAL_SET_FDC_PRECOMP:
  3241. precomp = (PUCHAR)irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3242. FdcDump(FDCINFO,
  3243. ("Fdc: Write Precomp: %x\n", *precomp)
  3244. );
  3245. WRITE_CONTROLLER(
  3246. fdoExtension->ControllerAddress.Status,
  3247. *precomp );
  3248. ntStatus = STATUS_SUCCESS;
  3249. break;
  3250. case IOCTL_DISK_INTERNAL_SET_HD_BIT:
  3251. if (IsNEC_98) {
  3252. FdcDump(FDCINFO,
  3253. ("Fdc: Set Hd Bit: \n")
  3254. );
  3255. setHdBitParams = (PSET_HD_BIT_PARMS)irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3256. FdcHdbit(DeviceObject, fdoExtension, setHdBitParams);
  3257. ntStatus = STATUS_SUCCESS;
  3258. break;
  3259. } // (IsNEC_98)
  3260. //
  3261. // If not NEC98, then pass through to "default:".
  3262. //
  3263. default:
  3264. //
  3265. // Mark the Irp pending and queue it.
  3266. //
  3267. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  3268. break;
  3269. }
  3270. }
  3271. if ( ntStatus != STATUS_PENDING ) {
  3272. if ( InterlockedDecrement(&fdoExtension->OutstandingRequests ) == 0 ) {
  3273. KeSetEvent( &fdoExtension->RemoveEvent, 0, FALSE );
  3274. }
  3275. currentIrp->IoStatus.Status = ntStatus;
  3276. IoCompleteRequest( currentIrp, IO_DISK_INCREMENT );
  3277. }
  3278. } while ( !powerQueueClear );
  3279. return ntStatus;
  3280. }
  3281. VOID
  3282. FcReportFdcInformation(
  3283. IN PFDC_PDO_EXTENSION PdoExtension,
  3284. IN PFDC_FDO_EXTENSION FdoExtension,
  3285. IN OUT PIO_STACK_LOCATION IrpSp
  3286. )
  3287. /*++
  3288. Routine Description:
  3289. This routine reports information about the Floppy Disk Controller
  3290. that a higher level driver might need; primarily information
  3291. regarding the DMA Adapter.
  3292. Arguments:
  3293. fdoExtension - Pointer to this device's extension data.
  3294. IrpSp - Pointer to the current Irp
  3295. Return Value:
  3296. STATUS_SUCCESS
  3297. --*/
  3298. {
  3299. PFDC_INFO fdcInfo;
  3300. ULONG bufferCount;
  3301. ULONG bufferSize;
  3302. ULONG i;
  3303. FdcDump( FDCINFO, ("Fdc: Report FDC Information\n") );
  3304. fdcInfo = (PFDC_INFO)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3305. //
  3306. // save the requested buffer count and buffer size.
  3307. //
  3308. bufferCount = fdcInfo->BufferCount;
  3309. bufferSize = fdcInfo->BufferSize;
  3310. //
  3311. // fill in the floppy controller hardware information
  3312. //
  3313. fdcInfo->BusType = FdoExtension->BusType;
  3314. fdcInfo->BusNumber = FdoExtension->BusNumber;
  3315. fdcInfo->ControllerNumber = FdoExtension->ControllerNumber;
  3316. if (IsNEC_98) {
  3317. UCHAR floppyEquip;
  3318. ULONG disketteCount = 0;
  3319. floppyEquip = FdoExtension->FloppyEquip;
  3320. //
  3321. // Make PeripheralNumber.
  3322. //
  3323. for (i = 0 ; i < 4 ; i++) {
  3324. if ((floppyEquip & 0x1) != 0) {
  3325. disketteCount++;
  3326. if(disketteCount > PdoExtension->PeripheralNumber){
  3327. break;
  3328. }
  3329. }
  3330. floppyEquip = floppyEquip >> 1;
  3331. }
  3332. fdcInfo->UnitNumber = (UCHAR)i;
  3333. } else {
  3334. //
  3335. // Only NEC98 is using it now, put Zero into UnitNumber.
  3336. //
  3337. fdcInfo->UnitNumber = 0;
  3338. }
  3339. fdcInfo->PeripheralNumber = PdoExtension->PeripheralNumber;
  3340. fdcInfo->FloppyControllerType = FdoExtension->FdcType;
  3341. fdcInfo->SpeedsAvailable = FdoExtension->FdcSpeeds;
  3342. fdcInfo->MaxTransferSize = FdoExtension->NumberOfMapRegisters * PAGE_SIZE;
  3343. fdcInfo->BufferSize = 0;
  3344. fdcInfo->BufferCount = 0;
  3345. if ( bufferSize <= FdoExtension->BufferSize ) {
  3346. fdcInfo->BufferSize = bufferSize;
  3347. fdcInfo->BufferCount = MIN( bufferCount,
  3348. FdoExtension->BufferCount );
  3349. FdoExtension->BuffersRequested = MAX( fdcInfo->BufferCount,
  3350. FdoExtension->BuffersRequested );
  3351. }
  3352. for ( i = 0 ; i < fdcInfo->BufferCount ; i++ ) {
  3353. fdcInfo->BufferAddress[i].Logical =
  3354. FdoExtension->TransferBuffers[i].Logical;
  3355. fdcInfo->BufferAddress[i].Virtual =
  3356. FdoExtension->TransferBuffers[i].Virtual;
  3357. }
  3358. }
  3359. VOID
  3360. FdcStartIo(
  3361. IN PDEVICE_OBJECT DeviceObject,
  3362. IN PIRP Irp
  3363. )
  3364. /*++
  3365. Routine Description:
  3366. Arguments:
  3367. DeviceObject - a pointer to the object that represents the device
  3368. that I/O is to be done on.
  3369. Irp - a pointer to the I/O Request Packet for this request.
  3370. Return Value:
  3371. --*/
  3372. {
  3373. PIO_STACK_LOCATION irpSp;
  3374. NTSTATUS ntStatus;
  3375. ULONG formatExParametersSize;
  3376. PUCHAR diskChange;
  3377. PUCHAR dataRate;
  3378. PUCHAR tapeMode;
  3379. PUCHAR precomp;
  3380. PFDC_FDO_EXTENSION fdoExtension;
  3381. PISSUE_FDC_COMMAND_PARMS issueCommandParms;
  3382. PKDEVICE_QUEUE_ENTRY request;
  3383. FdcDump( FDCSHOW, ("FdcStartIo...\n") );
  3384. fdoExtension = DeviceObject->DeviceExtension;
  3385. irpSp = IoGetCurrentIrpStackLocation( Irp );
  3386. ntStatus = STATUS_SUCCESS;
  3387. switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
  3388. case IOCTL_DISK_INTERNAL_ISSUE_FDC_COMMAND_QUEUED:
  3389. issueCommandParms =
  3390. (PISSUE_FDC_COMMAND_PARMS)
  3391. irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3392. if ( CommandTable[issueCommandParms->FifoInBuffer[0] &
  3393. COMMAND_MASK].InterruptExpected ) {
  3394. fdoExtension->CurrentDeviceObject = DeviceObject;
  3395. fdoExtension->AllowInterruptProcessing = TRUE;
  3396. fdoExtension->CommandHasResultPhase = FALSE;
  3397. fdoExtension->InterruptTimer =
  3398. issueCommandParms->TimeOut ?
  3399. issueCommandParms->TimeOut + 1 : START_TIMER;
  3400. fdoExtension->CurrentIrp = Irp;
  3401. }
  3402. ntStatus = FcStartCommand( fdoExtension,
  3403. issueCommandParms->FifoInBuffer,
  3404. issueCommandParms->FifoOutBuffer,
  3405. issueCommandParms->IoHandle,
  3406. issueCommandParms->IoOffset,
  3407. issueCommandParms->TransferBytes,
  3408. FALSE );
  3409. if ( NT_SUCCESS( ntStatus )) {
  3410. if ( CommandTable[issueCommandParms->FifoInBuffer[0] &
  3411. COMMAND_MASK].InterruptExpected ) {
  3412. ntStatus = STATUS_PENDING;
  3413. } else {
  3414. ntStatus = FcFinishCommand(
  3415. fdoExtension,
  3416. issueCommandParms->FifoInBuffer,
  3417. issueCommandParms->FifoOutBuffer,
  3418. issueCommandParms->IoHandle,
  3419. issueCommandParms->IoOffset,
  3420. issueCommandParms->TransferBytes,
  3421. FALSE );
  3422. }
  3423. }
  3424. break;
  3425. default: {
  3426. FdcDump(
  3427. FDCDBGP,
  3428. ("Fdc: invalid device request %x\n",
  3429. irpSp->Parameters.DeviceIoControl.IoControlCode)
  3430. );
  3431. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  3432. break;
  3433. }
  3434. }
  3435. if ( ntStatus != STATUS_PENDING ) {
  3436. Irp->IoStatus.Status = ntStatus;
  3437. if (!NT_SUCCESS( ntStatus ) &&
  3438. IoIsErrorUserInduced( ntStatus )) {
  3439. IoSetHardErrorOrVerifyDevice( Irp, DeviceObject );
  3440. }
  3441. IoStartNextPacket( DeviceObject, FALSE );
  3442. }
  3443. }
  3444. NTSTATUS
  3445. FcAcquireFdc(
  3446. IN PFDC_FDO_EXTENSION FdoExtension,
  3447. IN PLARGE_INTEGER TimeOut
  3448. )
  3449. /*++
  3450. Routine Description:
  3451. This routine acquires the floppy disk controller. This includes
  3452. allocating the adapter channel and connecting the interrupt.
  3453. NOTE - This is where the sharing mechanism will be put into
  3454. this driver. That is, higher level drivers will 'reserve' the
  3455. floppy controller with this ioctl. Subsequent calls to this driver
  3456. that are not from the 'reserving' drive will be rejected with a
  3457. BUSY status.
  3458. Arguments:
  3459. DeviceObject - Device object for the current device
  3460. Return Value:
  3461. STATUS_DEVICE_BUSY if we don't have the controller, otherwise
  3462. STATUS_SUCCESS
  3463. --*/
  3464. {
  3465. NTSTATUS ntStatus;
  3466. FdcDump(FDCINFO,
  3467. ("Fdc: Acquire the Floppy Controller\n")
  3468. );
  3469. //
  3470. // Wait for the Fdc, either from the enabler or directly here. Semaphores
  3471. // are used to synchronize usage of the Fdc hardware. If somebody else is
  3472. // using the floppy controller now we must wait for them to finish. If
  3473. // this takes too long we will just let the caller know that the device is
  3474. // busy.
  3475. //
  3476. if (FdoExtension->FdcEnablerSupported) {
  3477. ntStatus = FcFdcEnabler( FdoExtension->FdcEnablerDeviceObject,
  3478. // IOCTL_ACQUIRE_FDC, // For spelling miss in flpyenbl.h
  3479. IOCTL_AQUIRE_FDC,
  3480. TimeOut);
  3481. } else {
  3482. ntStatus = KeWaitForSingleObject( FdoExtension->AcquireEvent,
  3483. Executive,
  3484. KernelMode,
  3485. FALSE,
  3486. TimeOut );
  3487. if ( ntStatus == STATUS_TIMEOUT ) {
  3488. ntStatus = STATUS_DEVICE_BUSY;
  3489. }
  3490. }
  3491. if ( NT_SUCCESS(ntStatus) ) {
  3492. //
  3493. // Lock down the driver code in memory.
  3494. //
  3495. FDC_PAGE_RESET_DRIVER_WITH_MUTEX;
  3496. //
  3497. // Allocate the adapter channel
  3498. //
  3499. FcAllocateAdapterChannel( FdoExtension );
  3500. IoStartTimer(FdoExtension->Self);
  3501. if (IsNEC_98) {
  3502. //
  3503. // NEC98's FDD driver can't not disconnect interrupt,
  3504. // and can't not page out this driver. Because when a FD is inserted in FDD or
  3505. // is ejected from FDD, then H/W calls FDD driver's interrupt routine.
  3506. //
  3507. ntStatus = STATUS_SUCCESS;
  3508. } else { // (IsNEC_98)
  3509. //
  3510. // Connect the Interrupt
  3511. //
  3512. ntStatus = IoConnectInterrupt(&FdoExtension->InterruptObject,
  3513. FdcInterruptService,
  3514. FdoExtension,
  3515. NULL,
  3516. FdoExtension->ControllerVector,
  3517. FdoExtension->ControllerIrql,
  3518. FdoExtension->ControllerIrql,
  3519. FdoExtension->InterruptMode,
  3520. FdoExtension->SharableVector,
  3521. FdoExtension->ProcessorMask,
  3522. FdoExtension->SaveFloatState);
  3523. } // (IsNEC_98)
  3524. if ( NT_SUCCESS( ntStatus ) ) {
  3525. FdoExtension->ControllerInUse = TRUE;
  3526. } else {
  3527. FcFreeAdapterChannel( FdoExtension );
  3528. IoStopTimer(FdoExtension->Self);
  3529. }
  3530. } else {
  3531. ntStatus = STATUS_DEVICE_BUSY;
  3532. }
  3533. return ntStatus;
  3534. }
  3535. NTSTATUS
  3536. FcReleaseFdc(
  3537. IN PFDC_FDO_EXTENSION FdoExtension
  3538. )
  3539. /*++
  3540. Routine Description:
  3541. This routine releaese the floppy disk controller. This includes
  3542. freeing the adapter channel and disconnecting the interrupt.
  3543. NOTE - This is where the sharing mechanism will be put into
  3544. this driver. That is, higher level drivers will 'reserve' the
  3545. floppy controller with this ioctl. Subsequent calls to this driver
  3546. that are not from the 'reserving' drive will be rejected with a
  3547. BUSY status.
  3548. Arguments:
  3549. fdoExtension - Pointer to this device's extension data.
  3550. Return Value:
  3551. STATUS_DEVICE_BUSY if we don't have the controller, otherwise
  3552. STATUS_SUCCESS
  3553. --*/
  3554. {
  3555. FdcDump(FDCINFO, ("Fdc: Release the Floppy Controller\n") );
  3556. //
  3557. // Free the Adapter Channel
  3558. //
  3559. FcFreeAdapterChannel( FdoExtension );
  3560. FdoExtension->AllowInterruptProcessing = FALSE;
  3561. FdoExtension->ControllerInUse = FALSE;
  3562. if (IsNEC_98) {
  3563. //
  3564. // NEC98's FDD driver can't not disconnect interrupt,
  3565. // and can't not page out this driver. Because when a FD is inserted in FDD or
  3566. // is ejected from FDD, then H/W calls FDD driver's interrupt routine.
  3567. //
  3568. } else { // (IsNEC_98)
  3569. //
  3570. // Disconnect the Interrupt
  3571. //
  3572. IoDisconnectInterrupt(FdoExtension->InterruptObject);
  3573. } // (IsNEC_98)
  3574. IoStopTimer(FdoExtension->Self);
  3575. FDC_PAGE_ENTIRE_DRIVER_WITH_MUTEX;
  3576. //
  3577. // Release the Fdc Enabler card if there is one. Otherwise, set the
  3578. // floppy synchronization event.
  3579. //
  3580. if (FdoExtension->FdcEnablerSupported) {
  3581. FcFdcEnabler( FdoExtension->FdcEnablerDeviceObject,
  3582. IOCTL_RELEASE_FDC,
  3583. NULL);
  3584. } else {
  3585. KeSetEvent( FdoExtension->AcquireEvent,
  3586. (KPRIORITY) 0,
  3587. FALSE );
  3588. }
  3589. return STATUS_SUCCESS;
  3590. }
  3591. NTSTATUS
  3592. FcTurnOnMotor(
  3593. IN PFDC_FDO_EXTENSION FdoExtension,
  3594. IN OUT PIO_STACK_LOCATION IrpSp
  3595. )
  3596. /*++
  3597. Routine Description:
  3598. This routine turns on the motor if it not already running.
  3599. Arguments:
  3600. fdoExtension - Pointer to this device's extension data.
  3601. IrpSp - Pointer to the current Irp
  3602. Return Value:
  3603. STATUS_DEVICE_BUSY if we don't have the controller, otherwise
  3604. STATUS_SUCCESS
  3605. --*/
  3606. {
  3607. UCHAR driveStatus;
  3608. UCHAR newStatus;
  3609. LARGE_INTEGER motorOnDelay;
  3610. PFDC_ENABLE_PARMS fdcEnableParms;
  3611. USHORT lpc;
  3612. UCHAR resultStatus0Save[4];
  3613. fdcEnableParms =
  3614. (PFDC_ENABLE_PARMS)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  3615. FdcDump(FDCINFO,
  3616. ("Fdc: Turn Motor On: %x\n",fdcEnableParms->DriveOnValue)
  3617. );
  3618. driveStatus = FdoExtension->DriveControlImage;
  3619. if (IsNEC_98) {
  3620. newStatus = DRVCTL_MOTOR_MASK;
  3621. } else { // (IsNEC_98)
  3622. newStatus = fdcEnableParms->DriveOnValue |
  3623. DRVCTL_ENABLE_CONTROLLER |
  3624. DRVCTL_ENABLE_DMA_AND_INTERRUPTS;
  3625. } // (IsNEC_98)
  3626. if ( driveStatus != newStatus ) {
  3627. // If the drive is not on then check to see if we have
  3628. // the controller. Otherwise we assume that we have
  3629. // the controller since we give it up only when we
  3630. // turn off the motor.
  3631. if (IsNEC_98) {
  3632. if(FdoExtension->MotorRunning == 0){
  3633. //
  3634. // save status
  3635. //
  3636. for(lpc=0;lpc<4;lpc++){
  3637. resultStatus0Save[lpc] = FdoExtension->ResultStatus0[lpc];
  3638. }
  3639. FdcDump(
  3640. FDCSHOW,
  3641. ("Floppy: Turn on motor!\n")
  3642. );
  3643. FdoExtension->DriveControlImage = 0x18;
  3644. FdoExtension->DriveControlImage |= DRVCTL_AI_ENABLE;
  3645. WRITE_CONTROLLER(
  3646. FdoExtension->ControllerAddress.DriveControl,
  3647. FdoExtension->DriveControlImage );
  3648. FdoExtension->MotorRunning = 1;
  3649. }
  3650. } else { // (IsNEC_98)
  3651. if (!FdoExtension->CurrentInterrupt) {
  3652. FdoExtension->CurrentInterrupt = TRUE;
  3653. driveStatus = FdoExtension->DriveControlImage;
  3654. }
  3655. FdoExtension->AllowInterruptProcessing = TRUE;
  3656. FdoExtension->DriveControlImage = newStatus;
  3657. WRITE_CONTROLLER(
  3658. FdoExtension->ControllerAddress.DriveControl,
  3659. FdoExtension->DriveControlImage );
  3660. } // (IsNEC_98)
  3661. if (fdcEnableParms->TimeToWait > 0) {
  3662. if (IsNEC_98) {
  3663. //
  3664. // check if motor is on or not.
  3665. //
  3666. if(FdoExtension->MotorRunning == 1){
  3667. FdoExtension->MotorRunning = 2;
  3668. motorOnDelay.LowPart = (unsigned long)(- ( 10 * 1000 * 1000 ));
  3669. motorOnDelay.HighPart = -1;
  3670. KeDelayExecutionThread( KernelMode, FALSE, &motorOnDelay );
  3671. //
  3672. // after sense, restore status
  3673. //
  3674. for(lpc=0;lpc<4;lpc++){
  3675. FdoExtension->ResultStatus0[lpc] = resultStatus0Save[lpc];
  3676. }
  3677. }
  3678. } else { // (IsNEC_98)
  3679. motorOnDelay.LowPart =
  3680. - ( 10 * 1000 * fdcEnableParms->TimeToWait );
  3681. motorOnDelay.HighPart = -1;
  3682. FdoExtension->LastMotorSettleTime = motorOnDelay;
  3683. KeDelayExecutionThread( KernelMode, FALSE, &motorOnDelay );
  3684. } // (IsNEC_98)
  3685. }
  3686. fdcEnableParms->MotorStarted = TRUE;
  3687. }
  3688. return STATUS_SUCCESS;
  3689. }
  3690. NTSTATUS
  3691. FcTurnOffMotor(
  3692. IN PFDC_FDO_EXTENSION FdoExtension
  3693. )
  3694. /*++
  3695. Routine Description:
  3696. This routine turns off all motors. By default, Drive A is left selected
  3697. by this routine since it is not possible to deselect all drives. On a
  3698. Power PC, drive D is left selected.
  3699. Arguments:
  3700. fdoExtension - Supplies the fdc extension.
  3701. Return Value:
  3702. None.
  3703. --*/
  3704. {
  3705. FdcDump(FDCINFO,
  3706. ("Fdc: Turn Motor Off\n")
  3707. );
  3708. if (IsNEC_98) {
  3709. if (FdoExtension->MotorRunning != 0){
  3710. FdoExtension->DriveControlImage
  3711. = READ_CONTROLLER(FdoExtension->ControllerAddress.DriveControl);
  3712. FdoExtension->DriveControlImage = 0x10;
  3713. FdoExtension->DriveControlImage |= DRVCTL_AI_ENABLE;
  3714. WRITE_CONTROLLER(
  3715. FdoExtension->ControllerAddress.DriveControl,
  3716. FdoExtension->DriveControlImage );
  3717. if (FdoExtension->CurrentInterrupt) {
  3718. FdoExtension->CurrentInterrupt = FALSE;
  3719. KeSetEvent(FdoExtension->AcquireEvent,
  3720. (KPRIORITY) 0,
  3721. FALSE);
  3722. }
  3723. FdoExtension->MotorRunning = 0;
  3724. }
  3725. } else { // (IsNEC_98)
  3726. FdoExtension->DriveControlImage =
  3727. DRVCTL_ENABLE_DMA_AND_INTERRUPTS +
  3728. #ifdef _PPC_
  3729. DRVCTL_DRIVE_MASK +
  3730. #endif
  3731. DRVCTL_ENABLE_CONTROLLER;
  3732. WRITE_CONTROLLER(
  3733. FdoExtension->ControllerAddress.DriveControl,
  3734. FdoExtension->DriveControlImage );
  3735. } // (IsNEC_98)
  3736. return STATUS_SUCCESS;
  3737. }
  3738. VOID
  3739. FcAllocateAdapterChannel(
  3740. IN OUT PFDC_FDO_EXTENSION FdoExtension
  3741. )
  3742. /*++
  3743. Routine Description:
  3744. This routine allocates an adapter channel. The caller of
  3745. IoAllocateAdapterChannel routine must wait for the
  3746. 'AllocateAdapterChannelEvent' to be signalled before trying to use the
  3747. adapter channel.
  3748. Arguments:
  3749. fdoExtension - Supplies the fdc extension.
  3750. Return Value:
  3751. None.
  3752. --*/
  3753. {
  3754. KIRQL oldIrql;
  3755. if ( (FdoExtension->AdapterChannelRefCount)++ ) {
  3756. return;
  3757. }
  3758. KeResetEvent( &FdoExtension->AllocateAdapterChannelEvent );
  3759. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  3760. IoAllocateAdapterChannel( FdoExtension->AdapterObject,
  3761. FdoExtension->Self,
  3762. FdoExtension->NumberOfMapRegisters,
  3763. FdcAllocateAdapterChannel,
  3764. FdoExtension );
  3765. KeLowerIrql( oldIrql );
  3766. KeWaitForSingleObject( &FdoExtension->AllocateAdapterChannelEvent,
  3767. Executive,
  3768. KernelMode,
  3769. FALSE,
  3770. NULL);
  3771. }
  3772. VOID
  3773. FcFreeAdapterChannel(
  3774. IN OUT PFDC_FDO_EXTENSION FdoExtension
  3775. )
  3776. /*++
  3777. Routine Description:
  3778. This routine frees the previously allocated adapter channel.
  3779. Arguments:
  3780. fdoExtension - Supplies the fdc extension.
  3781. Return Value:
  3782. None.
  3783. --*/
  3784. {
  3785. KIRQL oldIrql;
  3786. if ( --(FdoExtension->AdapterChannelRefCount) ) {
  3787. return;
  3788. }
  3789. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  3790. IoFreeAdapterChannel( FdoExtension->AdapterObject );
  3791. KeLowerIrql( oldIrql );
  3792. }
  3793. IO_ALLOCATION_ACTION
  3794. FdcAllocateAdapterChannel(
  3795. IN PDEVICE_OBJECT DeviceObject,
  3796. IN PIRP Irp,
  3797. IN PVOID MapRegisterBase,
  3798. IN PVOID Context
  3799. )
  3800. /*++
  3801. Routine Description:
  3802. This DPC is called whenever the fdc.sys driver is trying to allocate
  3803. the adapter channel. It saves the MapRegisterBase in the controller data
  3804. area, and sets the AllocateAdapterChannelEvent to awaken the thread.
  3805. Arguments:
  3806. DeviceObject - unused.
  3807. Irp - unused.
  3808. MapRegisterBase - the base of the map registers that can be used
  3809. for this transfer.
  3810. Context - a pointer to our controller data area.
  3811. Return Value:
  3812. Returns Allocation Action 'KeepObject' which means that the adapter
  3813. object will be held for now (to be released explicitly later).
  3814. --*/
  3815. {
  3816. PFDC_FDO_EXTENSION fdoExtension = Context;
  3817. UNREFERENCED_PARAMETER( DeviceObject );
  3818. UNREFERENCED_PARAMETER( Irp );
  3819. fdoExtension->MapRegisterBase = MapRegisterBase;
  3820. KeSetEvent( &fdoExtension->AllocateAdapterChannelEvent,
  3821. 0L,
  3822. FALSE );
  3823. return KeepObject;
  3824. }
  3825. VOID
  3826. FcLogErrorDpc(
  3827. IN PKDPC Dpc,
  3828. IN PVOID DeferredContext,
  3829. IN PVOID SystemContext1,
  3830. IN PVOID SystemContext2
  3831. )
  3832. /*++
  3833. Routine Description:
  3834. This routine is merely used to log an error that we had to reset the device.
  3835. Arguments:
  3836. Dpc - The dpc object.
  3837. DeferredContext - A pointer to the controller data.
  3838. SystemContext1 - Unused.
  3839. SystemContext2 - Unused.
  3840. Return Value:
  3841. Mapped address
  3842. --*/
  3843. {
  3844. PIO_ERROR_LOG_PACKET errorLogEntry;
  3845. PFDC_FDO_EXTENSION fdoExtension = DeferredContext;
  3846. errorLogEntry = IoAllocateErrorLogEntry(
  3847. fdoExtension->DriverObject,
  3848. (UCHAR)(sizeof(IO_ERROR_LOG_PACKET))
  3849. );
  3850. if ( errorLogEntry != NULL) {
  3851. errorLogEntry->ErrorCode = IO_ERR_RESET;
  3852. errorLogEntry->SequenceNumber = 0;
  3853. errorLogEntry->MajorFunctionCode = 0;
  3854. errorLogEntry->RetryCount = 0;
  3855. errorLogEntry->UniqueErrorValue = 0;
  3856. errorLogEntry->FinalStatus = STATUS_SUCCESS;
  3857. errorLogEntry->DumpDataSize = 0;
  3858. IoWriteErrorLogEntry(errorLogEntry);
  3859. }
  3860. }
  3861. NTSTATUS
  3862. FcIssueCommand(
  3863. IN OUT PFDC_FDO_EXTENSION FdoExtension,
  3864. IN PUCHAR FifoInBuffer,
  3865. OUT PUCHAR FifoOutBuffer,
  3866. IN PVOID IoHandle,
  3867. IN ULONG IoOffset,
  3868. IN ULONG TransferBytes
  3869. )
  3870. /*++
  3871. Routine Description:
  3872. This routine sends the command and all parameters to the controller,
  3873. waits for the command to interrupt if necessary, and reads the result
  3874. bytes from the controller, if any.
  3875. Before calling this routine, the caller should put the parameters for
  3876. the command in ControllerData->FifoBuffer[]. The result bytes will
  3877. be returned in the same place.
  3878. This routine runs off the CommandTable. For each command, this says
  3879. how many parameters there are, whether or not there is an interrupt
  3880. to wait for, and how many result bytes there are. Note that commands
  3881. without result bytes actually have two, since the ISR will issue a
  3882. SENSE INTERRUPT STATUS command on their behalf.
  3883. Arguments:
  3884. Command - a byte specifying the command to be sent to the controller.
  3885. fdoExtension - a pointer to our data area for this controller.
  3886. Return Value:
  3887. STATUS_SUCCESS if the command was sent and bytes received properly;
  3888. appropriate error propogated otherwise.
  3889. --*/
  3890. {
  3891. NTSTATUS ntStatus;
  3892. NTSTATUS ntStatus2;
  3893. UCHAR i;
  3894. PUCHAR fifoBuffer;
  3895. UCHAR Command;
  3896. BOOLEAN NeedToFlush = FALSE;
  3897. //
  3898. // If this command causes an interrupt, set CurrentDeviceObject and
  3899. // reset the interrupt event.
  3900. //
  3901. Command = FifoInBuffer[0];
  3902. FdcDump( FDCINFO,
  3903. ("FcIssueCommand: Issue Command : %x\n",
  3904. CommandTable[Command & COMMAND_MASK].OpCode)
  3905. );
  3906. if ( CommandTable[Command & COMMAND_MASK].InterruptExpected ) {
  3907. FdoExtension->CurrentDeviceObject = FdoExtension->Self;
  3908. FdoExtension->AllowInterruptProcessing = TRUE;
  3909. FdoExtension->CommandHasResultPhase =
  3910. !!CommandTable[Command & COMMAND_MASK].FirstResultByte;
  3911. KeResetEvent( &FdoExtension->InterruptEvent );
  3912. }
  3913. //
  3914. // Start up the command
  3915. //
  3916. ntStatus = FcStartCommand( FdoExtension,
  3917. FifoInBuffer,
  3918. FifoOutBuffer,
  3919. IoHandle,
  3920. IoOffset,
  3921. TransferBytes,
  3922. TRUE );
  3923. if ( NT_SUCCESS( ntStatus ) ) {
  3924. //
  3925. // If there is an interrupt, wait for it.
  3926. //
  3927. if ( CommandTable[Command & COMMAND_MASK].InterruptExpected ) {
  3928. ntStatus = KeWaitForSingleObject(
  3929. &FdoExtension->InterruptEvent,
  3930. Executive,
  3931. KernelMode,
  3932. FALSE,
  3933. &FdoExtension->InterruptDelay );
  3934. if ( ntStatus == STATUS_TIMEOUT ) {
  3935. //
  3936. // Change info to an error. We'll just say
  3937. // that the device isn't ready.
  3938. //
  3939. ntStatus = STATUS_DEVICE_NOT_READY;
  3940. FdoExtension->HardwareFailed = TRUE;
  3941. }
  3942. }
  3943. //
  3944. // If successful so far, get the result bytes.
  3945. //
  3946. if ( NT_SUCCESS( ntStatus ) ) {
  3947. ntStatus = FcFinishCommand( FdoExtension,
  3948. FifoInBuffer,
  3949. FifoOutBuffer,
  3950. IoHandle,
  3951. IoOffset,
  3952. TransferBytes,
  3953. TRUE );
  3954. }
  3955. }
  3956. return ntStatus;
  3957. }
  3958. NTSTATUS
  3959. FcStartCommand(
  3960. IN OUT PFDC_FDO_EXTENSION FdoExtension,
  3961. IN PUCHAR FifoInBuffer,
  3962. OUT PUCHAR FifoOutBuffer,
  3963. IN PVOID IoHandle,
  3964. IN ULONG IoOffset,
  3965. IN ULONG TransferBytes,
  3966. IN BOOLEAN AllowLongDelay
  3967. )
  3968. /*++
  3969. Routine Description:
  3970. Arguments:
  3971. Return Value:
  3972. --*/
  3973. {
  3974. NTSTATUS ntStatus;
  3975. NTSTATUS ntStatus2;
  3976. UCHAR i = 0;
  3977. PUCHAR fifoBuffer;
  3978. UCHAR Command;
  3979. BOOLEAN NeedToFlush = FALSE;
  3980. PIO_STACK_LOCATION irpSp;
  3981. UCHAR status0;
  3982. //
  3983. // If this command causes an interrupt, set CurrentDeviceObject and
  3984. // reset the interrupt event.
  3985. //
  3986. Command = FifoInBuffer[0];
  3987. FdcDump( FDCINFO,
  3988. ("FcStartCommand: Issue Command : %x\n",
  3989. CommandTable[Command & COMMAND_MASK].OpCode)
  3990. );
  3991. FdoExtension->CommandHasResultPhase =
  3992. !!CommandTable[Command & COMMAND_MASK].FirstResultByte;
  3993. // First we will need to set up the data transfer if there is one associated
  3994. // with this request.
  3995. //
  3996. if (CommandTable[Command & COMMAND_MASK].DataTransfer == FDC_READ_DATA ) {
  3997. //
  3998. // Setup Adapter Channel for Read
  3999. //
  4000. IoMapTransfer(FdoExtension->AdapterObject,
  4001. IoHandle,
  4002. FdoExtension->MapRegisterBase,
  4003. (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress( (PMDL)IoHandle ) + IoOffset ),
  4004. &TransferBytes,
  4005. FALSE);
  4006. } else if (CommandTable[Command & COMMAND_MASK].DataTransfer ==
  4007. FDC_WRITE_DATA ) {
  4008. //
  4009. // Setup Adapter Channel for Write
  4010. //
  4011. IoMapTransfer(FdoExtension->AdapterObject,
  4012. IoHandle,
  4013. FdoExtension->MapRegisterBase,
  4014. (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress( (PMDL)IoHandle ) + IoOffset ),
  4015. &TransferBytes,
  4016. TRUE);
  4017. }
  4018. //
  4019. // Send the command to the controller.
  4020. //
  4021. if ( Command == COMMND_CONFIGURE ) {
  4022. if ( FdoExtension->Clock48MHz ) {
  4023. Command |= COMMND_OPTION_CLK48;
  4024. }
  4025. }
  4026. ntStatus = FcSendByte( (UCHAR)(CommandTable[Command & COMMAND_MASK].OpCode |
  4027. (Command & ~COMMAND_MASK)),
  4028. FdoExtension,
  4029. AllowLongDelay );
  4030. //
  4031. // If the command was successfully sent, we can proceed.
  4032. //
  4033. if ( NT_SUCCESS( ntStatus ) ) {
  4034. //
  4035. // Send the parameters as long as we succeed.
  4036. //
  4037. for ( i = 1;
  4038. ( i <= CommandTable[Command & COMMAND_MASK].NumberOfParameters ) &&
  4039. ( NT_SUCCESS( ntStatus ) );
  4040. i++ ) {
  4041. ntStatus = FcSendByte( FifoInBuffer[i],
  4042. FdoExtension,
  4043. AllowLongDelay );
  4044. //
  4045. // The Drive Specification is a special case since we don't really know
  4046. // how many bytes to send until we encounter the DONE bit (or we have sent
  4047. // the maximum allowable bytes).
  4048. //
  4049. if ((Command == COMMND_DRIVE_SPECIFICATION) &&
  4050. (FifoInBuffer[i] & COMMND_DRIVE_SPECIFICATION_DONE) ) {
  4051. break;
  4052. }
  4053. }
  4054. }
  4055. //
  4056. // If there was a problem, check to see if it was caused by an
  4057. // unimplemented command.
  4058. //
  4059. if ( !NT_SUCCESS( ntStatus ) ) {
  4060. if ( ( i == 2 ) &&
  4061. ( !CommandTable[Command & COMMAND_MASK].AlwaysImplemented ) ) {
  4062. //
  4063. // This error is probably caused by a command that's not
  4064. // implemented on this controller. Read the error from the
  4065. // controller, and we should be in a stable state.
  4066. //
  4067. ntStatus2 = FcGetByte( &status0,
  4068. FdoExtension,
  4069. AllowLongDelay );
  4070. //
  4071. // If GetByte went as planned, we'll return the original error.
  4072. //
  4073. if ( NT_SUCCESS( ntStatus2 ) ) {
  4074. if ( status0 != STREG0_END_INVALID_COMMAND ) {
  4075. //
  4076. // Status isn't as we expect, so return generic error.
  4077. //
  4078. ntStatus = STATUS_FLOPPY_BAD_REGISTERS;
  4079. FdoExtension->HardwareFailed = TRUE;
  4080. FdcDump( FDCINFO,
  4081. ("FcStartCommand: unexpected error value %2x\n",
  4082. status0) );
  4083. } else {
  4084. FdcDump( FDCINFO,
  4085. ("FcStartCommand: Invalid command error returned\n") );
  4086. }
  4087. } else {
  4088. //
  4089. // GetByte returned an error, so propogate THAT.
  4090. //
  4091. FdcDump( FDCINFO,
  4092. ("FcStartCommand: FcGetByte returned error %x\n",
  4093. ntStatus2) );
  4094. ntStatus = ntStatus2;
  4095. }
  4096. }
  4097. //
  4098. // Flush the Adapter Channel if we allocated it.
  4099. //
  4100. if (CommandTable[Command & COMMAND_MASK].DataTransfer ==
  4101. FDC_READ_DATA) {
  4102. IoFlushAdapterBuffers( FdoExtension->AdapterObject,
  4103. (PMDL)IoHandle,
  4104. FdoExtension->MapRegisterBase,
  4105. (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress( (PMDL)IoHandle) + IoOffset ),
  4106. TransferBytes,
  4107. FALSE);
  4108. } else if (CommandTable[Command & COMMAND_MASK].DataTransfer ==
  4109. FDC_WRITE_DATA) {
  4110. IoFlushAdapterBuffers( FdoExtension->AdapterObject,
  4111. (PMDL)IoHandle,
  4112. FdoExtension->MapRegisterBase,
  4113. (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress( (PMDL)IoHandle) + IoOffset ),
  4114. TransferBytes,
  4115. TRUE);
  4116. }
  4117. }
  4118. if ( !NT_SUCCESS( ntStatus ) ) {
  4119. //
  4120. // Print an error message unless the command isn't always
  4121. // implemented, ie CONFIGURE.
  4122. //
  4123. if ( !( ( ntStatus == STATUS_DEVICE_NOT_READY ) &&
  4124. ( !CommandTable[Command & COMMAND_MASK].AlwaysImplemented ) ) ) {
  4125. FdcDump( FDCDBGP,
  4126. ("Fdc: err %x ------ while giving command %x\n",
  4127. ntStatus, Command) );
  4128. }
  4129. }
  4130. return ntStatus;
  4131. }
  4132. NTSTATUS
  4133. FcFinishCommand(
  4134. IN OUT PFDC_FDO_EXTENSION FdoExtension,
  4135. IN PUCHAR FifoInBuffer,
  4136. OUT PUCHAR FifoOutBuffer,
  4137. IN PVOID IoHandle,
  4138. IN ULONG IoOffset,
  4139. IN ULONG TransferBytes,
  4140. IN BOOLEAN AllowLongDelay
  4141. )
  4142. /*++
  4143. Routine Description:
  4144. This function is called to complete a command to the floppy controller.
  4145. At this point the floppy controller has successfully been sent a command
  4146. and has either generated an interrupt or is ready with its result phase.
  4147. This routine will also flush the DMA Adapter Buffers if they have been
  4148. allocated.
  4149. Arguments:
  4150. FdoExtension - a pointer to our data area for this controller.
  4151. IssueCommandParms - Floppy controller command parameters.
  4152. Return Value:
  4153. STATUS_SUCCESS if the command is successfully completed.
  4154. --*/
  4155. {
  4156. NTSTATUS ntStatus = STATUS_SUCCESS;
  4157. NTSTATUS ntStatus2;
  4158. UCHAR i;
  4159. UCHAR Command;
  4160. Command = FifoInBuffer[0];
  4161. FdcDump(
  4162. FDCSHOW,
  4163. ("Fdc: FcFinishCommand...\n")
  4164. );
  4165. if (IsNEC_98) {
  4166. if (Command == COMMND_SENSE_DRIVE_STATUS) {
  4167. ntStatus = FcGetByte(
  4168. &FdoExtension->FifoBuffer[0],
  4169. FdoExtension,
  4170. AllowLongDelay );
  4171. if (NT_SUCCESS(ntStatus) && (FdoExtension->FifoBuffer[0] & STREG3_DRIVE_READY)) {
  4172. FdoExtension->ResultStatus0[FifoInBuffer[1]] = 0;
  4173. }
  4174. }
  4175. FifoOutBuffer[0] = FdoExtension->FifoBuffer[0];
  4176. for ( i = 1;
  4177. ( i < CommandTable[Command & COMMAND_MASK].NumberOfResultBytes ) &&
  4178. ( NT_SUCCESS( ntStatus ) );
  4179. i++ ) {
  4180. ntStatus = FcGetByte(
  4181. &FifoOutBuffer[i],
  4182. FdoExtension,
  4183. AllowLongDelay );
  4184. }
  4185. FdcRqmReadyWait(FdoExtension, 0);
  4186. } else { // (IsNEC_98)
  4187. if (CommandTable[Command & COMMAND_MASK].FirstResultByte > 0) {
  4188. FifoOutBuffer[0] = FdoExtension->FifoBuffer[0];
  4189. }
  4190. for ( i = CommandTable[Command & COMMAND_MASK].FirstResultByte;
  4191. ( i < CommandTable[Command & COMMAND_MASK].NumberOfResultBytes ) &&
  4192. ( NT_SUCCESS( ntStatus ) );
  4193. i++ ) {
  4194. ntStatus = FcGetByte(
  4195. &FifoOutBuffer[i],
  4196. FdoExtension,
  4197. AllowLongDelay );
  4198. }
  4199. } // (IsNEC_98)
  4200. //
  4201. // Flush the Adapter Channel
  4202. //
  4203. if (CommandTable[Command & COMMAND_MASK].DataTransfer == FDC_READ_DATA) {
  4204. IoFlushAdapterBuffers(FdoExtension->AdapterObject,
  4205. (PMDL)IoHandle,
  4206. FdoExtension->MapRegisterBase,
  4207. (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress( (PMDL)IoHandle ) + IoOffset ),
  4208. TransferBytes,
  4209. FALSE);
  4210. } else if (CommandTable[Command & COMMAND_MASK].DataTransfer ==
  4211. FDC_WRITE_DATA) {
  4212. //
  4213. // Setup Adapter Channel for Write
  4214. //
  4215. IoFlushAdapterBuffers(FdoExtension->AdapterObject,
  4216. (PMDL)IoHandle,
  4217. FdoExtension->MapRegisterBase,
  4218. (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress( (PMDL)IoHandle ) + IoOffset ),
  4219. TransferBytes,
  4220. TRUE);
  4221. }
  4222. return ntStatus;
  4223. }
  4224. NTSTATUS
  4225. FcSendByte(
  4226. IN UCHAR ByteToSend,
  4227. IN PFDC_FDO_EXTENSION FdoExtension,
  4228. IN BOOLEAN AllowLongDelay
  4229. )
  4230. /*++
  4231. Routine Description:
  4232. This routine is called to send a byte to the controller. It won't
  4233. send the byte unless the controller is ready to receive a byte; if
  4234. it's not ready after checking FIFO_TIGHTLOOP_RETRY_COUNT times, we
  4235. delay for the minimum possible time (10ms) and then try again. It
  4236. should always be ready after waiting 10ms.
  4237. Arguments:
  4238. ByteToSend - the byte to send to the controller.
  4239. ControllerData - a pointer to our data area for this controller.
  4240. Return Value:
  4241. STATUS_SUCCESS if the byte was sent to the controller;
  4242. STATUS_DEVICE_NOT_READY otherwise.
  4243. --*/
  4244. {
  4245. ULONG i = 0;
  4246. BOOLEAN byteWritten = FALSE;
  4247. if (IsNEC_98) {
  4248. // Always FALSE;
  4249. AllowLongDelay = FALSE;
  4250. }
  4251. //
  4252. // Sit in a tight loop for a while. If the controller becomes ready,
  4253. // send the byte.
  4254. //
  4255. do {
  4256. if ( ( READ_CONTROLLER( FdoExtension->ControllerAddress.Status )
  4257. & STATUS_IO_READY_MASK ) == STATUS_WRITE_READY ) {
  4258. WRITE_CONTROLLER(
  4259. FdoExtension->ControllerAddress.Fifo,
  4260. ByteToSend );
  4261. byteWritten = TRUE;
  4262. } else {
  4263. KeStallExecutionProcessor(1);
  4264. }
  4265. i++;
  4266. } while ( (!byteWritten) && ( i < FIFO_TIGHTLOOP_RETRY_COUNT ) );
  4267. //
  4268. // We hope that in most cases the FIFO will become ready very quickly
  4269. // and the above loop will have written the byte. But if the FIFO
  4270. // is not yet ready, we'll loop a few times delaying for 10ms and then
  4271. // try it again.
  4272. //
  4273. if ( AllowLongDelay ) {
  4274. i = 0;
  4275. while ( ( !byteWritten ) && ( i < FIFO_DELAY_RETRY_COUNT ) ) {
  4276. FdcDump(
  4277. FDCINFO,
  4278. ("Fdc: waiting for 10ms for controller write\n")
  4279. );
  4280. KeDelayExecutionThread(
  4281. KernelMode,
  4282. FALSE,
  4283. &FdoExtension->Minimum10msDelay );
  4284. i++;
  4285. if ( (READ_CONTROLLER( FdoExtension->ControllerAddress.Status )
  4286. & STATUS_IO_READY_MASK) == STATUS_WRITE_READY ) {
  4287. WRITE_CONTROLLER(
  4288. FdoExtension->ControllerAddress.Fifo,
  4289. ByteToSend );
  4290. byteWritten = TRUE;
  4291. }
  4292. }
  4293. }
  4294. if ( byteWritten ) {
  4295. return STATUS_SUCCESS;
  4296. } else {
  4297. //
  4298. // We've waited over 30ms, and the FIFO *still* isn't ready.
  4299. // Return an error.
  4300. //
  4301. FdcDump(
  4302. FDCWARN,
  4303. ("Fdc: FIFO not ready to write after 30ms\n")
  4304. );
  4305. FdoExtension->HardwareFailed = TRUE;
  4306. return STATUS_DEVICE_NOT_READY;
  4307. }
  4308. }
  4309. NTSTATUS
  4310. FcGetByte(
  4311. OUT PUCHAR ByteToGet,
  4312. IN PFDC_FDO_EXTENSION FdoExtension,
  4313. IN BOOLEAN AllowLongDelay
  4314. )
  4315. /*++
  4316. Routine Description:
  4317. This routine is called to get a byte from the controller. It won't
  4318. read the byte unless the controller is ready to send a byte; if
  4319. it's not ready after checking FIFO_RETRY_COUNT times, we delay for
  4320. the minimum possible time (10ms) and then try again. It should
  4321. always be ready after waiting 10ms.
  4322. Arguments:
  4323. ByteToGet - the address in which the byte read from the controller
  4324. is stored.
  4325. ControllerData - a pointer to our data area for this controller.
  4326. Return Value:
  4327. STATUS_SUCCESS if a byte was read from the controller;
  4328. STATUS_DEVICE_NOT_READY otherwise.
  4329. --*/
  4330. {
  4331. ULONG i = 0;
  4332. BOOLEAN byteRead = FALSE;
  4333. if (IsNEC_98) {
  4334. // Always FALSE;
  4335. AllowLongDelay = FALSE;
  4336. }
  4337. //
  4338. // Sit in a tight loop for a while. If the controller becomes ready,
  4339. // read the byte.
  4340. //
  4341. do {
  4342. if ( ( READ_CONTROLLER( FdoExtension->ControllerAddress.Status )
  4343. & STATUS_IO_READY_MASK ) == STATUS_READ_READY ) {
  4344. *ByteToGet = READ_CONTROLLER(
  4345. FdoExtension->ControllerAddress.Fifo );
  4346. byteRead = TRUE;
  4347. } else {
  4348. KeStallExecutionProcessor(1);
  4349. }
  4350. i++;
  4351. } while ( ( !byteRead ) && ( i < FIFO_TIGHTLOOP_RETRY_COUNT ) );
  4352. //
  4353. // We hope that in most cases the FIFO will become ready very quickly
  4354. // and the above loop will have read the byte. But if the FIFO
  4355. // is not yet ready, we'll loop a few times delaying for 10ms and then
  4356. // trying it again.
  4357. //
  4358. if ( AllowLongDelay ) {
  4359. i = 0;
  4360. while ( ( !byteRead ) && ( i < FIFO_DELAY_RETRY_COUNT ) ) {
  4361. FdcDump(
  4362. FDCINFO,
  4363. ("Fdc: waiting for 10ms for controller read\n")
  4364. );
  4365. KeDelayExecutionThread(
  4366. KernelMode,
  4367. FALSE,
  4368. &FdoExtension->Minimum10msDelay );
  4369. i++;
  4370. if ( (READ_CONTROLLER( FdoExtension->ControllerAddress.Status )
  4371. & STATUS_IO_READY_MASK) == STATUS_READ_READY ) {
  4372. *ByteToGet = READ_CONTROLLER(
  4373. FdoExtension->ControllerAddress.Fifo );
  4374. byteRead = TRUE;
  4375. }
  4376. }
  4377. }
  4378. if ( byteRead ) {
  4379. return STATUS_SUCCESS;
  4380. } else {
  4381. //
  4382. // We've waited over 30ms, and the FIFO *still* isn't ready.
  4383. // Return an error.
  4384. //
  4385. FdcDump(
  4386. FDCWARN,
  4387. ("Fdc: FIFO not ready to read after 30ms\n")
  4388. );
  4389. FdoExtension->HardwareFailed = TRUE;
  4390. return STATUS_DEVICE_NOT_READY;
  4391. }
  4392. }
  4393. VOID
  4394. FdcCheckTimer(
  4395. IN PDEVICE_OBJECT DeviceObject,
  4396. IN OUT PVOID Context
  4397. )
  4398. /*++
  4399. Routine Description:
  4400. This routine is called at DISPATCH_LEVEL once every second by the
  4401. I/O system.
  4402. If the timer is "set" (greater than 0) this routine will KeSync a
  4403. routine to decrement it. If it ever reaches 0, the hardware is
  4404. assumed to be in an unknown state, and so we log an error and
  4405. initiate a reset.
  4406. If a timeout occurs while resetting the controller, the KeSync'd
  4407. routine will return an error, and this routine will fail any IRPs
  4408. currently being processed. Future IRPs will try the hardware again.
  4409. When this routine is called, the driver state is impossible to
  4410. predict. However, when it is called and the timer is running, we
  4411. know that one of the disks on the controller is expecting an
  4412. interrupt. So no new packets are starting on the current disk due
  4413. to device queues, and no code should be processing this packet since
  4414. the packet is waiting for an interrupt.
  4415. Arguments:
  4416. DeviceObject - a pointer to the device object associated with this
  4417. timer.
  4418. Fdcxtension - a pointer to the fdc extension data.
  4419. Return Value:
  4420. None.
  4421. --*/
  4422. {
  4423. PFDC_FDO_EXTENSION fdoExtension;
  4424. PIRP irp;
  4425. fdoExtension = (PFDC_FDO_EXTENSION)Context;
  4426. irp = DeviceObject->CurrentIrp;
  4427. //
  4428. // When the counter is -1, the timer is "off" so we don't want to do
  4429. // anything. If it's on, we'll have to synchronize execution with
  4430. // other routines while we mess with the variables (and, potentially,
  4431. // the hardware).
  4432. //
  4433. if ( fdoExtension->InterruptTimer == CANCEL_TIMER ) {
  4434. return;
  4435. }
  4436. //
  4437. // In the unlikely event that we attempt to reset the controller due
  4438. // to a timeout AND that reset times out, we will need to fail the
  4439. // IRP that was in progress at the first timeout occurred.
  4440. //
  4441. if ( !KeSynchronizeExecution( fdoExtension->InterruptObject,
  4442. FdcTimerSync,
  4443. fdoExtension ) ) {
  4444. //
  4445. // We're done with the reset. Return the IRP that was being
  4446. // processed with an error, and release the controller object.
  4447. //
  4448. fdoExtension->ResettingController = RESET_NOT_RESETTING;
  4449. irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
  4450. IoSetHardErrorOrVerifyDevice( irp, DeviceObject );
  4451. if ( InterlockedDecrement(&fdoExtension->OutstandingRequests ) == 0 ) {
  4452. KeSetEvent( &fdoExtension->RemoveEvent, 0, FALSE );
  4453. }
  4454. IoCompleteRequest( irp, IO_DISK_INCREMENT );
  4455. IoStartNextPacket( DeviceObject, FALSE );
  4456. }
  4457. }
  4458. BOOLEAN
  4459. FdcTimerSync(
  4460. IN OUT PVOID Context
  4461. )
  4462. /*++
  4463. Routine Description:
  4464. This routine is called at DIRQL by FdcCheckTimer() when
  4465. InterruptTimer is greater than 0.
  4466. If the timer is "set" (greater than 0) this routine will decrement
  4467. it. If it ever reaches 0, the hardware is assumed to be in an
  4468. unknown state, and so we log an error and initiate a reset.
  4469. When this routine is called, the driver state is impossible to
  4470. predict. However, when it is called and the timer is running, we
  4471. know that one of the disks on the controller is expecting an
  4472. interrupt. So, no new packets are starting on the current disk due
  4473. to device queues, and no code should be processing this packet since
  4474. the packet is waiting for an interrupt. The controller object must
  4475. be held.
  4476. Arguments:
  4477. Context - a pointer to the controller extension.
  4478. Return Value:
  4479. Generally TRUE.
  4480. FALSE is only returned if the controller timed out while resetting
  4481. the drive, so this means that the hardware state is unknown.
  4482. --*/
  4483. {
  4484. PFDC_FDO_EXTENSION fdoExtension;
  4485. fdoExtension = (PFDC_FDO_EXTENSION)Context;
  4486. //
  4487. // When the counter is -1, the timer is "off" so we don't want to do
  4488. // anything. It may have changed since we last checked it in
  4489. // FdcCheckTimer().
  4490. //
  4491. if ( fdoExtension->InterruptTimer == CANCEL_TIMER ) {
  4492. return TRUE;
  4493. }
  4494. //
  4495. // The timer is "on", so decrement it.
  4496. //
  4497. fdoExtension->InterruptTimer--;
  4498. //
  4499. // If we hit zero, the timer has expired and we'll reset the
  4500. // controller.
  4501. //
  4502. if ( fdoExtension->InterruptTimer == EXPIRED_TIMER ) {
  4503. //
  4504. // If we were ALREADY resetting the controller when it timed out,
  4505. // there's something seriously wrong.
  4506. //
  4507. FdcDump( FDCDBGP, ("Fdc: Operation Timed Out.\n") );
  4508. if ( fdoExtension->ResettingController != RESET_NOT_RESETTING ) {
  4509. //
  4510. // Returning FALSE will cause the current IRP to be completed
  4511. // with an error. Future IRPs will probably get a timeout and
  4512. // attempt to reset the controller again. This will probably
  4513. // never happen.
  4514. //
  4515. FdcDump( FDCDBGP, ("Fdc: Timeout Reset timed out.\n") );
  4516. fdoExtension->InterruptTimer = CANCEL_TIMER;
  4517. return FALSE;
  4518. }
  4519. //
  4520. // Reset the controller. This will cause an interrupt. Reset
  4521. // CurrentDeviceObject until after the 10ms wait, in case any
  4522. // stray interrupts come in.
  4523. //
  4524. fdoExtension->ResettingController = RESET_DRIVE_RESETTING;
  4525. DISABLE_CONTROLLER_IMAGE (fdoExtension);
  4526. #ifdef _PPC_
  4527. fdoExtension->DriveControlImage |= DRVCTL_DRIVE_MASK;
  4528. #endif
  4529. WRITE_CONTROLLER(
  4530. fdoExtension->ControllerAddress.DriveControl,
  4531. fdoExtension->DriveControlImage );
  4532. KeStallExecutionProcessor( 10 );
  4533. fdoExtension->CommandHasResultPhase = FALSE;
  4534. fdoExtension->InterruptTimer = START_TIMER;
  4535. ENABLE_CONTROLLER_IMAGE (fdoExtension);
  4536. WRITE_CONTROLLER(
  4537. fdoExtension->ControllerAddress.DriveControl,
  4538. fdoExtension->DriveControlImage );
  4539. }
  4540. return TRUE;
  4541. }
  4542. BOOLEAN
  4543. FdcInterruptService(
  4544. IN PKINTERRUPT Interrupt,
  4545. IN PVOID Context
  4546. )
  4547. /*++
  4548. Routine Description:
  4549. This routine is called at DIRQL by the system when the controller
  4550. interrupts.
  4551. Arguments:
  4552. Interrupt - a pointer to the interrupt object.
  4553. Context - a pointer to our controller data area for the controller
  4554. that interrupted. (This was set up by the call to
  4555. IoConnectInterrupt).
  4556. Return Value:
  4557. Normally returns TRUE, but will return FALSE if this interrupt was
  4558. not expected.
  4559. --*/
  4560. {
  4561. PFDC_FDO_EXTENSION fdoExtension;
  4562. PDEVICE_OBJECT currentDeviceObject;
  4563. ULONG i;
  4564. UCHAR statusByte;
  4565. BOOLEAN controllerStateError;
  4566. UCHAR resultStatus0;
  4567. UCHAR aiStatus=0;
  4568. UCHAR aiInterrupt=0;
  4569. ULONG rqmReadyRetryCount;
  4570. BOOLEAN Response;
  4571. UNREFERENCED_PARAMETER( Interrupt );
  4572. #ifdef KEEP_COUNTERS
  4573. FloppyIntrTime = KeQueryPerformanceCounter((PVOID)NULL);
  4574. FloppyInterrupts++;
  4575. #endif
  4576. FdcDump( FDCSHOW, ("FdcInterruptService: ") );
  4577. fdoExtension = (PFDC_FDO_EXTENSION) Context;
  4578. if (!IsNEC_98) {
  4579. if (!fdoExtension->AllowInterruptProcessing) {
  4580. FdcDump( FDCSHOW, ("processing not allowed\n") );
  4581. return FALSE;
  4582. }
  4583. } // (!IsNEC_98)
  4584. //
  4585. // CurrentDeviceObject is set to the device object that is
  4586. // expecting an interrupt.
  4587. //
  4588. currentDeviceObject = fdoExtension->CurrentDeviceObject;
  4589. fdoExtension->CurrentDeviceObject = NULL;
  4590. controllerStateError = FALSE;
  4591. fdoExtension->InterruptTimer = CANCEL_TIMER;
  4592. KeStallExecutionProcessor(10);
  4593. if (IsNEC_98) {
  4594. do {
  4595. resultStatus0 = READ_CONTROLLER( fdoExtension->ControllerAddress.Status );
  4596. resultStatus0 &= STATUS_DATA_REQUEST;
  4597. } while (resultStatus0 != STATUS_DATA_REQUEST);
  4598. } // (IsNEC_98)
  4599. if ( fdoExtension->CommandHasResultPhase ) {
  4600. //
  4601. // Result phase of previous command. (Note that we can't trust
  4602. // the CMD_BUSY bit in the status register to tell us whether
  4603. // there's result bytes or not; it's sometimes wrong).
  4604. // By reading the first result byte, we reset the interrupt.
  4605. // The other result bytes will be read by a thread.
  4606. // Note that we want to do this even if the interrupt is
  4607. // unexpected, to make sure the interrupt is dismissed.
  4608. //
  4609. FdcDump(
  4610. FDCSHOW,
  4611. ("have result phase\n")
  4612. );
  4613. if (IsNEC_98) {
  4614. rqmReadyRetryCount = 0;
  4615. while ( ( READ_CONTROLLER( fdoExtension->ControllerAddress.Status)
  4616. & STATUS_IO_READY_MASK1) != STATUS_RQM_READY ) {
  4617. //
  4618. // RQM READY CHECK**
  4619. //
  4620. rqmReadyRetryCount++;
  4621. if( rqmReadyRetryCount > RQM_READY_RETRY_COUNT ) {
  4622. break;
  4623. }
  4624. KeStallExecutionProcessor( 10 );
  4625. }
  4626. if( rqmReadyRetryCount > ( RQM_READY_RETRY_COUNT - 1 ) ) {
  4627. FdcDump(
  4628. FDCDBGP,
  4629. ("Floppy: Int RQM ready wait 1 error! \n")
  4630. );
  4631. KeStallExecutionProcessor( 10 );
  4632. goto FdcInterruptMidterm;
  4633. }
  4634. } // (IsNEC_98)
  4635. if ( ( READ_CONTROLLER( fdoExtension->ControllerAddress.Status )
  4636. & STATUS_IO_READY_MASK ) == STATUS_READ_READY ) {
  4637. fdoExtension->FifoBuffer[0] =
  4638. READ_CONTROLLER( fdoExtension->ControllerAddress.Fifo );
  4639. FdcDump( FDCSHOW,
  4640. ("FdcInterruptService: 1st fifo byte %2x\n",
  4641. fdoExtension->FifoBuffer[0])
  4642. );
  4643. } else {
  4644. if (IsNEC_98) {
  4645. FdcRqmReadyWait(fdoExtension, 2);
  4646. } // (IsNEC_98)
  4647. //
  4648. // Should never get here. If we do, DON'T wake up the thread;
  4649. // let it time out and reset the controller, or let another
  4650. // interrupt handle this.
  4651. //
  4652. FdcDump(
  4653. FDCDBGP,
  4654. ("FdcInterruptService: controller not ready to be read in ISR\n")
  4655. );
  4656. controllerStateError = TRUE;
  4657. }
  4658. } else {
  4659. //
  4660. // Previous command doesn't have a result phase. To read how it
  4661. // completed, issue a sense interrupt command. Don't read
  4662. // the result bytes from the sense interrupt; that is the
  4663. // responsibility of the calling thread.
  4664. // Note that we want to do this even if the interrupt is
  4665. // unexpected, to make sure the interrupt is dismissed.
  4666. //
  4667. FdcDump(
  4668. FDCSHOW,
  4669. ("no result phase\n")
  4670. );
  4671. i = 0;
  4672. do {
  4673. KeStallExecutionProcessor( 1 );
  4674. statusByte =
  4675. READ_CONTROLLER(fdoExtension->ControllerAddress.Status);
  4676. i++;
  4677. } while ( ( i < FIFO_ISR_TIGHTLOOP_RETRY_COUNT ) &&
  4678. ( ( statusByte & STATUS_CONTROLLER_BUSY ) ||
  4679. ( ( statusByte & STATUS_IO_READY_MASK ) != STATUS_WRITE_READY ) ) );
  4680. if ( !( statusByte & STATUS_CONTROLLER_BUSY ) &&
  4681. ( ( statusByte & STATUS_IO_READY_MASK ) == STATUS_WRITE_READY ) ) {
  4682. WRITE_CONTROLLER(
  4683. fdoExtension->ControllerAddress.Fifo,
  4684. 0x08 );
  4685. // COMMND_SENSE_INTERRUPT_STATUS );
  4686. //
  4687. // Wait for the controller to ACK the SenseInterrupt command, by
  4688. // showing busy. On very fast machines we can end up running
  4689. // driver's system-thread before the controller has had time to
  4690. // set the busy bit.
  4691. //
  4692. for (i = ISR_SENSE_RETRY_COUNT; i; i--) {
  4693. statusByte =
  4694. READ_CONTROLLER( fdoExtension->ControllerAddress.Status );
  4695. if (statusByte & STATUS_CONTROLLER_BUSY) {
  4696. break;
  4697. }
  4698. KeStallExecutionProcessor( 1 );
  4699. }
  4700. if (!i) {
  4701. FdcDump(
  4702. FDCSHOW,
  4703. ("FdcInterruptService: spin loop complete and controller NOT busy\n")
  4704. );
  4705. }
  4706. if ( currentDeviceObject == NULL ) {
  4707. //
  4708. // This is an unexpected interrupt, so nobody's going to
  4709. // read the result bytes. Read them now.
  4710. //
  4711. if (IsNEC_98) {
  4712. resultStatus0 = FdcRqmReadyWait(fdoExtension, 0);
  4713. if ((resultStatus0 & STREG0_END_DRIVE_NOT_READY) != STREG0_END_INVALID_COMMAND ) {
  4714. resultStatus0 = FdcRqmReadyWait(fdoExtension, 1);
  4715. }
  4716. } else { // (IsNEC_98)
  4717. FdcDump(
  4718. FDCSHOW,
  4719. ("FdcInterruptService: Dumping fifo bytes!\n")
  4720. );
  4721. READ_CONTROLLER( fdoExtension->ControllerAddress.Fifo );
  4722. READ_CONTROLLER( fdoExtension->ControllerAddress.Fifo );
  4723. } // (IsNEC_98)
  4724. }
  4725. if (IsNEC_98) {
  4726. if ( currentDeviceObject != NULL ) {
  4727. FdcDump(
  4728. FDCSHOW,
  4729. ("Floppy: FloppyInt.---Deviceobject!=NULL2\n")
  4730. );
  4731. resultStatus0 = FdcRqmReadyWait(fdoExtension, 0);
  4732. //
  4733. // Check move state.
  4734. //
  4735. if((resultStatus0 & STREG0_END_MASK) == STREG0_END_DRIVE_NOT_READY) {
  4736. if(fdoExtension->ResetFlag){
  4737. aiStatus=1;
  4738. fdoExtension->CurrentDeviceObject = currentDeviceObject;
  4739. }
  4740. } else {
  4741. fdoExtension->FifoBuffer[0] = resultStatus0;
  4742. aiStatus=0;
  4743. aiInterrupt=1;
  4744. }
  4745. if (aiInterrupt == 0){
  4746. while( ((resultStatus0 & STREG0_END_DRIVE_NOT_READY) != STREG0_END_INVALID_COMMAND) && aiInterrupt==0 ) {
  4747. resultStatus0 = FdcRqmReadyWait(fdoExtension, 3);
  4748. do {
  4749. //
  4750. // Check move state.
  4751. //
  4752. if((resultStatus0 & STREG0_END_MASK) == STREG0_END_DRIVE_NOT_READY) {
  4753. if(fdoExtension->ResetFlag){
  4754. aiStatus=1;
  4755. fdoExtension->CurrentDeviceObject = currentDeviceObject;
  4756. }
  4757. } else {
  4758. fdoExtension->FifoBuffer[0] = resultStatus0;
  4759. aiStatus=0;
  4760. aiInterrupt=1;
  4761. break;
  4762. }
  4763. resultStatus0 = FdcRqmReadyWait(fdoExtension, 0);
  4764. } while ( aiInterrupt == 0 );
  4765. }
  4766. FdcDump(
  4767. FDCSHOW,
  4768. ("Floppy: FloppyInt.---Deviceobject!=NULL_out\n")
  4769. );
  4770. }
  4771. }
  4772. } // (IsNEC_98)
  4773. } else {
  4774. //
  4775. // Shouldn't get here. If we do, DON'T wake up the thread;
  4776. // let it time out and reset the controller, or let another
  4777. // interrupt take care of it.
  4778. //
  4779. FdcDump(
  4780. FDCDBGP,
  4781. ("Fdc: no result, but can't write SenseIntr\n")
  4782. );
  4783. controllerStateError = TRUE;
  4784. }
  4785. }
  4786. FdcInterruptMidterm:
  4787. //
  4788. // We've written to the controller, and we're about to leave. On
  4789. // machines with levelsensitive interrupts, we'll get another interrupt
  4790. // if we RETURN before the port is flushed. To make sure that doesn't
  4791. // happen, we'll do a read here.
  4792. //
  4793. statusByte = READ_CONTROLLER( fdoExtension->ControllerAddress.Status );
  4794. //
  4795. // Let the interrupt settle.
  4796. //
  4797. KeStallExecutionProcessor(10);
  4798. #ifdef KEEP_COUNTERS
  4799. FloppyEndIntrTime = KeQueryPerformanceCounter((PVOID)NULL);
  4800. FloppyIntrDelay.QuadPart = FloppyIntrDelay.QuadPart +
  4801. (FloppyEndIntrTime.QuadPart -
  4802. FloppyIntrTime.QuadPart);
  4803. #endif
  4804. if (IsNEC_98) {
  4805. if(!(fdoExtension->ResetFlag)){
  4806. fdoExtension->ResetFlag = TRUE;
  4807. }
  4808. } // (IsNEC_98)
  4809. if ( currentDeviceObject == NULL ) {
  4810. //
  4811. // We didn't expect this interrupt. We've dismissed it just
  4812. // in case, but now return FALSE withOUT waking up the thread.
  4813. //
  4814. FdcDump(FDCDBGP,
  4815. ("Fdc: unexpected interrupt\n"));
  4816. return FALSE;
  4817. }
  4818. if ( !controllerStateError ) {
  4819. //
  4820. // Request a DPC for execution later to get the remainder of the
  4821. // floppy state.
  4822. //
  4823. fdoExtension->IsrReentered = 0;
  4824. fdoExtension->AllowInterruptProcessing = FALSE;
  4825. if (IsNEC_98) {
  4826. if(aiStatus==0){
  4827. IoRequestDpc(currentDeviceObject,
  4828. currentDeviceObject->CurrentIrp,
  4829. (PVOID) NULL );
  4830. }
  4831. } else { // (IsNEC_98)
  4832. IoRequestDpc(currentDeviceObject,
  4833. currentDeviceObject->CurrentIrp,
  4834. (PVOID) NULL);
  4835. } // (IsNEC_98)
  4836. } else {
  4837. //
  4838. // Running the floppy (at least on R4000 boxes) we've seen
  4839. // examples where the device interrupts, yet it never says
  4840. // it *ISN'T* busy. If this ever happens on non-MCA x86 boxes
  4841. // it would be ok since we use latched interrupts. Even if
  4842. // the device isn't touched so that the line would be pulled
  4843. // down, on the latched machine, this ISR wouldn't be called
  4844. // again. The normal timeout code for a request would eventually
  4845. // reset the controller and retry the request.
  4846. //
  4847. // On the R4000 boxes and on MCA machines, the floppy is using
  4848. // level sensitive interrupts. Therefore if we don't do something
  4849. // to lower the interrupt line, we will be called over and over,
  4850. // *forever*. This makes it look as though the machine is hung.
  4851. // Unless we were lucky enough to be on a multiprocessor, the
  4852. // normal timeout code would NEVER get a chance to run because
  4853. // the timeout code runs at dispatch level, and we will never
  4854. // leave device level.
  4855. //
  4856. // What we will do is keep a counter that is incremented every
  4857. // time we reach this section of code. When the counter goes
  4858. // over the threshold we will do a hard reset of the device
  4859. // and reset the counter down to zero. The counter will be
  4860. // initialized when the device is first initialized. It will
  4861. // be set to zero in the other arm of this if, and it will be
  4862. // reset to zero by the normal timeout logic.
  4863. //
  4864. fdoExtension->CurrentDeviceObject = currentDeviceObject;
  4865. if (fdoExtension->IsrReentered > FLOPPY_RESET_ISR_THRESHOLD) {
  4866. //
  4867. // Reset the controller. This could cause an interrupt
  4868. //
  4869. fdoExtension->IsrReentered = 0;
  4870. DISABLE_CONTROLLER_IMAGE (fdoExtension);
  4871. #ifdef _PPC_
  4872. fdoExtension->DriveControlImage |= DRVCTL_DRIVE_MASK;
  4873. #endif
  4874. WRITE_CONTROLLER(fdoExtension->ControllerAddress.DriveControl,
  4875. fdoExtension->DriveControlImage);
  4876. KeStallExecutionProcessor( 10 );
  4877. ENABLE_CONTROLLER_IMAGE (fdoExtension);
  4878. WRITE_CONTROLLER(fdoExtension->ControllerAddress.DriveControl,
  4879. fdoExtension->DriveControlImage);
  4880. if (IsNEC_98) {
  4881. fdoExtension->ResetFlag = TRUE;
  4882. } // (IsNEC_98)
  4883. //
  4884. // Give the device plenty of time to be reset and
  4885. // interrupt again. Then just do the sense interrupt.
  4886. // this should quiet the device. We will then let
  4887. // the normal timeout code do its work.
  4888. //
  4889. KeStallExecutionProcessor(500);
  4890. WRITE_CONTROLLER(fdoExtension->ControllerAddress.Fifo,
  4891. 0x08 );
  4892. // COMMND_SENSE_INTERRUPT_STATUS );
  4893. KeStallExecutionProcessor(500);
  4894. KeInsertQueueDpc(&fdoExtension->LogErrorDpc,
  4895. NULL,
  4896. NULL);
  4897. } else {
  4898. fdoExtension->IsrReentered++;
  4899. }
  4900. }
  4901. return TRUE;
  4902. }
  4903. VOID
  4904. FdcDeferredProcedure(
  4905. IN PKDPC Dpc,
  4906. IN PVOID DeferredContext,
  4907. IN PVOID SystemArgument1,
  4908. IN PVOID SystemArgument2
  4909. )
  4910. /*++
  4911. Routine Description:
  4912. This routine is called at DISPATCH_LEVEL by the system at the
  4913. request of FdcInterruptService(). It simply sets the interrupt
  4914. event, which wakes up the floppy thread.
  4915. Arguments:
  4916. Dpc - a pointer to the DPC object used to invoke this routine.
  4917. DeferredContext - a pointer to the device object associated with this
  4918. DPC.
  4919. SystemArgument1 - unused.
  4920. SystemArgument2 - unused.
  4921. Return Value:
  4922. None.
  4923. --*/
  4924. {
  4925. NTSTATUS ntStatus;
  4926. PDEVICE_OBJECT deviceObject;
  4927. // PFDC_PDO_EXTENSION pdoExtension;
  4928. PFDC_FDO_EXTENSION fdoExtension;
  4929. PIRP irp;
  4930. PIO_STACK_LOCATION irpSp;
  4931. PLIST_ENTRY request;
  4932. PISSUE_FDC_COMMAND_PARMS issueCommandParms;
  4933. UNREFERENCED_PARAMETER( Dpc );
  4934. UNREFERENCED_PARAMETER( SystemArgument1 );
  4935. UNREFERENCED_PARAMETER( SystemArgument2 );
  4936. #ifdef KEEP_COUNTERS
  4937. FloppyDPCs++;
  4938. FloppyDPCTime = KeQueryPerformanceCounter((PVOID)NULL);
  4939. FloppyDPCDelay.QuadPart = FloppyDPCDelay.QuadPart +
  4940. (FloppyDPCTime.QuadPart -
  4941. FloppyIntrTime.QuadPart);
  4942. #endif
  4943. deviceObject = (PDEVICE_OBJECT) DeferredContext;
  4944. fdoExtension = deviceObject->DeviceExtension;
  4945. irp = deviceObject->CurrentIrp;
  4946. if ( irp != NULL ) {
  4947. irpSp = IoGetCurrentIrpStackLocation( irp );
  4948. }
  4949. if ( irp != NULL &&
  4950. irpSp->Parameters.DeviceIoControl.IoControlCode ==
  4951. IOCTL_DISK_INTERNAL_ISSUE_FDC_COMMAND_QUEUED ) {
  4952. issueCommandParms =
  4953. (PISSUE_FDC_COMMAND_PARMS)
  4954. irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  4955. ntStatus = FcFinishCommand(
  4956. fdoExtension,
  4957. issueCommandParms->FifoInBuffer,
  4958. issueCommandParms->FifoOutBuffer,
  4959. issueCommandParms->IoHandle,
  4960. issueCommandParms->IoOffset,
  4961. issueCommandParms->TransferBytes,
  4962. FALSE );
  4963. irp->IoStatus.Status = ntStatus;
  4964. if ( !NT_SUCCESS( ntStatus ) &&
  4965. IoIsErrorUserInduced( ntStatus ) ) {
  4966. IoSetHardErrorOrVerifyDevice( irp, deviceObject );
  4967. }
  4968. if ( InterlockedDecrement(&fdoExtension->OutstandingRequests ) == 0 ) {
  4969. KeSetEvent( &fdoExtension->RemoveEvent, 0, FALSE );
  4970. }
  4971. IoCompleteRequest( irp, IO_NO_INCREMENT );
  4972. IoStartNextPacket( deviceObject, FALSE );
  4973. } else {
  4974. FdcDump( FDCSHOW, ("FdcDeferredProcedure: Set Event\n") );
  4975. KeSetEvent( &fdoExtension->InterruptEvent, (KPRIORITY) 0, FALSE );
  4976. }
  4977. }
  4978. NTSTATUS
  4979. FcFinishReset(
  4980. IN OUT PFDC_FDO_EXTENSION FdoExtension
  4981. )
  4982. /*++
  4983. Routine Description:
  4984. This routine is called to complete a reset operation which entails
  4985. reading the interrupt status from each active channel on the floppy
  4986. controller.
  4987. Arguments:
  4988. FdoExtension - a pointer to our data area for this controller.
  4989. Return Value:
  4990. STATUS_SUCCESS if this controller appears to have been reset properly,
  4991. error otherwise.
  4992. --*/
  4993. {
  4994. NTSTATUS ntStatus = STATUS_SUCCESS;
  4995. UCHAR statusRegister0;
  4996. UCHAR cylinder;
  4997. UCHAR driveNumber;
  4998. FdcDump(
  4999. FDCSHOW,
  5000. ("Fdc: FcFinishReset\n")
  5001. );
  5002. //
  5003. // Sense interrupt status for all drives.
  5004. //
  5005. for ( driveNumber = 0;
  5006. ( driveNumber < MAXIMUM_DISKETTES_PER_CONTROLLER ) &&
  5007. ( NT_SUCCESS( ntStatus ) );
  5008. driveNumber++ ) {
  5009. if ( driveNumber != 0 ) {
  5010. //
  5011. // Note that the ISR issued first SENSE INTERRUPT for us.
  5012. //
  5013. ntStatus = FcSendByte(
  5014. CommandTable[COMMND_SENSE_INTERRUPT_STATUS].OpCode,
  5015. FdoExtension,
  5016. TRUE );
  5017. }
  5018. if ( NT_SUCCESS( ntStatus ) ) {
  5019. ntStatus = FcGetByte( &statusRegister0, FdoExtension, TRUE );
  5020. if ( NT_SUCCESS( ntStatus ) ) {
  5021. ntStatus = FcGetByte( &cylinder, FdoExtension, TRUE );
  5022. }
  5023. }
  5024. }
  5025. return ntStatus;
  5026. }
  5027. NTSTATUS
  5028. FcFdcEnabler(
  5029. IN PDEVICE_OBJECT DeviceObject,
  5030. IN ULONG Ioctl,
  5031. IN OUT PVOID Data
  5032. )
  5033. /*++
  5034. Routine Description:
  5035. Call the floppy enabler driver to execute a command. This is always a
  5036. synchronous call and, since it includes waiting for an event, should only
  5037. be done at IRQL_PASSIVE_LEVEL.
  5038. All communication with the Floppy Enabler driver is carried out through
  5039. device i/o control requests. Any data that is to be sent to or received
  5040. from the floppy enabler driver is included in the Type3InputBuffer section
  5041. of the irp.
  5042. Arguments:
  5043. DeviceObject - a pointer to the current device object.
  5044. Ioctl - the IoControl code that will be sent to the Floppy Enabler.
  5045. Data - a pointer to data that will be sent to or received from the Floppy
  5046. Enabler.
  5047. Return Value:
  5048. STATUS_TIMEOUT if the Floppy Enabler does not respond in a timely manner.
  5049. otherwise IoStatus.Status from the Floppy Enabler is returned.
  5050. --*/
  5051. {
  5052. PIRP irp;
  5053. PIO_STACK_LOCATION irpStack;
  5054. KEVENT doneEvent;
  5055. IO_STATUS_BLOCK ioStatus;
  5056. NTSTATUS ntStatus;
  5057. FdcDump(FDCINFO,("FcFdcEnabler: Calling fdc enabler with %x\n", Ioctl));
  5058. KeInitializeEvent( &doneEvent,
  5059. NotificationEvent,
  5060. FALSE);
  5061. //
  5062. // Create an IRP for enabler
  5063. //
  5064. irp = IoBuildDeviceIoControlRequest( Ioctl,
  5065. DeviceObject,
  5066. NULL,
  5067. 0,
  5068. NULL,
  5069. 0,
  5070. TRUE,
  5071. &doneEvent,
  5072. &ioStatus );
  5073. if (irp == NULL) {
  5074. FdcDump(FDCDBGP,("FcFdcEnabler: Can't allocate Irp\n"));
  5075. //
  5076. // If an Irp can't be allocated, then this call will
  5077. // simply return. This will leave the queue frozen for
  5078. // this device, which means it can no longer be accessed.
  5079. //
  5080. return STATUS_INSUFFICIENT_RESOURCES;
  5081. }
  5082. irpStack = IoGetNextIrpStackLocation(irp);
  5083. irpStack->Parameters.DeviceIoControl.Type3InputBuffer = Data;
  5084. //
  5085. // Call the driver and request the operation
  5086. //
  5087. ntStatus = IoCallDriver(DeviceObject, irp);
  5088. if ( ntStatus == STATUS_PENDING ) {
  5089. //
  5090. // Now wait for operation to complete (should already be done, but
  5091. // maybe not)
  5092. //
  5093. KeWaitForSingleObject( &doneEvent,
  5094. Executive,
  5095. KernelMode,
  5096. FALSE,
  5097. NULL);
  5098. ntStatus = ioStatus.Status;
  5099. }
  5100. return ntStatus;
  5101. }
  5102. VOID
  5103. FdcGetEnablerDevice(
  5104. IN OUT PFDC_FDO_EXTENSION FdoExtension
  5105. )
  5106. {
  5107. PIRP irp;
  5108. PIO_STACK_LOCATION irpSp;
  5109. KEVENT doneEvent;
  5110. IO_STATUS_BLOCK ioStatus;
  5111. NTSTATUS ntStatus;
  5112. FdcDump(FDCINFO,("FdcGetEnablerDevice:\n"));
  5113. KeInitializeEvent( &doneEvent,
  5114. NotificationEvent,
  5115. FALSE);
  5116. //
  5117. // Create an IRP for enabler
  5118. //
  5119. irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_INTERNAL_GET_ENABLER,
  5120. FdoExtension->TargetObject,
  5121. NULL,
  5122. 0,
  5123. NULL,
  5124. 0,
  5125. TRUE,
  5126. &doneEvent,
  5127. &ioStatus );
  5128. if (irp == NULL) {
  5129. FdcDump(FDCDBGP,("FdcGetEnablerDevice: Can't allocate Irp\n"));
  5130. //
  5131. // If an Irp can't be allocated, then this call will
  5132. // simply return. This will leave the queue frozen for
  5133. // this device, which means it can no longer be accessed.
  5134. //
  5135. return;
  5136. }
  5137. irpSp = IoGetNextIrpStackLocation( irp );
  5138. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = &FdoExtension->FdcEnablerSupported;
  5139. //
  5140. // Call the driver and request the operation
  5141. //
  5142. ntStatus = IoCallDriver( FdoExtension->TargetObject, irp );
  5143. //
  5144. // Now wait for operation to complete (should already be done, but
  5145. // maybe not)
  5146. //
  5147. if ( ntStatus == STATUS_PENDING ) {
  5148. ntStatus = KeWaitForSingleObject( &doneEvent,
  5149. Executive,
  5150. KernelMode,
  5151. FALSE,
  5152. NULL);
  5153. }
  5154. return;
  5155. }
  5156. ULONG
  5157. FdcFindIsaBusNode(
  5158. IN OUT VOID
  5159. )
  5160. /*++
  5161. Routine Description:
  5162. Find Isa bus node in the registry.
  5163. Arguments:
  5164. Return Value:
  5165. Node number.
  5166. --*/
  5167. {
  5168. ULONG NodeNumber = 0;
  5169. BOOLEAN FoundBus = FALSE;
  5170. NTSTATUS Status;
  5171. RTL_QUERY_REGISTRY_TABLE parameters[2];
  5172. UNICODE_STRING invalidBusName;
  5173. UNICODE_STRING targetBusName;
  5174. UNICODE_STRING isaBusName;
  5175. //
  5176. // Initialize invalid bus name.
  5177. //
  5178. RtlInitUnicodeString(&invalidBusName,L"BADBUS");
  5179. //
  5180. // Initialize "ISA" bus name.
  5181. //
  5182. RtlInitUnicodeString(&isaBusName,L"ISA");
  5183. parameters[0].QueryRoutine = NULL;
  5184. parameters[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
  5185. RTL_QUERY_REGISTRY_DIRECT;
  5186. parameters[0].Name = L"Identifier";
  5187. parameters[0].EntryContext = &targetBusName;
  5188. parameters[0].DefaultType = REG_SZ;
  5189. parameters[0].DefaultData = &invalidBusName;
  5190. parameters[0].DefaultLength = 0;
  5191. parameters[1].QueryRoutine = NULL;
  5192. parameters[1].Flags = 0;
  5193. parameters[1].Name = NULL;
  5194. parameters[1].EntryContext = NULL;
  5195. do {
  5196. CHAR AnsiBuffer[512];
  5197. ANSI_STRING AnsiString;
  5198. UNICODE_STRING registryPath;
  5199. //
  5200. // Build path buffer...
  5201. //
  5202. sprintf(AnsiBuffer,ISA_BUS_NODE,NodeNumber);
  5203. RtlInitAnsiString(&AnsiString,AnsiBuffer);
  5204. Status = RtlAnsiStringToUnicodeString(&registryPath,&AnsiString,TRUE);
  5205. if (!(NT_SUCCESS(Status))) {
  5206. break;
  5207. }
  5208. //
  5209. // Initialize recieve buffer.
  5210. //
  5211. targetBusName.Buffer = NULL;
  5212. //
  5213. // Query it.
  5214. //
  5215. Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  5216. registryPath.Buffer,
  5217. parameters,
  5218. NULL,
  5219. NULL);
  5220. RtlFreeUnicodeString(&registryPath);
  5221. if (!NT_SUCCESS(Status) || (targetBusName.Buffer == NULL)) {
  5222. break;
  5223. }
  5224. //
  5225. // Is this "ISA" node ?
  5226. //
  5227. if (RtlCompareUnicodeString(&targetBusName,&isaBusName,TRUE) == 0) {
  5228. //
  5229. // Found.
  5230. //
  5231. FoundBus = TRUE;
  5232. break;
  5233. }
  5234. //
  5235. // Can we find any node for this ??
  5236. //
  5237. if (RtlCompareUnicodeString(&targetBusName,&invalidBusName,TRUE) == 0) {
  5238. //
  5239. // Not found.
  5240. //
  5241. break;
  5242. }
  5243. RtlFreeUnicodeString(&targetBusName);
  5244. //
  5245. // Next node number..
  5246. //
  5247. NodeNumber++;
  5248. } while (TRUE);
  5249. if (targetBusName.Buffer) {
  5250. RtlFreeUnicodeString(&targetBusName);
  5251. }
  5252. if (!FoundBus) {
  5253. NodeNumber = (ULONG)-1;
  5254. }
  5255. return (NodeNumber);
  5256. }
  5257. NTSTATUS
  5258. FdcHdbit(
  5259. IN PDEVICE_OBJECT DeviceObject,
  5260. IN PFDC_FDO_EXTENSION FdoExtension,
  5261. IN PSET_HD_BIT_PARMS SetHdBitParams
  5262. )
  5263. /*++
  5264. Routine Description:
  5265. Set a Hd bit or a FDD EXC bit.
  5266. Arguments:
  5267. fdoExtension - a pointer to our data area for the device extension.
  5268. Return Value:
  5269. TRUE : Changed HD bit
  5270. FALSE: No changed HD bit
  5271. --*/
  5272. {
  5273. NTSTATUS ntStatus;
  5274. USHORT st; // State of HD bit
  5275. USHORT st2; // Set on/off HD bit
  5276. USHORT st3; // When set HD bit, then st3=1
  5277. USHORT st4; // 1.44MB bit for 1.44MB media
  5278. SHORT sel; // 1.44MB Selector No for 1.44MB media
  5279. SHORT st5=0; // 1.44MB on: wait for spin for 1.44MB media
  5280. LARGE_INTEGER motorOnDelay;
  5281. USHORT lpc;
  5282. UCHAR resultStatus0Save[4];
  5283. USHORT resultStatus0;
  5284. ULONG getStatusRetryCount;
  5285. ULONG rqmReadyRetryCount;
  5286. BOOLEAN media144MB;
  5287. BOOLEAN mediaMore120MB;
  5288. BOOLEAN supportDrive;
  5289. media144MB = SetHdBitParams->Media144MB;
  5290. mediaMore120MB = SetHdBitParams->More120MB;
  5291. sel = SetHdBitParams->DeviceUnit;
  5292. SetHdBitParams->ChangedHdBit = FALSE;
  5293. ASSERT( FdoExtension->ControllerAddress.ModeChange == (PUCHAR)0xbe );
  5294. ASSERT( FdoExtension->ControllerAddress.ModeChangeEx == (PUCHAR)0x4be );
  5295. supportDrive = TRUE;
  5296. st3=0;
  5297. ntStatus=0;
  5298. //
  5299. // Normal mode.
  5300. //
  5301. st = READ_CONTROLLER(FdoExtension->ControllerAddress.ModeChange);
  5302. st2 = st & 0x02;
  5303. //
  5304. // Normal mode.
  5305. // Check dip switch.
  5306. //
  5307. st4 = READ_CONTROLLER(FdoExtension->ControllerAddress.DriveControl);
  5308. st4 = st4 & 0x04;
  5309. if (((FdoExtension->FloppyEquip) & 0x0c) != 0) {
  5310. //
  5311. // Exist out side FDD unit.
  5312. //
  5313. if ( st4 == 0 ) {
  5314. //
  5315. // DIP SW 1-4 on
  5316. //
  5317. sel = sel - 2;
  5318. if( sel < 0 ) {
  5319. sel = sel + 4;
  5320. }
  5321. }
  5322. }
  5323. if ( supportDrive ) {
  5324. for( lpc = 0 ; lpc < 4 ; lpc++ ) {
  5325. resultStatus0Save[lpc]=FdoExtension->ResultStatus0[lpc];
  5326. }
  5327. if ( SetHdBitParams->DriveType144MB ) {
  5328. //
  5329. // 1.44MB drive.
  5330. //
  5331. st4=sel*32;
  5332. WRITE_CONTROLLER(FdoExtension->ControllerAddress.ModeChangeEx,st4);
  5333. st4 = READ_CONTROLLER(FdoExtension->ControllerAddress.ModeChangeEx);
  5334. st4 = st4 & 0x01;
  5335. if ( media144MB ) {
  5336. //
  5337. // 1.44MB media.
  5338. //
  5339. if(st4==0){
  5340. //
  5341. // WRE on, IHMD off.
  5342. //
  5343. st4=sel*32+0x11;
  5344. WRITE_CONTROLLER(FdoExtension->ControllerAddress.ModeChangeEx,st4);
  5345. st5=1;
  5346. }
  5347. } else {
  5348. //
  5349. // Not 1.44MB media.
  5350. //
  5351. if(st4!=0){
  5352. //
  5353. // WRE on, IHMD off.
  5354. //
  5355. st4=sel*32+0x10;
  5356. WRITE_CONTROLLER(FdoExtension->ControllerAddress.ModeChangeEx,st4);
  5357. st5=1;
  5358. }
  5359. }
  5360. }
  5361. if ( mediaMore120MB ) {
  5362. //
  5363. // Media 1.2MB and More.
  5364. //
  5365. if(st2==0){
  5366. //
  5367. // When FDD exc bit is on,
  5368. // then set FDD exc bit off,
  5369. // and set emotion bit on.
  5370. //
  5371. st |= 0x02;
  5372. st |= 0x04;
  5373. WRITE_CONTROLLER(FdoExtension->ControllerAddress.ModeChange,st);
  5374. st3 = 1;
  5375. }
  5376. } else {
  5377. //
  5378. // Media between 160 and 720
  5379. //
  5380. if ( st2 != 0 ) {
  5381. //
  5382. // When FDD exc bit is on,
  5383. // then set FDD exc bit off,
  5384. // and set emotion bit on.
  5385. //
  5386. st &= 0xfd;
  5387. st |= 0x04;
  5388. WRITE_CONTROLLER(FdoExtension->ControllerAddress.ModeChange,st);
  5389. st3 = 1;
  5390. }
  5391. }
  5392. if(st5==1){
  5393. //
  5394. // Wait until motor spin up.
  5395. //
  5396. motorOnDelay.LowPart = (unsigned long)(- ( 10 * 1000 * 600 )); /*500ms*/
  5397. motorOnDelay.HighPart = -1;
  5398. (VOID) KeDelayExecutionThread( KernelMode, FALSE, &motorOnDelay );
  5399. //
  5400. // Sense target drive and get all data at transition of condistion.
  5401. //
  5402. FdoExtension->FifoBuffer[0] = COMMND_SENSE_DRIVE_STATUS;
  5403. FdoExtension->FifoBuffer[1] = SetHdBitParams->DeviceUnit;
  5404. ntStatus = FcIssueCommand( FdoExtension,
  5405. FdoExtension->FifoBuffer,
  5406. FdoExtension->FifoBuffer,
  5407. NULL,
  5408. 0,
  5409. 0 );
  5410. resultStatus0 = FdcRqmReadyWait(FdoExtension, 0);
  5411. }
  5412. for(lpc=0;lpc<4;lpc++){
  5413. FdoExtension->ResultStatus0[lpc] = resultStatus0Save[lpc];
  5414. }
  5415. //
  5416. // Change HD bit?
  5417. //
  5418. if(st3==1){
  5419. FcInitializeControllerHardware(FdoExtension,DeviceObject);
  5420. SetHdBitParams->ChangedHdBit = TRUE;
  5421. }
  5422. }
  5423. FdcDump(
  5424. FDCSTATUS,
  5425. ("Floppy : HdBit resultStatus0 = %x \n",
  5426. resultStatus0)
  5427. );
  5428. return ntStatus;
  5429. }
  5430. ULONG
  5431. FdcGet0Seg(
  5432. IN PUCHAR ConfigurationData1,
  5433. IN ULONG Offset
  5434. )
  5435. /*++
  5436. Routine Description:
  5437. This routine get BIOS common area data and return it.
  5438. 0x500 : 1MB port or not
  5439. 0x501 : High resolution/Normal, 386/768KB
  5440. 0x55c : 1MB drive : [#0,#1] or [#0,#1,#2,#3]
  5441. Arguments:
  5442. Offset - Offset value from 0 segment(0:<Offset>).
  5443. Return Value:
  5444. BIOS common area data.
  5445. --*/
  5446. {
  5447. UCHAR biosCommonAreaData = 0;
  5448. if ((Offset<0x400) || (Offset>0x5ff)) {
  5449. return (ULONG)0xffff;
  5450. }
  5451. //
  5452. // Get BIOS common area data.
  5453. //
  5454. biosCommonAreaData = ConfigurationData1[40+(Offset-0x400)];
  5455. return (ULONG)biosCommonAreaData;
  5456. }
  5457. UCHAR
  5458. FdcRqmReadyWait(
  5459. IN PFDC_FDO_EXTENSION FdoExtension,
  5460. IN ULONG IssueSenseInterrupt
  5461. )
  5462. /*++
  5463. Routine Description:
  5464. RQM Ready wait
  5465. Arguments:
  5466. FdoExtension - a pointer to our data area for the device extension.
  5467. IssueSenseInterrupt - Indicate issue COMMND_SENSE_INTERRUPT_STATUS.
  5468. 0 - Issue no COMMND_SENSE_INTERRUPT_STATUS.
  5469. 1 - Issue COMMND_SENSE_INTERRUPT_STATUS with RQM Check.
  5470. 2 - Issue COMMND_SENSE_INTERRUPT_STATUS without RQM Check.
  5471. 3 - Issue COMMND_SENSE_INTERRUPT_STATUS for AI Interrupt.
  5472. Return Value:
  5473. ntStatus - STATUS_SUCCESS
  5474. --*/
  5475. {
  5476. ULONG getStatusRetryCount;
  5477. ULONG rqmReadyRetryCount;
  5478. ULONG j;
  5479. UCHAR resultStatus0;
  5480. UCHAR statusByte;
  5481. ASSERT(IssueSenseInterrupt < 4);
  5482. do{
  5483. if (IssueSenseInterrupt != 0) {
  5484. //
  5485. // Sense Interrupt status.
  5486. // RQM ready wait.
  5487. //
  5488. if ((IssueSenseInterrupt == 1) || (IssueSenseInterrupt == 3)) {
  5489. rqmReadyRetryCount=0;
  5490. //
  5491. // RQM ready check.
  5492. //
  5493. while ((READ_CONTROLLER( FdoExtension->ControllerAddress.Status)
  5494. & STATUS_IO_READY_MASK1) != STATUS_RQM_READY){
  5495. rqmReadyRetryCount++;
  5496. if(rqmReadyRetryCount > RQM_READY_RETRY_COUNT){
  5497. break;
  5498. }
  5499. KeStallExecutionProcessor( 1 );
  5500. }
  5501. if(rqmReadyRetryCount > (RQM_READY_RETRY_COUNT-1)){
  5502. FdcDump(
  5503. FDCDBGP,
  5504. ("Floppy: Issue RQM ready wait 1 error! \n")
  5505. );
  5506. if (IssueSenseInterrupt == 1) {
  5507. break;
  5508. }
  5509. }
  5510. }
  5511. //
  5512. // Issue sense interrupt forcibly.
  5513. //
  5514. WRITE_CONTROLLER(
  5515. FdoExtension->ControllerAddress.Fifo,
  5516. 0x08);
  5517. // COMMND_SENSE_INTERRUPT_STATUS ); //******C-Phase DATA WRITE*
  5518. //
  5519. // Wait for busy.
  5520. //
  5521. for (rqmReadyRetryCount = ISR_SENSE_RETRY_COUNT; rqmReadyRetryCount; rqmReadyRetryCount--) {
  5522. statusByte = READ_CONTROLLER(
  5523. FdoExtension->ControllerAddress.Status );
  5524. if (statusByte & STATUS_CONTROLLER_BUSY)
  5525. break;
  5526. KeStallExecutionProcessor( 1 );
  5527. }
  5528. }
  5529. //
  5530. // Get status.
  5531. //
  5532. getStatusRetryCount = 0;
  5533. j = 0;
  5534. do {
  5535. //
  5536. // Check RQM ready.
  5537. //
  5538. rqmReadyRetryCount=0;
  5539. while ((READ_CONTROLLER( FdoExtension->ControllerAddress.Status)
  5540. & STATUS_IO_READY_MASK1) != STATUS_RQM_READY){
  5541. rqmReadyRetryCount++;
  5542. if(rqmReadyRetryCount > RQM_READY_RETRY_COUNT){
  5543. break;
  5544. }
  5545. KeStallExecutionProcessor( 1 );
  5546. }
  5547. if(rqmReadyRetryCount > (RQM_READY_RETRY_COUNT-1)){
  5548. FdcDump(
  5549. FDCDBGP,
  5550. ("Floppy: Int RQM ready wait \n")
  5551. );
  5552. KeStallExecutionProcessor( 1 );
  5553. break;
  5554. }
  5555. //
  5556. // Get status even if it is transition of condition.
  5557. //
  5558. statusByte = READ_CONTROLLER(FdoExtension->ControllerAddress.Status);
  5559. if ((statusByte & STATUS_IO_READY_MASK) == STATUS_WRITE_READY) {
  5560. //
  5561. // DIO is 1.
  5562. //
  5563. break;
  5564. }
  5565. if (j == 0) {
  5566. //
  5567. // R-Phase: Data read.
  5568. //
  5569. resultStatus0 = READ_CONTROLLER( FdoExtension->ControllerAddress.Fifo );
  5570. j=1;
  5571. //
  5572. // Check transition of condition.
  5573. //
  5574. if((resultStatus0 & STREG0_END_MASK)==STREG0_END_INVALID_COMMAND){
  5575. //
  5576. // Invalid
  5577. //
  5578. break;
  5579. }
  5580. if((resultStatus0 & STREG0_END_MASK) == STREG0_END_DRIVE_NOT_READY){
  5581. if(FdoExtension->ResetFlag){
  5582. FdoExtension->ResultStatus0[resultStatus0 & 3] = resultStatus0;
  5583. }
  5584. }
  5585. } else {
  5586. //
  5587. // R-Phase: Data read.
  5588. //
  5589. READ_CONTROLLER( FdoExtension->ControllerAddress.Fifo );
  5590. }
  5591. getStatusRetryCount++;
  5592. } while (getStatusRetryCount > RQM_READY_RETRY_COUNT);
  5593. if(getStatusRetryCount > RQM_READY_RETRY_COUNT-1){
  5594. KeStallExecutionProcessor( 1 );
  5595. FdcDump(
  5596. FDCDBGP,
  5597. ("Floppy: Issue status overflow error! \n")
  5598. );
  5599. }
  5600. } while ((IssueSenseInterrupt != 0) &&
  5601. ((resultStatus0 & STREG0_END_MASK) != STREG0_END_INVALID_COMMAND));
  5602. return resultStatus0;
  5603. }
  5604. #ifdef TOSHIBAJ
  5605. /*
  5606. IOCTL_DISK_INTERNAL_ENABLE_3_MODE:
  5607. Media Speed T/F
  5608. -------------------------
  5609. 1.44MB 300RPM FALSE
  5610. 1.23MB 360RPM TRUE
  5611. */
  5612. #define RPM_300 1 // 1.44MB media format
  5613. #define RPM_360 2 // 1.2MB,1.23MB media format
  5614. NTSTATUS FcFdcEnable3Mode(
  5615. IN PFDC_FDO_EXTENSION FdoExtension,
  5616. IN PIRP Irp
  5617. )
  5618. { NTSTATUS ntStatus;
  5619. PENABLE_3_MODE param;
  5620. PIO_STACK_LOCATION irpSp;
  5621. UCHAR motorSpeed;
  5622. UCHAR unitNumber;
  5623. PUCHAR configPort;
  5624. UCHAR configDataValue = 0;
  5625. LARGE_INTEGER changeRotationDelay;
  5626. irpSp = IoGetCurrentIrpStackLocation( Irp );
  5627. param = (PENABLE_3_MODE)irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  5628. FdcDump(FDCSHOW,("FcFdcEnable3MODE()\n"));
  5629. if( param == NULL )
  5630. return STATUS_SUCCESS; // may be later...
  5631. FdcDump(FDCSHOW,("Parameters...%d %d\n",
  5632. // param->DeviceUnit, param->Enable3Mode, param->Context));
  5633. param->DeviceUnit, param->Enable3Mode));
  5634. if (FdoExtension->Available3Mode==FALSE)
  5635. return STATUS_SUCCESS;
  5636. // if(param->Context==TRUE)
  5637. // return STATUS_SUCCESS;
  5638. unitNumber = param->DeviceUnit;
  5639. motorSpeed = (param->Enable3Mode)? SMC_DENSEL_LOW: SMC_DELSEL_HIGH; // 360:300
  5640. // Feb.9.1998 KIADP013 Change Speed
  5641. // Change speed
  5642. // 1.Enter configuration state
  5643. // 2.Select device
  5644. // 3.Change speed
  5645. // Write 'f1h' to index port
  5646. // Read from data port
  5647. // Rewrite to data port
  5648. // bit [3:2] Densel speed
  5649. // 10 H 360rpm
  5650. // 11 L 300rpm
  5651. // 4.Exit configuration state
  5652. configPort = FdoExtension->ConfigBase;
  5653. FdcDump(
  5654. FDCSHOW,
  5655. ("Config: index port %x, data port %x\n",
  5656. SMC_INDEX_PORT(configPort), SMC_DATA_PORT(configPort))
  5657. );
  5658. // Must change data transfer rate to 500BPS when change FDD rotation.
  5659. WRITE_CONTROLLER(FdoExtension->ControllerAddress.DRDC.DataRate, DATART_0500 );
  5660. // Change speed
  5661. WRITE_PORT_UCHAR(configPort, SMC_KEY_ENTER_CONFIG); // Enter config state
  5662. // Select FDD
  5663. WRITE_PORT_UCHAR(SMC_INDEX_PORT(configPort), SMC_INDEX_DEVICE);
  5664. WRITE_PORT_UCHAR(SMC_DATA_PORT(configPort), SMC_DEVICE_FDC);
  5665. // Get current value
  5666. WRITE_PORT_UCHAR(SMC_INDEX_PORT(configPort), SMC_INDEX_FDC_OPT);
  5667. configDataValue = READ_PORT_UCHAR(SMC_DATA_PORT(configPort));
  5668. if ((configDataValue & SMC_MASK_DENSEL) == motorSpeed) {
  5669. WRITE_PORT_UCHAR(configPort, SMC_KEY_EXIT_CONFIG);
  5670. return STATUS_SUCCESS;
  5671. }
  5672. // Set speed
  5673. configDataValue &= ~SMC_MASK_DENSEL;
  5674. configDataValue |= motorSpeed;
  5675. WRITE_PORT_UCHAR(SMC_DATA_PORT(configPort), configDataValue);
  5676. WRITE_PORT_UCHAR(configPort, SMC_KEY_EXIT_CONFIG); // Exit config state
  5677. if (motorSpeed == SMC_DENSEL_LOW) {
  5678. FdcDump(
  5679. FDCSHOW,
  5680. ("------- FDD rotation change: 300rpm -> 360rpm\n")
  5681. );
  5682. } else {
  5683. FdcDump(
  5684. FDCSHOW,
  5685. ("------- FDD rotation change: 360rpm -> 300rpm\n")
  5686. );
  5687. }
  5688. // Set Delay time to 500ms
  5689. changeRotationDelay.LowPart =(ULONG)( - ( 10 * 1000 * 500 )); // 17-Oct-1994 RKBUG001
  5690. changeRotationDelay.HighPart = -1;
  5691. FdoExtension->LastMotorSettleTime = changeRotationDelay;
  5692. // Delay 500ms
  5693. KeDelayExecutionThread( KernelMode, FALSE, &changeRotationDelay );
  5694. return STATUS_SUCCESS;
  5695. }
  5696. NTSTATUS FcFdcAvailable3Mode(
  5697. IN PFDC_FDO_EXTENSION FdoExtension,
  5698. IN PIRP Irp
  5699. )
  5700. {
  5701. PIO_STACK_LOCATION irpSp;
  5702. FdcDump(FDCSHOW,("FcFdcAvailabe3MODE\n"));
  5703. irpSp = IoGetCurrentIrpStackLocation( Irp );
  5704. // Feb.9.1998 KIADP012 Identify controller
  5705. // Feb.12.1998 KIADP014 Get the address of config port
  5706. return (FdoExtension->Available3Mode)? STATUS_SUCCESS: STATUS_UNSUCCESSFUL;
  5707. }
  5708. // Feb.12.1998 KIADP014 Get the address of config port
  5709. BOOLEAN
  5710. FcCheckConfigPort(
  5711. IN PUCHAR ConfigPort
  5712. )
  5713. {
  5714. BOOLEAN found = FALSE;
  5715. ULONG configAddr = 0;
  5716. UCHAR controllerId = 0;
  5717. FdcDump( FDCSHOW, ("FcCheckConfigPort: Configuration Port %x\n", ConfigPort) );
  5718. if (!SmcConfigID) {
  5719. return found;
  5720. }
  5721. // Get data
  5722. if (ConfigPort) {
  5723. WRITE_PORT_UCHAR(ConfigPort, SMC_KEY_ENTER_CONFIG);
  5724. // Controller ID
  5725. if (SmcConfigID) {
  5726. WRITE_PORT_UCHAR(SMC_INDEX_PORT(ConfigPort), SMC_INDEX_IDENTIFY);
  5727. controllerId = READ_PORT_UCHAR(SMC_DATA_PORT(ConfigPort));
  5728. FdcDump( FDCINFO, ("Fdc: Controller ID %x\n", controllerId) );
  5729. }
  5730. WRITE_PORT_UCHAR(ConfigPort,SMC_KEY_EXIT_CONFIG);
  5731. }
  5732. // Check data
  5733. if (controllerId == SmcConfigID) {
  5734. found = TRUE;
  5735. }
  5736. return found;
  5737. }
  5738. #endif