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.

1433 lines
39 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. This module contains the code that manipulates the ARC firmware
  7. tree and other elements in the registry.
  8. Author:
  9. Bob Rinne
  10. Ravisankar Pudipeddi (ravisp) 1 Dec 1996
  11. Neil Sandlin (neilsa) June 1 1999
  12. Environment:
  13. Kernel mode
  14. Revision History :
  15. --*/
  16. #include "pch.h"
  17. //
  18. // Internal References
  19. //
  20. VOID
  21. PcmciaGetRegistryContextRange(
  22. IN HANDLE instanceHandle,
  23. IN PCWSTR Name,
  24. IN OPTIONAL const PCMCIA_CONTEXT_RANGE IncludeRange[],
  25. IN OPTIONAL const PCMCIA_CONTEXT_RANGE ExcludeRange[],
  26. OUT PPCMCIA_CONTEXT pContext
  27. );
  28. ULONG
  29. PcmciaGetDetectedFdoIrqMask(
  30. IN PFDO_EXTENSION FdoExtension
  31. );
  32. NTSTATUS
  33. PcmciaScanHardwareDescription(
  34. VOID
  35. );
  36. NTSTATUS
  37. PcmciaGetHardwareDetectedIrqMask(
  38. IN HANDLE handlePcCard
  39. );
  40. //
  41. //
  42. // Registry related definitions
  43. //
  44. #define PCMCIA_REGISTRY_PARAMETERS_KEY L"Pcmcia\\Parameters"
  45. #define PCMCIA_REGISTRY_DETECTED_DEVICE_KEY L"ControllerProperties"
  46. //
  47. // Per controller values (in control\class)
  48. //
  49. #define PCMCIA_REGISTRY_PCI_CONTEXT_VALUE L"CBSSCSContextRanges"
  50. #define PCMCIA_REGISTRY_CB_CONTEXT_VALUE L"CBSSCBContextRanges"
  51. #define PCMCIA_REGISTRY_EXCA_CONTEXT_VALUE L"CBSSEXCAContextRanges"
  52. #define PCMCIA_REGISTRY_CACHED_IRQMASK L"CachedIrqMask"
  53. #define PCMCIA_REGISTRY_COMPATIBLE_TYPE L"CompatibleControllerType"
  54. #define PCMCIA_REGISTRY_VOLTAGE_PREFERENCE L"VoltagePreference"
  55. //
  56. // Irq detection values (in hardware\description)
  57. //
  58. #define PCMCIA_REGISTRY_CONTROLLER_TYPE L"OtherController"
  59. #ifdef ALLOC_PRAGMA
  60. #pragma alloc_text(INIT,PcmciaLoadGlobalRegistryValues)
  61. #pragma alloc_text(INIT,PcmciaScanHardwareDescription)
  62. #pragma alloc_text(INIT,PcmciaGetHardwareDetectedIrqMask)
  63. #pragma alloc_text(PAGE,PcmciaGetControllerRegistrySettings)
  64. #pragma alloc_text(PAGE,PcmciaGetRegistryFdoIrqMask)
  65. #pragma alloc_text(PAGE,PcmciaGetDetectedFdoIrqMask)
  66. #pragma alloc_text(PAGE,PcmciaGetLegacyDetectedControllerType)
  67. #pragma alloc_text(PAGE,PcmciaSetLegacyDetectedControllerType)
  68. #pragma alloc_text(PAGE,PcmciaGetRegistryContextRange)
  69. #endif
  70. NTSTATUS
  71. PcmciaGetHardwareDetectedIrqMask(
  72. HANDLE handlePcCard
  73. )
  74. /*++
  75. Routine Description:
  76. This routine looks through the OtherController key for pccard entries
  77. created by NTDETECT. For each entry, the IRQ scan data is read in and
  78. saved for later.
  79. Arguments:
  80. handlePcCard - open handle to "OtherController" key in registry at
  81. HARDWARE\Description\System\MultifunctionAdapter\<ISA>
  82. Return value:
  83. status
  84. --*/
  85. {
  86. #define VALUE2_BUFFER_SIZE sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(CM_PCCARD_DEVICE_DATA) + sizeof(CM_FULL_RESOURCE_DESCRIPTOR)
  87. UCHAR valueBuffer[VALUE2_BUFFER_SIZE];
  88. PKEY_VALUE_PARTIAL_INFORMATION valueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) valueBuffer;
  89. NTSTATUS status;
  90. KEY_FULL_INFORMATION KeyFullInfo;
  91. PKEY_BASIC_INFORMATION subKeyInfo = NULL;
  92. OBJECT_ATTRIBUTES attributes;
  93. UNICODE_STRING strSubKey = {0};
  94. UNICODE_STRING strIdentifier;
  95. UNICODE_STRING strConfigData;
  96. HANDLE handleSubKey = NULL;
  97. ULONG subKeyInfoSize;
  98. ULONG index;
  99. ULONG resultLength;
  100. RtlInitUnicodeString(&strIdentifier, L"Identifier");
  101. RtlInitUnicodeString(&strConfigData, L"Configuration Data");
  102. status = ZwQueryKey(handlePcCard,
  103. KeyFullInformation,
  104. &KeyFullInfo,
  105. sizeof(KeyFullInfo),
  106. &resultLength);
  107. if ((!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW))) {
  108. goto cleanup;
  109. }
  110. strSubKey.MaximumLength = (USHORT) KeyFullInfo.MaxNameLen;
  111. subKeyInfoSize = sizeof(KEY_BASIC_INFORMATION) + KeyFullInfo.MaxNameLen;
  112. subKeyInfo = ExAllocatePool(PagedPool, subKeyInfoSize);
  113. if (!subKeyInfo) {
  114. goto cleanup;
  115. }
  116. for (index=0;;index++) {
  117. //
  118. // Loop through the children of the PcCardController key
  119. //
  120. status = ZwEnumerateKey(handlePcCard,
  121. index,
  122. KeyBasicInformation,
  123. subKeyInfo,
  124. subKeyInfoSize,
  125. &resultLength);
  126. if (!NT_SUCCESS(status)) {
  127. goto cleanup;
  128. }
  129. //
  130. // Init the name
  131. //
  132. if (subKeyInfo->NameLength > strSubKey.MaximumLength) {
  133. continue;
  134. }
  135. strSubKey.Length = (USHORT) subKeyInfo->NameLength;
  136. strSubKey.Buffer = subKeyInfo->Name;
  137. //
  138. // Get a handle to a child of PcCardController
  139. //
  140. InitializeObjectAttributes(&attributes,
  141. &strSubKey,
  142. 0, //Attributes
  143. handlePcCard,
  144. NULL //SecurityDescriptor
  145. );
  146. if (handleSubKey) {
  147. // close handle from previous iteration
  148. ZwClose(handleSubKey);
  149. handleSubKey = NULL;
  150. }
  151. status = ZwOpenKey(&handleSubKey, MAXIMUM_ALLOWED, &attributes);
  152. if (!NT_SUCCESS(status)) {
  153. goto cleanup;
  154. }
  155. //
  156. // Get the value of "Identifier"
  157. //
  158. status = ZwQueryValueKey(handleSubKey,
  159. &strIdentifier,
  160. KeyValuePartialInformation,
  161. valueInfo,
  162. VALUE2_BUFFER_SIZE,
  163. &resultLength);
  164. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW)) {
  165. PWCHAR pData = (PWCHAR)valueInfo->Data;
  166. if ((valueInfo->DataLength == 17*sizeof(WCHAR)) &&
  167. (pData[0] == (WCHAR)'P') &&
  168. (pData[1] == (WCHAR)'c') &&
  169. (pData[2] == (WCHAR)'C') &&
  170. (pData[3] == (WCHAR)'a') &&
  171. (pData[4] == (WCHAR)'r') &&
  172. (pData[5] == (WCHAR)'d')) {
  173. //
  174. // Get the IRQ detection data
  175. //
  176. status = ZwQueryValueKey(handleSubKey,
  177. &strConfigData,
  178. KeyValuePartialInformation,
  179. valueInfo,
  180. VALUE2_BUFFER_SIZE,
  181. &resultLength);
  182. if (NT_SUCCESS(status)) {
  183. PCM_FULL_RESOURCE_DESCRIPTOR pFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) valueInfo->Data;
  184. PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) pFullDesc->PartialResourceList.PartialDescriptors;
  185. if ((pPartialDesc->Type == CmResourceTypeDeviceSpecific) &&
  186. (pPartialDesc->u.DeviceSpecificData.DataSize == sizeof(CM_PCCARD_DEVICE_DATA))) {
  187. PCM_PCCARD_DEVICE_DATA pData = (PCM_PCCARD_DEVICE_DATA) ((ULONG_PTR)&pPartialDesc->u.DeviceSpecificData + 3*sizeof(ULONG));
  188. PPCMCIA_NTDETECT_DATA pNewData;
  189. pNewData = ExAllocatePool(PagedPool, sizeof(PCMCIA_NTDETECT_DATA));
  190. if (pNewData == NULL) {
  191. goto cleanup;
  192. }
  193. pNewData->PcCardData = *pData;
  194. pNewData->Next = pNtDetectDataList;
  195. pNtDetectDataList = pNewData;
  196. }
  197. }
  198. }
  199. }
  200. }
  201. cleanup:
  202. if (handleSubKey) {
  203. ZwClose(handleSubKey);
  204. }
  205. if (subKeyInfo) {
  206. ExFreePool(subKeyInfo);
  207. }
  208. return STATUS_SUCCESS;
  209. }
  210. ULONG
  211. PcmciaGetDetectedFdoIrqMask(
  212. IN PFDO_EXTENSION FdoExtension
  213. )
  214. /*++
  215. Routine Description:
  216. This routine looks through the cached PCMCIA_NTDETECT_DATA entries
  217. to see if there was an entry for this controller. It then returns the
  218. detected irq mask for that controller.
  219. Arguments:
  220. FdoExtension - The fdo extension corresponding to the PCMCIA controller
  221. Return value:
  222. status
  223. --*/
  224. {
  225. PPCMCIA_NTDETECT_DATA pData;
  226. PCM_PCCARD_DEVICE_DATA pPcCardData;
  227. ULONG detectedIrqMask = 0;
  228. if (FdoExtension->SocketList == NULL) {
  229. return 0;
  230. }
  231. for (pData = pNtDetectDataList; pData != NULL; pData = pData->Next) {
  232. pPcCardData = &pData->PcCardData;
  233. if (CardBusExtension(FdoExtension)) {
  234. if (!(pPcCardData->Flags & PCCARD_DEVICE_PCI) || ((pPcCardData->BusData) == 0) ||
  235. ((pPcCardData->BusData & 0xff) != FdoExtension->PciBusNumber) ||
  236. (((pPcCardData->BusData >> 8) & 0xff) != FdoExtension->PciDeviceNumber)) {
  237. continue;
  238. }
  239. SetFdoFlag(FdoExtension, PCMCIA_FDO_IRQ_DETECT_DEVICE_FOUND);
  240. if (!(pPcCardData->Flags & PCCARD_MAP_ERROR)) {
  241. //
  242. // we found the device, and the map looks good
  243. //
  244. break;
  245. }
  246. } else {
  247. if ((pPcCardData->Flags & PCCARD_DEVICE_PCI) ||
  248. (pPcCardData->LegacyBaseAddress != (ULONG_PTR)FdoExtension->SocketList->AddressPort)) {
  249. continue;
  250. }
  251. SetFdoFlag(FdoExtension, PCMCIA_FDO_IRQ_DETECT_DEVICE_FOUND);
  252. if (!(pPcCardData->Flags & PCCARD_MAP_ERROR)) {
  253. //
  254. // we found the device, and the map looks good
  255. //
  256. break;
  257. }
  258. }
  259. }
  260. if (pData) {
  261. ULONG i;
  262. //
  263. // Found the entry
  264. //
  265. // Since we don't currently handle "rewired" irqs, we can compact
  266. // it down to a bit mask, throwing away irqs that are wired, say
  267. // IRQ12 on the controller to IRQ15 on the isa bus.
  268. //
  269. for (i = 1; i < 16; i++) {
  270. if (pPcCardData->IRQMap[i] == i) {
  271. detectedIrqMask |= (1<<i);
  272. }
  273. }
  274. SetFdoFlag(FdoExtension, PCMCIA_FDO_IRQ_DETECT_COMPLETED);
  275. }
  276. return detectedIrqMask;
  277. }
  278. NTSTATUS
  279. PcmciaScanHardwareDescription(
  280. VOID
  281. )
  282. /*++
  283. Routine Description:
  284. This routine finds the "OtherController" entry in
  285. HARDWARE\Description\System\MultifunctionAdapter\<ISA>. This is
  286. where NTDETECT stores irq scan results.
  287. It also looks for machines that aren't supported, for example MCA
  288. bus.
  289. Arguments:
  290. Return value:
  291. status
  292. --*/
  293. {
  294. #define VALUE_BUFFER_SIZE sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 3*sizeof(WCHAR)
  295. UCHAR valueBuffer[VALUE_BUFFER_SIZE];
  296. PKEY_VALUE_PARTIAL_INFORMATION valueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) valueBuffer;
  297. PKEY_BASIC_INFORMATION subKeyInfo = NULL;
  298. KEY_FULL_INFORMATION KeyFullInfo;
  299. HANDLE handleRoot = NULL;
  300. HANDLE handleSubKey = NULL;
  301. HANDLE handlePcCard = NULL;
  302. UNICODE_STRING strRoot, strIdentifier;
  303. UNICODE_STRING strSubKey = {0};
  304. UNICODE_STRING strPcCard = {0};
  305. NTSTATUS status;
  306. OBJECT_ATTRIBUTES attributes;
  307. ULONG subKeyInfoSize;
  308. ULONG resultLength;
  309. ULONG index;
  310. PAGED_CODE();
  311. //
  312. // Get a handle to the MultifunctionAdapter key
  313. //
  314. RtlInitUnicodeString(&strRoot, L"\\Registry\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter");
  315. RtlInitUnicodeString(&strIdentifier, L"Identifier");
  316. RtlInitUnicodeString(&strPcCard, PCMCIA_REGISTRY_CONTROLLER_TYPE);
  317. InitializeObjectAttributes(&attributes,
  318. &strRoot,
  319. OBJ_CASE_INSENSITIVE,
  320. NULL,
  321. NULL);
  322. status = ZwOpenKey(&handleRoot, MAXIMUM_ALLOWED, &attributes);
  323. if (!NT_SUCCESS(status)) {
  324. goto cleanup;
  325. }
  326. status = ZwQueryKey(handleRoot,
  327. KeyFullInformation,
  328. &KeyFullInfo,
  329. sizeof(KeyFullInfo),
  330. &resultLength);
  331. if ((!NT_SUCCESS(status) && (status != STATUS_BUFFER_OVERFLOW))) {
  332. goto cleanup;
  333. }
  334. strSubKey.MaximumLength = (USHORT) KeyFullInfo.MaxNameLen;
  335. subKeyInfoSize = sizeof(KEY_BASIC_INFORMATION) + KeyFullInfo.MaxNameLen;
  336. subKeyInfo = ExAllocatePool(PagedPool, subKeyInfoSize);
  337. if (!subKeyInfo) {
  338. goto cleanup;
  339. }
  340. for (index=0;;index++) {
  341. //
  342. // Loop through the children of "MultifunctionAdapter"
  343. //
  344. status = ZwEnumerateKey(handleRoot,
  345. index,
  346. KeyBasicInformation,
  347. subKeyInfo,
  348. subKeyInfoSize,
  349. &resultLength);
  350. if (!NT_SUCCESS(status)) {
  351. goto cleanup;
  352. }
  353. //
  354. // Init the name
  355. //
  356. if (subKeyInfo->NameLength > strSubKey.MaximumLength) {
  357. continue;
  358. }
  359. strSubKey.Length = (USHORT) subKeyInfo->NameLength;
  360. strSubKey.Buffer = subKeyInfo->Name;
  361. //
  362. // Get a handle to a child of MultifunctionAdapter
  363. //
  364. InitializeObjectAttributes(&attributes,
  365. &strSubKey,
  366. 0, //Attributes
  367. handleRoot,
  368. NULL //SecurityDescriptor
  369. );
  370. if (handleSubKey) {
  371. // close handle from previous iteration
  372. ZwClose(handleSubKey);
  373. handleSubKey = NULL;
  374. }
  375. status = ZwOpenKey(&handleSubKey, MAXIMUM_ALLOWED, &attributes);
  376. if (!NT_SUCCESS(status)) {
  377. goto cleanup;
  378. }
  379. //
  380. // Get the value of "Identifier"
  381. //
  382. status = ZwQueryValueKey(handleSubKey,
  383. &strIdentifier,
  384. KeyValuePartialInformation,
  385. valueInfo,
  386. VALUE_BUFFER_SIZE,
  387. &resultLength);
  388. if (NT_SUCCESS(status)) {
  389. PWCHAR pData = (PWCHAR)valueInfo->Data;
  390. if ((valueInfo->DataLength == 4*sizeof(WCHAR)) &&
  391. (pData[0] == (WCHAR)'M') &&
  392. (pData[1] == (WCHAR)'C') &&
  393. (pData[2] == (WCHAR)'A') &&
  394. (pData[3] == UNICODE_NULL)) {
  395. status = STATUS_NO_SUCH_DEVICE;
  396. goto cleanup;
  397. }
  398. if ((valueInfo->DataLength == 4*sizeof(WCHAR)) &&
  399. (pData[0] == (WCHAR)'I') &&
  400. (pData[1] == (WCHAR)'S') &&
  401. (pData[2] == (WCHAR)'A') &&
  402. (pData[3] == UNICODE_NULL)) {
  403. InitializeObjectAttributes(&attributes,
  404. &strPcCard,
  405. 0, //Attributes
  406. handleSubKey,
  407. NULL //SecurityDescriptor
  408. );
  409. status = ZwOpenKey(&handlePcCard, MAXIMUM_ALLOWED, &attributes);
  410. if (NT_SUCCESS(status)) {
  411. status = PcmciaGetHardwareDetectedIrqMask(handlePcCard);
  412. ZwClose(handlePcCard);
  413. }
  414. }
  415. }
  416. }
  417. cleanup:
  418. if (handleRoot) {
  419. ZwClose(handleRoot);
  420. }
  421. if (handleSubKey) {
  422. ZwClose(handleSubKey);
  423. }
  424. if (subKeyInfo) {
  425. ExFreePool(subKeyInfo);
  426. }
  427. if (status == STATUS_NO_SUCH_DEVICE) {
  428. //
  429. // Must be an MCA machine
  430. //
  431. return status;
  432. }
  433. return STATUS_SUCCESS;
  434. }
  435. NTSTATUS
  436. PcmciaLoadGlobalRegistryValues(
  437. VOID
  438. )
  439. /*++
  440. Routine Description:
  441. This routine is called at driver init time to load in various global
  442. options from the registry.
  443. These are read in from SYSTEM\CurrentControlSet\Services\Pcmcia\Parameters.
  444. Arguments:
  445. none
  446. Return value:
  447. none
  448. --*/
  449. {
  450. PRTL_QUERY_REGISTRY_TABLE parms;
  451. NTSTATUS status;
  452. ULONG parmsSize;
  453. ULONG i;
  454. status = PcmciaScanHardwareDescription();
  455. if (!NT_SUCCESS(status)) {
  456. return status;
  457. }
  458. //
  459. // Needs a null entry to terminate the list
  460. //
  461. parmsSize = sizeof(RTL_QUERY_REGISTRY_TABLE) * (GlobalInfoCount+1);
  462. parms = ExAllocatePool(PagedPool, parmsSize);
  463. if (!parms) {
  464. return STATUS_INSUFFICIENT_RESOURCES;
  465. }
  466. RtlZeroMemory(parms, parmsSize);
  467. //
  468. // Fill in the query table from our table
  469. //
  470. for (i = 0; i < GlobalInfoCount; i++) {
  471. parms[i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  472. parms[i].Name = GlobalRegistryInfo[i].Name;
  473. parms[i].EntryContext = GlobalRegistryInfo[i].pValue;
  474. parms[i].DefaultType = REG_DWORD;
  475. parms[i].DefaultData = &GlobalRegistryInfo[i].Default;
  476. parms[i].DefaultLength = sizeof(ULONG);
  477. }
  478. //
  479. // Perform the query
  480. //
  481. status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES | RTL_REGISTRY_OPTIONAL,
  482. PCMCIA_REGISTRY_PARAMETERS_KEY,
  483. parms,
  484. NULL,
  485. NULL);
  486. if (!NT_SUCCESS(status)) {
  487. //
  488. // This is possible during text mode setup
  489. //
  490. for (i = 0; i < GlobalInfoCount; i++) {
  491. *GlobalRegistryInfo[i].pValue = GlobalRegistryInfo[i].Default;
  492. }
  493. }
  494. if (initSoundsEnabled) {
  495. PcmciaGlobalFlags |= PCMCIA_GLOBAL_SOUNDS_ENABLED;
  496. }
  497. if (initUsePolledCsc) {
  498. PcmciaGlobalFlags |= PCMCIA_GLOBAL_FORCE_POLL_MODE;
  499. }
  500. if (initDisableAcpiNameSpaceCheck) {
  501. PcmciaGlobalFlags |= PCMCIA_DISABLE_ACPI_NAMESPACE_CHECK;
  502. }
  503. if (initDefaultRouteR2ToIsa) {
  504. PcmciaGlobalFlags |= PCMCIA_DEFAULT_ROUTE_R2_TO_ISA;
  505. }
  506. if (!pcmciaIsaIrqRescanComplete) {
  507. UNICODE_STRING unicodeKey, unicodeValue;
  508. OBJECT_ATTRIBUTES objectAttributes;
  509. HANDLE handle;
  510. ULONG value;
  511. //
  512. // This mechanism is used to throw away the cached ISA irq map values. To do this
  513. // only once, we make sure a value in the registry is zero (or non-existant), and
  514. // here we set it to one.
  515. //
  516. RtlInitUnicodeString(&unicodeKey,
  517. L"\\Registry\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Pcmcia\\Parameters");
  518. RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));
  519. InitializeObjectAttributes(&objectAttributes,
  520. &unicodeKey,
  521. OBJ_CASE_INSENSITIVE,
  522. NULL,
  523. NULL);
  524. if (NT_SUCCESS(ZwOpenKey(&handle, KEY_READ | KEY_WRITE, &objectAttributes))) {
  525. RtlInitUnicodeString(&unicodeValue, PCMCIA_REGISTRY_ISA_IRQ_RESCAN_COMPLETE);
  526. value = 1;
  527. ZwSetValueKey(handle,
  528. &unicodeValue,
  529. 0,
  530. REG_DWORD,
  531. &value,
  532. sizeof(value));
  533. ZwClose(handle);
  534. }
  535. }
  536. ExFreePool(parms);
  537. return STATUS_SUCCESS;
  538. }
  539. NTSTATUS
  540. PcmciaGetControllerRegistrySettings(
  541. IN OUT PFDO_EXTENSION FdoExtension
  542. )
  543. /*++
  544. Routine Description:
  545. This routine looks in the registry to see if a compatible controller type
  546. was specified in the INF.
  547. Arguments:
  548. FdoExtension - The fdo extension corresponding to the PCMCIA controller
  549. Return value:
  550. --*/
  551. {
  552. NTSTATUS status = STATUS_UNSUCCESSFUL;
  553. UNICODE_STRING KeyName;
  554. HANDLE instanceHandle;
  555. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  556. PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  557. ULONG length;
  558. BOOLEAN UseLegacyIrqMask = TRUE;
  559. ULONG detectedIrqMask;
  560. if (FdoExtension->Pdo) {
  561. status = IoOpenDeviceRegistryKey(FdoExtension->Pdo,
  562. PLUGPLAY_REGKEY_DRIVER,
  563. KEY_READ,
  564. &instanceHandle
  565. );
  566. }
  567. if (!NT_SUCCESS(status)) {
  568. instanceHandle = NULL;
  569. }
  570. if (instanceHandle) {
  571. //
  572. // Look to see if a controller ID was specified
  573. //
  574. RtlInitUnicodeString(&KeyName, PCMCIA_REGISTRY_COMPATIBLE_TYPE);
  575. status = ZwQueryValueKey(instanceHandle,
  576. &KeyName,
  577. KeyValuePartialInformation,
  578. value,
  579. sizeof(buffer),
  580. &length);
  581. if (NT_SUCCESS(status)) {
  582. PcmciaSetControllerType(FdoExtension, *(PPCMCIA_CONTROLLER_TYPE)(value->Data));
  583. }
  584. //
  585. // Check for voltage preference
  586. // When an 3v R2 card is plugged in, and the controller
  587. // sets both 5v and 3.3v, this allows 3.3v to be preferred.
  588. //
  589. RtlInitUnicodeString(&KeyName, PCMCIA_REGISTRY_VOLTAGE_PREFERENCE);
  590. status = ZwQueryValueKey(instanceHandle,
  591. &KeyName,
  592. KeyValuePartialInformation,
  593. value,
  594. sizeof(buffer),
  595. &length);
  596. if (NT_SUCCESS(status) && (*(PULONG)(value->Data) == 33)) {
  597. SetDeviceFlag(FdoExtension, PCMCIA_FDO_PREFER_3V);
  598. }
  599. }
  600. //
  601. // Retrieve context ranges
  602. //
  603. PcmciaGetRegistryContextRange(instanceHandle,
  604. PCMCIA_REGISTRY_PCI_CONTEXT_VALUE,
  605. DefaultPciContextSave,
  606. NULL,
  607. &FdoExtension->PciContext
  608. );
  609. PcmciaGetRegistryContextRange(instanceHandle,
  610. PCMCIA_REGISTRY_CB_CONTEXT_VALUE,
  611. DefaultCardbusContextSave,
  612. ExcludeCardbusContextRange,
  613. &FdoExtension->CardbusContext
  614. );
  615. PcmciaGetRegistryContextRange(instanceHandle,
  616. PCMCIA_REGISTRY_EXCA_CONTEXT_VALUE,
  617. NULL,
  618. NULL,
  619. &FdoExtension->ExcaContext);
  620. if (instanceHandle) {
  621. ZwClose(instanceHandle);
  622. }
  623. FdoExtension->IoLow = globalIoLow;
  624. FdoExtension->IoHigh = globalIoHigh;
  625. FdoExtension->ReadyDelayIter = globalReadyDelayIter;
  626. FdoExtension->ReadyStall = globalReadyStall;
  627. FdoExtension->AttributeMemoryLow = globalAttributeMemoryLow;
  628. FdoExtension->AttributeMemoryHigh = globalAttributeMemoryHigh;
  629. if (FdoExtension->ControllerType == PcmciaDatabook) {
  630. FdoExtension->AttributeMemoryAlignment = TCIC_WINDOW_ALIGNMENT;
  631. } else {
  632. FdoExtension->AttributeMemoryAlignment = PCIC_WINDOW_ALIGNMENT;
  633. }
  634. //
  635. // Assign default attribute memory window size
  636. //
  637. if (globalAttributeMemorySize == 0) {
  638. switch (FdoExtension->ControllerType) {
  639. case PcmciaDatabook:
  640. FdoExtension->AttributeMemorySize = TCIC_WINDOW_SIZE;
  641. break;
  642. default:
  643. FdoExtension->AttributeMemorySize = PCIC_WINDOW_SIZE;
  644. break;
  645. }
  646. } else {
  647. FdoExtension->AttributeMemorySize = globalAttributeMemorySize;
  648. }
  649. //
  650. // See if the user asked for some special IRQ routing considerations based
  651. // on controller type
  652. //
  653. if (CardBusExtension(FdoExtension)) {
  654. //
  655. // route to PCI based on controller type
  656. //
  657. if (pcmciaIrqRouteToPciController) {
  658. ULONG ctlr = pcmciaIrqRouteToPciController;
  659. //
  660. // Check for exact match, or class if only a class was specified
  661. //
  662. if ((ctlr == FdoExtension->ControllerType) ||
  663. ((PcmciaClassFromControllerType(ctlr) == ctlr) && (ctlr == PcmciaClassFromControllerType(FdoExtension->ControllerType)))) {
  664. SetFdoFlag(FdoExtension, PCMCIA_FDO_PREFER_PCI_ROUTING);
  665. }
  666. }
  667. //
  668. // route to ISA based on controller type
  669. //
  670. if (pcmciaIrqRouteToIsaController) {
  671. ULONG ctlr = pcmciaIrqRouteToIsaController;
  672. //
  673. // Check for exact match, or class if only a class was specified
  674. //
  675. if ((ctlr == FdoExtension->ControllerType) ||
  676. ((PcmciaClassFromControllerType(ctlr) == ctlr) && (ctlr == PcmciaClassFromControllerType(FdoExtension->ControllerType)))) {
  677. SetFdoFlag(FdoExtension, PCMCIA_FDO_PREFER_ISA_ROUTING);
  678. }
  679. }
  680. //
  681. // route to PCI based on controller location
  682. //
  683. if (pcmciaIrqRouteToPciLocation) {
  684. ULONG loc = pcmciaIrqRouteToPciLocation;
  685. if ( ((loc & 0xff) == FdoExtension->PciBusNumber) &&
  686. (((loc >> 8) & 0xff) == FdoExtension->PciDeviceNumber)) {
  687. SetFdoFlag(FdoExtension, PCMCIA_FDO_FORCE_PCI_ROUTING);
  688. }
  689. }
  690. //
  691. // route to ISA based on controller location
  692. //
  693. if (pcmciaIrqRouteToIsaLocation) {
  694. ULONG loc = pcmciaIrqRouteToIsaLocation;
  695. if ( ((loc & 0xff) == FdoExtension->PciBusNumber) &&
  696. (((loc >> 8) & 0xff) == FdoExtension->PciDeviceNumber)) {
  697. SetFdoFlag(FdoExtension, PCMCIA_FDO_FORCE_ISA_ROUTING);
  698. }
  699. }
  700. }
  701. return status;
  702. }
  703. VOID
  704. PcmciaGetRegistryFdoIrqMask(
  705. IN OUT PFDO_EXTENSION FdoExtension
  706. )
  707. /*++
  708. Routine Description:
  709. This routine fills in the field "AllocatedIrqMask" in the specified
  710. fdo extension.
  711. Arguments:
  712. instanceHandle - open registry key for this controller
  713. pIrqMask - pointer to variable to receive irq mask
  714. Return value:
  715. none
  716. --*/
  717. {
  718. ULONG irqMask, cachedIrqMask = 0;
  719. UNICODE_STRING KeyName;
  720. NTSTATUS status;
  721. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  722. PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  723. ULONG length;
  724. HANDLE instanceHandle;
  725. ULONG detectedIrqMask;
  726. PAGED_CODE();
  727. if (globalOverrideIrqMask) {
  728. irqMask = globalOverrideIrqMask;
  729. } else {
  730. detectedIrqMask = PcmciaGetDetectedFdoIrqMask(FdoExtension);
  731. status = STATUS_UNSUCCESSFUL;
  732. if (FdoExtension->Pdo) {
  733. status = IoOpenDeviceRegistryKey(FdoExtension->Pdo,
  734. PLUGPLAY_REGKEY_DRIVER,
  735. KEY_READ,
  736. &instanceHandle
  737. );
  738. }
  739. if (NT_SUCCESS(status)) {
  740. //
  741. // Here we cache the value, and accumulate bits so that
  742. // our mask improves with time.
  743. //
  744. RtlInitUnicodeString(&KeyName, PCMCIA_REGISTRY_CACHED_IRQMASK);
  745. if (pcmciaIsaIrqRescanComplete) {
  746. status = ZwQueryValueKey(instanceHandle,
  747. &KeyName,
  748. KeyValuePartialInformation,
  749. value,
  750. sizeof(buffer),
  751. &length);
  752. if (NT_SUCCESS(status)) {
  753. cachedIrqMask = *(PULONG)(value->Data);
  754. }
  755. }
  756. irqMask = detectedIrqMask | cachedIrqMask;
  757. if ((cachedIrqMask != irqMask) || !pcmciaIsaIrqRescanComplete) {
  758. //
  759. // something changed, update the cached value
  760. //
  761. ZwSetValueKey(instanceHandle, &KeyName, 0, REG_DWORD, &irqMask, sizeof(irqMask));
  762. }
  763. ZwClose(instanceHandle);
  764. } else {
  765. //
  766. // Hmmm, no key. Can't cache the value
  767. //
  768. irqMask = detectedIrqMask;
  769. }
  770. if (pcmciaDisableIsaPciRouting && (PcmciaCountOnes(irqMask) < 2)) {
  771. //
  772. // Perhaps irq detection is broken... fall back on old NT4 behavior
  773. //
  774. irqMask = 0;
  775. }
  776. }
  777. irqMask &= ~globalFilterIrqMask;
  778. DebugPrint((PCMCIA_DEBUG_INFO, "IrqMask %08x (ovr %08x, flt %08x, det %08x, cache %08x)\n",
  779. irqMask, globalOverrideIrqMask, globalFilterIrqMask, detectedIrqMask, cachedIrqMask));
  780. FdoExtension->DetectedIrqMask = (USHORT)irqMask;
  781. }
  782. VOID
  783. PcmciaGetRegistryContextRange(
  784. IN HANDLE instanceHandle,
  785. IN PCWSTR Name,
  786. IN OPTIONAL const PCMCIA_CONTEXT_RANGE IncludeRange[],
  787. IN OPTIONAL const PCMCIA_CONTEXT_RANGE ExcludeRange[],
  788. OUT PPCMCIA_CONTEXT pContext
  789. )
  790. /*++
  791. Routine Description:
  792. This routine returns a buffer containing the contents of the
  793. data which set by the controller's inf definition (AddReg). The value
  794. is in CurrentControlSet\Control\Class\{GUID}\{Instance}.
  795. Arguments:
  796. FdoExtension - The fdo extension corresponding to the PCMCIA controller
  797. Name - The name of the value in the registry
  798. IncludeRange - defines areas in the range that must be included
  799. ExcludeRange - defines areas in the range that must be excluded
  800. Return value:
  801. Status
  802. --*/
  803. {
  804. #define PCMCIA_MAX_CONTEXT_ENTRIES 128
  805. #define MAX_RANGE_OFFSET 256
  806. NTSTATUS status;
  807. UNICODE_STRING unicodeKeyName;
  808. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
  809. PCMCIA_MAX_CONTEXT_ENTRIES*sizeof(PCMCIA_CONTEXT_RANGE)];
  810. PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  811. UCHAR rangeMap[MAX_RANGE_OFFSET] = {0};
  812. PPCMCIA_CONTEXT_RANGE newRange;
  813. LONG rangeCount;
  814. ULONG rangeLength;
  815. ULONG bufferLength;
  816. UCHAR lastEntry;
  817. ULONG keyLength;
  818. USHORT i, j;
  819. USHORT startOffset, endOffset;
  820. PAGED_CODE();
  821. //
  822. // Initialize the range map with the minimum range
  823. //
  824. if (IncludeRange) {
  825. for (i = 0; IncludeRange[i].wLen != 0; i++) {
  826. startOffset = IncludeRange[i].wOffset;
  827. endOffset = IncludeRange[i].wOffset + IncludeRange[i].wLen - 1;
  828. if ((startOffset >= MAX_RANGE_OFFSET) ||
  829. (endOffset >= MAX_RANGE_OFFSET)) {
  830. continue;
  831. }
  832. for (j = startOffset; j <= endOffset; j++) {
  833. rangeMap[j] = 0xff;
  834. }
  835. }
  836. }
  837. if (instanceHandle) {
  838. RtlInitUnicodeString(&unicodeKeyName, Name);
  839. status = ZwQueryValueKey(instanceHandle,
  840. &unicodeKeyName,
  841. KeyValuePartialInformation,
  842. value,
  843. sizeof(buffer),
  844. &keyLength);
  845. if (NT_SUCCESS(status)) {
  846. //
  847. // Merge in the range specified in the registry
  848. //
  849. newRange = (PPCMCIA_CONTEXT_RANGE) value->Data;
  850. for (i = 0; i < value->DataLength/sizeof(PCMCIA_CONTEXT_RANGE); i++) {
  851. startOffset = newRange[i].wOffset;
  852. endOffset = newRange[i].wOffset + newRange[i].wLen - 1;
  853. if ((startOffset >= MAX_RANGE_OFFSET) ||
  854. (endOffset >= MAX_RANGE_OFFSET)) {
  855. continue;
  856. }
  857. for (j = startOffset; j <= endOffset; j++) {
  858. rangeMap[j] = 0xff;
  859. }
  860. }
  861. }
  862. }
  863. //
  864. // Filter out registers defined in the exclude range
  865. //
  866. if (ExcludeRange) {
  867. for (i = 0; ExcludeRange[i].wLen != 0; i++) {
  868. startOffset = ExcludeRange[i].wOffset;
  869. endOffset = ExcludeRange[i].wOffset + ExcludeRange[i].wLen - 1;
  870. if ((startOffset >= MAX_RANGE_OFFSET) ||
  871. (endOffset >= MAX_RANGE_OFFSET)) {
  872. continue;
  873. }
  874. for (j = startOffset; j <= endOffset; j++) {
  875. rangeMap[j] = 0;
  876. }
  877. }
  878. }
  879. //
  880. // Now build the resulting merged range in the buffer on the
  881. // stack, and figure out how big it is.
  882. //
  883. newRange = (PPCMCIA_CONTEXT_RANGE) buffer;
  884. rangeCount = -1;
  885. bufferLength = 0;
  886. lastEntry = 0;
  887. for (i = 0; i < MAX_RANGE_OFFSET; i++) {
  888. if (rangeMap[i]) {
  889. bufferLength++;
  890. if (lastEntry) {
  891. //
  892. // This new byte belongs to the current range
  893. //
  894. newRange[rangeCount].wLen++;
  895. } else {
  896. //
  897. // Starting a new range
  898. //
  899. if (rangeCount == (PCMCIA_MAX_CONTEXT_ENTRIES - 1)) {
  900. break;
  901. }
  902. rangeCount++;
  903. newRange[rangeCount].wOffset = i;
  904. newRange[rangeCount].wLen = 1;
  905. }
  906. }
  907. lastEntry = rangeMap[i];
  908. }
  909. rangeCount++;
  910. pContext->Range = NULL;
  911. pContext->RangeCount = 0;
  912. if (rangeCount) {
  913. //
  914. // Length of data
  915. //
  916. rangeLength = rangeCount*sizeof(PCMCIA_CONTEXT_RANGE);
  917. pContext->Range = ExAllocatePool(NonPagedPool, rangeLength);
  918. if (pContext->Range != NULL) {
  919. RtlCopyMemory(pContext->Range, buffer, rangeLength);
  920. pContext->RangeCount = (ULONG)rangeCount;
  921. pContext->BufferLength = bufferLength;
  922. //
  923. // Find the length of the longest individual range
  924. //
  925. pContext->MaxLen = 0;
  926. for (i = 0; i < rangeCount; i++) {
  927. if (pContext->Range[i].wLen > pContext->MaxLen) {
  928. pContext->MaxLen = pContext->Range[i].wLen;
  929. }
  930. }
  931. } else {
  932. ASSERT(pContext->Range != NULL);
  933. }
  934. }
  935. }
  936. NTSTATUS
  937. PcmciaGetLegacyDetectedControllerType(
  938. IN PDEVICE_OBJECT Pdo,
  939. IN OUT PPCMCIA_CONTROLLER_TYPE ControllerType
  940. )
  941. /*++
  942. Routine Description:
  943. This routine returns the previously remembered controller type
  944. for the supplied pcmcia controller by poking in the registry
  945. at the appropriate places
  946. Arguments:
  947. Pdo - The Physical device object corresponding to the PCMCIA controller
  948. ControllerType - pointer to the object in which the controller type will
  949. be returned
  950. Return value:
  951. Status
  952. --*/
  953. {
  954. NTSTATUS status;
  955. OBJECT_ATTRIBUTES objectAttributes;
  956. UNICODE_STRING unicodeKeyName;
  957. HANDLE instanceHandle=NULL;
  958. HANDLE parametersHandle = NULL;
  959. RTL_QUERY_REGISTRY_TABLE queryTable[3];
  960. ULONG controllerType;
  961. ULONG invalid = 0xffffffff;
  962. PAGED_CODE();
  963. try {
  964. status = IoOpenDeviceRegistryKey(Pdo,
  965. PLUGPLAY_REGKEY_DEVICE,
  966. KEY_READ,
  967. &instanceHandle
  968. );
  969. if (!NT_SUCCESS(status)) {
  970. leave;
  971. }
  972. RtlInitUnicodeString(&unicodeKeyName, PCMCIA_REGISTRY_DETECTED_DEVICE_KEY);
  973. InitializeObjectAttributes(
  974. &objectAttributes,
  975. &unicodeKeyName,
  976. OBJ_CASE_INSENSITIVE,
  977. instanceHandle,
  978. NULL);
  979. status = ZwOpenKey(&parametersHandle,
  980. KEY_READ,
  981. &objectAttributes);
  982. if (!NT_SUCCESS(status)) {
  983. leave;
  984. }
  985. RtlZeroMemory(queryTable, sizeof(queryTable));
  986. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  987. queryTable[0].Name = L"ControllerType";
  988. queryTable[0].EntryContext = &controllerType;
  989. queryTable[0].DefaultType = REG_DWORD;
  990. queryTable[0].DefaultData = &invalid;
  991. queryTable[0].DefaultLength = sizeof(ULONG);
  992. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  993. (PWSTR) parametersHandle,
  994. queryTable,
  995. NULL,
  996. NULL);
  997. if (!NT_SUCCESS(status)) {
  998. leave;
  999. }
  1000. if (controllerType == invalid) {
  1001. *ControllerType = PcmciaIntelCompatible;
  1002. } else {
  1003. *ControllerType = (PCMCIA_CONTROLLER_TYPE) controllerType;
  1004. }
  1005. } finally {
  1006. if (instanceHandle != NULL) {
  1007. ZwClose(instanceHandle);
  1008. }
  1009. if (parametersHandle != NULL) {
  1010. ZwClose(parametersHandle);
  1011. }
  1012. }
  1013. return status;
  1014. }
  1015. NTSTATUS
  1016. PcmciaSetLegacyDetectedControllerType(
  1017. IN PDEVICE_OBJECT Pdo,
  1018. IN PCMCIA_CONTROLLER_TYPE ControllerType
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. This routine 'remembers' - by setting a value in the registry -
  1023. the type of the pcmcia controller that has been legacy detected
  1024. to be retrieved and used in subsequent boots - if legacy re-detection
  1025. of the controller is not performed
  1026. Arguments:
  1027. Pdo - The Physical device object corresponding to the PCMCIA controller
  1028. DeviceExtension - Device extension of the fdo corresponding to the
  1029. controller
  1030. Return value:
  1031. Status
  1032. --*/
  1033. {
  1034. HANDLE instanceHandle;
  1035. NTSTATUS status;
  1036. OBJECT_ATTRIBUTES objectAttributes;
  1037. HANDLE parametersHandle;
  1038. UNICODE_STRING unicodeString;
  1039. PAGED_CODE();
  1040. //
  1041. // Get a handle to the registry devnode for this pdo
  1042. //
  1043. status = IoOpenDeviceRegistryKey(Pdo,
  1044. PLUGPLAY_REGKEY_DEVICE,
  1045. KEY_CREATE_SUB_KEY,
  1046. &instanceHandle);
  1047. if (!NT_SUCCESS(status)) {
  1048. return status;
  1049. }
  1050. //
  1051. // Open or create a sub-key for this devnode to store
  1052. // the information in
  1053. //
  1054. RtlInitUnicodeString(&unicodeString, PCMCIA_REGISTRY_DETECTED_DEVICE_KEY);
  1055. InitializeObjectAttributes(&objectAttributes,
  1056. &unicodeString,
  1057. OBJ_CASE_INSENSITIVE,
  1058. instanceHandle,
  1059. NULL);
  1060. status = ZwCreateKey(&parametersHandle,
  1061. KEY_SET_VALUE,
  1062. &objectAttributes,
  1063. 0,
  1064. NULL,
  1065. REG_OPTION_NON_VOLATILE,
  1066. NULL);
  1067. if (!NT_SUCCESS(status)) {
  1068. ZwClose(instanceHandle);
  1069. return status;
  1070. }
  1071. //
  1072. // Set the controller type value in the registry
  1073. //
  1074. RtlInitUnicodeString(&unicodeString, L"ControllerType");
  1075. status = ZwSetValueKey(parametersHandle,
  1076. &unicodeString,
  1077. 0,
  1078. REG_DWORD,
  1079. &ControllerType,
  1080. sizeof(ControllerType));
  1081. ZwClose(parametersHandle);
  1082. ZwClose(instanceHandle);
  1083. return status;
  1084. }