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.

943 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. enum.c
  5. Abstract:
  6. This module contains the bus enum code for Pcmcia driver
  7. Authors:
  8. Ravisankar Pudipeddi (ravisp) 10/15/96
  9. Neil Sandlin (neilsa) 1-Jun-1999
  10. Environment:
  11. Kernel mode only
  12. Notes:
  13. Revision History:
  14. --*/
  15. #include "pch.h"
  16. //
  17. // Internal References
  18. //
  19. NTSTATUS
  20. PcmciaEnumerateDevices(
  21. IN PDEVICE_OBJECT Fdo,
  22. IN PIRP Irp
  23. );
  24. NTSTATUS
  25. PcmciaEnumerateCardBusCard(
  26. IN PSOCKET socket,
  27. IN PIRP Irp
  28. );
  29. NTSTATUS
  30. PcmciaEnumerateR2Card(
  31. IN PSOCKET socket
  32. );
  33. NTSTATUS
  34. PcmciaCreatePdo(
  35. IN PDEVICE_OBJECT Fdo,
  36. IN PSOCKET Socket,
  37. OUT PDEVICE_OBJECT *PdoPtr
  38. );
  39. VOID
  40. PcmciaSetPowerFromConfigData(
  41. IN PSOCKET Socket,
  42. IN PDEVICE_OBJECT Pdo
  43. );
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text(PAGE, PcmciaEnumerateDevices)
  46. #pragma alloc_text(PAGE, PcmciaEnumerateCardBusCard)
  47. #pragma alloc_text(PAGE, PcmciaCreatePdo)
  48. #pragma alloc_text(PAGE, PcmciaDeviceRelations)
  49. #endif
  50. NTSTATUS
  51. PcmciaEnumerateDevices(
  52. IN PDEVICE_OBJECT Fdo,
  53. IN PIRP Irp
  54. )
  55. /*++
  56. Routine Description:
  57. This enumerates the pcmcia bus which is represented by Fdo (a pointer to the device object representing
  58. the pcmcia controller. It creates new PDOs for any new PC-Cards which have been discovered
  59. since the last enumeration
  60. Notes:
  61. Because a user can yank a pccard at any time, the enumeration code only updates the current socket
  62. status after PnP has had a chance to gracefully remove the device. Specifically, if a surprise remove
  63. happens, then a number of things has to happen:
  64. - power has to be reset on the socket
  65. - bridge windows need to be closed
  66. - if cardbus, PCI.SYS needs to be informed
  67. The problem is that we can't do these things immediately here. Instead, on a surprise remove, we
  68. check to see if there is still state that has yet to be cleared. If so, we report the socket as
  69. empty, and bail out, even if another card has been inserted (or the same card re-inserted). Later,
  70. the remove code will cause a new enumeration call, at which point we can update the state and honestly
  71. report the new device.
  72. Arguments:
  73. Fdo - Pointer to the functional device object for the PCMCIA controller which needs to be enumerated
  74. Return value:
  75. None
  76. --*/
  77. {
  78. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  79. PPDO_EXTENSION pdoExtension = NULL;
  80. PDEVICE_OBJECT pdo;
  81. PSOCKET socket;
  82. NTSTATUS status = STATUS_SUCCESS;
  83. ULONG i;
  84. PAGED_CODE();
  85. DebugPrint((PCMCIA_DEBUG_ENUM, "fdo %08x enumerate devices\n", Fdo));
  86. for (socket = fdoExtension->SocketList; socket != NULL; socket = socket->NextSocket) {
  87. if (!IsSocketFlagSet(socket, SOCKET_CARD_STATUS_CHANGE)) {
  88. //
  89. // return previous results
  90. //
  91. DebugPrint((PCMCIA_DEBUG_ENUM, "fdo %08x skt %08x No status change\n", Fdo, socket));
  92. continue;
  93. }
  94. ResetDeviceFlag(fdoExtension, PCMCIA_FDO_DISABLE_AUTO_POWEROFF);
  95. //
  96. // The socket either has a new card, or the card has been
  97. // removed. Either way, the old pdo list on this socket, if
  98. // it exists, will now be thrown away.
  99. //
  100. for (pdo = socket->PdoList; pdo!=NULL; pdo=pdoExtension->NextPdoInSocket) {
  101. pdoExtension = pdo->DeviceExtension;
  102. DebugPrint((PCMCIA_DEBUG_INFO, "fdo %08x enumeration marking pdo %08x REMOVED\n", Fdo, pdo));
  103. MarkDevicePhysicallyRemoved(pdoExtension);
  104. }
  105. if (fdoExtension->PciCardBusDeviceContext != NULL) {
  106. //
  107. // If we previously had a cardbus card, and that status has changed,
  108. // let PCI learn about the empty slot. If there is currently a
  109. // cardbus card in the slot then PCI found out anyway.
  110. //
  111. status = (*fdoExtension->PciCardBusInterface.DispatchPnp)(fdoExtension->PciCardBusDeviceContext, Irp);
  112. }
  113. //
  114. // Check to see if we are waiting on a remove to finish cleaning up the socket. If so,
  115. // then don't enumerate anything just yet. Let the remove happen, and enumerate later.
  116. //
  117. if (socket->Flags & SOCKET_CLEANUP_MASK) {
  118. socket->Flags |= SOCKET_ENUMERATE_PENDING;
  119. DebugPrint((PCMCIA_DEBUG_ENUM, "fdo %08x skt %08x Enumeration deferred! Waiting on remove\n", Fdo, socket));
  120. continue;
  121. }
  122. //
  123. // Update the current socket status
  124. //
  125. PcmciaGetSocketStatus(socket);
  126. //
  127. // Now that we are committed to enumerating the card, this can be reset
  128. //
  129. ResetSocketFlag(socket, SOCKET_CARD_STATUS_CHANGE);
  130. //
  131. // Cleanup PCI state if we learn that the status has changed
  132. //
  133. if (fdoExtension->PciCardBusDeviceContext != NULL) {
  134. //
  135. // Let pci clean up
  136. //
  137. (*fdoExtension->PciCardBusInterface.DeleteCardBus)(fdoExtension->PciCardBusDeviceContext);
  138. fdoExtension->PciCardBusDeviceContext = NULL;
  139. if (IsDeviceFlagSet(fdoExtension, PCMCIA_INT_ROUTE_INTERFACE)) {
  140. //
  141. // Here is one might dereference the interface, that is if that
  142. // ever had any affect, which it doesn't.
  143. //
  144. ResetDeviceFlag(fdoExtension, PCMCIA_INT_ROUTE_INTERFACE);
  145. }
  146. }
  147. if (!IsCardInSocket(socket)) {
  148. //
  149. // This socket is empty, continue
  150. //
  151. DebugPrint((PCMCIA_DEBUG_ENUM, "fdo %08x skt %08x Socket is empty\n", Fdo, socket));
  152. continue;
  153. }
  154. //
  155. // If this is a cardbus card, check to see if we can run it
  156. //
  157. if (IsCardBusCardInSocket(socket) && IsDeviceFlagSet(fdoExtension, PCMCIA_CARDBUS_NOT_SUPPORTED)) {
  158. if (!IsSocketFlagSet(socket, SOCKET_SUPPORT_MESSAGE_SENT)) {
  159. SetSocketFlag(socket, SOCKET_SUPPORT_MESSAGE_SENT);
  160. PcmciaReportControllerError(fdoExtension, STATUS_CARDBUS_NOT_SUPPORTED);
  161. }
  162. continue;
  163. }
  164. //
  165. // Some cards may be in a funky state, particularly if the machine crashed
  166. // previously... power is shown to be on, but the device won't respond. The fix is
  167. // to force power off first.
  168. //
  169. if (!IsDeviceFlagSet(fdoExtension, PCMCIA_FDO_ON_DEBUG_PATH)) {
  170. //
  171. // Fool SetSocketPower into actually powering off the card no matter what
  172. // state it thinks it is in
  173. //
  174. SetSocketFlag(socket, SOCKET_CARD_POWERED_UP);
  175. PcmciaSetSocketPower(socket, NULL, NULL, PCMCIA_POWEROFF);
  176. }
  177. //
  178. // Power up the socket so the device(s) can be enumerated
  179. //
  180. if (!NT_SUCCESS(PcmciaSetSocketPower(socket, NULL, NULL, PCMCIA_POWERON))) {
  181. //
  182. // Tell the user there was an error
  183. //
  184. PcmciaLogError(fdoExtension, PCMCIA_DEVICE_POWER_ERROR, 1, 0);
  185. continue;
  186. }
  187. //
  188. // Card found here - but no Pdo for it
  189. // We create a new pdo for the card & initialize the
  190. // socket to point to it.
  191. //
  192. if (IsCardBusCardInSocket(socket)) {
  193. //
  194. // 32-bit cardbus card. Enum via PCI
  195. //
  196. status = PcmciaEnumerateCardBusCard(socket, Irp);
  197. } else {
  198. //
  199. // R2 card
  200. //
  201. status = PcmciaEnumerateR2Card(socket);
  202. }
  203. if (!NT_SUCCESS(status)) {
  204. DebugPrint((PCMCIA_DEBUG_FAIL, "fdo %08x CardBus enumeration failed: %x\n", Fdo, status));
  205. //
  206. // Tell the user there was an error
  207. //
  208. PcmciaSetSocketPower(socket, NULL, NULL, PCMCIA_POWEROFF);
  209. PcmciaLogError(fdoExtension, PCMCIA_DEVICE_ENUMERATION_ERROR, 1, 0);
  210. continue;
  211. }
  212. PcmciaSetPowerFromConfigData(socket, fdoExtension->PdoList);
  213. }
  214. fdoExtension->LivePdoCount = 0;
  215. for (pdo = fdoExtension->PdoList; pdo != NULL; pdo = pdoExtension->NextPdoInFdoChain) {
  216. pdoExtension = pdo->DeviceExtension;
  217. if (!IsDevicePhysicallyRemoved(pdoExtension)) {
  218. fdoExtension->LivePdoCount++;
  219. }
  220. }
  221. DebugPrint((PCMCIA_DEBUG_ENUM, "fdo %08x live pdo count = %d\n", Fdo, fdoExtension->LivePdoCount));
  222. if (fdoExtension->LivePdoCount == 0) {
  223. //
  224. // Hint for the controller to check if it should turn itself off
  225. //
  226. PcmciaFdoCheckForIdle(fdoExtension);
  227. }
  228. return status;
  229. }
  230. VOID
  231. PcmciaSetPowerFromConfigData(
  232. IN PSOCKET Socket,
  233. IN PDEVICE_OBJECT Pdo
  234. )
  235. /*++
  236. Routine Description:
  237. This routine will reset the socket power if the CIS of the device contains
  238. more specific power requirements than is shown on the controller hardware.
  239. Arguments
  240. Return value
  241. None
  242. --*/
  243. {
  244. PPDO_EXTENSION pdoExtension;
  245. PSOCKET_DATA socketData;
  246. BOOLEAN powerChange = FALSE;
  247. pdoExtension = Pdo->DeviceExtension;
  248. socketData = pdoExtension->SocketData;
  249. //
  250. // Only change Vcc if we are lowering it
  251. //
  252. if (socketData->Vcc && (socketData->Vcc < Socket->Vcc)) {
  253. //
  254. // Here we should check the controller if it can support the requested
  255. // voltage. This isn't implemented, so just hard-wire a check for 5v
  256. // and 3.3v.
  257. //
  258. if ((socketData->Vcc == 50) || (socketData->Vcc == 33)) {
  259. powerChange = TRUE;
  260. Socket->Vcc = socketData->Vcc;
  261. }
  262. }
  263. if (socketData->Vpp1 && (socketData->Vpp1 != Socket->Vpp1)) {
  264. powerChange = TRUE;
  265. Socket->Vpp1 = socketData->Vpp1;
  266. }
  267. if (socketData->Vpp2 && (socketData->Vpp2 != Socket->Vpp2)) {
  268. powerChange = TRUE;
  269. Socket->Vpp2 = socketData->Vpp2;
  270. }
  271. if (powerChange) {
  272. PcmciaSetSocketPower(Socket, NULL, NULL, PCMCIA_POWEROFF);
  273. PcmciaSetSocketPower(Socket, NULL, NULL, PCMCIA_POWERON);
  274. }
  275. }
  276. NTSTATUS
  277. PcmciaEnumerateCardBusCard(
  278. IN PSOCKET socket,
  279. IN PIRP Irp
  280. )
  281. /*++
  282. Routine Description:
  283. This enumerates the cardbus card present in the given cardbus controller
  284. Note: this routine effectively parties on Irp->IoStatus.Information. This
  285. value should not be relied upon after return from this routine.
  286. Arguments
  287. socket - pointer to the socket structure which contains the cardbus card
  288. Irp - Enumeration irp (IRP_MN_DEVICE_RELATIONS) sent to the controller
  289. Return value
  290. Status
  291. --*/
  292. {
  293. PFDO_EXTENSION FdoExtension = socket->DeviceExtension;
  294. PDEVICE_OBJECT Fdo = FdoExtension->DeviceObject;
  295. PVOID deviceContext;
  296. NTSTATUS status;
  297. ULONG i;
  298. PDEVICE_RELATIONS deviceRelations;
  299. PAGED_CODE();
  300. //
  301. // We should have already done a delete on any previous context
  302. //
  303. ASSERT(FdoExtension->PciCardBusDeviceContext == NULL);
  304. ASSERT(!IsDeviceFlagSet(FdoExtension, PCMCIA_INT_ROUTE_INTERFACE));
  305. //
  306. // Call PCI's private AddDevice routine to
  307. // indicate it needs to play a role in enumerating
  308. // cardbus cards
  309. //
  310. status = (*FdoExtension->PciCardBusInterface.AddCardBus)(FdoExtension->Pdo, &deviceContext);
  311. FdoExtension->PciCardBusDeviceContext = deviceContext;
  312. if (!NT_SUCCESS(status)) {
  313. return status;
  314. }
  315. status = PcmciaGetInterface(FdoExtension->Pdo,
  316. &GUID_INT_ROUTE_INTERFACE_STANDARD,
  317. sizeof(INT_ROUTE_INTERFACE_STANDARD),
  318. (PINTERFACE) &FdoExtension->PciIntRouteInterface
  319. );
  320. if (NT_SUCCESS(status)) {
  321. SetDeviceFlag(FdoExtension, PCMCIA_INT_ROUTE_INTERFACE);
  322. }
  323. //
  324. // Call PCI repeatedly till the card is enumerated.
  325. //
  326. // We don't let PCI report what has already been reported
  327. //
  328. Irp->IoStatus.Information = 0;
  329. status = STATUS_DEVICE_NOT_READY;
  330. for (i = 0; i < CARDBUS_CONFIG_RETRY_COUNT; i++) {
  331. status = (*FdoExtension->PciCardBusInterface.DispatchPnp)(deviceContext, Irp);
  332. if (!NT_SUCCESS(status)) {
  333. //
  334. // PCI failed this IRP for some reason.
  335. //
  336. break;
  337. }
  338. deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  339. if ((deviceRelations == NULL) ||
  340. ((deviceRelations)->Count <= 0)) {
  341. //
  342. // This is the problem case: try again
  343. //
  344. DebugPrint((PCMCIA_DEBUG_ENUM, "fdo %08x Pci enumerated ZERO device objects\n", FdoExtension->DeviceObject));
  345. status = STATUS_DEVICE_NOT_READY;
  346. } else {
  347. //
  348. // Cardbus card is enumerated, get out of this loop
  349. //
  350. DebugPrint((PCMCIA_DEBUG_ENUM, "fdo %08x Pci enumerated %d device object(s)\n",
  351. FdoExtension->DeviceObject, (deviceRelations)->Count));
  352. status = STATUS_SUCCESS;
  353. break;
  354. }
  355. }
  356. if (!NT_SUCCESS(status)) {
  357. //
  358. // Let pci clean up
  359. //
  360. (*FdoExtension->PciCardBusInterface.DeleteCardBus)(FdoExtension->PciCardBusDeviceContext);
  361. FdoExtension->PciCardBusDeviceContext = NULL;
  362. ResetDeviceFlag(FdoExtension, PCMCIA_INT_ROUTE_INTERFACE);
  363. return status;
  364. }
  365. ASSERT (deviceRelations && (deviceRelations->Count > 0));
  366. for (i = 0; i < deviceRelations->Count; i++) {
  367. PDEVICE_OBJECT pdo;
  368. PPDO_EXTENSION pdoExtension;
  369. //
  370. // Create a filter device for this pci owned pdo
  371. //
  372. status = PcmciaCreatePdo(Fdo, socket, &pdo);
  373. if (!NT_SUCCESS(status)) {
  374. //
  375. // Cleanup allocated socket data structures, if any
  376. //
  377. DebugPrint((PCMCIA_DEBUG_FAIL, "fdo %08x create pdo failed %08x\n", Fdo, status));
  378. continue;
  379. }
  380. DebugPrint((PCMCIA_DEBUG_INFO, "fdo %08x created pdo %08x (cardbus)\n", Fdo, pdo));
  381. pdoExtension = pdo->DeviceExtension;
  382. //
  383. // Layer ourselves on top of the PCI ejected pdo
  384. //
  385. pdoExtension->PciPdo = deviceRelations->Objects[i];
  386. MarkDeviceCardBus(pdoExtension);
  387. if (!NT_SUCCESS(PcmciaGetInterface(pdoExtension->PciPdo,
  388. &GUID_BUS_INTERFACE_STANDARD,
  389. sizeof(BUS_INTERFACE_STANDARD),
  390. (PINTERFACE) &pdoExtension->PciBusInterface))) {
  391. ASSERT(FALSE);
  392. }
  393. GetPciConfigSpace(pdoExtension,
  394. CFGSPACE_VENDOR_ID,
  395. &pdoExtension->CardBusId,
  396. sizeof(ULONG));
  397. DebugPrint((PCMCIA_DEBUG_ENUM, "pdo %08x CardBusId %08x\n", pdo, pdoExtension->CardBusId));
  398. //
  399. // Make the intline register of this cardbus card match the parent
  400. //
  401. PcmciaUpdateInterruptLine(pdoExtension, FdoExtension);
  402. //
  403. // See if there is any CIS data we may need
  404. //
  405. PcmciaGetConfigData(pdoExtension);
  406. //
  407. // Attach to stack
  408. //
  409. pdoExtension->LowerDevice = IoAttachDeviceToDeviceStack(pdo, deviceRelations->Objects[i]);
  410. //
  411. // Link this to the flat chain of PDOs hanging off the controller's extension
  412. //
  413. pdoExtension->NextPdoInFdoChain = FdoExtension->PdoList;
  414. FdoExtension->PdoList = pdo;
  415. pdoExtension->NextPdoInSocket = socket->PdoList;
  416. socket->PdoList = pdo;
  417. pdo->Flags &= ~DO_DEVICE_INITIALIZING;
  418. }
  419. //
  420. // Make the current socket point to the head of the pdo list off this socket
  421. //
  422. socket->NumberOfFunctions = (UCHAR) deviceRelations->Count;
  423. if (socket->NumberOfFunctions > 1) {
  424. //
  425. // This socket has a multifunction card in it
  426. //
  427. SetSocketFlag(socket, SOCKET_CARD_MULTIFUNCTION);
  428. }
  429. FdoExtension->PciAddCardBusCount = deviceRelations->Count;
  430. SetSocketFlag(socket, SOCKET_CLEANUP_PENDING);
  431. ExFreePool(deviceRelations);
  432. return status;
  433. }
  434. NTSTATUS
  435. PcmciaEnumerateR2Card(
  436. IN PSOCKET socket
  437. )
  438. /*++
  439. Routine Description:
  440. This enumerates the R2 card present in the given PCMCIA controller,
  441. and updates the internal structures to reflect the new card state.
  442. Arguments
  443. socket - pointer to the socket structure which contains the R2 card
  444. Return value
  445. Status
  446. --*/
  447. {
  448. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  449. PDEVICE_OBJECT Fdo = fdoExtension->DeviceObject;
  450. PDEVICE_OBJECT pdo;
  451. PPDO_EXTENSION pdoExtension = NULL;
  452. UCHAR DeviceType;
  453. NTSTATUS status;
  454. status = PcmciaCreatePdo(Fdo, socket, &pdo);
  455. if (!NT_SUCCESS(status)) {
  456. return status;
  457. }
  458. DebugPrint((PCMCIA_DEBUG_ENUM, "fdo %08x created PDO %08x (R2)\n", Fdo, pdo));
  459. //
  460. // initialize the pointers
  461. //
  462. pdoExtension = pdo->DeviceExtension;
  463. //
  464. // Add a reference count on the socket for power
  465. //
  466. PcmciaRequestSocketPower(pdoExtension, NULL);
  467. //
  468. // Get configuration info
  469. //
  470. status = PcmciaGetConfigData(pdoExtension);
  471. if (!NT_SUCCESS(status)) {
  472. DebugPrint((PCMCIA_DEBUG_FAIL, "socket %08x GetConfigData failed %08x\n", socket, status));
  473. MarkDeviceDeleted(pdoExtension);
  474. IoDeleteDevice(pdo);
  475. return status;
  476. }
  477. DebugPrint((PCMCIA_DEBUG_ENUM, "pdo %08x R2 CardId %x-%x-%x\n", pdo,
  478. pdoExtension->SocketData->ManufacturerCode,
  479. pdoExtension->SocketData->ManufacturerInfo,
  480. pdoExtension->SocketData->CisCrc
  481. ));
  482. //
  483. // Make the socket point to the head of the pdo's hanging off this socket
  484. //
  485. socket->PdoList = pdo;
  486. //
  487. // Link this to the flat chain of PDOs hanging off the controller's extension
  488. //
  489. pdoExtension->NextPdoInFdoChain = fdoExtension->PdoList;
  490. fdoExtension->PdoList = pdo;
  491. //
  492. // Remember if this is a multifunction card in the
  493. // parent pdo itself
  494. //
  495. if (socket->NumberOfFunctions > 1) {
  496. //
  497. // This is a multifunction card
  498. //
  499. MarkDeviceMultifunction(pdoExtension);
  500. }
  501. pdo->Flags &= ~DO_DEVICE_INITIALIZING;
  502. ASSERT(pdoExtension->SocketData);
  503. DeviceType = pdoExtension->SocketData->DeviceType;
  504. if (DeviceType == PCCARD_TYPE_MODEM ||
  505. DeviceType == PCCARD_TYPE_SERIAL ||
  506. DeviceType == PCCARD_TYPE_NETWORK ||
  507. DeviceType == PCCARD_TYPE_MULTIFUNCTION3) {
  508. //
  509. // We want power IRPs at < DPC_LEVEL
  510. //
  511. pdo->Flags |= DO_POWER_PAGABLE;
  512. }
  513. SetSocketFlag(socket, SOCKET_CLEANUP_PENDING);
  514. return status;
  515. }
  516. NTSTATUS
  517. PcmciaDeviceRelations(
  518. IN PDEVICE_OBJECT Fdo,
  519. IN PIRP Irp,
  520. IN DEVICE_RELATION_TYPE RelationType,
  521. OUT PDEVICE_RELATIONS *DeviceRelations
  522. )
  523. /*++
  524. Routine Description:
  525. This routine will force enumeration of the PCMCIA controller represented by Fdo,
  526. allocate a device relations structure and fill in the count and object array with
  527. referenced object pointers to the valid PDOs which are created during enumeration
  528. Arguments:
  529. Fdo - a pointer to the functional device object being enumerated
  530. Irp - pointer to the Irp
  531. RelationType - Type of relationship to be retrieved
  532. DeviceRelations - Structure to store the device relations
  533. --*/
  534. {
  535. PDEVICE_OBJECT currentPdo;
  536. PPDO_EXTENSION currentPdoExtension;
  537. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  538. ULONG newRelationsSize, oldRelationsSize = 0;
  539. PDEVICE_RELATIONS deviceRelations = NULL, oldDeviceRelations;
  540. ULONG i;
  541. ULONG count;
  542. NTSTATUS status;
  543. PAGED_CODE();
  544. //
  545. // Handle only bus, ejection & removal relations for now
  546. //
  547. if (RelationType != BusRelations &&
  548. RelationType != RemovalRelations) {
  549. DebugPrint((PCMCIA_DEBUG_INFO,
  550. "PcmciaDeviceRelations: RelationType %d, not handled\n",
  551. (USHORT) RelationType));
  552. return STATUS_NOT_SUPPORTED;
  553. }
  554. //
  555. // Need reenumeration only if bus relations are required
  556. // We need to save the pointer to the old device relations
  557. // before we call PcmciaReenumerateDevices, as it might trample
  558. // on it
  559. //
  560. oldDeviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  561. // I don't understand how this can be non-null, so I added this
  562. // assert to find out.
  563. ASSERT(oldDeviceRelations == NULL);
  564. if (RelationType == BusRelations) {
  565. status = PcmciaEnumerateDevices(Fdo, Irp);
  566. if (!NT_SUCCESS(status)) {
  567. return status;
  568. }
  569. }
  570. if ((fdoExtension->LivePdoCount == 0) ||
  571. (RelationType == RemovalRelations)) {
  572. //
  573. // No PDO's to report, we can return early.
  574. // If no device_relations structure has yet been allocated, however,
  575. // we need to allocate one & set the count to zero. This will ensure
  576. // that regardless of whether we pass this IRP down or not, the IO
  577. // subsystem won't barf.
  578. //
  579. if (oldDeviceRelations == NULL) {
  580. *DeviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
  581. if (*DeviceRelations == NULL) {
  582. return STATUS_INSUFFICIENT_RESOURCES;
  583. }
  584. (*DeviceRelations)->Count = 0;
  585. (*DeviceRelations)->Objects[0] = NULL;
  586. }
  587. return STATUS_SUCCESS;
  588. }
  589. if (!(oldDeviceRelations) || (oldDeviceRelations->Count == 0)) {
  590. newRelationsSize = sizeof(DEVICE_RELATIONS)+(fdoExtension->LivePdoCount - 1)
  591. * sizeof(PDEVICE_OBJECT);
  592. } else {
  593. oldRelationsSize = sizeof(DEVICE_RELATIONS) +
  594. (oldDeviceRelations->Count-1) * sizeof(PDEVICE_OBJECT);
  595. newRelationsSize = oldRelationsSize + fdoExtension->LivePdoCount
  596. * sizeof(PDEVICE_OBJECT);
  597. }
  598. deviceRelations = ExAllocatePool(PagedPool, newRelationsSize);
  599. if (deviceRelations == NULL) {
  600. DebugPrint((PCMCIA_DEBUG_FAIL,
  601. "PcmciaDeviceRelations: unable to allocate %d bytes for device relations\n",
  602. newRelationsSize));
  603. return STATUS_INSUFFICIENT_RESOURCES;
  604. }
  605. if (oldDeviceRelations) {
  606. if ((oldDeviceRelations)->Count > 0) {
  607. RtlCopyMemory(deviceRelations, oldDeviceRelations, oldRelationsSize);
  608. }
  609. count = oldDeviceRelations->Count; // May be zero
  610. ExFreePool (oldDeviceRelations);
  611. } else {
  612. count = 0;
  613. }
  614. //
  615. // Copy the object pointers into the structure
  616. //
  617. for (currentPdo = fdoExtension->PdoList ;currentPdo != NULL;
  618. currentPdo = currentPdoExtension->NextPdoInFdoChain) {
  619. currentPdoExtension = currentPdo->DeviceExtension;
  620. if (!IsDevicePhysicallyRemoved(currentPdoExtension)) {
  621. //
  622. // Return PCI pdo if it's a cardbus card
  623. //
  624. if (IsCardBusCard(currentPdoExtension)) {
  625. ASSERT(currentPdoExtension->PciPdo != NULL);
  626. //
  627. // Return the PDO provided by PCI instead of our filter
  628. //
  629. deviceRelations->Objects[count++] = currentPdoExtension->PciPdo;
  630. status = ObReferenceObjectByPointer(currentPdoExtension->PciPdo,
  631. 0,
  632. NULL,
  633. KernelMode);
  634. } else {
  635. //
  636. // Devices have to be referenced by the bus driver
  637. // before returning them to PNP
  638. //
  639. deviceRelations->Objects[count++] = currentPdo;
  640. status = ObReferenceObjectByPointer(currentPdo,
  641. 0,
  642. NULL,
  643. KernelMode);
  644. }
  645. if (!NT_SUCCESS(status)) {
  646. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaDeviceRelations: status %#08lx "
  647. "while referencing object %#08lx\n",
  648. status,
  649. currentPdo));
  650. }
  651. }
  652. }
  653. deviceRelations->Count = count;
  654. *DeviceRelations = deviceRelations;
  655. return STATUS_SUCCESS;
  656. }
  657. NTSTATUS
  658. PcmciaCreatePdo(
  659. IN PDEVICE_OBJECT Fdo,
  660. IN PSOCKET Socket,
  661. OUT PDEVICE_OBJECT *PdoPtr
  662. )
  663. /*++
  664. Routine Description:
  665. Creates and initializes a device object - which will be referred to as a Physical Device
  666. Object or PDO - for the PC-Card in the socket represented by Socket, hanging off the PCMCIA
  667. controller represented by Fdo.
  668. Arguments:
  669. Fdo - Functional device object representing the PCMCIA controller
  670. Socket - Socket in which the PC-Card for which we're creating a PDO resides
  671. PdoPtr - Pointer to an area of memory where the created PDO is returned
  672. Return value:
  673. STATUS_SUCCESS - Pdo creation/initialization successful, PdoPtr contains the pointer
  674. to the Pdo
  675. Any other status - creation/initialization unsuccessful
  676. --*/
  677. {
  678. ULONG pdoNameIndex = 0, socketNumber;
  679. PSOCKET currentSocket;
  680. PPDO_EXTENSION pdoExtension;
  681. PFDO_EXTENSION fdoExtension=Fdo->DeviceExtension;
  682. char deviceName[128];
  683. ANSI_STRING ansiName;
  684. UNICODE_STRING unicodeName;
  685. NTSTATUS status;
  686. PAGED_CODE();
  687. //
  688. // Locate socket 'number'
  689. //
  690. for (currentSocket=fdoExtension->SocketList, socketNumber=0;
  691. currentSocket && (currentSocket != Socket);
  692. currentSocket = currentSocket->NextSocket, socketNumber++);
  693. //
  694. // Allocate space for the Unicode string:(handles upto 0xFFFF
  695. // devices for now :)
  696. //
  697. sprintf(deviceName, "%s%d-%d", PCMCIA_PCCARD_NAME,socketNumber, 0xFFFF);
  698. RtlInitAnsiString(&ansiName, deviceName);
  699. status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, TRUE);
  700. if (!NT_SUCCESS(status)) {
  701. return status;
  702. }
  703. //
  704. // Attempt to create the device with a unique name
  705. //
  706. do {
  707. sprintf(deviceName, "%s%d-%d", PCMCIA_PCCARD_NAME,socketNumber, pdoNameIndex++);
  708. RtlInitAnsiString(&ansiName, deviceName);
  709. status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, FALSE);
  710. if (!NT_SUCCESS(status)) {
  711. RtlFreeUnicodeString(&unicodeName);
  712. return status;
  713. }
  714. status = IoCreateDevice(
  715. Fdo->DriverObject,
  716. sizeof(PDO_EXTENSION),
  717. &unicodeName,
  718. FILE_DEVICE_UNKNOWN,
  719. 0,
  720. FALSE,
  721. PdoPtr
  722. );
  723. } while ((status == STATUS_OBJECT_NAME_EXISTS) ||
  724. (status == STATUS_OBJECT_NAME_COLLISION));
  725. RtlFreeUnicodeString(&unicodeName);
  726. if (!NT_SUCCESS(status)) {
  727. return status;
  728. }
  729. //
  730. // Initialize the device extension for the PDO
  731. //
  732. pdoExtension = (*PdoPtr)->DeviceExtension;
  733. RtlZeroMemory(pdoExtension, sizeof(PDO_EXTENSION));
  734. pdoExtension->Signature = PCMCIA_PDO_EXTENSION_SIGNATURE;
  735. pdoExtension->DeviceObject = *PdoPtr;
  736. pdoExtension->Socket = Socket;
  737. pdoExtension->SpecifiedDeviceType = PCCARD_TYPE_RESERVED;
  738. //
  739. // Initialize power states
  740. //
  741. pdoExtension->SystemPowerState = PowerSystemWorking;
  742. pdoExtension->DevicePowerState = PowerDeviceD0;
  743. //
  744. // Initialize pending enable objects
  745. //
  746. KeInitializeTimer(&pdoExtension->ConfigurationTimer);
  747. KeInitializeDpc(&pdoExtension->ConfigurationDpc,
  748. PcmciaConfigurationWorker,
  749. pdoExtension);
  750. KeInitializeTimer(&pdoExtension->PowerWorkerTimer);
  751. KeInitializeDpc(&pdoExtension->PowerWorkerDpc,
  752. PcmciaPdoPowerWorkerDpc,
  753. pdoExtension);
  754. //
  755. // PNP is going to mark the PDO as a DO_BUS_ENUMERATED_DEVICE,
  756. // but for CardBus cards- the PDO we return is owned by PCI.
  757. // Hence we need to mark this device object (in that case a
  758. // filter on top of PCI's PDO) as PDO explicitly.
  759. //
  760. MARK_AS_PDO(*PdoPtr);
  761. return STATUS_SUCCESS;
  762. }