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.

1411 lines
39 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. workproc.c
  5. Abstract:
  6. This module contains the various "miniproc" handlers which are called
  7. by the worker engine. These routines handles the bulk of the real
  8. work for interfacing with an SD card.
  9. Authors:
  10. Neil Sandlin (neilsa) 1-Jan-2002
  11. Environment:
  12. Kernel mode only
  13. Notes:
  14. Revision History:
  15. --*/
  16. #include "pch.h"
  17. //
  18. // Internal References
  19. //
  20. VOID
  21. SdbusSynchronousWorkCompletion(
  22. IN PSD_WORK_PACKET WorkPacket,
  23. IN NTSTATUS status
  24. );
  25. //
  26. // MiniProc routines
  27. //
  28. NTSTATUS
  29. SdbusSetPowerWorker(
  30. IN PSD_WORK_PACKET WorkPacket
  31. );
  32. NTSTATUS
  33. SdbusIdentifyIoDeviceWorker(
  34. IN PSD_WORK_PACKET WorkPacket
  35. );
  36. NTSTATUS
  37. SdbusIdentifyMemoryFunctionWorker(
  38. IN PSD_WORK_PACKET WorkPacket
  39. );
  40. NTSTATUS
  41. SdbusInitializeCardWorker(
  42. IN PSD_WORK_PACKET WorkPacket
  43. );
  44. NTSTATUS
  45. SdbusInitializeFunctionWorker(
  46. IN PSD_WORK_PACKET WorkPacket
  47. );
  48. NTSTATUS
  49. SdbusMemoryBlockWorker(
  50. IN PSD_WORK_PACKET WorkPacket
  51. );
  52. NTSTATUS
  53. SdbusIoDirectWorker(
  54. IN PSD_WORK_PACKET WorkPacket
  55. );
  56. NTSTATUS
  57. SdbusIoExtendedWorker(
  58. IN PSD_WORK_PACKET WorkPacket
  59. );
  60. NTSTATUS
  61. SdbusBuildWorkPacket(
  62. PFDO_EXTENSION FdoExtension,
  63. WORKPROC_FUNCTION Function,
  64. PSDBUS_WORKPACKET_COMPLETION_ROUTINE CompletionRoutine,
  65. PVOID CompletionContext,
  66. PSD_WORK_PACKET *ReturnedWorkPacket
  67. )
  68. /*++
  69. Routine Description
  70. Arguments
  71. Return Value
  72. --*/
  73. {
  74. PSD_WORK_PACKET workPacket;
  75. PSDBUS_WORKER_MINIPROC WorkerMiniProc;
  76. BOOLEAN disableCardEvents = FALSE;
  77. switch(Function) {
  78. case SDWP_READBLOCK:
  79. case SDWP_WRITEBLOCK:
  80. WorkerMiniProc = SdbusMemoryBlockWorker;
  81. break;
  82. case SDWP_READIO:
  83. case SDWP_WRITEIO:
  84. WorkerMiniProc = SdbusIoDirectWorker;
  85. break;
  86. case SDWP_READIO_EXTENDED:
  87. case SDWP_WRITEIO_EXTENDED:
  88. WorkerMiniProc = SdbusIoExtendedWorker;
  89. break;
  90. case SDWP_POWER_ON:
  91. case SDWP_POWER_OFF:
  92. WorkerMiniProc = SdbusSetPowerWorker;
  93. disableCardEvents = TRUE;
  94. break;
  95. case SDWP_IDENTIFY_IO_DEVICE:
  96. WorkerMiniProc = SdbusIdentifyIoDeviceWorker;
  97. break;
  98. case SDWP_IDENTIFY_MEMORY_DEVICE:
  99. WorkerMiniProc = SdbusIdentifyMemoryFunctionWorker;
  100. break;
  101. case SDWP_INITIALIZE_CARD:
  102. WorkerMiniProc = SdbusInitializeCardWorker;
  103. break;
  104. case SDWP_INITIALIZE_FUNCTION:
  105. WorkerMiniProc = SdbusInitializeFunctionWorker;
  106. break;
  107. case SDWP_PASSTHRU:
  108. WorkerMiniProc = NULL;
  109. break;
  110. default:
  111. ASSERT(FALSE);
  112. }
  113. workPacket = ExAllocatePool(NonPagedPool, sizeof(SD_WORK_PACKET));
  114. if (workPacket == NULL) {
  115. return STATUS_INSUFFICIENT_RESOURCES;
  116. }
  117. RtlZeroMemory(workPacket, sizeof(SD_WORK_PACKET));
  118. workPacket->Function = Function;
  119. workPacket->WorkerMiniProc = WorkerMiniProc;
  120. workPacket->FdoExtension = FdoExtension;
  121. workPacket->CompletionRoutine = CompletionRoutine;
  122. workPacket->CompletionContext = CompletionContext;
  123. workPacket->DisableCardEvents = disableCardEvents;
  124. *ReturnedWorkPacket = workPacket;
  125. return STATUS_SUCCESS;
  126. }
  127. NTSTATUS
  128. SdbusSendCmdSynchronous(
  129. IN PFDO_EXTENSION FdoExtension,
  130. UCHAR Cmd,
  131. UCHAR ResponseType,
  132. ULONG Argument,
  133. ULONG Flags,
  134. PULONG ResponseBuffer,
  135. ULONG ResponseLength
  136. )
  137. /*++
  138. Routine Description:
  139. This routine is called from the enumeration routine to execute IO operations
  140. in the same manner as the normal IO worker, only that we are running here
  141. at passive level.
  142. Arguments:
  143. FdoExtension - device extension for the SD host controller
  144. Return Value:
  145. None
  146. --*/
  147. {
  148. PSD_WORK_PACKET workPacket;
  149. NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
  150. KEVENT event;
  151. DebugPrint((SDBUS_DEBUG_DEVICE, "SEND: Begin Cmd%d (0x%02x) %08x\n", Cmd, Cmd, Argument));
  152. status = SdbusBuildWorkPacket(FdoExtension,
  153. SDWP_PASSTHRU,
  154. SdbusSynchronousWorkCompletion,
  155. &event,
  156. &workPacket);
  157. if (!NT_SUCCESS(status)) {
  158. return status;
  159. }
  160. workPacket->ExecutingSDCommand = TRUE;
  161. workPacket->Cmd = Cmd;
  162. workPacket->ResponseType = ResponseType;
  163. workPacket->Argument = Argument;
  164. workPacket->Flags = Flags;
  165. KeInitializeEvent(&event, NotificationEvent, FALSE);
  166. SdbusQueueWorkPacket(FdoExtension, workPacket, WP_TYPE_IO);
  167. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  168. status = (NTSTATUS) workPacket->CompletionContext;
  169. DebugPrint((SDBUS_DEBUG_DEVICE, "SEND: End Cmd%d (0x%02x) status %08x\n", Cmd, Cmd, status));
  170. if (NT_SUCCESS(status)) {
  171. ULONG copyLength = MIN(ResponseLength, SDBUS_RESPONSE_BUFFER_LENGTH);
  172. RtlCopyMemory(ResponseBuffer, &workPacket->ResponseBuffer, copyLength);
  173. #if DBG
  174. DebugDumpSdResponse(workPacket->ResponseBuffer, workPacket->ResponseType);
  175. #endif
  176. }
  177. ExFreePool(workPacket);
  178. return(status);
  179. }
  180. NTSTATUS
  181. SdbusExecuteWorkSynchronous(
  182. WORKPROC_FUNCTION Function,
  183. IN PFDO_EXTENSION FdoExtension,
  184. IN PPDO_EXTENSION PdoExtension
  185. )
  186. /*++
  187. Routine Description:
  188. This routine is called from the enumeration routine to execute IO operations
  189. in the same manner as the normal IO worker, only that we are running here
  190. at passive level.
  191. Arguments:
  192. FdoExtension - device extension for the SD host controller
  193. Return Value:
  194. None
  195. --*/
  196. {
  197. PSD_WORK_PACKET workPacket;
  198. NTSTATUS status;
  199. KEVENT event;
  200. DebugPrint((SDBUS_DEBUG_WORKPROC, "ExecuteWorkSynchronous: %s\n", WP_FUNC_STRING(Function)));
  201. status = SdbusBuildWorkPacket(FdoExtension,
  202. Function,
  203. SdbusSynchronousWorkCompletion,
  204. &event,
  205. &workPacket);
  206. if (!NT_SUCCESS(status)) {
  207. return status;
  208. }
  209. workPacket->PdoExtension = PdoExtension;
  210. KeInitializeEvent(&event, NotificationEvent, FALSE);
  211. SdbusQueueWorkPacket(FdoExtension, workPacket, WP_TYPE_SYSTEM);
  212. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  213. status = (NTSTATUS) workPacket->CompletionContext;
  214. ExFreePool(workPacket);
  215. return(status);
  216. }
  217. VOID
  218. SdbusSynchronousWorkCompletion(
  219. IN PSD_WORK_PACKET WorkPacket,
  220. IN NTSTATUS status
  221. )
  222. /*++
  223. Routine Description:
  224. Generic completion routine used by the driver
  225. Arguments:
  226. DeviceObject
  227. Irp
  228. pdoIoCompletedEvent - this event will be signalled before return of this routine
  229. Return value:
  230. Status
  231. --*/
  232. {
  233. PKEVENT pEvent = WorkPacket->CompletionContext;
  234. WorkPacket->CompletionContext = (PVOID) status;
  235. KeSetEvent(pEvent, IO_NO_INCREMENT, FALSE);
  236. }
  237. //------------------------------------------------------------------
  238. //
  239. // Worker miniproc routines
  240. //
  241. //------------------------------------------------------------------
  242. NTSTATUS
  243. SdbusSetPowerWorker(
  244. IN PSD_WORK_PACKET WorkPacket
  245. )
  246. /*++
  247. Routine Description:
  248. Arguments:
  249. Return value:
  250. --*/
  251. {
  252. PFDO_EXTENSION fdoExtension = WorkPacket->FdoExtension;
  253. NTSTATUS status;
  254. switch(WorkPacket->FunctionPhase) {
  255. case 0:
  256. if (WorkPacket->Function == SDWP_POWER_OFF) {
  257. (*(fdoExtension->FunctionBlock->SetPower))(fdoExtension, FALSE, NULL);
  258. status = STATUS_SUCCESS;
  259. break;
  260. }
  261. status = (*(fdoExtension->FunctionBlock->SetPower))(fdoExtension, TRUE, &WorkPacket->DelayTime);
  262. if (!NT_SUCCESS(status)) {
  263. break;
  264. }
  265. //
  266. // Used for phase during host reset
  267. //
  268. WorkPacket->TempCtl = 0;
  269. WorkPacket->FunctionPhase++;
  270. status = STATUS_MORE_PROCESSING_REQUIRED;
  271. break;
  272. case 1:
  273. status = (*(fdoExtension->FunctionBlock->ResetHost))(fdoExtension,
  274. (UCHAR)WorkPacket->TempCtl,
  275. &WorkPacket->DelayTime);
  276. // Reset host will continue returning STATUS_MORE_PROCESSING_REQUIRED until
  277. // the end of the reset phase. At that point we are done here, so we will
  278. // just exit
  279. WorkPacket->TempCtl++;
  280. break;
  281. }
  282. return status;
  283. }
  284. NTSTATUS
  285. SdbusIdentifyIoDeviceWorker(
  286. IN PSD_WORK_PACKET WorkPacket
  287. )
  288. /*++
  289. Routine Description:
  290. Arguments:
  291. Return value:
  292. --*/
  293. {
  294. PFDO_EXTENSION fdoExtension = WorkPacket->FdoExtension;
  295. NTSTATUS status;
  296. ULONG ioOcr;
  297. ULONG cmdResponse;
  298. switch(WorkPacket->FunctionPhase) {
  299. case 0:
  300. fdoExtension->numFunctions = 0;
  301. fdoExtension->memFunction = FALSE;
  302. // need to return STATUS_SUCCESS on error
  303. WorkPacket->FunctionPhaseOnError = 255;
  304. //
  305. // send CMD5 to look for an SDIO card
  306. //
  307. //ISSUE: have the worker handle this housekeeping
  308. (*(fdoExtension->FunctionBlock->SetFunctionType))(fdoExtension, SDBUS_FUNCTION_TYPE_IO);
  309. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_SEND_OP_COND, SDCMD_RESP_4, 0, 0);
  310. WorkPacket->FunctionPhase++;
  311. status = STATUS_MORE_PROCESSING_REQUIRED;
  312. break;
  313. case 1:
  314. cmdResponse = WorkPacket->ResponseBuffer[0];
  315. fdoExtension->numFunctions = (UCHAR)((cmdResponse >> 28) & 0x7);
  316. fdoExtension->memFunction = ((cmdResponse & 0x8000000) != 0);
  317. ioOcr = cmdResponse & 0xFFFFFF;
  318. DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x #func=%d ioOCR=%06X\n", fdoExtension->DeviceObject,
  319. fdoExtension->numFunctions, ioOcr));
  320. if (fdoExtension->numFunctions == 0) {
  321. status = STATUS_SUCCESS;
  322. break;
  323. }
  324. //
  325. // SDIO card exists
  326. //
  327. //
  328. // ISSUE: NEED TO IMPLEMENT: test OCR for validity, and set new voltage
  329. //
  330. WorkPacket->TempCtl = ioOcr; // shouldn't this be host dependent?
  331. WorkPacket->ResetCount = 0;
  332. WorkPacket->FunctionPhase++;
  333. status = STATUS_MORE_PROCESSING_REQUIRED;
  334. break;
  335. #define CASE_IO_IDENTIFY_LOOP 2
  336. case CASE_IO_IDENTIFY_LOOP:
  337. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_SEND_OP_COND, SDCMD_RESP_4, WorkPacket->TempCtl, 0);
  338. WorkPacket->FunctionPhase++;
  339. status = STATUS_MORE_PROCESSING_REQUIRED;
  340. break;
  341. case 3:
  342. cmdResponse = WorkPacket->ResponseBuffer[0];
  343. if ((cmdResponse >> 31) == 1) {
  344. status = STATUS_SUCCESS;
  345. break;
  346. }
  347. if (++WorkPacket->ResetCount > 20) {
  348. DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x enumerate IO card fails\n", fdoExtension->DeviceObject));
  349. fdoExtension->numFunctions = 0;
  350. fdoExtension->memFunction = FALSE;
  351. status = STATUS_SUCCESS;
  352. break;
  353. }
  354. WorkPacket->DelayTime = 100000;
  355. WorkPacket->FunctionPhase = CASE_IO_IDENTIFY_LOOP;
  356. status = STATUS_MORE_PROCESSING_REQUIRED;
  357. break;
  358. case 255:
  359. //
  360. // Called on error, probably a CMD timeout. This means that an IO card
  361. // isn't there.
  362. //
  363. fdoExtension->numFunctions = 0;
  364. fdoExtension->memFunction = FALSE;
  365. status = STATUS_SUCCESS;
  366. break;
  367. default:
  368. ASSERT(FALSE);
  369. }
  370. return status;
  371. }
  372. NTSTATUS
  373. SdbusIdentifyMemoryFunctionWorker(
  374. IN PSD_WORK_PACKET WorkPacket
  375. )
  376. /*++
  377. Routine Description:
  378. Arguments:
  379. Return value:
  380. --*/
  381. {
  382. PFDO_EXTENSION fdoExtension = WorkPacket->FdoExtension;
  383. NTSTATUS status;
  384. ULONG argument;
  385. SD_OCR sdOCR;
  386. switch(WorkPacket->FunctionPhase) {
  387. case 0:
  388. if (fdoExtension->numFunctions && !fdoExtension->memFunction) {
  389. //
  390. // This means that the IoDevice worker found an IO device without
  391. // a memory function. So we just exit
  392. //
  393. status = STATUS_SUCCESS;
  394. break;
  395. }
  396. // need to return STATUS_SUCCESS on error
  397. WorkPacket->FunctionPhaseOnError = 255;
  398. (*(fdoExtension->FunctionBlock->SetFunctionType))(fdoExtension, SDBUS_FUNCTION_TYPE_MEMORY);
  399. SET_CMD_PARAMETERS(WorkPacket, SDCMD_GO_IDLE_STATE, SDCMD_RESP_NONE, 0, 0);
  400. WorkPacket->FunctionPhase++;
  401. status = STATUS_MORE_PROCESSING_REQUIRED;
  402. break;
  403. case 1:
  404. WorkPacket->TempCtl = 0;
  405. WorkPacket->ResetCount = 0;
  406. WorkPacket->FunctionPhase++;
  407. status = STATUS_MORE_PROCESSING_REQUIRED;
  408. break;
  409. #define CASE_MEM_IDENTIFY_LOOP 2
  410. case CASE_MEM_IDENTIFY_LOOP:
  411. SET_CMD_PARAMETERS(WorkPacket, SDCMD_APP_CMD, SDCMD_RESP_1, 0, 0);
  412. WorkPacket->FunctionPhase++;
  413. status = STATUS_MORE_PROCESSING_REQUIRED;
  414. break;
  415. case 3:
  416. SET_CMD_PARAMETERS(WorkPacket, SDCMD_SD_APP_OP_COND, SDCMD_RESP_3, WorkPacket->TempCtl, SDCMDF_ACMD);
  417. WorkPacket->FunctionPhase++;
  418. status = STATUS_MORE_PROCESSING_REQUIRED;
  419. break;
  420. case 4:
  421. sdOCR.u.AsULONG = WorkPacket->ResponseBuffer[0];
  422. WorkPacket->TempCtl = WorkPacket->ResponseBuffer[0];
  423. if (sdOCR.u.bits.PowerUpBusy) {
  424. // Memory Function found
  425. DebugPrint((SDBUS_DEBUG_INFO, "fdo %08x OCR voltage range == %08x\n",
  426. fdoExtension->DeviceObject, (ULONG)sdOCR.u.bits.VddVoltage));
  427. WorkPacket->FunctionPhase++;
  428. status = STATUS_MORE_PROCESSING_REQUIRED;
  429. break;
  430. }
  431. if (++WorkPacket->ResetCount > 20) {
  432. DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x enumerate MEM card fails\n", fdoExtension->DeviceObject));
  433. status = STATUS_UNSUCCESSFUL;
  434. break;
  435. }
  436. WorkPacket->DelayTime = 10000;
  437. WorkPacket->FunctionPhase = CASE_MEM_IDENTIFY_LOOP;
  438. status = STATUS_MORE_PROCESSING_REQUIRED;
  439. break;
  440. case 5:
  441. fdoExtension->memFunction = TRUE;
  442. //
  443. //
  444. // The memory function has moved from the Idle state, and should now be in the Ready state.
  445. // Issue a CMD2 to move the card to the Identification state.
  446. //
  447. SET_CMD_PARAMETERS(WorkPacket, SDCMD_ALL_SEND_CID, SDCMD_RESP_2, 0, 0);
  448. WorkPacket->FunctionPhase++;
  449. status = STATUS_MORE_PROCESSING_REQUIRED;
  450. break;
  451. case 6:
  452. status = STATUS_SUCCESS;
  453. break;
  454. case 255:
  455. //
  456. // Called on error, probably a CMD timeout. This means that an memory function
  457. // isn't there.
  458. //
  459. fdoExtension->memFunction = FALSE;
  460. status = STATUS_SUCCESS;
  461. break;
  462. default:
  463. ASSERT(FALSE);
  464. status = STATUS_UNSUCCESSFUL;
  465. }
  466. return status;
  467. }
  468. NTSTATUS
  469. SdbusInitializeCardWorker(
  470. IN PSD_WORK_PACKET WorkPacket
  471. )
  472. /*++
  473. Routine Description:
  474. Arguments:
  475. Return value:
  476. --*/
  477. {
  478. PPDO_EXTENSION pdoExtension = WorkPacket->PdoExtension;
  479. PFDO_EXTENSION fdoExtension = WorkPacket->FdoExtension;
  480. NTSTATUS status;
  481. SD_RW_DIRECT_ARGUMENT argument;
  482. UCHAR data;
  483. PUCHAR pResponse, pTarget;
  484. UCHAR i;
  485. switch(WorkPacket->FunctionPhase) {
  486. case 0:
  487. if (!fdoExtension->numFunctions && !fdoExtension->memFunction) {
  488. DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x initialize card worker fails\n", fdoExtension->DeviceObject));
  489. SdbusDumpDbgLog();
  490. status = STATUS_UNSUCCESSFUL;
  491. break;;
  492. }
  493. SET_CMD_PARAMETERS(WorkPacket, SDCMD_SEND_RELATIVE_ADDR, SDCMD_RESP_6, 0, 0);
  494. WorkPacket->FunctionPhase++;
  495. status = STATUS_MORE_PROCESSING_REQUIRED;
  496. break;
  497. case 1:
  498. fdoExtension->RelativeAddr = WorkPacket->ResponseBuffer[0] & 0xFFFF0000;
  499. DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x relative addr %08x\n", fdoExtension->DeviceObject, fdoExtension->RelativeAddr));
  500. if (!fdoExtension->memFunction) {
  501. //
  502. // Skip to I/O
  503. //
  504. WorkPacket->FunctionPhase = 10;
  505. status = STATUS_MORE_PROCESSING_REQUIRED;
  506. break;
  507. }
  508. (*(fdoExtension->FunctionBlock->SetFunctionType))(fdoExtension, SDBUS_FUNCTION_TYPE_MEMORY);
  509. //
  510. // The CSD contains the equivalent of tuples in a single 128-bit register
  511. //
  512. SET_CMD_PARAMETERS(WorkPacket, SDCMD_SEND_CSD, SDCMD_RESP_2, fdoExtension->RelativeAddr, 0);
  513. WorkPacket->FunctionPhase++;
  514. status = STATUS_MORE_PROCESSING_REQUIRED;
  515. break;
  516. case 2:
  517. //
  518. // Need to reverse the order of the bytes
  519. //
  520. for (i=0, pResponse=(PUCHAR)WorkPacket->ResponseBuffer, pTarget=(PUCHAR)&fdoExtension->SdCsd; i<15; i++) {
  521. pTarget[i] = pResponse[i];
  522. }
  523. //
  524. // Get CID
  525. // A CID is a unique 128=bit id for each individual memory card.
  526. //
  527. SET_CMD_PARAMETERS(WorkPacket, SDCMD_SEND_CID, SDCMD_RESP_2, fdoExtension->RelativeAddr, 0);
  528. WorkPacket->FunctionPhase++;
  529. status = STATUS_MORE_PROCESSING_REQUIRED;
  530. break;
  531. case 3:
  532. //
  533. // Need to reverse the order of the bytes
  534. //
  535. for (i=0, pResponse=(PUCHAR)WorkPacket->ResponseBuffer, pTarget=(PUCHAR)&fdoExtension->SdCid; i<15; i++) {
  536. pTarget[i] = pResponse[i];
  537. }
  538. #if DBG
  539. SdbusDebugDumpCsd(&fdoExtension->SdCsd);
  540. SdbusDebugDumpCid(&fdoExtension->SdCid);
  541. #endif
  542. //
  543. // Skip to I/O
  544. //
  545. WorkPacket->FunctionPhase = 10;
  546. status = STATUS_MORE_PROCESSING_REQUIRED;
  547. break;
  548. case 10:
  549. SET_CMD_PARAMETERS(WorkPacket, SDCMD_SELECT_CARD, SDCMD_RESP_1B, fdoExtension->RelativeAddr, 0);
  550. WorkPacket->FunctionPhase++;
  551. status = STATUS_MORE_PROCESSING_REQUIRED;
  552. break;
  553. case 11:
  554. if (!fdoExtension->numFunctions) {
  555. status = STATUS_SUCCESS;
  556. break;
  557. }
  558. (*(fdoExtension->FunctionBlock->SetFunctionType))(fdoExtension, SDBUS_FUNCTION_TYPE_IO);
  559. argument.u.AsULONG = 0;
  560. argument.u.bits.Address = SD_CCCR_BUS_CONTROL;
  561. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_RW_DIRECT, SDCMD_RESP_5, argument.u.AsULONG, SDCMDF_READ);
  562. WorkPacket->FunctionPhase++;
  563. status = STATUS_MORE_PROCESSING_REQUIRED;
  564. break;
  565. case 12:
  566. data = (UCHAR)WorkPacket->ResponseBuffer[0];
  567. data |= 2; // turn on 4-bit mode
  568. argument.u.AsULONG = 0;
  569. argument.u.bits.Address = SD_CCCR_BUS_CONTROL;
  570. argument.u.bits.Data = data;
  571. argument.u.bits.WriteToDevice = 1;
  572. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_RW_DIRECT, SDCMD_RESP_5, argument.u.AsULONG, SDCMDF_WRITE);
  573. WorkPacket->FunctionPhase++;
  574. status = STATUS_MORE_PROCESSING_REQUIRED;
  575. break;
  576. case 13:
  577. status = STATUS_SUCCESS;
  578. break;
  579. default:
  580. ASSERT(FALSE);
  581. status = STATUS_UNSUCCESSFUL;
  582. }
  583. return status;
  584. }
  585. NTSTATUS
  586. SdbusInitializeFunctionWorker(
  587. IN PSD_WORK_PACKET WorkPacket
  588. )
  589. /*++
  590. Routine Description:
  591. Arguments:
  592. Return value:
  593. --*/
  594. {
  595. PPDO_EXTENSION pdoExtension = WorkPacket->PdoExtension;
  596. PFDO_EXTENSION fdoExtension = WorkPacket->FdoExtension;
  597. NTSTATUS status;
  598. SD_RW_DIRECT_ARGUMENT argument;
  599. UCHAR data;
  600. switch(WorkPacket->FunctionPhase) {
  601. case 0:
  602. if (pdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_MEMORY) {
  603. // memory is already initialized during identify
  604. status = STATUS_SUCCESS;
  605. break;
  606. }
  607. argument.u.AsULONG = 0;
  608. argument.u.bits.Address = SD_CCCR_IO_ENABLE;
  609. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_RW_DIRECT, SDCMD_RESP_5, argument.u.AsULONG, SDCMDF_READ);
  610. WorkPacket->FunctionPhase++;
  611. status = STATUS_MORE_PROCESSING_REQUIRED;
  612. break;
  613. case 1:
  614. //
  615. // Turn on I/O enable
  616. //
  617. data = (UCHAR)WorkPacket->ResponseBuffer[0];
  618. data |= (1 << pdoExtension->Function);
  619. argument.u.AsULONG = 0;
  620. argument.u.bits.Address = SD_CCCR_IO_ENABLE;
  621. argument.u.bits.Data = data;
  622. argument.u.bits.WriteToDevice = 1;
  623. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_RW_DIRECT, SDCMD_RESP_5, argument.u.AsULONG, SDCMDF_WRITE);
  624. WorkPacket->TempCtl = 200; // wait up to 2 seconds (200 * 10msec)
  625. WorkPacket->FunctionPhase++;
  626. status = STATUS_MORE_PROCESSING_REQUIRED;
  627. break;
  628. #define CASE_INIT_FUNC_LOOP 2
  629. case CASE_INIT_FUNC_LOOP:
  630. argument.u.AsULONG = 0;
  631. argument.u.bits.Address = SD_CCCR_IO_READY;
  632. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_RW_DIRECT, SDCMD_RESP_5, argument.u.AsULONG, SDCMDF_READ);
  633. WorkPacket->FunctionPhase++;
  634. status = STATUS_MORE_PROCESSING_REQUIRED;
  635. break;
  636. case 3:
  637. //
  638. // Check to see if I/O ready for this function is on
  639. //
  640. data = (UCHAR)WorkPacket->ResponseBuffer[0];
  641. if (!(data & (1 << pdoExtension->Function))) {
  642. if (--WorkPacket->TempCtl == 0) {
  643. //
  644. // timeout waiting for I/O ready
  645. //
  646. DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x enumerate MEM card fails\n", fdoExtension->DeviceObject));
  647. status = STATUS_UNSUCCESSFUL;
  648. break;
  649. }
  650. //
  651. // Delay and loop back to re-read for I/O ready
  652. //
  653. WorkPacket->DelayTime = 10000; // 10 msec increments
  654. WorkPacket->FunctionPhase = CASE_INIT_FUNC_LOOP;
  655. status = STATUS_MORE_PROCESSING_REQUIRED;
  656. break;
  657. }
  658. //
  659. // I/O ready is on, continue
  660. //
  661. argument.u.AsULONG = 0;
  662. argument.u.bits.Address = SD_CCCR_INT_ENABLE;
  663. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_RW_DIRECT, SDCMD_RESP_5, argument.u.AsULONG, SDCMDF_READ);
  664. WorkPacket->FunctionPhase++;
  665. status = STATUS_MORE_PROCESSING_REQUIRED;
  666. break;
  667. case 4:
  668. //
  669. // Turn on INT ENABLE
  670. //
  671. data = (UCHAR)WorkPacket->ResponseBuffer[0];
  672. data |= (1 << pdoExtension->Function) + 1;
  673. argument.u.AsULONG = 0;
  674. argument.u.bits.Address = SD_CCCR_INT_ENABLE;
  675. argument.u.bits.Data = data;
  676. argument.u.bits.WriteToDevice = 1;
  677. SET_CMD_PARAMETERS(WorkPacket, SDCMD_IO_RW_DIRECT, SDCMD_RESP_5, argument.u.AsULONG, SDCMDF_WRITE);
  678. WorkPacket->FunctionPhase++;
  679. status = STATUS_MORE_PROCESSING_REQUIRED;
  680. break;
  681. case 5:
  682. status = STATUS_SUCCESS;
  683. break;
  684. default:
  685. ASSERT(FALSE);
  686. status = STATUS_UNSUCCESSFUL;
  687. }
  688. return status;
  689. }
  690. NTSTATUS
  691. SdbusMemoryBlockWorker(
  692. IN PSD_WORK_PACKET WorkPacket
  693. )
  694. /*++
  695. Routine Description:
  696. Arguments:
  697. Return value:
  698. --*/
  699. {
  700. PPDO_EXTENSION PdoExtension = WorkPacket->PdoExtension;
  701. PFDO_EXTENSION fdoExtension = PdoExtension->FdoExtension;
  702. ULONG sdRca = fdoExtension->RelativeAddr;
  703. ULONG Length;
  704. NTSTATUS status;
  705. switch(WorkPacket->FunctionPhase) {
  706. case 0:
  707. (*(fdoExtension->FunctionBlock->StartBlockOperation))(fdoExtension);
  708. SET_CMD_PARAMETERS(WorkPacket, SDCMD_SET_BLOCKLEN, SDCMD_RESP_1B, 512, 0);
  709. WorkPacket->FunctionPhase++;
  710. status = STATUS_MORE_PROCESSING_REQUIRED;
  711. break;
  712. case 1:
  713. SET_CMD_PARAMETERS(WorkPacket, SDCMD_APP_CMD, SDCMD_RESP_1, sdRca, 0);
  714. WorkPacket->FunctionPhase++;
  715. status = STATUS_MORE_PROCESSING_REQUIRED;
  716. break;
  717. case 2:
  718. SET_CMD_PARAMETERS(WorkPacket, SDCMD_SET_BUS_WIDTH,SDCMD_RESP_1, 2, SDCMDF_ACMD);
  719. WorkPacket->FunctionPhase++;
  720. status = STATUS_MORE_PROCESSING_REQUIRED;
  721. break;
  722. case 3:
  723. Length = (WorkPacket->Function == SDWP_READBLOCK) ? WorkPacket->Parameters.ReadBlock.Length :
  724. WorkPacket->Parameters.WriteBlock.Length;
  725. WorkPacket->BlockCount = Length / 512;
  726. (*(fdoExtension->FunctionBlock->SetBlockParameters))(fdoExtension, (USHORT) WorkPacket->BlockCount);
  727. #if 0
  728. if (workPacket->Function == SDWP_WRITEBLOCK) {
  729. DebugPrint((SDBUS_DEBUG_WORKER, "%02x %02x %02x %02x %02x %02x %02x %02x-%02x %02x %02x %02x %02x %02x %02x %02x\n",
  730. Buffer[0], Buffer[1], Buffer[2], Buffer[3],
  731. Buffer[4], Buffer[5], Buffer[6], Buffer[7],
  732. Buffer[8], Buffer[9], Buffer[10],Buffer[11],
  733. Buffer[12], Buffer[13], Buffer[14], Buffer[15]));
  734. }
  735. #endif
  736. WorkPacket->FunctionPhase++;
  737. status = STATUS_MORE_PROCESSING_REQUIRED;
  738. break;
  739. case 4:
  740. if (WorkPacket->Function == SDWP_READBLOCK) {
  741. SET_CMD_PARAMETERS(WorkPacket,
  742. SDCMD_READ_MULTIPLE_BLOCK,
  743. SDCMD_RESP_1,
  744. (ULONG) WorkPacket->Parameters.ReadBlock.ByteOffset,
  745. SDCMDF_READ | SDCMDF_DATA | SDCMDF_MULTIBLOCK);
  746. } else if (WorkPacket->Function == SDWP_WRITEBLOCK) {
  747. SET_CMD_PARAMETERS(WorkPacket,
  748. SDCMD_WRITE_MULTIPLE_BLOCK,
  749. SDCMD_RESP_1,
  750. (ULONG) WorkPacket->Parameters.WriteBlock.ByteOffset,
  751. SDCMDF_WRITE | SDCMDF_DATA | SDCMDF_MULTIBLOCK);
  752. } else {
  753. ASSERT(FALSE);
  754. }
  755. WorkPacket->FunctionPhase++;
  756. status = STATUS_MORE_PROCESSING_REQUIRED;
  757. break;
  758. case 5:
  759. WorkPacket->Retries = 5;
  760. WorkPacket->DelayTime = 1000;
  761. WorkPacket->RequiredEvent = (WorkPacket->Function == SDWP_READBLOCK) ? SDBUS_EVENT_BUFFER_FULL :
  762. SDBUS_EVENT_BUFFER_EMPTY;
  763. WorkPacket->FunctionPhase++;
  764. status = STATUS_MORE_PROCESSING_REQUIRED;
  765. break;
  766. #define MBW_START_COPY 6
  767. case MBW_START_COPY:
  768. DebugPrint((SDBUS_DEBUG_WORKPROC, "MemBlockWorker: begin sector copy\n"));
  769. if (WorkPacket->Function == SDWP_READBLOCK) {
  770. (*(fdoExtension->FunctionBlock->ReadDataPort))(fdoExtension,
  771. WorkPacket->Parameters.ReadBlock.Buffer,
  772. 512);
  773. WorkPacket->DelayTime = 1000;
  774. if (--WorkPacket->BlockCount > 0) {
  775. WorkPacket->RequiredEvent = SDBUS_EVENT_BUFFER_FULL;
  776. } else {
  777. WorkPacket->RequiredEvent = SDBUS_EVENT_CARD_RW_END;
  778. }
  779. } else if (WorkPacket->Function == SDWP_WRITEBLOCK) {
  780. (*(fdoExtension->FunctionBlock->WriteDataPort))(fdoExtension,
  781. WorkPacket->Parameters.WriteBlock.Buffer,
  782. 512);
  783. WorkPacket->DelayTime = 50000;
  784. if (--WorkPacket->BlockCount > 0) {
  785. WorkPacket->RequiredEvent = SDBUS_EVENT_BUFFER_EMPTY;
  786. } else {
  787. WorkPacket->RequiredEvent = SDBUS_EVENT_CARD_RW_END;
  788. }
  789. }
  790. DebugPrint((SDBUS_DEBUG_WORKPROC, "MemBlockWorker: end sector copy\n"));
  791. WorkPacket->Retries = 5;
  792. WorkPacket->FunctionPhase++;
  793. status = STATUS_MORE_PROCESSING_REQUIRED;
  794. break;
  795. case 7:
  796. if (WorkPacket->BlockCount > 0) {
  797. if (WorkPacket->Function == SDWP_READBLOCK) {
  798. WorkPacket->Parameters.ReadBlock.Buffer += 512;
  799. } else {
  800. WorkPacket->Parameters.WriteBlock.Buffer += 512;
  801. }
  802. WorkPacket->FunctionPhase = MBW_START_COPY;
  803. status = STATUS_MORE_PROCESSING_REQUIRED;
  804. break;
  805. }
  806. #if 0
  807. if (workPacket->Function == SDWP_READBLOCK) {
  808. DebugPrint((SDBUS_DEBUG_WORKER, "%02x %02x %02x %02x %02x %02x %02x %02x-%02x %02x %02x %02x %02x %02x %02x %02x\n",
  809. Buffer[0], Buffer[1], Buffer[2], Buffer[3],
  810. Buffer[4], Buffer[5], Buffer[6], Buffer[7],
  811. Buffer[8], Buffer[9], Buffer[10],Buffer[11],
  812. Buffer[12], Buffer[13], Buffer[14], Buffer[15]));
  813. }
  814. #endif
  815. (*(fdoExtension->FunctionBlock->EndBlockOperation))(fdoExtension);
  816. Length = (WorkPacket->Function == SDWP_READBLOCK) ? WorkPacket->Parameters.ReadBlock.Length :
  817. WorkPacket->Parameters.WriteBlock.Length;
  818. DebugPrint((SDBUS_DEBUG_WORKPROC, "MemBlockWorker: returns %x\n", Length));
  819. WorkPacket->Information = Length;
  820. status = STATUS_SUCCESS;
  821. break;
  822. default:
  823. ASSERT(FALSE);
  824. status = STATUS_UNSUCCESSFUL;
  825. }
  826. return status;
  827. }
  828. NTSTATUS
  829. SdbusIoDirectWorker(
  830. IN PSD_WORK_PACKET WorkPacket
  831. )
  832. /*++
  833. Routine Description:
  834. Arguments:
  835. Return value:
  836. --*/
  837. {
  838. PPDO_EXTENSION pdoExtension = WorkPacket->PdoExtension;
  839. PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
  840. NTSTATUS status;
  841. SD_RW_DIRECT_ARGUMENT argument;
  842. argument.u.AsULONG = 0;
  843. switch(WorkPacket->FunctionPhase) {
  844. case 0:
  845. if (WorkPacket->Function == SDWP_READIO) {
  846. argument.u.bits.Address = WorkPacket->Parameters.ReadIo.Offset;
  847. argument.u.bits.Function = pdoExtension->Function;
  848. SET_CMD_PARAMETERS(WorkPacket,
  849. SDCMD_IO_RW_DIRECT,
  850. SDCMD_RESP_5,
  851. argument.u.AsULONG,
  852. SDCMDF_READ);
  853. } else if (WorkPacket->Function == SDWP_WRITEIO) {
  854. argument.u.bits.Address = WorkPacket->Parameters.WriteIo.Offset;
  855. argument.u.bits.Data = WorkPacket->Parameters.WriteIo.Data;
  856. argument.u.bits.WriteToDevice = 1;
  857. argument.u.bits.Function = pdoExtension->Function;
  858. SET_CMD_PARAMETERS(WorkPacket,
  859. SDCMD_IO_RW_DIRECT,
  860. SDCMD_RESP_5,
  861. argument.u.AsULONG,
  862. SDCMDF_WRITE);
  863. } else {
  864. ASSERT(FALSE);
  865. }
  866. WorkPacket->FunctionPhase++;
  867. status = STATUS_MORE_PROCESSING_REQUIRED;
  868. break;
  869. case 1:
  870. if (WorkPacket->Function == SDWP_READIO) {
  871. *(PUCHAR) WorkPacket->Parameters.ReadIo.Buffer = (UCHAR)WorkPacket->ResponseBuffer[0];
  872. }
  873. status = STATUS_SUCCESS;
  874. break;
  875. default:
  876. ASSERT(FALSE);
  877. status = STATUS_UNSUCCESSFUL;
  878. }
  879. return status;
  880. }
  881. NTSTATUS
  882. SdbusIoExtendedWorker(
  883. IN PSD_WORK_PACKET WorkPacket
  884. )
  885. /*++
  886. Routine Description:
  887. Arguments:
  888. Return value:
  889. --*/
  890. {
  891. PPDO_EXTENSION pdoExtension = WorkPacket->PdoExtension;
  892. PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
  893. NTSTATUS status;
  894. SD_RW_EXTENDED_ARGUMENT argument;
  895. ULONG totalLength;
  896. argument.u.AsULONG = 0;
  897. switch(WorkPacket->FunctionPhase) {
  898. case 0:
  899. totalLength = (WorkPacket->Function == SDWP_READIO_EXTENDED) ?
  900. WorkPacket->Parameters.ReadIo.Length :
  901. WorkPacket->Parameters.WriteIo.Length;
  902. #define IO_BUFFER_SIZE 64
  903. WorkPacket->BlockCount = totalLength / IO_BUFFER_SIZE;
  904. WorkPacket->LastBlockLength = totalLength % IO_BUFFER_SIZE;
  905. DebugPrint((SDBUS_DEBUG_WORKPROC, "IoExtendedWorker: begin I/O length=%d, blocks=%d, last=%d\n",
  906. totalLength, WorkPacket->BlockCount, WorkPacket->LastBlockLength));
  907. WorkPacket->FunctionPhase++;
  908. status = STATUS_MORE_PROCESSING_REQUIRED;
  909. break;
  910. #define IEW_START_CMD 1
  911. case IEW_START_CMD:
  912. WorkPacket->CurrentBlockLength = WorkPacket->BlockCount ? IO_BUFFER_SIZE :
  913. WorkPacket->LastBlockLength;
  914. (*(fdoExtension->FunctionBlock->SetBlockParameters))(fdoExtension, (USHORT)WorkPacket->CurrentBlockLength);
  915. if (WorkPacket->Function == SDWP_READIO_EXTENDED) {
  916. argument.u.bits.Address = WorkPacket->Parameters.ReadIo.Offset;
  917. argument.u.bits.Count = WorkPacket->CurrentBlockLength;
  918. argument.u.bits.Function = pdoExtension->Function;
  919. SET_CMD_PARAMETERS(WorkPacket,
  920. SDCMD_IO_RW_EXTENDED,
  921. SDCMD_RESP_5,
  922. argument.u.AsULONG,
  923. SDCMDF_READ | SDCMDF_DATA);
  924. } else if (WorkPacket->Function == SDWP_WRITEIO_EXTENDED) {
  925. argument.u.bits.Address = WorkPacket->Parameters.WriteIo.Offset;
  926. argument.u.bits.Count = WorkPacket->CurrentBlockLength;
  927. argument.u.bits.WriteToDevice = 1;
  928. argument.u.bits.Function = pdoExtension->Function;
  929. SET_CMD_PARAMETERS(WorkPacket,
  930. SDCMD_IO_RW_EXTENDED,
  931. SDCMD_RESP_5,
  932. argument.u.AsULONG,
  933. SDCMDF_WRITE | SDCMDF_DATA);
  934. } else {
  935. ASSERT(FALSE);
  936. }
  937. WorkPacket->FunctionPhase++;
  938. status = STATUS_MORE_PROCESSING_REQUIRED;
  939. break;
  940. case 2:
  941. WorkPacket->Retries = 5;
  942. WorkPacket->DelayTime = 1000;
  943. WorkPacket->RequiredEvent = (WorkPacket->Function == SDWP_READIO_EXTENDED) ? SDBUS_EVENT_BUFFER_FULL :
  944. SDBUS_EVENT_BUFFER_EMPTY;
  945. WorkPacket->FunctionPhase++;
  946. status = STATUS_MORE_PROCESSING_REQUIRED;
  947. break;
  948. #define IEW_START_COPY 3
  949. case IEW_START_COPY:
  950. DebugPrint((SDBUS_DEBUG_WORKPROC, "IoExtendedWorker: begin data copy %d bytes\n", WorkPacket->CurrentBlockLength));
  951. if (WorkPacket->BlockCount) {
  952. //
  953. // Still have full blocks to copy
  954. //
  955. WorkPacket->BlockCount--;
  956. // if (WorkPacket->BlockCount || WorkPacket->LastBlockLength) {
  957. // WorkPacket->RequiredEvent = (WorkPacket->Function == SDWP_READIO_EXTENDED) ? SDBUS_EVENT_BUFFER_FULL :
  958. // SDBUS_EVENT_BUFFER_EMPTY;
  959. // } else {
  960. WorkPacket->RequiredEvent = SDBUS_EVENT_CARD_RW_END;
  961. // }
  962. } else {
  963. //
  964. // Copying the last partial block
  965. //
  966. ASSERT(WorkPacket->LastBlockLength);
  967. WorkPacket->LastBlockLength = 0;
  968. WorkPacket->RequiredEvent = SDBUS_EVENT_CARD_RW_END;
  969. }
  970. if (WorkPacket->Function == SDWP_READIO_EXTENDED) {
  971. (*(fdoExtension->FunctionBlock->ReadDataPort))(fdoExtension,
  972. WorkPacket->Parameters.ReadIo.Buffer,
  973. WorkPacket->CurrentBlockLength);
  974. WorkPacket->Parameters.ReadIo.Buffer += WorkPacket->CurrentBlockLength;
  975. WorkPacket->DelayTime = 1000;
  976. } else if (WorkPacket->Function == SDWP_WRITEIO_EXTENDED) {
  977. (*(fdoExtension->FunctionBlock->WriteDataPort))(fdoExtension,
  978. WorkPacket->Parameters.WriteIo.Buffer,
  979. WorkPacket->CurrentBlockLength);
  980. WorkPacket->Parameters.WriteIo.Buffer += WorkPacket->CurrentBlockLength;
  981. WorkPacket->DelayTime = 50000;
  982. }
  983. DebugPrint((SDBUS_DEBUG_WORKPROC, "IoExtendedWorker: end data copy\n"));
  984. WorkPacket->Retries = 5;
  985. WorkPacket->FunctionPhase++;
  986. status = STATUS_MORE_PROCESSING_REQUIRED;
  987. break;
  988. case 4:
  989. if (WorkPacket->BlockCount || WorkPacket->LastBlockLength) {
  990. WorkPacket->FunctionPhase = IEW_START_CMD;
  991. status = STATUS_MORE_PROCESSING_REQUIRED;
  992. break;
  993. }
  994. // (*(fdoExtension->FunctionBlock->EndBlockOperation))(fdoExtension);
  995. totalLength = (WorkPacket->Function == SDWP_READIO_EXTENDED) ? WorkPacket->Parameters.ReadIo.Length :
  996. WorkPacket->Parameters.WriteIo.Length;
  997. DebugPrint((SDBUS_DEBUG_WORKPROC, "IoExtendedWorker: returns %x\n", totalLength));
  998. WorkPacket->Information = totalLength;
  999. status = STATUS_SUCCESS;
  1000. break;
  1001. default:
  1002. ASSERT(FALSE);
  1003. status = STATUS_UNSUCCESSFUL;
  1004. }
  1005. return status;
  1006. }