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.

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