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.

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