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.

1345 lines
39 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. if (pcmciaIoctlInterface) {
  292. do {
  293. //
  294. // free buffer from previous loop
  295. //
  296. if (unicodeDeviceName.Buffer != NULL) {
  297. RtlFreeUnicodeString(&unicodeDeviceName);
  298. unicodeDeviceName.Buffer = NULL;
  299. }
  300. //
  301. // create the device name
  302. //
  303. sprintf(deviceNameBuffer, "%s%d", PCMCIA_DEVICE_NAME, ++deviceNumber);
  304. RtlInitAnsiString(&ansiDeviceName, deviceNameBuffer);
  305. status = RtlAnsiStringToUnicodeString(
  306. &unicodeDeviceName,
  307. &ansiDeviceName,
  308. TRUE);
  309. if (!NT_SUCCESS(status)) {
  310. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaCreateFdo: Error creating unicode "
  311. "string [%#08lx]\n",
  312. status));
  313. leave;
  314. }
  315. //
  316. // create the device object
  317. //
  318. status = IoCreateDevice(DriverObject,
  319. sizeof(FDO_EXTENSION),
  320. &unicodeDeviceName,
  321. FILE_DEVICE_CONTROLLER,
  322. FILE_DEVICE_SECURE_OPEN,
  323. FALSE,
  324. &deviceObject);
  325. } while ((status == STATUS_OBJECT_NAME_EXISTS) ||
  326. (status == STATUS_OBJECT_NAME_COLLISION));
  327. } else {
  328. status = IoCreateDevice(DriverObject,
  329. sizeof(FDO_EXTENSION),
  330. NULL,
  331. FILE_DEVICE_CONTROLLER,
  332. FILE_DEVICE_SECURE_OPEN,
  333. FALSE,
  334. &deviceObject);
  335. }
  336. if (!NT_SUCCESS(status)) {
  337. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaCreateFdo: Error creating device object "
  338. "[%#08lx]\n",
  339. status));
  340. leave;
  341. }
  342. //
  343. // Set up the device extension.
  344. //
  345. deviceExtension = deviceObject->DeviceExtension;
  346. deviceExtension->Signature = PCMCIA_FDO_EXTENSION_SIGNATURE;
  347. deviceExtension->DeviceObject = deviceObject;
  348. deviceExtension->RegistryPath = DriverRegistryPath;
  349. deviceExtension->DriverObject = DriverObject;
  350. deviceExtension->PdoList = NULL;
  351. deviceExtension->LivePdoCount = 0;
  352. deviceExtension->Flags = PCMCIA_FDO_OFFLINE;
  353. deviceExtension->WaitWakeState= WAKESTATE_DISARMED;
  354. // Setup symbolic link for VDDs
  355. //
  356. //
  357. // create the link name (reuse the device name buffers for this)
  358. //
  359. if (pcmciaIoctlInterface) {
  360. SetDeviceFlag(deviceExtension, PCMCIA_FDO_IOCTL_INTERFACE_ENABLED);
  361. sprintf(deviceNameBuffer,"%s%d", PCMCIA_LINK_NAME, deviceNumber);
  362. RtlInitAnsiString(&ansiDeviceName, deviceNameBuffer);
  363. status = RtlAnsiStringToUnicodeString(
  364. &unicodeLinkName,
  365. &ansiDeviceName,
  366. TRUE);
  367. if (!NT_SUCCESS(status)) {
  368. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaCreateFdo: Error creating unicode "
  369. "string [%#08lx]\n",
  370. status));
  371. leave;
  372. }
  373. status = IoCreateSymbolicLink(&unicodeLinkName, &unicodeDeviceName);
  374. if (!NT_SUCCESS(status)) {
  375. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaCreateFdo: Symbolic Link was not created\n"));
  376. leave;
  377. }
  378. LinkCreated = TRUE;
  379. deviceExtension->LinkName = unicodeLinkName;
  380. }
  381. //
  382. // Lock for synching device access
  383. //
  384. PCMCIA_INITIALIZE_DEVICE_LOCK(deviceExtension);
  385. *NewDeviceObject = deviceObject;
  386. } finally {
  387. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaCreateFdo: Cleanup\n"));
  388. //
  389. //
  390. // deallocate temporary objects
  391. //
  392. if (unicodeDeviceName.Buffer != NULL) {
  393. RtlFreeUnicodeString(&unicodeDeviceName);
  394. }
  395. //
  396. // destroy objects if there was an error
  397. //
  398. if (!NT_SUCCESS(status)) {
  399. if (LinkCreated) {
  400. IoDeleteSymbolicLink(&unicodeLinkName);
  401. }
  402. if (unicodeLinkName.Buffer != NULL) {
  403. RtlFreeUnicodeString(&unicodeLinkName);
  404. }
  405. if (deviceObject != NULL) {
  406. MarkDeviceDeleted(deviceExtension);
  407. IoDeleteDevice(deviceObject);
  408. }
  409. }
  410. }
  411. return status;
  412. }
  413. NTSTATUS
  414. PcmciaStartPcmciaController(
  415. IN PDEVICE_OBJECT Fdo
  416. )
  417. /*++
  418. Routine Description:
  419. Arguments:
  420. Return value:
  421. --*/
  422. {
  423. PFDO_EXTENSION deviceExtension = Fdo->DeviceExtension;
  424. PSOCKET socket;
  425. BOOLEAN sharedInterrupt;
  426. KINTERRUPT_MODE interruptMode;
  427. NTSTATUS status;
  428. INTERFACE_TYPE interfaceType;
  429. //
  430. // Now the controller registers should be accessible
  431. //
  432. deviceExtension->Flags &= ~PCMCIA_FDO_OFFLINE;
  433. //
  434. // Set up the socket list
  435. //
  436. if (!deviceExtension->SocketList) {
  437. if (CardBusExtension(deviceExtension)) {
  438. status = CBBuildSocketList(deviceExtension);
  439. } else {
  440. switch (deviceExtension->ControllerType) {
  441. case PcmciaIntelCompatible:
  442. case PcmciaElcController:
  443. case PcmciaCLPD6729:
  444. case PcmciaPciPcmciaBridge:
  445. case PcmciaNEC98:
  446. case PcmciaNEC98102: {
  447. status = PcicBuildSocketList(deviceExtension);
  448. break;
  449. }
  450. case PcmciaDatabook: {
  451. status = TcicBuildSocketList(deviceExtension);
  452. break;
  453. }
  454. default:
  455. status = STATUS_UNSUCCESSFUL;
  456. }
  457. }
  458. if (!NT_SUCCESS(status)) {
  459. return status;
  460. }
  461. }
  462. //
  463. // Get the IRQ mask for the controller. This is based on several
  464. // values in the registry.
  465. //
  466. PcmciaGetRegistryFdoIrqMask(deviceExtension);
  467. deviceExtension->SystemPowerState = PowerSystemWorking;
  468. deviceExtension->DevicePowerState = PowerDeviceD0;
  469. //
  470. // Initialize our DpcForIsr
  471. //
  472. IoInitializeDpcRequest(Fdo, PcmciaInterruptDpc);
  473. //
  474. // Initialize socket objects
  475. //
  476. for (socket = deviceExtension->SocketList; socket; socket = socket->NextSocket) {
  477. socket->Signature = PCMCIA_SOCKET_SIGNATURE;
  478. socket->PdoList = NULL;
  479. //
  480. // Initialize the ready enable event.
  481. //
  482. KeInitializeEvent(&socket->PCCardReadyEvent,
  483. SynchronizationEvent,
  484. FALSE
  485. );
  486. //
  487. // Initialize power objects
  488. //
  489. KeInitializeTimer(&socket->PowerTimer);
  490. KeInitializeDpc(&socket->PowerDpc, PcmciaSocketPowerWorker, socket);
  491. socket->FdoIrq = deviceExtension->Configuration.Interrupt.u.Interrupt.Vector;
  492. }
  493. //
  494. // Assume we are going to poll
  495. //
  496. deviceExtension->Flags |= PCMCIA_USE_POLLED_CSC;
  497. deviceExtension->PcmciaInterruptObject = NULL;
  498. if ((deviceExtension->Configuration.Interrupt.u.Interrupt.Level != 0) &&
  499. CardBusExtension(deviceExtension) &&
  500. !(PcmciaGlobalFlags & PCMCIA_GLOBAL_FORCE_POLL_MODE)) {
  501. //
  502. // Hook up the controller interrupt for detecting pc-card plug ins/outs
  503. //
  504. interruptMode=((deviceExtension->Configuration.Interrupt.Flags & CM_RESOURCE_INTERRUPT_LATCHED) == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched:LevelSensitive;
  505. sharedInterrupt=(deviceExtension->Configuration.Interrupt.ShareDisposition == CmResourceShareShared)?
  506. TRUE:FALSE;
  507. status = IoConnectInterrupt(&(deviceExtension->PcmciaInterruptObject),
  508. (PKSERVICE_ROUTINE) PcmciaInterrupt,
  509. (PVOID) Fdo,
  510. NULL,
  511. deviceExtension->Configuration.TranslatedInterrupt.u.Interrupt.Vector,
  512. (KIRQL) deviceExtension->Configuration.TranslatedInterrupt.u.Interrupt.Level,
  513. (KIRQL) deviceExtension->Configuration.TranslatedInterrupt.u.Interrupt.Level,
  514. interruptMode,
  515. sharedInterrupt,
  516. (KAFFINITY) deviceExtension->Configuration.TranslatedInterrupt.u.Interrupt.Affinity,
  517. FALSE);
  518. if (!NT_SUCCESS(status)) {
  519. DebugPrint((PCMCIA_DEBUG_FAIL, "Unable to connect interrupt\n"));
  520. } else {
  521. //
  522. // We connected. Turn off poll mode
  523. //
  524. deviceExtension->Flags &= ~PCMCIA_USE_POLLED_CSC;
  525. }
  526. }
  527. status = PcmciaInitializeController(Fdo);
  528. if (!NT_SUCCESS(status)) {
  529. DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaStartAdapter: PcmciaInitializeFdo failed\n"));
  530. return status;
  531. }
  532. if (deviceExtension->Flags & PCMCIA_USE_POLLED_CSC) {
  533. LARGE_INTEGER dueTime;
  534. KeInitializeDpc(&deviceExtension->TimerDpc, PcmciaTimerDpc, deviceExtension->DeviceObject);
  535. KeInitializeTimer(&deviceExtension->PollTimer);
  536. //
  537. // Set first fire to twice the peroidic interval - just
  538. //
  539. dueTime.QuadPart = -PCMCIA_CSC_POLL_INTERVAL * 1000 * 10 * 2;
  540. KeSetTimerEx(&(deviceExtension->PollTimer),
  541. dueTime,
  542. PCMCIA_CSC_POLL_INTERVAL,
  543. &deviceExtension->TimerDpc
  544. );
  545. }
  546. return STATUS_SUCCESS;
  547. }
  548. NTSTATUS
  549. PcmciaInitializeController(
  550. IN PDEVICE_OBJECT Fdo
  551. )
  552. /*++
  553. Routine Description:
  554. Initializes the pcmcia controller
  555. Arguments:
  556. Fdo - pointer to the device object for the controller
  557. Return value:
  558. STATUS_SUCCESS - if initialization is successful
  559. --*/
  560. {
  561. PFDO_EXTENSION fdoExtension=Fdo->DeviceExtension;
  562. PSOCKET socket;
  563. NTSTATUS status = STATUS_SUCCESS;
  564. //
  565. // do vendor-specific init of controller
  566. //
  567. if (DeviceDispatchTable[fdoExtension->DeviceDispatchIndex].InitController) {
  568. (*DeviceDispatchTable[fdoExtension->DeviceDispatchIndex].InitController)(fdoExtension);
  569. }
  570. //
  571. // If LegacyIrqMask is not filled in, put a generic mask there in case we need it
  572. //
  573. if (fdoExtension->LegacyIrqMask == 0) {
  574. fdoExtension->LegacyIrqMask = (USHORT)(*(fdoExtension->SocketList->SocketFnPtr->PCBGetIrqMask))(fdoExtension);
  575. }
  576. fdoExtension->LegacyIrqMask &= ~globalFilterIrqMask;
  577. for (socket = fdoExtension->SocketList; socket; socket = socket->NextSocket) {
  578. if (!(*(socket->SocketFnPtr->PCBInitializePcmciaSocket))(socket)) {
  579. status = STATUS_UNSUCCESSFUL;
  580. break;
  581. }
  582. PcmciaGetSocketStatus(socket);
  583. PcmciaSetZV(fdoExtension, socket, FALSE);
  584. ResetSocketFlag(socket, SOCKET_ENABLED_FOR_CARD_DETECT);
  585. if (!(fdoExtension->Flags & PCMCIA_USE_POLLED_CSC) && (socket->FdoIrq != 0)) {
  586. if ((*(socket->SocketFnPtr->PCBEnableDisableCardDetectEvent))(socket, TRUE)) {
  587. //
  588. // card detect event was successfully enabled
  589. //
  590. SetSocketFlag(socket, SOCKET_ENABLED_FOR_CARD_DETECT);
  591. } else {
  592. DebugPrint((PCMCIA_DEBUG_FAIL, "fdo %x failed to enable card detect event on IRQ %x\n",
  593. Fdo, fdoExtension->Configuration.Interrupt.u.Interrupt.Vector));
  594. }
  595. }
  596. }
  597. return status;
  598. }
  599. VOID
  600. PcmciaTimerDpc(
  601. IN PKDPC Dpc,
  602. IN PDEVICE_OBJECT DeviceObject,
  603. IN PVOID SystemContext1,
  604. IN PVOID SystemContext2
  605. )
  606. /*++
  607. Routine Description
  608. This routine polls for card insertions or deletions
  609. for the given PCMCIA controller. If a card status change
  610. condition is detected, it invokes the appropriate DPC
  611. to process the card arrival/departure.
  612. Arguments
  613. Dpc - Pointer to the Dpc object
  614. DeviceObject - Pointer to the FDO of the PCMCIA controller that should be polled
  615. Return Value
  616. None
  617. --*/
  618. {
  619. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  620. PSOCKET socket;
  621. BOOLEAN isCardInSocket, wasCardInSocket, callDpc = FALSE;
  622. if (fdoExtension->Flags & PCMCIA_FDO_OFFLINE) {
  623. return;
  624. }
  625. if (!ValidateController(fdoExtension)) {
  626. //
  627. // Something is wrong with the controller, hopefully it is just
  628. // temporary. For now, do nothing
  629. //
  630. return;
  631. }
  632. for (socket = fdoExtension->SocketList; socket; socket = socket->NextSocket) {
  633. isCardInSocket = (*(socket->SocketFnPtr->PCBDetectCardInSocket))(socket);
  634. wasCardInSocket = IsCardInSocket(socket);
  635. if (isCardInSocket != wasCardInSocket) {
  636. DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaTimerDpc: Setting socket %x change interrupt, cardInSocket=%x Socket->Flags=%x\n", socket, isCardInSocket, socket->Flags));
  637. SetSocketFlag(socket, SOCKET_CHANGE_INTERRUPT);
  638. callDpc = TRUE;
  639. }
  640. }
  641. if (callDpc) {
  642. LARGE_INTEGER dueTime;
  643. KeCancelTimer(&fdoExtension->EventTimer);
  644. dueTime.QuadPart = -((LONG)EventDpcDelay*10);
  645. KeSetTimer(&fdoExtension->EventTimer, dueTime, &fdoExtension->EventDpc);
  646. }
  647. }
  648. BOOLEAN
  649. PcmciaInterrupt(
  650. IN PKINTERRUPT InterruptObject,
  651. PVOID Context
  652. )
  653. /*++
  654. Routine Description:
  655. interrupt handler
  656. Arguments:
  657. InterruptObject - Pointer to the interrupt object.
  658. Context - Pointer to the device context.
  659. Return Value:
  660. Status
  661. --*/
  662. {
  663. PFDO_EXTENSION deviceExtension;
  664. PSOCKET socket;
  665. BOOLEAN statusChanged = FALSE;
  666. deviceExtension=((PDEVICE_OBJECT)Context)->DeviceExtension;
  667. if (deviceExtension->Flags & PCMCIA_FDO_OFFLINE) {
  668. return FALSE;
  669. }
  670. if (!ValidateController(deviceExtension)) {
  671. //
  672. // the controller is broken in some way. Treat like a spurious int
  673. //
  674. ASSERT(FALSE);
  675. return FALSE;
  676. }
  677. //
  678. // Interrupted because of a card removal, or a card insertion.
  679. //
  680. for (socket = deviceExtension->SocketList; socket; socket = socket->NextSocket) {
  681. //
  682. // Check if the card status changed
  683. //
  684. if ((*(socket->SocketFnPtr->PCBDetectCardChanged))(socket)) {
  685. DebugPrint((PCMCIA_DEBUG_ISR, "skt %x card change\n", socket));
  686. if (deviceExtension->DevicePowerState == PowerDeviceD0) {
  687. SetSocketFlag(socket, SOCKET_CHANGE_INTERRUPT);
  688. }
  689. statusChanged = TRUE;
  690. }
  691. socket->ReadyChanged = (*(socket->SocketFnPtr->PCBDetectReadyChanged))(socket);
  692. if (socket->ReadyChanged) {
  693. DebugPrint((PCMCIA_DEBUG_ISR, "skt %x Ready changed\n", socket));
  694. statusChanged = TRUE;
  695. }
  696. //
  697. // Clear card status interrupt, probably leftover from wait/wake
  698. //
  699. if ((socket->SocketFnPtr->PCBDetectCardStatus)) {
  700. (*(socket->SocketFnPtr->PCBDetectCardStatus))(socket);
  701. }
  702. }
  703. if (statusChanged && (deviceExtension->DevicePowerState == PowerDeviceD0)) {
  704. //
  705. // Something changed out there.. could be
  706. // a card insertion/removal.
  707. // Request a DPC to check it out.
  708. //
  709. IoRequestDpc((PDEVICE_OBJECT) Context, NULL, NULL);
  710. }
  711. return statusChanged;
  712. }
  713. VOID
  714. PcmciaInterruptDpc(
  715. IN PKDPC Dpc,
  716. IN PDEVICE_OBJECT DeviceObject,
  717. IN PVOID SystemContext1,
  718. IN PVOID SystemContext2
  719. )
  720. /*++
  721. Routine Description:
  722. This DPC is just an intermediate step in getting to the main DPC
  723. handler. This is used to "debounce" hardware and give it some time after
  724. the physical interrupt has come in.
  725. Arguments:
  726. DeviceObject - Pointer to the device object.
  727. Return Value:
  728. --*/
  729. {
  730. PFDO_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  731. LARGE_INTEGER dueTime;
  732. KeCancelTimer(&deviceExtension->EventTimer);
  733. dueTime.QuadPart = -((LONG)EventDpcDelay*10);
  734. KeSetTimer(&deviceExtension->EventTimer, dueTime, &deviceExtension->EventDpc);
  735. }
  736. VOID
  737. PcmciaDpc(
  738. IN PKDPC Dpc,
  739. IN PDEVICE_OBJECT DeviceObject,
  740. IN PVOID SystemContext1,
  741. IN PVOID SystemContext2
  742. )
  743. /*++
  744. Routine Description:
  745. This deferred procedure will be called due to a request for DPC
  746. from the interrupt routine. The device object passed contains
  747. information concerning which sockets have changed. Search this
  748. list and free/clean up any sockets that used to have PCCards.
  749. Arguments:
  750. DeviceObject - Pointer to the device object.
  751. Return Value:
  752. --*/
  753. {
  754. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  755. PSOCKET socket;
  756. if (fdoExtension->Flags & PCMCIA_FDO_OFFLINE) {
  757. return;
  758. }
  759. DebugPrint((PCMCIA_DEBUG_DPC, "PcmciaDpc: Card Status Change DPC entered...\n"));
  760. //
  761. // For synchronization with the enumeration & removal
  762. // routines which have a tendency to pop off pdo's
  763. // etc
  764. //
  765. PCMCIA_ACQUIRE_DEVICE_LOCK_AT_DPC_LEVEL(fdoExtension);
  766. for (socket = fdoExtension->SocketList; socket; socket = socket->NextSocket) {
  767. if (socket->ReadyChanged) {
  768. KeSetEvent(&socket->PCCardReadyEvent, 0, FALSE);
  769. }
  770. if (IsSocketFlagSet(socket,SOCKET_CHANGE_INTERRUPT)) {
  771. DebugPrint((PCMCIA_DEBUG_DPC, "PcmciaDpc: Socket %x has SOCKET_CHANGE_INTERRUPT set\n", socket));
  772. //
  773. // This socket has changed status
  774. //
  775. ResetSocketFlag(socket, SOCKET_CHANGE_INTERRUPT);
  776. ResetSocketFlag(socket, SOCKET_SUPPORT_MESSAGE_SENT);
  777. SetSocketFlag(socket, SOCKET_CARD_STATUS_CHANGE);
  778. if ((*(socket->SocketFnPtr->PCBDetectCardInSocket))(socket)) {
  779. //
  780. // Assume we have a single function card here.
  781. // This will be corrected by when we parse the tuple data (for an R2 card)
  782. // or PCI returns more than one PDO (for a cardbus card)
  783. //
  784. socket->NumberOfFunctions = 1;
  785. ResetSocketFlag(socket, SOCKET_CARD_MULTIFUNCTION);
  786. //
  787. // If we get a physical plug in, then we better clean up even if we didn't
  788. // get the remove yet.
  789. //
  790. ResetSocketFlag(socket, SOCKET_CLEANUP_PENDING);
  791. ResetSocketFlag(socket, SOCKET_ENUMERATE_PENDING);
  792. } else {
  793. if (socket->PdoList) {
  794. PPDO_EXTENSION pdoExtension;
  795. PDEVICE_OBJECT pdo;
  796. //
  797. // Mark all the pdo's which hang off this socket (more than one possible only
  798. // if this is a Multifunction PC-Card)
  799. //
  800. for (pdo = socket->PdoList; pdo!=NULL; pdo=pdoExtension->NextPdoInSocket) {
  801. pdoExtension = pdo->DeviceExtension;
  802. MarkDevicePhysicallyRemoved(pdoExtension);
  803. }
  804. }
  805. //
  806. // Hack for Topic95 controllers staying in 3.3v
  807. //
  808. if (fdoExtension->ControllerType == PcmciaTopic95) {
  809. ULONG state = CBReadSocketRegister(socket, CARDBUS_SOCKET_PRESENT_STATE_REG);
  810. if ((state & CARDBUS_CB_CARD) && !(state & (CARDBUS_CD1 | CARDBUS_CD2))) {
  811. state &= ~(SKTFORCE_CBCARD | SKTFORCE_3VCARD);
  812. CBWriteSocketRegister(socket, CARDBUS_SOCKET_FORCE_EVENT_REG, state);
  813. }
  814. }
  815. //
  816. // Clear power requirements
  817. //
  818. socket->Vcc = socket->Vpp1 = socket->Vpp2 = 0;
  819. //
  820. // Make sure i/o arbiter is not hanging on the devnode
  821. //
  822. if (CardBusExtension(fdoExtension)) {
  823. IoInvalidateDeviceState(fdoExtension->Pdo);
  824. }
  825. }
  826. }
  827. }
  828. PCMCIA_RELEASE_DEVICE_LOCK_FROM_DPC_LEVEL(fdoExtension);
  829. IoInvalidateDeviceRelations(fdoExtension->Pdo, BusRelations);
  830. return;
  831. }
  832. VOID
  833. PcmciaSetControllerType(
  834. IN PFDO_EXTENSION FdoExtension,
  835. IN PCMCIA_CONTROLLER_TYPE ControllerType
  836. )
  837. /*++
  838. Routine Description
  839. This routine does the housekeeping for setting the controller type,
  840. and the corresponding device index.
  841. Arguments
  842. FdoExtension - Pointer to device extension for the pcmcia controller
  843. ControllerType - new controller type to set into the extension
  844. Return Value
  845. None. Must succeed.
  846. --*/
  847. {
  848. PCMCIA_CONTROLLER_CLASS ctlClass;
  849. ULONG index;
  850. FdoExtension->ControllerType = ControllerType;
  851. ctlClass = PcmciaClassFromControllerType(FdoExtension->ControllerType);
  852. //
  853. // first assume cardbus
  854. //
  855. MarkDeviceCardBus(FdoExtension);
  856. switch(ctlClass) {
  857. case PcmciaIntelCompatible:
  858. case PcmciaPciPcmciaBridge:
  859. case PcmciaElcController:
  860. case PcmciaDatabook:
  861. case PcmciaNEC_98:
  862. MarkDevice16Bit(FdoExtension);
  863. break;
  864. case PcmciaCirrusLogic:
  865. if (ControllerType == PcmciaCLPD6729) {
  866. MarkDevice16Bit(FdoExtension);
  867. }
  868. break;
  869. }
  870. //
  871. // Look up the device in our dispatch table
  872. //
  873. for (index = 0; DeviceDispatchTable[index].ControllerClass != PcmciaInvalidControllerClass; index++) {
  874. if (DeviceDispatchTable[index].ControllerClass == ctlClass) {
  875. FdoExtension->DeviceDispatchIndex = index;
  876. break;
  877. }
  878. }
  879. FdoExtension->Flags &= ~PCMCIA_MEMORY_24BIT;
  880. if (!HasWindowPageRegister(FdoExtension)) {
  881. FdoExtension->Flags |= PCMCIA_MEMORY_24BIT;
  882. }
  883. if ((FdoExtension->InterfaceType == InterfaceTypeUndefined) ||
  884. (FdoExtension->InterfaceType == Isa)) {
  885. FdoExtension->Flags |= PCMCIA_MEMORY_24BIT;
  886. }
  887. switch(ControllerType) {
  888. case PcmciaTI1031:
  889. case PcmciaTI1130:
  890. //
  891. // restrict memory ranges for PDO's to 24bit
  892. // (because of missing "window page" functionality).
  893. //
  894. FdoExtension->Flags |= PCMCIA_MEMORY_24BIT;
  895. break;
  896. }
  897. DebugPrint((PCMCIA_DEBUG_INFO, "fdo %08x Controller Type %x\n",
  898. FdoExtension->DeviceObject, ControllerType));
  899. }
  900. NTSTATUS
  901. PcmciaGetPciControllerType(
  902. IN PDEVICE_OBJECT Pdo,
  903. IN PDEVICE_OBJECT Fdo
  904. )
  905. /*++
  906. Routine Description:
  907. Look at the PCI hardware ID to see if it is already a device we know about. If so,
  908. set the appropriate controller type in the fdoExtension.
  909. Arguments:
  910. Pdo - Physical Device object for the Pcmcia controller owned by the PCI driver
  911. Fdo - Functional Device object for the pcmcia controller owned by this driver, whose
  912. extension will store the relevant controller information upon exit from this routine.
  913. Return Value:
  914. STATUS_SUCCESS Things are fine and information obtained
  915. STATUS_NOT_SUPPORTED This is actually a healthy status for this routine: all it means
  916. is that this PDO is not on a PCI bus, so no information needs to be
  917. obtained anyways.
  918. Any other status Failure. Caller probably needs to back out & not support this controller
  919. --*/
  920. {
  921. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  922. PIRP irp;
  923. IO_STATUS_BLOCK statusBlock;
  924. PIO_STACK_LOCATION irpSp;
  925. PCI_COMMON_CONFIG pciConfig;
  926. PPCI_CONTROLLER_INFORMATION id;
  927. PPCI_VENDOR_INFORMATION vid;
  928. KEVENT event;
  929. NTSTATUS status;
  930. BOOLEAN foundController = FALSE;
  931. PAGED_CODE();
  932. //
  933. // Allocate & initialize an Irp (IRP_MN_READ_CONFIG) to be sent down
  934. // to the PCI bus driver to get config. header for this controller
  935. //
  936. // Following is all standard stuff to send an IRP down - needs no documentation
  937. //
  938. // Fresh PDO. No need to jump through hoops to get attached devices
  939. //
  940. KeInitializeEvent (&event, NotificationEvent, FALSE);
  941. irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
  942. Pdo,
  943. NULL,
  944. 0,
  945. 0,
  946. &event,
  947. &statusBlock
  948. );
  949. if (irp == NULL) {
  950. return STATUS_INSUFFICIENT_RESOURCES;
  951. }
  952. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  953. irp->IoStatus.Information = 0;
  954. irpSp = IoGetNextIrpStackLocation(irp);
  955. irpSp->MinorFunction = IRP_MN_READ_CONFIG;
  956. irpSp->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
  957. irpSp->Parameters.ReadWriteConfig.Buffer = &pciConfig;
  958. irpSp->Parameters.ReadWriteConfig.Offset = 0;
  959. irpSp->Parameters.ReadWriteConfig.Length = sizeof(pciConfig);
  960. status = IoCallDriver(Pdo, irp);
  961. if (status == STATUS_PENDING) {
  962. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  963. status = statusBlock.Status;
  964. }
  965. if (!NT_SUCCESS(status)) {
  966. return status;
  967. }
  968. //
  969. // Now weed out the critical information from the config header and
  970. // store it away in the fdo's extension
  971. //
  972. if (pciConfig.SubClass == PCI_SUBCLASS_BR_PCMCIA) {
  973. PcmciaSetControllerType(fdoExtension, PcmciaPciPcmciaBridge);
  974. } else if (pciConfig.SubClass == PCI_SUBCLASS_BR_CARDBUS) {
  975. PcmciaSetControllerType(fdoExtension, PcmciaCardBusCompatible);
  976. } else {
  977. //
  978. // Unknown controller
  979. //
  980. return STATUS_UNSUCCESSFUL;
  981. }
  982. //
  983. // Look up the PCI device id in our table
  984. //
  985. for (id = (PPCI_CONTROLLER_INFORMATION) PciControllerInformation;id->VendorID != PCI_INVALID_VENDORID; id++) {
  986. if ((id->VendorID == pciConfig.VendorID) && (id->DeviceID == pciConfig.DeviceID)) {
  987. PcmciaSetControllerType(fdoExtension, id->ControllerType);
  988. foundController = TRUE;
  989. break;
  990. }
  991. }
  992. //
  993. // Didn't find a specific vendor/device id, try to just base it on the vendor id
  994. //
  995. if (!foundController) {
  996. for (vid = (PPCI_VENDOR_INFORMATION) PciVendorInformation;vid->VendorID != PCI_INVALID_VENDORID; vid++) {
  997. if (vid->VendorID == pciConfig.VendorID) {
  998. PcmciaSetControllerType(fdoExtension, vid->ControllerClass);
  999. break;
  1000. }
  1001. }
  1002. }
  1003. return STATUS_SUCCESS;
  1004. }