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.

1592 lines
48 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. fdopnp.c
  5. Abstract:
  6. This module contains the code that handles PNP irps for pcmcia bus driver
  7. targeted towards the FDO's (for the pcmcia controller object)
  8. Author:
  9. Ravisankar Pudipeddi (ravisp) Oct 15 1996
  10. Neil Sandlin (neilsa) June 1 1999
  11. Environment:
  12. Kernel mode
  13. Revision History :
  14. --*/
  15. #include "pch.h"
  16. //
  17. // Internal References
  18. //
  19. NTSTATUS
  20. PcmciaFdoFilterResourceRequirements(
  21. IN PDEVICE_OBJECT Fdo,
  22. IN PIRP Irp
  23. );
  24. NTSTATUS
  25. PcmciaFdoGetHardwareIds(
  26. IN PDEVICE_OBJECT Fdo,
  27. OUT PUNICODE_STRING HardwareIds
  28. );
  29. NTSTATUS
  30. PcmciaFdoStartDevice(
  31. IN PDEVICE_OBJECT Fdo,
  32. IN PIRP Irp,
  33. OUT BOOLEAN *PassedDown,
  34. OUT BOOLEAN *NeedsRecompletion
  35. );
  36. NTSTATUS
  37. PcmciaFdoStopDevice(
  38. IN PDEVICE_OBJECT Fdo,
  39. IN PIRP Irp,
  40. OUT BOOLEAN *PassedDown,
  41. OUT BOOLEAN *NeedsRecompletion
  42. );
  43. NTSTATUS
  44. PcmciaFdoRemoveDevice(
  45. IN PDEVICE_OBJECT Fdo,
  46. IN PIRP Irp
  47. );
  48. VOID
  49. PcmciaCleanupFdo(
  50. IN PFDO_EXTENSION FdoExtension
  51. );
  52. NTSTATUS
  53. PcmciaFdoDeviceCapabilities(
  54. IN PDEVICE_OBJECT Fdo,
  55. IN PIRP Irp,
  56. OUT BOOLEAN *PassedDown,
  57. OUT BOOLEAN *NeedsRecompletion
  58. );
  59. NTSTATUS
  60. PcmciaAreCardBusCardsSupported(
  61. IN PFDO_EXTENSION FdoExtension
  62. );
  63. NTSTATUS
  64. PcmciaFdoGetAssignedResources(
  65. IN PCM_RESOURCE_LIST ResourceList,
  66. IN PCM_RESOURCE_LIST TranslatedResourceList,
  67. IN PFDO_EXTENSION DeviceExtension
  68. );
  69. #ifdef ALLOC_PRAGMA
  70. #pragma alloc_text(PAGE, PcmciaFdoPnpDispatch)
  71. #pragma alloc_text(PAGE, PcmciaFdoGetHardwareIds)
  72. #pragma alloc_text(PAGE, PcmciaFdoStartDevice)
  73. #pragma alloc_text(PAGE, PcmciaFdoStopDevice)
  74. #pragma alloc_text(PAGE, PcmciaFdoRemoveDevice)
  75. #pragma alloc_text(PAGE, PcmciaFdoFilterResourceRequirements)
  76. #pragma alloc_text(PAGE, PcmciaFdoGetAssignedResources)
  77. #pragma alloc_text(PAGE, PcmciaFdoDeviceCapabilities)
  78. #pragma alloc_text(PAGE, PcmciaAreCardBusCardsSupported)
  79. #endif
  80. NTSTATUS
  81. PcmciaFdoPnpDispatch (
  82. IN PDEVICE_OBJECT DeviceObject,
  83. IN PIRP Irp
  84. )
  85. /*++
  86. Routine Description:
  87. PNP/Power IRPs dispatch routine for the PCMCIA bus controller
  88. Arguments:
  89. DeviceObject - Pointer to the device object.
  90. Irp - Pointer to the IRP
  91. Return Value:
  92. Status
  93. --*/
  94. {
  95. PIO_STACK_LOCATION nextIrpStack;
  96. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  97. PFDO_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  98. NTSTATUS status = Irp->IoStatus.Status;
  99. BOOLEAN PassedDown = FALSE;
  100. BOOLEAN NeedsReCompletion = FALSE;
  101. PAGED_CODE();
  102. #if DBG
  103. if (irpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
  104. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x - Unknown PNP irp\n",
  105. DeviceObject, irpStack->MinorFunction));
  106. } else {
  107. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x --> %s\n",
  108. DeviceObject, Irp, PNP_IRP_STRING(irpStack->MinorFunction)));
  109. }
  110. #endif
  111. switch (irpStack->MinorFunction) {
  112. case IRP_MN_START_DEVICE: {
  113. status = PcmciaFdoStartDevice(DeviceObject,
  114. Irp,
  115. &PassedDown,
  116. &NeedsReCompletion);
  117. break;
  118. }
  119. case IRP_MN_QUERY_STOP_DEVICE: {
  120. status = STATUS_SUCCESS;
  121. break;
  122. }
  123. case IRP_MN_CANCEL_STOP_DEVICE: {
  124. status = STATUS_SUCCESS;
  125. break;
  126. }
  127. case IRP_MN_STOP_DEVICE: {
  128. status = PcmciaFdoStopDevice(DeviceObject,
  129. Irp,
  130. &PassedDown,
  131. &NeedsReCompletion);
  132. break;
  133. }
  134. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  135. //
  136. // Return the list of devices on the bus
  137. //
  138. status = PcmciaDeviceRelations(
  139. DeviceObject,
  140. Irp,
  141. irpStack->Parameters.QueryDeviceRelations.Type,
  142. (PDEVICE_RELATIONS *) &Irp->IoStatus.Information
  143. );
  144. break;
  145. }
  146. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: {
  147. status = PcmciaFdoFilterResourceRequirements(DeviceObject, Irp);
  148. PassedDown = TRUE;
  149. NeedsReCompletion = TRUE;
  150. break;
  151. }
  152. case IRP_MN_QUERY_REMOVE_DEVICE: {
  153. status = STATUS_SUCCESS;
  154. break;
  155. }
  156. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  157. status = STATUS_SUCCESS;
  158. break;
  159. }
  160. case IRP_MN_REMOVE_DEVICE:{
  161. status = PcmciaFdoRemoveDevice(DeviceObject, Irp);
  162. PassedDown = TRUE ;
  163. NeedsReCompletion = TRUE ;
  164. break;
  165. }
  166. case IRP_MN_SURPRISE_REMOVAL: {
  167. PcmciaFdoStopDevice(DeviceObject, NULL, NULL, NULL);
  168. status = STATUS_SUCCESS;
  169. break;
  170. }
  171. case IRP_MN_QUERY_ID: {
  172. UNICODE_STRING unicodeId;
  173. if (deviceExtension->Flags & PCMCIA_DEVICE_LEGACY_DETECTED) {
  174. RtlInitUnicodeString(&unicodeId, NULL);
  175. switch (irpStack->Parameters.QueryId.IdType) {
  176. case BusQueryHardwareIDs: {
  177. DebugPrint((PCMCIA_DEBUG_INFO, " Hardware Ids for fdo %x\n", DeviceObject));
  178. status = PcmciaFdoGetHardwareIds(DeviceObject, &unicodeId);
  179. if (NT_SUCCESS(status)) {
  180. Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
  181. }
  182. break;
  183. }
  184. }
  185. }
  186. break;
  187. }
  188. case IRP_MN_QUERY_CAPABILITIES: {
  189. status = PcmciaFdoDeviceCapabilities(DeviceObject,
  190. Irp,
  191. &PassedDown,
  192. &NeedsReCompletion);
  193. break;
  194. }
  195. case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
  196. //
  197. // If this FDO represents a CardBus bridge, we pass this irp down
  198. // to the PCI PDO which will fill in the PCI bus type and number,
  199. // otherwise we fail the IRP.
  200. //
  201. if (!CardBusExtension(deviceExtension)) {
  202. status = STATUS_NOT_IMPLEMENTED;
  203. }
  204. //
  205. // if status is still STATUS_NOT_SUPPORTED, then later code will pass
  206. // this irp down the stack.
  207. //
  208. break;
  209. default: {
  210. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x - Skipping unsupported irp\n", DeviceObject, Irp));
  211. break;
  212. }
  213. }
  214. if (!PassedDown) {
  215. //
  216. // Set the IRP status only if we set it to something other than
  217. // STATUS_NOT_SUPPORTED.
  218. //
  219. if (status != STATUS_NOT_SUPPORTED) {
  220. Irp->IoStatus.Status = status ;
  221. }
  222. //
  223. // Pass down if success or STATUS_NOT_SUPPORTED. Otherwise, Complete.
  224. //
  225. if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
  226. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x pass %s %08x\n",
  227. DeviceObject, Irp,
  228. STATUS_STRING(Irp->IoStatus.Status), Irp->IoStatus.Status));
  229. //
  230. // Below macro fills status with return of IoCallDriver. It does
  231. // not change the Irps status in any way.
  232. //
  233. PcmciaSkipCallLowerDriver(status, deviceExtension->LowerDevice, Irp);
  234. } else {
  235. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x comp %s %08x\n",
  236. DeviceObject, Irp,
  237. STATUS_STRING(status), status));
  238. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  239. }
  240. } else if (NeedsReCompletion) {
  241. //
  242. // Set the IRP status only if we set it to something other than
  243. // STATUS_NOT_SUPPORTED.
  244. //
  245. if (status != STATUS_NOT_SUPPORTED) {
  246. Irp->IoStatus.Status = status ;
  247. }
  248. status = Irp->IoStatus.Status ;
  249. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x comp %s %08x\n",
  250. DeviceObject, Irp,
  251. STATUS_STRING(status), status));
  252. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  253. }
  254. return status ;
  255. }
  256. NTSTATUS
  257. PcmciaFdoDeviceCapabilities(
  258. IN PDEVICE_OBJECT Fdo,
  259. IN PIRP Irp,
  260. OUT BOOLEAN *PassedDown,
  261. OUT BOOLEAN *NeedsRecompletion
  262. )
  263. /*++
  264. Routine Description
  265. Records the device capabilities of this pcmcia controller,
  266. so 1. they can be used in the power management for the controller
  267. and 2. they can be used for determining the capabilities of the
  268. child pc-card PDO's of this pcmcia controller.
  269. If this is legacy detected pcmcia controller (ISA-based), the pdo for
  270. the pcmcia controller is a dummy madeup device - hence the capabilities
  271. are filled in by ourselves.
  272. Otherwise, the capabilities are obtained by sending down the Irp
  273. to the parent bus.
  274. In either case, the capabilities are cached in the device extension of
  275. the pcmcia controller for future use.
  276. Arguments
  277. Fdo - Pointer to functional device object of the pcmcia
  278. controller
  279. Irp - Pointer to the i/o request packet
  280. PassedDown - Contains FALSE on entry, which means caller must
  281. complete or pass down irp based on status. If set
  282. to TRUE, Irp may need to be re-completed...
  283. NeedsRecompletion - ...In which case this parameter will be checked
  284. Return Value
  285. STATUS_SUCCESS Capabilities returned
  286. STATUS_INSUFFICIENT_RESOURCES Could not allocate memory to cache the capabilities
  287. --*/
  288. {
  289. PFDO_EXTENSION fdoExtension;
  290. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  291. PDEVICE_CAPABILITIES capabilities;
  292. NTSTATUS status;
  293. PAGED_CODE();
  294. capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
  295. fdoExtension = Fdo->DeviceExtension;
  296. if (fdoExtension->Flags & PCMCIA_DEVICE_LEGACY_DETECTED) {
  297. //
  298. // This is a madeup devnode (ISA based PCMCIA controller).
  299. // Fill in the capabilities ourselves
  300. //
  301. RtlZeroMemory(capabilities,
  302. sizeof(DEVICE_CAPABILITIES));
  303. //
  304. // Non removable, non ejectable
  305. //
  306. capabilities->Removable = FALSE;
  307. capabilities->UniqueID = FALSE;
  308. capabilities->EjectSupported = FALSE;
  309. //
  310. // Address & number need work..
  311. //
  312. capabilities->Address = -1;
  313. capabilities->UINumber = -1;
  314. //
  315. // We cannot power down this controller
  316. //
  317. capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD0;
  318. capabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD0;
  319. capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD0;
  320. capabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
  321. //
  322. // Obviously wake is not supported on this legacy detected
  323. // piece of xxxx
  324. //
  325. capabilities->SystemWake = PowerSystemUnspecified;
  326. capabilities->DeviceWake = PowerDeviceUnspecified;
  327. capabilities->D1Latency = 0;
  328. capabilities->D2Latency = 0;
  329. capabilities->D3Latency = 0;
  330. status = STATUS_SUCCESS;
  331. } else {
  332. //
  333. // Either a PCI-PCMCIA bridge or PCI-Cardbus bridge
  334. // Send this down the stack to obtain the capabilities
  335. //
  336. ASSERT (fdoExtension->LowerDevice != NULL);
  337. status = PcmciaIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  338. *PassedDown = TRUE ;
  339. *NeedsRecompletion = TRUE ;
  340. }
  341. if (NT_SUCCESS(status)) {
  342. //
  343. // NOTE: HACKHACK:
  344. //
  345. // Here we provide an option to override the device wake of the pcmcia controller.
  346. // There are several controllers, notably TI 12xx controllers, which say they
  347. // can wake from D3, but really can effectively only do WOL from D2. That's because they
  348. // turn of socket power when put into D3. They fixed this on the TI 14xx line.
  349. //
  350. // So here we update the device wake field, and potentially the device states from the BIOS.
  351. // Note that this has to be used carefully, and only override a particular BIOS's settings
  352. // where it has been verified the device still works at the lower (more awake) device state.
  353. //
  354. if (PcmciaControllerDeviceWake) {
  355. if (PcmciaControllerDeviceWake < capabilities->DeviceWake) {
  356. capabilities->DeviceWake = PcmciaControllerDeviceWake;
  357. }
  358. if (PcmciaControllerDeviceWake < capabilities->DeviceState[PowerSystemSleeping1]) {
  359. capabilities->DeviceState[PowerSystemSleeping1] = PcmciaControllerDeviceWake;
  360. }
  361. if (PcmciaControllerDeviceWake < capabilities->DeviceState[PowerSystemSleeping2]) {
  362. capabilities->DeviceState[PowerSystemSleeping2] = PcmciaControllerDeviceWake;
  363. }
  364. if (PcmciaControllerDeviceWake < capabilities->DeviceState[PowerSystemSleeping3]) {
  365. capabilities->DeviceState[PowerSystemSleeping3] = PcmciaControllerDeviceWake;
  366. }
  367. }
  368. //
  369. // Cache the device capabilities in the device extension
  370. // for this pcmcia controller.
  371. //
  372. RtlCopyMemory(&fdoExtension->DeviceCapabilities,
  373. capabilities,
  374. sizeof(DEVICE_CAPABILITIES));
  375. } else {
  376. RtlZeroMemory(&fdoExtension->DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  377. }
  378. return status;
  379. }
  380. NTSTATUS
  381. PcmciaFdoFilterResourceRequirements(
  382. IN PDEVICE_OBJECT Fdo,
  383. IN PIRP Irp
  384. )
  385. /*++
  386. Routine Description
  387. Filters Resource requirements for PCMCIA controllers generated
  388. by the bus driver controlling the PDO for the PCMCIA controller.
  389. Currently adds memory range as an additional resource requirement
  390. since the BAR doesn't specify this
  391. Note for CardBus controllers:
  392. It is necessary to request an attribute memory window here for
  393. reading CIS of 16-bit PC-Cards - we need a 24 bit address for that,
  394. and this is the most elegant way of doing it - instead of
  395. special casing it in PCI driver
  396. Arguments
  397. DeviceExtension - Pointer to extension for the PCMCIA controller in question
  398. IoReqList - Pointer the the original resource requiremnts ejected by
  399. the bus driver
  400. FilteredRequirements - Pointer to the filtered resource req. list will be returned
  401. in this variable
  402. Return Value:
  403. STATUS_SUCCESS if filtering is successful
  404. Any other status - could not filter
  405. --*/
  406. {
  407. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  408. PIO_RESOURCE_REQUIREMENTS_LIST oldReqList;
  409. PIO_RESOURCE_REQUIREMENTS_LIST newReqList;
  410. PIO_RESOURCE_LIST oldList, newList;
  411. PIO_RESOURCE_DESCRIPTOR ioResourceDesc;
  412. ULONG newReqSize;
  413. ULONG oldlistSize, newlistSize, altListSize;
  414. ULONG index;
  415. ULONG IntCount = 0;
  416. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  417. NTSTATUS status;
  418. PAGED_CODE();
  419. status = PcmciaIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  420. if (!NT_SUCCESS(status)) {
  421. return status;
  422. }
  423. if (Irp->IoStatus.Information == 0) {
  424. oldReqList = irpStack->Parameters.FilterResourceRequirements.IoResourceRequirementList;
  425. if (oldReqList == NULL) {
  426. //
  427. // NULL List, nothing to do
  428. //
  429. return(Irp->IoStatus.Status);
  430. }
  431. } else {
  432. //
  433. // Use the returned list
  434. //
  435. oldReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)Irp->IoStatus.Information;
  436. }
  437. //
  438. // Add an alternative list without the IRQ requirement, if one exists. Model the
  439. // new alternative list after the first list.
  440. //
  441. oldList = oldReqList->List;
  442. ioResourceDesc = oldList->Descriptors;
  443. altListSize = 0;
  444. for (index = 0; index < oldList->Count; index++) {
  445. // Count the descriptors, excluding any IRQ descriptors
  446. if (ioResourceDesc->Type == CmResourceTypeInterrupt) {
  447. IntCount++;
  448. }
  449. ioResourceDesc++;
  450. }
  451. if (IntCount) {
  452. //
  453. // "+1" because we are adding two later, but IO_RESOURCE_LIST already has 1
  454. //
  455. altListSize = sizeof(IO_RESOURCE_LIST) + ((oldList->Count+1)-IntCount)*sizeof(IO_RESOURCE_DESCRIPTOR);
  456. }
  457. //
  458. // Add a memory range requirement to what we already have..
  459. //
  460. newReqSize = oldReqList->ListSize +
  461. oldReqList->AlternativeLists*2*sizeof(IO_RESOURCE_DESCRIPTOR) +
  462. altListSize;
  463. newReqList = ExAllocatePool(PagedPool, newReqSize);
  464. if (newReqList == NULL) {
  465. return STATUS_INSUFFICIENT_RESOURCES;
  466. }
  467. RtlCopyMemory(newReqList, oldReqList, FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List));
  468. newReqList->ListSize = newReqSize;
  469. newList = newReqList->List;
  470. oldList = oldReqList->List;
  471. for (index = 0; index < oldReqList->AlternativeLists; index++) {
  472. //
  473. // Compute the size of the current original list
  474. //
  475. oldlistSize = sizeof(IO_RESOURCE_LIST) + (oldList->Count-1) * sizeof(IO_RESOURCE_DESCRIPTOR);
  476. newlistSize = oldlistSize;
  477. RtlCopyMemory(newList, oldList, newlistSize);
  478. //
  479. // Add memory requirement
  480. //
  481. ioResourceDesc = (PIO_RESOURCE_DESCRIPTOR) (((PUCHAR) newList) + newlistSize);
  482. ioResourceDesc->Option = IO_RESOURCE_PREFERRED;
  483. ioResourceDesc->Type = CmResourceTypeMemory;
  484. ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  485. ioResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  486. ioResourceDesc->u.Memory.MinimumAddress.QuadPart = fdoExtension->AttributeMemoryLow;
  487. ioResourceDesc->u.Memory.MaximumAddress.QuadPart = fdoExtension->AttributeMemoryHigh;
  488. ioResourceDesc->u.Memory.Length = fdoExtension->AttributeMemorySize;
  489. ioResourceDesc->u.Memory.Alignment = fdoExtension->AttributeMemoryAlignment;
  490. ioResourceDesc++;
  491. //
  492. // The other - less restrictive - alternative.
  493. //
  494. ioResourceDesc->Option = IO_RESOURCE_ALTERNATIVE;
  495. ioResourceDesc->Type = CmResourceTypeMemory;
  496. ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  497. ioResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  498. ioResourceDesc->u.Memory.MinimumAddress.QuadPart = 0;
  499. if ((fdoExtension->Flags & PCMCIA_MEMORY_24BIT) == 0) {
  500. ioResourceDesc->u.Memory.MaximumAddress.QuadPart = 0xFFFFFFFF;
  501. } else {
  502. ioResourceDesc->u.Memory.MaximumAddress.QuadPart = 0xFFFFFF;
  503. }
  504. ioResourceDesc->u.Memory.Length = fdoExtension->AttributeMemorySize;
  505. ioResourceDesc->u.Memory.Alignment = fdoExtension->AttributeMemoryAlignment;
  506. newList->Count += 2;
  507. newlistSize += 2*sizeof(IO_RESOURCE_DESCRIPTOR);
  508. oldList = (PIO_RESOURCE_LIST) (((PUCHAR) oldList) + oldlistSize);
  509. newList = (PIO_RESOURCE_LIST) (((PUCHAR) newList) + newlistSize);
  510. }
  511. if (altListSize != 0) {
  512. PIO_RESOURCE_DESCRIPTOR oldResourceDesc;
  513. //
  514. // Here we add the alternate list which doesn't contain an IRQ requirement.
  515. // Note that we use the first "new list" as the "old list". This way, we
  516. // pick up the things we added in the previous loop. All we have to do is
  517. // copy every descriptor except for the interrupt descriptor.
  518. //
  519. // Note: newList is still set from previous loop
  520. //
  521. oldList = newReqList->List;
  522. //
  523. // First copy the basic structure without the descriptors
  524. //
  525. RtlCopyMemory(newList, oldList, sizeof(IO_RESOURCE_LIST) - sizeof(IO_RESOURCE_DESCRIPTOR));
  526. oldResourceDesc = oldList->Descriptors;
  527. ioResourceDesc = newList->Descriptors;
  528. for (index = 0; index < oldList->Count; index++) {
  529. if (oldResourceDesc->Type != CmResourceTypeInterrupt) {
  530. *ioResourceDesc = *oldResourceDesc;
  531. ioResourceDesc++;
  532. } else {
  533. //
  534. // We've deleted a descriptor
  535. //
  536. newList->Count--;
  537. }
  538. oldResourceDesc++;
  539. }
  540. newReqList->AlternativeLists++;
  541. }
  542. Irp->IoStatus.Information = (ULONG_PTR) newReqList;
  543. irpStack->Parameters.FilterResourceRequirements.IoResourceRequirementList =
  544. newReqList;
  545. //
  546. // Free up the old resource reqs
  547. //
  548. ExFreePool(oldReqList);
  549. fdoExtension->Flags |= PCMCIA_FILTER_ADDED_MEMORY;
  550. return STATUS_SUCCESS;
  551. }
  552. NTSTATUS
  553. PcmciaFdoGetHardwareIds(
  554. IN PDEVICE_OBJECT Fdo,
  555. OUT PUNICODE_STRING HardwareIds
  556. )
  557. /*++
  558. Routine description:
  559. This routine returns the hardware ids for the given 'legacy' pcmcia controller
  560. NOTE: this routine is required only for pcmcia controllers detected by this driver
  561. itself and registered via IoReportDetectedDevice.
  562. Arguments:
  563. Fdo - Pointer to the functional device object representing the pcmcia controller
  564. CompatibleIds - Pointer to the unicode string which would contain the hardware ids
  565. as a multi-string on return
  566. Return value:
  567. STATUS_SUCCESS
  568. Any other status - could not generate compatible ids
  569. --*/
  570. {
  571. PCSTR strings[2];
  572. PCMCIA_CONTROLLER_TYPE controllerType;
  573. ULONG count, index;
  574. BOOLEAN found;
  575. PAGED_CODE();
  576. controllerType = ((PFDO_EXTENSION)Fdo->DeviceExtension)->ControllerType;
  577. found = FALSE;
  578. for (index = 0; (PcmciaAdapterHardwareIds[index].ControllerType != PcmciaInvalidControllerType); index++) {
  579. if (PcmciaAdapterHardwareIds[index].ControllerType == controllerType) {
  580. found = TRUE;
  581. break;
  582. }
  583. }
  584. if (found) {
  585. strings[0] = PcmciaAdapterHardwareIds[index].Id;
  586. } else {
  587. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaGetAdapterHardwareIds: Could not find find hardware id for %x, controllerType %x\n",
  588. Fdo,
  589. controllerType
  590. ));
  591. strings[0] = "";
  592. }
  593. count = 1;
  594. return PcmciaStringsToMultiString(strings,
  595. count,
  596. HardwareIds);
  597. }
  598. NTSTATUS
  599. PcmciaFdoStartDevice(
  600. IN PDEVICE_OBJECT Fdo,
  601. IN PIRP Irp,
  602. OUT BOOLEAN *PassedDown,
  603. OUT BOOLEAN *NeedsRecompletion
  604. )
  605. /*++
  606. Routine Description:
  607. This routine will start the PCMCIA controller with the supplied
  608. resources. The IRP is sent down to the pdo first, so PCI or ISAPNP
  609. or whoever sits underneath gets a chance to program the controller
  610. to decode the resources.
  611. Arguments:
  612. Fdo - Functional device object of the PCMCIA controller
  613. Irp - Well, it's the start irp, yah?
  614. PassedDown - Contains FALSE on entry, which means caller must
  615. complete or pass down irp based on status. If set
  616. to TRUE, Irp may need to be re-completed...
  617. NeedsRecompletion - ...In which case this parameter will be checked
  618. Return value:
  619. Status
  620. --*/
  621. {
  622. NTSTATUS status;
  623. PFDO_EXTENSION deviceExtension = Fdo->DeviceExtension;
  624. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  625. PCM_RESOURCE_LIST resList, translatedResList, newResList, newTranslatedResList;
  626. PAGED_CODE();
  627. if (deviceExtension->Flags & PCMCIA_DEVICE_STARTED) {
  628. //
  629. // Start to already started device
  630. //
  631. DebugPrint((PCMCIA_DEBUG_FAIL,"PcmciaFdoStartDevice: Fdo %x already started\n",
  632. Fdo));
  633. return STATUS_SUCCESS;
  634. }
  635. //
  636. // Parse AllocatedResources & get IoPort/AttributeMemoryBase/IRQ info.
  637. //
  638. status = PcmciaFdoGetAssignedResources(irpStack->Parameters.StartDevice.AllocatedResources,
  639. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated,
  640. deviceExtension
  641. );
  642. if (!NT_SUCCESS(status)) {
  643. //
  644. // Ha. This is most likely a START for a madeup devnode (report-detected legacy PCMCIA controller)
  645. // which has been removed subsequently, hence not reported again with proper resources.
  646. // We return an appropriate status
  647. //
  648. DebugPrint((PCMCIA_DEBUG_FAIL, "Pcmcia: No resources assigned to FDO, probably bogus START for"
  649. "non-existent controller\n" ));
  650. return STATUS_NO_SUCH_DEVICE;
  651. }
  652. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x StartAdapter: AttrMem Base %x\n", Fdo, deviceExtension->PhysicalBase));
  653. DebugPrint((PCMCIA_DEBUG_PNP, " VirtualBase %x AttrMem Size %x\n", deviceExtension->AttributeMemoryBase, deviceExtension->AttributeMemorySize));
  654. if (deviceExtension->Flags & PCMCIA_FILTER_ADDED_MEMORY) {
  655. ULONG newSize;
  656. ULONG index;
  657. PCM_PARTIAL_RESOURCE_LIST resPartialList, translatedResPartialList;
  658. PCM_PARTIAL_RESOURCE_DESCRIPTOR resDesc, translatedResDesc;
  659. PCM_PARTIAL_RESOURCE_DESCRIPTOR newResDesc, newTranslatedResDesc;
  660. //
  661. // We need to remove the memory resource requirement
  662. //
  663. resList= irpStack->Parameters.StartDevice.AllocatedResources;
  664. resPartialList = &resList->List[0].PartialResourceList;
  665. translatedResList= irpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
  666. translatedResPartialList = &translatedResList->List[0].PartialResourceList;
  667. newSize = sizeof(CM_RESOURCE_LIST) + (resPartialList->Count-2)*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  668. newResList = ExAllocatePool(PagedPool,
  669. newSize);
  670. if (newResList == NULL) {
  671. return STATUS_INSUFFICIENT_RESOURCES;
  672. }
  673. newTranslatedResList = ExAllocatePool(PagedPool,
  674. newSize);
  675. if (newTranslatedResList == NULL) {
  676. ExFreePool(newResList);
  677. return STATUS_INSUFFICIENT_RESOURCES;
  678. }
  679. newResList->Count = newTranslatedResList->Count = 1;
  680. newResList->List[0].InterfaceType = resList->List[0].InterfaceType;
  681. newTranslatedResList->List[0].InterfaceType = translatedResList->List[0].InterfaceType;
  682. newResList->List[0].BusNumber = resList->List[0].BusNumber;
  683. newTranslatedResList->List[0].BusNumber = translatedResList->List[0].BusNumber;
  684. newResList->List[0].PartialResourceList.Version = resPartialList->Version;
  685. newResList->List[0].PartialResourceList.Revision = resPartialList->Revision;
  686. newResList->List[0].PartialResourceList.Count = resPartialList->Count - 1;
  687. newTranslatedResList->List[0].PartialResourceList.Version = translatedResPartialList->Version;
  688. newTranslatedResList->List[0].PartialResourceList.Revision = translatedResPartialList->Revision;
  689. newTranslatedResList->List[0].PartialResourceList.Count = translatedResPartialList->Count - 1;
  690. resDesc = resPartialList->PartialDescriptors;
  691. translatedResDesc = translatedResPartialList->PartialDescriptors;
  692. newResDesc = newResList->List[0].PartialResourceList.PartialDescriptors;
  693. newTranslatedResDesc = newTranslatedResList->List[0].PartialResourceList.PartialDescriptors;
  694. if (CardBusExtension(deviceExtension)) {
  695. //
  696. // Remove last memory descriptor - which is what we added
  697. //
  698. RtlCopyMemory(newResDesc,
  699. resDesc,
  700. newResList->List[0].PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  701. RtlCopyMemory(newTranslatedResDesc,
  702. translatedResDesc,
  703. newTranslatedResList->List[0].PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  704. } else {
  705. //
  706. // Remove the only memory descriptor..
  707. //
  708. for (index = 0; index < resPartialList->Count;
  709. index++, resDesc++, translatedResDesc++, newResDesc++, newTranslatedResDesc++) {
  710. if (resDesc->Type != CmResourceTypeMemory) {
  711. *newResDesc = *resDesc;
  712. *newTranslatedResDesc = *translatedResDesc;
  713. }
  714. }
  715. }
  716. irpStack->Parameters.StartDevice.AllocatedResources = newResList;
  717. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated = newTranslatedResList;
  718. }
  719. //
  720. // Send this down to the PDO first
  721. //
  722. status = PcmciaIoCallDriverSynchronous(deviceExtension->LowerDevice, Irp);
  723. *PassedDown = TRUE ;
  724. //
  725. // We set this because the completion routine returns
  726. // STATUS_MORE_PROCESSING_REQUIRED, which means it needs to be completed
  727. // again.
  728. //
  729. *NeedsRecompletion = TRUE ;
  730. if (deviceExtension->Flags & PCMCIA_FILTER_ADDED_MEMORY) {
  731. ExFreePool(newResList);
  732. ExFreePool(newTranslatedResList);
  733. irpStack->Parameters.StartDevice.AllocatedResources = resList;
  734. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated = translatedResList;
  735. }
  736. if (!NT_SUCCESS(status)) {
  737. return status;
  738. }
  739. //
  740. // Give the hardware some time to settle after returning from the pdo
  741. //
  742. PcmciaWait(256);
  743. //
  744. // Initialize the hardware
  745. //
  746. status = PcmciaStartPcmciaController(Fdo);
  747. if (NT_SUCCESS(status)) {
  748. deviceExtension->Flags |= PCMCIA_DEVICE_STARTED;
  749. }
  750. //
  751. // Remember if cardbus cards will be supported for this controller
  752. //
  753. if (CardBusExtension(deviceExtension) &&
  754. !PcmciaAreCardBusCardsSupported(deviceExtension)) {
  755. deviceExtension->Flags |= PCMCIA_CARDBUS_NOT_SUPPORTED;
  756. }
  757. return status;
  758. }
  759. NTSTATUS
  760. PcmciaFdoStopDevice(
  761. IN PDEVICE_OBJECT Fdo,
  762. IN PIRP Irp OPTIONAL,
  763. OUT BOOLEAN *PassedDown OPTIONAL,
  764. OUT BOOLEAN *NeedsRecompletion OPTIONAL
  765. )
  766. /*++
  767. Routine Description:
  768. IRP_MN_STOP_DEVICE handler for the given pcmcia controller.
  769. If Irp is present, it'll send it down first to the PDO.
  770. Unhooks the interrupt/cancels poll timer etc.
  771. Arguments:
  772. Fdo - Pointer to functional device object for the pcmcia
  773. controller
  774. Irp - If present it's the pointer to the stop Irp initiated
  775. by PnP
  776. PassedDown - Contains FALSE on entry, which means caller must
  777. complete or pass down irp based on status. If set
  778. to TRUE, Irp may need to be re-completed...
  779. NeedsRecompletion - ...In which case this parameter will be checked.
  780. Note: PassedDown and NeedsCompletion are ignored and
  781. optional only if Irp is NULL.
  782. Return value:
  783. STATUS_SUCCESS - Pcmcia controller successfully stopped
  784. Other - Stop failed
  785. --*/
  786. {
  787. PFDO_EXTENSION deviceExtension = Fdo->DeviceExtension;
  788. PSOCKET socket;
  789. NTSTATUS status;
  790. if (!(deviceExtension->Flags & PCMCIA_DEVICE_STARTED)) {
  791. //
  792. // Already stopped
  793. //
  794. return STATUS_SUCCESS;
  795. }
  796. PcmciaFdoDisarmWake(deviceExtension);
  797. //
  798. // Disable the interrupt
  799. //
  800. if (deviceExtension->PcmciaInterruptObject) {
  801. for (socket = deviceExtension->SocketList; socket; socket = socket->NextSocket) {
  802. //
  803. // Disable the controller interrupts
  804. //
  805. (*(socket->SocketFnPtr->PCBEnableDisableCardDetectEvent))(socket, FALSE);
  806. (*(socket->SocketFnPtr->PCBEnableDisableWakeupEvent))(socket, NULL, FALSE);
  807. //
  808. // Apparently IBM ThinkPads like this
  809. //
  810. PcmciaWait(PCMCIA_ENABLE_DELAY);
  811. }
  812. }
  813. //
  814. // the bus driver below us will make us go offline
  815. //
  816. deviceExtension->Flags |= PCMCIA_FDO_OFFLINE;
  817. //
  818. // clear pending event
  819. //
  820. KeCancelTimer(&deviceExtension->EventTimer);
  821. //
  822. // Send this down to the PDO
  823. //
  824. if (ARGUMENT_PRESENT(Irp)) {
  825. status = PcmciaIoCallDriverSynchronous(deviceExtension->LowerDevice, Irp);
  826. *PassedDown = TRUE ;
  827. *NeedsRecompletion = TRUE ;
  828. if (!NT_SUCCESS(status)) {
  829. return status;
  830. }
  831. }
  832. if (deviceExtension->Flags & PCMCIA_USE_POLLED_CSC) {
  833. //
  834. // cancel the card status change poller
  835. //
  836. KeCancelTimer(&deviceExtension->PollTimer);
  837. deviceExtension->Flags &= ~PCMCIA_USE_POLLED_CSC;
  838. }
  839. if (deviceExtension->PcmciaInterruptObject) {
  840. //
  841. // unhook the interrupt
  842. //
  843. IoDisconnectInterrupt(deviceExtension->PcmciaInterruptObject);
  844. deviceExtension->PcmciaInterruptObject = NULL;
  845. }
  846. //
  847. // Unmap any i/o space or memory we might have mapped
  848. //
  849. if (deviceExtension->Flags & PCMCIA_ATTRIBUTE_MEMORY_MAPPED) {
  850. MmUnmapIoSpace(deviceExtension->AttributeMemoryBase,
  851. deviceExtension->AttributeMemorySize);
  852. deviceExtension->Flags &= ~PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
  853. deviceExtension->AttributeMemoryBase = 0;
  854. deviceExtension->AttributeMemorySize = 0;
  855. }
  856. if (deviceExtension->Flags & PCMCIA_SOCKET_REGISTER_BASE_MAPPED) {
  857. MmUnmapIoSpace(deviceExtension->CardBusSocketRegisterBase,
  858. deviceExtension->CardBusSocketRegisterSize);
  859. deviceExtension->Flags &= ~PCMCIA_SOCKET_REGISTER_BASE_MAPPED;
  860. deviceExtension->CardBusSocketRegisterBase = 0;
  861. deviceExtension->CardBusSocketRegisterSize = 0;
  862. }
  863. deviceExtension->Flags &= ~PCMCIA_DEVICE_STARTED;
  864. return STATUS_SUCCESS;
  865. }
  866. NTSTATUS
  867. PcmciaFdoRemoveDevice(
  868. IN PDEVICE_OBJECT Fdo,
  869. IN PIRP Irp
  870. )
  871. /*++
  872. Routine Description:
  873. Handles IRP_MN_REMOVE for the pcmcia controller.
  874. Stops the adapter if it isn't already, sends the IRP
  875. to the PDO first & cleans up the Fdo for this controller
  876. and detaches & deletes the device object.
  877. Arguments:
  878. Fdo - Pointer to functional device object for the controller
  879. to be removed
  880. Return value:
  881. Status
  882. --*/
  883. {
  884. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  885. PDEVICE_OBJECT pdo, nextPdo, fdo, prevFdo;
  886. PPDO_EXTENSION pdoExtension;
  887. NTSTATUS status;
  888. UNREFERENCED_PARAMETER(Irp);
  889. if (fdoExtension->Flags & PCMCIA_DEVICE_STARTED) {
  890. //
  891. // Stop the fdo first.
  892. //
  893. PcmciaFdoStopDevice(Fdo, NULL, NULL, NULL);
  894. }
  895. //
  896. // Send this down to the PDO
  897. //
  898. status = PcmciaIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  899. if (!NT_SUCCESS(status)) {
  900. return status;
  901. }
  902. //
  903. // If the PdoList in the fdoExtension is non-empty it means:
  904. // that the PDOs in the list were not physically removed, but
  905. // a soft REMOVE was issued, hence they are still hanging on
  906. // and now this controller itself is being REMOVED.
  907. // Hence we dispose of those PDOs now
  908. //
  909. for (pdo = fdoExtension->PdoList; pdo != NULL ; pdo = nextPdo) {
  910. DebugPrint((PCMCIA_DEBUG_INFO,
  911. "RemoveDevice: pdo %x child of fdo %x was not removed before fdo\n",
  912. pdo, Fdo));
  913. pdoExtension = pdo->DeviceExtension;
  914. ASSERT (!IsDevicePhysicallyRemoved(pdoExtension));
  915. //
  916. // It's possible for this bit to be on, if the device was added,
  917. // but never started (because of some other error.
  918. //ASSERT (!IsDeviceAlive(pdoExtension));
  919. nextPdo = pdoExtension->NextPdoInFdoChain;
  920. if (!IsDeviceDeleted(pdoExtension)) {
  921. MarkDeviceDeleted(pdoExtension);
  922. PcmciaCleanupPdo(pdo);
  923. IoDeleteDevice(pdo);
  924. }
  925. }
  926. MarkDeviceDeleted(fdoExtension);
  927. PcmciaCleanupFdo(fdoExtension);
  928. //
  929. // Remove this from the fdo list..
  930. //
  931. prevFdo = NULL;
  932. for (fdo = FdoList; fdo != NULL; prevFdo = fdo, fdo = fdoExtension->NextFdo) {
  933. fdoExtension = fdo->DeviceExtension;
  934. if (fdo == Fdo) {
  935. if (prevFdo) {
  936. //
  937. // Delink this fdo
  938. //
  939. ((PFDO_EXTENSION)prevFdo->DeviceExtension)->NextFdo
  940. = fdoExtension->NextFdo;
  941. } else {
  942. FdoList = fdoExtension->NextFdo;
  943. }
  944. break;
  945. }
  946. }
  947. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x Remove detach & delete\n", Fdo));
  948. IoDetachDevice(((PFDO_EXTENSION)Fdo->DeviceExtension)->LowerDevice);
  949. IoDeleteDevice(Fdo);
  950. return STATUS_SUCCESS;
  951. }
  952. VOID
  953. PcmciaCleanupContext(
  954. IN PPCMCIA_CONTEXT pContext
  955. )
  956. /*++
  957. Routine Description
  958. Frees up allocated pool associated with a specific controller
  959. register context.
  960. Arguments
  961. pContext - pointer to a PCMCIA_CONTEXT structure
  962. Return value
  963. none
  964. --*/
  965. {
  966. pContext->RangeCount = 0;
  967. if (pContext->Range) {
  968. ExFreePool(pContext->Range);
  969. pContext->Range = NULL;
  970. }
  971. }
  972. VOID
  973. PcmciaCleanupFdo(
  974. IN PFDO_EXTENSION FdoExtension
  975. )
  976. /*++
  977. Routine Description
  978. Frees up allocated pool, deletes symbolic links etc. for the
  979. associated FDO for the pcmcia controller which is to be removed.
  980. Arguments
  981. FdoExtension - Pointer to the device extension for the FDO of the pcmcia controller
  982. which is being removed
  983. Return value
  984. none
  985. --*/
  986. {
  987. PSOCKET socket, nextSocket;
  988. //
  989. // Free the controller register context
  990. //
  991. PcmciaCleanupContext(&FdoExtension->PciContext);
  992. if (FdoExtension->PciContextBuffer) {
  993. ExFreePool(FdoExtension->PciContextBuffer);
  994. FdoExtension->PciContextBuffer = NULL;
  995. }
  996. PcmciaCleanupContext(&FdoExtension->CardbusContext);
  997. PcmciaCleanupContext(&FdoExtension->ExcaContext);
  998. //
  999. // Delete symbolic links to this fdo
  1000. //
  1001. if (FdoExtension->LinkName.Buffer != NULL) {
  1002. IoDeleteSymbolicLink(&FdoExtension->LinkName);
  1003. RtlFreeUnicodeString(&FdoExtension->LinkName);
  1004. }
  1005. //
  1006. // Cleanup the socket structures
  1007. //
  1008. for (socket = FdoExtension->SocketList; socket != NULL; socket = nextSocket) {
  1009. if (socket->CardbusContextBuffer) {
  1010. ExFreePool(socket->CardbusContextBuffer);
  1011. socket->CardbusContextBuffer = NULL;
  1012. }
  1013. if (socket->ExcaContextBuffer) {
  1014. ExFreePool(socket->ExcaContextBuffer);
  1015. socket->ExcaContextBuffer = NULL;
  1016. }
  1017. nextSocket = socket->NextSocket;
  1018. ExFreePool(socket);
  1019. }
  1020. FdoExtension->SocketList = NULL;
  1021. return;
  1022. }
  1023. NTSTATUS
  1024. PcmciaFdoGetAssignedResources(
  1025. IN PCM_RESOURCE_LIST ResourceList,
  1026. IN PCM_RESOURCE_LIST TranslatedResourceList,
  1027. IN PFDO_EXTENSION DeviceExtension
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Extracts the assigned resources to the pcmcia controller
  1032. Arguments:
  1033. ResourceList - Raw resource list
  1034. TranslatedResourceList
  1035. DeviceExtension - Device extension of the PCMCIA controller
  1036. Return value:
  1037. STATUS_SUCCESS
  1038. STATUS_UNSUCCESSFUL if resources are not right or enough.
  1039. --*/
  1040. {
  1041. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  1042. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  1043. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
  1044. ULONG addressSpace;
  1045. PHYSICAL_ADDRESS physicalAddress;
  1046. PHYSICAL_ADDRESS translatedAddress;
  1047. ULONG i;
  1048. ULONG attributeIndex;
  1049. PULONG devicePrivate;
  1050. BOOLEAN translated;
  1051. PAGED_CODE();
  1052. if ((ResourceList == NULL) || (ResourceList->Count <=0) ) {
  1053. return STATUS_UNSUCCESSFUL;
  1054. }
  1055. if (CardBusExtension(DeviceExtension)) {
  1056. fullResourceDesc=&TranslatedResourceList->List[0];
  1057. DeviceExtension->Configuration.InterfaceType = fullResourceDesc->InterfaceType;
  1058. DeviceExtension->Configuration.BusNumber = fullResourceDesc->BusNumber;
  1059. partialResourceList = &fullResourceDesc->PartialResourceList;
  1060. partialResourceDesc = partialResourceList->PartialDescriptors;
  1061. //
  1062. // We need just the exca register base
  1063. // According to PeterJ the first descriptor
  1064. // for us is the cardbus socket register base.
  1065. // We trust him.
  1066. for (i=0; (i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeMemory);
  1067. i++, partialResourceDesc++);
  1068. if (i >= partialResourceList->Count) {
  1069. return STATUS_UNSUCCESSFUL;
  1070. };
  1071. //
  1072. // This is memory. We need to map it
  1073. //
  1074. DeviceExtension->CardBusSocketRegisterBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
  1075. partialResourceDesc->u.Memory.Length,
  1076. FALSE);
  1077. DeviceExtension->CardBusSocketRegisterSize = partialResourceDesc->u.Memory.Length;
  1078. DeviceExtension->Flags |= PCMCIA_SOCKET_REGISTER_BASE_MAPPED;
  1079. //
  1080. // Last BAR is attribute memory window. This will be peeled off later.
  1081. // It might be a good idea to tack a device private on at the end to
  1082. // confirm this. However how do we guarantee our device private does
  1083. // not contain the same data as somebody else's? PnP is lacking here -
  1084. // we need some convention so that devices can set uniquely identifying stuff
  1085. // in there - like maybe the device object they own - to identify it is
  1086. // theirs. Till then this should do.
  1087. //
  1088. if (i > (partialResourceList->Count - 2)) {
  1089. //
  1090. // No more resources? Bail out.
  1091. //
  1092. return STATUS_INSUFFICIENT_RESOURCES;
  1093. }
  1094. for (i++, partialResourceDesc++; (i < (partialResourceList->Count - 1));i++,partialResourceDesc++);
  1095. //
  1096. // partialResourceDesc points to the last descriptor
  1097. //
  1098. ASSERT (partialResourceDesc->Type == CmResourceTypeMemory);
  1099. DeviceExtension->PhysicalBase = partialResourceDesc->u.Memory.Start;
  1100. //
  1101. // This is memory. We need to map it
  1102. //
  1103. DeviceExtension->AttributeMemoryBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
  1104. partialResourceDesc->u.Memory.Length,
  1105. FALSE);
  1106. DeviceExtension->AttributeMemorySize = partialResourceDesc->u.Memory.Length;
  1107. DeviceExtension->Flags |= PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
  1108. //
  1109. // Finally see if an IRQ is assigned
  1110. //
  1111. for (i = 0, partialResourceDesc = partialResourceList->PartialDescriptors;
  1112. (i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
  1113. i++,partialResourceDesc++);
  1114. if (i < partialResourceList->Count) {
  1115. //
  1116. // We have an interrupt to used for CSC
  1117. // PCI will ensure that this interrupt is exactly the
  1118. // same as the one assigned to the functional interrupt
  1119. // for a cardbus pc-card in this controller's socket
  1120. //
  1121. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaGetAssignedResources: Interrupt resource assigned\n"));
  1122. DeviceExtension->Configuration.TranslatedInterrupt = *partialResourceDesc;
  1123. //
  1124. // Get the raw interrupt resource - needed to enable the interrupt on the controller
  1125. //
  1126. fullResourceDesc=&ResourceList->List[0];
  1127. partialResourceList = &fullResourceDesc->PartialResourceList;
  1128. partialResourceDesc = partialResourceList->PartialDescriptors;
  1129. for (i=0; (i< partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
  1130. i++, partialResourceDesc++);
  1131. if (i < partialResourceList->Count) {
  1132. DeviceExtension->Configuration.Interrupt = *partialResourceDesc;
  1133. } else {
  1134. //
  1135. // Should not happen.. translated descriptor was present, but raw is missing!
  1136. // Just reset the translated interrupt and pretend no interrupt was assigned
  1137. //
  1138. RtlZeroMemory(&DeviceExtension->Configuration.TranslatedInterrupt, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  1139. }
  1140. }
  1141. } else {
  1142. //
  1143. // 16-bit pcmcia controller
  1144. //
  1145. fullResourceDesc=&ResourceList->List[0];
  1146. DeviceExtension->Configuration.InterfaceType = fullResourceDesc->InterfaceType;
  1147. DeviceExtension->Configuration.BusNumber = fullResourceDesc->BusNumber;
  1148. partialResourceList = &fullResourceDesc->PartialResourceList;
  1149. partialResourceDesc = partialResourceList->PartialDescriptors;
  1150. for (i=0; i<partialResourceList->Count; i++, partialResourceDesc++) {
  1151. devicePrivate = partialResourceDesc->u.DevicePrivate.Data;
  1152. switch (partialResourceDesc->Type) {
  1153. case CmResourceTypeInterrupt: {
  1154. if (DeviceExtension->ControllerType != PcmciaCLPD6729 &&
  1155. DeviceExtension->ControllerType != PcmciaPciPcmciaBridge &&
  1156. DeviceExtension->ControllerType != PcmciaNEC98 &&
  1157. DeviceExtension->ControllerType != PcmciaNEC98102) {
  1158. // We always poll for Cirrus Logic PCI to PCMCIA controllers
  1159. // and other PCI-PCMCIA bridges
  1160. //
  1161. DeviceExtension->Configuration.Interrupt = *partialResourceDesc;
  1162. }
  1163. break;
  1164. }
  1165. case CmResourceTypePort: {
  1166. DeviceExtension->Configuration.UntranslatedPortAddress = (USHORT) partialResourceDesc->u.Port.Start.QuadPart;
  1167. DeviceExtension->Configuration.PortSize = (USHORT) partialResourceDesc->u.Port.Length;
  1168. break;
  1169. }
  1170. case CmResourceTypeMemory: {
  1171. DeviceExtension->PhysicalBase = partialResourceDesc->u.Memory.Start;
  1172. DeviceExtension->AttributeMemorySize = partialResourceDesc->u.Memory.Length;
  1173. attributeIndex = i;
  1174. break;
  1175. }
  1176. }
  1177. }
  1178. if ((DeviceExtension->PhysicalBase.QuadPart == 0) ||
  1179. (DeviceExtension->Configuration.UntranslatedPortAddress == 0)) {
  1180. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaGetAssignedResources: Need both memory and i/o for pcmcia controller 0x%X\n",
  1181. DeviceExtension->DeviceObject));
  1182. return STATUS_INSUFFICIENT_RESOURCES;
  1183. }
  1184. fullResourceDesc=&TranslatedResourceList->List[0];
  1185. partialResourceList = &fullResourceDesc->PartialResourceList;
  1186. partialResourceDesc = &partialResourceList->PartialDescriptors[attributeIndex];
  1187. switch (partialResourceDesc->Type) {
  1188. case CmResourceTypeMemory:
  1189. DeviceExtension->AttributeMemoryBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
  1190. DeviceExtension->AttributeMemorySize,
  1191. FALSE);
  1192. DeviceExtension->Flags |= PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
  1193. break;
  1194. case CmResourceTypePort:
  1195. DeviceExtension->AttributeMemoryBase = (PUCHAR)(partialResourceDesc->u.Port.Start.QuadPart);
  1196. DeviceExtension->Flags &= ~PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
  1197. break;
  1198. default:
  1199. ASSERT(FALSE);
  1200. return STATUS_INSUFFICIENT_RESOURCES;
  1201. }
  1202. }
  1203. return STATUS_SUCCESS;
  1204. }
  1205. NTSTATUS
  1206. PcmciaAreCardBusCardsSupported(
  1207. IN PFDO_EXTENSION FdoExtension
  1208. )
  1209. /*++
  1210. Routine Description:
  1211. Indicates if cardbus cards will be supported on the given PCMCIA
  1212. controller on this system
  1213. Currently we support cardbus cards only on:
  1214. Machines on which BIOS programmed the bus numbers & IntLine
  1215. Arguments:
  1216. FdoExtension - Pointer to device extension for the pcmcia controller
  1217. Return Value:
  1218. TRUE - if cardbus cards are supported
  1219. FALSE - if not
  1220. --*/
  1221. {
  1222. UCHAR byte;
  1223. PAGED_CODE();
  1224. //
  1225. // Check int line
  1226. //
  1227. GetPciConfigSpace(FdoExtension,
  1228. CFGSPACE_INT_LINE,
  1229. &byte,
  1230. 1);
  1231. if (byte == 0xff) {
  1232. return FALSE;
  1233. }
  1234. //
  1235. // Check cardbus bus number
  1236. //
  1237. GetPciConfigSpace(FdoExtension,
  1238. CFGSPACE_CARDBUS_BUSNUM,
  1239. &byte,
  1240. 1);
  1241. if (byte == 0) {
  1242. return FALSE;
  1243. }
  1244. //
  1245. // Check subordinate bus number
  1246. //
  1247. GetPciConfigSpace(FdoExtension,
  1248. CFGSPACE_SUB_BUSNUM,
  1249. &byte,
  1250. 1);
  1251. if (byte == 0) {
  1252. return FALSE;
  1253. }
  1254. //
  1255. // All tests passed
  1256. //
  1257. return TRUE;
  1258. }