/////////////////////////////////////////////////////////////////////////////// // SDMemWrite - Write data to card from pSG scatter gather buffers // Input: pMemCard - SD memory card structure // pSG - Scatter Gather buffer structure from FATFS // Output: // Return: Status - windows status code // Notes: Writes to the card are split into groups of size TransferBlockSize // This is controlled by a registry entry for the driver. /////////////////////////////////////////////////////////////////////////////// DWORD SDMemWrite( PSD_MEMCARD_INFO pMemCard, PSG_REQ pSG ) { DWORD NumBlocks; DWORD StartBlock; PUCHAR pBlockBuffer = NULL, pCardDataPtr = NULL; PUCHAR pSGBuffer = NULL; DWORD status = ERROR_SUCCESS; DWORD SGBufNum, SGBufLen, SGBufRemaining; DWORD PartialStartBlock; DWORD CardDataRemaining; DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: +SDMemWrite\r\n"))); PREFAST_DEBUGCHK(pSG); // pSG is a sterile SG_REQ copy of the callers's SG_REQ; we can map the // embedded pointers back into it // validate the embedded sb_bufs for (ULONG ul = 0; ul < pSG->sr_num_sg; ul += 1) { if ( (NULL == pSG->sr_sglist[ul].sb_buf) || (0 == pSG->sr_sglist[ul].sb_buf) ) { status = ERROR_INVALID_PARAMETER; goto statusReturn; } pSG->sr_sglist[ul].sb_buf = (PUCHAR)MapCallerPtr( (LPVOID)pSG->sr_sglist[ul].sb_buf, pSG->sr_sglist[ul].sb_len); if (pSG->sr_sglist[ul].sb_buf == NULL) { status = ERROR_INVALID_PARAMETER; goto statusReturn; } } // validate the I/O request if ((pSG->sr_start > pSG->sr_start + pSG->sr_num_sec) ||(pSG->sr_start + pSG->sr_num_sec) > pMemCard->DiskInfo.di_total_sectors) { status = ERROR_INVALID_PARAMETER; goto statusReturn; } // check card write protect status if (pMemCard->WriteProtected) { DEBUGMSG(SDMEM_ZONE_DISK_IO, (TEXT("SDMemWrite: Card is write protected\r\n"))); status = ERROR_WRITE_PROTECT; goto statusReturn; } // get number of sectors StartBlock = pSG->sr_start; NumBlocks = pSG->sr_num_sec; DEBUGMSG(SDMEM_ZONE_DISK_IO, (TEXT("SDMemWrite: Writing blocks %d-%d\r\n"), StartBlock, StartBlock+NumBlocks-1)); // calculate total buffer space of scatter gather buffers SGBufLen = 0; for (SGBufNum = 0; SGBufNum < pSG->sr_num_sg; SGBufNum++) { SGBufLen += pSG->sr_sglist[SGBufNum].sb_len; } // check total SG buffer space is enough for reqeusted transfer size if(SGBufLen < NumBlocks * SD_BLOCK_SIZE) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDMemWrite: SG Buffer space %d bytes less than block write size %d bytes\r\n"), SGBufLen, NumBlocks * SD_BLOCK_SIZE)); status = ERROR_GEN_FAILURE; goto statusReturn; } // get block transfer buffer pBlockBuffer = (PUCHAR)SDAllocateFromMemList(pMemCard->hBufferList); // initialize some variables used in data copy SGBufNum = 0; SGBufRemaining = pSG->sr_sglist[SGBufNum].sb_len; pSGBuffer = pSG->sr_sglist[SGBufNum].sb_buf; // split the writes into groups of TransferBlockSize in size to avoid // hogging the SD Bus with large writes for(PartialStartBlock = StartBlock; PartialStartBlock < StartBlock+NumBlocks; PartialStartBlock += pMemCard->BlockTransferSize) { // some variables just used for copying DWORD PartialTransferSize; DWORD CopySize; pCardDataPtr = pBlockBuffer; PartialTransferSize = MIN( pMemCard->BlockTransferSize, StartBlock+NumBlocks-PartialStartBlock); // copy from pSG buffers to pBlockArray CardDataRemaining = PartialTransferSize*SD_BLOCK_SIZE; while (CardDataRemaining) { // get minimum of remaining size in SG buf and data left in pBlockBuffer CopySize = MIN(SGBufRemaining, CardDataRemaining); // copy that much data to block buffer if (0 == CeSafeCopyMemory(pCardDataPtr, pSGBuffer, CopySize)) { status = ERROR_INVALID_PARAMETER; goto statusReturn; } // update pointers and counts pSGBuffer += CopySize; pCardDataPtr += CopySize; CardDataRemaining -= CopySize; SGBufRemaining -= CopySize; // get the next SG Buffer if needed if (!SGBufRemaining && CardDataRemaining) { SGBufNum++; SGBufRemaining = pSG->sr_sglist[SGBufNum].sb_len; pSGBuffer = pSG->sr_sglist[SGBufNum].sb_buf; } } // write the data to the SD Card status = SDMemWriteMultiple( pMemCard, PartialStartBlock, PartialTransferSize, pBlockBuffer); if (status != ERROR_SUCCESS) { break; } } statusReturn: // free the allocated block buffer if (pBlockBuffer) { SDFreeToMemList(pMemCard->hBufferList, pBlockBuffer); } // FATFS wants the status returned in the SG buffers also pSG->sr_status = status; DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: -SDMemWrite\r\n"))); return status; }
//------------------------------------------------------------------------------ // // Function: DMA_IOControl // // This function sends a command to a device. // BOOL DMA_IOControl( DWORD context, DWORD code, UCHAR *pInBuffer, DWORD inSize, UCHAR *pOutBuffer, DWORD outSize, DWORD *pOutSize ) { BOOL rc = FALSE; Instance_t *pInstance = (Instance_t*)context; Device_t *pDevice = pInstance->pDevice; UNREFERENCED_PARAMETER(pOutSize); DEBUGMSG(ZONE_FUNCTION, ( L"+DMA_IOControl(0x%08x, 0x%08x, 0x%08x, %d, 0x%08x, %d, 0x%08x)\r\n", context, code, pInBuffer, inSize, pOutBuffer, outSize, pOutSize )); // Check if we get correct context if ((pInstance == NULL) || (pInstance->cookie != DMA_INSTANCE_COOKIE)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"Incorrect context paramer\r\n" )); goto cleanUp; } switch (code) { case IOCTL_DMA_INTERRUPTDONE: { DmaControllerBase *pController; IOCTL_DMA_INTERRUPTDONE_IN *pContext; DEBUGMSG(ZONE_INFO, (L"DMA: IOCTL_DMA_INTERRUPTDONE\r\n")); if (pInBuffer == NULL || inSize != sizeof(IOCTL_DMA_INTERRUPTDONE_IN)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"IOCTL_DMA_INTERRUPTDONE invalid parameters\r\n" )); SetLastError(ERROR_INVALID_PARAMETER); break; } pContext = (IOCTL_DMA_INTERRUPTDONE_IN*)pInBuffer; switch (pContext->type) { case DMA_TYPE_SYSTEM: pController = pDevice->pSystemController; break; default: SetLastError(ERROR_INVALID_PARAMETER); goto cleanUp; } EnterCriticalSection(&pDevice->cs); rc = pController->InterruptDone(pContext); LeaveCriticalSection(&pDevice->cs); } break; case IOCTL_DMA_RESERVE_CHANNEL: { DmaControllerBase *pController; IOCTL_DMA_RESERVE_IN *pDmaType; IOCTL_DMA_RESERVE_OUT *pContext; DEBUGMSG(ZONE_INFO, (L"DMA: IOCTL_DMA_RESERVE_CHANNEL\r\n")); // check for correct parameters if (pOutBuffer == NULL || outSize != sizeof(IOCTL_DMA_RESERVE_OUT) || pInBuffer == NULL || inSize != sizeof(IOCTL_DMA_RESERVE_IN)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"IOCTL_DMA_RESERVE_CHANNEL invalid parameters\r\n" )); SetLastError(ERROR_INVALID_PARAMETER); break; } // if successful allocate memory pDmaType = (IOCTL_DMA_RESERVE_IN*)pInBuffer; pContext = (IOCTL_DMA_RESERVE_OUT*)pOutBuffer; switch (*pDmaType) { case DMA_TYPE_SYSTEM: pController = pDevice->pSystemController; break; default: SetLastError(ERROR_INVALID_PARAMETER); goto cleanUp; } // reset context information memset(pContext, 0, sizeof(IOCTL_DMA_RESERVE_OUT)); // copy context information pContext->type = *pDmaType; EnterCriticalSection(&pDevice->cs); if (pController->ReserveChannel(pContext) == FALSE) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"IOCTL_DMA_RESERVE_CHANNEL: failed\r\n" )); LeaveCriticalSection(&pDevice->cs); break; } LeaveCriticalSection(&pDevice->cs); rc = TRUE; } break; case IOCTL_DMA_RELEASE_CHANNEL: { DmaControllerBase *pController; IOCTL_DMA_RELEASE_IN *pContext; DEBUGMSG(ZONE_INFO, (L"DMA: IOCTL_DMA_RELEASE_CHANNEL\r\n")); if (pInBuffer == NULL || inSize != sizeof(IOCTL_DMA_RELEASE_IN)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"IOCTL_DMA_RELEASE_CHANNEL invalid parameters\r\n" )); SetLastError(ERROR_INVALID_PARAMETER); break; } pContext = (IOCTL_DMA_RELEASE_IN*)pInBuffer; switch (pContext->type) { case DMA_TYPE_SYSTEM: pController = pDevice->pSystemController; break; default: SetLastError(ERROR_INVALID_PARAMETER); goto cleanUp; } EnterCriticalSection(&pDevice->cs); pController->ReleaseChannel(pContext); LeaveCriticalSection(&pDevice->cs); rc = TRUE; } break; case IOCTL_DMA_REGISTER_EVENTHANDLE: { DmaControllerBase *pController; IOCTL_DMA_REGISTER_EVENTHANDLE_IN *pRegisterEvent; DEBUGMSG(ZONE_INFO, (L"DMA: IOCTL_DMA_REGISTER_EVENTHANDLE\r\n")); if (pInBuffer == NULL || inSize != sizeof(IOCTL_DMA_REGISTER_EVENTHANDLE_IN)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"IOCTL_DMA_REGISTER_EVENTHANDLE invalid parameters\r\n" )); SetLastError(ERROR_INVALID_PARAMETER); break; } pRegisterEvent = (IOCTL_DMA_REGISTER_EVENTHANDLE_IN*)pInBuffer; #if (_WINCEOSVER<600) pRegisterEvent->pContext = (DmaChannelContext_t*)MapCallerPtr( pRegisterEvent->pContext, sizeof(DmaChannelContext_t) ); #endif switch (pRegisterEvent->pContext->type) { case DMA_TYPE_SYSTEM: pController = pDevice->pSystemController; break; default: SetLastError(ERROR_INVALID_PARAMETER); goto cleanUp; } EnterCriticalSection(&pDevice->cs); rc = pController->SetSecondaryInterruptHandler( pRegisterEvent->pContext, pRegisterEvent->hEvent, pRegisterEvent->processId ); LeaveCriticalSection(&pDevice->cs); } break; case IOCTL_DMA_DISABLESTANDBY: { DmaControllerBase *pController; IOCTL_DMA_DISABLESTANDBY_IN *pIoctlInput; DEBUGMSG(ZONE_INFO, (L"DMA: IOCTL_DMA_DISABLESTANDBY\r\n")); if (pInBuffer == NULL || inSize != sizeof(IOCTL_DMA_DISABLESTANDBY_IN)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"IOCTL_DMA_DISABLESTANDBY invalid parameters\r\n" )); SetLastError(ERROR_INVALID_PARAMETER); break; } // Cast pInBuffer pIoctlInput = (IOCTL_DMA_DISABLESTANDBY_IN*)pInBuffer; #if (_WINCEOSVER<600) pIoctlInput->pContext = (DmaChannelContext_t*)MapCallerPtr( pIoctlInput->pContext, sizeof(DmaChannelContext_t) ); #endif if (!pIoctlInput->bDelicatedChannel) { switch (pIoctlInput->pContext->type) { case DMA_TYPE_SYSTEM: pController = pDevice->pSystemController; break; default: SetLastError(ERROR_INVALID_PARAMETER); goto cleanUp; } } else { pController = pDevice->pSystemController; } EnterCriticalSection(&pDevice->cs); rc = pController->DisableStandby( pIoctlInput->pContext, pIoctlInput->bNoStandby ); LeaveCriticalSection(&pDevice->cs); } break; case IOCTL_DMA_REQUEST_DEDICATED_INTERRUPT: { SystemDmaController *pController; IOCTL_DMA_REQUEST_DEDICATED_INTERRUPT_OUT *pIoctlOutput; DEBUGMSG(ZONE_INFO, (L"DMA: IOCTL_DMA_REQUEST_DEDICATED_INTERRUPT\r\n")); if (pOutBuffer == NULL || outSize != sizeof(IOCTL_DMA_REQUEST_DEDICATED_INTERRUPT_OUT) || pInBuffer == NULL || inSize != sizeof(IOCTL_DMA_REQUEST_DEDICATED_INTERRUPT_IN)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"IOCTL_DMA_REQUEST_DEDICATED_INTERRUPT invalid parameters\r\n" )); SetLastError(ERROR_INVALID_PARAMETER); break; } // Cast pOutBuffer pIoctlOutput = (IOCTL_DMA_REQUEST_DEDICATED_INTERRUPT_OUT*)pOutBuffer; //assume this is a system interrupt pController = pDevice->pSystemController; EnterCriticalSection(&pDevice->cs); rc = pController->DI_ReserveInterrupt( *((DWORD*)pInBuffer), &pIoctlOutput->IrqNum, &pIoctlOutput->DmaControllerPhysAddr, &pIoctlOutput->ffDmaChannels ); LeaveCriticalSection(&pDevice->cs); } break; case IOCTL_DMA_RELEASE_DEDICATED_INTERRUPT: { SystemDmaController *pController; DEBUGMSG(ZONE_INFO, (L"DMA: IOCTL_DMA_RELEASE_DEDICATED_INTERRUPT\r\n")); if (pInBuffer == NULL || inSize != sizeof(IOCTL_DMA_RELEASE_DEDICATED_INTERRUPT_IN)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: DMA_IOControl: " L"IOCTL_DMA_RELEASE_DEDICATED_INTERRUPT invalid parameters\r\n" )); SetLastError(ERROR_INVALID_PARAMETER); break; } //assume this is a system interrupt pController = pDevice->pSystemController; EnterCriticalSection(&pDevice->cs); rc = pController->DI_ReleaseInterrupt(*((DWORD*)pInBuffer)); LeaveCriticalSection(&pDevice->cs); } break; } cleanUp: DEBUGMSG(ZONE_FUNCTION, (L"-DMA_IOControl(rc = %d)\r\n", rc)); return rc; }