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.

1606 lines
52 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. if (fdoExtension->Flags & PCMCIA_MEMORY_24BIT) {
  491. ioResourceDesc->u.Memory.MaximumAddress.QuadPart &= 0xFFFFFF;
  492. }
  493. ioResourceDesc++;
  494. //
  495. // The other - less restrictive - alternative.
  496. //
  497. ioResourceDesc->Option = IO_RESOURCE_ALTERNATIVE;
  498. ioResourceDesc->Type = CmResourceTypeMemory;
  499. ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  500. ioResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  501. ioResourceDesc->u.Memory.MinimumAddress.QuadPart = 0;
  502. ioResourceDesc->u.Memory.MaximumAddress.QuadPart = 0xFFFFFFFF;
  503. ioResourceDesc->u.Memory.Length = fdoExtension->AttributeMemorySize;
  504. ioResourceDesc->u.Memory.Alignment = fdoExtension->AttributeMemoryAlignment;
  505. if (fdoExtension->Flags & PCMCIA_MEMORY_24BIT) {
  506. ioResourceDesc->u.Memory.MaximumAddress.QuadPart &= 0xFFFFFF;
  507. }
  508. newList->Count += 2;
  509. newlistSize += 2*sizeof(IO_RESOURCE_DESCRIPTOR);
  510. oldList = (PIO_RESOURCE_LIST) (((PUCHAR) oldList) + oldlistSize);
  511. newList = (PIO_RESOURCE_LIST) (((PUCHAR) newList) + newlistSize);
  512. }
  513. if (altListSize != 0) {
  514. PIO_RESOURCE_DESCRIPTOR oldResourceDesc;
  515. //
  516. // Here we add the alternate list which doesn't contain an IRQ requirement.
  517. // Note that we use the first "new list" as the "old list". This way, we
  518. // pick up the things we added in the previous loop. All we have to do is
  519. // copy every descriptor except for the interrupt descriptor.
  520. //
  521. // Note: newList is still set from previous loop
  522. //
  523. oldList = newReqList->List;
  524. //
  525. // First copy the basic structure without the descriptors
  526. //
  527. RtlCopyMemory(newList, oldList, sizeof(IO_RESOURCE_LIST) - sizeof(IO_RESOURCE_DESCRIPTOR));
  528. oldResourceDesc = oldList->Descriptors;
  529. ioResourceDesc = newList->Descriptors;
  530. for (index = 0; index < oldList->Count; index++) {
  531. if (oldResourceDesc->Type != CmResourceTypeInterrupt) {
  532. *ioResourceDesc = *oldResourceDesc;
  533. ioResourceDesc++;
  534. } else {
  535. //
  536. // We've deleted a descriptor
  537. //
  538. newList->Count--;
  539. }
  540. oldResourceDesc++;
  541. }
  542. newReqList->AlternativeLists++;
  543. }
  544. Irp->IoStatus.Information = (ULONG_PTR) newReqList;
  545. irpStack->Parameters.FilterResourceRequirements.IoResourceRequirementList =
  546. newReqList;
  547. //
  548. // Free up the old resource reqs
  549. //
  550. ExFreePool(oldReqList);
  551. fdoExtension->Flags |= PCMCIA_FILTER_ADDED_MEMORY;
  552. return STATUS_SUCCESS;
  553. }
  554. NTSTATUS
  555. PcmciaFdoGetHardwareIds(
  556. IN PDEVICE_OBJECT Fdo,
  557. OUT PUNICODE_STRING HardwareIds
  558. )
  559. /*++
  560. Routine description:
  561. This routine returns the hardware ids for the given 'legacy' pcmcia controller
  562. NOTE: this routine is required only for pcmcia controllers detected by this driver
  563. itself and registered via IoReportDetectedDevice.
  564. Arguments:
  565. Fdo - Pointer to the functional device object representing the pcmcia controller
  566. CompatibleIds - Pointer to the unicode string which would contain the hardware ids
  567. as a multi-string on return
  568. Return value:
  569. STATUS_SUCCESS
  570. Any other status - could not generate compatible ids
  571. --*/
  572. {
  573. PCSTR strings[2];
  574. PCMCIA_CONTROLLER_TYPE controllerType;
  575. ULONG count, index;
  576. BOOLEAN found;
  577. PAGED_CODE();
  578. controllerType = ((PFDO_EXTENSION)Fdo->DeviceExtension)->ControllerType;
  579. found = FALSE;
  580. for (index = 0; (PcmciaAdapterHardwareIds[index].ControllerType != PcmciaInvalidControllerType); index++) {
  581. if (PcmciaAdapterHardwareIds[index].ControllerType == controllerType) {
  582. found = TRUE;
  583. break;
  584. }
  585. }
  586. if (found) {
  587. strings[0] = PcmciaAdapterHardwareIds[index].Id;
  588. } else {
  589. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaGetAdapterHardwareIds: Could not find find hardware id for %x, controllerType %x\n",
  590. Fdo,
  591. controllerType
  592. ));
  593. strings[0] = "";
  594. }
  595. count = 1;
  596. return PcmciaStringsToMultiString(strings,
  597. count,
  598. HardwareIds);
  599. }
  600. NTSTATUS
  601. PcmciaFdoStartDevice(
  602. IN PDEVICE_OBJECT Fdo,
  603. IN PIRP Irp,
  604. OUT BOOLEAN *PassedDown,
  605. OUT BOOLEAN *NeedsRecompletion
  606. )
  607. /*++
  608. Routine Description:
  609. This routine will start the PCMCIA controller with the supplied
  610. resources. The IRP is sent down to the pdo first, so PCI or ISAPNP
  611. or whoever sits underneath gets a chance to program the controller
  612. to decode the resources.
  613. Arguments:
  614. Fdo - Functional device object of the PCMCIA controller
  615. Irp - Well, it's the start irp, yah?
  616. PassedDown - Contains FALSE on entry, which means caller must
  617. complete or pass down irp based on status. If set
  618. to TRUE, Irp may need to be re-completed...
  619. NeedsRecompletion - ...In which case this parameter will be checked
  620. Return value:
  621. Status
  622. --*/
  623. {
  624. NTSTATUS status;
  625. PFDO_EXTENSION deviceExtension = Fdo->DeviceExtension;
  626. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  627. PCM_RESOURCE_LIST resList, translatedResList, newResList, newTranslatedResList;
  628. PAGED_CODE();
  629. if (deviceExtension->Flags & PCMCIA_DEVICE_STARTED) {
  630. //
  631. // Start to already started device
  632. //
  633. DebugPrint((PCMCIA_DEBUG_FAIL,"PcmciaFdoStartDevice: Fdo %x already started\n",
  634. Fdo));
  635. return STATUS_SUCCESS;
  636. }
  637. //
  638. // Parse AllocatedResources & get IoPort/AttributeMemoryBase/IRQ info.
  639. //
  640. status = PcmciaFdoGetAssignedResources(irpStack->Parameters.StartDevice.AllocatedResources,
  641. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated,
  642. deviceExtension
  643. );
  644. if (!NT_SUCCESS(status)) {
  645. //
  646. // Ha. This is most likely a START for a madeup devnode (report-detected legacy PCMCIA controller)
  647. // which has been removed subsequently, hence not reported again with proper resources.
  648. // We return an appropriate status
  649. //
  650. DebugPrint((PCMCIA_DEBUG_FAIL, "Pcmcia: No resources assigned to FDO, probably bogus START for"
  651. "non-existent controller\n" ));
  652. return STATUS_NO_SUCH_DEVICE;
  653. }
  654. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x StartAdapter: AttrMem Base %x\n", Fdo, deviceExtension->PhysicalBase));
  655. DebugPrint((PCMCIA_DEBUG_PNP, " VirtualBase %x AttrMem Size %x\n", deviceExtension->AttributeMemoryBase, deviceExtension->AttributeMemorySize));
  656. if (deviceExtension->Flags & PCMCIA_FILTER_ADDED_MEMORY) {
  657. ULONG newSize;
  658. ULONG index;
  659. PCM_PARTIAL_RESOURCE_LIST resPartialList, translatedResPartialList;
  660. PCM_PARTIAL_RESOURCE_DESCRIPTOR resDesc, translatedResDesc;
  661. PCM_PARTIAL_RESOURCE_DESCRIPTOR newResDesc, newTranslatedResDesc;
  662. //
  663. // We need to remove the memory resource requirement
  664. //
  665. resList= irpStack->Parameters.StartDevice.AllocatedResources;
  666. resPartialList = &resList->List[0].PartialResourceList;
  667. translatedResList= irpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
  668. translatedResPartialList = &translatedResList->List[0].PartialResourceList;
  669. newSize = sizeof(CM_RESOURCE_LIST) + (resPartialList->Count-2)*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  670. newResList = ExAllocatePool(PagedPool,
  671. newSize);
  672. if (newResList == NULL) {
  673. return STATUS_INSUFFICIENT_RESOURCES;
  674. }
  675. newTranslatedResList = ExAllocatePool(PagedPool,
  676. newSize);
  677. if (newTranslatedResList == NULL) {
  678. ExFreePool(newResList);
  679. return STATUS_INSUFFICIENT_RESOURCES;
  680. }
  681. newResList->Count = newTranslatedResList->Count = 1;
  682. newResList->List[0].InterfaceType = resList->List[0].InterfaceType;
  683. newTranslatedResList->List[0].InterfaceType = translatedResList->List[0].InterfaceType;
  684. newResList->List[0].BusNumber = resList->List[0].BusNumber;
  685. newTranslatedResList->List[0].BusNumber = translatedResList->List[0].BusNumber;
  686. newResList->List[0].PartialResourceList.Version = resPartialList->Version;
  687. newResList->List[0].PartialResourceList.Revision = resPartialList->Revision;
  688. newResList->List[0].PartialResourceList.Count = resPartialList->Count - 1;
  689. newTranslatedResList->List[0].PartialResourceList.Version = translatedResPartialList->Version;
  690. newTranslatedResList->List[0].PartialResourceList.Revision = translatedResPartialList->Revision;
  691. newTranslatedResList->List[0].PartialResourceList.Count = translatedResPartialList->Count - 1;
  692. resDesc = resPartialList->PartialDescriptors;
  693. translatedResDesc = translatedResPartialList->PartialDescriptors;
  694. newResDesc = newResList->List[0].PartialResourceList.PartialDescriptors;
  695. newTranslatedResDesc = newTranslatedResList->List[0].PartialResourceList.PartialDescriptors;
  696. if (CardBusExtension(deviceExtension)) {
  697. //
  698. // Remove last memory descriptor - which is what we added
  699. //
  700. RtlCopyMemory(newResDesc,
  701. resDesc,
  702. newResList->List[0].PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  703. RtlCopyMemory(newTranslatedResDesc,
  704. translatedResDesc,
  705. newTranslatedResList->List[0].PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  706. } else {
  707. //
  708. // Remove the only memory descriptor..
  709. //
  710. for (index = 0; index < resPartialList->Count;
  711. index++, resDesc++, translatedResDesc++, newResDesc++, newTranslatedResDesc++) {
  712. if (resDesc->Type != CmResourceTypeMemory) {
  713. *newResDesc = *resDesc;
  714. *newTranslatedResDesc = *translatedResDesc;
  715. }
  716. }
  717. }
  718. irpStack->Parameters.StartDevice.AllocatedResources = newResList;
  719. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated = newTranslatedResList;
  720. }
  721. //
  722. // Send this down to the PDO first
  723. //
  724. status = PcmciaIoCallDriverSynchronous(deviceExtension->LowerDevice, Irp);
  725. *PassedDown = TRUE ;
  726. //
  727. // We set this because the completion routine returns
  728. // STATUS_MORE_PROCESSING_REQUIRED, which means it needs to be completed
  729. // again.
  730. //
  731. *NeedsRecompletion = TRUE ;
  732. if (deviceExtension->Flags & PCMCIA_FILTER_ADDED_MEMORY) {
  733. ExFreePool(newResList);
  734. ExFreePool(newTranslatedResList);
  735. irpStack->Parameters.StartDevice.AllocatedResources = resList;
  736. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated = translatedResList;
  737. }
  738. if (!NT_SUCCESS(status)) {
  739. return status;
  740. }
  741. //
  742. // Give the hardware some time to settle after returning from the pdo
  743. //
  744. PcmciaWait(256);
  745. //
  746. // Initialize the hardware
  747. //
  748. status = PcmciaStartPcmciaController(Fdo);
  749. if (NT_SUCCESS(status)) {
  750. deviceExtension->Flags |= PCMCIA_DEVICE_STARTED;
  751. }
  752. //
  753. // Remember if cardbus cards will be supported for this controller
  754. //
  755. if (CardBusExtension(deviceExtension) &&
  756. !PcmciaAreCardBusCardsSupported(deviceExtension)) {
  757. deviceExtension->Flags |= PCMCIA_CARDBUS_NOT_SUPPORTED;
  758. }
  759. return status;
  760. }
  761. NTSTATUS
  762. PcmciaFdoStopDevice(
  763. IN PDEVICE_OBJECT Fdo,
  764. IN PIRP Irp OPTIONAL,
  765. OUT BOOLEAN *PassedDown OPTIONAL,
  766. OUT BOOLEAN *NeedsRecompletion OPTIONAL
  767. )
  768. /*++
  769. Routine Description:
  770. IRP_MN_STOP_DEVICE handler for the given pcmcia controller.
  771. If Irp is present, it'll send it down first to the PDO.
  772. Unhooks the interrupt/cancels poll timer etc.
  773. Arguments:
  774. Fdo - Pointer to functional device object for the pcmcia
  775. controller
  776. Irp - If present it's the pointer to the stop Irp initiated
  777. by PnP
  778. PassedDown - Contains FALSE on entry, which means caller must
  779. complete or pass down irp based on status. If set
  780. to TRUE, Irp may need to be re-completed...
  781. NeedsRecompletion - ...In which case this parameter will be checked.
  782. Note: PassedDown and NeedsCompletion are ignored and
  783. optional only if Irp is NULL.
  784. Return value:
  785. STATUS_SUCCESS - Pcmcia controller successfully stopped
  786. Other - Stop failed
  787. --*/
  788. {
  789. PFDO_EXTENSION deviceExtension = Fdo->DeviceExtension;
  790. PSOCKET socket;
  791. NTSTATUS status;
  792. if (!(deviceExtension->Flags & PCMCIA_DEVICE_STARTED)) {
  793. //
  794. // Already stopped
  795. //
  796. return STATUS_SUCCESS;
  797. }
  798. PcmciaFdoDisarmWake(deviceExtension);
  799. //
  800. // Disable the interrupt
  801. //
  802. if (deviceExtension->PcmciaInterruptObject) {
  803. for (socket = deviceExtension->SocketList; socket; socket = socket->NextSocket) {
  804. //
  805. // Disable the controller interrupts
  806. //
  807. (*(socket->SocketFnPtr->PCBEnableDisableCardDetectEvent))(socket, FALSE);
  808. (*(socket->SocketFnPtr->PCBEnableDisableWakeupEvent))(socket, NULL, FALSE);
  809. //
  810. // Apparently IBM ThinkPads like this
  811. //
  812. PcmciaWait(PCMCIA_ENABLE_DELAY);
  813. }
  814. }
  815. //
  816. // the bus driver below us will make us go offline
  817. //
  818. deviceExtension->Flags |= PCMCIA_FDO_OFFLINE;
  819. //
  820. // clear pending event
  821. //
  822. KeCancelTimer(&deviceExtension->EventTimer);
  823. //
  824. // Send this down to the PDO
  825. //
  826. if (ARGUMENT_PRESENT(Irp)) {
  827. status = PcmciaIoCallDriverSynchronous(deviceExtension->LowerDevice, Irp);
  828. *PassedDown = TRUE ;
  829. *NeedsRecompletion = TRUE ;
  830. if (!NT_SUCCESS(status)) {
  831. return status;
  832. }
  833. }
  834. if (deviceExtension->Flags & PCMCIA_USE_POLLED_CSC) {
  835. //
  836. // cancel the card status change poller
  837. //
  838. KeCancelTimer(&deviceExtension->PollTimer);
  839. deviceExtension->Flags &= ~PCMCIA_USE_POLLED_CSC;
  840. }
  841. if (deviceExtension->PcmciaInterruptObject) {
  842. //
  843. // unhook the interrupt
  844. //
  845. IoDisconnectInterrupt(deviceExtension->PcmciaInterruptObject);
  846. deviceExtension->PcmciaInterruptObject = NULL;
  847. }
  848. //
  849. // Unmap any i/o space or memory we might have mapped
  850. //
  851. if (deviceExtension->Flags & PCMCIA_ATTRIBUTE_MEMORY_MAPPED) {
  852. MmUnmapIoSpace(deviceExtension->AttributeMemoryBase,
  853. deviceExtension->AttributeMemorySize);
  854. deviceExtension->Flags &= ~PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
  855. deviceExtension->AttributeMemoryBase = 0;
  856. deviceExtension->AttributeMemorySize = 0;
  857. }
  858. if (deviceExtension->Flags & PCMCIA_SOCKET_REGISTER_BASE_MAPPED) {
  859. MmUnmapIoSpace(deviceExtension->CardBusSocketRegisterBase,
  860. deviceExtension->CardBusSocketRegisterSize);
  861. deviceExtension->Flags &= ~PCMCIA_SOCKET_REGISTER_BASE_MAPPED;
  862. deviceExtension->CardBusSocketRegisterBase = 0;
  863. deviceExtension->CardBusSocketRegisterSize = 0;
  864. }
  865. deviceExtension->Flags &= ~PCMCIA_DEVICE_STARTED;
  866. return STATUS_SUCCESS;
  867. }
  868. NTSTATUS
  869. PcmciaFdoRemoveDevice(
  870. IN PDEVICE_OBJECT Fdo,
  871. IN PIRP Irp
  872. )
  873. /*++
  874. Routine Description:
  875. Handles IRP_MN_REMOVE for the pcmcia controller.
  876. Stops the adapter if it isn't already, sends the IRP
  877. to the PDO first & cleans up the Fdo for this controller
  878. and detaches & deletes the device object.
  879. Arguments:
  880. Fdo - Pointer to functional device object for the controller
  881. to be removed
  882. Return value:
  883. Status
  884. --*/
  885. {
  886. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  887. PDEVICE_OBJECT pdo, nextPdo, fdo, prevFdo;
  888. PPDO_EXTENSION pdoExtension;
  889. NTSTATUS status;
  890. ULONG waitCount = 0;
  891. UNREFERENCED_PARAMETER(Irp);
  892. if (fdoExtension->Flags & PCMCIA_DEVICE_STARTED) {
  893. //
  894. // Stop the fdo first.
  895. //
  896. PcmciaFdoStopDevice(Fdo, NULL, NULL, NULL);
  897. }
  898. //
  899. // Send this down to the PDO
  900. //
  901. status = PcmciaIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  902. if (!NT_SUCCESS(status)) {
  903. return status;
  904. }
  905. //
  906. // Synchronize with power routines
  907. //
  908. while(!PCMCIA_TEST_AND_SET(&fdoExtension->DeletionLock)) {
  909. PcmciaWait(1000000);
  910. if (waitCount++ > PCMCIA_DELETION_TIMEOUT) {
  911. ASSERT(waitCount <= PCMCIA_DELETION_TIMEOUT);
  912. break;
  913. }
  914. }
  915. //
  916. // If the PdoList in the fdoExtension is non-empty it means:
  917. // that the PDOs in the list were not physically removed, but
  918. // a soft REMOVE was issued, hence they are still hanging on
  919. // and now this controller itself is being REMOVED.
  920. // Hence we dispose of those PDOs now
  921. //
  922. for (pdo = fdoExtension->PdoList; pdo != NULL ; pdo = nextPdo) {
  923. DebugPrint((PCMCIA_DEBUG_INFO,
  924. "RemoveDevice: pdo %x child of fdo %x was not removed before fdo\n",
  925. pdo, Fdo));
  926. pdoExtension = pdo->DeviceExtension;
  927. ASSERT (!IsDevicePhysicallyRemoved(pdoExtension));
  928. //
  929. // It's possible for this bit to be on, if the device was added,
  930. // but never started (because of some other error.
  931. //ASSERT (!IsDeviceAlive(pdoExtension));
  932. nextPdo = pdoExtension->NextPdoInFdoChain;
  933. if (!IsDeviceDeleted(pdoExtension)) {
  934. MarkDeviceDeleted(pdoExtension);
  935. PcmciaCleanupPdo(pdo);
  936. IoDeleteDevice(pdo);
  937. }
  938. }
  939. MarkDeviceDeleted(fdoExtension);
  940. PcmciaCleanupFdo(fdoExtension);
  941. //
  942. // Remove this from the fdo list..
  943. //
  944. prevFdo = NULL;
  945. for (fdo = FdoList; fdo != NULL; prevFdo = fdo, fdo = fdoExtension->NextFdo) {
  946. fdoExtension = fdo->DeviceExtension;
  947. if (fdo == Fdo) {
  948. if (prevFdo) {
  949. //
  950. // Delink this fdo
  951. //
  952. ((PFDO_EXTENSION)prevFdo->DeviceExtension)->NextFdo
  953. = fdoExtension->NextFdo;
  954. } else {
  955. FdoList = fdoExtension->NextFdo;
  956. }
  957. break;
  958. }
  959. }
  960. DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x Remove detach & delete\n", Fdo));
  961. IoDetachDevice(((PFDO_EXTENSION)Fdo->DeviceExtension)->LowerDevice);
  962. IoDeleteDevice(Fdo);
  963. return STATUS_SUCCESS;
  964. }
  965. VOID
  966. PcmciaCleanupContext(
  967. IN PPCMCIA_CONTEXT pContext
  968. )
  969. /*++
  970. Routine Description
  971. Frees up allocated pool associated with a specific controller
  972. register context.
  973. Arguments
  974. pContext - pointer to a PCMCIA_CONTEXT structure
  975. Return value
  976. none
  977. --*/
  978. {
  979. pContext->RangeCount = 0;
  980. if (pContext->Range) {
  981. ExFreePool(pContext->Range);
  982. pContext->Range = NULL;
  983. }
  984. }
  985. VOID
  986. PcmciaCleanupFdo(
  987. IN PFDO_EXTENSION FdoExtension
  988. )
  989. /*++
  990. Routine Description
  991. Frees up allocated pool, deletes symbolic links etc. for the
  992. associated FDO for the pcmcia controller which is to be removed.
  993. Arguments
  994. FdoExtension - Pointer to the device extension for the FDO of the pcmcia controller
  995. which is being removed
  996. Return value
  997. none
  998. --*/
  999. {
  1000. PSOCKET socket, nextSocket;
  1001. //
  1002. // Free the controller register context
  1003. //
  1004. PcmciaCleanupContext(&FdoExtension->PciContext);
  1005. if (FdoExtension->PciContextBuffer) {
  1006. ExFreePool(FdoExtension->PciContextBuffer);
  1007. FdoExtension->PciContextBuffer = NULL;
  1008. }
  1009. PcmciaCleanupContext(&FdoExtension->CardbusContext);
  1010. PcmciaCleanupContext(&FdoExtension->ExcaContext);
  1011. //
  1012. // Delete symbolic links to this fdo
  1013. //
  1014. if (FdoExtension->LinkName.Buffer != NULL) {
  1015. IoDeleteSymbolicLink(&FdoExtension->LinkName);
  1016. RtlFreeUnicodeString(&FdoExtension->LinkName);
  1017. }
  1018. //
  1019. // Cleanup the socket structures
  1020. //
  1021. for (socket = FdoExtension->SocketList; socket != NULL; socket = nextSocket) {
  1022. if (socket->CardbusContextBuffer) {
  1023. ExFreePool(socket->CardbusContextBuffer);
  1024. socket->CardbusContextBuffer = NULL;
  1025. }
  1026. if (socket->ExcaContextBuffer) {
  1027. ExFreePool(socket->ExcaContextBuffer);
  1028. socket->ExcaContextBuffer = NULL;
  1029. }
  1030. nextSocket = socket->NextSocket;
  1031. ExFreePool(socket);
  1032. }
  1033. FdoExtension->SocketList = NULL;
  1034. return;
  1035. }
  1036. NTSTATUS
  1037. PcmciaFdoGetAssignedResources(
  1038. IN PCM_RESOURCE_LIST ResourceList,
  1039. IN PCM_RESOURCE_LIST TranslatedResourceList,
  1040. IN PFDO_EXTENSION DeviceExtension
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. Extracts the assigned resources to the pcmcia controller
  1045. Arguments:
  1046. ResourceList - Raw resource list
  1047. TranslatedResourceList
  1048. DeviceExtension - Device extension of the PCMCIA controller
  1049. Return value:
  1050. STATUS_SUCCESS
  1051. STATUS_UNSUCCESSFUL if resources are not right or enough.
  1052. --*/
  1053. {
  1054. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  1055. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  1056. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
  1057. ULONG addressSpace;
  1058. PHYSICAL_ADDRESS physicalAddress;
  1059. PHYSICAL_ADDRESS translatedAddress;
  1060. ULONG i;
  1061. ULONG attributeIndex;
  1062. PULONG devicePrivate;
  1063. BOOLEAN translated;
  1064. PAGED_CODE();
  1065. if ((ResourceList == NULL) || (ResourceList->Count <=0) ) {
  1066. return STATUS_UNSUCCESSFUL;
  1067. }
  1068. if (CardBusExtension(DeviceExtension)) {
  1069. fullResourceDesc=&TranslatedResourceList->List[0];
  1070. DeviceExtension->Configuration.InterfaceType = fullResourceDesc->InterfaceType;
  1071. DeviceExtension->Configuration.BusNumber = fullResourceDesc->BusNumber;
  1072. partialResourceList = &fullResourceDesc->PartialResourceList;
  1073. partialResourceDesc = partialResourceList->PartialDescriptors;
  1074. //
  1075. // We need just the exca register base
  1076. // According to PeterJ the first descriptor
  1077. // for us is the cardbus socket register base.
  1078. // We trust him.
  1079. for (i=0; (i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeMemory);
  1080. i++, partialResourceDesc++);
  1081. if (i >= partialResourceList->Count) {
  1082. return STATUS_UNSUCCESSFUL;
  1083. };
  1084. //
  1085. // This is memory. We need to map it
  1086. //
  1087. DeviceExtension->CardBusSocketRegisterBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
  1088. partialResourceDesc->u.Memory.Length,
  1089. FALSE);
  1090. DeviceExtension->CardBusSocketRegisterSize = partialResourceDesc->u.Memory.Length;
  1091. DeviceExtension->Flags |= PCMCIA_SOCKET_REGISTER_BASE_MAPPED;
  1092. //
  1093. // Last BAR is attribute memory window. This will be peeled off later.
  1094. // It might be a good idea to tack a device private on at the end to
  1095. // confirm this. However how do we guarantee our device private does
  1096. // not contain the same data as somebody else's? PnP is lacking here -
  1097. // we need some convention so that devices can set uniquely identifying stuff
  1098. // in there - like maybe the device object they own - to identify it is
  1099. // theirs. Till then this should do.
  1100. //
  1101. if (i > (partialResourceList->Count - 2)) {
  1102. //
  1103. // No more resources? Bail out.
  1104. //
  1105. return STATUS_INSUFFICIENT_RESOURCES;
  1106. }
  1107. for (i++, partialResourceDesc++; (i < (partialResourceList->Count - 1));i++,partialResourceDesc++);
  1108. //
  1109. // partialResourceDesc points to the last descriptor
  1110. //
  1111. ASSERT (partialResourceDesc->Type == CmResourceTypeMemory);
  1112. DeviceExtension->PhysicalBase = partialResourceDesc->u.Memory.Start;
  1113. //
  1114. // This is memory. We need to map it
  1115. //
  1116. DeviceExtension->AttributeMemoryBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
  1117. partialResourceDesc->u.Memory.Length,
  1118. FALSE);
  1119. DeviceExtension->AttributeMemorySize = partialResourceDesc->u.Memory.Length;
  1120. DeviceExtension->Flags |= PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
  1121. //
  1122. // Finally see if an IRQ is assigned
  1123. //
  1124. for (i = 0, partialResourceDesc = partialResourceList->PartialDescriptors;
  1125. (i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
  1126. i++,partialResourceDesc++);
  1127. if (i < partialResourceList->Count) {
  1128. //
  1129. // We have an interrupt to used for CSC
  1130. // PCI will ensure that this interrupt is exactly the
  1131. // same as the one assigned to the functional interrupt
  1132. // for a cardbus pc-card in this controller's socket
  1133. //
  1134. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaGetAssignedResources: Interrupt resource assigned\n"));
  1135. DeviceExtension->Configuration.TranslatedInterrupt = *partialResourceDesc;
  1136. //
  1137. // Get the raw interrupt resource - needed to enable the interrupt on the controller
  1138. //
  1139. fullResourceDesc=&ResourceList->List[0];
  1140. partialResourceList = &fullResourceDesc->PartialResourceList;
  1141. partialResourceDesc = partialResourceList->PartialDescriptors;
  1142. for (i=0; (i< partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
  1143. i++, partialResourceDesc++);
  1144. if (i < partialResourceList->Count) {
  1145. DeviceExtension->Configuration.Interrupt = *partialResourceDesc;
  1146. } else {
  1147. //
  1148. // Should not happen.. translated descriptor was present, but raw is missing!
  1149. // Just reset the translated interrupt and pretend no interrupt was assigned
  1150. //
  1151. RtlZeroMemory(&DeviceExtension->Configuration.TranslatedInterrupt, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  1152. }
  1153. }
  1154. } else {
  1155. //
  1156. // 16-bit pcmcia controller
  1157. //
  1158. fullResourceDesc=&ResourceList->List[0];
  1159. DeviceExtension->Configuration.InterfaceType = fullResourceDesc->InterfaceType;
  1160. DeviceExtension->Configuration.BusNumber = fullResourceDesc->BusNumber;
  1161. partialResourceList = &fullResourceDesc->PartialResourceList;
  1162. partialResourceDesc = partialResourceList->PartialDescriptors;
  1163. for (i=0; i<partialResourceList->Count; i++, partialResourceDesc++) {
  1164. devicePrivate = partialResourceDesc->u.DevicePrivate.Data;
  1165. switch (partialResourceDesc->Type) {
  1166. case CmResourceTypeInterrupt: {
  1167. if (DeviceExtension->ControllerType != PcmciaCLPD6729 &&
  1168. DeviceExtension->ControllerType != PcmciaPciPcmciaBridge &&
  1169. DeviceExtension->ControllerType != PcmciaNEC98 &&
  1170. DeviceExtension->ControllerType != PcmciaNEC98102) {
  1171. // We always poll for Cirrus Logic PCI to PCMCIA controllers
  1172. // and other PCI-PCMCIA bridges
  1173. //
  1174. DeviceExtension->Configuration.Interrupt = *partialResourceDesc;
  1175. }
  1176. break;
  1177. }
  1178. case CmResourceTypePort: {
  1179. DeviceExtension->Configuration.UntranslatedPortAddress = (USHORT) partialResourceDesc->u.Port.Start.QuadPart;
  1180. DeviceExtension->Configuration.PortSize = (USHORT) partialResourceDesc->u.Port.Length;
  1181. break;
  1182. }
  1183. case CmResourceTypeMemory: {
  1184. DeviceExtension->PhysicalBase = partialResourceDesc->u.Memory.Start;
  1185. DeviceExtension->AttributeMemorySize = partialResourceDesc->u.Memory.Length;
  1186. attributeIndex = i;
  1187. break;
  1188. }
  1189. }
  1190. }
  1191. if ((DeviceExtension->PhysicalBase.QuadPart == 0) ||
  1192. (DeviceExtension->Configuration.UntranslatedPortAddress == 0)) {
  1193. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaGetAssignedResources: Need both memory and i/o for pcmcia controller 0x%X\n",
  1194. DeviceExtension->DeviceObject));
  1195. return STATUS_INSUFFICIENT_RESOURCES;
  1196. }
  1197. fullResourceDesc=&TranslatedResourceList->List[0];
  1198. partialResourceList = &fullResourceDesc->PartialResourceList;
  1199. partialResourceDesc = &partialResourceList->PartialDescriptors[attributeIndex];
  1200. switch (partialResourceDesc->Type) {
  1201. case CmResourceTypeMemory:
  1202. DeviceExtension->AttributeMemoryBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
  1203. DeviceExtension->AttributeMemorySize,
  1204. FALSE);
  1205. DeviceExtension->Flags |= PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
  1206. break;
  1207. case CmResourceTypePort:
  1208. DeviceExtension->AttributeMemoryBase = (PUCHAR)(partialResourceDesc->u.Port.Start.QuadPart);
  1209. DeviceExtension->Flags &= ~PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
  1210. break;
  1211. default:
  1212. ASSERT(FALSE);
  1213. return STATUS_INSUFFICIENT_RESOURCES;
  1214. }
  1215. }
  1216. return STATUS_SUCCESS;
  1217. }
  1218. NTSTATUS
  1219. PcmciaAreCardBusCardsSupported(
  1220. IN PFDO_EXTENSION FdoExtension
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. Indicates if cardbus cards will be supported on the given PCMCIA
  1225. controller on this system
  1226. Currently we support cardbus cards only on:
  1227. Machines on which BIOS programmed the bus numbers & IntLine
  1228. Arguments:
  1229. FdoExtension - Pointer to device extension for the pcmcia controller
  1230. Return Value:
  1231. TRUE - if cardbus cards are supported
  1232. FALSE - if not
  1233. --*/
  1234. {
  1235. UCHAR byte;
  1236. PAGED_CODE();
  1237. //
  1238. // Check int line
  1239. //
  1240. GetPciConfigSpace(FdoExtension,
  1241. CFGSPACE_INT_LINE,
  1242. &byte,
  1243. 1);
  1244. if (byte == 0xff) {
  1245. return FALSE;
  1246. }
  1247. //
  1248. // Check cardbus bus number
  1249. //
  1250. GetPciConfigSpace(FdoExtension,
  1251. CFGSPACE_CARDBUS_BUSNUM,
  1252. &byte,
  1253. 1);
  1254. if (byte == 0) {
  1255. return FALSE;
  1256. }
  1257. //
  1258. // Check subordinate bus number
  1259. //
  1260. GetPciConfigSpace(FdoExtension,
  1261. CFGSPACE_SUB_BUSNUM,
  1262. &byte,
  1263. 1);
  1264. if (byte == 0) {
  1265. return FALSE;
  1266. }
  1267. //
  1268. // All tests passed
  1269. //
  1270. return TRUE;
  1271. }