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.

2964 lines
94 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. pdopnp.c
  5. Abstract:
  6. This module contains the code to handle
  7. the IRP_MJ_PNP dispatches for the PDOs
  8. enumerated by the PCMCIA bus driver
  9. Authors:
  10. Ravisankar Pudipeddi (ravisp)
  11. Neil Sandlin (neilsa) 1-Jun-1999
  12. Environment:
  13. Kernel mode only
  14. Notes:
  15. Revision History:
  16. --*/
  17. #include "pch.h"
  18. //
  19. // Internal References
  20. //
  21. NTSTATUS
  22. PcmciaFilterPcCardResourceRequirements(
  23. IN PPDO_EXTENSION DeviceExtension,
  24. IN PIRP Irp
  25. );
  26. NTSTATUS
  27. PcmciaFilterPcCardInterrupts(
  28. IN PIO_RESOURCE_REQUIREMENTS_LIST oldReqList,
  29. IN ULONG IrqCount,
  30. IN ULONG IrqMask,
  31. OUT PIO_RESOURCE_REQUIREMENTS_LIST * FilteredReqList,
  32. BOOLEAN RouteIsaToPci
  33. );
  34. VOID
  35. PcmciaCleanupSocketData(
  36. IN PSOCKET_DATA SocketData
  37. );
  38. VOID
  39. PcmciaCleanupSocketConfiguration(
  40. PPDO_EXTENSION pdoExtension
  41. );
  42. NTSTATUS
  43. PcmciaPdoDeviceCapabilities(
  44. IN PDEVICE_OBJECT Pdo,
  45. IN PIRP Irp
  46. );
  47. NTSTATUS
  48. PcmciaGetPcCardResourceRequirements(
  49. IN PPDO_EXTENSION PdoExtension,
  50. PULONG_PTR Information
  51. );
  52. NTSTATUS
  53. PcmciaConfigEntriesToResourceListChain(
  54. PPDO_EXTENSION pdoExtension,
  55. PCONFIG_LIST ConfigList,
  56. ULONG configCount,
  57. PPCMCIA_RESOURCE_CHAIN *ResListChainHead
  58. );
  59. NTSTATUS
  60. PcmciaMergeResourceChainToList(
  61. PPCMCIA_RESOURCE_CHAIN ResListChain,
  62. PIO_RESOURCE_REQUIREMENTS_LIST *GeneratedResourceRequirementsList
  63. );
  64. VOID
  65. PcmciaFreeResourceChain(
  66. PPCMCIA_RESOURCE_CHAIN ResListChain
  67. );
  68. NTSTATUS
  69. PcmciaStartPcCard(
  70. IN PDEVICE_OBJECT Pdo,
  71. IN PCM_RESOURCE_LIST AllocatedResources,
  72. IN OUT PIRP Irp
  73. );
  74. NTSTATUS
  75. PcmciaStopPcCard(
  76. IN PDEVICE_OBJECT Pdo
  77. );
  78. NTSTATUS
  79. PcmciaRemovePcCard(
  80. IN PDEVICE_OBJECT Pdo,
  81. IN PIRP Irp
  82. );
  83. NTSTATUS
  84. PcmciaMfEnumerateConfigurations(
  85. IN PPDO_EXTENSION PdoExtension,
  86. IN PSOCKET_DATA socketData,
  87. PCONFIG_LIST ConfigList,
  88. IN ULONG Depth,
  89. PPCMCIA_RESOURCE_CHAIN *MfResListChain
  90. );
  91. NTSTATUS
  92. PcmciaMfGetResourceRequirements(
  93. IN PPDO_EXTENSION PdoExtension,
  94. PULONG_PTR Information
  95. );
  96. VOID
  97. PcmciaMfBuildResourceMapInfo(
  98. IN PPDO_EXTENSION PdoExtension,
  99. PCONFIG_LIST ConfigList,
  100. ULONG ConfigCount
  101. );
  102. BOOLEAN
  103. PcmciaMfCheckForOverlappingRanges(
  104. PCONFIG_LIST ConfigList,
  105. LONG ConfigCount
  106. );
  107. NTSTATUS
  108. PcmciaPdoGetBusInformation(
  109. IN PPDO_EXTENSION PdoExtension,
  110. OUT PPNP_BUS_INFORMATION * BusInformation
  111. );
  112. NTSTATUS
  113. PcmciaQueryDeviceText(
  114. IN PDEVICE_OBJECT Pdo,
  115. IN OUT PIRP Irp
  116. );
  117. VOID
  118. PcmciaPdoGetDeviceInfSettings(
  119. IN PPDO_EXTENSION PdoExtension
  120. );
  121. VOID
  122. PcmciaPdoSetDeviceIrqRouting(
  123. IN PPDO_EXTENSION PdoExtension
  124. );
  125. #ifdef ALLOC_PRAGMA
  126. #pragma alloc_text(PAGE, PcmciaPdoPnpDispatch)
  127. #pragma alloc_text(PAGE, PcmciaPdoGetDeviceInfSettings)
  128. #pragma alloc_text(PAGE, PcmciaPdoSetDeviceIrqRouting)
  129. #pragma alloc_text(PAGE, PcmciaFilterPcCardInterrupts)
  130. #pragma alloc_text(PAGE, PcmciaFilterPcCardResourceRequirements)
  131. #pragma alloc_text(PAGE, PcmciaQueryDeviceText)
  132. #pragma alloc_text(PAGE, PcmciaGetPcCardResourceRequirements)
  133. #pragma alloc_text(PAGE, PcmciaConfigEntriesToResourceListChain)
  134. #pragma alloc_text(PAGE, PcmciaMergeResourceChainToList)
  135. #pragma alloc_text(PAGE, PcmciaFreeResourceChain)
  136. #pragma alloc_text(PAGE, PcmciaPdoGetBusInformation)
  137. #pragma alloc_text(PAGE, PcmciaStartPcCard)
  138. #pragma alloc_text(PAGE, PcmciaStopPcCard)
  139. #pragma alloc_text(PAGE, PcmciaRemovePcCard)
  140. #pragma alloc_text(PAGE, PcmciaPdoDeviceCapabilities)
  141. #pragma alloc_text(PAGE, PcmciaPdoDeviceControl)
  142. #pragma alloc_text(PAGE, PcmciaPdoGetDeviceInfSettings)
  143. #pragma alloc_text(PAGE, PcmciaMfGetResourceRequirements)
  144. #pragma alloc_text(PAGE, PcmciaMfEnumerateConfigurations)
  145. #pragma alloc_text(PAGE, PcmciaMfBuildResourceMapInfo)
  146. #pragma alloc_text(PAGE, PcmciaMfCheckForOverlappingRanges)
  147. #endif
  148. NTSTATUS
  149. PcmciaPdoPnpDispatch(
  150. IN PDEVICE_OBJECT Pdo,
  151. IN PIRP Irp
  152. )
  153. /*++
  154. Routine Description:
  155. This routine handles pnp requests
  156. for the PDOs.
  157. Arguments:
  158. Pdo - pointer to the physical device object
  159. Irp - pointer to the io request packet
  160. Return Value:
  161. status
  162. --*/
  163. {
  164. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  165. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  166. NTSTATUS status;
  167. PAGED_CODE();
  168. //
  169. // CardBus PnP Dispatch
  170. //
  171. if (IsCardBusCard(pdoExtension)) { //
  172. return PcmciaPdoCardBusPnPDispatch(Pdo, Irp);
  173. }
  174. #if DBG
  175. if (irpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
  176. DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x Unknown minor function %x\n",
  177. Pdo, Irp, irpStack->MinorFunction));
  178. } else {
  179. DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x --> %s\n",
  180. Pdo, Irp, PNP_IRP_STRING(irpStack->MinorFunction)));
  181. }
  182. #endif
  183. //
  184. // 16-bit (R2) PcCard PnP Dispatch
  185. //
  186. switch (irpStack->MinorFunction) {
  187. case IRP_MN_START_DEVICE: {
  188. status = PcmciaStartPcCard(Pdo, irpStack->Parameters.StartDevice.AllocatedResources, Irp);
  189. PcmciaDoStartSound(pdoExtension->Socket, status);
  190. break;
  191. }
  192. case IRP_MN_QUERY_STOP_DEVICE:{
  193. status = STATUS_SUCCESS;
  194. break;
  195. }
  196. case IRP_MN_CANCEL_STOP_DEVICE:{
  197. status = STATUS_SUCCESS;
  198. break;
  199. }
  200. case IRP_MN_STOP_DEVICE: {
  201. status = PcmciaStopPcCard(Pdo);
  202. break;
  203. }
  204. case IRP_MN_QUERY_REMOVE_DEVICE:{
  205. status = STATUS_SUCCESS;
  206. break;
  207. }
  208. case IRP_MN_CANCEL_REMOVE_DEVICE:{
  209. status = STATUS_SUCCESS;
  210. break;
  211. }
  212. case IRP_MN_REMOVE_DEVICE: {
  213. status = PcmciaRemovePcCard(Pdo, Irp);
  214. break;
  215. }
  216. case IRP_MN_SURPRISE_REMOVAL: {
  217. PcmciaReleaseSocketPower(pdoExtension, NULL);
  218. status = STATUS_SUCCESS;
  219. break;
  220. }
  221. case IRP_MN_QUERY_ID: {
  222. UNICODE_STRING unicodeId;
  223. status = Irp->IoStatus.Status;
  224. RtlInitUnicodeString(&unicodeId, NULL);
  225. switch (irpStack->Parameters.QueryId.IdType) {
  226. case BusQueryDeviceID: {
  227. DebugPrint((PCMCIA_DEBUG_INFO, " Device Id for pdo %x\n", Pdo));
  228. status = PcmciaGetDeviceId(Pdo, PCMCIA_MULTIFUNCTION_PARENT, &unicodeId);
  229. if (NT_SUCCESS(status)) {
  230. Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
  231. }
  232. break;
  233. }
  234. case BusQueryInstanceID: {
  235. DebugPrint((PCMCIA_DEBUG_INFO, " Instance Id for pdo %x\n", Pdo));
  236. status = PcmciaGetInstanceId(Pdo, &unicodeId);
  237. if (NT_SUCCESS(status)) {
  238. Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
  239. }
  240. break;
  241. }
  242. case BusQueryHardwareIDs: {
  243. DebugPrint((PCMCIA_DEBUG_INFO, " Hardware Ids for pdo %x\n", Pdo));
  244. status = PcmciaGetHardwareIds(Pdo, PCMCIA_MULTIFUNCTION_PARENT, &unicodeId);
  245. if (NT_SUCCESS(status)) {
  246. Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
  247. }
  248. break;
  249. }
  250. case BusQueryCompatibleIDs: {
  251. DebugPrint((PCMCIA_DEBUG_INFO, " Compatible Ids for pdo %x\n", Pdo));
  252. status = PcmciaGetCompatibleIds( Pdo, PCMCIA_MULTIFUNCTION_PARENT, &unicodeId);
  253. if (NT_SUCCESS(status)) {
  254. Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
  255. }
  256. break;
  257. }
  258. }
  259. break;
  260. }
  261. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: {
  262. //
  263. // PcmciaGetPcCardResourceRequirements will
  264. // allocate storage for the resource requirements which will be released
  265. // by the OS.
  266. //
  267. Irp->IoStatus.Information = 0;
  268. PcmciaPdoGetDeviceInfSettings(pdoExtension);
  269. PcmciaPdoSetDeviceIrqRouting(pdoExtension);
  270. if (IsDeviceMultifunction(pdoExtension)) {
  271. status = PcmciaMfGetResourceRequirements(pdoExtension,
  272. &Irp->IoStatus.Information);
  273. } else {
  274. status = PcmciaGetPcCardResourceRequirements(pdoExtension,
  275. &Irp->IoStatus.Information);
  276. }
  277. break;
  278. }
  279. case IRP_MN_WRITE_CONFIG:
  280. case IRP_MN_READ_CONFIG: {
  281. PFDO_EXTENSION fdoExtension= pdoExtension->Socket->DeviceExtension;
  282. ULONG whichSpace;
  283. PVOID buffer;
  284. ULONG offset;
  285. ULONG length;
  286. whichSpace = irpStack->Parameters.ReadWriteConfig.WhichSpace;
  287. buffer = irpStack->Parameters.ReadWriteConfig.Buffer;
  288. offset = irpStack->Parameters.ReadWriteConfig.Offset;
  289. length = irpStack->Parameters.ReadWriteConfig.Length;
  290. if (irpStack->MinorFunction == IRP_MN_READ_CONFIG) {
  291. status = PcmciaReadWriteCardMemory(Pdo,
  292. whichSpace,
  293. buffer,
  294. offset,
  295. length,
  296. TRUE);
  297. } else {
  298. status = PcmciaReadWriteCardMemory(Pdo,
  299. whichSpace,
  300. buffer,
  301. offset,
  302. length,
  303. FALSE);
  304. }
  305. break;
  306. }
  307. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  308. PDEVICE_RELATIONS deviceRelations;
  309. if (irpStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) {
  310. status = Irp->IoStatus.Status;
  311. break;
  312. }
  313. deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
  314. if (deviceRelations == NULL) {
  315. DebugPrint((PCMCIA_DEBUG_FAIL,
  316. "PcmciaPdoPnpDispatch:unable to allocate memory for device relations\n"));
  317. status = STATUS_INSUFFICIENT_RESOURCES;
  318. break;
  319. }
  320. status = ObReferenceObjectByPointer(Pdo,
  321. 0,
  322. NULL,
  323. KernelMode);
  324. if (!NT_SUCCESS(status)) {
  325. ExFreePool(deviceRelations);
  326. break;
  327. }
  328. deviceRelations->Count = 1;
  329. deviceRelations->Objects[0] = Pdo;
  330. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  331. status = STATUS_SUCCESS;
  332. break;
  333. }
  334. case IRP_MN_QUERY_CAPABILITIES: {
  335. status = PcmciaPdoDeviceCapabilities(Pdo, Irp);
  336. break;
  337. }
  338. case IRP_MN_QUERY_INTERFACE: {
  339. status = PcmciaPdoQueryInterface(Pdo, Irp);
  340. //
  341. // QueryInterface completes the passed in Irp.
  342. // So just return immediately.
  343. //
  344. return status;
  345. }
  346. case IRP_MN_QUERY_DEVICE_TEXT: {
  347. status = PcmciaQueryDeviceText(Pdo, Irp);
  348. if (status == STATUS_NOT_SUPPORTED ) {
  349. //
  350. // Do not change IRP status if this IRP is
  351. // not handled
  352. //
  353. status = Irp->IoStatus.Status;
  354. }
  355. break;
  356. }
  357. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: {
  358. status = PcmciaFilterPcCardResourceRequirements(pdoExtension, Irp);
  359. break;
  360. }
  361. case IRP_MN_QUERY_BUS_INFORMATION: {
  362. status = PcmciaPdoGetBusInformation(pdoExtension,
  363. (PPNP_BUS_INFORMATION *) &Irp->IoStatus.Information);
  364. break;
  365. }
  366. default: {
  367. //
  368. // Retain the status
  369. //
  370. DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x Skipping unsupported irp\n", Pdo, Irp));
  371. status = Irp->IoStatus.Status;
  372. break;
  373. }
  374. }
  375. Irp->IoStatus.Status = status;
  376. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  377. DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x comp %s %08x\n", Pdo, Irp,
  378. STATUS_STRING(status), status));
  379. return status;
  380. }
  381. NTSTATUS
  382. PcmciaPdoGetBusInformation(
  383. IN PPDO_EXTENSION PdoExtension,
  384. OUT PPNP_BUS_INFORMATION * BusInformation
  385. )
  386. /*++
  387. Routine Description:
  388. Returns the bus type information for the pc-card.
  389. Bus type is GUID_BUS_TYPE_PCMCIA(legacy type is PcmciaBus) for R2 cards
  390. Bus numbers are not implemented for PCMCIA, so it's always 0
  391. Arguments:
  392. PdoExtension - pointer to device extension for the pc-card
  393. BusInformation - pointer to the bus information structure that
  394. needs to be filled in
  395. Return value:
  396. Status
  397. --*/
  398. {
  399. PAGED_CODE();
  400. *BusInformation = ExAllocatePool(PagedPool, sizeof (PNP_BUS_INFORMATION));
  401. if (!*BusInformation) {
  402. return STATUS_INSUFFICIENT_RESOURCES;
  403. }
  404. RtlCopyMemory(&((*BusInformation)->BusTypeGuid),
  405. &GUID_BUS_TYPE_PCMCIA,
  406. sizeof(GUID));
  407. (*BusInformation)->LegacyBusType = PCMCIABus;
  408. (*BusInformation)->BusNumber = 0;
  409. return STATUS_SUCCESS;
  410. }
  411. VOID
  412. PcmciaPdoGetDeviceInfSettings(
  413. IN PPDO_EXTENSION PdoExtension
  414. )
  415. /*++
  416. Routine Description:
  417. This routine retrieves settings from the INF for this device.
  418. Arguments:
  419. DeviceExtension - Device extension of the Pc-Card
  420. Return value:
  421. None
  422. --*/
  423. {
  424. NTSTATUS status;
  425. PSOCKET socket = PdoExtension->Socket;
  426. UNICODE_STRING KeyName;
  427. HANDLE instanceHandle;
  428. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  429. PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  430. ULONG length;
  431. PAGED_CODE();
  432. status = IoOpenDeviceRegistryKey(PdoExtension->DeviceObject,
  433. PLUGPLAY_REGKEY_DRIVER,
  434. KEY_READ,
  435. &instanceHandle
  436. );
  437. if (NT_SUCCESS(status)) {
  438. //
  439. // Look to see if PcmciaExclusiveIrq is specified
  440. //
  441. RtlInitUnicodeString(&KeyName, L"PcmciaExclusiveIrq");
  442. status = ZwQueryValueKey(instanceHandle,
  443. &KeyName,
  444. KeyValuePartialInformation,
  445. value,
  446. sizeof(buffer),
  447. &length);
  448. //
  449. // If the key doesn't exist, or zero was specified, it means that
  450. // routing is ok
  451. //
  452. if (NT_SUCCESS(status) && (*(PULONG)(value->Data) != 0)) {
  453. SetDeviceFlag(PdoExtension, PCMCIA_PDO_EXCLUSIVE_IRQ);
  454. }
  455. //
  456. // Look to see if PcmciaAutoPowerOff is specified
  457. //
  458. RtlInitUnicodeString(&KeyName, L"PcmciaAutoPowerOff");
  459. status = ZwQueryValueKey(instanceHandle,
  460. &KeyName,
  461. KeyValuePartialInformation,
  462. value,
  463. sizeof(buffer),
  464. &length);
  465. //
  466. // If zero was specified, then don't automatically cut power on shutdown
  467. //
  468. if (NT_SUCCESS(status) && (*(PULONG)(value->Data) == 0)) {
  469. SetDeviceFlag(socket->DeviceExtension, PCMCIA_FDO_DISABLE_AUTO_POWEROFF);
  470. }
  471. //
  472. // Look to see if PcmciaEnableAudio is specified
  473. //
  474. RtlInitUnicodeString(&KeyName, L"PcmciaEnableAudio");
  475. status = ZwQueryValueKey(instanceHandle,
  476. &KeyName,
  477. KeyValuePartialInformation,
  478. value,
  479. sizeof(buffer),
  480. &length);
  481. //
  482. // If zero was specified, then don't automatically cut power on shutdown
  483. //
  484. if (NT_SUCCESS(status) && (*(PULONG)(value->Data) != 0)) {
  485. SetDeviceFlag(PdoExtension, PCMCIA_PDO_ENABLE_AUDIO);
  486. }
  487. ZwClose(instanceHandle);
  488. }
  489. }
  490. VOID
  491. PcmciaPdoSetDeviceIrqRouting(
  492. IN PPDO_EXTENSION PdoExtension
  493. )
  494. /*++
  495. Routine Description:
  496. This routine retrieves settings from the INF for this device.
  497. Notes:
  498. PcmciaExclusiveIrq in the INF determines how the IRQ for the R2 card will be routed.
  499. Currently, the following logic is used:
  500. if (routing disabled)
  501. choose either detected or legacy
  502. else
  503. if !detected, use FdoIrq
  504. So, if routing to PCI at all, then only the PCI IRQ will show up in the IoResList.
  505. BUT: Another approach would be to use the following logic:
  506. if (routing disabled)
  507. choose either detected or legacy
  508. else
  509. *merge detected with FdoIrq*
  510. This way we may end up using an exclusive IRQ or routing to PCI, depending on what
  511. the arbiter has decided. That is the reason why I kept both Detected and Legacy around
  512. in the FdoExtension, because otherwise it would have made more sense just to choose
  513. and merge them back when they were generated.
  514. Arguments:
  515. DeviceExtension - Device extension of the Pc-Card
  516. Return value:
  517. None (SOCKET structure is updated)
  518. --*/
  519. {
  520. NTSTATUS status;
  521. PSOCKET socket = PdoExtension->Socket;
  522. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  523. PAGED_CODE();
  524. ResetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
  525. //
  526. // First check the conditions that specify we definitely don't want to route to PCI
  527. //
  528. if (!pcmciaDisableIsaPciRouting &&
  529. CardBusExtension(fdoExtension) &&
  530. !IsDeviceFlagSet(PdoExtension, PCMCIA_PDO_EXCLUSIVE_IRQ)) {
  531. //
  532. // Here we know we *could* route to PCI, now determine if we *should*. This takes
  533. // into account several registry settings, as well as the result from the NtDetect
  534. // IRQ detection algorithm.
  535. //
  536. //
  537. // First check to see if there was an override with specifically targeted this
  538. // controller. This will take precedence.
  539. //
  540. if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_FORCE_PCI_ROUTING)) {
  541. SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
  542. }
  543. else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_FORCE_ISA_ROUTING)) {
  544. ResetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
  545. }
  546. //
  547. // Now check to see if the detection algorithm succeeded. We should honor this result,
  548. // particularly if the map was zero, which tells us there are no ISA IRQs attached.
  549. //
  550. else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_IRQ_DETECT_COMPLETED)) {
  551. if (fdoExtension->DetectedIrqMask == 0) {
  552. SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
  553. }
  554. }
  555. //
  556. // Now see if there was a general override based on this controller type. This has
  557. // less precedence than the detection algorithm.
  558. //
  559. else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_PREFER_PCI_ROUTING)) {
  560. SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
  561. }
  562. else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_PREFER_ISA_ROUTING)) {
  563. ResetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
  564. }
  565. //
  566. // Here look to see if the device was found, but the irq detection failed for some
  567. // reason. With no special registry overrides, we fall back on the global default.
  568. //
  569. else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_IRQ_DETECT_DEVICE_FOUND)) {
  570. if (!(PcmciaGlobalFlags & PCMCIA_DEFAULT_ROUTE_R2_TO_ISA)) {
  571. SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
  572. }
  573. }
  574. //
  575. // Here ntdetect never saw the device. Maybe we just hot-docked.
  576. // We will base our decision on if it was in ACPI namespace or not. If it
  577. // isn't in ACPI namespace, then it probably is not connected to ISA
  578. //
  579. else {
  580. if (!IsFdoFlagSet(fdoExtension, PCMCIA_FDO_IN_ACPI_NAMESPACE)) {
  581. SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
  582. }
  583. }
  584. }
  585. socket->IrqMask = fdoExtension->DetectedIrqMask ? fdoExtension->DetectedIrqMask : fdoExtension->LegacyIrqMask;
  586. DebugPrint((PCMCIA_DEBUG_RESOURCES, "pdo %08x IRQ routing=%s, IRQMask=%08x\n", PdoExtension->DeviceObject,
  587. IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI) ? "PCI" : "ISA",
  588. socket->IrqMask));
  589. }
  590. NTSTATUS
  591. PcmciaFilterPcCardInterrupts(
  592. IN PIO_RESOURCE_REQUIREMENTS_LIST oldReqList,
  593. IN ULONG IrqCount,
  594. IN ULONG IrqMask,
  595. OUT PIO_RESOURCE_REQUIREMENTS_LIST * FilteredReqList,
  596. BOOLEAN RouteIsaToPci
  597. )
  598. /*++
  599. Routine Description:
  600. Filters the interrupt resource requirements for R2 Pc-Cards
  601. Arguments:
  602. oldReqList - Original, 'raw' resource requirements list
  603. IrqCount - # of irq's that will be deleted (already computed by caller)
  604. IrqMask - bit mask which indicates which interrupts are valid
  605. FilteredReqList - pointer to the filtered requirements list which
  606. will be filled in by this routine
  607. Return value:
  608. Status
  609. --*/
  610. {
  611. PIO_RESOURCE_REQUIREMENTS_LIST newReqList;
  612. PIO_RESOURCE_LIST oldList, newList;
  613. ULONG newReqSize;
  614. ULONG oldlistSize, newlistSize;
  615. ULONG index, oldIndex, newIndex;
  616. BOOLEAN irqAlternative;
  617. PAGED_CODE();
  618. //
  619. // Compute the size of the structure with the offending IRQs removed.
  620. //
  621. newReqSize = oldReqList->ListSize - IrqCount*sizeof(IO_RESOURCE_DESCRIPTOR);
  622. newReqList = ExAllocatePool(PagedPool, newReqSize);
  623. if (newReqList == NULL) {
  624. return STATUS_INSUFFICIENT_RESOURCES;
  625. }
  626. RtlCopyMemory(newReqList, oldReqList, FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List));
  627. newReqList->ListSize = newReqSize;
  628. newList = newReqList->List;
  629. oldList = oldReqList->List;
  630. //
  631. // Loop through each alternative list
  632. //
  633. for (index = 0; index < oldReqList->AlternativeLists; index++) {
  634. newList->Version = oldList->Version;
  635. newList->Revision = oldList->Revision;
  636. irqAlternative = FALSE;
  637. //
  638. // Loop through each descriptor in the old list
  639. //
  640. for (oldIndex = 0, newIndex = 0; oldIndex < oldList->Count; oldIndex++) {
  641. if (oldList->Descriptors[oldIndex].Type == CmResourceTypeInterrupt) {
  642. if (RouteIsaToPci) {
  643. if (!irqAlternative) {
  644. //
  645. // First interrupt found, this will be the one we use to route
  646. //
  647. newList->Descriptors[newIndex++] = oldList->Descriptors[oldIndex];
  648. irqAlternative = TRUE;
  649. }
  650. } else {
  651. //
  652. // Normal case (not routed). Filter out irqs that aren't in our mask
  653. //
  654. if ((IrqMask & (1<<oldList->Descriptors[oldIndex].u.Interrupt.MinimumVector)) != 0) {
  655. //
  656. // Not a bad interrupt descriptor. Copy the old to the new
  657. //
  658. newList->Descriptors[newIndex] = oldList->Descriptors[oldIndex];
  659. if (newList->Descriptors[newIndex].Type == CmResourceTypeInterrupt) {
  660. if (irqAlternative) {
  661. newList->Descriptors[newIndex].Option = IO_RESOURCE_ALTERNATIVE;
  662. } else {
  663. irqAlternative = TRUE;
  664. newList->Descriptors[newIndex].Option = 0;
  665. }
  666. }
  667. newIndex++;
  668. }
  669. }
  670. } else {
  671. //
  672. // Not an interrupt descriptor. Copy the old to the new
  673. //
  674. newList->Descriptors[newIndex++] = oldList->Descriptors[oldIndex];
  675. }
  676. }
  677. newList->Count = newIndex;
  678. oldlistSize = sizeof(IO_RESOURCE_LIST) + (oldList->Count-1) * sizeof(IO_RESOURCE_DESCRIPTOR);
  679. newlistSize = sizeof(IO_RESOURCE_LIST) + (newList->Count-1) * sizeof(IO_RESOURCE_DESCRIPTOR);
  680. oldList = (PIO_RESOURCE_LIST) (((PUCHAR) oldList) + oldlistSize);
  681. newList = (PIO_RESOURCE_LIST) (((PUCHAR) newList) + newlistSize);
  682. }
  683. *FilteredReqList = newReqList;
  684. return STATUS_SUCCESS;
  685. }
  686. NTSTATUS
  687. PcmciaFilterPcCardResourceRequirements(
  688. IN PPDO_EXTENSION DeviceExtension,
  689. IN PIRP Irp
  690. )
  691. /*++
  692. Routine Description:
  693. Filters the resource requirements for R2 Pc-Cards
  694. Arguments:
  695. DeviceExtension - Device extension of the Pc-Card
  696. Return value:
  697. Status
  698. --*/
  699. {
  700. PIO_RESOURCE_REQUIREMENTS_LIST IoReqList;
  701. PIO_RESOURCE_REQUIREMENTS_LIST newReqList;
  702. PIO_RESOURCE_LIST ioResourceList;
  703. PIO_RESOURCE_DESCRIPTOR ioResourceDesc;
  704. PSOCKET socket;
  705. PFDO_EXTENSION fdoExtension;
  706. ULONG index1, index2, len;
  707. ULONGLONG low, high;
  708. ULONG IrqsToDeleteCount = 0;
  709. NTSTATUS status = STATUS_SUCCESS;
  710. BOOLEAN RouteIrqFound;
  711. PAGED_CODE();
  712. IoReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->IoStatus.Information;
  713. if (IoReqList == NULL) {
  714. return STATUS_SUCCESS;
  715. }
  716. socket = DeviceExtension->Socket;
  717. fdoExtension = socket->DeviceExtension;
  718. for (index1 = 0, ioResourceList = IoReqList->List;
  719. index1 < IoReqList->AlternativeLists; index1++) {
  720. ioResourceDesc = ioResourceList->Descriptors;
  721. RouteIrqFound = FALSE;
  722. for (index2 = 0 ; index2 < ioResourceList->Count; index2++, ioResourceDesc++) {
  723. if (ioResourceDesc->Type == CmResourceTypeInterrupt) {
  724. if (IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI)) {
  725. //
  726. // make sure there is space for just 1 level interrupt requirement
  727. //
  728. if (!RouteIrqFound) {
  729. RouteIrqFound = TRUE;
  730. ioResourceDesc->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  731. ioResourceDesc->Option = 0;
  732. ioResourceDesc->ShareDisposition = CmResourceShareShared;
  733. ioResourceDesc->u.Interrupt.MinimumVector = socket->FdoIrq;
  734. ioResourceDesc->u.Interrupt.MaximumVector = socket->FdoIrq;
  735. } else {
  736. //
  737. // Don't need any other IRQs in this list
  738. //
  739. IrqsToDeleteCount++;
  740. }
  741. } else {
  742. ASSERT (ioResourceDesc->u.Interrupt.MinimumVector == ioResourceDesc->u.Interrupt.MaximumVector);
  743. //
  744. // Look to see if there are IRQ's specified in this IoResList which are
  745. // not in our mask. If so, we are going to have to create a new IoResList.
  746. // Keep track of how many
  747. if (!(socket->IrqMask & (1<<ioResourceDesc->u.Interrupt.MinimumVector))) {
  748. IrqsToDeleteCount++;
  749. }
  750. }
  751. } else if (ioResourceDesc->Type == CmResourceTypePort) {
  752. //
  753. // We might want to filter this..
  754. //
  755. low = ioResourceDesc->u.Port.MinimumAddress.QuadPart;
  756. high = ioResourceDesc->u.Port.MaximumAddress.QuadPart;
  757. len = ioResourceDesc->u.Port.Length;
  758. //
  759. // A set of messy rules to see if we should filter the requirements.
  760. //
  761. // We don't filter if:
  762. // 1. User requested number of ports which are more than
  763. // we can legally ask with our filtered high & low caps on the
  764. // requirements.
  765. // 2. User requested a 'fixed' resource requirement, i.e. a specific
  766. // set of ports of a specified length.
  767. // 3. User specified resource requirements range is smaller
  768. // than the range we would obtain if we filter it. We don't filter
  769. // in this case because the filtering is supposed to restrict the range
  770. // not expand it. If user thinks he can restrict better than us,
  771. // honor it .
  772. //
  773. //
  774. if (len > (fdoExtension->IoHigh - fdoExtension->IoLow + 1)) {
  775. //
  776. // Case 1. above.
  777. // Don't filter this.
  778. //
  779. continue;
  780. }
  781. if ((low + len -1) >= high) {
  782. //
  783. // Case 2.
  784. // This is a fixed requirement. Don't filter it
  785. //
  786. continue;
  787. }
  788. if (((ULONG)(high - low)) <= (fdoExtension->IoHigh - fdoExtension->IoLow)) {
  789. //
  790. // Case 3.
  791. // Don't filter this
  792. //
  793. continue;
  794. }
  795. if ((ULONG) low < fdoExtension->IoLow) {
  796. low = (ULONGLONG) fdoExtension->IoLow;
  797. }
  798. if ((ULONG) high > fdoExtension->IoHigh) {
  799. high = (ULONGLONG) fdoExtension->IoHigh;
  800. }
  801. ioResourceDesc->u.Port.MinimumAddress.QuadPart = low;
  802. ioResourceDesc->u.Port.MaximumAddress.QuadPart = high;
  803. } else if (ioResourceDesc->Type == CmResourceTypeMemory) {
  804. //
  805. // pccard hardware can't handle > 32bit addressing
  806. //
  807. ASSERT(ioResourceDesc->u.Memory.MinimumAddress.HighPart == 0);
  808. ioResourceDesc->u.Memory.MaximumAddress.HighPart = 0;
  809. if (fdoExtension->Flags & PCMCIA_MEMORY_24BIT) {
  810. ASSERT((ioResourceDesc->u.Memory.MinimumAddress.LowPart & 0xFF000000) == 0);
  811. ioResourceDesc->u.Memory.MaximumAddress.LowPart &= 0xFFFFFF;
  812. }
  813. //
  814. // win2k had a bug where o2micro controllers were marked as 24bit. When
  815. // that was fixed, an o2micro smart card device with an INF bug suddenly
  816. // stopped working (because the first bug masked the second). This code
  817. // fixes their INF.
  818. //
  819. if ((ioResourceDesc->Flags & CM_RESOURCE_MEMORY_24) &&
  820. (ioResourceDesc->u.Memory.MinimumAddress.LowPart > 0xFFFFFF) &&
  821. (PcmciaClassFromControllerType(fdoExtension->ControllerType) == PcmciaO2Micro)) {
  822. ioResourceDesc->u.Memory.MinimumAddress.LowPart &= 0xFFFFFF;
  823. }
  824. }
  825. }
  826. ioResourceList = (PIO_RESOURCE_LIST) (((PUCHAR) ioResourceList) +
  827. sizeof(IO_RESOURCE_LIST) +
  828. (ioResourceList->Count - 1)* sizeof(IO_RESOURCE_DESCRIPTOR));
  829. } // outer for loop
  830. if (IrqsToDeleteCount) {
  831. status = PcmciaFilterPcCardInterrupts(IoReqList,
  832. IrqsToDeleteCount,
  833. socket->IrqMask,
  834. &newReqList,
  835. IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI)
  836. );
  837. if (NT_SUCCESS(status)) {
  838. Irp->IoStatus.Information = (ULONG_PTR) newReqList;
  839. ExFreePool(IoReqList);
  840. }
  841. }
  842. return status;
  843. }
  844. NTSTATUS
  845. PcmciaQueryDeviceText(
  846. IN PDEVICE_OBJECT Pdo,
  847. IN OUT PIRP Irp
  848. )
  849. /*++
  850. Routine Description:
  851. Returns descriptive text information about the
  852. PDO (location and device desc.)
  853. Arguments:
  854. Pdo - Pointer to the PC-Card's device object
  855. Irp - IRP_MN_QUERY_DEVICE_TEXT Irp
  856. Return Value:
  857. STATUS_SUCCESS
  858. STATUS_NOT_SUPPORTED - if not supported
  859. --*/
  860. {
  861. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  862. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  863. UNICODE_STRING unicodeString;
  864. ANSI_STRING ansiString;
  865. UCHAR deviceText[128];
  866. NTSTATUS status;
  867. USHORT deviceTextLength;
  868. PSOCKET_DATA socketData = pdoExtension->SocketData;
  869. PAGED_CODE();
  870. if (irpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) {
  871. if (*(socketData->Mfg) == '\0' ) {
  872. if (socketData->Flags & SDF_JEDEC_ID) {
  873. sprintf(deviceText, "%s %s-%04x", PCMCIA_ID_STRING, PCMCIA_MEMORY_ID_STRING, socketData->JedecId);
  874. } else {
  875. sprintf(deviceText, "%s %s", PCMCIA_ID_STRING, PCMCIA_UNKNOWN_MANUFACTURER_STRING);
  876. }
  877. } else {
  878. sprintf(deviceText, "%s %s", socketData->Mfg, socketData->Ident);
  879. }
  880. RtlInitAnsiString(&ansiString, deviceText);
  881. deviceTextLength = (strlen(deviceText) + 1)*sizeof(WCHAR);
  882. unicodeString.Buffer = ExAllocatePool(PagedPool, deviceTextLength);
  883. if (unicodeString.Buffer == NULL) {
  884. return STATUS_INSUFFICIENT_RESOURCES;
  885. }
  886. unicodeString.MaximumLength = deviceTextLength;
  887. unicodeString.Length = 0;
  888. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
  889. if (!NT_SUCCESS(status)) {
  890. ExFreePool(unicodeString.Buffer);
  891. return status;
  892. }
  893. unicodeString.Buffer[unicodeString.Length/sizeof(WCHAR)] = L'\0';
  894. Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer;
  895. status = STATUS_SUCCESS;
  896. } else {
  897. status = STATUS_NOT_SUPPORTED ;
  898. }
  899. return status;
  900. }
  901. NTSTATUS
  902. PcmciaGetPcCardResourceRequirements(
  903. PPDO_EXTENSION pdoExtension,
  904. PULONG_PTR Information
  905. )
  906. /*++
  907. Routine Description:
  908. Fills in the resource requirements for the PC-Card obtained from the tuple information
  909. Arguments:
  910. PdoExtension - Pointer to the device extension for the PDO of the pc-card
  911. Information - Pointer to an allocated resource requirements list is stored in this
  912. argument. Caller's responsibility to free the list
  913. Return value:
  914. STATUS_INSUFFICIENT_RESOURCES Could not allocate the list
  915. STATUS_SUCCES Obtained resource requirements, Information contains the pointer
  916. to the IO_RESOURCE_REQUIREMENTS list
  917. --*/
  918. {
  919. NTSTATUS status;
  920. PPCMCIA_RESOURCE_CHAIN resListChain = NULL;
  921. PIO_RESOURCE_REQUIREMENTS_LIST ioResourceRequirementsList;
  922. PSOCKET socket = pdoExtension->Socket;
  923. PSOCKET_DATA socketData = pdoExtension->SocketData;
  924. PCONFIG_ENTRY currentConfigEntry;
  925. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  926. CONFIG_LIST configList;
  927. PAGED_CODE();
  928. ASSERT (!IsDeviceMultifunction(pdoExtension));
  929. //
  930. // Run through the config entry chains for IO space & Mem space requirements
  931. //
  932. configList.SocketData = socketData;
  933. for (currentConfigEntry=socketData->ConfigEntryChain; currentConfigEntry != NULL; currentConfigEntry=currentConfigEntry->NextEntry) {
  934. if (currentConfigEntry->Flags & PCMCIA_INVALID_CONFIGURATION) {
  935. continue;
  936. }
  937. configList.ConfigEntry = currentConfigEntry;
  938. status = PcmciaConfigEntriesToResourceListChain(pdoExtension,
  939. &configList,
  940. (ULONG)1,
  941. &resListChain
  942. );
  943. if (!NT_SUCCESS(status)) {
  944. return status;
  945. }
  946. }
  947. status = PcmciaMergeResourceChainToList(resListChain, &ioResourceRequirementsList);
  948. if (NT_SUCCESS(status) && (ioResourceRequirementsList != NULL)) {
  949. ioResourceRequirementsList->InterfaceType = Isa;
  950. ioResourceRequirementsList->BusNumber = fdoExtension->Configuration.BusNumber;
  951. ioResourceRequirementsList->SlotNumber = 0; // Need to revisit this..
  952. *Information = (ULONG_PTR) ioResourceRequirementsList;
  953. }
  954. PcmciaFreeResourceChain(resListChain);
  955. return status;
  956. }
  957. NTSTATUS
  958. PcmciaConfigEntriesToResourceListChain(
  959. PPDO_EXTENSION pdoExtension,
  960. PCONFIG_LIST ConfigList,
  961. ULONG configCount,
  962. PPCMCIA_RESOURCE_CHAIN *ResListChainHead
  963. )
  964. /*++
  965. Routine Description:
  966. Fills in the resource requirements for the PC-Card obtained from the tuple information
  967. Arguments:
  968. PdoExtension - Pointer to the device extension for the PDO of the pc-card
  969. Return value:
  970. STATUS_INSUFFICIENT_RESOURCES Could not allocate the list
  971. STATUS_SUCCES Obtained resource requirements, Information contains the pointer
  972. to the IO_RESOURCE_REQUIREMENTS list
  973. --*/
  974. {
  975. PSOCKET socket = pdoExtension->Socket;
  976. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  977. PCONFIG_ENTRY currentConfigEntry;
  978. PPCMCIA_RESOURCE_CHAIN resListChain;
  979. PIO_RESOURCE_LIST ioResourceList;
  980. PIO_RESOURCE_DESCRIPTOR ioResourceDesc;
  981. ULONG irqMask = 0, i, iConfig;
  982. ULONG totalDescriptorCount = 0;
  983. ULONG TotalIoRanges = 0;
  984. ULONG listSize;
  985. BOOLEAN IoRangeIs16Bit[MAX_NUMBER_OF_IO_RANGES] = {0};
  986. BOOLEAN irqAlternative;
  987. PAGED_CODE();
  988. DebugPrint((PCMCIA_DEBUG_RESOURCES, "pdo %08x build ioreslist from configlist %08x, config count=%d\n",
  989. pdoExtension->DeviceObject, ConfigList, configCount));
  990. //
  991. // Calculate how many descriptors we need. This involves also generating
  992. // the irqmask with the intersection of the irqmasks of the config entries
  993. // in the array.
  994. //
  995. for (iConfig = 0; iConfig < configCount; iConfig++) {
  996. currentConfigEntry = ConfigList[iConfig].ConfigEntry;
  997. irqMask |= currentConfigEntry->IrqMask;
  998. totalDescriptorCount += currentConfigEntry->NumberOfIoPortRanges;
  999. totalDescriptorCount += currentConfigEntry->NumberOfMemoryRanges;
  1000. }
  1001. if (irqMask) {
  1002. if (IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI)) {
  1003. totalDescriptorCount++;
  1004. } else {
  1005. totalDescriptorCount += PcmciaCountOnes(socket->IrqMask);
  1006. }
  1007. }
  1008. if (!totalDescriptorCount) {
  1009. return STATUS_SUCCESS;
  1010. }
  1011. //
  1012. // Add one more for our private DPTYPE_PCMCIA_CONFIGURATION
  1013. //
  1014. totalDescriptorCount++;
  1015. if (configCount > 1) {
  1016. //
  1017. // Add more for our private DPTYPE_PCMCIA_MF_CONFIGURATION
  1018. //
  1019. totalDescriptorCount+=configCount;
  1020. }
  1021. //
  1022. // Calculate the size of IO_RESOURCE_LIST, allocate and clear it
  1023. //
  1024. listSize = (totalDescriptorCount - 1) * sizeof(IO_RESOURCE_DESCRIPTOR)
  1025. + sizeof(IO_RESOURCE_LIST);
  1026. ioResourceList = ExAllocatePool(PagedPool, listSize);
  1027. if (ioResourceList == NULL) {
  1028. return STATUS_INSUFFICIENT_RESOURCES;
  1029. }
  1030. RtlZeroMemory(ioResourceList, listSize);
  1031. //
  1032. // Now that we have the resource list allocated, fill it in
  1033. //
  1034. ioResourceList->Version = IO_RESOURCE_LIST_VERSION;
  1035. ioResourceList->Revision = IO_RESOURCE_LIST_REVISION;
  1036. ioResourceList->Count = totalDescriptorCount;
  1037. ioResourceDesc = &ioResourceList->Descriptors[0];
  1038. //
  1039. // Fill in the IRQ info.
  1040. //
  1041. if (irqMask) {
  1042. if (IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI)) {
  1043. ioResourceDesc->Type = CmResourceTypeInterrupt;
  1044. ioResourceDesc->Option = 0;
  1045. ioResourceDesc->Flags = (USHORT)CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1046. ioResourceDesc->ShareDisposition = CmResourceShareShared;
  1047. ioResourceDesc->u.Interrupt.MinimumVector = socket->FdoIrq;
  1048. ioResourceDesc->u.Interrupt.MaximumVector = socket->FdoIrq;
  1049. ioResourceDesc++;
  1050. } else {
  1051. ULONG irqn;
  1052. irqMask = socket->IrqMask;
  1053. DebugPrint((PCMCIA_DEBUG_RESOURCES, "irq mask %04x\n", irqMask));
  1054. //
  1055. // For each IRQ supported, fill in a separate IO descriptor
  1056. //
  1057. irqAlternative = FALSE;
  1058. for (irqn = 0 ;irqMask; irqMask = (irqMask >> 1), irqn++) {
  1059. if (irqMask & 0x1) {
  1060. if (irqAlternative) {
  1061. ioResourceDesc->Option = IO_RESOURCE_ALTERNATIVE;
  1062. } else {
  1063. irqAlternative = TRUE;
  1064. ioResourceDesc->Option = 0;
  1065. }
  1066. ioResourceDesc->Type = CmResourceTypeInterrupt;
  1067. //
  1068. // This is for 16-bit pc-cards.. so request an edge-triggered
  1069. // exclusive interrupt
  1070. //
  1071. ioResourceDesc->Flags = (USHORT)CM_RESOURCE_INTERRUPT_LATCHED;
  1072. ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  1073. ioResourceDesc->u.Interrupt.MinimumVector =
  1074. ioResourceDesc->u.Interrupt.MaximumVector = irqn;
  1075. ioResourceDesc++;
  1076. }
  1077. }
  1078. }
  1079. }
  1080. for (iConfig = 0; iConfig < configCount; iConfig++) {
  1081. currentConfigEntry = ConfigList[iConfig].ConfigEntry;
  1082. //
  1083. // for each I/O range, fill in an IoResourceDescriptor
  1084. //
  1085. for (i = 0; i < currentConfigEntry->NumberOfIoPortRanges; i++) {
  1086. PHYSICAL_ADDRESS port;
  1087. ioResourceDesc->Option = 0;
  1088. ioResourceDesc->Type = CmResourceTypePort;
  1089. ioResourceDesc->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
  1090. ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  1091. if (currentConfigEntry->IoPortBase[i] == 0) {
  1092. //
  1093. // This is a flexible requirement. Basically means we need
  1094. // any system address range of specified length & alignment
  1095. //
  1096. port=RtlConvertUlongToLargeInteger(fdoExtension->IoLow);
  1097. ioResourceDesc->u.Port.MinimumAddress = port;
  1098. port=RtlConvertUlongToLargeInteger(fdoExtension->IoHigh);
  1099. ioResourceDesc->u.Port.MaximumAddress = port;
  1100. } else {
  1101. port = RtlConvertUlongToLargeInteger((ULONG) currentConfigEntry->IoPortBase[i]);
  1102. ioResourceDesc->u.Port.MinimumAddress = port;
  1103. port = RtlConvertUlongToLargeInteger((ULONG) (currentConfigEntry->IoPortBase[i]+
  1104. currentConfigEntry->IoPortLength[i]));
  1105. ioResourceDesc->u.Port.MaximumAddress = port;
  1106. }
  1107. ioResourceDesc->u.Port.Length = (ULONG) currentConfigEntry->IoPortLength[i]+1;
  1108. ioResourceDesc->u.Port.Alignment = currentConfigEntry->IoPortAlignment[i];
  1109. DebugPrint((PCMCIA_DEBUG_RESOURCES, "Port range: %08x-%08x, Length %04x\n",
  1110. ioResourceDesc->u.Port.MinimumAddress.LowPart,
  1111. ioResourceDesc->u.Port.MaximumAddress.LowPart,
  1112. ioResourceDesc->u.Port.Length
  1113. ));
  1114. if ((TotalIoRanges < MAX_NUMBER_OF_IO_RANGES) &&
  1115. (currentConfigEntry->Io16BitAccess)) {
  1116. IoRangeIs16Bit[TotalIoRanges] = TRUE;
  1117. }
  1118. TotalIoRanges++;
  1119. ioResourceDesc++;
  1120. }
  1121. }
  1122. for (iConfig = 0; iConfig < configCount; iConfig++) {
  1123. currentConfigEntry = ConfigList[iConfig].ConfigEntry;
  1124. //
  1125. // for each memory range, fill in an IoResourceDescriptor
  1126. //
  1127. for (i = 0; i < currentConfigEntry->NumberOfMemoryRanges; i++) {
  1128. PHYSICAL_ADDRESS mem;
  1129. ioResourceDesc->Option = 0;
  1130. ioResourceDesc->Type = CmResourceTypeMemory;
  1131. ioResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  1132. ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  1133. if (currentConfigEntry->MemoryHostBase[i]) {
  1134. mem = RtlConvertUlongToLargeInteger((ULONG) currentConfigEntry->MemoryHostBase[i]);
  1135. ioResourceDesc->u.Memory.MinimumAddress = mem;
  1136. mem = RtlConvertUlongToLargeInteger((ULONG) currentConfigEntry->MemoryHostBase[i]+
  1137. (ULONG) currentConfigEntry->MemoryLength[i]-1);
  1138. ioResourceDesc->u.Memory.MaximumAddress = mem;
  1139. } else {
  1140. //
  1141. // Any physical address is ok
  1142. //
  1143. mem = RtlConvertUlongToLargeInteger(0);
  1144. ioResourceDesc->u.Memory.MinimumAddress = mem;
  1145. //
  1146. // Only decode 24 bit memory addresses if there is no page register
  1147. //
  1148. if ((fdoExtension->Flags & PCMCIA_MEMORY_24BIT) == 0) {
  1149. mem = RtlConvertUlongToLargeInteger(0xFFFFFFFF);
  1150. } else {
  1151. mem = RtlConvertUlongToLargeInteger(0xFFFFFF);
  1152. }
  1153. ioResourceDesc->u.Memory.MaximumAddress = mem;
  1154. }
  1155. ioResourceDesc->u.Memory.Length = currentConfigEntry->MemoryLength[i];
  1156. //
  1157. // Alignment has to be 12 bits
  1158. //
  1159. ioResourceDesc->u.Memory.Alignment = 0x1000;
  1160. DebugPrint((PCMCIA_DEBUG_RESOURCES, "Mem range: %08x-%08x, Length %08x\n",
  1161. ioResourceDesc->u.Memory.MinimumAddress.LowPart,
  1162. ioResourceDesc->u.Memory.MaximumAddress.LowPart,
  1163. ioResourceDesc->u.Memory.Length
  1164. ));
  1165. ioResourceDesc++;
  1166. }
  1167. }
  1168. //
  1169. // Fill in device private containing our config index
  1170. //
  1171. ioResourceDesc->Option = 0;
  1172. ioResourceDesc->Type = CmResourceTypeDevicePrivate;
  1173. PCMRES_SET_DESCRIPTOR_TYPE(ioResourceDesc, DPTYPE_PCMCIA_CONFIGURATION);
  1174. currentConfigEntry = ConfigList[0].ConfigEntry;
  1175. PCMRES_SET_CONFIG_INDEX(ioResourceDesc, currentConfigEntry->IndexForThisConfiguration);
  1176. for (i = 0; i < MAX_NUMBER_OF_IO_RANGES; i++) {
  1177. if (IoRangeIs16Bit[i]) {
  1178. PCMRES_SET_IO_FLAG(ioResourceDesc, i, PCMRESF_IO_16BIT_ACCESS);
  1179. PCMRES_SET_IO_FLAG(ioResourceDesc, i, PCMRESF_IO_SOURCE_16);
  1180. PCMRES_SET_IO_FLAG(ioResourceDesc, i, PCMRESF_IO_WAIT_16);
  1181. }
  1182. }
  1183. PCMRES_SET_MEMORY_CARDBASE(ioResourceDesc, 0, currentConfigEntry->MemoryCardBase[0]);
  1184. PCMRES_SET_MEMORY_CARDBASE(ioResourceDesc, 1, currentConfigEntry->MemoryCardBase[1]);
  1185. //
  1186. // Set defaults
  1187. //
  1188. PCMRES_SET_MEMORY_WAITSTATES(ioResourceDesc, 0, PCMRESF_MEM_WAIT_3);
  1189. PCMRES_SET_MEMORY_WAITSTATES(ioResourceDesc, 1, PCMRESF_MEM_WAIT_3);
  1190. DebugPrint((PCMCIA_DEBUG_RESOURCES, "device private %08x %08x %08x\n",
  1191. ioResourceDesc->u.DevicePrivate.Data[0],
  1192. ioResourceDesc->u.DevicePrivate.Data[1],
  1193. ioResourceDesc->u.DevicePrivate.Data[2]
  1194. ));
  1195. ioResourceDesc++;
  1196. //
  1197. // Fill in device private for MF configurations
  1198. //
  1199. if (configCount > 1) {
  1200. for (iConfig = 0; iConfig < configCount; iConfig++) {
  1201. PSOCKET_DATA socketData;
  1202. currentConfigEntry = ConfigList[iConfig].ConfigEntry;
  1203. socketData = ConfigList[iConfig].SocketData;
  1204. ioResourceDesc->Option = 0;
  1205. ioResourceDesc->Type = CmResourceTypeDevicePrivate;
  1206. PCMRES_SET_DESCRIPTOR_TYPE(ioResourceDesc, DPTYPE_PCMCIA_MF_CONFIGURATION);
  1207. PCMRES_SET_CONFIG_OPTIONS(ioResourceDesc, currentConfigEntry->IndexForThisConfiguration);
  1208. PCMRES_SET_PORT_RESOURCE_INDEX(ioResourceDesc, socketData->MfIoPortResourceMapIndex);
  1209. if (socketData->DeviceType == PCCARD_TYPE_MODEM) {
  1210. PCMRES_SET_AUDIO_ENABLE(ioResourceDesc);
  1211. }
  1212. PCMRES_SET_CONFIG_REGISTER_BASE(ioResourceDesc, socketData->ConfigRegisterBase);
  1213. DebugPrint((PCMCIA_DEBUG_RESOURCES, "device private MF %08x %08x %08x\n",
  1214. ioResourceDesc->u.DevicePrivate.Data[0],
  1215. ioResourceDesc->u.DevicePrivate.Data[1],
  1216. ioResourceDesc->u.DevicePrivate.Data[2]
  1217. ));
  1218. ioResourceDesc++;
  1219. }
  1220. }
  1221. ASSERT(ioResourceDesc == &ioResourceList->Descriptors[ioResourceList->Count]);
  1222. //
  1223. // Allocate an PCMCIA_RESOURCE_CHAIN structure to track the IO_RESOURCE_LIST.
  1224. //
  1225. resListChain = ExAllocatePool(PagedPool, sizeof(PCMCIA_RESOURCE_CHAIN));
  1226. if (resListChain == NULL) {
  1227. ExFreePool(ioResourceList);
  1228. return STATUS_INSUFFICIENT_RESOURCES;
  1229. }
  1230. resListChain->IoResList = ioResourceList;
  1231. //
  1232. // Link this new node onto the passed in chain
  1233. //
  1234. resListChain->NextList = *ResListChainHead;
  1235. *ResListChainHead = resListChain;
  1236. DebugPrint((PCMCIA_DEBUG_RESOURCES, "Added resource chain node %08x, ioreslist %08x\n",
  1237. resListChain, ioResourceList));
  1238. return STATUS_SUCCESS;
  1239. }
  1240. NTSTATUS
  1241. PcmciaMergeResourceChainToList(
  1242. PPCMCIA_RESOURCE_CHAIN ResListChainHead,
  1243. PIO_RESOURCE_REQUIREMENTS_LIST *GeneratedResourceRequirementsList
  1244. )
  1245. /*++
  1246. Routine Description:
  1247. Arguments:
  1248. Return value:
  1249. --*/
  1250. {
  1251. PPCMCIA_RESOURCE_CHAIN resListChain;
  1252. PIO_RESOURCE_REQUIREMENTS_LIST ioResourceRequirementsList;
  1253. PIO_RESOURCE_LIST newIoResList, oldIoResList;
  1254. ULONG listSize, listCount, totalDescriptorCount;
  1255. PAGED_CODE();
  1256. //
  1257. // Now merge the newly created IO_RESOURCE_LISTs into one big
  1258. // IO_RESOURCE_REQUIREMENTS list.
  1259. //
  1260. listCount = 0;
  1261. totalDescriptorCount = 0;
  1262. for (resListChain = ResListChainHead; resListChain != NULL; resListChain = resListChain->NextList) {
  1263. listCount++;
  1264. totalDescriptorCount += resListChain->IoResList->Count;
  1265. }
  1266. if (totalDescriptorCount > 0) {
  1267. listSize = (totalDescriptorCount - listCount) * sizeof(IO_RESOURCE_DESCRIPTOR)
  1268. + (listCount-1) * sizeof(IO_RESOURCE_LIST)
  1269. + sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
  1270. //
  1271. // Allocate space for the res. req. list here
  1272. //
  1273. ioResourceRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, listSize);
  1274. if (ioResourceRequirementsList == NULL) {
  1275. return STATUS_INSUFFICIENT_RESOURCES;
  1276. }
  1277. //
  1278. // Init the list
  1279. //
  1280. RtlZeroMemory(ioResourceRequirementsList, listSize);
  1281. ioResourceRequirementsList->ListSize = listSize;
  1282. ioResourceRequirementsList->AlternativeLists = listCount;
  1283. //
  1284. // Copy in all the other lists. Point the target pointer (newIoResList)
  1285. // at the end of the list, and lay each new list preceding the old
  1286. // one. This is done because the list is LIFO.
  1287. //
  1288. newIoResList = (PIO_RESOURCE_LIST) (((PUCHAR) ioResourceRequirementsList) + listSize);
  1289. for (resListChain = ResListChainHead; resListChain != NULL; resListChain = resListChain->NextList) {
  1290. oldIoResList = resListChain->IoResList;
  1291. listSize = sizeof(IO_RESOURCE_LIST) + (oldIoResList->Count-1)*sizeof(IO_RESOURCE_DESCRIPTOR);
  1292. newIoResList = (PIO_RESOURCE_LIST) (((PUCHAR) newIoResList) - listSize);
  1293. DebugPrint((PCMCIA_DEBUG_RESOURCES, "Merge resource chain node %08x, ioreslist %08x\n",
  1294. resListChain, oldIoResList));
  1295. RtlCopyMemory(newIoResList, oldIoResList, listSize);
  1296. }
  1297. ASSERT(newIoResList == &ioResourceRequirementsList->List[0]);
  1298. DebugPrint((PCMCIA_DEBUG_RESOURCES, "Resource chain merged to ioResourceRequirementsList %08x\n",
  1299. ioResourceRequirementsList));
  1300. } else {
  1301. ioResourceRequirementsList = NULL;
  1302. }
  1303. *GeneratedResourceRequirementsList = ioResourceRequirementsList;
  1304. return STATUS_SUCCESS;
  1305. }
  1306. VOID
  1307. PcmciaFreeResourceChain(
  1308. PPCMCIA_RESOURCE_CHAIN ResListChain
  1309. )
  1310. /*++
  1311. Routine Description:
  1312. Arguments:
  1313. Return value:
  1314. --*/
  1315. {
  1316. PPCMCIA_RESOURCE_CHAIN prevResListChain;
  1317. PAGED_CODE();
  1318. //
  1319. // free the temporary structures
  1320. //
  1321. while (ResListChain != NULL) {
  1322. DebugPrint((PCMCIA_DEBUG_RESOURCES, "Delete resource chain node %08x, ioreslist %08x\n",
  1323. ResListChain, ResListChain->IoResList));
  1324. if (ResListChain->IoResList) {
  1325. ExFreePool(ResListChain->IoResList);
  1326. }
  1327. prevResListChain = ResListChain;
  1328. ResListChain = ResListChain->NextList;
  1329. ExFreePool(prevResListChain);
  1330. }
  1331. }
  1332. NTSTATUS
  1333. PcmciaMfEnumerateConfigurations(
  1334. IN PPDO_EXTENSION PdoExtension,
  1335. IN PSOCKET_DATA socketData,
  1336. PCONFIG_LIST ConfigList,
  1337. IN ULONG Depth,
  1338. PPCMCIA_RESOURCE_CHAIN *MfResListChain
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. This routine is responsible for enumerating combinations of resource
  1343. requirements for the functions in a true R2 MF card. It is called
  1344. recursively to perform this function.
  1345. See the description of PcmciaMfGetResourceRequirements() to see the
  1346. initial state. This routine runs down the linked list of SocketData
  1347. structures, and each corresponding linked list of ConfigData structures.
  1348. When it finds itself at the end of the SocketData list, it is ready
  1349. to build an IoResList for a single permutation. It calls
  1350. PcmciaConfigEntriesToResourceList() to build a single IoResList.
  1351. In the example MF card with two functions, and 2 and 3 resource
  1352. alternatives respectively, this routine will build a list that looks
  1353. something like this:
  1354. +--------------+
  1355. |MfResListChain|
  1356. +--------------+
  1357. | +-----------------------+ +----------------+
  1358. +--------|MF_RESOURCE_LIST(A1+B1)|-----|IoResList(A1+B1)|
  1359. +-----------------------+ +----------------+
  1360. |
  1361. +-----------------------+ +----------------+
  1362. |MF_RESOURCE_LIST(A1+B2)|-----|IoResList(A1+B2)|
  1363. +-----------------------+ +----------------+
  1364. |
  1365. +-----------------------+ +----------------+
  1366. |MF_RESOURCE_LIST(A1+B3)|-----|IoResList(A1+B3)|
  1367. +-----------------------+ +----------------+
  1368. |
  1369. +-----------------------+ +----------------+
  1370. |MF_RESOURCE_LIST(A2+B1)|-----|IoResList(A2+B1)|
  1371. +-----------------------+ +----------------+
  1372. |
  1373. +-----------------------+ +----------------+
  1374. |MF_RESOURCE_LIST(A2+B2)|-----|IoResList(A2+B2)|
  1375. +-----------------------+ +----------------+
  1376. |
  1377. +-----------------------+ +----------------+
  1378. |MF_RESOURCE_LIST(A2+B3)|-----|IoResList(A2+B3)|
  1379. +-----------------------+ +----------------+
  1380. It returns to PcmciaMfGetResourceRequirements() when the list is complete.
  1381. Arguments:
  1382. PdoExtension - Pointer to the device extension for the PDO of the pc-card
  1383. Return Value:
  1384. STATUS_SUCCESS
  1385. --*/
  1386. {
  1387. NTSTATUS status = STATUS_SUCCESS;
  1388. PFDO_EXTENSION fdoExtension = PdoExtension->Socket->DeviceExtension;
  1389. PAGED_CODE();
  1390. if (!socketData) {
  1391. //
  1392. // End of SocketData chain, now ready to generate IoResList for this
  1393. //
  1394. if (PcmciaMfCheckForOverlappingRanges(ConfigList, (LONG)Depth)) {
  1395. //
  1396. // This combination would have generated a bad IoResList
  1397. //
  1398. return STATUS_SUCCESS;
  1399. }
  1400. //
  1401. // Build an io resource list from the current config list
  1402. //
  1403. status = PcmciaConfigEntriesToResourceListChain(PdoExtension,
  1404. ConfigList,
  1405. Depth,
  1406. MfResListChain
  1407. );
  1408. } else {
  1409. PCONFIG_ENTRY configEntry;
  1410. //
  1411. // Not at the bottom of the tree. Recurse through each config entry
  1412. // in this socket data.
  1413. //
  1414. ConfigList[Depth].SocketData = socketData;
  1415. for (configEntry = socketData->ConfigEntryChain;
  1416. configEntry != NULL; configEntry = configEntry->NextEntry) {
  1417. if (configEntry->Flags & PCMCIA_INVALID_CONFIGURATION) {
  1418. continue;
  1419. }
  1420. ConfigList[Depth].ConfigEntry = configEntry;
  1421. DebugPrint((PCMCIA_DEBUG_RESOURCES, "pdo %08x mf enum %d sktdata %08x configEntry %08x\n",
  1422. PdoExtension->DeviceObject, Depth, socketData, configEntry));
  1423. status = PcmciaMfEnumerateConfigurations(PdoExtension,
  1424. socketData->Next,
  1425. ConfigList,
  1426. Depth+1,
  1427. MfResListChain);
  1428. }
  1429. }
  1430. return status;
  1431. }
  1432. NTSTATUS
  1433. PcmciaMfGetResourceRequirements(
  1434. IN PPDO_EXTENSION PdoExtension,
  1435. PULONG_PTR Information
  1436. )
  1437. /*++
  1438. Routine Description:
  1439. For true Multifunction R2 cards, this routine generates a conglomerate
  1440. IoResourceList based on the permutations of configurations of the
  1441. functions.
  1442. Initially the tuple parsing code builds an internal representation of
  1443. the configuration requirements of the cards with SocketData and
  1444. ConfigData structures. Each SocketData structure represents an
  1445. individual function, and each ConfigData represents an alternative
  1446. resource requirement list for that function.
  1447. So for example, an MF card that has two functions may have an internal
  1448. layout like this:
  1449. +------------+
  1450. |PdoExtension|
  1451. +------------+
  1452. | +-----------+ +-----------+
  1453. +----------|SocketDataA|----------|SocketDataB|----0
  1454. +-----------+ +-----------+
  1455. | |
  1456. +------------+ +------------+
  1457. |ConfigDataA1| |ConfigDataB1|
  1458. +------------+ +------------+
  1459. | |
  1460. +------------+ +------------+
  1461. |ConfigDataA2| |ConfigDataB2|
  1462. +------------+ +------------+
  1463. | |
  1464. 0 +------------+
  1465. |ConfigDataB3|
  1466. +------------+
  1467. |
  1468. 0
  1469. This example shows that function A has two resource requirement alternatives,
  1470. and function B has three. What we do is make permutations of each alternative,
  1471. e.g.:
  1472. A1-B1, A1-B2, A1-B3, A2-B1, A2-B2, A2-B3
  1473. The permutations are built with recursive calls to PcmciaMfEnumerateConfigurations().
  1474. In this example, the result of this enumeration will be six independent
  1475. IoResLists. Each IoResList will be a merge of the particular permutation. When
  1476. PcmciaMfEnumerateConfigurations() returns to this routine, these IoResLists will
  1477. be chained together through the pointer MfResListChain. The rest of the routine
  1478. builds a single "six-member" IoResList from the chain.
  1479. Finally the support structure and lists for performing the operation are freed, and
  1480. the single conglomerate list is returned.
  1481. Arguments:
  1482. PdoExtension - Pointer to the device extension for the PDO of the pc-card
  1483. Information - Pointer to an allocated resource requirements list is stored in this
  1484. argument. Caller's responsibility to free the list
  1485. Return value:
  1486. STATUS_INSUFFICIENT_RESOURCES Could not allocate the list
  1487. STATUS_SUCCES Obtained resource requirements, Information contains the pointer
  1488. to the IO_RESOURCE_REQUIREMENTS list
  1489. --*/
  1490. {
  1491. NTSTATUS status;
  1492. PFDO_EXTENSION fdoExtension = PdoExtension->Socket->DeviceExtension;
  1493. ULONG MaxDepth = 0;
  1494. PSOCKET_DATA socketData;
  1495. PCONFIG_LIST ConfigList;
  1496. PPCMCIA_RESOURCE_CHAIN MfResListChain = NULL;
  1497. PIO_RESOURCE_REQUIREMENTS_LIST ioResourceRequirementsList;
  1498. PAGED_CODE();
  1499. ASSERT (IsDeviceMultifunction(PdoExtension));
  1500. //
  1501. // Find out how deep the enumeration will be.
  1502. // Should be the same as Socket->NumberOfFunctions, but just to be paranoid...
  1503. //
  1504. for (socketData = PdoExtension->SocketData; socketData != NULL; socketData = socketData->Next) {
  1505. MaxDepth++;
  1506. }
  1507. if (!MaxDepth) {
  1508. ASSERT (PdoExtension->SocketData);
  1509. return STATUS_UNSUCCESSFUL;
  1510. }
  1511. ConfigList = ExAllocatePool(PagedPool, MaxDepth*sizeof(CONFIG_LIST));
  1512. if (!ConfigList) {
  1513. return STATUS_INSUFFICIENT_RESOURCES;
  1514. }
  1515. PcmciaMfBuildResourceMapInfo(PdoExtension, ConfigList, MaxDepth);
  1516. status = PcmciaMfEnumerateConfigurations(PdoExtension,
  1517. PdoExtension->SocketData,
  1518. ConfigList,
  1519. 0,
  1520. &MfResListChain);
  1521. ExFreePool(ConfigList);
  1522. if (NT_SUCCESS(status)) {
  1523. //
  1524. // Now merge everything that EnumerateConfigurations built into a single list
  1525. //
  1526. status = PcmciaMergeResourceChainToList(MfResListChain, &ioResourceRequirementsList);
  1527. }
  1528. if (NT_SUCCESS(status) && (ioResourceRequirementsList != NULL)) {
  1529. ioResourceRequirementsList->InterfaceType = Isa;
  1530. ioResourceRequirementsList->BusNumber = fdoExtension->Configuration.BusNumber;
  1531. ioResourceRequirementsList->SlotNumber = 0; // Need to revisit this..
  1532. *Information = (ULONG_PTR) ioResourceRequirementsList;
  1533. DebugPrint((PCMCIA_DEBUG_RESOURCES, "pdo %08x mf returning req list %08x, %d alternatives\n",
  1534. PdoExtension->DeviceObject, ioResourceRequirementsList,
  1535. ioResourceRequirementsList->AlternativeLists
  1536. ));
  1537. }
  1538. PcmciaFreeResourceChain(MfResListChain);
  1539. return status;
  1540. }
  1541. VOID
  1542. PcmciaMfBuildResourceMapInfo(
  1543. IN PPDO_EXTENSION PdoExtension,
  1544. PCONFIG_LIST ConfigList,
  1545. ULONG ConfigCount
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. This routine initializes variables in the SocketData structures to allow
  1550. PcmciaMfEnumerateChild() to correctly build ChildInfo ResourceMaps for MF.SYS.
  1551. It needs to calculate the base index for a particular resource of a particular
  1552. function. So for the example of a 2-function MF R2 card, the resulting CmResList
  1553. will be layed out positionally like:
  1554. CmResList
  1555. IRQ (Shared)
  1556. I/O (Function A)
  1557. I/O (Function B)
  1558. Mem (Function A)
  1559. Mem (Function B)
  1560. The reason for this is this is simply how PcmciaConfigEntriesToResourceList()
  1561. happens to lay out the requirements. So in order to generate a valid resource
  1562. map, this routine has to calculate, for example, the Memory Base for function B
  1563. by adding together:
  1564. 1 (if there will be an IRQ in the cmreslist)
  1565. # of I/O port resources for A
  1566. # of I/O port resources for B
  1567. # of Mem resource for A
  1568. This sum will give you the position in the CmReslist for the first memory resource
  1569. that B would use.
  1570. These calculations are stored in the socket data structures for each corresponding
  1571. function so that PcmciaMfEnumerateChild() can simply fill in the maps for MF.
  1572. Arguments:
  1573. PdoExtension - Pointer to the device extension for the PDO of the pc-card
  1574. ConfigList - config list array holds a permutation of configdata's
  1575. ConfigCount - # of card functions
  1576. Return value:
  1577. --*/
  1578. {
  1579. PSOCKET_DATA socketData;
  1580. PCONFIG_ENTRY configEntry;
  1581. ULONG index;
  1582. USHORT count;
  1583. UCHAR currentResourceMapIndex = 0;
  1584. BOOLEAN needsIRQ = FALSE;
  1585. for (index = 0, socketData = PdoExtension->SocketData; socketData != NULL; socketData = socketData->Next) {
  1586. //
  1587. // In the current implementation we assume that all the alternative lists in the
  1588. // io resource requirements for the multifunction parent pc-card have the same number
  1589. // and types of resource requirements. i.e. it's currently illegal to request
  1590. // one configuration in which only IRQ and I/O are requested, for example, and an
  1591. // alternative configuration in which MEMORY is also specified.
  1592. // This is because of the limitation in the MF enumerator - (which in turn relied
  1593. // on the Win 9x implementation).
  1594. // So we currently look at only the first valid configuration - that is representative
  1595. // of all the other configurations.
  1596. //
  1597. for (configEntry = socketData->ConfigEntryChain; (configEntry != NULL) &&
  1598. (configEntry->Flags & PCMCIA_INVALID_CONFIGURATION);
  1599. configEntry = configEntry->NextEntry);
  1600. if (configEntry == NULL) {
  1601. return;
  1602. }
  1603. ASSERT(index < ConfigCount);
  1604. ConfigList[index].SocketData = socketData;
  1605. ConfigList[index].ConfigEntry = configEntry;
  1606. index++;
  1607. }
  1608. //
  1609. // IRQ is unique because it is the only shared resource. So if the card needs an IRQ, then
  1610. // all devices point to the same resource
  1611. for (index = 0; index < ConfigCount; index++) {
  1612. if (ConfigList[index].ConfigEntry->IrqMask) {
  1613. //
  1614. // Index always maps to zero since PcmciaConfigEntriesToResourceList
  1615. // builds IRQs first.
  1616. //
  1617. ConfigList[index].SocketData->MfIrqResourceMapIndex = currentResourceMapIndex;
  1618. ConfigList[index].SocketData->MfNeedsIrq = TRUE;
  1619. needsIRQ = TRUE;
  1620. }
  1621. }
  1622. if (needsIRQ) {
  1623. currentResourceMapIndex++;
  1624. }
  1625. //
  1626. // fill in the bases of the I/O port ranges
  1627. //
  1628. for (index = 0; index < ConfigCount; index++) {
  1629. ConfigList[index].SocketData->MfIoPortResourceMapIndex = currentResourceMapIndex;
  1630. count = ConfigList[index].ConfigEntry->NumberOfIoPortRanges;
  1631. ConfigList[index].SocketData->MfIoPortCount = count;
  1632. currentResourceMapIndex += count;
  1633. }
  1634. //
  1635. // fill in the bases of the memory ranges
  1636. //
  1637. for (index = 0; index < ConfigCount; index++) {
  1638. ConfigList[index].SocketData->MfMemoryResourceMapIndex = currentResourceMapIndex;
  1639. count = ConfigList[index].ConfigEntry->NumberOfMemoryRanges;
  1640. ConfigList[index].SocketData->MfMemoryCount = count;
  1641. currentResourceMapIndex += count;
  1642. }
  1643. }
  1644. BOOLEAN
  1645. PcmciaMfCheckForOverlappingRanges(
  1646. PCONFIG_LIST ConfigList,
  1647. LONG ConfigCount
  1648. )
  1649. /*++
  1650. Routine Description:
  1651. This routine scans through the current config list to see if the set of configurations
  1652. overlap. For example, if the MF R2 card is a dual-serial card, then each serial device
  1653. may want to have one of the standard com addresses (e.g. 3f8, 2f8, etc.). But now
  1654. that we are merging configurations, we need to weed out any overlapping ranges so
  1655. we don't produce a congolmerate IoResList that contains the same range for different
  1656. functions.
  1657. Arguments:
  1658. ConfigList - config list array holds a permutation of configdata's
  1659. ConfigCount - # of card functions
  1660. Return value:
  1661. --*/
  1662. {
  1663. PCONFIG_ENTRY configEntry1, configEntry2;
  1664. LONG configIndex1, configIndex2;
  1665. LONG configCount1, configCount2;
  1666. LONG rangeIndex1, rangeIndex2;
  1667. LONG rangeCount1, rangeCount2;
  1668. ULONG rangeStart1, rangeStart2;
  1669. ULONG rangeEnd1, rangeEnd2;
  1670. BOOLEAN rangesOverlap = FALSE;
  1671. DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Range Check--------------\n"));
  1672. //
  1673. // Check for overlap in the I/O port ranges
  1674. //
  1675. try {
  1676. for (configIndex1 = 0; configIndex1 < ConfigCount; configIndex1++) {
  1677. configEntry1 = ConfigList[configIndex1].ConfigEntry;
  1678. rangeCount1 = configEntry1->NumberOfIoPortRanges;
  1679. for (rangeIndex1 = 0; rangeIndex1 < rangeCount1; rangeIndex1++) {
  1680. //
  1681. // Get the current range we will compare
  1682. //
  1683. rangeStart1 = configEntry1->IoPortBase[rangeIndex1];
  1684. rangeEnd1 = rangeStart1 + configEntry1->IoPortLength[rangeIndex1];
  1685. if (rangeStart1 == 0) {
  1686. DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck I/O: skip unrestricted range %x.%x\n",
  1687. configIndex1, rangeIndex1));
  1688. continue;
  1689. }
  1690. //
  1691. // Now start comparing this against the rest of the ranges by
  1692. // starting at then end and working backwards.
  1693. //
  1694. for (configIndex2 = ConfigCount-1; configIndex2 >= 0; configIndex2--) {
  1695. configEntry2 = ConfigList[configIndex2].ConfigEntry;
  1696. rangeCount2 = configEntry2->NumberOfIoPortRanges;
  1697. for (rangeIndex2 = rangeCount2-1; rangeIndex2 >= 0; rangeIndex2--) {
  1698. if ((configEntry1 == configEntry2) && (rangeIndex1 == rangeIndex2)) {
  1699. leave;
  1700. }
  1701. rangeStart2 = configEntry2->IoPortBase[rangeIndex2];
  1702. rangeEnd2 = rangeStart2 + configEntry2->IoPortLength[rangeIndex2];
  1703. if (rangeStart2 == 0) {
  1704. DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck I/O: skip unrestricted range %x.%x\n",
  1705. configIndex2, rangeIndex2));
  1706. continue;
  1707. }
  1708. DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck I/O: %x.%x %04x-%04x :: %x.%x %04x-%04x\n",
  1709. configIndex1, rangeIndex1, rangeStart1, rangeEnd1,
  1710. configIndex2, rangeIndex2, rangeStart2, rangeEnd2));
  1711. if (((rangeStart1 >= rangeStart2) && (rangeStart1 <= rangeEnd2)) ||
  1712. ((rangeEnd1 >= rangeStart2) && (rangeEnd1 <= rangeEnd2))) {
  1713. rangesOverlap = TRUE;
  1714. leave;
  1715. }
  1716. }
  1717. }
  1718. }
  1719. }
  1720. } finally {
  1721. }
  1722. if (rangesOverlap) {
  1723. DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Overlap Detected---------\n"));
  1724. return TRUE;
  1725. }
  1726. //
  1727. // Check for overlap in the memory ranges
  1728. //
  1729. try {
  1730. for (configIndex1 = 0; configIndex1 < ConfigCount; configIndex1++) {
  1731. configEntry1 = ConfigList[configIndex1].ConfigEntry;
  1732. rangeCount1 = configEntry1->NumberOfMemoryRanges;
  1733. for (rangeIndex1 = 0; rangeIndex1 < rangeCount1; rangeIndex1++) {
  1734. //
  1735. // Get the current range we will compare
  1736. //
  1737. rangeStart1 = configEntry1->MemoryHostBase[rangeIndex1];
  1738. rangeEnd1 = rangeStart1 + configEntry1->MemoryLength[rangeIndex1] - 1;
  1739. if (rangeStart1 == 0) {
  1740. DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck MEM: skip unrestricted range %x.%x\n",
  1741. configIndex1, rangeIndex1));
  1742. continue;
  1743. }
  1744. //
  1745. // Now start comparing this against the rest of the ranges by
  1746. // starting at then end and working backwards.
  1747. //
  1748. for (configIndex2 = ConfigCount-1; configIndex2 >= 0; configIndex2--) {
  1749. configEntry2 = ConfigList[configIndex2].ConfigEntry;
  1750. rangeCount2 = configEntry2->NumberOfMemoryRanges;
  1751. for (rangeIndex2 = rangeCount2-1; rangeIndex2 >= 0; rangeIndex2--) {
  1752. if ((configEntry1 == configEntry2) && (rangeIndex1 == rangeIndex2)) {
  1753. leave;
  1754. }
  1755. rangeStart2 = configEntry2->MemoryHostBase[rangeIndex2];
  1756. rangeEnd2 = rangeStart2 + configEntry2->MemoryLength[rangeIndex2] - 1;
  1757. if (rangeStart2 == 0) {
  1758. DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck MEM: skip unrestricted range %x.%x\n",
  1759. configIndex2, rangeIndex2));
  1760. continue;
  1761. }
  1762. DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck MEM: %x.%x %08x-%08x :: %x.%x %08x-%08x\n",
  1763. configIndex1, rangeIndex1, rangeStart1, rangeEnd1,
  1764. configIndex2, rangeIndex2, rangeStart2, rangeEnd2));
  1765. if (((rangeStart1 >= rangeStart2) && (rangeStart1 <= rangeEnd2)) ||
  1766. ((rangeEnd1 >= rangeStart2) && (rangeEnd1 <= rangeEnd2))) {
  1767. DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Overlap Detected---------\n"));
  1768. rangesOverlap = TRUE;
  1769. leave;
  1770. }
  1771. }
  1772. }
  1773. }
  1774. }
  1775. } finally {
  1776. }
  1777. #if DBG
  1778. if (rangesOverlap) {
  1779. DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Overlap Detected---------\n"));
  1780. } else {
  1781. DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Generate IoResList-------\n"));
  1782. }
  1783. #endif
  1784. return rangesOverlap;
  1785. }
  1786. NTSTATUS
  1787. PcmciaStartPcCard(
  1788. IN PDEVICE_OBJECT Pdo,
  1789. IN PCM_RESOURCE_LIST ResourceList,
  1790. IN OUT PIRP Irp
  1791. )
  1792. /*++
  1793. Routine Description:
  1794. This routine attempts to start the PC-Card by configuring it with the supplied resources.
  1795. Arguments:
  1796. Pdo - Pointer to the device object representing the PC-Card which needs to be started
  1797. ResourceList - Pointer the list of assigned resources for the PC-Card
  1798. Return value:
  1799. STATUS_INSUFFICIENT_RESOURCES - Not sufficient resources supplied to start device/
  1800. could not allocate memory
  1801. STATUS_UNSUCCESSFUL - Supplied resources are invalid for this PC-Card
  1802. STATUS_SUCCESS - Configured and started the card successfully
  1803. --*/
  1804. {
  1805. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  1806. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  1807. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
  1808. ULONG fullResourceDescCount, partialResourceDescCount, i, index;
  1809. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  1810. PSOCKET socket = pdoExtension->Socket;
  1811. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  1812. PSOCKET_DATA socketData = pdoExtension->SocketData;
  1813. PSOCKET_CONFIGURATION socketConfig;
  1814. PCONFIG_ENTRY currentConfig;
  1815. PFUNCTION_CONFIGURATION fnConfig;
  1816. NTSTATUS status;
  1817. ULONG scIoIndex = 0, scMemIndex = 0;
  1818. PAGED_CODE();
  1819. if (IsDeviceStarted(pdoExtension)) {
  1820. //
  1821. // Already started..
  1822. //
  1823. return STATUS_SUCCESS;
  1824. }
  1825. if (IsDevicePhysicallyRemoved(pdoExtension)) {
  1826. return STATUS_DEVICE_DOES_NOT_EXIST;
  1827. }
  1828. if ( ResourceList == NULL ) {
  1829. return STATUS_INSUFFICIENT_RESOURCES;
  1830. }
  1831. PcmciaCleanupSocketConfiguration(pdoExtension);
  1832. socketConfig = ExAllocatePool(NonPagedPool, sizeof(SOCKET_CONFIGURATION));
  1833. if (!socketConfig) {
  1834. return STATUS_INSUFFICIENT_RESOURCES;
  1835. }
  1836. RtlZeroMemory(socketConfig, sizeof(SOCKET_CONFIGURATION));
  1837. fullResourceDescCount = ResourceList->Count;
  1838. ASSERT(fullResourceDescCount == 1);
  1839. fullResourceDesc = &ResourceList->List[0];
  1840. partialResourceList = &fullResourceDesc->PartialResourceList;
  1841. partialResourceDesc = partialResourceList->PartialDescriptors;
  1842. partialResourceDescCount = partialResourceList->Count;
  1843. socketConfig->NumberOfIoPortRanges =
  1844. socketConfig->NumberOfMemoryRanges = 0;
  1845. for (i=0; i< partialResourceList->Count; i++, partialResourceDesc++) {
  1846. switch (partialResourceDesc->Type) {
  1847. case CmResourceTypePort: {
  1848. index = socketConfig->NumberOfIoPortRanges;
  1849. socketConfig->Io[index].Base = partialResourceDesc->u.Port.Start.LowPart;
  1850. socketConfig->Io[index].Length = (USHORT) partialResourceDesc->u.Port.Length-1;
  1851. socketConfig->NumberOfIoPortRanges++;
  1852. break;
  1853. }
  1854. case CmResourceTypeMemory: {
  1855. index = socketConfig->NumberOfMemoryRanges;
  1856. socketConfig->Memory[index].HostBase = partialResourceDesc->u.Memory.Start.LowPart;
  1857. socketConfig->Memory[index].Length = partialResourceDesc->u.Memory.Length;
  1858. socketConfig->NumberOfMemoryRanges++;
  1859. break;
  1860. }
  1861. case CmResourceTypeInterrupt: {
  1862. socketConfig->Irq = partialResourceDesc->u.Interrupt.Level;
  1863. DebugPrint((PCMCIA_DEBUG_RESOURCES, "Assigned Irq: 0x%x for socket register offset %d\n",
  1864. socketConfig->Irq, socket->RegisterOffset));
  1865. break;
  1866. }
  1867. case CmResourceTypePcCardConfig:
  1868. case CmResourceTypeMfCardConfig:
  1869. case CmResourceTypeDevicePrivate: {
  1870. DebugPrint((PCMCIA_DEBUG_RESOURCES, "DevicePrivate received, Data= %08x %08x %08x\n",
  1871. partialResourceDesc->u.DevicePrivate.Data[0],
  1872. partialResourceDesc->u.DevicePrivate.Data[1],
  1873. partialResourceDesc->u.DevicePrivate.Data[2]));
  1874. if (PCMRES_GET_DESCRIPTOR_TYPE (partialResourceDesc) == DPTYPE_PCMCIA_CONFIGURATION) {
  1875. //
  1876. // Single function configuration private
  1877. //
  1878. socketConfig->IndexForCurrentConfiguration = PCMRES_GET_CONFIG_INDEX(partialResourceDesc);
  1879. socketConfig->ConfigRegisterBase = socketData->ConfigRegisterBase;
  1880. DebugPrint((PCMCIA_DEBUG_RESOURCES, "Pccard config resource\n"));
  1881. DebugPrint((PCMCIA_DEBUG_RESOURCES, " Index %x\n", socketConfig->IndexForCurrentConfiguration));
  1882. for (index = 0; index < PCMRES_PCMCIA_MAX_IO; index++) {
  1883. if (scIoIndex >= MAX_NUMBER_OF_IO_RANGES) {
  1884. break;
  1885. }
  1886. socketConfig->Io[scIoIndex].Width16 = PCMRES_GET_IO_FLAG(partialResourceDesc, index, PCMRESF_IO_16BIT_ACCESS);
  1887. socketConfig->Io[scIoIndex].WaitState16 = PCMRES_GET_IO_FLAG(partialResourceDesc, index, PCMRESF_IO_WAIT_16);
  1888. socketConfig->Io[scIoIndex].Source16 = PCMRES_GET_IO_FLAG(partialResourceDesc, index, PCMRESF_IO_SOURCE_16);
  1889. socketConfig->Io[scIoIndex].ZeroWait8 = PCMRES_GET_IO_FLAG(partialResourceDesc, index, PCMRESF_IO_ZERO_WAIT_8);
  1890. DebugPrint((PCMCIA_DEBUG_RESOURCES, "PcCardConfig IO%d - Width:%d, Wait16:%d, Source16:%d, ZeroWait8:%d\n", scIoIndex,
  1891. socketConfig->Io[scIoIndex].Width16,
  1892. socketConfig->Io[scIoIndex].WaitState16,
  1893. socketConfig->Io[scIoIndex].Source16,
  1894. socketConfig->Io[scIoIndex].ZeroWait8));
  1895. scIoIndex++;
  1896. }
  1897. for (index = 0; index < PCMRES_PCMCIA_MAX_MEM; index++) {
  1898. if (scMemIndex >= MAX_NUMBER_OF_MEMORY_RANGES) {
  1899. break;
  1900. }
  1901. socketConfig->Memory[scMemIndex].Width16 = PCMRES_GET_MEMORY_FLAG(partialResourceDesc, index, PCMRESF_MEM_16BIT_ACCESS);
  1902. socketConfig->Memory[scMemIndex].WaitState = PCMRES_GET_MEMORY_WAITSTATES(partialResourceDesc, index);
  1903. socketConfig->Memory[scMemIndex].IsAttribute = PCMRES_GET_MEMORY_FLAG(partialResourceDesc, index, PCMRESF_MEM_ATTRIBUTE);
  1904. socketConfig->Memory[scMemIndex].CardBase = PCMRES_GET_MEMORY_CARDBASE(partialResourceDesc, index);
  1905. DebugPrint((PCMCIA_DEBUG_RESOURCES, "PcCardConfig MEM%d - Width:%d, Wait:%d, IsAttr:%d, CardBase:%x\n", scMemIndex,
  1906. socketConfig->Memory[scMemIndex].Width16,
  1907. socketConfig->Memory[scMemIndex].WaitState,
  1908. socketConfig->Memory[scMemIndex].IsAttribute,
  1909. socketConfig->Memory[scMemIndex].CardBase));
  1910. scMemIndex++;
  1911. }
  1912. } else if (PCMRES_GET_DESCRIPTOR_TYPE (partialResourceDesc) == DPTYPE_PCMCIA_MF_CONFIGURATION) {
  1913. //
  1914. // Multifunction configuration private
  1915. //
  1916. UCHAR IoResourceIndex;
  1917. fnConfig = ExAllocatePool(NonPagedPool, sizeof(FUNCTION_CONFIGURATION));
  1918. if (!fnConfig) {
  1919. return STATUS_INSUFFICIENT_RESOURCES;
  1920. }
  1921. RtlZeroMemory(fnConfig, sizeof(FUNCTION_CONFIGURATION));
  1922. fnConfig->ConfigRegisterBase = PCMRES_GET_CONFIG_REGISTER_BASE(partialResourceDesc);
  1923. fnConfig->ConfigOptions = PCMRES_GET_CONFIG_OPTIONS(partialResourceDesc);
  1924. if (PCMRES_GET_AUDIO_ENABLE(partialResourceDesc)) {
  1925. fnConfig->ConfigFlags = 0x08;
  1926. }
  1927. if (fnConfig->ConfigOptions & 0x02) {
  1928. IoResourceIndex = PCMRES_GET_PORT_RESOURCE_INDEX(partialResourceDesc);
  1929. if ((IoResourceIndex < partialResourceList->Count) &&
  1930. (partialResourceList->PartialDescriptors[IoResourceIndex].Type == CmResourceTypePort)) {
  1931. fnConfig->IoLimit = (UCHAR) (partialResourceList->PartialDescriptors[IoResourceIndex].u.Port.Length-1);
  1932. fnConfig->IoBase = partialResourceList->PartialDescriptors[IoResourceIndex].u.Port.Start.LowPart;
  1933. }
  1934. }
  1935. if (socketConfig->FunctionConfiguration == NULL) {
  1936. //
  1937. // This is the first MfConfig
  1938. //
  1939. socketConfig->FunctionConfiguration = fnConfig;
  1940. } else {
  1941. //
  1942. // Chain it on the end so it is fifo
  1943. //
  1944. PFUNCTION_CONFIGURATION mfTmp = socketConfig->FunctionConfiguration;
  1945. while (mfTmp->Next != NULL) {
  1946. mfTmp = mfTmp->Next;
  1947. }
  1948. mfTmp->Next = fnConfig;
  1949. }
  1950. }
  1951. break;
  1952. }
  1953. default: {
  1954. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaStartPcCard:Unknown resource type %d handed down",
  1955. (ULONG) partialResourceDesc->Type));
  1956. break;
  1957. }
  1958. }
  1959. }
  1960. //
  1961. // Power up the card if it isn't already..
  1962. //
  1963. status = PcmciaRequestSocketPower(pdoExtension, NULL);
  1964. if (!NT_SUCCESS(status)) {
  1965. ASSERT(NT_SUCCESS(status));
  1966. return status;
  1967. }
  1968. //
  1969. // Turn on ZV for this card, if it needs it
  1970. //
  1971. if (socketData->Flags & SDF_ZV) {
  1972. PcmciaSetZV(fdoExtension, socket, TRUE);
  1973. SetSocketFlag(socket, SOCKET_CUSTOM_INTERFACE);
  1974. } else if (IsSocketFlagSet(socket, SOCKET_CUSTOM_INTERFACE)) {
  1975. PcmciaSetZV(fdoExtension, socket, FALSE);
  1976. ResetSocketFlag(socket, SOCKET_CUSTOM_INTERFACE);
  1977. }
  1978. PcmciaSetAudio(fdoExtension, socket, IsDeviceFlagSet(pdoExtension, PCMCIA_PDO_ENABLE_AUDIO));
  1979. pdoExtension->SocketConfiguration = socketConfig;
  1980. if (!NT_SUCCESS(PcmciaConfigurePcCard(pdoExtension, NULL))) {
  1981. //
  1982. // Problems in configuring the card: could be the card
  1983. // was removed while configuring it
  1984. //
  1985. pdoExtension->SocketConfiguration = NULL;
  1986. ExFreePool(socketConfig);
  1987. return STATUS_DEVICE_NOT_READY;
  1988. }
  1989. MarkDeviceStarted(pdoExtension);
  1990. MarkDeviceLogicallyInserted(pdoExtension);
  1991. return STATUS_SUCCESS;
  1992. }
  1993. NTSTATUS
  1994. PcmciaStopPcCard(
  1995. IN PDEVICE_OBJECT Pdo
  1996. )
  1997. /*++
  1998. Routine Description:
  1999. This routine stops and deconfigures the given PC-Card
  2000. Arguments:
  2001. Pdo - Pointer to the device object representing the PC-Card which needs to be stopped
  2002. Return value:
  2003. STATUS_SUCCESS - PC-Card was already stopped, or stopped and deconfigured now successfully
  2004. --*/
  2005. {
  2006. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  2007. PSOCKET socket = pdoExtension->Socket;
  2008. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  2009. CARD_REQUEST cardRequest;
  2010. PAGED_CODE();
  2011. if (!IsDeviceStarted(pdoExtension)) {
  2012. return STATUS_SUCCESS;
  2013. }
  2014. //
  2015. // Need to deconfigure the controller
  2016. //
  2017. PcmciaSocketDeconfigure(socket);
  2018. (socket->SocketFnPtr->PCBInitializePcmciaSocket)(socket);
  2019. MarkDeviceNotStarted(pdoExtension);
  2020. return STATUS_SUCCESS;
  2021. }
  2022. NTSTATUS
  2023. PcmciaRemovePcCard(
  2024. IN PDEVICE_OBJECT Pdo,
  2025. IN PIRP Irp
  2026. )
  2027. /*++
  2028. Routine Description:
  2029. Arguments:
  2030. Return value:
  2031. --*/
  2032. {
  2033. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  2034. PSOCKET socket = pdoExtension->Socket;
  2035. NTSTATUS status;
  2036. PAGED_CODE();
  2037. if (socket == NULL) {
  2038. return STATUS_SUCCESS;
  2039. }
  2040. PcmciaStopPcCard(Pdo);
  2041. PcmciaReleaseSocketPower(pdoExtension, NULL);
  2042. if (IsDevicePhysicallyRemoved(pdoExtension)) {
  2043. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  2044. PDEVICE_OBJECT curPdo, prevPdo;
  2045. PPDO_EXTENSION curPdoExt;
  2046. ULONG waitCount = 0;
  2047. //
  2048. // Synchronize with power routines
  2049. // LATER: make these values adjustable
  2050. //
  2051. while(!PCMCIA_TEST_AND_SET(&pdoExtension->DeletionLock)) {
  2052. PcmciaWait(1000000);
  2053. if (waitCount++ > 20) {
  2054. ASSERT(waitCount <= 20);
  2055. break;
  2056. }
  2057. }
  2058. //
  2059. // Delink this Pdo from the FDO list.
  2060. //
  2061. for (curPdo = fdoExtension->PdoList, prevPdo = NULL; curPdo!=NULL; prevPdo = curPdo, curPdo=curPdoExt->NextPdoInFdoChain) {
  2062. curPdoExt = curPdo->DeviceExtension;
  2063. if (curPdo == Pdo) {
  2064. if (prevPdo) {
  2065. ((PPDO_EXTENSION)prevPdo->DeviceExtension)->NextPdoInFdoChain = pdoExtension->NextPdoInFdoChain;
  2066. } else {
  2067. fdoExtension->PdoList = pdoExtension->NextPdoInFdoChain;
  2068. }
  2069. break;
  2070. }
  2071. }
  2072. for (curPdo = socket->PdoList, prevPdo = NULL; curPdo!=NULL; prevPdo = curPdo, curPdo=curPdoExt->NextPdoInSocket) {
  2073. curPdoExt = curPdo->DeviceExtension;
  2074. if (curPdo == Pdo) {
  2075. //
  2076. // Delink this Pdo from the socket list.
  2077. //
  2078. if (prevPdo) {
  2079. ((PPDO_EXTENSION)prevPdo->DeviceExtension)->NextPdoInSocket = pdoExtension->NextPdoInSocket;
  2080. } else {
  2081. socket->PdoList = pdoExtension->NextPdoInSocket;
  2082. }
  2083. break;
  2084. }
  2085. }
  2086. PcmciaCleanupSocketConfiguration(pdoExtension);
  2087. PcmciaCleanupPdo(Pdo);
  2088. //
  2089. // Delete..
  2090. //
  2091. if (!IsDeviceDeleted(pdoExtension)) {
  2092. MarkDeviceDeleted(pdoExtension);
  2093. IoDeleteDevice(Pdo);
  2094. }
  2095. ResetSocketFlag(socket, SOCKET_CLEANUP_PENDING);
  2096. //
  2097. // If a query_device_relations came in after a card was inserted, but before
  2098. // we have removed the previous card configuration, the enumeration would have been
  2099. // postponed. Here, we start it up again
  2100. //
  2101. if (IsSocketFlagSet(socket, SOCKET_ENUMERATE_PENDING)) {
  2102. ResetSocketFlag(socket, SOCKET_ENUMERATE_PENDING);
  2103. SetSocketFlag(socket, SOCKET_CARD_STATUS_CHANGE);
  2104. IoInvalidateDeviceRelations(fdoExtension->Pdo, BusRelations);
  2105. }
  2106. } else {
  2107. //
  2108. // We will keep this Pdo around, since this is not physically ejected.
  2109. //
  2110. MarkDeviceLogicallyRemoved(pdoExtension);
  2111. }
  2112. return STATUS_SUCCESS;
  2113. }
  2114. VOID
  2115. PcmciaCleanupPdo(
  2116. IN PDEVICE_OBJECT Pdo
  2117. )
  2118. /*++
  2119. Routine Description:
  2120. Arguments:
  2121. Return value:
  2122. --*/
  2123. {
  2124. PPDO_EXTENSION pdoExtension;
  2125. PSOCKET_DATA socketData, tmpSocketData;
  2126. ASSERT (Pdo != NULL);
  2127. pdoExtension = Pdo->DeviceExtension;
  2128. ASSERT(pdoExtension->WaitWakeIrp == NULL);
  2129. if (pdoExtension->LowerDevice!=NULL) {
  2130. //
  2131. // Detach our filter device
  2132. //
  2133. IoDetachDevice(pdoExtension->LowerDevice);
  2134. pdoExtension->LowerDevice = NULL;
  2135. }
  2136. socketData = pdoExtension->SocketData;
  2137. pdoExtension->SocketData = NULL;
  2138. while (socketData != NULL) {
  2139. tmpSocketData = socketData;
  2140. socketData = socketData->Next;
  2141. PcmciaCleanupSocketData(tmpSocketData);
  2142. }
  2143. PcmciaCleanupSocketConfiguration(pdoExtension);
  2144. //
  2145. // Cleanup device id
  2146. //
  2147. if (pdoExtension->DeviceId) {
  2148. ExFreePool(pdoExtension->DeviceId);
  2149. pdoExtension->DeviceId = NULL;
  2150. }
  2151. if (pdoExtension->CisCache) {
  2152. ExFreePool(pdoExtension->CisCache);
  2153. pdoExtension->CisCache = NULL;
  2154. }
  2155. }
  2156. VOID
  2157. PcmciaCleanupSocketData(
  2158. IN PSOCKET_DATA SocketData
  2159. )
  2160. /*++
  2161. Routine Descrption
  2162. Frees up the passed in SocketData structure & any
  2163. structures it might point to
  2164. Arguments
  2165. SocketData - Pointer to the SOCKET_DATA structure
  2166. Return Value
  2167. none
  2168. --*/
  2169. {
  2170. PCONFIG_ENTRY configEntry, nextConfigEntry;
  2171. if (SocketData == NULL) {
  2172. return;
  2173. }
  2174. //
  2175. // Free up the config entry descriptors
  2176. //
  2177. configEntry = SocketData->ConfigEntryChain;
  2178. SocketData->ConfigEntryChain = NULL;
  2179. while (configEntry) {
  2180. nextConfigEntry = configEntry->NextEntry;
  2181. ExFreePool(configEntry);
  2182. configEntry = nextConfigEntry;
  2183. }
  2184. //
  2185. // Free up socket data
  2186. //
  2187. ExFreePool(SocketData);
  2188. return;
  2189. }
  2190. VOID
  2191. PcmciaCleanupSocketConfiguration(
  2192. PPDO_EXTENSION pdoExtension
  2193. )
  2194. /*++
  2195. Routine Description:
  2196. Frees up the linked list of function configuration, as well as
  2197. the base socket configuration structure itself.
  2198. Arguments:
  2199. Return value:
  2200. --*/
  2201. {
  2202. PSOCKET_CONFIGURATION socketConfig = pdoExtension->SocketConfiguration;
  2203. PFUNCTION_CONFIGURATION fnConfig, fnConfigNext;
  2204. if (socketConfig == NULL) {
  2205. return;
  2206. }
  2207. fnConfig = socketConfig->FunctionConfiguration;
  2208. while(fnConfig) {
  2209. fnConfigNext = fnConfig->Next;
  2210. ExFreePool(fnConfig);
  2211. fnConfig = fnConfigNext;
  2212. }
  2213. ExFreePool(pdoExtension->SocketConfiguration);
  2214. pdoExtension->SocketConfiguration = NULL;
  2215. }
  2216. NTSTATUS
  2217. PcmciaPdoDeviceControl(
  2218. IN PDEVICE_OBJECT Pdo,
  2219. IN PIRP Irp
  2220. )
  2221. /*++
  2222. Routine Description:
  2223. Arguments:
  2224. Return value:
  2225. --*/
  2226. {
  2227. PAGED_CODE();
  2228. //
  2229. // No IOCTLs handled currently
  2230. //
  2231. UNREFERENCED_PARAMETER(Pdo);
  2232. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  2233. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2234. return STATUS_INVALID_DEVICE_REQUEST;
  2235. }
  2236. NTSTATUS
  2237. PcmciaPdoDeviceCapabilities(
  2238. IN PDEVICE_OBJECT Pdo,
  2239. IN PIRP Irp
  2240. )
  2241. /*++
  2242. Routine Description:
  2243. Obtains the device capabilities of the given pc-card.
  2244. If the pc-card is an R2 card (16-bit pc-card), the capabilities
  2245. are constructed from the parent PCMCIA controller's capabilities.
  2246. Finally the obtained capabilities are cached in the pc-card's device
  2247. extension for use in power management of the card.
  2248. Arguments:
  2249. Pdo - Pointer to the device object for the pc-card
  2250. Irp - Pointer to the query device capabilities Irp
  2251. Return Value:
  2252. STATUS_SUCCESS - Capabilities obtained and recorded in the passed in pointer
  2253. STATUS_INSUFFICIENT_RESOURCES - Could not allocate memory to cache the capabilities
  2254. --*/
  2255. {
  2256. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  2257. PDEVICE_CAPABILITIES capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
  2258. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  2259. PDEVICE_CAPABILITIES busCapabilities = &pdoExtension->Socket->DeviceExtension->DeviceCapabilities;
  2260. PAGED_CODE();
  2261. //
  2262. // R2 card. Fill in the capabilities ourselves..
  2263. //
  2264. capabilities->Removable = TRUE;
  2265. capabilities->UniqueID = TRUE;
  2266. capabilities->EjectSupported = FALSE;
  2267. capabilities->Address = pdoExtension->Socket->RegisterOffset;
  2268. // Don't know the UINumber, just leave it alone
  2269. if (busCapabilities->DeviceState[PowerSystemWorking] != PowerDeviceUnspecified) {
  2270. capabilities->DeviceState[PowerSystemWorking] = busCapabilities->DeviceState[PowerSystemWorking];
  2271. capabilities->DeviceState[PowerSystemSleeping1] = busCapabilities->DeviceState[PowerSystemSleeping1];
  2272. capabilities->DeviceState[PowerSystemSleeping2] = busCapabilities->DeviceState[PowerSystemSleeping2];
  2273. capabilities->DeviceState[PowerSystemSleeping3] = busCapabilities->DeviceState[PowerSystemSleeping3];
  2274. capabilities->DeviceState[PowerSystemHibernate] = busCapabilities->DeviceState[PowerSystemHibernate];
  2275. capabilities->DeviceState[PowerSystemShutdown] = busCapabilities->DeviceState[PowerSystemShutdown];
  2276. capabilities->SystemWake = MIN(PowerSystemSleeping3, busCapabilities->SystemWake);
  2277. capabilities->DeviceWake = PowerDeviceD0; // don't rely on FDO mungeing in the right thing for r2 cards
  2278. capabilities->D1Latency = busCapabilities->D1Latency;
  2279. capabilities->D2Latency = busCapabilities->D2Latency;
  2280. capabilities->D3Latency = busCapabilities->D3Latency;
  2281. } else {
  2282. capabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
  2283. capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
  2284. capabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
  2285. capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
  2286. capabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
  2287. capabilities->DeviceState[PowerSystemShutdown] = PowerDeviceD3;
  2288. capabilities->SystemWake = PowerSystemUnspecified;
  2289. capabilities->DeviceWake = PowerDeviceD0; // don't rely on FDO mungeing in the right thing for r2 cards
  2290. capabilities->D1Latency = 0; // No latency - since we do nothing
  2291. capabilities->D2Latency = 0; //
  2292. capabilities->D3Latency = 100;
  2293. }
  2294. //
  2295. // Store these capabilities away..
  2296. //
  2297. RtlCopyMemory(&pdoExtension->DeviceCapabilities,
  2298. capabilities,
  2299. sizeof(DEVICE_CAPABILITIES));
  2300. return STATUS_SUCCESS;
  2301. }