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.

1243 lines
36 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. //
  495. // this will happen only in native mode since
  496. // the range length is 1 for legacy systems
  497. //
  498. p.QuadPart += 2;
  499. }
  500. if (partialDescriptors[j].Type == CmResourceTypePort) {
  501. IdeResource->TranslatedControlBaseAddress =
  502. (PUCHAR)(ULONG_PTR)p.QuadPart;
  503. IdeResource->ControlBaseAddressSpace = IO_SPACE;
  504. } else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
  505. IdeResource->TranslatedControlBaseAddress = MmMapIoSpace(
  506. p,
  507. 1,
  508. FALSE);
  509. IdeResource->ControlBaseAddressSpace = MEMORY_SPACE;
  510. } else {
  511. IdeResource->TranslatedControlBaseAddress = FALSE;
  512. ASSERT (FALSE);
  513. }
  514. if (IdeResource->TranslatedControlBaseAddress) {
  515. foundControlBase = TRUE;
  516. } else {
  517. status = STATUS_INVALID_PARAMETER;
  518. }
  519. }
  520. } else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) {
  521. if (foundIrqLevel) {
  522. //
  523. // got this before, just ignore it
  524. //
  525. // status = STATUS_INVALID_PARAMETER;
  526. } else {
  527. //
  528. // Probably the device IRQ
  529. //
  530. //
  531. // May want to disable device interrupt here
  532. //
  533. //
  534. // Save interrupt level.
  535. //
  536. IdeResource->InterruptLevel = partialDescriptors[j].u.Interrupt.Level;
  537. IdeResource->InterruptMode = partialDescriptors[j].Flags & CM_RESOURCE_INTERRUPT_LATCHED ?
  538. Latched :
  539. LevelSensitive;
  540. *IrqPartialDescriptors = partialDescriptors + j;
  541. foundIrqLevel = TRUE;
  542. }
  543. } else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  544. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  545. ((partialDescriptors[j].u.Port.Length >= 16) &&
  546. (partialDescriptors[j].u.Port.Length <= 32)) ) {
  547. if (foundControlBase || foundCommandBase) {
  548. //
  549. // got this before, just ignore it
  550. //
  551. // status = STATUS_INVALID_PARAMETER;
  552. } else {
  553. PHYSICAL_ADDRESS ctrlAddr;
  554. //
  555. // Probably a pcmcia device that has its command and control
  556. // registers lumped into one I/O range
  557. //
  558. // We are guessing the control block register is the second
  559. // from the last i/o space. Some standard!
  560. //
  561. ctrlAddr.QuadPart = partialDescriptors[j].u.Port.Start.QuadPart +
  562. partialDescriptors[j].u.Port.Length - 2;
  563. if (partialDescriptors[j].Type == CmResourceTypePort) {
  564. IdeResource->TranslatedCommandBaseAddress =
  565. (PUCHAR)(ULONG_PTR)partialDescriptors[j].u.Port.Start.QuadPart;
  566. IdeResource->CommandBaseAddressSpace = IO_SPACE;
  567. IdeResource->TranslatedControlBaseAddress =
  568. (PUCHAR)(ULONG_PTR)ctrlAddr.QuadPart;
  569. IdeResource->ControlBaseAddressSpace = IO_SPACE;
  570. } else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
  571. IdeResource->TranslatedCommandBaseAddress = MmMapIoSpace(
  572. partialDescriptors[j].u.Port.Start,
  573. baseIoAddress1Length,
  574. FALSE);
  575. IdeResource->CommandBaseAddressSpace = MEMORY_SPACE;
  576. IdeResource->TranslatedControlBaseAddress = MmMapIoSpace(
  577. ctrlAddr,
  578. 1,
  579. FALSE);
  580. IdeResource->ControlBaseAddressSpace = MEMORY_SPACE;
  581. } else {
  582. IdeResource->TranslatedCommandBaseAddress = FALSE;
  583. IdeResource->TranslatedControlBaseAddress = FALSE;
  584. ASSERT (FALSE);
  585. }
  586. if (IdeResource->TranslatedCommandBaseAddress) {
  587. foundCommandBase = TRUE;
  588. } else {
  589. status = STATUS_INVALID_PARAMETER;
  590. }
  591. if (IdeResource->TranslatedControlBaseAddress) {
  592. foundControlBase = TRUE;
  593. } else {
  594. status = STATUS_INVALID_PARAMETER;
  595. }
  596. }
  597. }
  598. }
  599. fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + partialResourceList->Count);
  600. }
  601. if (foundCommandBase && foundControlBase && NT_SUCCESS(status)) {
  602. IdeResource->AtdiskPrimaryClaimed = AtdiskPrimaryClaimed;
  603. IdeResource->AtdiskSecondaryClaimed = AtdiskSecondaryClaimed;
  604. return STATUS_SUCCESS;
  605. } else {
  606. DebugPrint((0, "IdePort: pnp manager gave me bad ressources!\n"));
  607. if (foundCommandBase &&
  608. (IdeResource->CommandBaseAddressSpace == MEMORY_SPACE)) {
  609. MmUnmapIoSpace (
  610. IdeResource->TranslatedCommandBaseAddress,
  611. baseIoAddress1Length
  612. );
  613. IdeResource->TranslatedCommandBaseAddress = 0;
  614. }
  615. if (foundControlBase &&
  616. (IdeResource->ControlBaseAddressSpace == MEMORY_SPACE)) {
  617. MmUnmapIoSpace (
  618. IdeResource->TranslatedControlBaseAddress,
  619. 1
  620. );
  621. IdeResource->TranslatedControlBaseAddress = 0;
  622. }
  623. return STATUS_INVALID_PARAMETER;
  624. }
  625. } // DigestResourceList
  626. VOID
  627. AtapiBuildIoAddress (
  628. IN PUCHAR CmdBaseAddress,
  629. IN PUCHAR CtrlBaseAddress,
  630. OUT PIDE_REGISTERS_1 BaseIoAddress1,
  631. OUT PIDE_REGISTERS_2 BaseIoAddress2,
  632. OUT PULONG BaseIoAddress1Length,
  633. OUT PULONG BaseIoAddress2Length,
  634. OUT PULONG MaxIdeDevice,
  635. OUT PULONG MaxIdeTargetId
  636. )
  637. {
  638. PUCHAR baseIoAddress;
  639. BOOLEAN LegacyIdeOfNec98;
  640. LegacyIdeOfNec98 = FALSE;
  641. if (IsNEC_98) {
  642. if (CmdBaseAddress == (PUCHAR)IDE_NEC98_COMMAND_PORT_ADDRESS) {
  643. LegacyIdeOfNec98 = TRUE;
  644. }
  645. }
  646. if (!LegacyIdeOfNec98) {
  647. //
  648. // Build command registers.
  649. //
  650. baseIoAddress = CmdBaseAddress;
  651. if (BaseIoAddress1) {
  652. BaseIoAddress1->RegistersBaseAddress = baseIoAddress;
  653. BaseIoAddress1->Data = (PUSHORT)baseIoAddress;
  654. BaseIoAddress1->Error = baseIoAddress + 1;
  655. BaseIoAddress1->BlockCount = baseIoAddress + 2;
  656. BaseIoAddress1->BlockNumber = baseIoAddress + 3;
  657. BaseIoAddress1->CylinderLow = baseIoAddress + 4;
  658. BaseIoAddress1->CylinderHigh = baseIoAddress + 5;
  659. BaseIoAddress1->DriveSelect = baseIoAddress + 6;
  660. BaseIoAddress1->Command = baseIoAddress + 7;
  661. }
  662. //
  663. // Build control registers.
  664. //
  665. baseIoAddress = CtrlBaseAddress;
  666. if (BaseIoAddress2) {
  667. BaseIoAddress2->RegistersBaseAddress = baseIoAddress;
  668. BaseIoAddress2->DeviceControl = baseIoAddress;
  669. BaseIoAddress2->DriveAddress = baseIoAddress + 1;
  670. }
  671. if (BaseIoAddress1Length) {
  672. *BaseIoAddress1Length = 8;
  673. }
  674. if (BaseIoAddress2Length) {
  675. *BaseIoAddress2Length = 1;
  676. }
  677. if (MaxIdeDevice) {
  678. *MaxIdeDevice = MAX_IDE_DEVICE;
  679. }
  680. if (MaxIdeTargetId) {
  681. *MaxIdeTargetId = MAX_IDE_DEVICE;
  682. }
  683. } else {
  684. //
  685. // Build command registers.
  686. //
  687. baseIoAddress = CmdBaseAddress;
  688. if (BaseIoAddress1) {
  689. BaseIoAddress1->RegistersBaseAddress = baseIoAddress;
  690. BaseIoAddress1->Data = (PUSHORT)baseIoAddress;
  691. BaseIoAddress1->Error = baseIoAddress + 2;
  692. BaseIoAddress1->BlockCount = baseIoAddress + 4;
  693. BaseIoAddress1->BlockNumber = baseIoAddress + 6;
  694. BaseIoAddress1->CylinderLow = baseIoAddress + 8;
  695. BaseIoAddress1->CylinderHigh = baseIoAddress + 10;
  696. BaseIoAddress1->DriveSelect = baseIoAddress + 12;
  697. BaseIoAddress1->Command = baseIoAddress + 14;
  698. }
  699. //
  700. // Build control registers.
  701. //
  702. baseIoAddress = CtrlBaseAddress;
  703. if (BaseIoAddress2) {
  704. BaseIoAddress2->RegistersBaseAddress = baseIoAddress;
  705. BaseIoAddress2->DeviceControl = baseIoAddress;
  706. BaseIoAddress2->DriveAddress = baseIoAddress + 2;
  707. }
  708. if (BaseIoAddress1Length) {
  709. *BaseIoAddress1Length = 1;
  710. }
  711. if (BaseIoAddress2Length) {
  712. *BaseIoAddress2Length = 1;
  713. }
  714. if (MaxIdeDevice) {
  715. *MaxIdeDevice = MAX_IDE_DEVICE * MAX_IDE_LINE;
  716. }
  717. if (MaxIdeTargetId) {
  718. *MaxIdeTargetId = MAX_IDE_DEVICE * MAX_IDE_LINE;
  719. }
  720. }
  721. return;
  722. } // AtapiBuildIoAddress
  723. NTSTATUS
  724. IdePortpWaitOnBusyEx (
  725. IN PIDE_REGISTERS_1 CmdRegBase,
  726. IN OUT PUCHAR Status,
  727. IN UCHAR BadStatus
  728. #if DBG
  729. ,
  730. IN PCSTR FileName,
  731. IN ULONG LineNumber
  732. #endif
  733. )
  734. {
  735. UCHAR status;
  736. ULONG sec;
  737. ULONG i;
  738. for (sec=0; sec<2; sec++) {
  739. /**/
  740. /* one second loop */
  741. /**/
  742. for (i=0; i<200000; i++) {
  743. GetStatus(CmdRegBase, status);
  744. if (status == BadStatus) {
  745. break;
  746. } else if (status & IDE_STATUS_BUSY) {
  747. KeStallExecutionProcessor(5);
  748. continue;
  749. } else {
  750. break;
  751. }
  752. }
  753. if (status == BadStatus) {
  754. break;
  755. } else if (status & IDE_STATUS_BUSY) {
  756. DebugPrint ((1, "ATAPI: after 1 sec wait, device is still busy with 0x%x status = 0x%x\n", CmdRegBase->RegistersBaseAddress, (ULONG) (status)));
  757. } else {
  758. break;
  759. }
  760. }
  761. *Status = status;
  762. if ((status & IDE_STATUS_BUSY) && (status != BadStatus)) {
  763. DebugPrint ((0, "WaitOnBusy failed in %s line %u. 0x%x status = 0x%x\n", FileName, LineNumber, CmdRegBase->RegistersBaseAddress, (ULONG) (status)));
  764. return STATUS_UNSUCCESSFUL;
  765. }
  766. return STATUS_SUCCESS;
  767. } // IdePortpWaitOnBusyEx
  768. static PVOID IdeDirectory = NULL;
  769. VOID
  770. IdeCreateIdeDirectory(
  771. VOID
  772. )
  773. {
  774. UNICODE_STRING unicodeDirectoryName;
  775. OBJECT_ATTRIBUTES objectAttributes;
  776. HANDLE directory;
  777. NTSTATUS status;
  778. PAGED_CODE();
  779. RtlInitUnicodeString(
  780. &unicodeDirectoryName,
  781. DEVICE_OJBECT_BASE_NAME);
  782. InitializeObjectAttributes(
  783. &objectAttributes,
  784. &unicodeDirectoryName,
  785. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  786. NULL,
  787. NULL);
  788. status = ZwCreateDirectoryObject(&directory,
  789. DIRECTORY_ALL_ACCESS,
  790. &objectAttributes);
  791. if(NT_SUCCESS(status)) {
  792. ObReferenceObjectByHandle(directory,
  793. FILE_READ_ATTRIBUTES,
  794. NULL,
  795. KernelMode,
  796. &IdeDirectory,
  797. NULL);
  798. ZwClose(directory);
  799. }
  800. return;
  801. }
  802. NTSTATUS
  803. IdeGetDeviceCapabilities(
  804. IN PDEVICE_OBJECT DeviceObject,
  805. IN PDEVICE_CAPABILITIES DeviceCapabilities
  806. )
  807. /*++
  808. Routine Description:
  809. This routine sends the get capabilities irp to the given stack
  810. Arguments:
  811. DeviceObject A device object in the stack whose capabilities we want
  812. DeviceCapabilites Where to store the answer
  813. Return Value:
  814. NTSTATUS
  815. --*/
  816. {
  817. IO_STATUS_BLOCK ioStatus;
  818. KEVENT pnpEvent;
  819. NTSTATUS status;
  820. PDEVICE_OBJECT targetObject;
  821. PIO_STACK_LOCATION irpStack;
  822. PIRP pnpIrp;
  823. PAGED_CODE();
  824. //
  825. // Initialize the capabilities that we will send down
  826. //
  827. RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
  828. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  829. DeviceCapabilities->Version = 1;
  830. DeviceCapabilities->Address = -1;
  831. DeviceCapabilities->UINumber = -1;
  832. //
  833. // Initialize the event
  834. //
  835. KeInitializeEvent( &pnpEvent, SynchronizationEvent, FALSE );
  836. //
  837. // Get the irp that we will send the request to
  838. //
  839. targetObject = IoGetAttachedDeviceReference( DeviceObject );
  840. //
  841. // Build an Irp
  842. //
  843. pnpIrp = IoBuildSynchronousFsdRequest(
  844. IRP_MJ_PNP,
  845. targetObject,
  846. NULL,
  847. 0,
  848. NULL,
  849. &pnpEvent,
  850. &ioStatus
  851. );
  852. if (pnpIrp == NULL) {
  853. status = STATUS_INSUFFICIENT_RESOURCES;
  854. goto IdeGetDeviceCapabilitiesExit;
  855. }
  856. //
  857. // Pnp Irps all begin life as STATUS_NOT_SUPPORTED;
  858. //
  859. pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  860. pnpIrp->IoStatus.Information = 0;
  861. //
  862. // Get the top of stack
  863. //
  864. irpStack = IoGetNextIrpStackLocation( pnpIrp );
  865. if (irpStack == NULL) {
  866. status = STATUS_INVALID_PARAMETER;
  867. goto IdeGetDeviceCapabilitiesExit;
  868. }
  869. //
  870. // Set the top of stack
  871. //
  872. RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) );
  873. irpStack->MajorFunction = IRP_MJ_PNP;
  874. irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  875. irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
  876. //
  877. // Make sure that there are no completion routines set
  878. //
  879. IoSetCompletionRoutine(
  880. pnpIrp,
  881. NULL,
  882. NULL,
  883. FALSE,
  884. FALSE,
  885. FALSE
  886. );
  887. //
  888. // Call the driver
  889. //
  890. status = IoCallDriver( targetObject, pnpIrp );
  891. if (status == STATUS_PENDING) {
  892. //
  893. // Block until the irp comes back
  894. //
  895. KeWaitForSingleObject(
  896. &pnpEvent,
  897. Executive,
  898. KernelMode,
  899. FALSE,
  900. NULL
  901. );
  902. status = ioStatus.Status;
  903. }
  904. IdeGetDeviceCapabilitiesExit:
  905. //
  906. // Done with reference
  907. //
  908. ObDereferenceObject( targetObject );
  909. //
  910. // Done
  911. //
  912. return status;
  913. }