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.

1430 lines
41 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 pPcCardData = (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 = *pPcCardData;
  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 (initUsePolledCsc) {
  495. PcmciaGlobalFlags |= PCMCIA_GLOBAL_FORCE_POLL_MODE;
  496. }
  497. if (initDisableAcpiNameSpaceCheck) {
  498. PcmciaGlobalFlags |= PCMCIA_DISABLE_ACPI_NAMESPACE_CHECK;
  499. }
  500. if (initDefaultRouteR2ToIsa) {
  501. PcmciaGlobalFlags |= PCMCIA_DEFAULT_ROUTE_R2_TO_ISA;
  502. }
  503. if (EventDpcDelay > PCMCIA_MAX_EVENT_DPC_DELAY) {
  504. EventDpcDelay = PCMCIA_MAX_EVENT_DPC_DELAY;
  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->AttributeMemoryLow = globalAttributeMemoryLow;
  624. FdoExtension->AttributeMemoryHigh = globalAttributeMemoryHigh;
  625. if (FdoExtension->ControllerType == PcmciaDatabook) {
  626. FdoExtension->AttributeMemoryAlignment = TCIC_WINDOW_ALIGNMENT;
  627. } else {
  628. FdoExtension->AttributeMemoryAlignment = PCIC_WINDOW_ALIGNMENT;
  629. }
  630. //
  631. // Assign default attribute memory window size
  632. //
  633. if (globalAttributeMemorySize == 0) {
  634. switch (FdoExtension->ControllerType) {
  635. case PcmciaDatabook:
  636. FdoExtension->AttributeMemorySize = TCIC_WINDOW_SIZE;
  637. break;
  638. default:
  639. FdoExtension->AttributeMemorySize = PCIC_WINDOW_SIZE;
  640. break;
  641. }
  642. } else {
  643. FdoExtension->AttributeMemorySize = globalAttributeMemorySize;
  644. }
  645. //
  646. // See if the user asked for some special IRQ routing considerations based
  647. // on controller type
  648. //
  649. if (CardBusExtension(FdoExtension)) {
  650. //
  651. // route to PCI based on controller type
  652. //
  653. if (pcmciaIrqRouteToPciController) {
  654. ULONG ctlr = pcmciaIrqRouteToPciController;
  655. //
  656. // Check for exact match, or class if only a class was specified
  657. //
  658. if ((ctlr == FdoExtension->ControllerType) ||
  659. ((PcmciaClassFromControllerType(ctlr) == ctlr) && (ctlr == PcmciaClassFromControllerType(FdoExtension->ControllerType)))) {
  660. SetFdoFlag(FdoExtension, PCMCIA_FDO_PREFER_PCI_ROUTING);
  661. }
  662. }
  663. //
  664. // route to ISA based on controller type
  665. //
  666. if (pcmciaIrqRouteToIsaController) {
  667. ULONG ctlr = pcmciaIrqRouteToIsaController;
  668. //
  669. // Check for exact match, or class if only a class was specified
  670. //
  671. if ((ctlr == FdoExtension->ControllerType) ||
  672. ((PcmciaClassFromControllerType(ctlr) == ctlr) && (ctlr == PcmciaClassFromControllerType(FdoExtension->ControllerType)))) {
  673. SetFdoFlag(FdoExtension, PCMCIA_FDO_PREFER_ISA_ROUTING);
  674. }
  675. }
  676. //
  677. // route to PCI based on controller location
  678. //
  679. if (pcmciaIrqRouteToPciLocation) {
  680. ULONG loc = pcmciaIrqRouteToPciLocation;
  681. if ( ((loc & 0xff) == FdoExtension->PciBusNumber) &&
  682. (((loc >> 8) & 0xff) == FdoExtension->PciDeviceNumber)) {
  683. SetFdoFlag(FdoExtension, PCMCIA_FDO_FORCE_PCI_ROUTING);
  684. }
  685. }
  686. //
  687. // route to ISA based on controller location
  688. //
  689. if (pcmciaIrqRouteToIsaLocation) {
  690. ULONG loc = pcmciaIrqRouteToIsaLocation;
  691. if ( ((loc & 0xff) == FdoExtension->PciBusNumber) &&
  692. (((loc >> 8) & 0xff) == FdoExtension->PciDeviceNumber)) {
  693. SetFdoFlag(FdoExtension, PCMCIA_FDO_FORCE_ISA_ROUTING);
  694. }
  695. }
  696. }
  697. return status;
  698. }
  699. VOID
  700. PcmciaGetRegistryFdoIrqMask(
  701. IN OUT PFDO_EXTENSION FdoExtension
  702. )
  703. /*++
  704. Routine Description:
  705. This routine fills in the field "AllocatedIrqMask" in the specified
  706. fdo extension.
  707. Arguments:
  708. instanceHandle - open registry key for this controller
  709. pIrqMask - pointer to variable to receive irq mask
  710. Return value:
  711. none
  712. --*/
  713. {
  714. ULONG irqMask, cachedIrqMask = 0;
  715. UNICODE_STRING KeyName;
  716. NTSTATUS status;
  717. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  718. PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  719. ULONG length;
  720. HANDLE instanceHandle;
  721. ULONG detectedIrqMask;
  722. PAGED_CODE();
  723. if (globalOverrideIrqMask) {
  724. irqMask = globalOverrideIrqMask;
  725. } else {
  726. detectedIrqMask = PcmciaGetDetectedFdoIrqMask(FdoExtension);
  727. status = STATUS_UNSUCCESSFUL;
  728. if (FdoExtension->Pdo) {
  729. status = IoOpenDeviceRegistryKey(FdoExtension->Pdo,
  730. PLUGPLAY_REGKEY_DRIVER,
  731. KEY_READ,
  732. &instanceHandle
  733. );
  734. }
  735. if (NT_SUCCESS(status)) {
  736. //
  737. // Here we cache the value, and accumulate bits so that
  738. // our mask improves with time.
  739. //
  740. RtlInitUnicodeString(&KeyName, PCMCIA_REGISTRY_CACHED_IRQMASK);
  741. if (pcmciaIsaIrqRescanComplete) {
  742. status = ZwQueryValueKey(instanceHandle,
  743. &KeyName,
  744. KeyValuePartialInformation,
  745. value,
  746. sizeof(buffer),
  747. &length);
  748. if (NT_SUCCESS(status)) {
  749. cachedIrqMask = *(PULONG)(value->Data);
  750. }
  751. }
  752. irqMask = detectedIrqMask | cachedIrqMask;
  753. if ((cachedIrqMask != irqMask) || !pcmciaIsaIrqRescanComplete) {
  754. //
  755. // something changed, update the cached value
  756. //
  757. ZwSetValueKey(instanceHandle, &KeyName, 0, REG_DWORD, &irqMask, sizeof(irqMask));
  758. }
  759. ZwClose(instanceHandle);
  760. } else {
  761. //
  762. // Hmmm, no key. Can't cache the value
  763. //
  764. irqMask = detectedIrqMask;
  765. }
  766. if (pcmciaDisableIsaPciRouting && (PcmciaCountOnes(irqMask) < 2)) {
  767. //
  768. // Perhaps irq detection is broken... fall back on old NT4 behavior
  769. //
  770. irqMask = 0;
  771. }
  772. }
  773. irqMask &= ~globalFilterIrqMask;
  774. DebugPrint((PCMCIA_DEBUG_INFO, "IrqMask %08x (ovr %08x, flt %08x, det %08x, cache %08x)\n",
  775. irqMask, globalOverrideIrqMask, globalFilterIrqMask, detectedIrqMask, cachedIrqMask));
  776. FdoExtension->DetectedIrqMask = (USHORT)irqMask;
  777. }
  778. VOID
  779. PcmciaGetRegistryContextRange(
  780. IN HANDLE instanceHandle,
  781. IN PCWSTR Name,
  782. IN OPTIONAL const PCMCIA_CONTEXT_RANGE IncludeRange[],
  783. IN OPTIONAL const PCMCIA_CONTEXT_RANGE ExcludeRange[],
  784. OUT PPCMCIA_CONTEXT pContext
  785. )
  786. /*++
  787. Routine Description:
  788. This routine returns a buffer containing the contents of the
  789. data which set by the controller's inf definition (AddReg). The value
  790. is in CurrentControlSet\Control\Class\{GUID}\{Instance}.
  791. Arguments:
  792. FdoExtension - The fdo extension corresponding to the PCMCIA controller
  793. Name - The name of the value in the registry
  794. IncludeRange - defines areas in the range that must be included
  795. ExcludeRange - defines areas in the range that must be excluded
  796. Return value:
  797. Status
  798. --*/
  799. {
  800. #define PCMCIA_MAX_CONTEXT_ENTRIES 128
  801. #define MAX_RANGE_OFFSET 256
  802. NTSTATUS status;
  803. UNICODE_STRING unicodeKeyName;
  804. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
  805. PCMCIA_MAX_CONTEXT_ENTRIES*sizeof(PCMCIA_CONTEXT_RANGE)];
  806. PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  807. UCHAR rangeMap[MAX_RANGE_OFFSET] = {0};
  808. PPCMCIA_CONTEXT_RANGE newRange;
  809. LONG rangeCount;
  810. ULONG rangeLength;
  811. ULONG bufferLength;
  812. UCHAR lastEntry;
  813. ULONG keyLength;
  814. USHORT i, j;
  815. USHORT startOffset, endOffset;
  816. PAGED_CODE();
  817. //
  818. // Initialize the range map with the minimum range
  819. //
  820. if (IncludeRange) {
  821. for (i = 0; IncludeRange[i].wLen != 0; i++) {
  822. startOffset = IncludeRange[i].wOffset;
  823. endOffset = IncludeRange[i].wOffset + IncludeRange[i].wLen - 1;
  824. if ((startOffset >= MAX_RANGE_OFFSET) ||
  825. (endOffset >= MAX_RANGE_OFFSET)) {
  826. continue;
  827. }
  828. for (j = startOffset; j <= endOffset; j++) {
  829. rangeMap[j] = 0xff;
  830. }
  831. }
  832. }
  833. if (instanceHandle) {
  834. RtlInitUnicodeString(&unicodeKeyName, Name);
  835. status = ZwQueryValueKey(instanceHandle,
  836. &unicodeKeyName,
  837. KeyValuePartialInformation,
  838. value,
  839. sizeof(buffer),
  840. &keyLength);
  841. if (NT_SUCCESS(status)) {
  842. //
  843. // Merge in the range specified in the registry
  844. //
  845. newRange = (PPCMCIA_CONTEXT_RANGE) value->Data;
  846. for (i = 0; i < value->DataLength/sizeof(PCMCIA_CONTEXT_RANGE); i++) {
  847. startOffset = newRange[i].wOffset;
  848. endOffset = newRange[i].wOffset + newRange[i].wLen - 1;
  849. if ((startOffset >= MAX_RANGE_OFFSET) ||
  850. (endOffset >= MAX_RANGE_OFFSET)) {
  851. continue;
  852. }
  853. for (j = startOffset; j <= endOffset; j++) {
  854. rangeMap[j] = 0xff;
  855. }
  856. }
  857. }
  858. }
  859. //
  860. // Filter out registers defined in the exclude range
  861. //
  862. if (ExcludeRange) {
  863. for (i = 0; ExcludeRange[i].wLen != 0; i++) {
  864. startOffset = ExcludeRange[i].wOffset;
  865. endOffset = ExcludeRange[i].wOffset + ExcludeRange[i].wLen - 1;
  866. if ((startOffset >= MAX_RANGE_OFFSET) ||
  867. (endOffset >= MAX_RANGE_OFFSET)) {
  868. continue;
  869. }
  870. for (j = startOffset; j <= endOffset; j++) {
  871. rangeMap[j] = 0;
  872. }
  873. }
  874. }
  875. //
  876. // Now build the resulting merged range in the buffer on the
  877. // stack, and figure out how big it is.
  878. //
  879. newRange = (PPCMCIA_CONTEXT_RANGE) buffer;
  880. rangeCount = -1;
  881. bufferLength = 0;
  882. lastEntry = 0;
  883. for (i = 0; i < MAX_RANGE_OFFSET; i++) {
  884. if (rangeMap[i]) {
  885. bufferLength++;
  886. if (lastEntry) {
  887. //
  888. // This new byte belongs to the current range
  889. //
  890. newRange[rangeCount].wLen++;
  891. } else {
  892. //
  893. // Starting a new range
  894. //
  895. if (rangeCount == (PCMCIA_MAX_CONTEXT_ENTRIES - 1)) {
  896. break;
  897. }
  898. rangeCount++;
  899. newRange[rangeCount].wOffset = i;
  900. newRange[rangeCount].wLen = 1;
  901. }
  902. }
  903. lastEntry = rangeMap[i];
  904. }
  905. rangeCount++;
  906. pContext->Range = NULL;
  907. pContext->RangeCount = 0;
  908. if (rangeCount) {
  909. //
  910. // Length of data
  911. //
  912. rangeLength = rangeCount*sizeof(PCMCIA_CONTEXT_RANGE);
  913. pContext->Range = ExAllocatePool(NonPagedPool, rangeLength);
  914. if (pContext->Range != NULL) {
  915. RtlCopyMemory(pContext->Range, buffer, rangeLength);
  916. pContext->RangeCount = (ULONG)rangeCount;
  917. pContext->BufferLength = bufferLength;
  918. //
  919. // Find the length of the longest individual range
  920. //
  921. pContext->MaxLen = 0;
  922. for (i = 0; i < rangeCount; i++) {
  923. if (pContext->Range[i].wLen > pContext->MaxLen) {
  924. pContext->MaxLen = pContext->Range[i].wLen;
  925. }
  926. }
  927. } else {
  928. ASSERT(pContext->Range != NULL);
  929. }
  930. }
  931. }
  932. NTSTATUS
  933. PcmciaGetLegacyDetectedControllerType(
  934. IN PDEVICE_OBJECT Pdo,
  935. IN OUT PPCMCIA_CONTROLLER_TYPE ControllerType
  936. )
  937. /*++
  938. Routine Description:
  939. This routine returns the previously remembered controller type
  940. for the supplied pcmcia controller by poking in the registry
  941. at the appropriate places
  942. Arguments:
  943. Pdo - The Physical device object corresponding to the PCMCIA controller
  944. ControllerType - pointer to the object in which the controller type will
  945. be returned
  946. Return value:
  947. Status
  948. --*/
  949. {
  950. NTSTATUS status;
  951. OBJECT_ATTRIBUTES objectAttributes;
  952. UNICODE_STRING unicodeKeyName;
  953. HANDLE instanceHandle=NULL;
  954. HANDLE parametersHandle = NULL;
  955. RTL_QUERY_REGISTRY_TABLE queryTable[3];
  956. ULONG controllerType;
  957. ULONG invalid = 0xffffffff;
  958. PAGED_CODE();
  959. try {
  960. status = IoOpenDeviceRegistryKey(Pdo,
  961. PLUGPLAY_REGKEY_DEVICE,
  962. KEY_READ,
  963. &instanceHandle
  964. );
  965. if (!NT_SUCCESS(status)) {
  966. leave;
  967. }
  968. RtlInitUnicodeString(&unicodeKeyName, PCMCIA_REGISTRY_DETECTED_DEVICE_KEY);
  969. InitializeObjectAttributes(
  970. &objectAttributes,
  971. &unicodeKeyName,
  972. OBJ_CASE_INSENSITIVE,
  973. instanceHandle,
  974. NULL);
  975. status = ZwOpenKey(&parametersHandle,
  976. KEY_READ,
  977. &objectAttributes);
  978. if (!NT_SUCCESS(status)) {
  979. leave;
  980. }
  981. RtlZeroMemory(queryTable, sizeof(queryTable));
  982. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  983. queryTable[0].Name = L"ControllerType";
  984. queryTable[0].EntryContext = &controllerType;
  985. queryTable[0].DefaultType = REG_DWORD;
  986. queryTable[0].DefaultData = &invalid;
  987. queryTable[0].DefaultLength = sizeof(ULONG);
  988. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  989. (PWSTR) parametersHandle,
  990. queryTable,
  991. NULL,
  992. NULL);
  993. if (!NT_SUCCESS(status)) {
  994. leave;
  995. }
  996. if (controllerType == invalid) {
  997. *ControllerType = PcmciaIntelCompatible;
  998. } else {
  999. *ControllerType = (PCMCIA_CONTROLLER_TYPE) controllerType;
  1000. }
  1001. } finally {
  1002. if (instanceHandle != NULL) {
  1003. ZwClose(instanceHandle);
  1004. }
  1005. if (parametersHandle != NULL) {
  1006. ZwClose(parametersHandle);
  1007. }
  1008. }
  1009. return status;
  1010. }
  1011. NTSTATUS
  1012. PcmciaSetLegacyDetectedControllerType(
  1013. IN PDEVICE_OBJECT Pdo,
  1014. IN PCMCIA_CONTROLLER_TYPE ControllerType
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. This routine 'remembers' - by setting a value in the registry -
  1019. the type of the pcmcia controller that has been legacy detected
  1020. to be retrieved and used in subsequent boots - if legacy re-detection
  1021. of the controller is not performed
  1022. Arguments:
  1023. Pdo - The Physical device object corresponding to the PCMCIA controller
  1024. DeviceExtension - Device extension of the fdo corresponding to the
  1025. controller
  1026. Return value:
  1027. Status
  1028. --*/
  1029. {
  1030. HANDLE instanceHandle;
  1031. NTSTATUS status;
  1032. OBJECT_ATTRIBUTES objectAttributes;
  1033. HANDLE parametersHandle;
  1034. UNICODE_STRING unicodeString;
  1035. PAGED_CODE();
  1036. //
  1037. // Get a handle to the registry devnode for this pdo
  1038. //
  1039. status = IoOpenDeviceRegistryKey(Pdo,
  1040. PLUGPLAY_REGKEY_DEVICE,
  1041. KEY_CREATE_SUB_KEY,
  1042. &instanceHandle);
  1043. if (!NT_SUCCESS(status)) {
  1044. return status;
  1045. }
  1046. //
  1047. // Open or create a sub-key for this devnode to store
  1048. // the information in
  1049. //
  1050. RtlInitUnicodeString(&unicodeString, PCMCIA_REGISTRY_DETECTED_DEVICE_KEY);
  1051. InitializeObjectAttributes(&objectAttributes,
  1052. &unicodeString,
  1053. OBJ_CASE_INSENSITIVE,
  1054. instanceHandle,
  1055. NULL);
  1056. status = ZwCreateKey(&parametersHandle,
  1057. KEY_SET_VALUE,
  1058. &objectAttributes,
  1059. 0,
  1060. NULL,
  1061. REG_OPTION_NON_VOLATILE,
  1062. NULL);
  1063. if (!NT_SUCCESS(status)) {
  1064. ZwClose(instanceHandle);
  1065. return status;
  1066. }
  1067. //
  1068. // Set the controller type value in the registry
  1069. //
  1070. RtlInitUnicodeString(&unicodeString, L"ControllerType");
  1071. status = ZwSetValueKey(parametersHandle,
  1072. &unicodeString,
  1073. 0,
  1074. REG_DWORD,
  1075. &ControllerType,
  1076. sizeof(ControllerType));
  1077. ZwClose(parametersHandle);
  1078. ZwClose(instanceHandle);
  1079. return status;
  1080. }