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.

1837 lines
55 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. socket.c
  5. Abstract:
  6. This module contains the socket functions of the pcmcia driver
  7. Author:
  8. Neil Sandlin (neilsa) 3-Mar-1999
  9. Environment:
  10. Kernel mode
  11. Revision History :
  12. --*/
  13. #include "pch.h"
  14. //
  15. // Internal References
  16. //
  17. VOID
  18. PcmciaConfigurationWorkerInitialization(
  19. PPDO_EXTENSION pdoExtension
  20. );
  21. NTSTATUS
  22. PcmciaConfigurePcCardMemIoWindows(
  23. IN PSOCKET Socket,
  24. IN PSOCKET_CONFIGURATION SocketConfig
  25. );
  26. NTSTATUS
  27. PcmciaConfigurePcCardIrq(
  28. IN PSOCKET Socket,
  29. IN PSOCKET_CONFIGURATION SocketConfig
  30. );
  31. NTSTATUS
  32. PcmciaConfigurePcCardRegisters(
  33. PPDO_EXTENSION pdoExtension
  34. );
  35. VOID
  36. PcmciaConfigureModemHack(
  37. IN PSOCKET Socket,
  38. IN PSOCKET_CONFIGURATION SocketConfig
  39. );
  40. BOOLEAN
  41. PcmciaProcessConfigureRequest(
  42. IN PFDO_EXTENSION DeviceExtension,
  43. IN PSOCKET Socket,
  44. IN PCARD_REQUEST CardConfigurationRequest
  45. );
  46. #ifdef ALLOC_PRAGMA
  47. #pragma alloc_text(PAGE, PcmciaGetConfigData)
  48. #endif
  49. NTSTATUS
  50. PcmciaRequestSocketPower(
  51. IN PPDO_EXTENSION PdoExtension,
  52. IN PPCMCIA_COMPLETION_ROUTINE PowerCompletionRoutine
  53. )
  54. /*++
  55. Routine Description:
  56. This routine maintains a reference count of how many devices have requested power.
  57. When the count increments from zero to one, a call is made to actually turn power
  58. on.
  59. Arguments:
  60. Socket - Pointer to the socket for which power is to be applied
  61. PowerCompletionRoutine - routine to be called after configuration is complete
  62. Return value:
  63. status
  64. --*/
  65. {
  66. NTSTATUS status = STATUS_SUCCESS;
  67. PSOCKET socket = PdoExtension->Socket;
  68. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  69. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x request power\n", socket));
  70. if (PCMCIA_TEST_AND_SET(&PdoExtension->SocketPowerRequested)) {
  71. if (InterlockedIncrement(&socket->PowerRequests) == 1) {
  72. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power requests now %d, status %08x\n", socket, socket->PowerRequests));
  73. status = PcmciaSetSocketPower(socket, PowerCompletionRoutine, PdoExtension, TRUE);
  74. }
  75. }
  76. return status;
  77. }
  78. NTSTATUS
  79. PcmciaReleaseSocketPower(
  80. IN PPDO_EXTENSION PdoExtension,
  81. IN PPCMCIA_COMPLETION_ROUTINE PowerCompletionRoutine
  82. )
  83. /*++
  84. Routine Description:
  85. This routine maintains a reference count of how many devices have requested power.
  86. When the count decrements from one to zero, a call is made to actually turn power
  87. off.
  88. Arguments:
  89. Socket - Pointer to the socket for which power is to be removed
  90. PowerCompletionRoutine - routine to be called after configuration is complete
  91. Return value:
  92. status
  93. --*/
  94. {
  95. NTSTATUS status = STATUS_SUCCESS;
  96. PSOCKET socket = PdoExtension->Socket;
  97. PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
  98. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x release power\n", socket));
  99. if (PCMCIA_TEST_AND_RESET(&PdoExtension->SocketPowerRequested)) {
  100. if (InterlockedDecrement(&socket->PowerRequests) == 0) {
  101. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power requests now %d, status %08x\n", socket, socket->PowerRequests));
  102. //
  103. // Never actually turn off the drive rails for cardbus functions since
  104. // we don't have tight integration with pci.sys, and config space will
  105. // disappear
  106. //
  107. if (!IsCardBusCardInSocket(socket)) {
  108. status = PcmciaSetSocketPower(socket, PowerCompletionRoutine, PdoExtension, FALSE);
  109. }
  110. }
  111. ASSERT(socket->PowerRequests >= 0);
  112. }
  113. return status;
  114. }
  115. NTSTATUS
  116. PcmciaSetSocketPower(
  117. IN PSOCKET Socket,
  118. IN PPCMCIA_COMPLETION_ROUTINE PowerCompletionRoutine,
  119. IN PVOID Context,
  120. IN BOOLEAN PowerOn
  121. )
  122. /*++
  123. Routine Description:
  124. This routine is entered when we know the power state of the socket will
  125. actually be set.
  126. NOTE: If this routine is called at less than DISPATCH_LEVEL, then the call
  127. will complete (not return STATUS_PENDING). If this routine is called at
  128. DISPATCH_LEVEL or greater, this routine returns STATUS_PENDING, and completes
  129. the power process using a KTIMER.
  130. Arguments:
  131. Socket - Pointer to the socket for which power is to be removed
  132. PowerCompletionRoutine - routine to be called after configuration is complete
  133. Return value:
  134. status
  135. --*/
  136. {
  137. NTSTATUS status;
  138. PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
  139. SPW_STATE InitialState = PowerOn ? SPW_RequestPower : SPW_ReleasePower;
  140. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x set power %s\n", Socket, PowerOn ? "ON" : "OFF"));
  141. if (!PCMCIA_TEST_AND_SET(&Socket->WorkerBusy)) {
  142. return STATUS_DEVICE_BUSY;
  143. }
  144. ASSERT(Socket->WorkerState == SPW_Stopped);
  145. //
  146. // committed, will enter SocketPowerWorker now
  147. //
  148. Socket->WorkerState = InitialState;
  149. Socket->PowerCompletionRoutine = PowerCompletionRoutine;
  150. Socket->PowerCompletionContext = Context;
  151. PcmciaSocketPowerWorker(&Socket->PowerDpc, Socket, NULL, NULL);
  152. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x SetSocketPower returning %08x\n",
  153. Socket, Socket->CallerStatus));
  154. return(Socket->CallerStatus);
  155. }
  156. VOID
  157. PcmciaSocketPowerWorker(
  158. IN PKDPC Dpc,
  159. IN PVOID Context,
  160. IN PVOID SystemArgument1,
  161. IN PVOID SystemArgument2
  162. )
  163. /*++
  164. Routine Description
  165. This routine handles the power up process of a socket. Because such
  166. long delays are needed, and because this routine may be called at
  167. raised irql, this is a state machine that has the capability of
  168. calling itself on a KTIMER.
  169. Arguments
  170. same as KDPC (DeferredContext is socket)
  171. Return Value
  172. status
  173. --*/
  174. {
  175. PSOCKET Socket = Context;
  176. PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
  177. NTSTATUS status = Socket->DeferredStatus;
  178. ULONG DelayTime = 0;
  179. BOOLEAN ContinueExecution = TRUE;
  180. #if DBG
  181. {
  182. ULONG Phase = 0;
  183. switch(Socket->WorkerState) {
  184. case SPW_SetPowerOn:
  185. case SPW_SetPowerOff:
  186. Phase = Socket->PowerPhase;
  187. break;
  188. }
  189. if (Phase) {
  190. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power worker - %s(%d)\n", Socket,
  191. SOCKET_POWER_WORKER_STRING(Socket->WorkerState), Phase));
  192. } else {
  193. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power worker - %s\n", Socket,
  194. SOCKET_POWER_WORKER_STRING(Socket->WorkerState)));
  195. }
  196. }
  197. #endif
  198. //
  199. // Socket power state machine
  200. //
  201. switch(Socket->WorkerState) {
  202. case SPW_RequestPower:
  203. status = STATUS_SUCCESS;
  204. if (IsSocketFlagSet(Socket, SOCKET_CARD_POWERED_UP)) {
  205. Socket->WorkerState = SPW_Exit;
  206. } else {
  207. if ((KeGetCurrentIrql() >= DISPATCH_LEVEL) && (Socket->PowerCompletionRoutine == NULL)) {
  208. ASSERT((KeGetCurrentIrql() < DISPATCH_LEVEL) || (Socket->PowerCompletionRoutine != NULL));
  209. //
  210. // no completion routine at raised irql
  211. //
  212. status = STATUS_INVALID_PARAMETER;
  213. } else {
  214. //
  215. // All ok, continue to next state
  216. //
  217. Socket->PowerPhase = 1;
  218. Socket->WorkerState = SPW_SetPowerOn;
  219. }
  220. }
  221. break;
  222. case SPW_ReleasePower:
  223. status = STATUS_SUCCESS;
  224. if (!IsSocketFlagSet(Socket, SOCKET_CARD_POWERED_UP)) {
  225. Socket->WorkerState = SPW_Exit;
  226. } else {
  227. if ((KeGetCurrentIrql() >= DISPATCH_LEVEL) && (Socket->PowerCompletionRoutine == NULL)) {
  228. ASSERT((KeGetCurrentIrql() < DISPATCH_LEVEL) || (Socket->PowerCompletionRoutine != NULL));
  229. //
  230. // no completion routine at raised irql
  231. //
  232. status = STATUS_INVALID_PARAMETER;
  233. } else {
  234. //
  235. // All ok, continue to next state
  236. //
  237. Socket->WorkerState = SPW_Deconfigure;
  238. }
  239. }
  240. break;
  241. case SPW_SetPowerOn:
  242. //
  243. // Turn power ON
  244. //
  245. status = (*(DeviceDispatchTable[fdoExtension->DeviceDispatchIndex].SetPower))
  246. (Socket, TRUE, &DelayTime);
  247. Socket->PowerPhase++;
  248. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  249. if (NT_SUCCESS(status)) {
  250. //
  251. // Done with power up, proceed to the init sequence
  252. //
  253. SetSocketFlag(Socket, SOCKET_CARD_POWERED_UP);
  254. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power UP\n", Socket));
  255. Socket->WorkerState = SPW_ResetCard;
  256. Socket->CardResetPhase = 1;
  257. } else if (status == STATUS_INVALID_DEVICE_STATE) {
  258. //
  259. // Power was already on, don't reset the card
  260. //
  261. SetSocketFlag(Socket, SOCKET_CARD_POWERED_UP);
  262. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power already UP\n", Socket));
  263. Socket->WorkerState = SPW_Exit;
  264. status = STATUS_SUCCESS;
  265. } else {
  266. //
  267. // Power didn't go on
  268. //
  269. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x poweron fail %08x\n", Socket, status));
  270. Socket->WorkerState = SPW_Exit;
  271. }
  272. }
  273. break;
  274. case SPW_ResetCard:
  275. //
  276. // Make sure the card is ready to be enumerated
  277. //
  278. status = (*(Socket->SocketFnPtr->PCBResetCard))(Socket, &DelayTime);
  279. Socket->CardResetPhase++;
  280. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  281. Socket->WorkerState = SPW_Exit;
  282. }
  283. break;
  284. case SPW_Deconfigure:
  285. PcmciaSocketDeconfigure(Socket);
  286. Socket->PowerPhase = 1;
  287. Socket->WorkerState = SPW_SetPowerOff;
  288. break;
  289. case SPW_SetPowerOff:
  290. //
  291. // Turn power OFF
  292. //
  293. status = (*(DeviceDispatchTable[fdoExtension->DeviceDispatchIndex].SetPower))
  294. (Socket, FALSE, &DelayTime);
  295. Socket->PowerPhase++;
  296. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  297. Socket->WorkerState = SPW_Exit;
  298. if (NT_SUCCESS(status)) {
  299. //
  300. // Power is now off
  301. //
  302. ResetSocketFlag(Socket, SOCKET_CARD_POWERED_UP);
  303. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power DOWN\n", Socket));
  304. } else if (status == STATUS_INVALID_DEVICE_STATE) {
  305. //
  306. // Power was already off
  307. //
  308. ResetSocketFlag(Socket, SOCKET_CARD_POWERED_UP);
  309. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power already DOWN\n", Socket));
  310. status = STATUS_SUCCESS;
  311. } else {
  312. //
  313. // Power didn't go off
  314. //
  315. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x poweroff fail %08x\n", Socket, status));
  316. Socket->WorkerState = SPW_Exit;
  317. }
  318. }
  319. break;
  320. case SPW_Exit:
  321. if (!NT_SUCCESS(status)) {
  322. DebugPrint((PCMCIA_DEBUG_FAIL, "skt %08x SocketPowerWorker FAILED, status %08x\n", Socket, status));
  323. ASSERT(NT_SUCCESS(status));
  324. }
  325. //
  326. // Done. Update flags, and call the completion routine if required
  327. //
  328. if (PCMCIA_TEST_AND_RESET(&Socket->DeferredStatusLock)) {
  329. PPCMCIA_COMPLETION_ROUTINE PowerCompletionRoutine = Socket->PowerCompletionRoutine;
  330. PVOID PowerCompletionContext = Socket->PowerCompletionContext;
  331. Socket->WorkerState = SPW_Stopped;
  332. PCMCIA_TEST_AND_RESET(&Socket->WorkerBusy);
  333. if (PowerCompletionRoutine) {
  334. (*PowerCompletionRoutine)(PowerCompletionContext, status);
  335. } else {
  336. ASSERT(PowerCompletionRoutine != NULL);
  337. }
  338. } else {
  339. Socket->CallerStatus = status;
  340. Socket->WorkerState = SPW_Stopped;
  341. PCMCIA_TEST_AND_RESET(&Socket->WorkerBusy);
  342. }
  343. return;
  344. default:
  345. ASSERT(FALSE);
  346. return;
  347. }
  348. //
  349. // Now check the results
  350. //
  351. if (status == STATUS_PENDING) {
  352. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x worker exit, status pending\n", Socket));
  353. //
  354. // whatever returned pending will call us back
  355. //
  356. if (PCMCIA_TEST_AND_SET(&Socket->DeferredStatusLock)) {
  357. //
  358. // First time that we are waiting, we will return to original
  359. // caller. So update the main power status just this time.
  360. //
  361. Socket->CallerStatus = STATUS_PENDING;
  362. }
  363. return;
  364. }
  365. //
  366. // remember for next time
  367. //
  368. Socket->DeferredStatus = status;
  369. if (!NT_SUCCESS(status) && (status != STATUS_MORE_PROCESSING_REQUIRED)) {
  370. Socket->WorkerState = SPW_Exit;
  371. DelayTime = 0;
  372. }
  373. //
  374. // Not done yet. Recurse or call timer
  375. //
  376. if (DelayTime) {
  377. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x power worker delay type %s, %d usec\n", Socket,
  378. (KeGetCurrentIrql() < DISPATCH_LEVEL) ? "Wait" : "Timer",
  379. DelayTime));
  380. if ((KeGetCurrentIrql() < DISPATCH_LEVEL) && !Socket->PowerCompletionRoutine) {
  381. PcmciaWait(DelayTime);
  382. } else {
  383. LARGE_INTEGER dueTime;
  384. //
  385. // Running on a DPC, kick of a kernel timer
  386. //
  387. if (PCMCIA_TEST_AND_SET(&Socket->DeferredStatusLock)) {
  388. //
  389. // First time that we are waiting, we will return to original
  390. // caller. So update the main power status just this time.
  391. //
  392. Socket->CallerStatus = STATUS_PENDING;
  393. }
  394. dueTime.QuadPart = -((LONG) DelayTime*10);
  395. KeSetTimer(&Socket->PowerTimer, dueTime, &Socket->PowerDpc);
  396. //
  397. // We will reenter on timer dpc
  398. //
  399. return;
  400. }
  401. }
  402. //
  403. // Recurse
  404. //
  405. PcmciaSocketPowerWorker(&Socket->PowerDpc, Socket, NULL, NULL);
  406. }
  407. VOID
  408. PcmciaGetSocketStatus(
  409. IN PSOCKET Socket
  410. )
  411. /*++
  412. Routine Description:
  413. A small utility routine that returns some common socket flags. The reason
  414. it exists is to allow the Enumerate Devices routine to remain pagable.
  415. NOTE: This routine updates the "software view" of the device state. This
  416. should only be done at well-defined points in the driver. In particular,
  417. you do not want to be updating the software state immediately after
  418. a surprise remove. Instead, most of the driver needs to continue to
  419. believe the card is still there while it does its unconfigure and
  420. poweroff.
  421. Arguments:
  422. Socket - The socket in which the PC-Card resides
  423. boolean parameters are written according to socket flags
  424. Return Value:
  425. none
  426. --*/
  427. {
  428. BOOLEAN isCardInSocket, isCardBusCard;
  429. UCHAR previousDeviceState;
  430. PCMCIA_ACQUIRE_DEVICE_LOCK(Socket->DeviceExtension);
  431. isCardInSocket = (*(Socket->SocketFnPtr->PCBDetectCardInSocket))(Socket);
  432. isCardBusCard = FALSE;
  433. if (isCardInSocket && CardBus(Socket)) {
  434. isCardBusCard = ((CBReadSocketRegister(Socket, CARDBUS_SOCKET_PRESENT_STATE_REG) & CARDBUS_CB_CARD) != 0);
  435. }
  436. previousDeviceState = Socket->DeviceState;
  437. if (!isCardInSocket) {
  438. SetSocketEmpty(Socket);
  439. } else if (isCardBusCard) {
  440. SetCardBusCardInSocket(Socket);
  441. } else {
  442. Set16BitCardInSocket(Socket);
  443. }
  444. if (previousDeviceState != Socket->DeviceState) {
  445. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %x Socket Status: Card Status Change!\n", Socket));
  446. SetSocketFlag(Socket, SOCKET_CARD_STATUS_CHANGE);
  447. }
  448. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %x Socket Status: %s\n",
  449. Socket, isCardInSocket ? (isCardBusCard ? "INSERTED Cardbus" : "INSERTED R2") : "EMPTY"));
  450. PCMCIA_RELEASE_DEVICE_LOCK(Socket->DeviceExtension);
  451. //
  452. // Fill in socket power values
  453. //
  454. if (isCardInSocket && IsSocketFlagSet(Socket, SOCKET_CARD_STATUS_CHANGE) && Socket->SocketFnPtr->PCBGetPowerRequirements) {
  455. (*(Socket->SocketFnPtr->PCBGetPowerRequirements))(Socket);
  456. }
  457. }
  458. NTSTATUS
  459. PcmciaGetConfigData(
  460. PPDO_EXTENSION PdoExtension
  461. )
  462. /*++
  463. Routine Description:
  464. This routine controls the translation of the CIS config data for the card into
  465. SOCKET_DATA structures chained onto the PDO. The action of this routine depends
  466. on the type of device:
  467. 1) For a standard R2 card, a single SOCKET_DATA structure is linked to the pdo
  468. extension, which contains a straight translation of the CIS contents.
  469. 2) For a fully compliant true R2 MF card, a chain of SOCKET_DATA structures is
  470. created, one for each function on the card.
  471. 3) For a non-conforming R2 MF card (the typical case), a single structure is
  472. linked just like case #1.
  473. 4) For a CardBus card, a single SOCKET_DATA is linked to the pdo extension. If
  474. there are multiple functions on the device, then there will be multiple pdo
  475. extensions, each with a single SOCKET_DATA structure.
  476. Arguments:
  477. pdoExtension - The pdo extension corresponding to the specified pccard or cb function.
  478. Return Value:
  479. STATUS_SUCCESS
  480. STATUS_NO_SUCH_DEVICE if no card is present in the socket (i.e. the passed in PDO is 'dead')
  481. --*/
  482. {
  483. NTSTATUS status = STATUS_SUCCESS;
  484. PSOCKET_DATA socketData, prevSocketData;
  485. PSOCKET_DATA socketDataList = NULL;
  486. UCHAR function = 0;
  487. PSOCKET Socket = PdoExtension->Socket;
  488. PAGED_CODE ();
  489. if (!IsCardInSocket(Socket)) {
  490. //
  491. // Card probably removed,
  492. // and Pdo's ghost still hanging around
  493. //
  494. return STATUS_NO_SUCH_DEVICE;
  495. }
  496. ResetSocketFlag(Socket, SOCKET_CARD_MEMORY);
  497. ResetSocketFlag(Socket, SOCKET_CARD_CONFIGURED);
  498. DebugPrint((PCMCIA_DEBUG_SOCKET, "skt %08x performing GetSocketData\n", Socket));
  499. Socket->NumberOfFunctions = 1;
  500. prevSocketData = NULL;
  501. while (function < 255) {
  502. //
  503. // Parse tuples of next function on the card
  504. //
  505. socketData = ExAllocatePool(NonPagedPool, sizeof(SOCKET_DATA));
  506. if (socketData == NULL) {
  507. status = STATUS_INSUFFICIENT_RESOURCES;
  508. break;
  509. }
  510. RtlZeroMemory(socketData, sizeof(SOCKET_DATA));
  511. socketData->Function = function;
  512. socketData->PdoExtension = PdoExtension;
  513. socketData->Socket = Socket;
  514. DebugPrint((PCMCIA_DEBUG_SOCKET, "Parsing function %d...\n", socketData->Function));
  515. status = PcmciaParseFunctionData(Socket, socketData);
  516. if (NT_SUCCESS(status)) {
  517. //
  518. // Link it to the list of socketdata structures
  519. //
  520. socketData->Prev = prevSocketData;
  521. socketData->Next = NULL;
  522. if (prevSocketData) {
  523. prevSocketData->Next = socketData;
  524. } else {
  525. //
  526. // This is the first function on the card
  527. // Make it the head of the list
  528. //
  529. socketDataList = socketData;
  530. }
  531. if (socketData->DeviceType == PCCARD_TYPE_MODEM) {
  532. SetDeviceFlag(PdoExtension, PCMCIA_PDO_ENABLE_AUDIO);
  533. }
  534. } else {
  535. //
  536. // no more functions on this card
  537. //
  538. ExFreePool(socketData);
  539. if ((function > 0) && (status == STATUS_NO_MORE_ENTRIES)) {
  540. status = STATUS_SUCCESS;
  541. }
  542. break;
  543. }
  544. function++;
  545. prevSocketData = socketData;
  546. }
  547. if (!NT_SUCCESS(status)) {
  548. socketData = socketDataList;
  549. while(socketData) {
  550. prevSocketData = socketData;
  551. socketData = socketData->Next;
  552. ExFreePool(prevSocketData);
  553. }
  554. } else {
  555. PdoExtension->SocketData = socketDataList;
  556. }
  557. return status;
  558. }
  559. UCHAR
  560. PcmciaReadCISChar(
  561. PPDO_EXTENSION PdoExtension,
  562. IN MEMORY_SPACE MemorySpace,
  563. IN ULONG Offset
  564. )
  565. /*++
  566. Routine Description:
  567. Returns the card data. This information is cached in the socket
  568. structure. This way once a PCCARD is enabled it will not be touched
  569. due to a query ioctl.
  570. Arguments:
  571. Context
  572. Return Value:
  573. TRUE
  574. --*/
  575. {
  576. PSOCKET socket = PdoExtension->Socket;
  577. PDEVICE_OBJECT pdo;
  578. UCHAR retValue = 0xff;
  579. ULONG relativeOffset;
  580. ULONG bytesRead;
  581. if (socket && IsCardInSocket(socket)) {
  582. if (!PdoExtension->CisCache) {
  583. #define PCMCIA_CIS_CACHE_SIZE 2048
  584. PdoExtension->CisCache = ExAllocatePool(NonPagedPool, PCMCIA_CIS_CACHE_SIZE);
  585. PdoExtension->CisCacheSpace = 0xff;
  586. PdoExtension->CisCacheBase = 0;
  587. }
  588. if (PdoExtension->CisCache) {
  589. if ((MemorySpace != PdoExtension->CisCacheSpace) ||
  590. (Offset < PdoExtension->CisCacheBase) ||
  591. (Offset > PdoExtension->CisCacheBase + PCMCIA_CIS_CACHE_SIZE - 1)) {
  592. //
  593. // LATER: If devices have CIS > CacheSize, then we should window this
  594. //
  595. bytesRead = (*(socket->SocketFnPtr->PCBReadCardMemory))(PdoExtension,
  596. MemorySpace,
  597. 0,
  598. PdoExtension->CisCache,
  599. PCMCIA_CIS_CACHE_SIZE);
  600. PdoExtension->CisCacheSpace = MemorySpace;
  601. }
  602. relativeOffset = Offset - PdoExtension->CisCacheBase;
  603. if (relativeOffset < PCMCIA_CIS_CACHE_SIZE) {
  604. retValue = PdoExtension->CisCache[relativeOffset];
  605. }
  606. }
  607. }
  608. return retValue;
  609. }
  610. NTSTATUS
  611. PcmciaReadWriteCardMemory(
  612. IN PDEVICE_OBJECT Pdo,
  613. IN ULONG WhichSpace,
  614. IN OUT PUCHAR Buffer,
  615. IN ULONG Offset,
  616. IN ULONG Length,
  617. IN BOOLEAN Read
  618. )
  619. /*++
  620. Routine Description:
  621. This routine is to provide IRP_MN_READ_CONFIG/WRITE_CONFIG support: this would locate the
  622. socket on which Pdo resides and map the card's memory into the system space.
  623. If Read is TRUE it would:
  624. copy the contents of the config memory at a specified offset and length to the
  625. caller supplied buffer.
  626. else
  627. copy the contents of the caller specified buffer at the specified offset and length of
  628. the config memory
  629. Note: this has to be non-paged since it can be called by
  630. clients at DISPATCH_LEVEL
  631. Arguments:
  632. Pdo - Device object representing the PC-CARD whose config memory needs to be read/written
  633. WhichSpace - Indicates which memory space needs to be mapped: one of
  634. PCCARD_COMMON_MEMORY_SPACE
  635. PCCARD_ATTRIBUTE_MEMORY_SPACE
  636. PCCARD_PCI_CONFIGURATION_MEMORY_SPACE (only for cardbus cards)
  637. Buffer - Caller supplied buffer into/out of which the memory contents are copied
  638. Offset - Offset of the attribute memory at which we copy
  639. Length - Number of bytes of attribute memory/buffer to be copied
  640. Return value:
  641. STATUS_INVALID_PARAMETER_1
  642. STATUS_INVALID_PARAMETER_2
  643. STATUS_INVALID_PARAMETER_3 If supplied parameters are not valid
  644. STATUS_NO_SUCH_DEVICE No PC-Card in the socket
  645. STATUS_DEVICE_NOT_READY PC-Card not initialized yet or some other hardware related error
  646. STATUS_SUCCESS Contents copied as requested
  647. --*/
  648. {
  649. PSOCKET socket;
  650. PSOCKET_DATA socketData;
  651. PUCHAR tupleData;
  652. ULONG tupleDataSize;
  653. PPDO_EXTENSION pdoExtension;
  654. NTSTATUS status = STATUS_UNSUCCESSFUL;
  655. pdoExtension = Pdo->DeviceExtension;
  656. socket= pdoExtension->Socket;
  657. //
  658. // Got to have a card in the socket to read/write from it..
  659. //
  660. if (!IsCardInSocket(socket)) {
  661. return STATUS_NO_SUCH_DEVICE;
  662. }
  663. //
  664. // Memory space has to be one of the defined ones.
  665. //
  666. if ((WhichSpace != PCCARD_COMMON_MEMORY) &&
  667. (WhichSpace != PCCARD_ATTRIBUTE_MEMORY) &&
  668. (WhichSpace != PCCARD_PCI_CONFIGURATION_SPACE)) {
  669. return STATUS_INVALID_PARAMETER_1;
  670. }
  671. //
  672. // We support PCCARD_PCI_CONFIGURATION_SPACE only
  673. // for cardbus cards (doesn't make sense for R2 cards)
  674. // Similarily PCCARD_ATTRIBUTE/COMMON_MEMORY only for
  675. // R2 cards
  676. //
  677. if ((((WhichSpace == PCCARD_ATTRIBUTE_MEMORY) ||
  678. (WhichSpace == PCCARD_COMMON_MEMORY)) && !Is16BitCard(pdoExtension)) ||
  679. ((WhichSpace == PCCARD_PCI_CONFIGURATION_SPACE) && !IsCardBusCard(pdoExtension))) {
  680. return STATUS_INVALID_PARAMETER_1;
  681. }
  682. if (!Buffer) {
  683. return STATUS_INVALID_PARAMETER_2;
  684. }
  685. if (WhichSpace == PCCARD_PCI_CONFIGURATION_SPACE) {
  686. //
  687. // This has to be a cardbus card.
  688. //
  689. // NOTE: unimplemented: fill this in! send an IRP down to PCI
  690. // to get the config space
  691. status = STATUS_NOT_SUPPORTED;
  692. } else {
  693. //
  694. // This has to be an R2 Card.
  695. // Attribute/common memory space
  696. //
  697. ASSERT ((WhichSpace == PCCARD_ATTRIBUTE_MEMORY) ||
  698. (WhichSpace == PCCARD_COMMON_MEMORY));
  699. //
  700. // Offset and length are >= 0 because they are ULONGs,
  701. // so don't worry about that.
  702. //
  703. if (!IsSocketFlagSet(socket, SOCKET_CARD_POWERED_UP)) {
  704. return STATUS_DEVICE_NOT_READY;
  705. }
  706. PCMCIA_ACQUIRE_DEVICE_LOCK(socket->DeviceExtension);
  707. if (Read && (socket->SocketFnPtr->PCBReadCardMemory != NULL)) {
  708. //
  709. // Read from card memory
  710. //
  711. status = ((*(socket->SocketFnPtr->PCBReadCardMemory))(pdoExtension,
  712. WhichSpace,
  713. Offset,
  714. Buffer,
  715. Length) == Length)
  716. ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  717. } else if (socket->SocketFnPtr->PCBWriteCardMemory != NULL) {
  718. //
  719. // Write to card memory
  720. //
  721. status = ((*(socket->SocketFnPtr->PCBWriteCardMemory))(pdoExtension,
  722. WhichSpace,
  723. Offset,
  724. Buffer,
  725. Length) == Length)
  726. ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  727. }
  728. PCMCIA_RELEASE_DEVICE_LOCK(socket->DeviceExtension);
  729. }
  730. return status;
  731. }
  732. NTSTATUS
  733. PcmciaConfigureCardBusCard(
  734. PPDO_EXTENSION pdoExtension
  735. )
  736. /*++
  737. Routine Description:
  738. This routine does some verification, and applies hacks
  739. Arguments:
  740. pdoExtension - Pointer to the physical device object extension for the pc-card
  741. Return value:
  742. status
  743. --*/
  744. {
  745. ULONG i, pciConfig;
  746. NTSTATUS status = STATUS_SUCCESS;
  747. PSOCKET Socket = pdoExtension->Socket;
  748. for (i = 0; i < CARDBUS_CONFIG_RETRY_COUNT; i++) {
  749. GetPciConfigSpace(pdoExtension, CFGSPACE_VENDOR_ID, &pciConfig, sizeof(pciConfig));
  750. if (pciConfig != 0xffffffff) {
  751. break;
  752. }
  753. }
  754. if (pciConfig == 0xffffffff) {
  755. DebugPrint((PCMCIA_DEBUG_FAIL, "pdo %08x failed to verify CardBus config space\n", pdoExtension->DeviceObject));
  756. status = STATUS_DEVICE_NOT_READY;
  757. } else {
  758. PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
  759. //
  760. // The TI1130, 1131, 1031 have a bug such that CAUDIO on a cardbus card
  761. // is gated by the following bit (which normally only has meaning only
  762. // for R2 cards). We can workaround the problem simply by turning it on
  763. // for cardbus cards.
  764. //
  765. if ((fdoExtension->ControllerType == PcmciaTI1130) ||
  766. (fdoExtension->ControllerType == PcmciaTI1131) ||
  767. (fdoExtension->ControllerType == PcmciaTI1031)) {
  768. UCHAR byte;
  769. byte = PcicReadSocket(Socket, PCIC_INTERRUPT);
  770. byte |= IGC_PCCARD_IO;
  771. PcicWriteSocket(Socket, PCIC_INTERRUPT, byte);
  772. }
  773. }
  774. return status;
  775. }
  776. NTSTATUS
  777. PcmciaConfigurePcCard(
  778. PPDO_EXTENSION pdoExtension,
  779. IN PPCMCIA_COMPLETION_ROUTINE ConfigCompletionRoutine
  780. )
  781. /*++
  782. Routine Description:
  783. This routine does the brunt work of enabling the PC-Card using the supplied
  784. resources.
  785. NOTE: If this routine is called at less than DISPATCH_LEVEL, then the call
  786. will complete (not return STATUS_PENDING). If this routine is called at
  787. DISPATCH_LEVEL or greater, this routine returns STATUS_PENDING, and completes
  788. the configuration process using a KTIMER.
  789. Arguments:
  790. pdoExtension - Pointer to the physical device object extension for the pc-card
  791. ConfigCompletionRoutine - routine to be called after configuration is complete
  792. Return value:
  793. status
  794. --*/
  795. {
  796. DebugPrint((PCMCIA_DEBUG_CONFIG, "pdo %08x ConfigurePcCard entered\n", pdoExtension->DeviceObject));
  797. if (!PCMCIA_TEST_AND_SET(&pdoExtension->Socket->WorkerBusy)) {
  798. return STATUS_DEVICE_BUSY;
  799. }
  800. ASSERT(pdoExtension->ConfigurationPhase == CW_Stopped);
  801. pdoExtension->ConfigurationPhase = CW_InitialState;
  802. pdoExtension->ConfigCompletionRoutine = ConfigCompletionRoutine;
  803. pdoExtension->ConfigurationStatus = STATUS_SUCCESS;
  804. PcmciaConfigurationWorker(&pdoExtension->ConfigurationDpc, pdoExtension, NULL, NULL);
  805. DebugPrint((PCMCIA_DEBUG_CONFIG, "pdo %08x ConfigurePcCard returning %08x\n", pdoExtension->DeviceObject, pdoExtension->ConfigurationStatus));
  806. return(pdoExtension->ConfigurationStatus);
  807. }
  808. VOID
  809. PcmciaConfigurationWorker(
  810. IN PKDPC Dpc,
  811. IN PVOID DeferredContext,
  812. IN PVOID SystemArgument1,
  813. IN PVOID SystemArgument2
  814. )
  815. /*++
  816. Routine Description
  817. This routine handles the configuration process of a 16-bit R2 pccard.
  818. Because certain cards are finicky (modems), and require gigantic pauses
  819. between steps, this worker routine acts as a state machine, and will
  820. delay after each step.
  821. Arguments
  822. same as KDPC (DeferredContext is pdoExtension)
  823. Return Value
  824. status
  825. --*/
  826. {
  827. PPDO_EXTENSION pdoExtension = DeferredContext;
  828. PSOCKET Socket = pdoExtension->Socket;
  829. PSOCKET_CONFIGURATION SocketConfig = pdoExtension->SocketConfiguration;
  830. NTSTATUS status = pdoExtension->DeferredConfigurationStatus;
  831. ULONG DelayUsec = 0;
  832. DebugPrint((PCMCIA_DEBUG_CONFIG, "pdo %08x config worker - %s\n", pdoExtension->DeviceObject,
  833. CONFIGURATION_WORKER_STRING(pdoExtension->ConfigurationPhase)));
  834. switch(pdoExtension->ConfigurationPhase) {
  835. case CW_InitialState:
  836. if (IsSocketFlagSet(pdoExtension->Socket, SOCKET_CARD_CONFIGURED)) {
  837. pdoExtension->ConfigurationPhase = CW_Exit;
  838. break;
  839. }
  840. if (!IsCardInSocket(pdoExtension->Socket)) {
  841. status = STATUS_NO_SUCH_DEVICE;
  842. pdoExtension->ConfigurationPhase = CW_Exit;
  843. break;
  844. }
  845. pdoExtension->ConfigurationPhase = CW_ResetCard;
  846. Socket->CardResetPhase = 1;
  847. break;
  848. case CW_ResetCard:
  849. //
  850. // Reset the card
  851. //
  852. status = (*(Socket->SocketFnPtr->PCBResetCard))(Socket, &DelayUsec);
  853. Socket->CardResetPhase++;
  854. if (status != STATUS_MORE_PROCESSING_REQUIRED) {
  855. pdoExtension->ConfigurationPhase = CW_Phase1;
  856. }
  857. break;
  858. case CW_Phase1:
  859. //
  860. // Initialize variables
  861. //
  862. PcmciaConfigurationWorkerInitialization(pdoExtension);
  863. //
  864. // Configure the cards configuration registers, and the socket mem
  865. // and I/O windows
  866. //
  867. status = PcmciaConfigurePcCardRegisters(pdoExtension);
  868. if (NT_SUCCESS(status)) {
  869. status = PcmciaConfigurePcCardMemIoWindows(Socket, SocketConfig);
  870. }
  871. DelayUsec = 1000 * (ULONG)pdoExtension->ConfigureDelay1;
  872. pdoExtension->ConfigurationPhase = CW_Phase2;
  873. break;
  874. case CW_Phase2:
  875. //
  876. // Take this opportunity to "poke" the modem
  877. //
  878. if (pdoExtension->ConfigurationFlags & CONFIG_WORKER_APPLY_MODEM_HACK) {
  879. PcmciaConfigureModemHack(Socket, SocketConfig);
  880. }
  881. DelayUsec = 1000 * (ULONG)pdoExtension->ConfigureDelay2;
  882. pdoExtension->ConfigurationPhase = CW_Phase3;
  883. break;
  884. case CW_Phase3:
  885. //
  886. // Configure the IRQ
  887. //
  888. status = PcmciaConfigurePcCardIrq(Socket, SocketConfig);
  889. DelayUsec = 1000 * (ULONG)pdoExtension->ConfigureDelay3;
  890. pdoExtension->ConfigurationPhase = CW_Exit;
  891. break;
  892. case CW_Exit:
  893. //
  894. // Done. Update flags, and call the completion routine if required
  895. //
  896. if (IsDeviceFlagSet(pdoExtension, PCMCIA_CONFIG_STATUS_DEFERRED)) {
  897. if (pdoExtension->ConfigCompletionRoutine) {
  898. (*pdoExtension->ConfigCompletionRoutine)(pdoExtension,
  899. pdoExtension->DeferredConfigurationStatus);
  900. }
  901. ResetDeviceFlag(pdoExtension, PCMCIA_CONFIG_STATUS_DEFERRED);
  902. } else {
  903. pdoExtension->ConfigurationStatus = status;
  904. }
  905. if (NT_SUCCESS(status)) {
  906. SetSocketFlag(Socket, SOCKET_CARD_CONFIGURED);
  907. }
  908. pdoExtension->ConfigurationPhase = CW_Stopped;
  909. PCMCIA_TEST_AND_RESET(&Socket->WorkerBusy);
  910. DebugPrint((PCMCIA_DEBUG_CONFIG, "pdo %08x config worker exit %08x\n", pdoExtension->DeviceObject, status));
  911. return;
  912. default:
  913. ASSERT(FALSE);
  914. return;
  915. }
  916. pdoExtension->DeferredConfigurationStatus = status;
  917. if (!NT_SUCCESS(status) && (status != STATUS_MORE_PROCESSING_REQUIRED)) {
  918. DelayUsec = 0;
  919. pdoExtension->ConfigurationPhase = CW_Exit;
  920. }
  921. //
  922. // Not done yet. Recurse or call timer
  923. //
  924. if (DelayUsec) {
  925. DebugPrint((PCMCIA_DEBUG_CONFIG, "pdo %08x config worker delay type %s, %d usec\n",
  926. pdoExtension->DeviceObject,
  927. (KeGetCurrentIrql() < DISPATCH_LEVEL) ? "Wait" : "Timer",
  928. DelayUsec));
  929. if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
  930. PcmciaWait(DelayUsec);
  931. } else {
  932. LARGE_INTEGER dueTime;
  933. dueTime.QuadPart = -((LONG) DelayUsec*10);
  934. //
  935. // Running on a DPC, kick of a kernel timer
  936. //
  937. KeSetTimer(&pdoExtension->ConfigurationTimer,
  938. dueTime,
  939. &pdoExtension->ConfigurationDpc);
  940. if (!IsDeviceFlagSet(pdoExtension, PCMCIA_CONFIG_STATUS_DEFERRED)) {
  941. SetDeviceFlag(pdoExtension, PCMCIA_CONFIG_STATUS_DEFERRED);
  942. pdoExtension->ConfigurationStatus = STATUS_PENDING;
  943. }
  944. return;
  945. }
  946. }
  947. PcmciaConfigurationWorker(&pdoExtension->ConfigurationDpc, pdoExtension, NULL, NULL);
  948. }
  949. VOID
  950. PcmciaConfigurationWorkerInitialization(
  951. PPDO_EXTENSION pdoExtension
  952. )
  953. /*++
  954. Routine Description:
  955. This routine sets variables which control the configuration process.
  956. Arguments:
  957. pdoExtension - Pointer to the physical device object extension for the pc-card
  958. Return value:
  959. none
  960. --*/
  961. {
  962. PSOCKET_DATA socketData = pdoExtension->SocketData;
  963. ULONG i;
  964. pdoExtension->ConfigurationFlags = 0;
  965. pdoExtension->ConfigureDelay1 = 0;
  966. pdoExtension->ConfigureDelay2 = 0;
  967. pdoExtension->ConfigureDelay3 = 0;
  968. while (socketData) {
  969. i = 0;
  970. while (DeviceConfigParams[i].ValidEntry) {
  971. if (((DeviceConfigParams[i].DeviceType == 0xff) ||
  972. (DeviceConfigParams[i].DeviceType == socketData->DeviceType)) &&
  973. ((DeviceConfigParams[i].ManufacturerCode == 0xffff) ||
  974. (DeviceConfigParams[i].ManufacturerCode == socketData->ManufacturerCode)) &&
  975. ((DeviceConfigParams[i].ManufacturerInfo == 0xffff) ||
  976. (DeviceConfigParams[i].ManufacturerInfo == socketData->ManufacturerInfo)) &&
  977. ((DeviceConfigParams[i].CisCrc == 0xffff) ||
  978. (DeviceConfigParams[i].CisCrc == socketData->CisCrc))) {
  979. pdoExtension->ConfigurationFlags = DeviceConfigParams[i].ConfigFlags;
  980. pdoExtension->ConfigureDelay1 = DeviceConfigParams[i].ConfigDelay1;
  981. pdoExtension->ConfigureDelay2 = DeviceConfigParams[i].ConfigDelay2;
  982. pdoExtension->ConfigureDelay3 = DeviceConfigParams[i].ConfigDelay3;
  983. break;
  984. }
  985. i++;
  986. }
  987. socketData = socketData->Next;
  988. }
  989. }
  990. NTSTATUS
  991. PcmciaConfigurePcCardMemIoWindows(
  992. IN PSOCKET Socket,
  993. IN PSOCKET_CONFIGURATION SocketConfig
  994. )
  995. /*++
  996. Routine Description:
  997. This routine enables the socket memory and I/O windows
  998. Arguments:
  999. Socket - Pointer to the socket containing the PC-Card
  1000. SocketConfig - Pointer to the socket configuration structure which contains the
  1001. resources required to enable this pc-card
  1002. Return value:
  1003. status
  1004. --*/
  1005. {
  1006. CARD_REQUEST cardRequest = {0};
  1007. PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
  1008. NTSTATUS status = STATUS_SUCCESS;
  1009. ULONG i;
  1010. DebugPrint((PCMCIA_DEBUG_CONFIG, "socket %08x config MemIo\n", Socket));
  1011. //
  1012. // Setup IO ranges if there are any
  1013. //
  1014. if (SocketConfig->NumberOfIoPortRanges) {
  1015. cardRequest.RequestType = IO_REQUEST;
  1016. cardRequest.u.Io.NumberOfRanges = (USHORT) SocketConfig->NumberOfIoPortRanges;
  1017. for (i = 0; i < SocketConfig->NumberOfIoPortRanges; i++) {
  1018. DebugPrint((PCMCIA_DEBUG_CONFIG, "\tport range: 0x%x-0x%x\n",
  1019. SocketConfig->Io[i].Base,
  1020. SocketConfig->Io[i].Base + SocketConfig->Io[i].Length));
  1021. cardRequest.u.Io.IoEntry[i].BasePort = SocketConfig->Io[i].Base;
  1022. cardRequest.u.Io.IoEntry[i].NumPorts = SocketConfig->Io[i].Length;
  1023. cardRequest.u.Io.IoEntry[i].Attributes = 0;
  1024. if (SocketConfig->Io[i].Width16) {
  1025. cardRequest.u.Io.IoEntry[i].Attributes |= IO_DATA_PATH_WIDTH;
  1026. }
  1027. if (SocketConfig->Io[i].WaitState16) {
  1028. cardRequest.u.Io.IoEntry[i].Attributes |= IO_WAIT_STATE_16;
  1029. }
  1030. if (SocketConfig->Io[i].Source16) {
  1031. cardRequest.u.Io.IoEntry[i].Attributes |= IO_SOURCE_16;
  1032. }
  1033. if (SocketConfig->Io[i].ZeroWait8) {
  1034. cardRequest.u.Io.IoEntry[i].Attributes |= IO_ZERO_WAIT_8;
  1035. }
  1036. }
  1037. if (!PcmciaProcessConfigureRequest(fdoExtension, Socket, &cardRequest)) {
  1038. status = STATUS_UNSUCCESSFUL;
  1039. DebugPrint((PCMCIA_DEBUG_FAIL, "Failed to configure PcCardIO for socket %x\n", Socket));
  1040. }
  1041. }
  1042. //
  1043. // Set up Memory space if there is some.
  1044. //
  1045. if (NT_SUCCESS(status) && SocketConfig->NumberOfMemoryRanges) {
  1046. cardRequest.RequestType = MEM_REQUEST;
  1047. cardRequest.u.Memory.NumberOfRanges = (USHORT) SocketConfig->NumberOfMemoryRanges;
  1048. for (i = 0; i < SocketConfig->NumberOfMemoryRanges; i++) {
  1049. DebugPrint((PCMCIA_DEBUG_CONFIG, "\tmemory: host %08x for 0x%x, card %08x\n",
  1050. SocketConfig->Memory[i].HostBase,
  1051. SocketConfig->Memory[i].Length,
  1052. SocketConfig->Memory[i].CardBase));
  1053. cardRequest.u.Memory.MemoryEntry[i].BaseAddress = SocketConfig->Memory[i].CardBase;
  1054. cardRequest.u.Memory.MemoryEntry[i].HostAddress = SocketConfig->Memory[i].HostBase;
  1055. cardRequest.u.Memory.MemoryEntry[i].WindowSize = SocketConfig->Memory[i].Length;
  1056. cardRequest.u.Memory.MemoryEntry[i].AttributeMemory = SocketConfig->Memory[i].IsAttribute;
  1057. cardRequest.u.Memory.MemoryEntry[i].WindowDataSize16 = SocketConfig->Memory[i].Width16;
  1058. cardRequest.u.Memory.MemoryEntry[i].WaitStates = SocketConfig->Memory[i].WaitState;
  1059. }
  1060. if (!PcmciaProcessConfigureRequest(fdoExtension, Socket, &cardRequest)) {
  1061. status = STATUS_UNSUCCESSFUL;
  1062. DebugPrint((PCMCIA_DEBUG_FAIL, "Failed to configure PcCardMem for socket %x\n", Socket));
  1063. }
  1064. }
  1065. return status;
  1066. }
  1067. NTSTATUS
  1068. PcmciaConfigurePcCardIrq(
  1069. IN PSOCKET Socket,
  1070. IN PSOCKET_CONFIGURATION SocketConfig
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. This routine enables the socket IRQ
  1075. Arguments:
  1076. Socket - Pointer to the socket containing the PC-Card
  1077. SocketConfig - Pointer to the socket configuration structure which contains the
  1078. resources required to enable this pc-card
  1079. Return value:
  1080. status
  1081. --*/
  1082. {
  1083. CARD_REQUEST cardRequest = {0};
  1084. PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
  1085. NTSTATUS status = STATUS_SUCCESS;
  1086. DebugPrint((PCMCIA_DEBUG_CONFIG, "skt %08x irq=0x%x\n",
  1087. Socket,
  1088. SocketConfig->Irq));
  1089. //
  1090. // Set the IRQ on the controller.
  1091. //
  1092. if (SocketConfig->Irq) {
  1093. cardRequest.RequestType = IRQ_REQUEST;
  1094. cardRequest.u.Irq.AssignedIRQ = (UCHAR) SocketConfig->Irq;
  1095. cardRequest.u.Irq.ReadyIRQ = (UCHAR) SocketConfig->ReadyIrq;
  1096. if (!PcmciaProcessConfigureRequest(fdoExtension, Socket, &cardRequest)) {
  1097. status = STATUS_UNSUCCESSFUL;
  1098. DebugPrint((PCMCIA_DEBUG_FAIL, "Failed to configure PcCardIrq for socket %x\n", Socket));
  1099. }
  1100. }
  1101. return status;
  1102. }
  1103. NTSTATUS
  1104. PcmciaConfigurePcCardRegisters(
  1105. PPDO_EXTENSION pdoExtension
  1106. )
  1107. /*++
  1108. Routine Description:
  1109. This routine does the work of configuring the function configuration registers
  1110. on the card.
  1111. Arguments:
  1112. pdoExtension - Pointer to the physical device object extension for the pc-card
  1113. Return value:
  1114. status
  1115. --*/
  1116. {
  1117. PSOCKET Socket = pdoExtension->Socket;
  1118. PSOCKET_CONFIGURATION SocketConfig = pdoExtension->SocketConfiguration;
  1119. PSOCKET_DATA socketData ;
  1120. CARD_REQUEST cardRequest = {0};
  1121. PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
  1122. NTSTATUS status = STATUS_UNSUCCESSFUL;
  1123. ULONG ccrBase;
  1124. PFUNCTION_CONFIGURATION fnConfig;
  1125. UCHAR configIndex;
  1126. //
  1127. // Set up the configuration index on the PCCARD.
  1128. //
  1129. cardRequest.RequestType = CONFIGURE_REQUEST;
  1130. fnConfig = SocketConfig->FunctionConfiguration;
  1131. socketData = pdoExtension->SocketData;
  1132. ASSERT(socketData != NULL);
  1133. do {
  1134. cardRequest.u.Config.RegisterWriteMask = 0;
  1135. if (fnConfig) {
  1136. //
  1137. // MF card -
  1138. // pick up the base and options from the linked list
  1139. //
  1140. ccrBase = fnConfig->ConfigRegisterBase;
  1141. configIndex = fnConfig->ConfigOptions;
  1142. } else {
  1143. //
  1144. // Single function card -
  1145. // get the base and index from base config structure
  1146. //
  1147. ccrBase = SocketConfig->ConfigRegisterBase;
  1148. configIndex = SocketConfig->IndexForCurrentConfiguration;
  1149. }
  1150. DebugPrint((PCMCIA_DEBUG_CONFIG, "pdo %08x config registers ccr %x\n", pdoExtension->DeviceObject, ccrBase));
  1151. //
  1152. // We support only 2 interfaces:
  1153. // Memory only
  1154. // I/o and memory
  1155. // We consider a card to be memory only if:
  1156. // The card is of device type PCCARD_TYPE_MEMORY: this is true
  1157. // for flash memory cards currently
  1158. // OR
  1159. // The card doesn't have any i/o ranges & the config register base is 0.
  1160. //
  1161. if (((ccrBase == 0) && (SocketConfig->NumberOfIoPortRanges == 0)) ||
  1162. (socketData->DeviceType == PCCARD_TYPE_MEMORY) ||
  1163. (socketData->DeviceType == PCCARD_TYPE_FLASH_MEMORY)) {
  1164. cardRequest.u.Config.InterfaceType = CONFIG_INTERFACE_MEM;
  1165. } else {
  1166. //
  1167. // i/o mem card
  1168. //
  1169. cardRequest.u.Config.ConfigBase = ccrBase;
  1170. cardRequest.u.Config.InterfaceType = CONFIG_INTERFACE_IO_MEM;
  1171. cardRequest.u.Config.RegisterWriteMask |= REGISTER_WRITE_CONFIGURATION_INDEX;
  1172. cardRequest.u.Config.ConfigIndex = configIndex;
  1173. if (IsConfigRegisterPresent(socketData, 1)) {
  1174. cardRequest.u.Config.RegisterWriteMask |= REGISTER_WRITE_CARD_CONFIGURATION;
  1175. cardRequest.u.Config.CardConfiguration = 0;
  1176. }
  1177. if (fnConfig) {
  1178. //
  1179. // MF card - set up the rest of the configuration registers
  1180. //
  1181. // Just check audio for now
  1182. if (fnConfig->ConfigFlags & 0x8) {
  1183. // probably a modem
  1184. cardRequest.u.Config.CardConfiguration = 0x08;
  1185. }
  1186. if (fnConfig->ConfigOptions & 0x02) {
  1187. cardRequest.u.Config.IoBaseRegister = fnConfig->IoBase;
  1188. cardRequest.u.Config.IoLimitRegister = fnConfig->IoLimit;
  1189. cardRequest.u.Config.RegisterWriteMask |= (REGISTER_WRITE_IO_BASE | REGISTER_WRITE_IO_LIMIT);
  1190. }
  1191. } else if (IsDeviceFlagSet(pdoExtension, PCMCIA_PDO_ENABLE_AUDIO)) {
  1192. //
  1193. // Request that the audio pin in the card configuration register
  1194. // be set.
  1195. //
  1196. cardRequest.u.Config.CardConfiguration = 0x08;
  1197. }
  1198. }
  1199. if (!PcmciaProcessConfigureRequest(fdoExtension, Socket, &cardRequest)) {
  1200. DebugPrint((PCMCIA_DEBUG_FAIL, "Failed to configure PcCardRegisters for PDO %x\n", pdoExtension->DeviceObject));
  1201. return status;
  1202. }
  1203. if (fnConfig) {
  1204. fnConfig = fnConfig->Next;
  1205. } else {
  1206. //
  1207. // Remember that the socket is configured and what index was used.
  1208. //
  1209. socketData->ConfigIndexUsed = configIndex;
  1210. }
  1211. } while(fnConfig);
  1212. status = STATUS_SUCCESS;
  1213. return status;
  1214. }
  1215. VOID
  1216. PcmciaConfigureModemHack(
  1217. IN PSOCKET Socket,
  1218. IN PSOCKET_CONFIGURATION SocketConfig
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. This routine does magic to wake the modem up. It is written to accomodate
  1223. the Motorola MobileSURFR 56k, but there may be other modems that need it.
  1224. Arguments:
  1225. Socket - Pointer to the socket containing the PC-Card
  1226. SocketConfig - Pointer to the socket configuration structure which contains the
  1227. resources required to enable this pc-card
  1228. Return value:
  1229. status
  1230. --*/
  1231. {
  1232. static const ULONG ValidPortBases[4] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
  1233. ULONG i;
  1234. UCHAR ch;
  1235. ULONG base;
  1236. for (i = 0; i < 4; i++) {
  1237. base = SocketConfig->Io[0].Base;
  1238. if (base == ValidPortBases[i]) {
  1239. DebugPrint((PCMCIA_DEBUG_CONFIG, "skt %08x ModemHack base %x\n", Socket, base));
  1240. // read and write the modem control register
  1241. ch = READ_PORT_UCHAR((PUCHAR)ULongToPtr(base + 4));
  1242. WRITE_PORT_UCHAR((PUCHAR)ULongToPtr(base + 4), ch);
  1243. break;
  1244. }
  1245. }
  1246. }
  1247. VOID
  1248. PcmciaSocketDeconfigure(
  1249. IN PSOCKET Socket
  1250. )
  1251. /*++
  1252. Routine Description:
  1253. deconfigures the card
  1254. Arguments:
  1255. Socket - Pointer to the socket containing the PC-Card
  1256. Return Value
  1257. none
  1258. --*/
  1259. {
  1260. CARD_REQUEST cardReq;
  1261. if (IsSocketFlagSet(Socket, SOCKET_CARD_CONFIGURED)) {
  1262. cardReq.RequestType = DECONFIGURE_REQUEST;
  1263. PcmciaProcessConfigureRequest(Socket->DeviceExtension, Socket, &cardReq);
  1264. ResetSocketFlag(Socket, SOCKET_CARD_CONFIGURED);
  1265. }
  1266. //
  1267. // If a query_device_relations came in after a card was inserted, but before
  1268. // we have removed the previous card configuration, the enumeration would have been
  1269. // postponed. Here, we start it up again
  1270. //
  1271. if (IsSocketFlagSet(Socket, SOCKET_ENUMERATE_PENDING)) {
  1272. ResetSocketFlag(Socket, SOCKET_ENUMERATE_PENDING);
  1273. SetSocketFlag(Socket, SOCKET_CARD_STATUS_CHANGE);
  1274. IoInvalidateDeviceRelations(Socket->DeviceExtension->Pdo, BusRelations);
  1275. }
  1276. }
  1277. BOOLEAN
  1278. PcmciaProcessConfigureRequest(
  1279. IN PFDO_EXTENSION DeviceExtension,
  1280. IN PSOCKET Socket,
  1281. IN PCARD_REQUEST CardConfigurationRequest
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. Actually configures the card
  1286. Arguments:
  1287. Context
  1288. Return Value
  1289. True
  1290. --*/
  1291. {
  1292. BOOLEAN status;
  1293. ULONG counter;
  1294. PCMCIA_ACQUIRE_DEVICE_LOCK(DeviceExtension);
  1295. //
  1296. // Configuring the card can be tricky: the user may pop out the card while
  1297. // configuration is taking place.
  1298. //
  1299. counter = 0;
  1300. do {
  1301. status = (*(Socket->SocketFnPtr->PCBProcessConfigureRequest))(Socket,
  1302. CardConfigurationRequest,
  1303. Socket->AddressPort);
  1304. if (!status) {
  1305. if (!(Socket->SocketFnPtr->PCBDetectCardInSocket(Socket))) {
  1306. //
  1307. // Somebody popped out the card
  1308. //
  1309. break;
  1310. }
  1311. }
  1312. counter++;
  1313. } while (!status && counter < PCMCIA_MAX_CONFIG_TRIES);
  1314. PCMCIA_RELEASE_DEVICE_LOCK(DeviceExtension);
  1315. return status;
  1316. }
  1317. BOOLEAN
  1318. PcmciaVerifyCardInSocket(
  1319. IN PSOCKET Socket
  1320. )
  1321. /*++
  1322. Routine Description:
  1323. This routine compares the current known state to the id of the
  1324. card in the slot to determine if the state is consistent. That is,
  1325. if there is no card in the socket, then we would expect to see no
  1326. cards enumerated in the socket data. If there is a card in the socket,
  1327. then we would expect to see the socket data match the card.
  1328. Arguments
  1329. Socket - Point to the socket to verify
  1330. Return Value
  1331. TRUE if the logical state of the socket matches its physical state
  1332. FALSE otherwise
  1333. --*/
  1334. {
  1335. NTSTATUS status;
  1336. PDEVICE_OBJECT pdo, nextPdo;
  1337. PPDO_EXTENSION pdoExtension;
  1338. BOOLEAN verified = FALSE;
  1339. try {
  1340. if (!IsCardInSocket(Socket)) {
  1341. leave;
  1342. }
  1343. if (IsCardBusCardInSocket(Socket)) {
  1344. ULONG pciConfig;
  1345. ULONG i;
  1346. //
  1347. // Cardbus card now in slot, check to see if it matches the
  1348. // PdoList state.
  1349. //
  1350. if (!Socket->PdoList) {
  1351. leave;
  1352. }
  1353. for (pdo = Socket->PdoList; pdo!=NULL; pdo=nextPdo) {
  1354. pdoExtension = pdo->DeviceExtension;
  1355. nextPdo = pdoExtension->NextPdoInSocket;
  1356. if (!IsCardBusCard(pdoExtension)) {
  1357. leave;
  1358. }
  1359. for (i = 0; i < 1000; i++) {
  1360. GetPciConfigSpace(pdoExtension, CFGSPACE_VENDOR_ID, &pciConfig, sizeof(pciConfig));
  1361. if (pdoExtension->CardBusId == pciConfig) {
  1362. break;
  1363. }
  1364. PcmciaWait(10);
  1365. }
  1366. if (i > 0) {
  1367. DebugPrint((PCMCIA_DEBUG_FAIL, "pdo %08x waited %d usec to verify device id %08x\n",
  1368. pdoExtension->DeviceObject, i*10, pdoExtension->CardBusId));
  1369. }
  1370. if (pdoExtension->CardBusId != pciConfig) {
  1371. DebugPrint((PCMCIA_DEBUG_FAIL, "pdo %08x verify device id FAILED: %08x %08x\n",
  1372. pdoExtension->DeviceObject, pdoExtension->CardBusId, pciConfig));
  1373. leave;
  1374. }
  1375. }
  1376. verified = TRUE;
  1377. } else {
  1378. //
  1379. // R2 card now in slot
  1380. //
  1381. pdo = Socket->PdoList;
  1382. if (pdo) {
  1383. pdoExtension = pdo->DeviceExtension;
  1384. if (Is16BitCard(pdoExtension)) {
  1385. //
  1386. // Invalidate the cache to force re-reading the CIS
  1387. //
  1388. pdoExtension->CisCacheSpace = 0xff;
  1389. if ((NT_SUCCESS(PcmciaParseFunctionDataForID(pdoExtension->SocketData)))) {
  1390. verified = TRUE;
  1391. }
  1392. }
  1393. }
  1394. }
  1395. } finally {
  1396. if (!verified) {
  1397. SetSocketFlag(Socket, SOCKET_CARD_STATUS_CHANGE);
  1398. }
  1399. DebugPrint((PCMCIA_DEBUG_INFO, "skt %08x - card %s\n", Socket, verified ? "not changed" : "changed!"));
  1400. }
  1401. return verified;
  1402. }