Source code of Windows XP (NT5)
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.

1239 lines
34 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: util.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "ide.h"
  11. #pragma alloc_text(NONPAGE, IdePortChannelEmpty)
  12. #pragma alloc_text(PAGE, DigestResourceList)
  13. #pragma alloc_text(PAGE, AtapiBuildIoAddress)
  14. #pragma alloc_text(PAGE, IdeGetDeviceCapabilities)
  15. #pragma alloc_text(NONPAGE, IdePortpWaitOnBusyEx)
  16. #pragma alloc_text(PAGE, IdeCreateIdeDirectory)
  17. #ifdef DPC_FOR_EMPTY_CHANNEL
  18. BOOLEAN
  19. IdePortIdentifyDevice(
  20. IN PIDE_REGISTERS_1 CmdRegBase,
  21. IN PIDE_REGISTERS_2 CtrlRegBase,
  22. IN ULONG MaxIdeDevice
  23. )
  24. {
  25. UCHAR statusByte1;
  26. ULONG retryCount=4;
  27. BOOLEAN emptyChannel=TRUE;
  28. ULONG deviceNumber=0;
  29. ULONG i;
  30. retryCount = 4;
  31. emptyChannel = TRUE;
  32. deviceNumber = 0;
  33. retryIdentifier:
  34. //
  35. // Select the master device
  36. //
  37. SelectIdeDevice(CmdRegBase, deviceNumber, 0);
  38. //
  39. // write out indentifier to readable and writable io registers
  40. //
  41. WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
  42. WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
  43. //
  44. // Check if indentifier can be read back.
  45. //
  46. if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) ||
  47. (READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) {
  48. statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command);
  49. DebugPrint((2,
  50. "IdePortChannelEmpty: status read back from Master (%x)\n",
  51. statusByte1));
  52. if (statusByte1 & IDE_STATUS_BUSY) {
  53. i = 0;
  54. //
  55. // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
  56. // warm boots don't clear.
  57. //
  58. do {
  59. KeStallExecutionProcessor(1000);
  60. statusByte1 = READ_PORT_UCHAR(CmdRegBase->Command);
  61. DebugPrint((3,
  62. "IdePortChannelEmpty: First access to status %x\n",
  63. statusByte1));
  64. } while ((statusByte1 & IDE_STATUS_BUSY) && ++i < 10);
  65. if (retryCount-- && (!(statusByte1 & IDE_STATUS_BUSY))) {
  66. goto retryIdentifier;
  67. }
  68. }
  69. //
  70. // Select slave.
  71. //
  72. deviceNumber++;
  73. SelectIdeDevice(CmdRegBase, deviceNumber, 0);
  74. //
  75. // write out indentifier to readable and writable io registers
  76. //
  77. WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
  78. WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
  79. //
  80. // Check if indentifier can be read back.
  81. //
  82. if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) ||
  83. (READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) {
  84. statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command);
  85. DebugPrint((2,
  86. "IdePortChannelEmpty: status read back from Slave (%x)\n",
  87. statusByte1));
  88. } else {
  89. emptyChannel = FALSE;
  90. }
  91. } else {
  92. emptyChannel = FALSE;
  93. }
  94. deviceNumber++;
  95. if ( (deviceNumber < MaxIdeDevice) && emptyChannel ) {
  96. goto retryIdentifier;
  97. }
  98. return emptyChannel;
  99. } //IdePortIdentifyDevice
  100. ULONG
  101. IdePortChannelEmptyQuick (
  102. IN PIDE_REGISTERS_1 CmdRegBase,
  103. IN PIDE_REGISTERS_2 CtrlRegBase,
  104. IN ULONG MaxIdeDevice,
  105. IN PULONG CurrentDevice,
  106. IN PULONG moreWait,
  107. IN PULONG NoRetry
  108. )
  109. {
  110. //
  111. // try EXECUTE_DIAGNOSTICS. No.
  112. //
  113. //
  114. // statusByte1 needs to be initialized to ff
  115. //
  116. UCHAR statusByte1=0xff;
  117. UCHAR statusByte2;
  118. ULONG i;
  119. BOOLEAN allStatusBytesAllFs;
  120. allStatusBytesAllFs = TRUE;
  121. DebugPrint((1, "ChannelEmptyQuick: wait=%d, Device=%d\n",
  122. *moreWait, *CurrentDevice));
  123. if (*moreWait) {
  124. (*moreWait)--;
  125. SelectIdeDevice(CmdRegBase, (*CurrentDevice), 0);
  126. IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff);
  127. DebugPrint((1, "ATAPI: Status after first retry=%x\n", statusByte1));
  128. if (statusByte1==0xff) {
  129. (*CurrentDevice)++;
  130. *moreWait=0;
  131. }
  132. }
  133. if (*moreWait && (statusByte1 & IDE_STATUS_BUSY)) {
  134. return STATUS_RETRY;
  135. }
  136. if (!(*NoRetry) && (statusByte1 & IDE_STATUS_BUSY) &&
  137. ((statusByte1 != 0xfe) &&
  138. (statusByte1 != 0xff))) {
  139. DebugPrint((1,
  140. "ATAPI: IdePortChannelEmpty: channel looks busy 0x%x. try a reset\n",
  141. statusByte1));
  142. //
  143. // channel look hung or busy
  144. //
  145. // try a hard reset to bring it to idle
  146. WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_RESET_CONTROLLER);
  147. //
  148. // ATA-2 spec requires a minimum of 5 microsec stall here
  149. //
  150. KeStallExecutionProcessor (10);
  151. WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_REENABLE_CONTROLLER);
  152. i=*CurrentDevice;
  153. SelectIdeDevice(CmdRegBase, i, 0);
  154. IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff);
  155. if ((statusByte1 & IDE_STATUS_BUSY) && (statusByte1 != 0xff)) {
  156. *moreWait=2; //wait for 2 more timer ticks
  157. *NoRetry=1;
  158. return STATUS_RETRY;
  159. }
  160. }
  161. if (statusByte1 != 0xFF) {
  162. allStatusBytesAllFs = FALSE;
  163. (*CurrentDevice)++;
  164. }
  165. for (i=*CurrentDevice; i<MaxIdeDevice && allStatusBytesAllFs; i++) {
  166. //
  167. // make sure device is not busy
  168. //
  169. //
  170. // Select the master device
  171. //
  172. SelectIdeDevice(CmdRegBase, i, 0);
  173. if (Is98LegacyIde(CmdRegBase)) {
  174. if (READ_PORT_UCHAR(CmdRegBase->DriveSelect) != (((i & 0x1) << 4) | 0xA0)) {
  175. //
  176. // Bad controller.
  177. //
  178. continue;
  179. }
  180. }
  181. GetStatus(CmdRegBase, statusByte1);
  182. DebugPrint((1, "ATAPI:status for device %d after GetStatus=%x\n",i, statusByte1));
  183. if (statusByte1 == 0xff) {
  184. continue;
  185. }
  186. if (statusByte1 == 0xfe) {
  187. continue;
  188. }
  189. IdePortWaitOnBusyExK (CmdRegBase, statusByte1, 0xff);
  190. if ((statusByte1 & 0xfe) == 0xfe) {
  191. continue;
  192. }
  193. if (statusByte1 & IDE_STATUS_BUSY) {
  194. DebugPrint((1, "ATAPI: Re-init the counts:device=%d, status=%x",
  195. i, statusByte1));
  196. *CurrentDevice=i;
  197. *moreWait=2;
  198. *NoRetry=0;
  199. return STATUS_RETRY;
  200. }
  201. if (statusByte1 != 0xFF) {
  202. allStatusBytesAllFs = FALSE;
  203. }
  204. }
  205. if (allStatusBytesAllFs) {
  206. //
  207. // all status bytes are 0xff,
  208. // no controller at this location
  209. //
  210. return 1;
  211. }
  212. i=(IdePortIdentifyDevice(CmdRegBase, CtrlRegBase, MaxIdeDevice)) ? 1: 0;
  213. return i;
  214. }//IdePortChannelEmptyQuick
  215. #endif
  216. BOOLEAN
  217. IdePortChannelEmpty (
  218. IN PIDE_REGISTERS_1 CmdRegBase,
  219. IN PIDE_REGISTERS_2 CtrlRegBase,
  220. IN ULONG MaxIdeDevice
  221. )
  222. /*++
  223. Routine Description:
  224. quickly check whether a IDE channel exist at the given io location
  225. Arguments:
  226. CmdRegBase - command registers
  227. CtrlRegBase - control registers
  228. MaxIdeDevice - number of max devices
  229. Return Value:
  230. TRUE - Yes, the channel is empty
  231. FALSE - No, the channel is not empty
  232. --*/
  233. {
  234. UCHAR statusByte1;
  235. UCHAR statusByte2;
  236. ULONG retryCount;
  237. ULONG i;
  238. BOOLEAN emptyChannel;
  239. ULONG deviceNumber;
  240. BOOLEAN allStatusBytesAllFs;
  241. allStatusBytesAllFs = TRUE;
  242. for (i=0; i<MaxIdeDevice; i++) {
  243. //
  244. // make sure device is not busy
  245. //
  246. //
  247. // Select the master device
  248. //
  249. SelectIdeDevice(CmdRegBase, i, 0);
  250. if (Is98LegacyIde(CmdRegBase)) {
  251. if (READ_PORT_UCHAR(CmdRegBase->DriveSelect) != (((i & 0x1) << 4) | 0xA0)) {
  252. //
  253. // Bad controller.
  254. //
  255. continue;
  256. }
  257. }
  258. GetStatus(CmdRegBase, statusByte1);
  259. if (statusByte1 == 0xff) {
  260. continue;
  261. }
  262. if (statusByte1 == 0xfe) {
  263. continue;
  264. }
  265. IdePortWaitOnBusyEx (CmdRegBase, &statusByte1, 0xff);
  266. if ((statusByte1 & IDE_STATUS_BUSY) &&
  267. ((statusByte1 != 0xfe) &&
  268. (statusByte1 != 0xff))) {
  269. DebugPrint((1,
  270. "IdePortChannelEmpty: channel looks busy 0x%x. try a reset\n",
  271. statusByte1));
  272. //
  273. // channel look hung or busy
  274. //
  275. // try a hard reset to bring it to idle
  276. WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_RESET_CONTROLLER);
  277. //
  278. // ATA-2 spec requires a minimum of 5 microsec stall here
  279. //
  280. KeStallExecutionProcessor (10);
  281. WRITE_PORT_UCHAR (CtrlRegBase->DeviceControl, IDE_DC_REENABLE_CONTROLLER);
  282. SelectIdeDevice(CmdRegBase, i, 0);
  283. IdePortWaitOnBusyEx (CmdRegBase, &statusByte1, 0xff);
  284. }
  285. if (statusByte1 != 0xFF) {
  286. allStatusBytesAllFs = FALSE;
  287. }
  288. }
  289. if (allStatusBytesAllFs) {
  290. //
  291. // all status bytes are 0xff,
  292. // no controller at this location
  293. //
  294. return TRUE;
  295. }
  296. #ifdef DPC_FOR_EMPTY_CHANNEL
  297. return IdePortIdentifyDevice(CmdRegBase, CtrlRegBase, MaxIdeDevice);
  298. #endif
  299. retryCount = 4;
  300. emptyChannel = TRUE;
  301. deviceNumber = 0;
  302. retryIdentifier:
  303. //
  304. // Select the master device
  305. //
  306. SelectIdeDevice(CmdRegBase, deviceNumber, 0);
  307. //
  308. // write out indentifier to readable and writable io registers
  309. //
  310. WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
  311. WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
  312. //
  313. // Check if indentifier can be read back.
  314. //
  315. if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) ||
  316. (READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) {
  317. statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command);
  318. DebugPrint((2,
  319. "IdePortChannelEmpty: status read back from Master (%x)\n",
  320. statusByte1));
  321. if (statusByte1 & IDE_STATUS_BUSY) {
  322. i = 0;
  323. //
  324. // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
  325. // warm boots don't clear.
  326. //
  327. do {
  328. KeStallExecutionProcessor(1000);
  329. statusByte1 = READ_PORT_UCHAR(CmdRegBase->Command);
  330. DebugPrint((3,
  331. "IdePortChannelEmpty: First access to status %x\n",
  332. statusByte1));
  333. } while ((statusByte1 & IDE_STATUS_BUSY) && ++i < 10);
  334. if (retryCount-- && (!(statusByte1 & IDE_STATUS_BUSY))) {
  335. goto retryIdentifier;
  336. }
  337. }
  338. //
  339. // Select slave.
  340. //
  341. deviceNumber++;
  342. SelectIdeDevice(CmdRegBase, deviceNumber, 0);
  343. //
  344. // write out indentifier to readable and writable io registers
  345. //
  346. WRITE_PORT_UCHAR (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
  347. WRITE_PORT_UCHAR (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
  348. //
  349. // Check if indentifier can be read back.
  350. //
  351. if ((READ_PORT_UCHAR (CmdRegBase->CylinderHigh) != SAMPLE_CYLINDER_HIGH_VALUE) ||
  352. (READ_PORT_UCHAR (CmdRegBase->CylinderLow) != SAMPLE_CYLINDER_LOW_VALUE)) {
  353. statusByte1 = READ_PORT_UCHAR (CmdRegBase->Command);
  354. DebugPrint((2,
  355. "IdePortChannelEmpty: status read back from Slave (%x)\n",
  356. statusByte1));
  357. } else {
  358. emptyChannel = FALSE;
  359. }
  360. } else {
  361. emptyChannel = FALSE;
  362. }
  363. deviceNumber++;
  364. if ( (deviceNumber < MaxIdeDevice) && emptyChannel ) {
  365. goto retryIdentifier;
  366. }
  367. return emptyChannel;
  368. } //IdePortChannelEmpty
  369. NTSTATUS
  370. DigestResourceList (
  371. IN OUT PIDE_RESOURCE IdeResource,
  372. IN PCM_RESOURCE_LIST ResourceList,
  373. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *IrqPartialDescriptors
  374. )
  375. {
  376. NTSTATUS status;
  377. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
  378. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  379. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
  380. ULONG resourceListSize;
  381. ULONG i;
  382. ULONG j;
  383. BOOLEAN foundCommandBase;
  384. BOOLEAN foundControlBase;
  385. BOOLEAN foundIrqLevel;
  386. BOOLEAN resourceIsCommandPort;
  387. BOOLEAN AtdiskPrimaryClaimed;
  388. BOOLEAN AtdiskSecondaryClaimed;
  389. PHYSICAL_ADDRESS tranlatedAddress;
  390. IDE_REGISTERS_1 baseIoAddress1;
  391. ULONG baseIoAddress1Length;
  392. fullResourceList = ResourceList->List;
  393. resourceListSize = 0;
  394. DebugPrint ((5, "IdePort: DigestResourceList()\n"));
  395. foundCommandBase = FALSE;
  396. foundControlBase = FALSE;
  397. foundIrqLevel = FALSE;
  398. *IrqPartialDescriptors = NULL;
  399. status = STATUS_SUCCESS;
  400. AtdiskPrimaryClaimed = FALSE;
  401. AtdiskSecondaryClaimed = FALSE;
  402. for (i = 0;
  403. (i < ResourceList->Count) && NT_SUCCESS(status);
  404. i++) {
  405. partialResourceList = &(fullResourceList->PartialResourceList);
  406. partialDescriptors = fullResourceList->PartialResourceList.PartialDescriptors;
  407. AtapiBuildIoAddress ((PUCHAR)partialDescriptors[0].u.Port.Start.QuadPart,
  408. 0,
  409. &baseIoAddress1,
  410. NULL,
  411. &baseIoAddress1Length,
  412. NULL,
  413. NULL,
  414. NULL);
  415. for (j = 0;
  416. (j < partialResourceList->Count) && NT_SUCCESS(status);
  417. j++) {
  418. resourceIsCommandPort = FALSE;
  419. if (!Is98LegacyIde(&baseIoAddress1)) {
  420. if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  421. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  422. (partialDescriptors[j].u.Port.Length == baseIoAddress1Length)) {
  423. resourceIsCommandPort = TRUE;
  424. }
  425. } else {
  426. if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  427. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  428. (partialDescriptors[j].u.Port.Start.QuadPart == IDE_NEC98_COMMAND_PORT_ADDRESS)){
  429. resourceIsCommandPort = TRUE;
  430. } else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  431. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  432. (partialDescriptors[j].u.Port.Start.QuadPart != IDE_NEC98_COMMAND_PORT_ADDRESS) &&
  433. (partialDescriptors[j].u.Port.Start.QuadPart != (IDE_NEC98_COMMAND_PORT_ADDRESS + 0x10C))) {
  434. //
  435. // This is not the base port address for Legacy ide on NEC98;
  436. //
  437. continue;
  438. }
  439. }
  440. if (resourceIsCommandPort) {
  441. if (foundCommandBase) {
  442. //
  443. // got this before, just ignore it
  444. //
  445. // status = STATUS_INVALID_PARAMETER;
  446. } else {
  447. if (!Is98LegacyIde(&baseIoAddress1)) {
  448. if (partialDescriptors[j].u.Port.Start.QuadPart == IDE_STANDARD_PRIMARY_ADDRESS) {
  449. AtdiskPrimaryClaimed = TRUE;
  450. } else if (partialDescriptors[j].u.Port.Start.QuadPart == IDE_STANDARD_SECONDARY_ADDRESS) {
  451. AtdiskSecondaryClaimed = TRUE;
  452. }
  453. } else {
  454. AtdiskPrimaryClaimed = TRUE;
  455. AtdiskSecondaryClaimed = TRUE;
  456. }
  457. if (partialDescriptors[j].Type == CmResourceTypePort) {
  458. IdeResource->TranslatedCommandBaseAddress =
  459. (PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart;
  460. IdeResource->CommandBaseAddressSpace = IO_SPACE;
  461. } else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
  462. IdeResource->TranslatedCommandBaseAddress = MmMapIoSpace(
  463. partialDescriptors[j].u.Port.Start,
  464. baseIoAddress1Length,
  465. FALSE);
  466. IdeResource->CommandBaseAddressSpace = MEMORY_SPACE;
  467. } else {
  468. IdeResource->TranslatedCommandBaseAddress = FALSE;
  469. ASSERT (FALSE);
  470. }
  471. if (IdeResource->TranslatedCommandBaseAddress) {
  472. foundCommandBase = TRUE;
  473. } else {
  474. status = STATUS_INVALID_PARAMETER;
  475. }
  476. }
  477. } else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  478. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  479. ((partialDescriptors[j].u.Port.Length == 1) ||
  480. (partialDescriptors[j].u.Port.Length == 2) ||
  481. (partialDescriptors[j].u.Port.Length == 4))) {
  482. if (foundControlBase) {
  483. //
  484. // got this before, just ignore it
  485. //
  486. // status = STATUS_INVALID_PARAMETER;
  487. } else {
  488. PHYSICAL_ADDRESS p;
  489. //
  490. // Probably the control block register
  491. //
  492. p = partialDescriptors[j].u.Port.Start;
  493. if (partialDescriptors[j].u.Port.Length == 4) {
  494. p.QuadPart += 2;
  495. }
  496. if (partialDescriptors[j].Type == CmResourceTypePort) {
  497. IdeResource->TranslatedControlBaseAddress =
  498. (PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart;
  499. IdeResource->ControlBaseAddressSpace = IO_SPACE;
  500. } else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
  501. IdeResource->TranslatedControlBaseAddress = MmMapIoSpace(
  502. p,
  503. 1,
  504. FALSE);
  505. IdeResource->ControlBaseAddressSpace = MEMORY_SPACE;
  506. } else {
  507. IdeResource->TranslatedControlBaseAddress = FALSE;
  508. ASSERT (FALSE);
  509. }
  510. if (IdeResource->TranslatedControlBaseAddress) {
  511. foundControlBase = TRUE;
  512. } else {
  513. status = STATUS_INVALID_PARAMETER;
  514. }
  515. }
  516. } else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) {
  517. if (foundIrqLevel) {
  518. //
  519. // got this before, just ignore it
  520. //
  521. // status = STATUS_INVALID_PARAMETER;
  522. } else {
  523. //
  524. // Probably the device IRQ
  525. //
  526. //
  527. // May want to disable device interrupt here
  528. //
  529. //
  530. // Save interrupt level.
  531. //
  532. IdeResource->InterruptLevel = partialDescriptors[j].u.Interrupt.Level;
  533. IdeResource->InterruptMode = partialDescriptors[j].Flags & CM_RESOURCE_INTERRUPT_LATCHED ?
  534. Latched :
  535. LevelSensitive;
  536. *IrqPartialDescriptors = partialDescriptors + j;
  537. foundIrqLevel = TRUE;
  538. }
  539. } else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  540. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  541. ((partialDescriptors[j].u.Port.Length >= 16) &&
  542. (partialDescriptors[j].u.Port.Length <= 32)) ) {
  543. if (foundControlBase || foundCommandBase) {
  544. //
  545. // got this before, just ignore it
  546. //
  547. // status = STATUS_INVALID_PARAMETER;
  548. } else {
  549. PHYSICAL_ADDRESS ctrlAddr;
  550. //
  551. // Probably a pcmcia device that has its command and control
  552. // registers lumped into one I/O range
  553. //
  554. // We are guessing the control block register is the second
  555. // from the last i/o space. Some standard!
  556. //
  557. ctrlAddr.QuadPart = partialDescriptors[j].u.Port.Start.QuadPart +
  558. partialDescriptors[j].u.Port.Length - 2;
  559. if (partialDescriptors[j].Type == CmResourceTypePort) {
  560. IdeResource->TranslatedCommandBaseAddress =
  561. (PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart;
  562. IdeResource->CommandBaseAddressSpace = IO_SPACE;
  563. IdeResource->TranslatedControlBaseAddress =
  564. (PUCHAR)(ULONG_PTR)ctrlAddr.QuadPart;
  565. IdeResource->ControlBaseAddressSpace = IO_SPACE;
  566. } else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
  567. IdeResource->TranslatedCommandBaseAddress = MmMapIoSpace(
  568. partialDescriptors[j].u.Port.Start,
  569. baseIoAddress1Length,
  570. FALSE);
  571. IdeResource->CommandBaseAddressSpace = MEMORY_SPACE;
  572. IdeResource->TranslatedControlBaseAddress = MmMapIoSpace(
  573. ctrlAddr,
  574. 1,
  575. FALSE);
  576. IdeResource->ControlBaseAddressSpace = MEMORY_SPACE;
  577. } else {
  578. IdeResource->TranslatedCommandBaseAddress = FALSE;
  579. IdeResource->TranslatedControlBaseAddress = FALSE;
  580. ASSERT (FALSE);
  581. }
  582. if (IdeResource->TranslatedCommandBaseAddress) {
  583. foundCommandBase = TRUE;
  584. } else {
  585. status = STATUS_INVALID_PARAMETER;
  586. }
  587. if (IdeResource->TranslatedControlBaseAddress) {
  588. foundControlBase = TRUE;
  589. } else {
  590. status = STATUS_INVALID_PARAMETER;
  591. }
  592. }
  593. }
  594. }
  595. fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + partialResourceList->Count);
  596. }
  597. if (foundCommandBase && foundControlBase && NT_SUCCESS(status)) {
  598. IdeResource->AtdiskPrimaryClaimed = AtdiskPrimaryClaimed;
  599. IdeResource->AtdiskSecondaryClaimed = AtdiskSecondaryClaimed;
  600. return STATUS_SUCCESS;
  601. } else {
  602. DebugPrint((0, "IdePort: pnp manager gave me bad ressources!\n"));
  603. if (foundCommandBase &&
  604. (IdeResource->CommandBaseAddressSpace == MEMORY_SPACE)) {
  605. MmUnmapIoSpace (
  606. IdeResource->TranslatedCommandBaseAddress,
  607. baseIoAddress1Length
  608. );
  609. IdeResource->TranslatedCommandBaseAddress = 0;
  610. }
  611. if (foundControlBase &&
  612. (IdeResource->ControlBaseAddressSpace == MEMORY_SPACE)) {
  613. MmUnmapIoSpace (
  614. IdeResource->TranslatedControlBaseAddress,
  615. 1
  616. );
  617. IdeResource->TranslatedControlBaseAddress = 0;
  618. }
  619. return STATUS_INVALID_PARAMETER;
  620. }
  621. } // DigestResourceList
  622. VOID
  623. AtapiBuildIoAddress (
  624. IN PUCHAR CmdBaseAddress,
  625. IN PUCHAR CtrlBaseAddress,
  626. OUT PIDE_REGISTERS_1 BaseIoAddress1,
  627. OUT PIDE_REGISTERS_2 BaseIoAddress2,
  628. OUT PULONG BaseIoAddress1Length,
  629. OUT PULONG BaseIoAddress2Length,
  630. OUT PULONG MaxIdeDevice,
  631. OUT PULONG MaxIdeTargetId
  632. )
  633. {
  634. PUCHAR baseIoAddress;
  635. BOOLEAN LegacyIdeOfNec98;
  636. LegacyIdeOfNec98 = FALSE;
  637. if (IsNEC_98) {
  638. if (CmdBaseAddress == (PUCHAR)IDE_NEC98_COMMAND_PORT_ADDRESS) {
  639. LegacyIdeOfNec98 = TRUE;
  640. }
  641. }
  642. if (!LegacyIdeOfNec98) {
  643. //
  644. // Build command registers.
  645. //
  646. baseIoAddress = CmdBaseAddress;
  647. if (BaseIoAddress1) {
  648. BaseIoAddress1->RegistersBaseAddress = baseIoAddress;
  649. BaseIoAddress1->Data = (PUSHORT)baseIoAddress;
  650. BaseIoAddress1->Error = baseIoAddress + 1;
  651. BaseIoAddress1->BlockCount = baseIoAddress + 2;
  652. BaseIoAddress1->BlockNumber = baseIoAddress + 3;
  653. BaseIoAddress1->CylinderLow = baseIoAddress + 4;
  654. BaseIoAddress1->CylinderHigh = baseIoAddress + 5;
  655. BaseIoAddress1->DriveSelect = baseIoAddress + 6;
  656. BaseIoAddress1->Command = baseIoAddress + 7;
  657. }
  658. //
  659. // Build control registers.
  660. //
  661. baseIoAddress = CtrlBaseAddress;
  662. if (BaseIoAddress2) {
  663. BaseIoAddress2->RegistersBaseAddress = baseIoAddress;
  664. BaseIoAddress2->DeviceControl = baseIoAddress;
  665. BaseIoAddress2->DriveAddress = baseIoAddress + 1;
  666. }
  667. if (BaseIoAddress1Length) {
  668. *BaseIoAddress1Length = 8;
  669. }
  670. if (BaseIoAddress2Length) {
  671. *BaseIoAddress2Length = 1;
  672. }
  673. if (MaxIdeDevice) {
  674. *MaxIdeDevice = MAX_IDE_DEVICE;
  675. }
  676. if (MaxIdeTargetId) {
  677. *MaxIdeTargetId = MAX_IDE_DEVICE;
  678. }
  679. } else {
  680. //
  681. // Build command registers.
  682. //
  683. baseIoAddress = CmdBaseAddress;
  684. if (BaseIoAddress1) {
  685. BaseIoAddress1->RegistersBaseAddress = baseIoAddress;
  686. BaseIoAddress1->Data = (PUSHORT)baseIoAddress;
  687. BaseIoAddress1->Error = baseIoAddress + 2;
  688. BaseIoAddress1->BlockCount = baseIoAddress + 4;
  689. BaseIoAddress1->BlockNumber = baseIoAddress + 6;
  690. BaseIoAddress1->CylinderLow = baseIoAddress + 8;
  691. BaseIoAddress1->CylinderHigh = baseIoAddress + 10;
  692. BaseIoAddress1->DriveSelect = baseIoAddress + 12;
  693. BaseIoAddress1->Command = baseIoAddress + 14;
  694. }
  695. //
  696. // Build control registers.
  697. //
  698. baseIoAddress = CtrlBaseAddress;
  699. if (BaseIoAddress2) {
  700. BaseIoAddress2->RegistersBaseAddress = baseIoAddress;
  701. BaseIoAddress2->DeviceControl = baseIoAddress;
  702. BaseIoAddress2->DriveAddress = baseIoAddress + 2;
  703. }
  704. if (BaseIoAddress1Length) {
  705. *BaseIoAddress1Length = 1;
  706. }
  707. if (BaseIoAddress2Length) {
  708. *BaseIoAddress2Length = 1;
  709. }
  710. if (MaxIdeDevice) {
  711. *MaxIdeDevice = MAX_IDE_DEVICE * MAX_IDE_LINE;
  712. }
  713. if (MaxIdeTargetId) {
  714. *MaxIdeTargetId = MAX_IDE_DEVICE * MAX_IDE_LINE;
  715. }
  716. }
  717. return;
  718. } // AtapiBuildIoAddress
  719. NTSTATUS
  720. IdePortpWaitOnBusyEx (
  721. IN PIDE_REGISTERS_1 CmdRegBase,
  722. IN OUT PUCHAR Status,
  723. IN UCHAR BadStatus
  724. #if DBG
  725. ,
  726. IN PCSTR FileName,
  727. IN ULONG LineNumber
  728. #endif
  729. )
  730. {
  731. UCHAR status;
  732. ULONG sec;
  733. ULONG i;
  734. for (sec=0; sec<2; sec++) {
  735. /**/
  736. /* one second loop */
  737. /**/
  738. for (i=0; i<200000; i++) {
  739. GetStatus(CmdRegBase, status);
  740. if (status == BadStatus) {
  741. break;
  742. } else if (status & IDE_STATUS_BUSY) {
  743. KeStallExecutionProcessor(5);
  744. continue;
  745. } else {
  746. break;
  747. }
  748. }
  749. if (status == BadStatus) {
  750. break;
  751. } else if (status & IDE_STATUS_BUSY) {
  752. DebugPrint ((1, "ATAPI: after 1 sec wait, device is still busy with 0x%x status = 0x%x\n", CmdRegBase->RegistersBaseAddress, (ULONG) (status)));
  753. } else {
  754. break;
  755. }
  756. }
  757. *Status = status;
  758. if ((status & IDE_STATUS_BUSY) && (status != BadStatus)) {
  759. DebugPrint ((0, "WaitOnBusy failed in %s line %u. 0x%x status = 0x%x\n", FileName, LineNumber, CmdRegBase->RegistersBaseAddress, (ULONG) (status)));
  760. return STATUS_UNSUCCESSFUL;
  761. }
  762. return STATUS_SUCCESS;
  763. } // IdePortpWaitOnBusyEx
  764. static PVOID IdeDirectory = NULL;
  765. VOID
  766. IdeCreateIdeDirectory(
  767. VOID
  768. )
  769. {
  770. UNICODE_STRING unicodeDirectoryName;
  771. OBJECT_ATTRIBUTES objectAttributes;
  772. HANDLE directory;
  773. NTSTATUS status;
  774. PAGED_CODE();
  775. RtlInitUnicodeString(
  776. &unicodeDirectoryName,
  777. DEVICE_OJBECT_BASE_NAME);
  778. InitializeObjectAttributes(
  779. &objectAttributes,
  780. &unicodeDirectoryName,
  781. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  782. NULL,
  783. NULL);
  784. status = ZwCreateDirectoryObject(&directory,
  785. DIRECTORY_ALL_ACCESS,
  786. &objectAttributes);
  787. if(NT_SUCCESS(status)) {
  788. ObReferenceObjectByHandle(directory,
  789. FILE_READ_ATTRIBUTES,
  790. NULL,
  791. KernelMode,
  792. &IdeDirectory,
  793. NULL);
  794. ZwClose(directory);
  795. }
  796. return;
  797. }
  798. NTSTATUS
  799. IdeGetDeviceCapabilities(
  800. IN PDEVICE_OBJECT DeviceObject,
  801. IN PDEVICE_CAPABILITIES DeviceCapabilities
  802. )
  803. /*++
  804. Routine Description:
  805. This routine sends the get capabilities irp to the given stack
  806. Arguments:
  807. DeviceObject A device object in the stack whose capabilities we want
  808. DeviceCapabilites Where to store the answer
  809. Return Value:
  810. NTSTATUS
  811. --*/
  812. {
  813. IO_STATUS_BLOCK ioStatus;
  814. KEVENT pnpEvent;
  815. NTSTATUS status;
  816. PDEVICE_OBJECT targetObject;
  817. PIO_STACK_LOCATION irpStack;
  818. PIRP pnpIrp;
  819. PAGED_CODE();
  820. //
  821. // Initialize the capabilities that we will send down
  822. //
  823. RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
  824. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  825. DeviceCapabilities->Version = 1;
  826. DeviceCapabilities->Address = -1;
  827. DeviceCapabilities->UINumber = -1;
  828. //
  829. // Initialize the event
  830. //
  831. KeInitializeEvent( &pnpEvent, SynchronizationEvent, FALSE );
  832. //
  833. // Get the irp that we will send the request to
  834. //
  835. targetObject = IoGetAttachedDeviceReference( DeviceObject );
  836. //
  837. // Build an Irp
  838. //
  839. pnpIrp = IoBuildSynchronousFsdRequest(
  840. IRP_MJ_PNP,
  841. targetObject,
  842. NULL,
  843. 0,
  844. NULL,
  845. &pnpEvent,
  846. &ioStatus
  847. );
  848. if (pnpIrp == NULL) {
  849. status = STATUS_INSUFFICIENT_RESOURCES;
  850. goto IdeGetDeviceCapabilitiesExit;
  851. }
  852. //
  853. // Pnp Irps all begin life as STATUS_NOT_SUPPORTED;
  854. //
  855. pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  856. pnpIrp->IoStatus.Information = 0;
  857. //
  858. // Get the top of stack
  859. //
  860. irpStack = IoGetNextIrpStackLocation( pnpIrp );
  861. if (irpStack == NULL) {
  862. status = STATUS_INVALID_PARAMETER;
  863. goto IdeGetDeviceCapabilitiesExit;
  864. }
  865. //
  866. // Set the top of stack
  867. //
  868. RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) );
  869. irpStack->MajorFunction = IRP_MJ_PNP;
  870. irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  871. irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
  872. //
  873. // Make sure that there are no completion routines set
  874. //
  875. IoSetCompletionRoutine(
  876. pnpIrp,
  877. NULL,
  878. NULL,
  879. FALSE,
  880. FALSE,
  881. FALSE
  882. );
  883. //
  884. // Call the driver
  885. //
  886. status = IoCallDriver( targetObject, pnpIrp );
  887. if (status == STATUS_PENDING) {
  888. //
  889. // Block until the irp comes back
  890. //
  891. KeWaitForSingleObject(
  892. &pnpEvent,
  893. Executive,
  894. KernelMode,
  895. FALSE,
  896. NULL
  897. );
  898. status = ioStatus.Status;
  899. }
  900. IdeGetDeviceCapabilitiesExit:
  901. //
  902. // Done with reference
  903. //
  904. ObDereferenceObject( targetObject );
  905. //
  906. // Done
  907. //
  908. return status;
  909. }