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.

1066 lines
34 KiB

  1. /*++
  2. Copyright (C) 1997-99 Microsoft Corporation
  3. Module Name:
  4. detect.c
  5. Abstract:
  6. This contain legacy detection routines
  7. Author:
  8. Joe Dai (joedai)
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "ideport.h"
  15. #if !defined(NO_LEGACY_DRIVERS)
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(INIT, IdePortDetectLegacyController)
  18. #pragma alloc_text(INIT, IdePortCreateDetectionList)
  19. #pragma alloc_text(INIT, IdePortTranslateAddress)
  20. #pragma alloc_text(INIT, IdePortFreeTranslatedAddress)
  21. #pragma alloc_text(INIT, IdePortDetectAlias)
  22. #endif // ALLOC_PRAGMA
  23. NTSTATUS
  24. IdePortDetectLegacyController (
  25. IN PDRIVER_OBJECT DriverObject,
  26. IN PUNICODE_STRING RegistryPath
  27. )
  28. /*++
  29. Routine Description:
  30. Detect legacy IDE controllers and report them to PnP
  31. Arguments:
  32. DriverObject - this driver's driver object
  33. RegistryPath - this driver's registry path
  34. Return Value:
  35. NT Status
  36. --*/
  37. {
  38. ULONG cmResourceListSize;
  39. PCM_RESOURCE_LIST cmResourceList = NULL;
  40. PCM_FULL_RESOURCE_DESCRIPTOR cmFullResourceDescriptor;
  41. PCM_PARTIAL_RESOURCE_LIST cmPartialResourceList;
  42. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartialDescriptors;
  43. BOOLEAN conflictDetected;
  44. BOOLEAN resourceIsCmdPort;
  45. PDEVICE_OBJECT detectedPhysicalDeviceObject;
  46. PFDO_EXTENSION fdoExtension = NULL;
  47. UNICODE_STRING deviceClassName;
  48. NTSTATUS status;
  49. PDETECTION_PORT detectionPort;
  50. ULONG numPort;
  51. ULONG i;
  52. ULONG j;
  53. ULONG cmdAddressSpace;
  54. ULONG ctrlAddressSpace;
  55. PUCHAR cmdRegBase;
  56. PUCHAR ctrlRegBase;
  57. IDE_REGISTERS_1 baseIoAddress1;
  58. IDE_REGISTERS_2 baseIoAddress2;
  59. PHYSICAL_ADDRESS cmdRegMemoryBase;
  60. PHYSICAL_ADDRESS ctrlRegMemoryBase;
  61. UCHAR statusByte;
  62. ULONG baseIoAddress1Length;
  63. ULONG baseIoAddress2Length;
  64. ULONG maxIdeDevice;
  65. UCHAR altMasterStatus;
  66. UCHAR altSlaveStatus;
  67. #if !defined (ALWAYS_DO_LEGACY_DETECTION)
  68. if (!IdePortOkToDetectLegacy(DriverObject)) {
  69. //
  70. // legacy detection is not enabled
  71. //
  72. return STATUS_SUCCESS;
  73. }
  74. #endif
  75. //
  76. // make up a list of popular legacy I/O ports
  77. //
  78. status = IdePortCreateDetectionList (
  79. DriverObject,
  80. &detectionPort,
  81. &numPort
  82. );
  83. if (!NT_SUCCESS(status)) {
  84. goto GetOut;
  85. }
  86. //
  87. // Resource Requirement List
  88. //
  89. cmResourceListSize = sizeof (CM_RESOURCE_LIST) +
  90. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (((!IsNEC_98) ? 3 : 12) - 1);
  91. cmResourceList = ExAllocatePool (PagedPool, cmResourceListSize);
  92. if (cmResourceList == NULL){
  93. status = STATUS_NO_MEMORY;
  94. goto GetOut;
  95. }
  96. RtlZeroMemory(cmResourceList, cmResourceListSize);
  97. RtlInitUnicodeString(&deviceClassName, L"ScsiAdapter");
  98. for (i=0; i<numPort; i++) {
  99. //
  100. // Build io address structure.
  101. //
  102. AtapiBuildIoAddress ( (PUCHAR)detectionPort[i].CommandRegisterBase,
  103. (PUCHAR)detectionPort[i].ControlRegisterBase,
  104. &baseIoAddress1,
  105. &baseIoAddress2,
  106. &baseIoAddress1Length,
  107. &baseIoAddress2Length,
  108. &maxIdeDevice,
  109. NULL);
  110. //
  111. // Build resource requirement list
  112. //
  113. cmResourceList->Count = 1;
  114. cmFullResourceDescriptor = cmResourceList->List;
  115. cmFullResourceDescriptor->InterfaceType = Isa;
  116. cmFullResourceDescriptor->BusNumber = 0;
  117. cmPartialResourceList = &cmFullResourceDescriptor->PartialResourceList;
  118. cmPartialResourceList->Version = 1;
  119. cmPartialResourceList->Revision = 1;
  120. cmPartialResourceList->Count = 3;
  121. cmPartialDescriptors = cmPartialResourceList->PartialDescriptors;
  122. cmPartialDescriptors[0].Type = CmResourceTypePort;
  123. cmPartialDescriptors[0].ShareDisposition = CmResourceShareDeviceExclusive;
  124. cmPartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO |
  125. (!Is98LegacyIde(&baseIoAddress1)? CM_RESOURCE_PORT_10_BIT_DECODE :
  126. CM_RESOURCE_PORT_16_BIT_DECODE);
  127. cmPartialDescriptors[0].u.Port.Length = baseIoAddress1Length;
  128. cmPartialDescriptors[0].u.Port.Start.QuadPart = detectionPort[i].CommandRegisterBase;
  129. cmPartialDescriptors[1].Type = CmResourceTypePort;
  130. cmPartialDescriptors[1].ShareDisposition = CmResourceShareDeviceExclusive;
  131. cmPartialDescriptors[1].Flags = CM_RESOURCE_PORT_IO |
  132. (!Is98LegacyIde(&baseIoAddress1)? CM_RESOURCE_PORT_10_BIT_DECODE :
  133. CM_RESOURCE_PORT_16_BIT_DECODE);
  134. cmPartialDescriptors[1].u.Port.Length = 1;
  135. cmPartialDescriptors[1].u.Port.Start.QuadPart = detectionPort[i].ControlRegisterBase;
  136. cmPartialDescriptors[2].Type = CmResourceTypeInterrupt;
  137. cmPartialDescriptors[2].ShareDisposition = CmResourceShareDeviceExclusive;
  138. cmPartialDescriptors[2].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
  139. cmPartialDescriptors[2].u.Interrupt.Level = detectionPort[i].IrqLevel;
  140. cmPartialDescriptors[2].u.Interrupt.Vector = detectionPort[i].IrqLevel;
  141. cmPartialDescriptors[2].u.Interrupt.Affinity = -1;
  142. if (Is98LegacyIde(&baseIoAddress1)) {
  143. ULONG resourceCount;
  144. ULONG commandRegisters;
  145. commandRegisters = detectionPort[i].CommandRegisterBase + 2;
  146. resourceCount = 3;
  147. while (commandRegisters < (IDE_NEC98_COMMAND_PORT_ADDRESS + 0x10)) {
  148. cmPartialDescriptors[resourceCount].Type = CmResourceTypePort;
  149. cmPartialDescriptors[resourceCount].ShareDisposition = CmResourceShareDeviceExclusive;
  150. cmPartialDescriptors[resourceCount].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  151. cmPartialDescriptors[resourceCount].u.Port.Length = 1;
  152. cmPartialDescriptors[resourceCount].u.Port.Start.QuadPart = commandRegisters;
  153. resourceCount++;
  154. commandRegisters += 2;
  155. }
  156. cmPartialDescriptors[resourceCount].Type = CmResourceTypePort;
  157. cmPartialDescriptors[resourceCount].ShareDisposition = CmResourceShareDeviceExclusive;
  158. cmPartialDescriptors[resourceCount].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  159. cmPartialDescriptors[resourceCount].u.Port.Length = 2;
  160. cmPartialDescriptors[resourceCount].u.Port.Start.QuadPart = (ULONG_PTR)SELECT_IDE_PORT;
  161. resourceCount++;
  162. cmPartialDescriptors[resourceCount].Type = CmResourceTypePort;
  163. cmPartialDescriptors[resourceCount].ShareDisposition = CmResourceShareDeviceExclusive;
  164. cmPartialDescriptors[resourceCount].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  165. cmPartialDescriptors[resourceCount].u.Port.Length = 1;
  166. cmPartialDescriptors[resourceCount].u.Port.Start.QuadPart = (ULONG_PTR)SELECT_IDE_PORT + 3;
  167. resourceCount++;
  168. cmPartialResourceList->Count = resourceCount;
  169. }
  170. //
  171. // check to see if the resource is available
  172. // if not, assume no legacy IDE controller
  173. // is at the this location
  174. //
  175. for (j=0; j<2; j++) {
  176. status = IoReportResourceForDetection (
  177. DriverObject,
  178. cmResourceList,
  179. cmResourceListSize,
  180. NULL,
  181. NULL,
  182. 0,
  183. &conflictDetected
  184. );
  185. if (NT_SUCCESS(status) && !conflictDetected) {
  186. //
  187. // got our resources
  188. //
  189. break;
  190. } else {
  191. if (NT_SUCCESS(status)) {
  192. IoReportResourceForDetection (
  193. DriverObject,
  194. NULL,
  195. 0,
  196. NULL,
  197. NULL,
  198. 0,
  199. &conflictDetected
  200. );
  201. status = STATUS_UNSUCCESSFUL;
  202. }
  203. //
  204. // try 16 bit decode
  205. //
  206. cmPartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  207. cmPartialDescriptors[1].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  208. if (Is98LegacyIde(&baseIoAddress1)) {
  209. ULONG k;
  210. for (k=3; k<12; k++) {
  211. cmPartialDescriptors[k].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  212. }
  213. }
  214. }
  215. }
  216. if (!NT_SUCCESS(status)) {
  217. continue;
  218. }
  219. //
  220. // translate the i/o port via Hal
  221. //
  222. status = STATUS_SUCCESS;
  223. if (Is98LegacyIde(&baseIoAddress1)) {
  224. for (j=3; j<12; j++) {
  225. cmdRegBase = NULL;
  226. cmdAddressSpace = IO_SPACE;
  227. status = IdePortTranslateAddress (
  228. cmFullResourceDescriptor->InterfaceType,
  229. cmFullResourceDescriptor->BusNumber,
  230. cmPartialDescriptors[j].u.Port.Start,
  231. cmPartialDescriptors[j].u.Port.Length,
  232. &cmdAddressSpace,
  233. &cmdRegBase,
  234. &cmdRegMemoryBase
  235. );
  236. if (!NT_SUCCESS(status)) {
  237. break;
  238. }
  239. }
  240. }
  241. if (NT_SUCCESS(status)) {
  242. cmdRegBase = NULL;
  243. ctrlRegBase = NULL;
  244. cmdAddressSpace = IO_SPACE;
  245. status = IdePortTranslateAddress (
  246. cmFullResourceDescriptor->InterfaceType,
  247. cmFullResourceDescriptor->BusNumber,
  248. cmPartialDescriptors[0].u.Port.Start,
  249. cmPartialDescriptors[0].u.Port.Length,
  250. &cmdAddressSpace,
  251. &cmdRegBase,
  252. &cmdRegMemoryBase
  253. );
  254. }
  255. if (NT_SUCCESS(status)) {
  256. ctrlRegBase = NULL;
  257. ctrlAddressSpace = IO_SPACE;
  258. status = IdePortTranslateAddress (
  259. cmFullResourceDescriptor->InterfaceType,
  260. cmFullResourceDescriptor->BusNumber,
  261. cmPartialDescriptors[1].u.Port.Start,
  262. cmPartialDescriptors[1].u.Port.Length,
  263. &ctrlAddressSpace,
  264. &ctrlRegBase,
  265. &ctrlRegMemoryBase
  266. );
  267. }
  268. if (NT_SUCCESS(status)) {
  269. //
  270. // 2nd build io address structure.
  271. //
  272. AtapiBuildIoAddress ( cmdRegBase,
  273. ctrlRegBase,
  274. &baseIoAddress1,
  275. &baseIoAddress2,
  276. &baseIoAddress1Length,
  277. &baseIoAddress2Length,
  278. &maxIdeDevice,
  279. NULL);
  280. //
  281. // The IBM Aptiva ide channel with the external cdrom doesn't power up with any device selected
  282. // we must select a device; otherwise, we get a 0xff from all IO ports
  283. //
  284. SelectIdeDevice(&baseIoAddress1, 0, 0);
  285. altMasterStatus = IdePortInPortByte(baseIoAddress2.DeviceControl);
  286. SelectIdeDevice(&baseIoAddress1, 1, 0);
  287. altSlaveStatus = IdePortInPortByte(baseIoAddress2.DeviceControl);
  288. if ((!Is98LegacyIde(&baseIoAddress1)) && (altMasterStatus == 0xff) && (altSlaveStatus == 0xff)) {
  289. //
  290. // the alternate status byte is 0xff,
  291. // guessing we have a SCSI adapter (DPT) that emulate IDE controller
  292. // say the channel is empty, let the real SCSI driver picks up
  293. // the controller
  294. //
  295. status = STATUS_UNSUCCESSFUL;
  296. //
  297. // Note: The IDE port on SB16/AWE32 does not have the alternate status
  298. // register. Because of this alternate status test, we will fail to
  299. // detect this IDE port. However, this IDE port should be enumerated
  300. // by ISA-PnP bus driver.
  301. //
  302. } else if (IdePortChannelEmpty (&baseIoAddress1, &baseIoAddress2, maxIdeDevice)) {
  303. //
  304. // channel looks empty
  305. //
  306. status = STATUS_UNSUCCESSFUL;
  307. } else {
  308. BOOLEAN deviceFound;
  309. IDENTIFY_DATA IdentifyData;
  310. ULONG i;
  311. for (i=0; i<maxIdeDevice; i++) {
  312. if (Is98LegacyIde(&baseIoAddress1)) {
  313. UCHAR driveHeadReg;
  314. //
  315. // Check master device only.
  316. //
  317. if ( i & 0x1 ) {
  318. continue;
  319. }
  320. //
  321. // Check device is present.
  322. //
  323. SelectIdeDevice(&baseIoAddress1, i, 0);
  324. driveHeadReg = IdePortInPortByte(baseIoAddress1.DriveSelect);
  325. if (driveHeadReg != ((i & 0x1) << 4 | 0xA0)) {
  326. //
  327. // Bad controller.
  328. //
  329. continue;
  330. }
  331. }
  332. //
  333. // Is there a ATA device?
  334. //
  335. deviceFound = IssueIdentify(
  336. &baseIoAddress1,
  337. &baseIoAddress2,
  338. i,
  339. IDE_COMMAND_IDENTIFY,
  340. TRUE,
  341. &IdentifyData
  342. );
  343. if (deviceFound) {
  344. break;
  345. }
  346. //
  347. // Is there a ATAPI device?
  348. //
  349. deviceFound = IssueIdentify(
  350. &baseIoAddress1,
  351. &baseIoAddress2,
  352. i,
  353. IDE_COMMAND_ATAPI_IDENTIFY,
  354. TRUE,
  355. &IdentifyData
  356. );
  357. if (deviceFound) {
  358. break;
  359. }
  360. }
  361. if (!deviceFound) {
  362. status = STATUS_UNSUCCESSFUL;
  363. }
  364. }
  365. }
  366. if (!NT_SUCCESS (status)) {
  367. //
  368. // if we didn't found anything,
  369. // unmap the reosurce
  370. //
  371. if (cmdRegBase) {
  372. IdePortFreeTranslatedAddress (
  373. cmdRegBase,
  374. cmPartialDescriptors[0].u.Port.Length,
  375. cmdAddressSpace
  376. );
  377. if (Is98LegacyIde(&baseIoAddress1)) {
  378. for (j=3; j<12; j++) {
  379. IdePortFreeTranslatedAddress (
  380. cmdRegBase,
  381. cmPartialDescriptors[j].u.Port.Length,
  382. cmdAddressSpace
  383. );
  384. }
  385. }
  386. }
  387. if (ctrlRegBase) {
  388. IdePortFreeTranslatedAddress (
  389. ctrlRegBase,
  390. cmPartialDescriptors[1].u.Port.Length,
  391. ctrlAddressSpace
  392. );
  393. }
  394. } else {
  395. //
  396. // check for alias ports
  397. //
  398. if (cmPartialDescriptors[0].Flags & CM_RESOURCE_PORT_10_BIT_DECODE) {
  399. if (!IdePortDetectAlias (&baseIoAddress1)) {
  400. cmPartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  401. cmPartialDescriptors[1].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  402. if (Is98LegacyIde(&baseIoAddress1)) {
  403. for (j=3; j<12; j++) {
  404. cmPartialDescriptors[j].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  405. }
  406. }
  407. }
  408. }
  409. }
  410. //
  411. // release the resources we have grab, IoReportDetectedDevice()
  412. // will grab them for us again when we call and it will grab them
  413. // on behalf of the detected PDO.
  414. //
  415. IoReportResourceForDetection (
  416. DriverObject,
  417. NULL,
  418. 0,
  419. NULL,
  420. NULL,
  421. 0,
  422. &conflictDetected
  423. );
  424. if (NT_SUCCESS(status)) {
  425. detectedPhysicalDeviceObject = NULL;
  426. status = IoReportDetectedDevice(DriverObject,
  427. InterfaceTypeUndefined,
  428. -1,
  429. -1,
  430. cmResourceList,
  431. NULL,
  432. FALSE,
  433. &detectedPhysicalDeviceObject);
  434. if (NT_SUCCESS (status)) {
  435. //
  436. // create a FDO and attach it to the detected PDO
  437. //
  438. status = ChannelAddChannel (
  439. DriverObject,
  440. detectedPhysicalDeviceObject,
  441. &fdoExtension
  442. );
  443. if (NT_SUCCESS (status)) {
  444. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
  445. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  446. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
  447. ULONG i, j;
  448. //
  449. // translate resources
  450. //
  451. fullResourceList = cmResourceList->List;
  452. for (i=0; i<cmResourceList->Count; i++) {
  453. partialResourceList = &(fullResourceList->PartialResourceList);
  454. partialDescriptors = fullResourceList->PartialResourceList.PartialDescriptors;
  455. for (j=0; j<partialResourceList->Count; j++) {
  456. resourceIsCmdPort = FALSE;
  457. if (!Is98LegacyIde(&baseIoAddress1)) {
  458. if ((partialDescriptors[j].Type == CmResourceTypePort) &&
  459. (partialDescriptors[j].u.Port.Length == baseIoAddress1Length)) {
  460. resourceIsCmdPort = TRUE;
  461. }
  462. } else {
  463. if ((partialDescriptors[j].Type == CmResourceTypePort) &&
  464. (partialDescriptors[j].u.Port.Start.QuadPart == IDE_NEC98_COMMAND_PORT_ADDRESS)) {
  465. resourceIsCmdPort = TRUE;
  466. } else if ((partialDescriptors[j].Type == CmResourceTypePort) &&
  467. (partialDescriptors[j].u.Port.Start.QuadPart != IDE_NEC98_COMMAND_PORT_ADDRESS) &&
  468. (partialDescriptors[j].u.Port.Start.QuadPart != (IDE_NEC98_COMMAND_PORT_ADDRESS + 0x10C))) {
  469. //
  470. // This is not the base port address for Legacy ide on NEC98;
  471. //
  472. continue;
  473. }
  474. }
  475. if (resourceIsCmdPort) {
  476. if (cmdAddressSpace == MEMORY_SPACE) {
  477. partialDescriptors[j].Type = CmResourceTypeMemory;
  478. partialDescriptors[j].u.Memory.Start = cmdRegMemoryBase;
  479. partialDescriptors[j].u.Memory.Length = partialDescriptors[j].u.Port.Length;
  480. } else {
  481. partialDescriptors[j].u.Port.Start.QuadPart = (ULONG_PTR) cmdRegBase;
  482. }
  483. } else if ((partialDescriptors[j].Type == CmResourceTypePort) &&
  484. (partialDescriptors[j].u.Port.Length == 1)) {
  485. if (ctrlAddressSpace == MEMORY_SPACE) {
  486. partialDescriptors[j].Type = CmResourceTypeMemory;
  487. partialDescriptors[j].u.Memory.Start = ctrlRegMemoryBase;
  488. partialDescriptors[j].u.Memory.Length = partialDescriptors[j].u.Port.Length;
  489. } else {
  490. partialDescriptors[j].u.Port.Start.QuadPart = (ULONG_PTR) ctrlRegBase;
  491. }
  492. } else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) {
  493. partialDescriptors[j].u.Interrupt.Vector = HalGetInterruptVector(fullResourceList->InterfaceType,
  494. fullResourceList->BusNumber,
  495. partialDescriptors[j].u.Interrupt.Level,
  496. partialDescriptors[j].u.Interrupt.Vector,
  497. (PKIRQL) &partialDescriptors[j].u.Interrupt.Level,
  498. &partialDescriptors[j].u.Interrupt.Affinity);
  499. }
  500. }
  501. fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + j);
  502. }
  503. //
  504. // start the FDO
  505. //
  506. status = ChannelStartChannel (fdoExtension,
  507. cmResourceList); // callee is keeping this if no error
  508. }
  509. if (!NT_SUCCESS (status)) {
  510. //
  511. // go through the remove sequence
  512. //
  513. if (fdoExtension) {
  514. ChannelRemoveChannel (fdoExtension);
  515. IoDetachDevice (fdoExtension->AttacheeDeviceObject);
  516. IoDeleteDevice (fdoExtension->DeviceObject);
  517. }
  518. DebugPrint ((0, "IdePort: Unable to start detected device\n"));
  519. ASSERT (FALSE);
  520. } else {
  521. IoInvalidateDeviceRelations (
  522. fdoExtension->AttacheePdo,
  523. BusRelations
  524. );
  525. }
  526. }
  527. }
  528. }
  529. GetOut:
  530. if (cmResourceList) {
  531. ExFreePool (cmResourceList);
  532. }
  533. if (detectionPort) {
  534. ExFreePool (detectionPort);
  535. }
  536. return status;
  537. } //IdePortDetectLegacyController
  538. NTSTATUS
  539. IdePortCreateDetectionList (
  540. IN PDRIVER_OBJECT DriverObject,
  541. OUT PDETECTION_PORT *DetectionPort,
  542. OUT PULONG NumPort
  543. )
  544. /*++
  545. Routine Description:
  546. create a list of popular legacy ports
  547. Arguments:
  548. DriverObject - this driver's driver object
  549. DetectionPort - pointer to port list
  550. NumPort - number of ports in the list
  551. Return Value:
  552. NT Status
  553. --*/
  554. {
  555. NTSTATUS status;
  556. CCHAR deviceBuffer[50];
  557. ANSI_STRING ansiString;
  558. UNICODE_STRING subKeyPath;
  559. HANDLE subServiceKey;
  560. PDETECTION_PORT detectionPort;
  561. ULONG numDevices;
  562. ULONG i;
  563. ULONG j;
  564. CUSTOM_DEVICE_PARAMETER customDeviceParameter;
  565. PCONFIGURATION_INFORMATION configurationInformation = IoGetConfigurationInformation();
  566. numDevices = 0;
  567. status = STATUS_SUCCESS;
  568. #ifdef DRIVER_PARAMETER_REGISTRY_SUPPORT
  569. //
  570. // look for non-standard legacy port setting in the registry
  571. // 9
  572. do {
  573. sprintf (deviceBuffer, "Parameters\\Device%d", numDevices);
  574. RtlInitAnsiString(&ansiString, deviceBuffer);
  575. status = RtlAnsiStringToUnicodeString(&subKeyPath, &ansiString, TRUE);
  576. if (NT_SUCCESS(status)) {
  577. subServiceKey = IdePortOpenServiceSubKey (
  578. DriverObject,
  579. &subKeyPath
  580. );
  581. RtlFreeUnicodeString (&subKeyPath);
  582. if (subServiceKey) {
  583. numDevices++;
  584. IdePortCloseServiceSubKey (
  585. subServiceKey
  586. );
  587. } else {
  588. status = STATUS_UNSUCCESSFUL;
  589. }
  590. }
  591. } while (NT_SUCCESS(status));
  592. #endif // DRIVER_PARAMETER_REGISTRY_SUPPORT
  593. //
  594. // always have at least 4 to return
  595. //
  596. detectionPort = ExAllocatePool (
  597. PagedPool,
  598. (numDevices + 4) * sizeof (DETECTION_PORT)
  599. );
  600. if (detectionPort) {
  601. for (i = j = 0; i < numDevices; i++) {
  602. #ifdef DRIVER_PARAMETER_REGISTRY_SUPPORT
  603. //
  604. // look for non-standard legacy port setting in the registry
  605. //
  606. sprintf (deviceBuffer, "Parameters\\Device%d", i);
  607. RtlInitAnsiString(&ansiString, deviceBuffer);
  608. status = RtlAnsiStringToUnicodeString(&subKeyPath, &ansiString, TRUE);
  609. if (NT_SUCCESS(status)) {
  610. subServiceKey = IdePortOpenServiceSubKey (
  611. DriverObject,
  612. &subKeyPath
  613. );
  614. RtlFreeUnicodeString (&subKeyPath);
  615. if (subServiceKey) {
  616. RtlZeroMemory (
  617. &customDeviceParameter,
  618. sizeof (CUSTOM_DEVICE_PARAMETER)
  619. );
  620. IdeParseDeviceParameters (
  621. subServiceKey,
  622. &customDeviceParameter
  623. );
  624. if (customDeviceParameter.CommandRegisterBase) {
  625. detectionPort[j].CommandRegisterBase =
  626. customDeviceParameter.CommandRegisterBase;
  627. detectionPort[j].ControlRegisterBase =
  628. customDeviceParameter.CommandRegisterBase + 0x206;
  629. detectionPort[j].IrqLevel =
  630. customDeviceParameter.IrqLevel;
  631. j++;
  632. }
  633. IdePortCloseServiceSubKey (
  634. subServiceKey
  635. );
  636. }
  637. }
  638. #endif // DRIVER_PARAMETER_REGISTRY_SUPPORT
  639. }
  640. //
  641. // populate the list with popular i/o ports
  642. //
  643. if ( !IsNEC_98 ) {
  644. if (configurationInformation->AtDiskPrimaryAddressClaimed == FALSE) {
  645. detectionPort[j].CommandRegisterBase = 0x1f0;
  646. detectionPort[j].ControlRegisterBase = 0x1f0 + 0x206;
  647. detectionPort[j].IrqLevel = 14;
  648. j++;
  649. }
  650. if (configurationInformation->AtDiskSecondaryAddressClaimed == FALSE) {
  651. detectionPort[j].CommandRegisterBase = 0x170;
  652. detectionPort[j].ControlRegisterBase = 0x170 + 0x206;
  653. detectionPort[j].IrqLevel = 15;
  654. j++;
  655. }
  656. detectionPort[j].CommandRegisterBase = 0x1e8;
  657. detectionPort[j].ControlRegisterBase = 0x1e8 + 0x206;
  658. detectionPort[j].IrqLevel = 11;
  659. // DEC Hi-Note hack
  660. // detectionPort[j].ControlRegisterBase = 0x1e8 + 0x1f - 0x2;
  661. // detectionPort[j].IrqLevel = 7;
  662. // DEC Hi-Note hack
  663. j++;
  664. detectionPort[j].CommandRegisterBase = 0x168;
  665. detectionPort[j].ControlRegisterBase = 0x168 + 0x206;
  666. detectionPort[j].IrqLevel = 10;
  667. j++;
  668. } else { // IsNEC_98
  669. if ((configurationInformation->AtDiskPrimaryAddressClaimed == FALSE) &&
  670. (configurationInformation->AtDiskSecondaryAddressClaimed == FALSE)) {
  671. detectionPort[j].CommandRegisterBase = 0x640;
  672. detectionPort[j].ControlRegisterBase = 0x640 + 0x10c; //0x74c
  673. detectionPort[j].IrqLevel = 9;
  674. j++;
  675. }
  676. }
  677. *NumPort = j;
  678. *DetectionPort = detectionPort;
  679. return STATUS_SUCCESS;
  680. } else {
  681. *NumPort = 0;
  682. *DetectionPort = NULL;
  683. return STATUS_INSUFFICIENT_RESOURCES;
  684. }
  685. } // IdePortCreateDetectionList
  686. NTSTATUS
  687. IdePortTranslateAddress (
  688. IN INTERFACE_TYPE InterfaceType,
  689. IN ULONG BusNumber,
  690. IN PHYSICAL_ADDRESS StartAddress,
  691. IN LONG Length,
  692. IN OUT PULONG AddressSpace,
  693. OUT PVOID *TranslatedAddress,
  694. OUT PPHYSICAL_ADDRESS TranslatedMemoryAddress
  695. )
  696. /*++
  697. Routine Description:
  698. translate i/o address
  699. Arguments:
  700. InterfaceType - bus interface
  701. BusNumber - bus number
  702. StartAddress - address to translate
  703. Length - number of byte to translate
  704. AddressSpace - address space for the given address
  705. Return Value:
  706. AddressSpace - address space for the translated address
  707. TranslatedAddress - translated address
  708. TranslatedMemoryAddress - tranlated memory address if translated to memory space
  709. NT Status
  710. --*/
  711. {
  712. PHYSICAL_ADDRESS translatedAddress;
  713. ASSERT (Length);
  714. ASSERT (AddressSpace);
  715. ASSERT (TranslatedAddress);
  716. *TranslatedAddress = NULL;
  717. TranslatedMemoryAddress->QuadPart = (ULONGLONG) NULL;
  718. if (HalTranslateBusAddress(InterfaceType,
  719. BusNumber,
  720. StartAddress,
  721. AddressSpace,
  722. &translatedAddress)) {
  723. if (*AddressSpace == IO_SPACE) {
  724. *TranslatedAddress = (PVOID) translatedAddress.u.LowPart;
  725. } else if (*AddressSpace == MEMORY_SPACE) {
  726. //
  727. // translated address is in memory space,
  728. // need to map it to I/O space.
  729. //
  730. *TranslatedMemoryAddress = translatedAddress;
  731. *TranslatedAddress = MmMapIoSpace(
  732. translatedAddress,
  733. Length,
  734. FALSE);
  735. }
  736. }
  737. if (*TranslatedAddress) {
  738. return STATUS_SUCCESS;
  739. } else {
  740. return STATUS_INVALID_PARAMETER;
  741. }
  742. } // IdePortTranslateAddress
  743. VOID
  744. IdePortFreeTranslatedAddress (
  745. IN PVOID TranslatedAddress,
  746. IN LONG Length,
  747. IN ULONG AddressSpace
  748. )
  749. /*++
  750. Routine Description:
  751. free resources created for a translated address
  752. Arguments:
  753. TranslatedAddress - translated address
  754. Length - number of byte to translated
  755. AddressSpace - address space for the translated address
  756. Return Value:
  757. None
  758. --*/
  759. {
  760. if (TranslatedAddress) {
  761. if (AddressSpace == MEMORY_SPACE) {
  762. MmUnmapIoSpace (
  763. TranslatedAddress,
  764. Length
  765. );
  766. }
  767. }
  768. return;
  769. } // IdePortFreeTranslatedAddress
  770. BOOLEAN
  771. IdePortDetectAlias (
  772. PIDE_REGISTERS_1 CmdRegBase
  773. )
  774. {
  775. PIDE_REGISTERS_1 cmdRegBaseAlias;
  776. PUCHAR cylinderHighAlias;
  777. PUCHAR cylinderLowAlias;
  778. //
  779. // alias port
  780. //
  781. cylinderHighAlias = (PUCHAR) ((ULONG_PTR) CmdRegBase->CylinderHigh | (1 << 15));
  782. cylinderLowAlias = (PUCHAR) ((ULONG_PTR) CmdRegBase->CylinderLow | (1 << 15));
  783. IdePortOutPortByte (CmdRegBase->CylinderHigh, SAMPLE_CYLINDER_HIGH_VALUE);
  784. IdePortOutPortByte (CmdRegBase->CylinderLow, SAMPLE_CYLINDER_LOW_VALUE);
  785. //
  786. // Check if indentifier can be read back via the alias port
  787. //
  788. if ((IdePortInPortByte (cylinderHighAlias) != SAMPLE_CYLINDER_HIGH_VALUE) ||
  789. (IdePortInPortByte (cylinderLowAlias) != SAMPLE_CYLINDER_LOW_VALUE)) {
  790. return FALSE;
  791. } else {
  792. return TRUE;
  793. }
  794. }
  795. #endif // NO_LEGACY_DRIVERS