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.

576 lines
16 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. pdocb.c
  5. Abstract:
  6. This module contains the code to handle
  7. the IRP_MJ_PNP dispatches for the PDOs
  8. for cardbus devices
  9. Authors:
  10. Ravisankar Pudipeddi (ravisp)
  11. Neil Sandlin (neilsa) 1-Jun-1999
  12. Environment:
  13. Kernel mode only
  14. Notes:
  15. Revision History:
  16. --*/
  17. #include "pch.h"
  18. //
  19. // Internal References
  20. //
  21. NTSTATUS
  22. PcmciaStartCardBusCard(
  23. IN PDEVICE_OBJECT Pdo,
  24. IN OUT PIRP Irp
  25. );
  26. NTSTATUS
  27. PcmciaRemoveCardBusCard(
  28. IN PDEVICE_OBJECT Pdo,
  29. IN PIRP Irp
  30. );
  31. NTSTATUS
  32. PcmciaQueryCardBusCardResourceRequirements(
  33. IN PDEVICE_OBJECT Pdo,
  34. IN PIRP Irp
  35. );
  36. NTSTATUS
  37. PcmciaQueryCardBusCardCapabilities(
  38. IN PDEVICE_OBJECT Pdo,
  39. IN PIRP Irp
  40. );
  41. #ifdef ALLOC_PRAGMA
  42. #pragma alloc_text(PAGE, PcmciaPdoCardBusPnPDispatch)
  43. #pragma alloc_text(PAGE, PcmciaStartCardBusCard)
  44. #pragma alloc_text(PAGE, PcmciaRemoveCardBusCard)
  45. #pragma alloc_text(PAGE, PcmciaQueryCardBusCardResourceRequirements)
  46. #pragma alloc_text(PAGE, PcmciaQueryCardBusCardCapabilities)
  47. #endif
  48. NTSTATUS
  49. PcmciaPdoCardBusPnPDispatch(
  50. IN PDEVICE_OBJECT Pdo,
  51. IN PIRP Irp
  52. )
  53. /*++
  54. Routine Description:
  55. This routine handles pnp requests for the filter object for CardBus devices.
  56. Arguments:
  57. Pdo - pointer to the physical device object
  58. Irp - pointer to the io request packet
  59. Return Value:
  60. status
  61. --*/
  62. {
  63. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  64. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  65. NTSTATUS status = STATUS_NOT_SUPPORTED;
  66. PAGED_CODE();
  67. ASSERT (pdoExtension->LowerDevice);
  68. #if DBG
  69. if (irpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
  70. DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x Unknown minor function %x\n",
  71. Pdo, Irp, irpStack->MinorFunction));
  72. } else {
  73. DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x --> %s\n",
  74. Pdo, Irp, PNP_IRP_STRING(irpStack->MinorFunction)));
  75. }
  76. #endif
  77. //
  78. // CardBus PnP Dispatch
  79. //
  80. switch (irpStack->MinorFunction) {
  81. case IRP_MN_START_DEVICE:
  82. status = PcmciaStartCardBusCard(Pdo, Irp);
  83. PcmciaDoStartSound(pdoExtension->Socket, status);
  84. break;
  85. case IRP_MN_REMOVE_DEVICE:
  86. status = PcmciaRemoveCardBusCard(Pdo, Irp);
  87. break;
  88. case IRP_MN_STOP_DEVICE:
  89. PcmciaSkipCallLowerDriver(status, pdoExtension->LowerDevice, Irp);
  90. MarkDeviceNotStarted(pdoExtension);
  91. break;
  92. case IRP_MN_SURPRISE_REMOVAL:
  93. if (IsDevicePhysicallyRemoved(pdoExtension)) {
  94. PcmciaSetSocketPower(pdoExtension->Socket, NULL, NULL, PCMCIA_POWEROFF);
  95. }
  96. PcmciaSkipCallLowerDriver(status, pdoExtension->LowerDevice, Irp);
  97. break;
  98. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  99. status = PcmciaQueryCardBusCardResourceRequirements(Pdo, Irp);
  100. break;
  101. case IRP_MN_QUERY_CAPABILITIES:
  102. status = PcmciaQueryCardBusCardCapabilities(Pdo, Irp);
  103. break;
  104. case IRP_MN_QUERY_INTERFACE:
  105. status = PcmciaPdoQueryInterface(Pdo, Irp);
  106. break;
  107. default:
  108. PcmciaSkipCallLowerDriver(status, pdoExtension->LowerDevice, Irp);
  109. }
  110. DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x <-- %s %08x\n", Pdo, Irp,
  111. STATUS_STRING(status), status));
  112. return status;
  113. }
  114. NTSTATUS
  115. PcmciaStartCardBusCard(
  116. IN PDEVICE_OBJECT Pdo,
  117. IN OUT PIRP Irp
  118. )
  119. /*++
  120. Routine Description:
  121. This routine attempts to start the PC-Card by configuring it with the supplied resources.
  122. Arguments:
  123. Pdo - Pointer to the device object representing the PC-Card which needs to be started
  124. ResourceList - Pointer the list of assigned resources for the PC-Card
  125. Return value:
  126. STATUS_INSUFFICIENT_RESOURCES - Not sufficient resources supplied to start device/
  127. could not allocate memory
  128. STATUS_UNSUCCESSFUL - Supplied resources are invalid for this PC-Card
  129. STATUS_SUCCESS - Configured and started the card successfully
  130. --*/
  131. {
  132. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  133. PSOCKET socket = pdoExtension->Socket;
  134. PSOCKET_DATA socketData = pdoExtension->SocketData;
  135. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  136. USHORT word;
  137. UCHAR BaseClass;
  138. NTSTATUS status = STATUS_NOT_SUPPORTED;
  139. ULONG i;
  140. ULONG devid;
  141. USHORT cls_lat;
  142. BOOLEAN setAudio = FALSE;
  143. PAGED_CODE();
  144. ASSERT (pdoExtension->LowerDevice);
  145. //
  146. // Apply some hacks if necessary
  147. //
  148. status = PcmciaConfigureCardBusCard(pdoExtension);
  149. if (!NT_SUCCESS(status)) {
  150. //
  151. // The card's config space probably never became visible
  152. //
  153. Irp->IoStatus.Status = status;
  154. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  155. return status;
  156. }
  157. //
  158. // Select PCI IRQ routing
  159. //
  160. CBEnableDeviceInterruptRouting(socket);
  161. //
  162. // Turn on ZV for this card, if it needs it
  163. //
  164. if (socketData && (socketData->Flags & SDF_ZV)) {
  165. if (PcmciaSetZV(fdoExtension, socket, TRUE)) {
  166. SetSocketFlag(socket, SOCKET_CUSTOM_INTERFACE);
  167. }
  168. } else if (IsSocketFlagSet(socket, SOCKET_CUSTOM_INTERFACE)) {
  169. PcmciaSetZV(fdoExtension, socket, FALSE);
  170. ResetSocketFlag(socket, SOCKET_CUSTOM_INTERFACE);
  171. }
  172. //
  173. // Pci needs to enable this card .. send it down to the PDO
  174. //
  175. status = PcmciaIoCallDriverSynchronous(pdoExtension->LowerDevice, Irp);
  176. //
  177. // Apparently cardbus modems aren't immune to needing delays
  178. // This yield duration was emperically determined using the Xircom RBM56G
  179. //
  180. GetPciConfigSpace(pdoExtension, CFGSPACE_CLASSCODE_BASECLASS, &BaseClass, 1);
  181. if (BaseClass == PCI_CLASS_SIMPLE_COMMS_CTLR) {
  182. //
  183. // Wait for modem to warm up
  184. //
  185. PcmciaWait(CBModemReadyDelay);
  186. setAudio = TRUE;
  187. }
  188. PcmciaSetAudio(fdoExtension, socket, setAudio);
  189. //
  190. // Assume that the cardbus controller has the correct CLS and latency
  191. // timer values, and that the cardbus device has zeroes.
  192. //
  193. GetPciConfigSpace(fdoExtension, CFGSPACE_CACHE_LINESIZE, &cls_lat, sizeof(cls_lat));
  194. SetPciConfigSpace(pdoExtension, CFGSPACE_CACHE_LINESIZE, &cls_lat, sizeof(cls_lat));
  195. if (NT_SUCCESS(status)) {
  196. MarkDeviceStarted(pdoExtension);
  197. MarkDeviceLogicallyInserted(pdoExtension);
  198. }
  199. Irp->IoStatus.Status = status;
  200. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  201. return status;
  202. }
  203. NTSTATUS
  204. PcmciaRemoveCardBusCard(
  205. IN PDEVICE_OBJECT Pdo,
  206. IN PIRP Irp
  207. )
  208. /*++
  209. Routine Description:
  210. Arguments:
  211. Return value:
  212. --*/
  213. {
  214. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  215. PSOCKET socket = pdoExtension->Socket;
  216. NTSTATUS status;
  217. ASSERT(socket != NULL);
  218. //
  219. // Send this down to the PDO first
  220. //
  221. status = PcmciaIoCallDriverSynchronous(pdoExtension->LowerDevice, Irp);
  222. if (!NT_SUCCESS(status)) {
  223. Irp->IoStatus.Status = status;
  224. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  225. return status;
  226. }
  227. if (IsDevicePhysicallyRemoved(pdoExtension)) {
  228. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  229. PDEVICE_OBJECT curPdo, prevPdo;
  230. PPDO_EXTENSION curPdoExt;
  231. ULONG waitCount = 0;
  232. //
  233. // Synchronize with power routines
  234. // LATER: make these values adjustable
  235. //
  236. while(!PCMCIA_TEST_AND_SET(&pdoExtension->DeletionLock)) {
  237. PcmciaWait(1000000);
  238. if (waitCount++ > 20) {
  239. ASSERT(waitCount <= 20);
  240. break;
  241. }
  242. }
  243. //
  244. // Delink this Pdo from the FDO list.
  245. //
  246. for (curPdo = fdoExtension->PdoList, prevPdo = NULL; curPdo!=NULL; prevPdo=curPdo, curPdo=curPdoExt->NextPdoInFdoChain) {
  247. curPdoExt = curPdo->DeviceExtension;
  248. if (curPdo == Pdo) {
  249. if (prevPdo) {
  250. ((PPDO_EXTENSION)prevPdo->DeviceExtension)->NextPdoInFdoChain = pdoExtension->NextPdoInFdoChain;
  251. } else {
  252. fdoExtension->PdoList = pdoExtension->NextPdoInFdoChain;
  253. }
  254. break;
  255. }
  256. }
  257. //
  258. // Delink this Pdo from the socket list.
  259. //
  260. for (curPdo = socket->PdoList, prevPdo = NULL; curPdo!=NULL; prevPdo=curPdo, curPdo=curPdoExt->NextPdoInSocket) {
  261. curPdoExt = curPdo->DeviceExtension;
  262. if (curPdo == Pdo) {
  263. if (prevPdo) {
  264. ((PPDO_EXTENSION)prevPdo->DeviceExtension)->NextPdoInSocket = pdoExtension->NextPdoInSocket;
  265. } else {
  266. socket->PdoList = pdoExtension->NextPdoInSocket;
  267. }
  268. break;
  269. }
  270. }
  271. PcmciaCleanupPdo(Pdo);
  272. //
  273. // Delete..
  274. //
  275. if (!IsDeviceDeleted(pdoExtension)) {
  276. MarkDeviceDeleted(pdoExtension);
  277. IoDeleteDevice(Pdo);
  278. }
  279. PcmciaSetSocketPower(pdoExtension->Socket, NULL, NULL, PCMCIA_POWEROFF);
  280. if (--fdoExtension->PciAddCardBusCount == 0) {
  281. ResetSocketFlag(socket, SOCKET_CLEANUP_PENDING);
  282. //
  283. // If a query_device_relations came in after a card was inserted, but before
  284. // we have removed the previous card configuration, the enumeration would have been
  285. // postponed. Here, we start it up again
  286. //
  287. if (IsSocketFlagSet(socket, SOCKET_ENUMERATE_PENDING)) {
  288. ResetSocketFlag(socket, SOCKET_ENUMERATE_PENDING);
  289. SetSocketFlag(socket, SOCKET_CARD_STATUS_CHANGE);
  290. IoInvalidateDeviceRelations(fdoExtension->Pdo, BusRelations);
  291. }
  292. }
  293. } else {
  294. //
  295. // We will keep this Pdo around, since this is not physically ejected.
  296. //
  297. MarkDeviceLogicallyRemoved(pdoExtension);
  298. }
  299. Irp->IoStatus.Status = status;
  300. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  301. return status;
  302. }
  303. NTSTATUS
  304. PcmciaQueryCardBusCardResourceRequirements(
  305. IN PDEVICE_OBJECT Pdo,
  306. IN PIRP Irp
  307. )
  308. /*++
  309. Routine Description:
  310. This routine filters the interrupt requirement generated by pci for the cardbus
  311. card to restrict it to the parent controller's vector. This is anyway what has to
  312. happen, and this way, the card will still get the interrupt even if there is no
  313. irq routing on the machine.
  314. Arguments:
  315. Pdo - Pointer to the device object representing the PC-Card which needs to be started
  316. Irp - IRP_MN_QUERY_RESOURCE_REQUIREMENTS Irp
  317. Return value:
  318. status
  319. --*/
  320. {
  321. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  322. PFDO_EXTENSION fdoExtension = pdoExtension->Socket->DeviceExtension;
  323. NTSTATUS status;
  324. ULONG index1, index2;
  325. PIO_RESOURCE_REQUIREMENTS_LIST IoReqList;
  326. PIO_RESOURCE_LIST ioResourceList;
  327. PIO_RESOURCE_DESCRIPTOR ioResourceDesc;
  328. PAGED_CODE();
  329. PcmciaUpdateInterruptLine(pdoExtension, fdoExtension);
  330. //
  331. // First pass the irp down the stack
  332. //
  333. status = PcmciaIoCallDriverSynchronous(pdoExtension->LowerDevice, Irp);
  334. IoReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->IoStatus.Information;
  335. if (!NT_SUCCESS(status) ||
  336. (IoReqList == NULL) ||
  337. (fdoExtension->Configuration.Interrupt.u.Interrupt.Vector == 0)) {
  338. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  339. return status;
  340. }
  341. //
  342. // Change interrupt descriptors to specifically request the parent vector
  343. //
  344. for (index1 = 0, ioResourceList = IoReqList->List;
  345. index1 < IoReqList->AlternativeLists; index1++) {
  346. ioResourceDesc = ioResourceList->Descriptors;
  347. for (index2 = 0 ; index2 < ioResourceList->Count; index2++, ioResourceDesc++) {
  348. if (ioResourceDesc->Type == CmResourceTypeInterrupt) {
  349. //
  350. // Cardbus cards by design use the same irq as the parent bus controller
  351. //
  352. ioResourceDesc->u.Interrupt.MinimumVector = fdoExtension->Configuration.Interrupt.u.Interrupt.Vector;
  353. ioResourceDesc->u.Interrupt.MaximumVector = fdoExtension->Configuration.Interrupt.u.Interrupt.Vector;
  354. }
  355. }
  356. ioResourceList = (PIO_RESOURCE_LIST) (((PUCHAR) ioResourceList) +
  357. sizeof(IO_RESOURCE_LIST) +
  358. (ioResourceList->Count - 1)* sizeof(IO_RESOURCE_DESCRIPTOR));
  359. } // outer for loop
  360. Irp->IoStatus.Status = status;
  361. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  362. return status;
  363. }
  364. NTSTATUS
  365. PcmciaQueryCardBusCardCapabilities(
  366. IN PDEVICE_OBJECT Pdo,
  367. IN PIRP Irp
  368. )
  369. /*++
  370. Routine Description:
  371. Obtains the device capabilities of the given pc-card.
  372. If the pc-card is an R2 card (16-bit pc-card), the capabilities
  373. are constructed from the parent PCMCIA controller's capabilities.
  374. If it's a cardbus card, the capabilities are obtained from the underlying
  375. PCI pdo for the card.
  376. Finally the obtained capabilities are cached in the pc-card's device
  377. extension for use in power management of the card.
  378. Arguments:
  379. Pdo - Pointer to the device object for the pc-card
  380. Irp - Pointer to the query device capabilities Irp
  381. Return Value:
  382. STATUS_SUCCESS - Capabilities obtained and recorded in the passed in pointer
  383. STATUS_INSUFFICIENT_RESOURCES - Could not allocate memory to cache the capabilities
  384. --*/
  385. {
  386. PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  387. NTSTATUS status;
  388. PAGED_CODE();
  389. //
  390. // CardBus card. Get the capabilities from PCI
  391. //
  392. status = PcmciaIoCallDriverSynchronous(pdoExtension->LowerDevice, Irp);
  393. if (NT_SUCCESS(status)) {
  394. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  395. PDEVICE_CAPABILITIES capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
  396. //
  397. // Filter the capabilities: we need to set Removable true
  398. // since this is a pc-card (PCI doesn't know the difference)
  399. //
  400. capabilities->Removable = TRUE;
  401. //********************************
  402. // NOTE: HACKHACK
  403. // This is temporary code only to get cardbus wake-on-lan up and running. Here
  404. // we check to see if this has only been marked as a "can't wake" device by
  405. // pci because it said it could wake from D3Hot, but not from D3Cold.
  406. //********************************
  407. if (capabilities->DeviceWake <= PowerDeviceD0) {
  408. UCHAR capptr;
  409. ULONG powercaps;
  410. GetPciConfigSpace(pdoExtension, CBCFG_CAPPTR, &capptr, sizeof(capptr));
  411. if (capptr) {
  412. GetPciConfigSpace(pdoExtension, capptr, &powercaps, sizeof(powercaps));
  413. if (((powercaps & 0xff) == 1) && ((powercaps&0x40000000) && !(powercaps&0x80000000))) {
  414. capabilities->DeviceWake = PowerDeviceD3;
  415. capabilities->SystemWake = PowerSystemSleeping3;
  416. capabilities->WakeFromD3 = 1;
  417. }
  418. }
  419. }
  420. if (capabilities->SystemWake > PowerSystemSleeping3) {
  421. capabilities->SystemWake = PowerSystemSleeping3;
  422. }
  423. //********************************
  424. // END HACK
  425. //********************************
  426. //
  427. // Store these capabilities away..
  428. //
  429. RtlCopyMemory(&pdoExtension->DeviceCapabilities,
  430. capabilities,
  431. sizeof(DEVICE_CAPABILITIES));
  432. } else {
  433. RtlZeroMemory(&pdoExtension->DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  434. }
  435. Irp->IoStatus.Status = status;
  436. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  437. return status;
  438. }