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.

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