diff -r b7e488c49d0d -r 117faf51deac omap3530/beagle_drivers/wb/api/src/cyasstorage.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omap3530/beagle_drivers/wb/api/src/cyasstorage.c Wed Mar 03 13:10:32 2010 +0000 @@ -0,0 +1,3941 @@ +/* Cypress West Bridge API source file (cyasstorage.c) +## =========================== +## +## Copyright Cypress Semiconductor Corporation, 2006-2009, +## All Rights Reserved +## UNPUBLISHED, LICENSED SOFTWARE. +## +## CONFIDENTIAL AND PROPRIETARY INFORMATION +## WHICH IS THE PROPERTY OF CYPRESS. +## +## Use of this file is governed +## by the license agreement included in the file +## +## /license/license.txt +## +## where is the Cypress software +## installation root directory path. +## +## =========================== +*/ + +/* +* Storage Design +* +* The storage module is fairly straight forward once the DMA and LOWLEVEL modules +* have been designed. The storage module simple takes requests from the user, queues the +* associated DMA requests for action, and then sends the low level requests to the +* West Bridge firmware. +* +*/ + +#include "cyashal.h" +#include "cyasstorage.h" +#include "cyaserr.h" +#include "cyasdevice.h" +#include "cyaslowlevel.h" +#include "cyasdma.h" +#include "cyasregs.h" + +/* Map a pre-V1.2 media type to the V1.2+ bus number */ +CyAsReturnStatus_t +CyAnMapBusFromMediaType(CyAsDevice *dev_p, CyAsMediaType type, CyAsBusNumber_t *bus) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t code = (uint8_t)(1 << type) ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (!CyAsDeviceIsConfigured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED ; + + if (!CyAsDeviceIsFirmwareLoaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE ; + + + if (dev_p->media_supported[0] & code) + { + if (dev_p->media_supported[1] & code) + { + /* + * This media type could be supported on multiple buses. So, report + * an address resolution error. + */ + ret = CY_AS_ERROR_ADDRESS_RESOLUTION_ERROR ; + } + else + *bus = 0 ; + } + else + { + if (dev_p->media_supported[1] & code) + *bus = 1 ; + else + ret = CY_AS_ERROR_NO_SUCH_MEDIA ; + } + + return ret ; +} + +static uint16_t +CreateAddress(CyAsBusNumber_t bus, uint32_t device, uint8_t unit) +{ + CyAsHalAssert(bus >= 0 && bus < CY_AS_MAX_BUSES) ; + CyAsHalAssert(device < 16) ; + + return (uint16_t)(((uint8_t)bus << 12) | (device << 8) | unit) ; +} + +CyAsMediaType +CyAsStorageGetMediaFromAddress(uint16_t v) +{ + CyAsMediaType media = CyAsMediaMaxMediaValue ; + + switch(v & 0xFF) + { + case 0x00: + break; + case 0x01: + media = CyAsMediaNand ; + break ; + case 0x02: + media = CyAsMediaSDFlash ; + break ; + case 0x04: + media = CyAsMediaMMCFlash ; + break ; + case 0x08: + media = CyAsMediaCEATA ; + break ; + case 0x10: + media = CyAsMediaSDIO ; + break ; + default: + CyAsHalAssert(0) ; + break ; + } + + return media ; +} + +CyAsBusNumber_t +CyAsStorageGetBusFromAddress(uint16_t v) +{ + CyAsBusNumber_t bus = (CyAsBusNumber_t)((v >> 12) & 0x0f) ; + CyAsHalAssert(bus >= 0 && bus < CY_AS_MAX_BUSES) ; + return bus ; +} + +uint32_t +CyAsStorageGetDeviceFromAddress(uint16_t v) +{ + return (uint32_t)((v >> 8) & 0x0f) ; +} + +static uint8_t +GetUnitFromAddress(uint16_t v) +{ + return (uint8_t)(v & 0xff) ; +} + +static CyAsReturnStatus_t +CyAsMapBadAddr(uint16_t val) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_INVALID_RESPONSE ; + + switch(val) + { + case 0: + ret = CY_AS_ERROR_NO_SUCH_BUS ; + break ; + case 1: + ret = CY_AS_ERROR_NO_SUCH_DEVICE ; + break ; + case 2: + ret = CY_AS_ERROR_NO_SUCH_UNIT ; + break ; + case 3: + ret = CY_AS_ERROR_INVALID_BLOCK ; + break ; + } + + return ret ; +} + +static void +MyStorageRequestCallback(CyAsDevice *dev_p, uint8_t context, CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *resp_p, CyAsReturnStatus_t ret) +{ + uint16_t val ; + uint16_t addr ; + CyAsBusNumber_t bus; + uint32_t device; + CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ; + CyAsDmaEndPoint *ep_p = NULL ; + + (void)resp_p ; + (void)context ; + (void)ret ; + + switch(CyAsLLRequestResponse_GetCode(req_p)) + { + case CY_RQT_MEDIA_CHANGED: + CyAsLLSendStatusResponse(dev_p, CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; + + /* Media has either been inserted or removed */ + addr = CyAsLLRequestResponse_GetWord(req_p, 0) ; + + bus = CyAsStorageGetBusFromAddress(addr); + device = CyAsStorageGetDeviceFromAddress(addr); + + /* Clear the entry for this device to force re-query later */ + CyAsHalMemSet(&(dev_p->storage_device_info[bus][device]), 0, + sizeof(dev_p->storage_device_info[bus][device])) ; + + val = CyAsLLRequestResponse_GetWord(req_p, 1) ; + if (dev_p->storage_event_cb_ms) + { + if (val == 1) + dev_p->storage_event_cb_ms(h, bus, device, CyAsStorageRemoved, 0) ; + else + dev_p->storage_event_cb_ms(h, bus, device, CyAsStorageInserted, 0) ; + } + else if (dev_p->storage_event_cb) + { + if (val == 1) + dev_p->storage_event_cb(h, (CyAsMediaType)bus, CyAsStorageRemoved, 0) ; /*nxz*/ + else + dev_p->storage_event_cb(h, (CyAsMediaType)bus, CyAsStorageInserted, 0) ; /*nxz*/ + } + + break ; + + case CY_RQT_ANTIOCH_CLAIM: + CyAsLLSendStatusResponse(dev_p, CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; + if (dev_p->storage_event_cb || dev_p->storage_event_cb_ms) + { + val = CyAsLLRequestResponse_GetWord(req_p, 0) ; + if (dev_p->storage_event_cb_ms) + { + if (val & 0x0100) + dev_p->storage_event_cb_ms(h, 0, 0, CyAsStorageAntioch, 0) ; + if (val & 0x0200) + dev_p->storage_event_cb_ms(h, 1, 0, CyAsStorageAntioch, 0) ; + } + else + { + if (val & 0x01) + dev_p->storage_event_cb(h, CyAsMediaNand, CyAsStorageAntioch, 0) ; + if (val & 0x02) + dev_p->storage_event_cb(h, CyAsMediaSDFlash, CyAsStorageAntioch, 0) ; + if (val & 0x04) + dev_p->storage_event_cb(h, CyAsMediaMMCFlash, CyAsStorageAntioch, 0) ; + if (val & 0x08) + dev_p->storage_event_cb(h, CyAsMediaCEATA, CyAsStorageAntioch, 0) ; + } + } + break ; + + case CY_RQT_ANTIOCH_RELEASE: + CyAsLLSendStatusResponse(dev_p, CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; + val = CyAsLLRequestResponse_GetWord(req_p, 0) ; + if (dev_p->storage_event_cb_ms) + { + if (val & 0x0100) + dev_p->storage_event_cb_ms(h, 0, 0, CyAsStorageProcessor, 0) ; + if (val & 0x0200) + dev_p->storage_event_cb_ms(h, 1, 0, CyAsStorageProcessor, 0) ; + } + else if (dev_p->storage_event_cb) + { + if (val & 0x01) + dev_p->storage_event_cb(h, CyAsMediaNand, CyAsStorageProcessor, 0) ; + if (val & 0x02) + dev_p->storage_event_cb(h, CyAsMediaSDFlash, CyAsStorageProcessor, 0) ; + if (val & 0x04) + dev_p->storage_event_cb(h, CyAsMediaMMCFlash, CyAsStorageProcessor, 0) ; + if (val & 0x08) + dev_p->storage_event_cb(h, CyAsMediaCEATA, CyAsStorageProcessor, 0) ; + } + break ; + + + case CY_RQT_SDIO_INTR: + CyAsLLSendStatusResponse(dev_p, CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; + val = CyAsLLRequestResponse_GetWord(req_p, 0) ; + if (dev_p->storage_event_cb_ms) + { + if (val & 0x0100) + dev_p->storage_event_cb_ms(h, 1, 0, CyAsSdioInterrupt, 0) ; + else + dev_p->storage_event_cb_ms(h, 0, 0, CyAsSdioInterrupt, 0) ; + + } + else if (dev_p->storage_event_cb) + { + dev_p->storage_event_cb(h, CyAsMediaSDIO, CyAsSdioInterrupt, 0) ; + } + break; + + case CY_RQT_P2S_DMA_START: + /* Do the DMA setup for the waiting operation. This event is used only in + * the MTP mode firmware. */ + CyAsLLSendStatusResponse(dev_p, CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; + if (dev_p->storage_oper == CyAsOpRead) + { + ep_p = CY_AS_NUM_EP(dev_p, CY_AS_P2S_READ_ENDPOINT) ; + CyAsDmaEndPointSetStopped(ep_p) ; + CyAsDmaKickStart(dev_p, CY_AS_P2S_READ_ENDPOINT) ; + } + else + { + ep_p = CY_AS_NUM_EP(dev_p, CY_AS_P2S_WRITE_ENDPOINT) ; + CyAsDmaEndPointSetStopped(ep_p) ; + CyAsDmaKickStart(dev_p, CY_AS_P2S_WRITE_ENDPOINT) ; + } + break ; + + default: + CyAsHalPrintMessage("Invalid request received on storage context\n") ; + val = req_p->box0 ; + CyAsLLSendDataResponse(dev_p, CY_RQT_STORAGE_RQT_CONTEXT, CY_RESP_INVALID_REQUEST, sizeof(val), &val) ; + break ; + } +} + +static CyAsReturnStatus_t +IsStorageActive(CyAsDevice *dev_p) +{ + if (!CyAsDeviceIsConfigured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED ; + + if (!CyAsDeviceIsFirmwareLoaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE ; + + if (dev_p->storage_count == 0) + return CY_AS_ERROR_NOT_RUNNING ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + return CY_AS_ERROR_SUCCESS ; +} + +static void +CyAsStorageFuncCallback(CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t ret) ; + +static CyAsReturnStatus_t +MyHandleResponseNoData(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyHandleResponseStorageStart(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyAsReturnStatus_t ret) +{ + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + if (dev_p->storage_count > 0 && ret == CY_AS_ERROR_ALREADY_RUNNING) + ret = CY_AS_ERROR_SUCCESS ; + + ret = CyAsDmaEnableEndPoint(dev_p, CY_AS_P2S_WRITE_ENDPOINT, CyTrue, CyAsDirectionIn) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + ret = CyAsDmaSetMaxDmaSize(dev_p, CY_AS_P2S_WRITE_ENDPOINT, CY_AS_STORAGE_EP_SIZE) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + ret = CyAsDmaEnableEndPoint(dev_p, CY_AS_P2S_READ_ENDPOINT, CyTrue, CyAsDirectionOut) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + ret = CyAsDmaSetMaxDmaSize(dev_p, CY_AS_P2S_READ_ENDPOINT, CY_AS_STORAGE_EP_SIZE) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + CyAsLLRegisterRequestCallback(dev_p, CY_RQT_STORAGE_RQT_CONTEXT, MyStorageRequestCallback) ; + + /* Create the request/response used for storage reads and writes. */ + dev_p->storage_rw_req_p = CyAsLLCreateRequest(dev_p, 0, CY_RQT_STORAGE_RQT_CONTEXT, 5) ; + if (dev_p->storage_rw_req_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY; + goto destroy; + } + + dev_p->storage_rw_resp_p = CyAsLLCreateResponse(dev_p, 5) ; + if (dev_p->storage_rw_resp_p == 0) + { + CyAsLLDestroyRequest(dev_p, dev_p->storage_rw_req_p) ; + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + } + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + /* Increment the storage count only if the above functionality succeeds.*/ + if (ret == CY_AS_ERROR_SUCCESS) + { + if (dev_p->storage_count == 0) + { + CyAsHalMemSet(dev_p->storage_device_info, 0, sizeof(dev_p->storage_device_info)) ; + dev_p->is_storage_only_mode = CyFalse ; + } + + dev_p->storage_count++ ; + } + + CyAsDeviceClearSSSPending(dev_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageStart(CyAsDeviceHandle handle, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (!CyAsDeviceIsConfigured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED ; + + if (!CyAsDeviceIsFirmwareLoaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + if(CyAsDeviceIsSSSPending(dev_p)) + return CY_AS_ERROR_STARTSTOP_PENDING ; + + CyAsDeviceSetSSSPending(dev_p) ; + + if (dev_p->storage_count == 0) + { + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_START_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + { + CyAsDeviceClearSSSPending(dev_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + CyAsDeviceClearSSSPending(dev_p) ; + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseStorageStart(dev_p, req_p, reply_p, ret) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_START, + 0, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the FuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + } + else + { + dev_p->storage_count++ ; + if (cb) + cb(handle, ret, client, CY_FUNCT_CB_STOR_START, 0) ; + } + + CyAsDeviceClearSSSPending(dev_p) ; + + return ret ; +} + + +static CyAsReturnStatus_t +MyHandleResponseStorageStop(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyAsReturnStatus_t ret) +{ + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + if (ret == CY_AS_ERROR_SUCCESS) + { + CyAsLLDestroyRequest(dev_p, dev_p->storage_rw_req_p) ; + CyAsLLDestroyResponse(dev_p, dev_p->storage_rw_resp_p) ; + dev_p->storage_count-- ; + } + + CyAsDeviceClearSSSPending(dev_p) ; + + return ret ; +} +CyAsReturnStatus_t +CyAsStorageStop(CyAsDeviceHandle handle, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (CyAsDeviceIsStorageAsyncPending(dev_p)) + return CY_AS_ERROR_ASYNC_PENDING ; + + if(CyAsDeviceIsSSSPending(dev_p)) + return CY_AS_ERROR_STARTSTOP_PENDING ; + + CyAsDeviceSetSSSPending(dev_p) ; + + if (dev_p->storage_count == 1) + { + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_STOP_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 0) ; + if (req_p == 0) + { + CyAsDeviceClearSSSPending(dev_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + CyAsDeviceClearSSSPending(dev_p) ; + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseStorageStop(dev_p, req_p, reply_p, ret) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_STOP, + 0, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the MiscFuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + } + else if(dev_p->storage_count > 1) + { + dev_p->storage_count-- ; + if (cb) + cb(handle, ret, client, CY_FUNCT_CB_STOR_STOP, 0) ; + } + + CyAsDeviceClearSSSPending(dev_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageRegisterCallback(CyAsDeviceHandle handle, CyAsStorageEventCallback callback) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (!CyAsDeviceIsConfigured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED ; + + if (!CyAsDeviceIsFirmwareLoaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE ; + + if (dev_p->storage_count == 0) + return CY_AS_ERROR_NOT_RUNNING ; + + dev_p->storage_event_cb = NULL ; + dev_p->storage_event_cb_ms = callback ; + + return CY_AS_ERROR_SUCCESS ; +} + + + +static CyAsReturnStatus_t +MyHandleResponseStorageClaim(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_NO_SUCH_ADDRESS) + { + ret = CyAsMapBadAddr(CyAsLLRequestResponse_GetWord(reply_p, 3)) ; + goto destroy ; + } + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_MEDIA_CLAIMED_RELEASED) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + /* The response must be about the address I am trying to claim or the firmware is broken */ + if ((CyAsStorageGetBusFromAddress(CyAsLLRequestResponse_GetWord(req_p, 0)) != + CyAsStorageGetBusFromAddress(CyAsLLRequestResponse_GetWord(reply_p, 0))) || + (CyAsStorageGetDeviceFromAddress(CyAsLLRequestResponse_GetWord(req_p, 0)) != + CyAsStorageGetDeviceFromAddress(CyAsLLRequestResponse_GetWord(reply_p, 0)))) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + if (CyAsLLRequestResponse_GetWord(reply_p, 1) != 1) + ret = CY_AS_ERROR_NOT_ACQUIRED ; + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyStorageClaim(CyAsDevice *dev_p, + void* data, + CyAsBusNumber_t bus, + uint32_t device, + uint16_t req_flags, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if(dev_p->mtp_count > 0) + return CY_AS_ERROR_NOT_VALID_IN_MTP ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_CLAIM_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, device, 0)) ; + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 4) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseStorageClaim(dev_p, req_p, reply_p) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_CLAIM, + data, dev_p->func_cbs_stor, req_flags, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the MiscFuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageClaim(CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS ; + + return MyStorageClaim(dev_p, NULL, bus, device, CY_AS_REQUEST_RESPONSE_MS, cb, client) ; +} + +static CyAsReturnStatus_t +MyHandleResponseStorageRelease(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_NO_SUCH_ADDRESS) + { + ret = CyAsMapBadAddr(CyAsLLRequestResponse_GetWord(reply_p, 3)) ; + goto destroy ; + } + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_MEDIA_CLAIMED_RELEASED) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + /* The response must be about the address I am trying to release or the firmware is broken */ + if ((CyAsStorageGetBusFromAddress(CyAsLLRequestResponse_GetWord(req_p, 0)) != + CyAsStorageGetBusFromAddress(CyAsLLRequestResponse_GetWord(reply_p, 0))) || + (CyAsStorageGetDeviceFromAddress(CyAsLLRequestResponse_GetWord(req_p, 0)) != + CyAsStorageGetDeviceFromAddress(CyAsLLRequestResponse_GetWord(reply_p, 0)))) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + + if (CyAsLLRequestResponse_GetWord(reply_p, 1) != 0) + ret = CY_AS_ERROR_NOT_RELEASED ; + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyStorageRelease(CyAsDevice* dev_p, + void* data, + CyAsBusNumber_t bus, + uint32_t device, + uint16_t req_flags, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if(dev_p->mtp_count > 0) + return CY_AS_ERROR_NOT_VALID_IN_MTP ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_RELEASE_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, device, 0)) ; + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 4) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseStorageRelease(dev_p, req_p, reply_p) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_RELEASE, + data, dev_p->func_cbs_stor, req_flags, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the MiscFuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageRelease(CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS ; + + return MyStorageRelease(dev_p, NULL, bus, device, CY_AS_REQUEST_RESPONSE_MS, cb, client) ; +} + +static CyAsReturnStatus_t +MyHandleResponseStorageQueryBus(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + uint32_t* count) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t code = CyAsLLRequestResponse_GetCode(reply_p) ; + uint16_t v ; + + if (code == CY_RESP_NO_SUCH_ADDRESS) + { + ret = CY_AS_ERROR_NO_SUCH_BUS ; + goto destroy ; + } + + if (code != CY_RESP_BUS_DESCRIPTOR) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + /* + * Verify that the response corresponds to the bus that was queried. + */ + if (CyAsStorageGetBusFromAddress(CyAsLLRequestResponse_GetWord(req_p, 0)) != + CyAsStorageGetBusFromAddress(CyAsLLRequestResponse_GetWord(reply_p, 0))) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + v = CyAsLLRequestResponse_GetWord(reply_p, 1) ; + if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) + { + /* + * This request is only for the count of devices on the bus. There + * is no need to check the media type. + */ + if (v) + *count = 1 ; + else + *count = 0 ; + } + else + { + /* + * This request is for the count of devices of a particular type. We need + * to check whether the media type found matches the queried type. + */ + CyAsMediaType queried = (CyAsMediaType)CyAsLLRequestResponse_GetWord(req_p, 1) ; + CyAsMediaType found = CyAsStorageGetMediaFromAddress(v) ; + + if (queried == found) + *count = 1 ; + else + *count = 0 ; + } + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +MyStorageQueryBus(CyAsDevice *dev_p, + CyAsBusNumber_t bus, + CyAsMediaType type, + uint16_t req_flags, + uint32_t *count, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret ; + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsFunctCBType cbType = CY_FUNCT_CB_STOR_QUERYBUS ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* Create the request to send to the Antioch device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_QUERY_BUS, CY_RQT_STORAGE_RQT_CONTEXT, 2) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, 0, 0)) ; + CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)type) ; + + /* Reserve space for the reply, the reply data will not exceed two words. */ + reply_p = CyAsLLCreateResponse(dev_p, 2) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + req_p->flags |= req_flags; + return MyHandleResponseStorageQueryBus(dev_p, req_p, reply_p, count) ; + } + else + { + if (req_flags == CY_AS_REQUEST_RESPONSE_EX) + cbType = CY_FUNCT_CB_STOR_QUERYMEDIA ; + + ret = CyAsMiscSendRequest(dev_p, cb, client, cbType, + count, dev_p->func_cbs_stor, req_flags, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the MiscFuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageQueryBus(CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t *count, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + return MyStorageQueryBus(dev_p, bus, CyAsMediaMaxMediaValue, CY_AS_REQUEST_RESPONSE_MS, + count, cb, client) ; +} + +CyAsReturnStatus_t +CyAsStorageQueryMedia(CyAsDeviceHandle handle, + CyAsMediaType type, + uint32_t *count, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsBusNumber_t bus ; + + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + ret = CyAnMapBusFromMediaType(dev_p, type, &bus) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + return MyStorageQueryBus(dev_p, bus, type, CY_AS_REQUEST_RESPONSE_EX, + count, cb, client) ; +} + +static CyAsReturnStatus_t +MyHandleResponseStorageQueryDevice(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + void* data_p) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint16_t v ; + CyAsBusNumber_t bus ; + CyAsMediaType type ; + uint32_t device ; + CyBool removable ; + CyBool writeable ; + CyBool locked ; + uint16_t block_size ; + uint32_t number_units ; + uint32_t number_eus ; + + if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_NO_SUCH_ADDRESS) + { + ret = CyAsMapBadAddr(CyAsLLRequestResponse_GetWord(reply_p, 3)) ; + goto destroy ; + } + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_DEVICE_DESCRIPTOR) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + /* Unpack the response */ + v = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + type = CyAsStorageGetMediaFromAddress(v) ; + bus = CyAsStorageGetBusFromAddress(v) ; + device = CyAsStorageGetDeviceFromAddress(v) ; + + block_size = CyAsLLRequestResponse_GetWord(reply_p, 1) ; + + v = CyAsLLRequestResponse_GetWord(reply_p, 2) ; + removable = (v & 0x8000) ? CyTrue : CyFalse ; + writeable = (v & 0x0100) ? CyTrue : CyFalse ; + locked = (v & 0x0200) ? CyTrue : CyFalse ; + number_units = (v & 0xff) ; + + number_eus = (CyAsLLRequestResponse_GetWord(reply_p, 3) << 16) | CyAsLLRequestResponse_GetWord(reply_p, 4) ; + + /* Store the results based on the version of originating function */ + if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) + { + CyAsStorageQueryDeviceData *store_p = (CyAsStorageQueryDeviceData*)data_p ; + + /* Make sure the response is about the address we asked about - if not, firmware error */ + if ((bus != store_p->bus) || (device != store_p->device)) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + store_p->desc_p.type = type ; + store_p->desc_p.removable = removable ; + store_p->desc_p.writeable = writeable ; + store_p->desc_p.block_size = block_size ; + store_p->desc_p.number_units = number_units ; + store_p->desc_p.locked = locked ; + store_p->desc_p.erase_unit_size = number_eus ; + dev_p->storage_device_info[bus][device] = store_p->desc_p ; + } + else + { + CyAsStorageQueryDeviceData_dep *store_p = (CyAsStorageQueryDeviceData_dep*)data_p ; + + /* Make sure the response is about the address we asked about - if not, firmware error */ + if ((type != store_p->type) || (device != store_p->device)) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + store_p->desc_p.type = type ; + store_p->desc_p.removable = removable ; + store_p->desc_p.writeable = writeable ; + store_p->desc_p.block_size = block_size ; + store_p->desc_p.number_units = number_units ; + store_p->desc_p.locked = locked ; + store_p->desc_p.erase_unit_size = number_eus ; + dev_p->storage_device_info[bus][device] = store_p->desc_p ; + } + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyStorageQueryDevice(CyAsDevice *dev_p, + void* data_p, + uint16_t req_flags, + CyAsBusNumber_t bus, + uint32_t device, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* Create the request to send to the Antioch device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_QUERY_DEVICE, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, device, 0)) ; + + /* Reserve space for the reply, the reply data will not exceed five words. */ + reply_p = CyAsLLCreateResponse(dev_p, 5) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + req_p->flags |= req_flags; + return MyHandleResponseStorageQueryDevice(dev_p, req_p, reply_p, data_p) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_QUERYDEVICE, + data_p, dev_p->func_cbs_stor, req_flags, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the MiscFuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageQueryDevice(CyAsDeviceHandle handle, + CyAsStorageQueryDeviceData* data_p, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + return MyStorageQueryDevice(dev_p, data_p, CY_AS_REQUEST_RESPONSE_MS, data_p->bus, + data_p->device, cb, client) ; +} + +static CyAsReturnStatus_t +MyHandleResponseStorageQueryUnit(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + void* data_p) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsBusNumber_t bus ; + uint32_t device ; + uint32_t unit ; + CyAsMediaType type ; + uint16_t block_size ; + uint32_t start_block ; + uint32_t unit_size ; + uint16_t v ; + + if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_NO_SUCH_ADDRESS) + { + ret = CyAsMapBadAddr(CyAsLLRequestResponse_GetWord(reply_p, 3)) ; + goto destroy ; + } + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_UNIT_DESCRIPTOR) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + /* Unpack the response */ + v = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + bus = CyAsStorageGetBusFromAddress(v) ; + device = CyAsStorageGetDeviceFromAddress(v) ; + unit = GetUnitFromAddress(v) ; + + type = CyAsStorageGetMediaFromAddress(CyAsLLRequestResponse_GetWord(reply_p, 1)); + + block_size = CyAsLLRequestResponse_GetWord(reply_p, 2) ; + start_block = CyAsLLRequestResponse_GetWord(reply_p, 3) | (CyAsLLRequestResponse_GetWord(reply_p, 4) << 16) ; + unit_size = CyAsLLRequestResponse_GetWord(reply_p, 5) | (CyAsLLRequestResponse_GetWord(reply_p, 6) << 16) ; + + /* Store the results based on the version of originating function */ + if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) + { + CyAsStorageQueryUnitData *store_p = (CyAsStorageQueryUnitData*)data_p ; + + /* Make sure the response is about the address we asked about - if not, firmware error */ + if (bus != store_p->bus || device != store_p->device || unit != store_p->unit) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + store_p->desc_p.type = type ; + store_p->desc_p.block_size = block_size ; + store_p->desc_p.start_block = start_block ; + store_p->desc_p.unit_size = unit_size ; + } + else + { + CyAsStorageQueryUnitData_dep *store_p = (CyAsStorageQueryUnitData_dep*)data_p ; + + /* Make sure the response is about the media type we asked about - if not, firmware error */ + if ((type != store_p->type) || (device != store_p->device) || (unit != store_p->unit) ) { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + store_p->desc_p.type = type ; + store_p->desc_p.block_size = block_size ; + store_p->desc_p.start_block = start_block ; + store_p->desc_p.unit_size = unit_size ; + } + + dev_p->storage_device_info[bus][device].type = type ; + dev_p->storage_device_info[bus][device].block_size = block_size ; + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyStorageQueryUnit(CyAsDevice *dev_p, + void* data_p, + uint16_t req_flags, + CyAsBusNumber_t bus, + uint32_t device, + uint32_t unit, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_QUERY_UNIT, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + if (device > 255) + return CY_AS_ERROR_NO_SUCH_DEVICE ; + + if (unit > 255) + return CY_AS_ERROR_NO_SUCH_UNIT ; + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, device, (uint8_t)unit)) ; + + /* Reserve space for the reply, the reply data will be of seven words. */ + reply_p = CyAsLLCreateResponse(dev_p, 7) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + req_p->flags |= req_flags ; + return MyHandleResponseStorageQueryUnit(dev_p, req_p, reply_p, data_p) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_QUERYUNIT, + data_p, dev_p->func_cbs_stor, req_flags, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the MiscFuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageQueryUnit(CyAsDeviceHandle handle, + CyAsStorageQueryUnitData* data_p, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + return MyStorageQueryUnit(dev_p, data_p, CY_AS_REQUEST_RESPONSE_MS, data_p->bus, + data_p->device, data_p->unit, cb, client) ; +} + + +static CyAsReturnStatus_t +CyAsGetBlockSize(CyAsDevice *dev_p, + CyAsBusNumber_t bus, + uint32_t device, + CyAsFunctionCallback cb) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_QUERY_DEVICE, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, device, 0)) ; + + reply_p = CyAsLLCreateResponse(dev_p, 4) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_NO_SUCH_ADDRESS) + { + ret = CY_AS_ERROR_NO_SUCH_BUS ; + goto destroy ; + } + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_DEVICE_DESCRIPTOR) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + /* Make sure the response is about the media type we asked about - if not, firmware error */ + if ((CyAsStorageGetBusFromAddress(CyAsLLRequestResponse_GetWord(reply_p, 0)) != bus) || + (CyAsStorageGetDeviceFromAddress(CyAsLLRequestResponse_GetWord(reply_p, 0)) != device) ) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + + dev_p->storage_device_info[bus][device].block_size = CyAsLLRequestResponse_GetWord(reply_p, 1) ; + } + else + ret = CY_AS_ERROR_INVALID_REQUEST ; + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +MyStorageDeviceControl( + CyAsDevice *dev_p, + CyAsBusNumber_t bus, + uint32_t device, + CyBool card_detect_en, + CyBool write_prot_en, + CyAsStorageCardDetect config_detect, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret ; + CyBool use_gpio = CyFalse ; + + (void)device ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (!CyAsDeviceIsConfigured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED ; + + if (!CyAsDeviceIsFirmwareLoaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS ; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE ; + + /* If SD is not supported on the specified bus, then return ERROR */ + if((dev_p->media_supported[bus] ==0 ) || (dev_p->media_supported[bus] &(1<func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the MiscFuncCallback */ + return ret ; + } +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageDeviceControl(CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + CyBool card_detect_en, + CyBool write_prot_en, + CyAsStorageCardDetect config_detect, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + return MyStorageDeviceControl(dev_p, bus, device, card_detect_en, write_prot_en, config_detect, cb, client); +} + +static void +CyAsAsyncStorageCallback(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, void *buf_p, uint32_t size, CyAsReturnStatus_t ret) +{ + CyAsStorageCallback_dep cb ; + CyAsStorageCallback cb_ms ; + + (void)size ; + (void)buf_p ; + (void)ep ; + + CyAsDeviceClearStorageAsyncPending(dev_p) ; + + /* + * If the LL request callback has already been called, the user + * callback has to be called from here. + */ + if (!dev_p->storage_wait) + { + CyAsHalAssert(dev_p->storage_cb != NULL || dev_p->storage_cb_ms != NULL) ; + cb = dev_p->storage_cb ; + cb_ms = dev_p->storage_cb_ms ; + + dev_p->storage_cb = 0 ; + dev_p->storage_cb_ms = 0 ; + + if (ret == CY_AS_ERROR_SUCCESS) + ret = dev_p->storage_error ; + + if (cb_ms) + { + cb_ms((CyAsDeviceHandle)dev_p, dev_p->storage_bus_index, dev_p->storage_device_index, + dev_p->storage_unit, dev_p->storage_block_addr, dev_p->storage_oper, ret) ; + } + else + { + cb((CyAsDeviceHandle)dev_p, + dev_p->storage_device_info[dev_p->storage_bus_index][dev_p->storage_device_index].type, + dev_p->storage_device_index, dev_p->storage_unit, dev_p->storage_block_addr, dev_p->storage_oper, ret) ; + } + } + else + dev_p->storage_error = ret ; +} + +static void +CyAsAsyncStorageReplyCallback( + CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t ret) +{ + CyAsStorageCallback_dep cb ; + CyAsStorageCallback cb_ms ; + uint8_t reqtype ; + (void)rqt ; + (void)context ; + + reqtype = CyAsLLRequestResponse_GetCode(rqt) ; + + if (ret == CY_AS_ERROR_SUCCESS) + { + if (CyAsLLRequestResponse_GetCode(resp) == CY_RESP_ANTIOCH_DEFERRED_ERROR) + { + ret = CyAsLLRequestResponse_GetWord(resp, 0) & 0x00FF ; + } + else if (CyAsLLRequestResponse_GetCode(resp) != CY_RESP_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + } + + if (ret != CY_AS_ERROR_SUCCESS) + { + if(reqtype == CY_RQT_READ_BLOCK) + CyAsDmaCancel(dev_p, dev_p->storage_read_endpoint, ret) ; + else + CyAsDmaCancel(dev_p, dev_p->storage_write_endpoint, ret) ; + } + + dev_p->storage_wait = CyFalse ; + + /* + * If the DMA callback has already been called, the user callback + * has to be called from here. + */ + if (!CyAsDeviceIsStorageAsyncPending(dev_p)) + { + CyAsHalAssert(dev_p->storage_cb != NULL || dev_p->storage_cb_ms != NULL) ; + cb = dev_p->storage_cb ; + cb_ms = dev_p->storage_cb_ms ; + + dev_p->storage_cb = 0 ; + dev_p->storage_cb_ms = 0 ; + + if (ret == CY_AS_ERROR_SUCCESS) + ret = dev_p->storage_error ; + + if (cb_ms) + { + cb_ms((CyAsDeviceHandle)dev_p, dev_p->storage_bus_index, dev_p->storage_device_index, + dev_p->storage_unit, dev_p->storage_block_addr, dev_p->storage_oper, ret) ; + } + else + { + cb((CyAsDeviceHandle)dev_p, + dev_p->storage_device_info[dev_p->storage_bus_index][dev_p->storage_device_index].type, + dev_p->storage_device_index, dev_p->storage_unit, dev_p->storage_block_addr, dev_p->storage_oper, ret) ; + } + } + else + dev_p->storage_error = ret ; +} + +static CyAsReturnStatus_t +CyAsStorageAsyncOper(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, uint8_t reqtype, uint16_t req_flags, + CyAsBusNumber_t bus, uint32_t device, uint32_t unit, + uint32_t block, void *data_p, uint16_t num_blocks, + CyAsStorageCallback_dep callback, CyAsStorageCallback callback_ms) +{ + uint32_t mask ; + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS ; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE ; + + if (unit > 255) + return CY_AS_ERROR_NO_SUCH_UNIT ; + + /* We are supposed to return sucess if the number of + * blocks is zero + */ + if (num_blocks == 0) + { + if (callback_ms) + callback_ms((CyAsDeviceHandle)dev_p, bus, device, unit, block, + ((reqtype == CY_RQT_WRITE_BLOCK) ? CyAsOpWrite : CyAsOpRead), + CY_AS_ERROR_SUCCESS) ; + else + callback((CyAsDeviceHandle)dev_p, dev_p->storage_device_info[bus][device].type, + device, unit, block, ((reqtype == CY_RQT_WRITE_BLOCK) ? CyAsOpWrite : CyAsOpRead), + CY_AS_ERROR_SUCCESS) ; + + return CY_AS_ERROR_SUCCESS ; + } + + if (dev_p->storage_device_info[bus][device].block_size == 0) + return CY_AS_ERROR_QUERY_DEVICE_NEEDED ; + + /* + * Since async operations can be triggered by interrupt code, we must + * insure that we do not get multiple async operations going at one time and + * protect this test and set operation from interrupts. + * Also need to check for pending Async MTP writes + */ + mask = CyAsHalDisableInterrupts() ; + if ((CyAsDeviceIsStorageAsyncPending(dev_p)) || (dev_p->storage_wait) || (CyAsDeviceIsUsbAsyncPending(dev_p, 6))) + { + CyAsHalEnableInterrupts(mask) ; + return CY_AS_ERROR_ASYNC_PENDING ; + } + + CyAsDeviceSetStorageAsyncPending(dev_p) ; + CyAsHalEnableInterrupts(mask) ; + + /* + * Storage information about the currently outstanding request + */ + dev_p->storage_cb = callback ; + dev_p->storage_cb_ms = callback_ms ; + dev_p->storage_bus_index = bus ; + dev_p->storage_device_index = device ; + dev_p->storage_unit = unit ; + dev_p->storage_block_addr = block ; + + /* Initialise the request to send to the West Bridge. */ + req_p = dev_p->storage_rw_req_p ; + CyAsLLInitRequest(req_p, reqtype, CY_RQT_STORAGE_RQT_CONTEXT, 5) ; + + /* Initialise the space for reply from the West Bridge. */ + reply_p = dev_p->storage_rw_resp_p ; + CyAsLLInitResponse(reply_p, 5) ; + + /* Remember which version of the API originated the request */ + req_p->flags |= req_flags ; + + /* Setup the DMA request and adjust the storage operation if we are reading */ + if (reqtype == CY_RQT_READ_BLOCK) + { + ret = CyAsDmaQueueRequest(dev_p, ep, data_p, dev_p->storage_device_info[bus][device].block_size * num_blocks, + CyFalse, CyTrue, CyAsAsyncStorageCallback) ; + dev_p->storage_oper = CyAsOpRead ; + } + else if (reqtype == CY_RQT_WRITE_BLOCK) + { + ret = CyAsDmaQueueRequest(dev_p, ep, data_p, dev_p->storage_device_info[bus][device].block_size * num_blocks, + CyFalse, CyFalse, CyAsAsyncStorageCallback) ; + dev_p->storage_oper = CyAsOpWrite ; + } + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsDeviceClearStorageAsyncPending(dev_p) ; + return ret ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, (uint8_t)unit)) ; + CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((block >> 16) & 0xffff)) ; + CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)(block & 0xffff)) ; + CyAsLLRequestResponse_SetWord(req_p, 3, (uint16_t)((num_blocks >> 8) & 0x00ff)) ; + CyAsLLRequestResponse_SetWord(req_p, 4, (uint16_t)((num_blocks << 8) & 0xff00)) ; + + /* Set the burst mode flag. */ + if (dev_p->is_storage_only_mode) + req_p->data[4] |= 0x0001; + + /* Send the request and wait for completion of storage request */ + dev_p->storage_wait = CyTrue ; + ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyTrue, CyAsAsyncStorageReplyCallback) ; + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsDmaCancel(dev_p, ep, CY_AS_ERROR_CANCELED) ; + CyAsDeviceClearStorageAsyncPending(dev_p) ; + } + + return ret ; +} + +static void +CyAsSyncStorageCallback(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, void *buf_p, uint32_t size, CyAsReturnStatus_t err) +{ + (void)ep ; + (void)buf_p ; + (void)size ; + + dev_p->storage_error = err ; +} + +static void +CyAsSyncStorageReplyCallback( + CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t ret) +{ + uint8_t reqtype ; + (void)rqt ; + + reqtype = CyAsLLRequestResponse_GetCode(rqt) ; + + if (CyAsLLRequestResponse_GetCode(resp) == CY_RESP_ANTIOCH_DEFERRED_ERROR) + { + ret = CyAsLLRequestResponse_GetWord(resp, 0) & 0x00FF ; + + if (ret != CY_AS_ERROR_SUCCESS) + { + if(reqtype == CY_RQT_READ_BLOCK) + CyAsDmaCancel(dev_p, dev_p->storage_read_endpoint, ret) ; + else + CyAsDmaCancel(dev_p, dev_p->storage_write_endpoint, ret) ; + } + } + else if (CyAsLLRequestResponse_GetCode(resp) != CY_RESP_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + + dev_p->storage_wait = CyFalse ; + dev_p->storage_error = ret ; + + /* Wake any threads/processes that are waiting on the read/write completion. */ + CyAsHalWake (&dev_p->context[context]->channel) ; +} + +static CyAsReturnStatus_t +CyAsStorageSyncOper(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, uint8_t reqtype, CyAsBusNumber_t bus, uint32_t device, + uint32_t unit, uint32_t block, void *data_p, uint16_t num_blocks) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsContext *ctxt_p ; + uint32_t loopcount = 200 ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS ; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE ; + + if (unit > 255) + return CY_AS_ERROR_NO_SUCH_UNIT ; + + if ((CyAsDeviceIsStorageAsyncPending(dev_p)) || (dev_p->storage_wait)) + return CY_AS_ERROR_ASYNC_PENDING ; + + /* Also need to check for pending Async MTP writes */ + if(CyAsDeviceIsUsbAsyncPending(dev_p, 6)) + return CY_AS_ERROR_ASYNC_PENDING ; + + /* We are supposed to return sucess if the number of + * blocks is zero + */ + if (num_blocks == 0) + return CY_AS_ERROR_SUCCESS ; + + if (dev_p->storage_device_info[bus][device].block_size == 0) + { + /* + * Normally, a given device has been queried via the query device call before a + * read request is issued. Therefore, this normally will not be run. + */ + ret = CyAsGetBlockSize(dev_p, bus, device, 0) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + } + + /* Initialise the request to send to the West Bridge. */ + req_p = dev_p->storage_rw_req_p ; + CyAsLLInitRequest(req_p, reqtype, CY_RQT_STORAGE_RQT_CONTEXT, 5) ; + + /* Initialise the space for reply from the West Bridge. */ + reply_p = dev_p->storage_rw_resp_p ; + CyAsLLInitResponse(reply_p, 5) ; + + /* Setup the DMA request */ + if (reqtype == CY_RQT_READ_BLOCK) + { + ret = CyAsDmaQueueRequest(dev_p, ep, data_p, dev_p->storage_device_info[bus][device].block_size * num_blocks, CyFalse, + CyTrue, CyAsSyncStorageCallback) ; + dev_p->storage_oper = CyAsOpRead ; + } + else if (reqtype == CY_RQT_WRITE_BLOCK) + { + ret = CyAsDmaQueueRequest(dev_p, ep, data_p, dev_p->storage_device_info[bus][device].block_size * num_blocks, CyFalse, + CyFalse, CyAsSyncStorageCallback) ; + dev_p->storage_oper = CyAsOpWrite ; + } + if (ret != CY_AS_ERROR_SUCCESS) + { + return ret ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, (uint8_t)unit)) ; + CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((block >> 16) & 0xffff)) ; + CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)(block & 0xffff)) ; + CyAsLLRequestResponse_SetWord(req_p, 3, (uint16_t)((num_blocks >> 8) & 0x00ff)) ; + CyAsLLRequestResponse_SetWord(req_p, 4, (uint16_t)((num_blocks << 8) & 0xff00)) ; + + /* Set the burst mode flag. */ + if (dev_p->is_storage_only_mode) + req_p->data[4] |= 0x0001; + + /* Send the request and wait for completion of storage request */ + dev_p->storage_wait = CyTrue ; + ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyTrue, CyAsSyncStorageReplyCallback) ; + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsDmaCancel(dev_p, ep, CY_AS_ERROR_CANCELED) ; + } + else + { + /* Setup the DMA request */ + ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT] ; + ret = CyAsDmaDrainQueue(dev_p, ep, CyFalse) ; + + while (loopcount-- > 0) + { + if (dev_p->storage_wait == CyFalse) + break ; + CyAsHalSleepOn(&ctxt_p->channel, 10) ; + } + + if (dev_p->storage_wait == CyTrue) + { + dev_p->storage_wait = CyFalse ; + CyAsLLRemoveRequest(dev_p, ctxt_p, req_p, CyTrue) ; + ret = CY_AS_ERROR_TIMEOUT ; + } + + if (ret == CY_AS_ERROR_SUCCESS) + ret = dev_p->storage_error ; + } + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageRead(CyAsDeviceHandle handle, CyAsBusNumber_t bus, uint32_t device, uint32_t unit, uint32_t block, + void *data_p, uint16_t num_blocks) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + return CyAsStorageSyncOper(dev_p, dev_p->storage_read_endpoint, CY_RQT_READ_BLOCK, bus, device, + unit, block, data_p, num_blocks) ; +} + +CyAsReturnStatus_t +CyAsStorageWrite(CyAsDeviceHandle handle, CyAsBusNumber_t bus, uint32_t device, uint32_t unit, uint32_t block, + void *data_p, uint16_t num_blocks) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if(dev_p->mtp_turbo_active) + return CY_AS_ERROR_NOT_VALID_DURING_MTP ; + + return CyAsStorageSyncOper(dev_p, dev_p->storage_write_endpoint, CY_RQT_WRITE_BLOCK, bus, device, + unit, block, data_p, num_blocks) ; +} + + +CyAsReturnStatus_t +CyAsStorageReadAsync(CyAsDeviceHandle handle, CyAsBusNumber_t bus, uint32_t device, uint32_t unit, + uint32_t block, void *data_p, uint16_t num_blocks, CyAsStorageCallback callback) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (callback == 0) + return CY_AS_ERROR_NULL_CALLBACK ; + + return CyAsStorageAsyncOper(dev_p, dev_p->storage_read_endpoint, CY_RQT_READ_BLOCK, + CY_AS_REQUEST_RESPONSE_MS, bus, device, unit, block, data_p, num_blocks, NULL, callback); +} + +CyAsReturnStatus_t +CyAsStorageWriteAsync(CyAsDeviceHandle handle, CyAsBusNumber_t bus, uint32_t device, uint32_t unit, + uint32_t block, void *data_p, uint16_t num_blocks, CyAsStorageCallback callback) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (callback == 0) + return CY_AS_ERROR_NULL_CALLBACK ; + + if(dev_p->mtp_turbo_active) + return CY_AS_ERROR_NOT_VALID_DURING_MTP ; + + return CyAsStorageAsyncOper(dev_p, dev_p->storage_write_endpoint, CY_RQT_WRITE_BLOCK, + CY_AS_REQUEST_RESPONSE_MS, bus, device, unit, block, data_p, num_blocks, NULL, callback); +} + + +static void +MyStorageCancelCallback ( + CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t stat) +{ + (void)context ; + (void)stat ; + + /* Nothing to do here, except free up the request and response structures. */ + CyAsLLDestroyResponse(dev_p, resp) ; + CyAsLLDestroyRequest(dev_p, rqt) ; +} + + +CyAsReturnStatus_t +CyAsStorageCancelAsync(CyAsDeviceHandle handle) +{ + CyAsReturnStatus_t ret ; + CyAsLLRequestResponse *req_p , *reply_p ; + + CyAsDevice *dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (!CyAsDeviceIsStorageAsyncPending(dev_p)) + return CY_AS_ERROR_ASYNC_NOT_PENDING ; + + /* + * Create and send a mailbox request to firmware asking it to abort processing + * of the current P2S operation. The rest of the cancel processing will be + * driven through the callbacks for the read/write call. + */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_ABORT_P2S_XFER, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyFalse, MyStorageCancelCallback) ; + if (ret) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + } + + return CY_AS_ERROR_SUCCESS ; +} + +/* + * This function does all the API side clean-up associated with + * CyAsStorageStop, without any communication with the firmware. + */ +void CyAsStorageCleanup(CyAsDevice *dev_p) +{ + if (dev_p->storage_count) + { + CyAsLLDestroyRequest(dev_p, dev_p->storage_rw_req_p) ; + CyAsLLDestroyResponse(dev_p, dev_p->storage_rw_resp_p) ; + dev_p->storage_count = 0 ; + CyAsDeviceClearScsiMessages(dev_p) ; + CyAsHalMemSet(dev_p->storage_device_info, 0, sizeof(dev_p->storage_device_info)) ; + + CyAsDeviceClearStorageAsyncPending(dev_p) ; + dev_p->storage_cb = 0 ; + dev_p->storage_cb_ms = 0 ; + dev_p->storage_wait = CyFalse ; + } +} + +static CyAsReturnStatus_t +MyHandleResponseSDRegRead( + CyAsDevice *dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyAsStorageSDRegReadData *info) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t resp_type, i ; + uint16_t resp_len ; + uint8_t length = info->length ; + uint8_t *data_p = info->buf_p ; + + resp_type = CyAsLLRequestResponse_GetCode(reply_p) ; + if (resp_type == CY_RESP_SD_REGISTER_DATA) + { + uint16_t *resp_p = reply_p->data + 1 ; + uint16_t temp ; + + resp_len = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + CyAsHalAssert(resp_len >= length) ; + + /* + * Copy the values into the output buffer after doing the + * necessary bit shifting. The bit shifting is required because + * the data comes out of the West Bridge with a 6 bit offset. + */ + i = 0 ; + while (length) + { + temp = ((resp_p[i] << 6) | (resp_p[i + 1] >> 10)) ; + i++ ; + + *data_p++ = (uint8_t)(temp >> 8) ; + length-- ; + + if (length) + { + *data_p++ = (uint8_t)(temp & 0xFF) ; + length-- ; + } + } + } + else + { + if (resp_type == CY_RESP_SUCCESS_FAILURE) + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + else + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + + CyAsLLDestroyResponse(dev_p, reply_p) ; + CyAsLLDestroyRequest(dev_p, req_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageSDRegisterRead( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint8_t device, + CyAsSDCardRegType regType, + CyAsStorageSDRegReadData *data_p, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t length ; + + /* + * Sanity checks required before sending the request to the + * firmware. + */ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE ; + + if (regType > CyAsSDReg_CSD) + return CY_AS_ERROR_INVALID_PARAMETER ; + + /* If SD/MMC media is not supported on the addressed bus, return error. */ + if ((dev_p->media_supported[bus] & (1 << CyAsMediaSDFlash)) == 0) + return CY_AS_ERROR_INVALID_PARAMETER ; + + /* + * Find the amount of data to be returned. This will be the minimum of + * the actual data length, and the length requested. + */ + switch (regType) + { + case CyAsSDReg_OCR: + length = CY_AS_SD_REG_OCR_LENGTH ; + break ; + + case CyAsSDReg_CID: + length = CY_AS_SD_REG_CID_LENGTH ; + break ; + + case CyAsSDReg_CSD: + length = CY_AS_SD_REG_CSD_LENGTH ; + break ; + + default: + length = 0 ; + CyAsHalAssert(0) ; + } + + if (length < data_p->length) + data_p->length = length ; + length = data_p->length ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SD_REGISTER_READ, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, (CreateAddress(bus, device, 0) | (uint16_t)regType)) ; + + reply_p = CyAsLLCreateResponse(dev_p, CY_AS_SD_REG_MAX_RESP_LENGTH) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + if (cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseSDRegRead(dev_p, req_p, reply_p, data_p) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_SDREGISTERREAD, + data_p, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the MiscFuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageCreatePPartition( + CyAsDeviceHandle handle, /* Handle to the device of interest */ + CyAsBusNumber_t bus, + uint32_t device, + uint32_t size, /* of P-port only partition in blocks */ + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* Partitions cannot be created or deleted while the USB stack is active. */ + if (dev_p->usb_count) + return CY_AS_ERROR_USB_RUNNING ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_PARTITION_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 3) ; + if (req_p == 0) + { + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, 0x00) ); + CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((size >> 16) & 0xffff)) ; + CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)(size & 0xffff)) ; + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseNoData(dev_p, req_p, reply_p) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_PARTITION, + 0, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the FuncCallback */ + return ret ; + + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageRemovePPartition( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* Partitions cannot be created or deleted while the USB stack is active. */ + if (dev_p->usb_count) + return CY_AS_ERROR_USB_RUNNING ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_PARTITION_ERASE, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + { + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, 0x00) ); + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseNoData(dev_p, req_p, reply_p) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_NODATA, + 0, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the FuncCallback */ + return ret ; + + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyHandleResponseGetTransferAmount(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyAsMSCProgressData *data) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t code = CyAsLLRequestResponse_GetCode(reply_p) ; + uint16_t v1, v2 ; + + if (code != CY_RESP_TRANSFER_COUNT) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + v1 = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + v2 = CyAsLLRequestResponse_GetWord(reply_p, 1) ; + data->wr_count = (uint32_t)((v1 << 16) | v2) ; + + v1 = CyAsLLRequestResponse_GetWord(reply_p, 2) ; + v2 = CyAsLLRequestResponse_GetWord(reply_p, 3) ; + data->rd_count = (uint32_t)((v1 << 16) | v2) ; + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsStorageGetTransferAmount( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + CyAsMSCProgressData *data_p, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* Check if the firmware image supports this feature. */ + if ((dev_p->media_supported[0]) && (dev_p->media_supported[0] == (1 << CyAsMediaNand))) + return CY_AS_ERROR_NOT_SUPPORTED ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_GET_TRANSFER_AMOUNT, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + { + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + /* Reserve space for the reply, the reply data will not exceed four words. */ + reply_p = CyAsLLCreateResponse(dev_p, 4) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, 0x00)); + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseGetTransferAmount(dev_p, req_p, reply_p, data_p) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_GETTRANSFERAMOUNT, + (void *)data_p, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the FuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; + +} + +CyAsReturnStatus_t +CyAsStorageErase( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint32_t erase_unit, + uint16_t num_erase_units, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsStorageActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS ; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE ; + + if (dev_p->storage_device_info[bus][device].block_size == 0) + return CY_AS_ERROR_QUERY_DEVICE_NEEDED ; + + /* If SD is not supported on the specified bus, then return ERROR */ + if(dev_p->storage_device_info[bus][device].type != CyAsMediaSDFlash) + return CY_AS_ERROR_NOT_SUPPORTED; + + if (num_erase_units == 0) + return CY_AS_ERROR_SUCCESS ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_ERASE, CY_RQT_STORAGE_RQT_CONTEXT, 5) ; + if (req_p == 0) + { + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + /* Reserve space for the reply, the reply data will not exceed four words. */ + reply_p = CyAsLLCreateResponse(dev_p, 4) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, 0x00)); + CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((erase_unit >> 16) & 0xffff)) ; + CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)(erase_unit & 0xffff)) ; + CyAsLLRequestResponse_SetWord(req_p, 3, (uint16_t)((num_erase_units >> 8) & 0x00ff)) ; + CyAsLLRequestResponse_SetWord(req_p, 4, (uint16_t)((num_erase_units << 8) & 0xff00)) ; + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + ret = MyHandleResponseNoData(dev_p, req_p, reply_p) ; + + /* If error = "invalid response", this (very likely) means that we are not using the SD-only firmware module + which is the only one supporting StorageErase. In this case force a "non supported" error code */ + if (ret == CY_AS_ERROR_INVALID_RESPONSE) + ret = CY_AS_ERROR_NOT_SUPPORTED; + + return ret ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_STOR_ERASE, + 0, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsStorageFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed as part of the FuncCallback */ + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static void +CyAsStorageFuncCallback(CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t stat) +{ + CyAsFuncCBNode* node = (CyAsFuncCBNode*)dev_p->func_cbs_stor->head_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + CyBool exRequest = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX) == CY_AS_REQUEST_RESPONSE_EX ; + CyBool msRequest = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS) == CY_AS_REQUEST_RESPONSE_MS ; + uint8_t code ; + uint8_t cntxt ; + + CyAsHalAssert(exRequest || msRequest) ; + CyAsHalAssert(dev_p->func_cbs_stor->count != 0) ; + CyAsHalAssert(dev_p->func_cbs_stor->type == CYAS_FUNC_CB) ; + (void) exRequest; + (void) msRequest; + + (void)context ; + + cntxt = CyAsLLRequestResponse_GetContext(rqt) ; + CyAsHalAssert(cntxt == CY_RQT_STORAGE_RQT_CONTEXT) ; + + code = CyAsLLRequestResponse_GetCode(rqt) ; + switch(code) + { + case CY_RQT_START_STORAGE: + ret = MyHandleResponseStorageStart(dev_p, rqt, resp, stat) ; + break ; + case CY_RQT_STOP_STORAGE: + ret = MyHandleResponseStorageStop(dev_p, rqt, resp, stat) ; + break ; + case CY_RQT_CLAIM_STORAGE: + ret = MyHandleResponseStorageClaim(dev_p, rqt, resp) ; + break ; + case CY_RQT_RELEASE_STORAGE: + ret = MyHandleResponseStorageRelease(dev_p, rqt, resp) ; + break ; + case CY_RQT_QUERY_MEDIA: + CyAsHalAssert(CyFalse) ; /* Not used any more. */ + break ; + case CY_RQT_QUERY_BUS: + CyAsHalAssert(node->data != 0) ; + ret = MyHandleResponseStorageQueryBus(dev_p, rqt, resp, (uint32_t*)node->data) ; + break ; + case CY_RQT_QUERY_DEVICE: + CyAsHalAssert(node->data != 0) ; + ret = MyHandleResponseStorageQueryDevice(dev_p, rqt, resp, node->data) ; + break ; + case CY_RQT_QUERY_UNIT: + CyAsHalAssert(node->data != 0) ; + ret = MyHandleResponseStorageQueryUnit(dev_p, rqt, resp, node->data) ; + break ; + case CY_RQT_SD_INTERFACE_CONTROL: + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + case CY_RQT_SD_REGISTER_READ: + CyAsHalAssert(node->data != 0) ; + ret = MyHandleResponseSDRegRead(dev_p, rqt, resp, (CyAsStorageSDRegReadData *)node->data) ; + break ; + case CY_RQT_PARTITION_STORAGE: + ret = MyHandleResponseNoData(dev_p, rqt, resp); + break ; + case CY_RQT_PARTITION_ERASE: + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + case CY_RQT_GET_TRANSFER_AMOUNT: + CyAsHalAssert(node->data != 0) ; + ret = MyHandleResponseGetTransferAmount(dev_p, rqt, resp, (CyAsMSCProgressData *)node->data) ; + break ; + case CY_RQT_ERASE: + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + + /* If error = "invalid response", this (very likely) means that we are not using the SD-only firmware module + which is the only one supporting StorageErase. In this case force a "non supported" error code */ + if (ret == CY_AS_ERROR_INVALID_RESPONSE) + ret = CY_AS_ERROR_NOT_SUPPORTED; + + break ; + + default: + ret = CY_AS_ERROR_INVALID_RESPONSE ; + CyAsHalAssert(CyFalse) ; + break ; + } + + /* + * If the low level layer returns a direct error, use the corresponding error code. + * If not, use the error code based on the response from firmware. + */ + if (stat == CY_AS_ERROR_SUCCESS) + stat = ret ; + + /* Call the user callback, if there is one */ + if (node->cb_p) + node->cb_p((CyAsDeviceHandle)dev_p, stat, node->client_data, (CyAsFunctCBType)node->dataType, node->data) ; + CyAsRemoveCBNode(dev_p->func_cbs_stor) ; +} + + +static void +CyAsSdioSyncReplyCallback( + CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t ret) +{ + (void)rqt ; + + if ((CyAsLLRequestResponse_GetCode(resp) == CY_RESP_SDIO_GET_TUPLE )|| + (CyAsLLRequestResponse_GetCode(resp) == CY_RESP_SDIO_EXT)) + { + ret = CyAsLLRequestResponse_GetWord(resp, 0) ; + if ((ret & 0x00FF) != CY_AS_ERROR_SUCCESS) + { + if(CyAsLLRequestResponse_GetCode(rqt) == CY_RQT_SDIO_READ_EXTENDED) + CyAsDmaCancel(dev_p, dev_p->storage_read_endpoint, ret) ; + else + CyAsDmaCancel(dev_p, dev_p->storage_write_endpoint, ret) ; + } + } + else + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + + dev_p->storage_rw_resp_p=resp; + dev_p->storage_wait = CyFalse ; + if(((ret & 0x00FF) == CY_AS_ERROR_IO_ABORTED) || ((ret & 0x00FF) == CY_AS_ERROR_IO_SUSPENDED)) + dev_p->storage_error = (ret & 0x00FF); + else + dev_p->storage_error = (ret & 0x00FF)? CY_AS_ERROR_INVALID_RESPONSE : CY_AS_ERROR_SUCCESS ; + + /* Wake any threads/processes that are waiting on the read/write completion. */ + CyAsHalWake (&dev_p->context[context]->channel); +} + +CyAsReturnStatus_t +CyAsSdioDeviceCheck( + CyAsDevice* dev_p, + CyAsBusNumber_t bus, + uint32_t device) +{ + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS ; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE ; + + if (!CyAsDeviceIsAstoriaDev(dev_p)) + return CY_AS_ERROR_NOT_SUPPORTED ; + + return (IsStorageActive(dev_p)) ; +} + +CyAsReturnStatus_t +CyAsSdioDirectIo( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint32_t address, + uint8_t miscBuf, + uint16_t argument, + uint8_t isWrite, + uint8_t * data_p ) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint16_t resp_data; + + /* + * Sanity checks required before sending the request to the + * firmware. + */ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + return CY_AS_ERROR_INVALID_FUNCTION; + if(CyAsSdioCheckFunctionSuspended(handle,bus,nFunctionNo)) + return CY_AS_ERROR_FUNCTION_SUSPENDED; + + req_p = CyAsLLCreateRequest(dev_p, (isWrite==CyTrue)?CY_RQT_SDIO_WRITE_DIRECT:CY_RQT_SDIO_READ_DIRECT, + CY_RQT_STORAGE_RQT_CONTEXT, 3) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + /*Setting up request*/ + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, nFunctionNo) ) ; + /* D1 */ + if(isWrite==CyTrue) + { + CyAsLLRequestResponse_SetWord(req_p, 1, ((argument<<8)|0x0080|(nFunctionNo<<4)| + ((miscBuf&CY_SDIO_RAW)<<3)|((miscBuf&CY_SDIO_REARM_INT)>>5)|(uint16_t)(address>>15))); + } + else + { + CyAsLLRequestResponse_SetWord(req_p, 1, (nFunctionNo<<4)|((miscBuf&CY_SDIO_REARM_INT)>>5)| + (uint16_t)(address>>15)); + } + /* D2 */ + CyAsLLRequestResponse_SetWord(req_p, 2, ((uint16_t)((address&0x00007fff)<<1))) ; + + /*Create response*/ + reply_p = CyAsLLCreateResponse(dev_p, 2) ; + + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + /*Sending the request*/ + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /*Check reply type*/ + if ( CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_SDIO_DIRECT) + { + resp_data = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + if(resp_data>>8) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + else if (data_p!=0) + *(uint8_t*)(data_p)=(uint8_t)(resp_data&0x00ff); + } + else + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + +destroy: + if(req_p!=0) + CyAsLLDestroyRequest(dev_p, req_p) ; + if(reply_p!=0) + CyAsLLDestroyResponse(dev_p, reply_p) ; + return ret ; +} + + +CyAsReturnStatus_t +CyAsSdioDirectRead( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint32_t address, + uint8_t miscBuf, + uint8_t * data_p) +{ + return (CyAsSdioDirectIo(handle,bus,device, nFunctionNo, address, miscBuf, 0x00, CyFalse, data_p)); +} + +CyAsReturnStatus_t +CyAsSdioDirectWrite( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint32_t address, + uint8_t miscBuf, + uint16_t argument, + uint8_t * data_p) +{ + return (CyAsSdioDirectIo(handle,bus,device, nFunctionNo, address, miscBuf, argument, CyTrue, data_p)); +} + +/*Cmd53 IO*/ +CyAsReturnStatus_t +CyAsSdioExtendedIO( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint32_t address, + uint8_t miscBuf, + uint16_t argument, + uint8_t isWrite, + uint8_t * data_p , + uint8_t isResume) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t resp_type; + uint8_t reqtype; + uint16_t resp_data; + CyAsContext *ctxt_p ; + uint32_t dmasize,loopcount = 200; + CyAsEndPointNumber_t ep; + + CyAsDevice *dev_p = (CyAsDevice *)handle ; + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + return CY_AS_ERROR_INVALID_FUNCTION; + if(CyAsSdioCheckFunctionSuspended(handle,bus,nFunctionNo)) + return CY_AS_ERROR_FUNCTION_SUSPENDED; + + + if ((CyAsDeviceIsStorageAsyncPending(dev_p)) || (dev_p->storage_wait)) + return CY_AS_ERROR_ASYNC_PENDING ; + + /* Request for 0 bytes of blocks is returned as a success*/ + if(argument == 0) + return CY_AS_ERROR_SUCCESS; + + /* Initialise the request to send to the West Bridge device. */ + if(isWrite == CyTrue) + { + reqtype =CY_RQT_SDIO_WRITE_EXTENDED; + ep=dev_p->storage_write_endpoint; + } + else + { + reqtype=CY_RQT_SDIO_READ_EXTENDED; + ep=dev_p->storage_read_endpoint; + } + + req_p = dev_p->storage_rw_req_p ; + CyAsLLInitRequest(req_p, reqtype, CY_RQT_STORAGE_RQT_CONTEXT, 3) ; + + /* Initialise the space for reply from the Antioch. */ + reply_p = dev_p->storage_rw_resp_p ; + CyAsLLInitResponse(reply_p, 2) ; + + /* Setup the DMA request */ + if(!(miscBuf&CY_SDIO_BLOCKMODE)) + { + if(argument > dev_p->sdiocard[bus].function[nFunctionNo-1].blocksize) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + + } + else + { + if( argument > 511) + { + return CY_AS_ERROR_INVALID_BLOCKSIZE; + } + } + + if(argument == 512) + argument =0; + + dmasize=((miscBuf&CY_SDIO_BLOCKMODE) !=0)? dev_p->sdiocard[bus].function[nFunctionNo-1].blocksize*argument:argument; + + ret = CyAsDmaQueueRequest(dev_p, ep, (void*)(data_p), dmasize, CyFalse, + (isWrite & CyTrue)?CyFalse:CyTrue, CyAsSyncStorageCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + { + return ret ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, nFunctionNo|((isResume)?0x80:0x00) )) ; + CyAsLLRequestResponse_SetWord(req_p, 1, ((uint16_t)nFunctionNo)<<12| + ((uint16_t)(miscBuf&(CY_SDIO_BLOCKMODE|CY_SDIO_OP_INCR)))<<9| + (uint16_t)(address>>7)|((isWrite==CyTrue)?0x8000:0x0000 )) ; + CyAsLLRequestResponse_SetWord(req_p, 2, ((uint16_t)(address&0x0000ffff)<<9) | argument) ; + + + /* Send the request and wait for completion of storage request */ + dev_p->storage_wait = CyTrue ; + ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyTrue, CyAsSdioSyncReplyCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsDmaCancel(dev_p, ep, CY_AS_ERROR_CANCELED) ; + } + else + { + /* Setup the DMA request */ + ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT] ; + ret = CyAsDmaDrainQueue(dev_p, ep, CyTrue) ; + + while (loopcount-- > 0) + { + if (dev_p->storage_wait == CyFalse) + break; + CyAsHalSleepOn(&ctxt_p->channel, 10) ; + } + if (dev_p->storage_wait == CyTrue) + { + dev_p->storage_wait = CyFalse ; + CyAsLLRemoveRequest(dev_p, ctxt_p, req_p, CyTrue) ; + dev_p->storage_error = CY_AS_ERROR_TIMEOUT ; + } + + ret=dev_p->storage_error; + + if (ret != CY_AS_ERROR_SUCCESS) + { + return ret ; + } + + + resp_type = CyAsLLRequestResponse_GetCode(dev_p->storage_rw_resp_p) ; + if (resp_type == CY_RESP_SDIO_EXT) + { + resp_data = CyAsLLRequestResponse_GetWord(reply_p, 0)&0x00ff ; + if(resp_data) + { + ret = CY_AS_ERROR_INVALID_REQUEST ; + } + + } + else + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + } + return ret; + +} + +static void +CyAsSdioAsyncReplyCallback( + CyAsDevice* dev_p, + uint8_t context, + CyAsLLRequestResponse* rqt, + CyAsLLRequestResponse* resp, + CyAsReturnStatus_t ret ) +{ + CyAsStorageCallback cb_ms ; + uint8_t reqtype ; + uint32_t pendingblocks; + (void)rqt ; + (void)context ; + + pendingblocks = 0; + reqtype = CyAsLLRequestResponse_GetCode(rqt) ; + if (ret == CY_AS_ERROR_SUCCESS) + { + if ((CyAsLLRequestResponse_GetCode(resp) == CY_RESP_SUCCESS_FAILURE) || + (CyAsLLRequestResponse_GetCode(resp) == CY_RESP_SDIO_EXT)) + { + ret = CyAsLLRequestResponse_GetWord(resp, 0) ; + ret &= 0x00FF ; + } + else + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + } + + if (ret != CY_AS_ERROR_SUCCESS) + { + if(reqtype == CY_RQT_SDIO_READ_EXTENDED) + CyAsDmaCancel(dev_p, dev_p->storage_read_endpoint, ret) ; + else + CyAsDmaCancel(dev_p, dev_p->storage_write_endpoint, ret) ; + + dev_p->storage_error = ret; + } + + + + dev_p->storage_wait = CyFalse ; + + /* + * If the DMA callback has already been called, the user callback + * has to be called from here. + */ + if (!CyAsDeviceIsStorageAsyncPending(dev_p)) + { + CyAsHalAssert(dev_p->storage_cb_ms != NULL) ; + cb_ms = dev_p->storage_cb_ms ; + + dev_p->storage_cb = 0 ; + dev_p->storage_cb_ms = 0 ; + + if ((ret == CY_AS_ERROR_SUCCESS) || (ret == CY_AS_ERROR_IO_ABORTED) || (ret == CY_AS_ERROR_IO_SUSPENDED)) + { + ret = dev_p->storage_error ; + pendingblocks = ((uint32_t)CyAsLLRequestResponse_GetWord(resp, 1))<<16; + } + else + ret = CY_AS_ERROR_INVALID_RESPONSE; + + cb_ms((CyAsDeviceHandle)dev_p, dev_p->storage_bus_index, dev_p->storage_device_index, + (dev_p->storage_unit | pendingblocks), dev_p->storage_block_addr, dev_p->storage_oper, ret) ; + } + else + dev_p->storage_error = ret ; +} + + +CyAsReturnStatus_t +CyAsSdioExtendedIOAsync( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint32_t address, + uint8_t miscBuf, + uint16_t argument, + uint8_t isWrite, + uint8_t * data_p, + CyAsStorageCallback callback ) +{ + + uint32_t mask ; + uint32_t dmasize; + CyAsLLRequestResponse *req_p , *reply_p ; + uint8_t reqtype; + CyAsEndPointNumber_t ep; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + return CY_AS_ERROR_INVALID_FUNCTION; + if(CyAsSdioCheckFunctionSuspended(handle,bus,nFunctionNo)) + return CY_AS_ERROR_FUNCTION_SUSPENDED; + + if (callback == 0) + return CY_AS_ERROR_NULL_CALLBACK ; + + /* We are supposed to return sucess if the number of + * blocks is zero + */ + if(((miscBuf&CY_SDIO_BLOCKMODE)!=0)&&(argument==0)) + { + callback(handle, bus, device,nFunctionNo,address,((isWrite) ? CyAsOpWrite : CyAsOpRead), CY_AS_ERROR_SUCCESS) ; + return CY_AS_ERROR_SUCCESS ; + } + + + /* + * Since async operations can be triggered by interrupt code, we must + * insure that we do not get multiple async operations going at one time and + * protect this test and set operation from interrupts. + */ + mask = CyAsHalDisableInterrupts() ; + if ((CyAsDeviceIsStorageAsyncPending(dev_p)) || (dev_p->storage_wait)) + { + CyAsHalEnableInterrupts(mask) ; + return CY_AS_ERROR_ASYNC_PENDING ; + } + CyAsDeviceSetStorageAsyncPending(dev_p) ; + CyAsHalEnableInterrupts(mask) ; + + + /* + * Storage information about the currently outstanding request + */ + dev_p->storage_cb_ms = callback ; + dev_p->storage_bus_index = bus ; + dev_p->storage_device_index = device ; + dev_p->storage_unit = nFunctionNo ; + dev_p->storage_block_addr = address ; + + if(isWrite == CyTrue) + { + reqtype =CY_RQT_SDIO_WRITE_EXTENDED; + ep=dev_p->storage_write_endpoint; + } + else + { + reqtype=CY_RQT_SDIO_READ_EXTENDED; + ep=dev_p->storage_read_endpoint; + } + + /* Initialise the request to send to the West Bridge. */ + req_p = dev_p->storage_rw_req_p ; + CyAsLLInitRequest(req_p, reqtype, CY_RQT_STORAGE_RQT_CONTEXT, 3) ; + + /* Initialise the space for reply from the West Bridge. */ + reply_p = dev_p->storage_rw_resp_p ; + CyAsLLInitResponse(reply_p, 2) ; + + if(!(miscBuf&CY_SDIO_BLOCKMODE)) + { + if(argument > dev_p->sdiocard[bus].function[nFunctionNo-1].blocksize) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + + } + else + { + if( argument > 511) + { + return CY_AS_ERROR_INVALID_BLOCKSIZE; + } + } + + if(argument == 512) + argument =0; + dmasize=((miscBuf&CY_SDIO_BLOCKMODE) !=0)? dev_p->sdiocard[bus].function[nFunctionNo-1].blocksize*argument:argument; + + /* Setup the DMA request and adjust the storage operation if we are reading */ + if (reqtype == CY_RQT_SDIO_READ_EXTENDED) + { + ret = CyAsDmaQueueRequest(dev_p, ep, (void*)data_p,dmasize , CyFalse, CyTrue,CyAsAsyncStorageCallback) ; + dev_p->storage_oper = CyAsOpRead ; + } + else if (reqtype == CY_RQT_SDIO_WRITE_EXTENDED) + { + ret = CyAsDmaQueueRequest(dev_p, ep, (void*)data_p, dmasize, CyFalse, CyFalse,CyAsAsyncStorageCallback) ; + dev_p->storage_oper = CyAsOpWrite ; + } + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsDeviceClearStorageAsyncPending(dev_p) ; + return ret ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, nFunctionNo )) ; + CyAsLLRequestResponse_SetWord(req_p, 1, ((uint16_t)nFunctionNo)<<12| + ((uint16_t)(miscBuf&(CY_SDIO_BLOCKMODE|CY_SDIO_OP_INCR)))<<9| + (uint16_t)(address>>7)|((isWrite==CyTrue)?0x8000:0x0000 )) ; + CyAsLLRequestResponse_SetWord(req_p, 2, ((uint16_t)(address&0x0000ffff)<<9) | argument) ; + + + /* Send the request and wait for completion of storage request */ + dev_p->storage_wait = CyTrue ; + ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyTrue, CyAsSdioAsyncReplyCallback) ; + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsDmaCancel(dev_p, ep, CY_AS_ERROR_CANCELED) ; + CyAsDeviceClearStorageAsyncPending(dev_p) ; + } + else + { + CyAsDmaKickStart(dev_p, ep) ; + } + + return ret ; +} + +/* CMD53 Extended Read*/ +CyAsReturnStatus_t +CyAsSdioExtendedRead( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint32_t address, + uint8_t miscBuf, + uint16_t argument, + uint8_t * data_p, + CyAsSdioCallback callback ) +{ + if (callback==0) + return CyAsSdioExtendedIO(handle,bus,device,nFunctionNo,address,miscBuf,argument,CyFalse,data_p,0); + + return CyAsSdioExtendedIOAsync(handle,bus,device,nFunctionNo,address,miscBuf,argument,CyFalse,data_p,callback); +} + +/* CMD53 Extended Write*/ +CyAsReturnStatus_t +CyAsSdioExtendedWrite( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint32_t address, + uint8_t miscBuf, + uint16_t argument, + uint8_t * data_p, + CyAsSdioCallback callback ) +{ + if (callback==0) + return CyAsSdioExtendedIO(handle,bus,device,nFunctionNo,address,miscBuf,argument,CyTrue,data_p,0); + + return CyAsSdioExtendedIOAsync(handle,bus,device,nFunctionNo,address,miscBuf,argument,CyTrue,data_p,callback); +} + + +/* Read the CIS info tuples for the given function and Tuple ID*/ +CyAsReturnStatus_t +CyAsSdioGetCISInfo( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint16_t tupleId, + uint8_t * data_p ) +{ + + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint16_t resp_data; + CyAsContext *ctxt_p ; + uint32_t loopcount = 200; + + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(!( CyAsSdioCheckFunctionInitialized(handle,bus,0) )) + return CY_AS_ERROR_INVALID_FUNCTION; + + if ((CyAsDeviceIsStorageAsyncPending(dev_p)) || (dev_p->storage_wait)) + return CY_AS_ERROR_ASYNC_PENDING ; + + + /* Initialise the request to send to the Antioch. */ + req_p = dev_p->storage_rw_req_p ; + CyAsLLInitRequest(req_p, CY_RQT_SDIO_GET_TUPLE, CY_RQT_STORAGE_RQT_CONTEXT, 2) ; + + /* Initialise the space for reply from the Antioch. */ + reply_p = dev_p->storage_rw_resp_p ; + CyAsLLInitResponse(reply_p, 3) ; + + /* Setup the DMA request */ + ret = CyAsDmaQueueRequest(dev_p, dev_p->storage_read_endpoint, data_p+1, 255, CyFalse, CyTrue, + CyAsSyncStorageCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + { + return ret ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, nFunctionNo )) ; + + /* Set tuple id to fetch. */ + CyAsLLRequestResponse_SetWord(req_p, 1, tupleId<<8) ; + + /* Send the request and wait for completion of storage request */ + dev_p->storage_wait = CyTrue ; + ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyTrue, CyAsSdioSyncReplyCallback) ; + + + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsDmaCancel(dev_p, dev_p->storage_read_endpoint, CY_AS_ERROR_CANCELED) ; + } + else + { + /* Setup the DMA request */ + ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT] ; + ret = CyAsDmaDrainQueue(dev_p, dev_p->storage_read_endpoint, CyTrue) ; + + while (loopcount-- > 0) + { + if (dev_p->storage_wait == CyFalse) + break; + CyAsHalSleepOn(&ctxt_p->channel, 10) ; + } + + if (dev_p->storage_wait == CyTrue) + { + dev_p->storage_wait = CyFalse ; + CyAsLLRemoveRequest(dev_p, ctxt_p, req_p, CyTrue) ; + return CY_AS_ERROR_TIMEOUT ; + } + ret = dev_p->storage_error ; + + if (ret != CY_AS_ERROR_SUCCESS) + { + return ret ; + } + + if ( CyAsLLRequestResponse_GetCode(dev_p->storage_rw_resp_p) == CY_RESP_SDIO_GET_TUPLE) + { + resp_data = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + if(resp_data) + { + ret = CY_AS_ERROR_INVALID_REQUEST ; + } + else if (data_p!=0) + *(uint8_t*)data_p=(uint8_t)(CyAsLLRequestResponse_GetWord(reply_p, 0)&0x00ff); + } + else + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + } + return ret; +} + +/*Query Device*/ +CyAsReturnStatus_t +CyAsSdioQueryCard( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + CyAsSDIOCard* data_p ) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + uint8_t resp_type; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + /* Allocating memory to the SDIO device structure in dev_p */ + + CyAsHalMemSet(& dev_p->sdiocard[bus],0,sizeof(CyAsSDIODevice)); + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SDIO_QUERY_CARD, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, 0 )) ; + + reply_p = CyAsLLCreateResponse(dev_p, 5) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + resp_type = CyAsLLRequestResponse_GetCode(reply_p); + if ( resp_type == CY_RESP_SDIO_QUERY_CARD) + { + dev_p->sdiocard[bus].card.num_functions = (uint8_t)((reply_p->data[0]&0xff00)>>8); + dev_p->sdiocard[bus].card.memory_present = (uint8_t)reply_p->data[0]&0x0001; + dev_p->sdiocard[bus].card.manufacturer_Id = reply_p->data[1]; + dev_p->sdiocard[bus].card.manufacturer_info = reply_p->data[2]; + dev_p->sdiocard[bus].card.blocksize = reply_p->data[3]; + dev_p->sdiocard[bus].card.maxblocksize = reply_p->data[3]; + dev_p->sdiocard[bus].card.card_capability = (uint8_t)((reply_p->data[4]&0xff00)>>8); + dev_p->sdiocard[bus].card.sdio_version = (uint8_t)(reply_p->data[4]&0x00ff); + dev_p->sdiocard[bus].function_init_map = 0x01; + data_p->num_functions = dev_p->sdiocard[bus].card.num_functions; + data_p->memory_present = dev_p->sdiocard[bus].card.memory_present; + data_p->manufacturer_Id = dev_p->sdiocard[bus].card.manufacturer_Id; + data_p->manufacturer_info = dev_p->sdiocard[bus].card.manufacturer_info; + data_p->blocksize = dev_p->sdiocard[bus].card.blocksize; + data_p->maxblocksize = dev_p->sdiocard[bus].card.maxblocksize; + data_p->card_capability = dev_p->sdiocard[bus].card.card_capability; + data_p->sdio_version = dev_p->sdiocard[bus].card.sdio_version; + } + else + { + if (resp_type == CY_RESP_SUCCESS_FAILURE) + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + else + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } +destroy: + if(req_p!=0) + CyAsLLDestroyRequest(dev_p, req_p) ; + if(reply_p!=0) + CyAsLLDestroyResponse(dev_p, reply_p) ; + return ret ; +} + +/*Reset SDIO card. */ +CyAsReturnStatus_t +CyAsSdioResetCard( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device ) +{ + + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t resp_type; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(dev_p->sdiocard != 0) + { + dev_p->sdiocard[bus].function_init_map=0; + dev_p->sdiocard[bus].function_suspended_map = 0; + } + + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SDIO_RESET_DEV, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + /*Setup mailbox */ + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, 0) ) ; + + reply_p = CyAsLLCreateResponse(dev_p, 2) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + + resp_type = CyAsLLRequestResponse_GetCode(reply_p) ; + + + if (resp_type == CY_RESP_SUCCESS_FAILURE) + { + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + if(ret == CY_AS_ERROR_SUCCESS) + { + ret = CyAsSdioQueryCard(handle,bus,device,0); + } + } + else + ret = CY_AS_ERROR_INVALID_RESPONSE ; + +destroy: + if(req_p!=0) + CyAsLLDestroyRequest(dev_p, req_p) ; + if(reply_p!=0) + CyAsLLDestroyResponse(dev_p, reply_p) ; + return ret ; +} + +/* Initialise an IO function*/ +CyAsReturnStatus_t +CyAsSdioInitFunction( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint8_t miscBuf ) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t resp_type; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,0))) + return CY_AS_ERROR_NOT_RUNNING; + + if((CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + { + if(miscBuf&CY_SDIO_FORCE_INIT) + dev_p->sdiocard[bus].function_init_map&=(~(1<sdiocard[bus].function[nFunctionNo-1].function_code = (uint8_t)((reply_p->data[0]&0xff00)>>8); + dev_p->sdiocard[bus].function[nFunctionNo-1].extended_func_code = (uint8_t)reply_p->data[0]&0x00ff; + dev_p->sdiocard[bus].function[nFunctionNo-1].blocksize = reply_p->data[1]; + dev_p->sdiocard[bus].function[nFunctionNo-1].maxblocksize = reply_p->data[1]; + dev_p->sdiocard[bus].function[nFunctionNo-1].card_psn = (uint32_t)(reply_p->data[2])<<16; + dev_p->sdiocard[bus].function[nFunctionNo-1].card_psn |=(uint32_t)(reply_p->data[3]); + dev_p->sdiocard[bus].function[nFunctionNo-1].csa_bits = (uint8_t)((reply_p->data[4]&0xff00)>>8); + dev_p->sdiocard[bus].function[nFunctionNo-1].wakeup_support = (uint8_t)(reply_p->data[4]&0x0001); + dev_p->sdiocard[bus].function_init_map |= (1<blocksize = dev_p->sdiocard[bus].function[nFunctionNo-1].blocksize; + data_p->card_psn = dev_p->sdiocard[bus].function[nFunctionNo-1].card_psn; + data_p->csa_bits = dev_p->sdiocard[bus].function[nFunctionNo-1].csa_bits; + data_p->extended_func_code = dev_p->sdiocard[bus].function[nFunctionNo-1].extended_func_code; + data_p->function_code = dev_p->sdiocard[bus].function[nFunctionNo-1].function_code; + data_p->maxblocksize = dev_p->sdiocard[bus].function[nFunctionNo-1].maxblocksize; + data_p->wakeup_support = dev_p->sdiocard[bus].function[nFunctionNo-1].wakeup_support; + + + return CY_AS_ERROR_SUCCESS; +} + +/* Abort the Current Extended IO Operation*/ +CyAsReturnStatus_t +CyAsSdioAbortFunction( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t resp_type; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + return CY_AS_ERROR_INVALID_FUNCTION; + + if ((CyAsDeviceIsStorageAsyncPending(dev_p)) || (dev_p->storage_wait)) + { + if(!(CyAsSdioGetCardCapability(handle,bus) & CY_SDIO_SDC )) + { + return CY_AS_ERROR_INVALID_COMMAND; + } + } + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SDIO_ABORT_IO, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + /*Setup mailbox */ + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, nFunctionNo) ) ; + + reply_p = CyAsLLCreateResponse(dev_p, 2) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + resp_type = CyAsLLRequestResponse_GetCode(reply_p) ; + + if (resp_type == CY_RESP_SUCCESS_FAILURE) + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + else + ret = CY_AS_ERROR_INVALID_RESPONSE ; + + +destroy: + if(req_p!=0) + CyAsLLDestroyRequest(dev_p, req_p) ; + if(reply_p!=0) + CyAsLLDestroyResponse(dev_p, reply_p) ; + return ret ; +} + +/* Suspend IO to current function*/ +CyAsReturnStatus_t +CyAsSdioSuspend( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + return CY_AS_ERROR_INVALID_FUNCTION; + if(!(CyAsSdioCheckSupportBusSuspend(handle,bus))) + return CY_AS_ERROR_INVALID_FUNCTION; + if(!(CyAsSdioGetCardCapability(handle,bus) & CY_SDIO_SDC)) + return CY_AS_ERROR_INVALID_FUNCTION; + if(CyAsSdioCheckFunctionSuspended(handle,bus,nFunctionNo)) + return CY_AS_ERROR_FUNCTION_SUSPENDED; + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SDIO_SUSPEND, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + /*Setup mailbox */ + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, nFunctionNo) ) ; + + reply_p = CyAsLLCreateResponse(dev_p, 2) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + + if (ret == CY_AS_ERROR_SUCCESS) + { + ret = CyAsLLRequestResponse_GetCode(reply_p) ; + CyAsSdioSetFunctionSuspended(handle,bus,nFunctionNo); + } + + if(req_p!=0) + CyAsLLDestroyRequest(dev_p, req_p) ; + if(reply_p!=0) + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +/*Resume suspended function*/ +CyAsReturnStatus_t +CyAsSdioResume( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + CyAsOperType op, + uint8_t miscBuf, + uint16_t pendingblockcount, + uint8_t *data_p + ) +{ + CyAsLLRequestResponse *req_p , *reply_p ; + CyAsReturnStatus_t resp_data, ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + return CY_AS_ERROR_INVALID_FUNCTION; + + /* If suspend resume is not supported return */ + if(!(CyAsSdioCheckSupportBusSuspend(handle,bus))) + return CY_AS_ERROR_INVALID_FUNCTION; + + /* if the function is not suspended return. */ + if(!(CyAsSdioCheckFunctionSuspended(handle,bus,nFunctionNo))) + return CY_AS_ERROR_INVALID_FUNCTION; + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SDIO_RESUME, CY_RQT_STORAGE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + /*Setup mailbox */ + CyAsLLRequestResponse_SetWord(req_p, 0, CreateAddress(bus, (uint8_t)device, nFunctionNo) ) ; + + reply_p = CyAsLLCreateResponse(dev_p, 2) ; + if (reply_p == 0) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + + if ( CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_SDIO_RESUME) + { + resp_data = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + if(resp_data & 0x00ff) + { + /* Send extended read request to resume the read. */ + if(op == CyAsOpRead) + { + ret = CyAsSdioExtendedIO(handle,bus,device,nFunctionNo,0,miscBuf,pendingblockcount,CyFalse,data_p,1); + } + else + { + ret = CyAsSdioExtendedIO(handle,bus,device,nFunctionNo,0,miscBuf,pendingblockcount,CyTrue,data_p,1); + } + } + else + { + ret= CY_AS_ERROR_SUCCESS; + } + + } + else + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + +destroy: + CyAsSdioClearFunctionSuspended(handle,bus,nFunctionNo); + if(req_p!=0) + CyAsLLDestroyRequest(dev_p, req_p) ; + if(reply_p!=0) + CyAsLLDestroyResponse(dev_p, reply_p) ; + return ret ; + +} + +/*Set function blocksize. Size cannot exceed max block size for the function*/ +CyAsReturnStatus_t +CyAsSdioSetBlocksize( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo, + uint16_t blocksize) +{ + CyAsReturnStatus_t ret; + CyAsDevice *dev_p = (CyAsDevice *)handle ; + ret = CyAsSdioDeviceCheck(dev_p,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + return CY_AS_ERROR_INVALID_FUNCTION; + if( nFunctionNo == 0) + { + if ( blocksize > CyAsSdioGetCardMaxBlocksize(handle,bus)) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + else if (blocksize == CyAsSdioGetCardBlocksize(handle,bus)) + return CY_AS_ERROR_SUCCESS; + } + else + { + if ( blocksize > CyAsSdioGetFunctionMaxBlocksize(handle,bus,nFunctionNo)) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + else if (blocksize == CyAsSdioGetFunctionBlocksize(handle,bus,nFunctionNo)) + return CY_AS_ERROR_SUCCESS; + } + + ret = CyAsSdioDirectWrite(handle,bus,device,0,(uint16_t)(nFunctionNo<<8)|0x10,0,blocksize&0x00ff,0); + if(ret != CY_AS_ERROR_SUCCESS ) + return ret; + ret = CyAsSdioDirectWrite(handle,bus,device,0,(uint16_t)(nFunctionNo<<8)|0x11,0,(blocksize&0xff00)>>8,0); + if (ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(nFunctionNo ==0) + CyAsSdioSetCardBlockSize(handle,bus,blocksize); + else + CyAsSdioSetFunctionBlockSize(handle,bus,nFunctionNo,blocksize); + return ret; +} + +/* Deinitialize an SDIO function*/ +CyAsReturnStatus_t +CyAsSdioDeInitFunction( + CyAsDeviceHandle handle, + CyAsBusNumber_t bus, + uint32_t device, + uint8_t nFunctionNo) +{ + CyAsReturnStatus_t ret; + uint8_t temp; + + if(nFunctionNo == 0) + return CY_AS_ERROR_INVALID_FUNCTION; + + ret = CyAsSdioDeviceCheck((CyAsDevice*)handle,bus,device); + if( ret != CY_AS_ERROR_SUCCESS ) + return ret; + + if(!(CyAsSdioCheckFunctionInitialized(handle,bus,nFunctionNo))) + return CY_AS_ERROR_SUCCESS; + + temp =(uint8_t)(((CyAsDevice*)handle)->sdiocard[bus].function_init_map & (~(1<sdiocard[bus].function_init_map &= (~(1<