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.

1338 lines
36 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. ctlr.c
  5. Abstract:
  6. This module contains code to support starting and stopping the
  7. pcmcia controller.
  8. Author:
  9. Neil Sandlin (neilsa) 1-Jun-1999
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "pch.h"
  15. //
  16. // Internal References
  17. //
  18. NTSTATUS
  19. PcmciaInitializeController(
  20. IN PDEVICE_OBJECT Fdo
  21. );
  22. NTSTATUS
  23. PcmciaGetPciControllerType(
  24. IN PDEVICE_OBJECT Pdo,
  25. IN PDEVICE_OBJECT Fdo
  26. );
  27. NTSTATUS
  28. PcmciaCreateFdo(
  29. IN PDRIVER_OBJECT DriverObject,
  30. OUT PDEVICE_OBJECT *NewDeviceObject
  31. );
  32. BOOLEAN
  33. PcmciaInterrupt(
  34. IN PKINTERRUPT InterruptObject,
  35. IN PVOID Context
  36. );
  37. VOID
  38. PcmciaInterruptDpc(
  39. IN PKDPC Dpc,
  40. IN PDEVICE_OBJECT DeviceObject,
  41. IN PVOID SystemContext1,
  42. IN PVOID SystemContext2
  43. );
  44. VOID
  45. PcmciaTimerDpc(
  46. IN PKDPC Dpc,
  47. IN PDEVICE_OBJECT DeviceObject,
  48. IN PVOID SystemContext1,
  49. IN PVOID SystemContext2
  50. );
  51. VOID
  52. PcmciaDpc(
  53. IN PKDPC Dpc,
  54. IN PDEVICE_OBJECT DeviceObject,
  55. IN PVOID SystemContext1,
  56. IN PVOID SystemContext2
  57. );
  58. PUNICODE_STRING DriverRegistryPath;
  59. #ifdef ALLOC_PRAGMA
  60. #pragma alloc_text(PAGE, PcmciaAddDevice)
  61. #pragma alloc_text(PAGE, PcmciaCreateFdo)
  62. #pragma alloc_text(PAGE, PcmciaStartPcmciaController)
  63. #pragma alloc_text(PAGE, PcmciaSetControllerType)
  64. #pragma alloc_text(PAGE, PcmciaGetPciControllerType)
  65. #endif
  66. NTSTATUS
  67. PcmciaAddDevice(
  68. IN PDRIVER_OBJECT DriverObject,
  69. IN PDEVICE_OBJECT Pdo
  70. )
  71. /*++
  72. Routine Description:
  73. This routine creates functional device objects for each Pcmcia controller in the
  74. system and attaches them to the physical device objects for the controllers
  75. Arguments:
  76. DriverObject - a pointer to the object for this driver
  77. PhysicalDeviceObject - a pointer to the physical object we need to attach to
  78. Return Value:
  79. Status from device creation and initialization
  80. --*/
  81. {
  82. PDEVICE_OBJECT fdo = NULL;
  83. PDEVICE_OBJECT lowerDevice = NULL;
  84. PFDO_EXTENSION deviceExtension;
  85. ULONG resultLength;
  86. NTSTATUS status;
  87. PAGED_CODE();
  88. DebugPrint((PCMCIA_DEBUG_PNP, "AddDevice Entered with pdo %x\n", Pdo));
  89. if (Pdo == NULL) {
  90. //
  91. // Have we been asked to do detection on our own?
  92. // if so just return no more devices
  93. //
  94. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaAddDevice - asked to do detection\n"));
  95. return STATUS_NO_MORE_ENTRIES;
  96. }
  97. //
  98. // create and initialize the new functional device object
  99. //
  100. status = PcmciaCreateFdo(DriverObject, &fdo);
  101. if (!NT_SUCCESS(status)) {
  102. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaAddDevice - error creating Fdo [%#08lx]\n",
  103. status));
  104. return status;
  105. }
  106. deviceExtension = fdo->DeviceExtension;
  107. KeInitializeTimer(&deviceExtension->EventTimer);
  108. KeInitializeDpc(&deviceExtension->EventDpc, PcmciaDpc, fdo);
  109. KeInitializeTimer(&deviceExtension->PowerTimer);
  110. KeInitializeDpc(&deviceExtension->PowerDpc, PcmciaFdoPowerWorkerDpc, deviceExtension);
  111. InitializeListHead(&deviceExtension->PdoPowerRetryList);
  112. KeInitializeDpc(&deviceExtension->PdoPowerRetryDpc, PcmciaFdoRetryPdoPowerRequest, deviceExtension);
  113. //
  114. // Layer our FDO on top of the PDO
  115. //
  116. //
  117. lowerDevice = IoAttachDeviceToDeviceStack(fdo,Pdo);
  118. //
  119. // No status. Do the best we can.
  120. //
  121. if (lowerDevice == NULL) {
  122. status = STATUS_INSUFFICIENT_RESOURCES;
  123. goto cleanupExit;
  124. };
  125. deviceExtension->LowerDevice = lowerDevice;
  126. deviceExtension->Pdo = Pdo;
  127. status = IoGetDeviceProperty(Pdo,
  128. DevicePropertyLegacyBusType,
  129. sizeof(INTERFACE_TYPE),
  130. (PVOID)&deviceExtension->InterfaceType,
  131. &resultLength);
  132. if (!NT_SUCCESS(status)) {
  133. //
  134. // Probably a legacy pcic device
  135. //
  136. deviceExtension->InterfaceType = InterfaceTypeUndefined;
  137. }
  138. //
  139. // Get our controller type
  140. //
  141. deviceExtension->ControllerType = PcmciaInvalidControllerType;
  142. if (deviceExtension->InterfaceType == PCIBus) {
  143. status = PcmciaGetPciControllerType(Pdo, fdo);
  144. if (!NT_SUCCESS(status)) {
  145. goto cleanupExit;
  146. }
  147. } else {
  148. PCMCIA_CONTROLLER_TYPE controllerType;
  149. status = PcmciaGetLegacyDetectedControllerType(deviceExtension->Pdo,
  150. &controllerType);
  151. if (NT_SUCCESS(status)) {
  152. PcmciaSetControllerType(deviceExtension, controllerType);
  153. }
  154. }
  155. //
  156. // Do some cardbus specific initialization
  157. //
  158. if (CardBusExtension(deviceExtension)) {
  159. BOOLEAN OnDebugPath;
  160. ACPI_INTERFACE_STANDARD AcpiInterface;
  161. USHORT word;
  162. //
  163. // Get the pci/cardbus private interface
  164. //
  165. status = PcmciaGetInterface(Pdo,
  166. &GUID_PCI_CARDBUS_INTERFACE_PRIVATE,
  167. sizeof(PCI_CARDBUS_INTERFACE_PRIVATE),
  168. (PINTERFACE) &deviceExtension->PciCardBusInterface
  169. );
  170. if (!NT_SUCCESS(status)) {
  171. goto cleanupExit;
  172. }
  173. status = deviceExtension->PciCardBusInterface.GetLocation(Pdo,
  174. &deviceExtension->PciBusNumber,
  175. &deviceExtension->PciDeviceNumber,
  176. &deviceExtension->PciFunctionNumber,
  177. &OnDebugPath);
  178. if (!NT_SUCCESS(status)) {
  179. goto cleanupExit;
  180. }
  181. if (OnDebugPath) {
  182. SetDeviceFlag(deviceExtension, PCMCIA_FDO_ON_DEBUG_PATH);
  183. }
  184. //
  185. // Get the pci interface for reading/writing to config header space
  186. //
  187. status = PcmciaGetInterface(Pdo,
  188. &GUID_BUS_INTERFACE_STANDARD,
  189. sizeof(BUS_INTERFACE_STANDARD),
  190. (PINTERFACE) &deviceExtension->PciBusInterface);
  191. if (!NT_SUCCESS(status)) {
  192. goto cleanupExit;
  193. }
  194. //
  195. // Make sure IRQ routing is to isa. This has come up when installing from a pcmcia CD-rom.
  196. // What happens is that, after we start booting GUI mode, the controller is at first
  197. // in legacy PCIC mode (set by the bios to accomplish boot). At some point, the _INIT
  198. // method is run, and we switch to cardbus mode. So, under the following conditions:
  199. // 1) irq routing bit is still off
  200. // 2) cd-rom is asserting its interrupt
  201. // 3) host controller routes cd-rom interrupt to PCI
  202. // then we hang.
  203. //
  204. GetPciConfigSpace(deviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
  205. word |= BCTRL_IRQROUTING_ENABLE;
  206. SetPciConfigSpace(deviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
  207. if (!(PcmciaGlobalFlags & PCMCIA_DISABLE_ACPI_NAMESPACE_CHECK)) {
  208. status = PcmciaGetInterface(fdo,
  209. &GUID_ACPI_INTERFACE_STANDARD,
  210. sizeof(ACPI_INTERFACE_STANDARD),
  211. (PINTERFACE) &AcpiInterface
  212. );
  213. if (NT_SUCCESS(status)) {
  214. SetFdoFlag(deviceExtension, PCMCIA_FDO_IN_ACPI_NAMESPACE);
  215. }
  216. }
  217. }
  218. //
  219. // Get settings from registry (potentially also compatible ControllerType)
  220. //
  221. PcmciaGetControllerRegistrySettings(deviceExtension);
  222. if ((deviceExtension->ControllerType == PcmciaInvalidControllerType)) {
  223. //
  224. // not really sure what this is... maybe it's a PNP0E00 on a boot. Just do
  225. // the least common denominator
  226. //
  227. PcmciaSetControllerType(deviceExtension, PcmciaIntelCompatible);
  228. }
  229. //
  230. // Link this fdo to the list of fdo's managed by the driver
  231. //
  232. DebugPrint((PCMCIA_DEBUG_PNP, "FDO %08X now linked to fdolist by AddDevice\n", fdo));
  233. deviceExtension->NextFdo = FdoList;
  234. FdoList = fdo;
  235. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  236. return STATUS_SUCCESS;
  237. cleanupExit:
  238. MarkDeviceDeleted(deviceExtension);
  239. //
  240. // Cannot support a controller without knowing its type etc.
  241. //
  242. if (deviceExtension->LinkName.Buffer) {
  243. IoDeleteSymbolicLink(&deviceExtension->LinkName);
  244. ExFreePool(deviceExtension->LinkName.Buffer);
  245. }
  246. if (deviceExtension->LowerDevice) {
  247. IoDetachDevice(deviceExtension->LowerDevice);
  248. }
  249. IoDeleteDevice(fdo);
  250. return status;
  251. }
  252. NTSTATUS
  253. PcmciaCreateFdo(
  254. IN PDRIVER_OBJECT DriverObject,
  255. OUT PDEVICE_OBJECT *NewDeviceObject
  256. )
  257. /*++
  258. Routine Description:
  259. This routine will create and initialize a functional device object to
  260. be attached to a Pcmcia controller PDO.
  261. Arguments:
  262. DriverObject - a pointer to the driver object this is created under
  263. DeviceObject - a location to store the pointer to the new device object
  264. Return Value:
  265. STATUS_SUCCESS if everything was successful
  266. reason for failure otherwise
  267. --*/
  268. {
  269. UCHAR deviceNameBuffer[64];
  270. LONG deviceNumber = -1;
  271. ANSI_STRING ansiDeviceName;
  272. UNICODE_STRING unicodeDeviceName;
  273. UNICODE_STRING unicodeLinkName;
  274. PDEVICE_OBJECT deviceObject = NULL;
  275. PFDO_EXTENSION deviceExtension = NULL;
  276. BOOLEAN LinkCreated = FALSE;
  277. ULONG count;
  278. NTSTATUS status=STATUS_SUCCESS;
  279. PAGED_CODE();
  280. //
  281. // Zero out allocated memory pointers so we know if they must be freed
  282. //
  283. RtlZeroMemory(&ansiDeviceName, sizeof(ANSI_STRING));
  284. RtlZeroMemory(&unicodeDeviceName, sizeof(UNICODE_STRING));
  285. RtlZeroMemory(&unicodeLinkName, sizeof(UNICODE_STRING));
  286. //
  287. // Run in a loop incrementing the device number count until we either
  288. // get an error or find a name that's not taken
  289. //
  290. try {
  291. do {
  292. //
  293. // free buffer from previous loop
  294. //
  295. if (unicodeDeviceName.Buffer != NULL) {
  296. RtlFreeUnicodeString(&unicodeDeviceName);
  297. unicodeDeviceName.Buffer = NULL;
  298. }
  299. //
  300. // create the device name
  301. //
  302. sprintf(deviceNameBuffer, "%s%d", PCMCIA_DEVICE_NAME, ++deviceNumber);
  303. RtlInitAnsiString(&ansiDeviceName, deviceNameBuffer);
  304. status = RtlAnsiStringToUnicodeString(
  305. &unicodeDeviceName,
  306. &ansiDeviceName,
  307. TRUE);
  308. if (!NT_SUCCESS(status)) {
  309. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaCreateFdo: Error creating unicode "
  310. "string [%#08lx]\n",
  311. status));
  312. leave;
  313. }
  314. //
  315. // create the device object
  316. //
  317. status = IoCreateDevice(DriverObject,
  318. sizeof(FDO_EXTENSION),
  319. &unicodeDeviceName,
  320. FILE_DEVICE_CONTROLLER,
  321. 0L,
  322. FALSE,
  323. &deviceObject);
  324. } while ((status == STATUS_OBJECT_NAME_EXISTS) ||
  325. (status == STATUS_OBJECT_NAME_COLLISION));
  326. if (!NT_SUCCESS(status)) {
  327. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaCreateFdo: Error creating device object "
  328. "[%#08lx]\n",
  329. status));
  330. leave;
  331. }
  332. // Setup symbolic link for VDDs
  333. //
  334. //
  335. // create the link name (reuse the device name buffers for this)
  336. //
  337. sprintf(deviceNameBuffer,"%s%d", PCMCIA_LINK_NAME, deviceNumber);
  338. RtlInitAnsiString(&ansiDeviceName, deviceNameBuffer);
  339. status = RtlAnsiStringToUnicodeString(
  340. &unicodeLinkName,
  341. &ansiDeviceName,
  342. TRUE);
  343. if (!NT_SUCCESS(status)) {
  344. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaCreateFdo: Error creating unicode "
  345. "string [%#08lx]\n",
  346. status));
  347. leave;
  348. }
  349. status = IoCreateSymbolicLink(&unicodeLinkName, &unicodeDeviceName);
  350. if (!NT_SUCCESS(status)) {
  351. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaCreateFdo: Symbolic Link was not created\n"));
  352. leave;
  353. }
  354. LinkCreated = TRUE;
  355. //
  356. // Set up the device extension.
  357. //
  358. deviceExtension = deviceObject->DeviceExtension;
  359. deviceExtension->DeviceObject = deviceObject;
  360. deviceExtension->LinkName = unicodeLinkName;
  361. deviceExtension->RegistryPath = DriverRegistryPath;
  362. deviceExtension->DriverObject = DriverObject;
  363. deviceExtension->DeviceObject = deviceObject;
  364. deviceExtension->PdoList = NULL;
  365. deviceExtension->LivePdoCount = 0;
  366. deviceExtension->Flags = PCMCIA_FDO_OFFLINE;
  367. deviceExtension->WaitWakeState= WAKESTATE_DISARMED;
  368. //
  369. // Lock for synching device access
  370. //
  371. PCMCIA_INITIALIZE_DEVICE_LOCK(deviceExtension);
  372. *NewDeviceObject = deviceObject;
  373. } finally {
  374. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaCreateFdo: Cleanup\n"));
  375. //
  376. //
  377. // deallocate temporary objects
  378. //
  379. if (unicodeDeviceName.Buffer != NULL) {
  380. RtlFreeUnicodeString(&unicodeDeviceName);
  381. }
  382. //
  383. // destroy objects if there was an error
  384. //
  385. if (!NT_SUCCESS(status)) {
  386. if (LinkCreated) {
  387. IoDeleteSymbolicLink(&unicodeLinkName);
  388. }
  389. if (unicodeLinkName.Buffer != NULL) {
  390. RtlFreeUnicodeString(&unicodeLinkName);
  391. }
  392. if (deviceObject != NULL) {
  393. MarkDeviceDeleted(deviceExtension);
  394. IoDeleteDevice(deviceObject);
  395. }
  396. }
  397. }
  398. return status;
  399. }
  400. NTSTATUS
  401. PcmciaStartPcmciaController(
  402. IN PDEVICE_OBJECT Fdo
  403. )
  404. /*++
  405. Routine Description:
  406. Arguments:
  407. Return value:
  408. --*/
  409. {
  410. PFDO_EXTENSION deviceExtension = Fdo->DeviceExtension;
  411. PSOCKET socket;
  412. BOOLEAN sharedInterrupt;
  413. KINTERRUPT_MODE interruptMode;
  414. NTSTATUS status;
  415. INTERFACE_TYPE interfaceType;
  416. //
  417. // Now the controller registers should be accessible
  418. //
  419. deviceExtension->Flags &= ~PCMCIA_FDO_OFFLINE;
  420. //
  421. // Set up the socket list
  422. //
  423. if (!deviceExtension->SocketList) {
  424. if (CardBusExtension(deviceExtension)) {
  425. status = CBBuildSocketList(deviceExtension);
  426. } else {
  427. switch (deviceExtension->ControllerType) {
  428. case PcmciaIntelCompatible:
  429. case PcmciaElcController:
  430. case PcmciaCLPD6729:
  431. case PcmciaPciPcmciaBridge:
  432. case PcmciaNEC98:
  433. case PcmciaNEC98102: {
  434. status = PcicBuildSocketList(deviceExtension);
  435. break;
  436. }
  437. case PcmciaDatabook: {
  438. status = TcicBuildSocketList(deviceExtension);
  439. break;
  440. }
  441. default:
  442. status = STATUS_UNSUCCESSFUL;
  443. }
  444. }
  445. if (!NT_SUCCESS(status)) {
  446. return status;
  447. }
  448. }
  449. //
  450. // Get the IRQ mask for the controller. This is based on several
  451. // values in the registry.
  452. //
  453. PcmciaGetRegistryFdoIrqMask(deviceExtension);
  454. deviceExtension->SystemPowerState = PowerSystemWorking;
  455. deviceExtension->DevicePowerState = PowerDeviceD0;
  456. //
  457. // Initialize our DpcForIsr
  458. //
  459. IoInitializeDpcRequest(Fdo, PcmciaInterruptDpc);
  460. //
  461. // Initialize socket objects
  462. //
  463. for (socket = deviceExtension->SocketList; socket; socket = socket->NextSocket) {
  464. socket->PdoList = NULL;
  465. //
  466. // Initialize the ready enable event.
  467. //
  468. KeInitializeEvent(&socket->PCCardReadyEvent,
  469. SynchronizationEvent,
  470. FALSE
  471. );
  472. //
  473. // Initialize power objects
  474. //
  475. KeInitializeTimer(&socket->PowerTimer);
  476. KeInitializeDpc(&socket->PowerDpc, PcmciaSocketPowerWorker, socket);
  477. socket->FdoIrq = deviceExtension->Configuration.Interrupt.u.Interrupt.Vector;
  478. }
  479. //
  480. // Assume we are going to poll
  481. //
  482. deviceExtension->Flags |= PCMCIA_USE_POLLED_CSC;
  483. deviceExtension->PcmciaInterruptObject = NULL;
  484. if ((deviceExtension->Configuration.Interrupt.u.Interrupt.Level != 0) &&
  485. CardBusExtension(deviceExtension) &&
  486. !(PcmciaGlobalFlags & PCMCIA_GLOBAL_FORCE_POLL_MODE)) {
  487. //
  488. // Hook up the controller interrupt for detecting pc-card plug ins/outs
  489. //
  490. interruptMode=((deviceExtension->Configuration.Interrupt.Flags & CM_RESOURCE_INTERRUPT_LATCHED) == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched:LevelSensitive;
  491. sharedInterrupt=(deviceExtension->Configuration.Interrupt.ShareDisposition == CmResourceShareShared)?
  492. TRUE:FALSE;
  493. status = IoConnectInterrupt(&(deviceExtension->PcmciaInterruptObject),
  494. (PKSERVICE_ROUTINE) PcmciaInterrupt,
  495. (PVOID) Fdo,
  496. NULL,
  497. deviceExtension->Configuration.TranslatedInterrupt.u.Interrupt.Vector,
  498. (KIRQL) deviceExtension->Configuration.TranslatedInterrupt.u.Interrupt.Level,
  499. (KIRQL) deviceExtension->Configuration.TranslatedInterrupt.u.Interrupt.Level,
  500. interruptMode,
  501. sharedInterrupt,
  502. (KAFFINITY) deviceExtension->Configuration.TranslatedInterrupt.u.Interrupt.Affinity,
  503. FALSE);
  504. if (!NT_SUCCESS(status)) {
  505. DebugPrint((PCMCIA_DEBUG_FAIL, "Unable to connect interrupt\n"));
  506. } else {
  507. //
  508. // We connected. Turn off poll mode
  509. //
  510. deviceExtension->Flags &= ~PCMCIA_USE_POLLED_CSC;
  511. }
  512. }
  513. status = PcmciaInitializeController(Fdo);
  514. if (!NT_SUCCESS(status)) {
  515. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaStartAdapter: PcmciaInitializeFdo failed\n"));
  516. return status;
  517. }
  518. if (deviceExtension->Flags & PCMCIA_USE_POLLED_CSC) {
  519. LARGE_INTEGER dueTime;
  520. KeInitializeDpc(&deviceExtension->TimerDpc, PcmciaTimerDpc, deviceExtension->DeviceObject);
  521. KeInitializeTimer(&deviceExtension->PollTimer);
  522. //
  523. // Set first fire to twice the peroidic interval - just
  524. //
  525. dueTime.QuadPart = -PCMCIA_CSC_POLL_INTERVAL * 1000 * 10 * 2;
  526. KeSetTimerEx(&(deviceExtension->PollTimer),
  527. dueTime,
  528. PCMCIA_CSC_POLL_INTERVAL,
  529. &deviceExtension->TimerDpc
  530. );
  531. }
  532. return STATUS_SUCCESS;
  533. }
  534. NTSTATUS
  535. PcmciaInitializeController(
  536. IN PDEVICE_OBJECT Fdo
  537. )
  538. /*++
  539. Routine Description:
  540. Initializes the pcmcia controller
  541. Arguments:
  542. Fdo - pointer to the device object for the controller
  543. Return value:
  544. STATUS_SUCCESS - if initialization is successful
  545. --*/
  546. {
  547. PFDO_EXTENSION fdoExtension=Fdo->DeviceExtension;
  548. PSOCKET socket;
  549. NTSTATUS status = STATUS_SUCCESS;
  550. //
  551. // do vendor-specific init of controller
  552. //
  553. if (DeviceDispatchTable[fdoExtension->DeviceDispatchIndex].InitController) {
  554. (*DeviceDispatchTable[fdoExtension->DeviceDispatchIndex].InitController)(fdoExtension);
  555. }
  556. //
  557. // If LegacyIrqMask is not filled in, put a generic mask there in case we need it
  558. //
  559. if (fdoExtension->LegacyIrqMask == 0) {
  560. fdoExtension->LegacyIrqMask = (USHORT)(*(fdoExtension->SocketList->SocketFnPtr->PCBGetIrqMask))(fdoExtension);
  561. }
  562. fdoExtension->LegacyIrqMask &= ~globalFilterIrqMask;
  563. for (socket = fdoExtension->SocketList; socket; socket = socket->NextSocket) {
  564. if (!(*(socket->SocketFnPtr->PCBInitializePcmciaSocket))(socket)) {
  565. status = STATUS_UNSUCCESSFUL;
  566. break;
  567. }
  568. PcmciaGetSocketStatus(socket);
  569. PcmciaSetZV(fdoExtension, socket, FALSE);
  570. ResetSocketFlag(socket, SOCKET_ENABLED_FOR_CARD_DETECT);
  571. if (!(fdoExtension->Flags & PCMCIA_USE_POLLED_CSC) && (socket->FdoIrq != 0)) {
  572. if ((*(socket->SocketFnPtr->PCBEnableDisableCardDetectEvent))(socket, TRUE)) {
  573. //
  574. // card detect event was successfully enabled
  575. //
  576. SetSocketFlag(socket, SOCKET_ENABLED_FOR_CARD_DETECT);
  577. } else {
  578. DebugPrint((PCMCIA_DEBUG_FAIL, "fdo %x failed to enable card detect event on IRQ %x\n",
  579. Fdo, fdoExtension->Configuration.Interrupt.u.Interrupt.Vector));
  580. }
  581. }
  582. }
  583. return status;
  584. }
  585. VOID
  586. PcmciaTimerDpc(
  587. IN PKDPC Dpc,
  588. IN PDEVICE_OBJECT DeviceObject,
  589. IN PVOID SystemContext1,
  590. IN PVOID SystemContext2
  591. )
  592. /*++
  593. Routine Description
  594. This routine polls for card insertions or deletions
  595. for the given PCMCIA controller. If a card status change
  596. condition is detected, it invokes the appropriate DPC
  597. to process the card arrival/departure.
  598. Arguments
  599. Dpc - Pointer to the Dpc object
  600. DeviceObject - Pointer to the FDO of the PCMCIA controller that should be polled
  601. Return Value
  602. None
  603. --*/
  604. {
  605. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  606. PSOCKET socket;
  607. BOOLEAN isCardInSocket, wasCardInSocket, callDpc = FALSE;
  608. if (fdoExtension->Flags & PCMCIA_FDO_OFFLINE) {
  609. return;
  610. }
  611. if (!ValidateController(fdoExtension)) {
  612. //
  613. // Something is wrong with the controller, hopefully it is just
  614. // temporary. For now, do nothing
  615. //
  616. return;
  617. }
  618. for (socket = fdoExtension->SocketList; socket; socket = socket->NextSocket) {
  619. isCardInSocket = (*(socket->SocketFnPtr->PCBDetectCardInSocket))(socket);
  620. wasCardInSocket = IsCardInSocket(socket);
  621. if (isCardInSocket != wasCardInSocket) {
  622. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaTimerDpc: Setting socket %x change interrupt, cardInSocket=%x Socket->Flags=%x\n", socket, isCardInSocket, socket->Flags));
  623. SetSocketFlag(socket, SOCKET_CHANGE_INTERRUPT);
  624. callDpc = TRUE;
  625. }
  626. }
  627. if (callDpc) {
  628. LARGE_INTEGER dueTime;
  629. KeCancelTimer(&fdoExtension->EventTimer);
  630. dueTime.QuadPart = -((LONG)EventDpcDelay*10);
  631. KeSetTimer(&fdoExtension->EventTimer, dueTime, &fdoExtension->EventDpc);
  632. }
  633. }
  634. BOOLEAN
  635. PcmciaInterrupt(
  636. IN PKINTERRUPT InterruptObject,
  637. PVOID Context
  638. )
  639. /*++
  640. Routine Description:
  641. interrupt handler
  642. Arguments:
  643. InterruptObject - Pointer to the interrupt object.
  644. Context - Pointer to the device context.
  645. Return Value:
  646. Status
  647. --*/
  648. {
  649. PFDO_EXTENSION deviceExtension;
  650. PSOCKET socket;
  651. BOOLEAN statusChanged = FALSE;
  652. deviceExtension=((PDEVICE_OBJECT)Context)->DeviceExtension;
  653. if (deviceExtension->Flags & PCMCIA_FDO_OFFLINE) {
  654. return FALSE;
  655. }
  656. if (!ValidateController(deviceExtension)) {
  657. //
  658. // the controller is broken in some way. Treat like a spurious int
  659. //
  660. ASSERT(FALSE);
  661. return FALSE;
  662. }
  663. //
  664. // Interrupted because of a card removal, or a card insertion.
  665. //
  666. for (socket = deviceExtension->SocketList; socket; socket = socket->NextSocket) {
  667. //
  668. // Check if the card status changed
  669. //
  670. if ((*(socket->SocketFnPtr->PCBDetectCardChanged))(socket)) {
  671. DebugPrint((PCMCIA_DEBUG_ISR, "skt %x card change\n", socket));
  672. if (deviceExtension->DevicePowerState == PowerDeviceD0) {
  673. SetSocketFlag(socket, SOCKET_CHANGE_INTERRUPT);
  674. }
  675. statusChanged = TRUE;
  676. }
  677. socket->ReadyChanged = (*(socket->SocketFnPtr->PCBDetectReadyChanged))(socket);
  678. if (socket->ReadyChanged) {
  679. DebugPrint((PCMCIA_DEBUG_ISR, "skt %x Ready changed\n", socket));
  680. statusChanged = TRUE;
  681. }
  682. //
  683. // Clear card status interrupt, probably leftover from wait/wake
  684. //
  685. if ((socket->SocketFnPtr->PCBDetectCardStatus)) {
  686. (*(socket->SocketFnPtr->PCBDetectCardStatus))(socket);
  687. }
  688. }
  689. if (statusChanged && (deviceExtension->DevicePowerState == PowerDeviceD0)) {
  690. //
  691. // Something changed out there.. could be
  692. // a card insertion/removal.
  693. // Request a DPC to check it out.
  694. //
  695. IoRequestDpc((PDEVICE_OBJECT) Context, NULL, NULL);
  696. }
  697. return statusChanged;
  698. }
  699. VOID
  700. PcmciaInterruptDpc(
  701. IN PKDPC Dpc,
  702. IN PDEVICE_OBJECT DeviceObject,
  703. IN PVOID SystemContext1,
  704. IN PVOID SystemContext2
  705. )
  706. /*++
  707. Routine Description:
  708. This DPC is just an intermediate step in getting to the main DPC
  709. handler. This is used to "debounce" hardware and give it some time after
  710. the physical interrupt has come in.
  711. Arguments:
  712. DeviceObject - Pointer to the device object.
  713. Return Value:
  714. --*/
  715. {
  716. PFDO_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  717. LARGE_INTEGER dueTime;
  718. KeCancelTimer(&deviceExtension->EventTimer);
  719. dueTime.QuadPart = -((LONG)EventDpcDelay*10);
  720. KeSetTimer(&deviceExtension->EventTimer, dueTime, &deviceExtension->EventDpc);
  721. }
  722. VOID
  723. PcmciaDpc(
  724. IN PKDPC Dpc,
  725. IN PDEVICE_OBJECT DeviceObject,
  726. IN PVOID SystemContext1,
  727. IN PVOID SystemContext2
  728. )
  729. /*++
  730. Routine Description:
  731. This deferred procedure will be called due to a request for DPC
  732. from the interrupt routine. The device object passed contains
  733. information concerning which sockets have changed. Search this
  734. list and free/clean up any sockets that used to have PCCards.
  735. Arguments:
  736. DeviceObject - Pointer to the device object.
  737. Return Value:
  738. --*/
  739. {
  740. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  741. PSOCKET socket;
  742. if (fdoExtension->Flags & PCMCIA_FDO_OFFLINE) {
  743. return;
  744. }
  745. DebugPrint((PCMCIA_DEBUG_DPC, "PcmciaDpc: Card Status Change DPC entered...\n"));
  746. //
  747. // For synchronization with the enumeration & removal
  748. // routines which have a tendency to pop off pdo's
  749. // etc
  750. //
  751. PCMCIA_ACQUIRE_DEVICE_LOCK_AT_DPC_LEVEL(fdoExtension);
  752. for (socket = fdoExtension->SocketList; socket; socket = socket->NextSocket) {
  753. if (socket->ReadyChanged) {
  754. KeSetEvent(&socket->PCCardReadyEvent, 0, FALSE);
  755. }
  756. if (IsSocketFlagSet(socket,SOCKET_CHANGE_INTERRUPT)) {
  757. DebugPrint((PCMCIA_DEBUG_DPC, "PcmciaDpc: Socket %x has SOCKET_CHANGE_INTERRUPT set\n", socket));
  758. //
  759. // This socket has changed status
  760. //
  761. ResetSocketFlag(socket, SOCKET_CHANGE_INTERRUPT);
  762. ResetSocketFlag(socket, SOCKET_SUPPORT_MESSAGE_SENT);
  763. SetSocketFlag(socket, SOCKET_CARD_STATUS_CHANGE);
  764. if ((*(socket->SocketFnPtr->PCBDetectCardInSocket))(socket)) {
  765. SetSocketFlag(socket, SOCKET_INSERTED_SOUND_PENDING);
  766. //
  767. // Assume we have a single function card here.
  768. // This will be corrected by when we parse the tuple data (for an R2 card)
  769. // or PCI returns more than one PDO (for a cardbus card)
  770. //
  771. socket->NumberOfFunctions = 1;
  772. ResetSocketFlag(socket, SOCKET_CARD_MULTIFUNCTION);
  773. //
  774. // If we get a physical plug in, then we better clean up even if we didn't
  775. // get the remove yet.
  776. //
  777. ResetSocketFlag(socket, SOCKET_CLEANUP_PENDING);
  778. ResetSocketFlag(socket, SOCKET_ENUMERATE_PENDING);
  779. } else {
  780. if (IsSocketFlagSet(socket, SOCKET_REMOVED_SOUND_PENDING)) {
  781. ResetSocketFlag(socket, SOCKET_REMOVED_SOUND_PENDING);
  782. PcmciaPlaySound(CARD_REMOVED_SOUND);
  783. }
  784. if (socket->PdoList) {
  785. PPDO_EXTENSION pdoExtension;
  786. PDEVICE_OBJECT pdo, nextPdo;
  787. //
  788. // Mark all the pdo's which hang off this socket (more than one possible only
  789. // if this is a Multifunction PC-Card)
  790. //
  791. for (pdo = socket->PdoList; pdo!=NULL; pdo=nextPdo) {
  792. pdoExtension = pdo->DeviceExtension;
  793. nextPdo = pdoExtension->NextPdoInSocket;
  794. pdoExtension->NextPdoInSocket = NULL;
  795. MarkDevicePhysicallyRemoved(pdoExtension);
  796. }
  797. socket->PdoList = NULL;
  798. }
  799. //
  800. // Hack for Topic95 controllers staying in 3.3v
  801. //
  802. if (fdoExtension->ControllerType == PcmciaTopic95) {
  803. ULONG state = CBReadSocketRegister(socket, CARDBUS_SOCKET_PRESENT_STATE_REG);
  804. if ((state & CARDBUS_CB_CARD) && !(state & (CARDBUS_CD1 | CARDBUS_CD2))) {
  805. state &= ~(SKTFORCE_CBCARD | SKTFORCE_3VCARD);
  806. CBWriteSocketRegister(socket, CARDBUS_SOCKET_FORCE_EVENT_REG, state);
  807. }
  808. }
  809. //
  810. // Clear power requirements
  811. //
  812. socket->Vcc = socket->Vpp1 = socket->Vpp2 = 0;
  813. //
  814. // Make sure i/o arbiter is not hanging on the devnode
  815. //
  816. if (CardBusExtension(fdoExtension)) {
  817. IoInvalidateDeviceState(fdoExtension->Pdo);
  818. }
  819. }
  820. }
  821. }
  822. PCMCIA_RELEASE_DEVICE_LOCK_FROM_DPC_LEVEL(fdoExtension);
  823. IoInvalidateDeviceRelations(fdoExtension->Pdo, BusRelations);
  824. return;
  825. }
  826. VOID
  827. PcmciaSetControllerType(
  828. IN PFDO_EXTENSION FdoExtension,
  829. IN PCMCIA_CONTROLLER_TYPE ControllerType
  830. )
  831. /*++
  832. Routine Description
  833. This routine does the housekeeping for setting the controller type,
  834. and the corresponding device index.
  835. Arguments
  836. FdoExtension - Pointer to device extension for the pcmcia controller
  837. ControllerType - new controller type to set into the extension
  838. Return Value
  839. None. Must succeed.
  840. --*/
  841. {
  842. PCMCIA_CONTROLLER_CLASS ctlClass;
  843. ULONG index;
  844. FdoExtension->ControllerType = ControllerType;
  845. ctlClass = PcmciaClassFromControllerType(FdoExtension->ControllerType);
  846. //
  847. // first assume cardbus
  848. //
  849. MarkDeviceCardBus(FdoExtension);
  850. switch(ctlClass) {
  851. case PcmciaIntelCompatible:
  852. case PcmciaPciPcmciaBridge:
  853. case PcmciaElcController:
  854. case PcmciaDatabook:
  855. case PcmciaNEC_98:
  856. MarkDevice16Bit(FdoExtension);
  857. break;
  858. case PcmciaCirrusLogic:
  859. if (ControllerType == PcmciaCLPD6729) {
  860. MarkDevice16Bit(FdoExtension);
  861. }
  862. break;
  863. }
  864. //
  865. // Look up the device in our dispatch table
  866. //
  867. for (index = 0; DeviceDispatchTable[index].ControllerClass != PcmciaInvalidControllerClass; index++) {
  868. if (DeviceDispatchTable[index].ControllerClass == ctlClass) {
  869. FdoExtension->DeviceDispatchIndex = index;
  870. break;
  871. }
  872. }
  873. FdoExtension->Flags &= ~PCMCIA_MEMORY_24BIT;
  874. if (!HasWindowPageRegister(FdoExtension)) {
  875. FdoExtension->Flags |= PCMCIA_MEMORY_24BIT;
  876. }
  877. if ((FdoExtension->InterfaceType == InterfaceTypeUndefined) ||
  878. (FdoExtension->InterfaceType == Isa)) {
  879. FdoExtension->Flags |= PCMCIA_MEMORY_24BIT;
  880. }
  881. switch(ControllerType) {
  882. case PcmciaTI1031:
  883. case PcmciaTI1130:
  884. //
  885. // restrict memory ranges for PDO's to 24bit
  886. // (because of missing "window page" functionality).
  887. //
  888. FdoExtension->Flags |= PCMCIA_MEMORY_24BIT;
  889. break;
  890. }
  891. DebugPrint((PCMCIA_DEBUG_INFO, "fdo %08x Controller Type %x\n",
  892. FdoExtension->DeviceObject, ControllerType));
  893. }
  894. NTSTATUS
  895. PcmciaGetPciControllerType(
  896. IN PDEVICE_OBJECT Pdo,
  897. IN PDEVICE_OBJECT Fdo
  898. )
  899. /*++
  900. Routine Description:
  901. Look at the PCI hardware ID to see if it is already a device we know about. If so,
  902. set the appropriate controller type in the fdoExtension.
  903. Arguments:
  904. Pdo - Physical Device object for the Pcmcia controller owned by the PCI driver
  905. Fdo - Functional Device object for the pcmcia controller owned by this driver, whose
  906. extension will store the relevant controller information upon exit from this routine.
  907. Return Value:
  908. STATUS_SUCCESS Things are fine and information obtained
  909. STATUS_NOT_SUPPORTED This is actually a healthy status for this routine: all it means
  910. is that this PDO is not on a PCI bus, so no information needs to be
  911. obtained anyways.
  912. Any other status Failure. Caller probably needs to back out & not support this controller
  913. --*/
  914. {
  915. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  916. PIRP irp;
  917. IO_STATUS_BLOCK statusBlock;
  918. PIO_STACK_LOCATION irpSp;
  919. PCI_COMMON_CONFIG pciConfig;
  920. PPCI_CONTROLLER_INFORMATION id;
  921. PPCI_VENDOR_INFORMATION vid;
  922. KEVENT event;
  923. NTSTATUS status;
  924. BOOLEAN foundController = FALSE;
  925. PAGED_CODE();
  926. //
  927. // Allocate & initialize an Irp (IRP_MN_READ_CONFIG) to be sent down
  928. // to the PCI bus driver to get config. header for this controller
  929. //
  930. // Following is all standard stuff to send an IRP down - needs no documentation
  931. //
  932. // Fresh PDO. No need to jump through hoops to get attached devices
  933. //
  934. KeInitializeEvent (&event, NotificationEvent, FALSE);
  935. irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
  936. Pdo,
  937. NULL,
  938. 0,
  939. 0,
  940. &event,
  941. &statusBlock
  942. );
  943. if (irp == NULL) {
  944. return STATUS_INSUFFICIENT_RESOURCES;
  945. }
  946. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  947. irp->IoStatus.Information = 0;
  948. irpSp = IoGetNextIrpStackLocation(irp);
  949. irpSp->MinorFunction = IRP_MN_READ_CONFIG;
  950. irpSp->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
  951. irpSp->Parameters.ReadWriteConfig.Buffer = &pciConfig;
  952. irpSp->Parameters.ReadWriteConfig.Offset = 0;
  953. irpSp->Parameters.ReadWriteConfig.Length = sizeof(pciConfig);
  954. status = IoCallDriver(Pdo, irp);
  955. if (status == STATUS_PENDING) {
  956. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  957. status = statusBlock.Status;
  958. }
  959. if (!NT_SUCCESS(status)) {
  960. return status;
  961. }
  962. //
  963. // Now weed out the critical information from the config header and
  964. // store it away in the fdo's extension
  965. //
  966. if (pciConfig.SubClass == PCI_SUBCLASS_BR_PCMCIA) {
  967. PcmciaSetControllerType(fdoExtension, PcmciaPciPcmciaBridge);
  968. } else if (pciConfig.SubClass == PCI_SUBCLASS_BR_CARDBUS) {
  969. PcmciaSetControllerType(fdoExtension, PcmciaCardBusCompatible);
  970. } else {
  971. //
  972. // Unknown controller
  973. //
  974. return STATUS_UNSUCCESSFUL;
  975. }
  976. //
  977. // Look up the PCI device id in our table
  978. //
  979. for (id = (PPCI_CONTROLLER_INFORMATION) PciControllerInformation;id->VendorID != PCI_INVALID_VENDORID; id++) {
  980. if ((id->VendorID == pciConfig.VendorID) && (id->DeviceID == pciConfig.DeviceID)) {
  981. PcmciaSetControllerType(fdoExtension, id->ControllerType);
  982. foundController = TRUE;
  983. break;
  984. }
  985. }
  986. //
  987. // Didn't find a specific vendor/device id, try to just base it on the vendor id
  988. //
  989. if (!foundController) {
  990. for (vid = (PPCI_VENDOR_INFORMATION) PciVendorInformation;vid->VendorID != PCI_INVALID_VENDORID; vid++) {
  991. if (vid->VendorID == pciConfig.VendorID) {
  992. PcmciaSetControllerType(fdoExtension, vid->ControllerClass);
  993. break;
  994. }
  995. }
  996. }
  997. return STATUS_SUCCESS;
  998. }