diff -r b7e488c49d0d -r 117faf51deac omap3530/beagle_drivers/wb/api/src/cyasmtp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omap3530/beagle_drivers/wb/api/src/cyasmtp.c Wed Mar 03 13:10:32 2010 +0000 @@ -0,0 +1,1073 @@ +/* Cypress West Bridge API header file (cyasmtp.h) +## =========================== +## +## 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. +## +## =========================== +*/ + +#include "cyashal.h" +#include "cyasmtp.h" +#include "cyaserr.h" +#include "cyasdma.h" +#include "cyaslowlevel.h" + +static void +CyAsMTPFuncCallback(CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t stat) ; + +static CyAsReturnStatus_t +IsMTPActive(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->mtp_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 +MyMtpRequestCallback(CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *resp_p, + CyAsReturnStatus_t ret) +{ + uint16_t val, ev, status ; + uint16_t mtp_datalen = 0 ; + uint32_t bytecount_l, bytecount_h ; + CyAsMTPSendObjectCompleteData sendObjData ; + CyAsMTPGetObjectCompleteData getObjData ; + CyAsDmaEndPoint *ep_p ; + + uint8_t code = CyAsLLRequestResponse_GetCode(req_p) ; + + (void)resp_p ; + (void)context ; + (void)ret ; + + switch(code) + { + case CY_RQT_MTP_EVENT: + val = CyAsLLRequestResponse_GetWord(req_p, 0) ; + status = (val >> 8) & 0xFF ; /* MSB indicates status of read/write */ + ev = val & 0xFF ; /* event type */ + switch(ev) + { + case 0: /* SendObject Complete */ + { + bytecount_l = CyAsLLRequestResponse_GetWord(req_p, 1) ; + bytecount_h = CyAsLLRequestResponse_GetWord(req_p, 2) ; + sendObjData.byte_count = (bytecount_h << 16) | bytecount_l ; + + sendObjData.status = status ; + + /* use the byte count again */ + bytecount_l = CyAsLLRequestResponse_GetWord(req_p, 3) ; + bytecount_h = CyAsLLRequestResponse_GetWord(req_p, 4) ; + sendObjData.transaction_id = (bytecount_h << 16) | bytecount_l ; + + dev_p->mtp_turbo_active = CyFalse ; + + if (dev_p->mtp_event_cb) + dev_p->mtp_event_cb((CyAsDeviceHandle)dev_p, CyAsMTPSendObjectComplete, + &sendObjData) ; + } + break ; + + case 1: /* GetObject Complete */ + { + bytecount_l = CyAsLLRequestResponse_GetWord(req_p, 1) ; + bytecount_h = CyAsLLRequestResponse_GetWord(req_p, 2) ; + + getObjData.byte_count = (bytecount_h << 16) | bytecount_l ; + getObjData.status = status ; + + dev_p->mtp_turbo_active = CyFalse ; + + if (dev_p->mtp_event_cb) + dev_p->mtp_event_cb((CyAsDeviceHandle)dev_p, CyAsMTPGetObjectComplete, + &getObjData); + } + break ; + + case 2: /* BlockTable Needed */ + { + if (dev_p->mtp_event_cb) + dev_p->mtp_event_cb((CyAsDeviceHandle)dev_p, CyAsMTPBlockTableNeeded, 0); + } + break ; + default: + CyAsHalPrintMessage("Invalid event type\n") ; + CyAsLLSendDataResponse(dev_p, CY_RQT_TUR_RQT_CONTEXT, CY_RESP_MTP_INVALID_EVENT, sizeof(ev), &ev) ; + break ; + } + break ; + + case CY_RQT_TURBO_CMD_FROM_HOST: + { + mtp_datalen = CyAsLLRequestResponse_GetWord(req_p, 1) ; + + /* Get the endpoint pointer based on the endpoint number */ + ep_p = CY_AS_NUM_EP(dev_p, CY_AS_MTP_READ_ENDPOINT) ; + + /* The event should arrive only after the DMA operation has been queued. */ + CyAsHalAssert(ep_p->queue_p != 0) ; + + /* Put the len in ep data information in dmaqueue and kick start the queue */ + CyAsHalAssert(ep_p->queue_p->size >= mtp_datalen) ; + + if (mtp_datalen == 0) + { + CyAsDmaCompletedCallback(dev_p->tag, CY_AS_MTP_READ_ENDPOINT, 0, CY_AS_ERROR_SUCCESS) ; + } + else + { + ep_p->maxhwdata = mtp_datalen ; + + /* + * Make sure that the DMA status for this EP is not running, so that + * the call to CyAsDmaKickStart gets this transfer going. + * Note: In MTP mode, we never leave a DMA transfer of greater than one + * packet running. So, it is okay to override the status here and start + * the next packet transfer. + */ + CyAsDmaEndPointSetStopped(ep_p) ; + + /* Kick start the queue if it is not running */ + CyAsDmaKickStart(dev_p, CY_AS_MTP_READ_ENDPOINT) ; + } + } + break ; + + case CY_RQT_TURBO_START_WRITE_DMA: + { + /* + * Now that the firmware is ready to receive the next packet of data, start + * the corresponding DMA transfer. First, ensure that a DMA operation is still + * pending in the queue for the write endpoint. + */ + CyAsLLSendStatusResponse(dev_p, CY_RQT_TUR_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; + + ep_p = CY_AS_NUM_EP(dev_p, CY_AS_MTP_WRITE_ENDPOINT) ; + CyAsHalAssert (ep_p->queue_p != 0) ; + + CyAsDmaEndPointSetStopped(ep_p) ; + CyAsDmaKickStart(dev_p, CY_AS_MTP_WRITE_ENDPOINT) ; + } + break ; + + default: + CyAsHalPrintMessage("Invalid request received on TUR context\n") ; + val = req_p->box0 ; + CyAsLLSendDataResponse(dev_p, CY_RQT_TUR_RQT_CONTEXT, CY_RESP_INVALID_REQUEST, sizeof(val), &val) ; + break ; + } +} + +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 +MyHandleResponseMTPStart(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 (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + dev_p->mtp_count++ ; + + CyAsDmaEnableEndPoint(dev_p, CY_AS_MTP_READ_ENDPOINT, CyTrue, CyAsDirectionOut) ; + dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].enabled = CyTrue ; + dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].dir = CyAsUsbOut ; + dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].type = CyAsUsbBulk ; + + CyAsDmaEnableEndPoint(dev_p, CY_AS_MTP_WRITE_ENDPOINT, CyTrue, CyAsDirectionIn) ; + dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].enabled = CyTrue ; + dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].dir = CyAsUsbIn ; + dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].type = CyAsUsbBulk ; + + CyAsDmaSetMaxDmaSize(dev_p, 0x02, 0x0200) ; /* Packet size is 512 bytes */ + CyAsDmaSetMaxDmaSize(dev_p, 0x06, 0x40) ; /* Packet size is 64 bytes until a switch to high speed happens. */ + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + if (ret != CY_AS_ERROR_SUCCESS) + CyAsLLRegisterRequestCallback(dev_p, CY_RQT_TUR_RQT_CONTEXT, 0) ; + + CyAsDeviceClearMSSPending(dev_p) ; + + return ret ; +} + + +CyAsReturnStatus_t +CyAsMTPStart(CyAsDeviceHandle handle, + CyAsMTPEventCallback eventCB, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice* dev_p ; + + 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 (CyAsDeviceIsInCallback(dev_p)) + return CY_AS_ERROR_INVALID_IN_CALLBACK ; + + if(CyAsDeviceIsMSSPending(dev_p)) + return CY_AS_ERROR_STARTSTOP_PENDING ; + + if (dev_p->storage_count == 0) + return CY_AS_ERROR_NOT_RUNNING ; + + if (dev_p->usb_count == 0) + return CY_AS_ERROR_NOT_RUNNING ; + + if (dev_p->is_mtp_firmware == 0) + return CY_AS_ERROR_NOT_SUPPORTED ; + + CyAsDeviceSetMSSPending(dev_p) ; + + if (dev_p->mtp_count == 0) + { + + dev_p->mtp_event_cb = eventCB ; + /* + * We register here becuase the start request may cause events to occur before the + * response to the start request. + */ + CyAsLLRegisterRequestCallback(dev_p, CY_RQT_TUR_RQT_CONTEXT, MyMtpRequestCallback) ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_START_MTP, CY_RQT_TUR_RQT_CONTEXT, 0) ; + if (req_p == 0) + { + CyAsDeviceClearMSSPending(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) + { + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsDeviceClearMSSPending(dev_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 MyHandleResponseMTPStart(dev_p, req_p, reply_p, ret) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MTP_START, + 0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMTPFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + } + else + { + dev_p->mtp_count++ ; + if (cb) + cb(handle, ret, client, CY_FUNCT_CB_MTP_START, 0) ; + } + + CyAsDeviceClearMSSPending(dev_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyHandleResponseMTPStop(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 (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* + * We sucessfully shutdown the stack, so decrement to make the count + * zero. + */ + dev_p->mtp_count-- ; + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + if (ret != CY_AS_ERROR_SUCCESS) + CyAsLLRegisterRequestCallback(dev_p, CY_RQT_TUR_RQT_CONTEXT, 0) ; + + CyAsDeviceClearMSSPending(dev_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMTPStop(CyAsDeviceHandle handle, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsLLRequestResponse *req_p = 0, *reply_p = 0 ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + CyAsDevice*dev_p ; + + CyAsLogDebugMessage(6, "CyAsMTPStop called") ; + + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + ret = IsMTPActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (CyAsDeviceIsInCallback(dev_p)) + return CY_AS_ERROR_INVALID_IN_CALLBACK ; + + if(CyAsDeviceIsMSSPending(dev_p)) + return CY_AS_ERROR_STARTSTOP_PENDING ; + + CyAsDeviceSetMSSPending(dev_p) ; + + if (dev_p->mtp_count == 1) + { + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_STOP_MTP, CY_RQT_TUR_RQT_CONTEXT, 0) ; + if (req_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + goto destroy ; + } + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + goto destroy ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseMTPStop(dev_p, req_p, reply_p, ret) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MTP_STOP, + 0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMTPFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + } + else if (dev_p->mtp_count > 1) + { + + dev_p->mtp_count-- ; + + if (cb) + cb(handle, ret, client, CY_FUNCT_CB_MTP_STOP, 0) ; + } + + CyAsDeviceClearMSSPending(dev_p) ; + + return ret ; +} + +static void +MtpWriteCallback( + CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t ret) +{ + CyAsHalAssert(context == CY_RQT_TUR_RQT_CONTEXT) ; + + if (ret == CY_AS_ERROR_SUCCESS) + { + if (CyAsLLRequestResponse_GetCode(resp) != CY_RESP_SUCCESS_FAILURE) + ret = CY_AS_ERROR_INVALID_RESPONSE ; + else + ret = CyAsLLRequestResponse_GetWord(resp, 0) ; + } + + if (ret != CY_AS_ERROR_SUCCESS) + { + /* Firmware failed the request. Cancel the DMA transfer. */ + CyAsDmaCancel(dev_p, 0x04, CY_AS_ERROR_CANCELED) ; + CyAsDeviceClearStorageAsyncPending(dev_p) ; + } + + CyAsLLDestroyResponse(dev_p, resp) ; + CyAsLLDestroyRequest(dev_p, rqt) ; +} + +static void +AsyncWriteRequestCallback(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, void *buf_p, uint32_t size, CyAsReturnStatus_t err) +{ + CyAsDeviceHandle h ; + CyAsFunctionCallback cb ; + + (void)size ; + (void)buf_p ; + (void)ep ; + + + CyAsLogDebugMessage(6, "AsyncWriteRequestCallback called") ; + + h = (CyAsDeviceHandle)dev_p ; + + cb = dev_p->mtp_cb ; + dev_p->mtp_cb = 0 ; + + CyAsDeviceClearStorageAsyncPending(dev_p) ; + + if (cb) + cb(h, err, dev_p->mtp_client, dev_p->mtp_op, 0) ; + +} + +static void +SyncMTPCallback(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, void *buf_p, uint32_t size, CyAsReturnStatus_t err) +{ + (void)ep ; + (void)buf_p ; + (void)size ; + + dev_p->mtp_error = err ; +} + +static CyAsReturnStatus_t +CyAsMTPOperation(CyAsDevice *dev_p, + CyAsMTPBlockTable* blk_table, + uint32_t num_bytes, + uint32_t transaction_id, + CyAsFunctionCallback cb, + uint32_t client, + uint8_t rqttype + ) +{ + CyAsLLRequestResponse *req_p = 0, *reply_p = 0 ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint32_t mask = 0 ; + CyAsFunctCBType mtp_cb_op = (CyAsFunctCBType)0 ; + uint16_t size = 2 ; + + if(dev_p->mtp_count == 0) + return CY_AS_ERROR_NOT_RUNNING ; + + if (rqttype == CY_RQT_INIT_SEND_OBJECT) + { + mtp_cb_op = CY_FUNCT_CB_MTP_INIT_SEND_OBJECT ; + dev_p->mtp_turbo_active = CyTrue ; + } + else if (rqttype == CY_RQT_INIT_GET_OBJECT) + { + mtp_cb_op = CY_FUNCT_CB_MTP_INIT_GET_OBJECT ; + dev_p->mtp_turbo_active = CyTrue ; + } + else + mtp_cb_op = CY_FUNCT_CB_MTP_SEND_BLOCK_TABLE ; + + ret = IsMTPActive(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (CY_RQT_INIT_GET_OBJECT == rqttype) + { + size = 4 ; + } + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, rqttype, CY_RQT_TUR_RQT_CONTEXT, size) ; + if (req_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + goto destroy ; + } + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + goto destroy ; + } + + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)(num_bytes & 0xFFFF)) ; + CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((num_bytes >> 16) & 0xFFFF)) ; + + /* If it is GET_OBJECT, send transaction id as well */ + if (CY_RQT_INIT_GET_OBJECT == rqttype) + { + CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)(transaction_id & 0xFFFF)) ; + CyAsLLRequestResponse_SetWord(req_p, 3, (uint16_t)((transaction_id >> 16) & 0xFFFF)) ; + } + + if(cb == 0) + { + /* Queue the DMA request for block table write */ + ret = CyAsDmaQueueRequest(dev_p, 4, blk_table, sizeof(CyAsMTPBlockTable), CyFalse, CyFalse, SyncMTPCallback) ; + + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsDmaCancel(dev_p, 4, CY_AS_ERROR_CANCELED) ; + CyAsDeviceClearStorageAsyncPending(dev_p) ; + + goto destroy ; + } + + ret = CyAsDmaDrainQueue(dev_p, 4, CyTrue) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + ret = dev_p->mtp_error ; + goto destroy ; + } + else + { +#if 0 + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MTP_INIT_SEND_OBJECT, + 0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMTPFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; +#endif + + /* Protection from interrupt driven code */ + /* since we are using storage EP4 check if any storage activity is pending */ + mask = CyAsHalDisableInterrupts() ; + if ((CyAsDeviceIsStorageAsyncPending(dev_p)) || (dev_p->storage_wait)) + { + CyAsHalEnableInterrupts(mask) ; + return CY_AS_ERROR_ASYNC_PENDING ; + } + CyAsDeviceSetStorageAsyncPending(dev_p) ; + CyAsHalEnableInterrupts(mask) ; + + dev_p->mtp_cb = cb ; + dev_p->mtp_client = client ; + dev_p->mtp_op = mtp_cb_op ; + + ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyFalse, MtpWriteCallback) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + ret = CyAsDmaQueueRequest(dev_p, 4, blk_table, sizeof(CyAsMTPBlockTable), CyFalse, CyFalse, AsyncWriteRequestCallback) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* Kick start the queue if it is not running */ + CyAsDmaKickStart(dev_p, 4) ; + + return CY_AS_ERROR_SUCCESS ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMTPInitSendObject(CyAsDeviceHandle handle, + CyAsMTPBlockTable* blk_table, + uint32_t num_bytes, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsDevice* dev_p ; + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + return CyAsMTPOperation(dev_p, blk_table, num_bytes, 0, cb, client, CY_RQT_INIT_SEND_OBJECT) ; + +} + +CyAsReturnStatus_t +CyAsMTPInitGetObject(CyAsDeviceHandle handle, + CyAsMTPBlockTable* blk_table, + uint32_t num_bytes, + uint32_t transaction_id, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsDevice* dev_p ; + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + return CyAsMTPOperation(dev_p, blk_table, num_bytes, transaction_id, cb, client, CY_RQT_INIT_GET_OBJECT) ; + +} + +static CyAsReturnStatus_t +MyHandleResponseCancelSendObject(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 (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMTPCancelSendObject(CyAsDeviceHandle handle, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsLLRequestResponse *req_p = 0, *reply_p = 0 ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice*dev_p ; + + 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_count == 0) + return CY_AS_ERROR_NOT_RUNNING ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_CANCEL_SEND_OBJECT, CY_RQT_TUR_RQT_CONTEXT, 0) ; + if (req_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + goto destroy ; + } + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + goto destroy ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseCancelSendObject(dev_p, req_p, reply_p, ret) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MTP_CANCEL_SEND_OBJECT, + 0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMTPFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return ret ; + } + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyHandleResponseCancelGetObject(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 (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMTPCancelGetObject(CyAsDeviceHandle handle, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsLLRequestResponse *req_p = 0, *reply_p = 0 ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsDevice*dev_p ; + + 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_count == 0) + return CY_AS_ERROR_NOT_RUNNING ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_CANCEL_GET_OBJECT, CY_RQT_TUR_RQT_CONTEXT, 0) ; + if (req_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + goto destroy ; + } + + /* Reserve space for the reply, the reply data will not exceed one word */ + reply_p = CyAsLLCreateResponse(dev_p, 1) ; + if (reply_p == 0) + { + ret = CY_AS_ERROR_OUT_OF_MEMORY ; + goto destroy ; + } + + if(cb == 0) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return MyHandleResponseCancelGetObject(dev_p, req_p, reply_p, ret) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MTP_CANCEL_GET_OBJECT, + 0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMTPFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMTPSendBlockTable(CyAsDeviceHandle handle, + CyAsMTPBlockTable* blk_table, + CyAsFunctionCallback cb, + uint32_t client + ) +{ + CyAsDevice* dev_p ; + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + return CyAsMTPOperation(dev_p, blk_table, 0, 0, cb, client, CY_RQT_SEND_BLOCK_TABLE) ; +} + +static void +CyAsMTPFuncCallback(CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t stat) +{ + CyAsFuncCBNode* node = (CyAsFuncCBNode*)dev_p->func_cbs_mtp->head_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint8_t code ; + CyBool delay_callback = CyFalse ; + + CyAsHalAssert(dev_p->func_cbs_mtp->count != 0) ; + CyAsHalAssert(dev_p->func_cbs_mtp->type == CYAS_FUNC_CB) ; + + (void)context ; + + /* The Handlers are responsible for Deleting the rqt and resp when + * they are finished + */ + code = CyAsLLRequestResponse_GetCode(rqt) ; + switch(code) + { + case CY_RQT_START_MTP: + ret = MyHandleResponseMTPStart(dev_p, rqt, resp, stat) ; + break ; + case CY_RQT_STOP_MTP: + ret = MyHandleResponseMTPStop(dev_p, rqt, resp, stat) ; + break ; +#if 0 + case CY_RQT_INIT_SEND_OBJECT: + ret = MyHandleResponseInitSendObject(dev_p, rqt, resp, stat, CyTrue) ; + delay_callback = CyTrue ; + break ; +#endif + case CY_RQT_CANCEL_SEND_OBJECT: + ret = MyHandleResponseCancelSendObject(dev_p, rqt, resp, stat) ; + break ; +#if 0 + case CY_RQT_INIT_GET_OBJECT: + ret = MyHandleResponseInitGetObject(dev_p, rqt, resp, stat, CyTrue) ; + delay_callback = CyTrue ; + break ; +#endif + case CY_RQT_CANCEL_GET_OBJECT: + ret = MyHandleResponseCancelGetObject(dev_p, rqt, resp, stat) ; + break ; +#if 0 + case CY_RQT_SEND_BLOCK_TABLE: + ret = MyHandleResponseSendBlockTable(dev_p, rqt, resp, stat, CyTrue) ; + delay_callback = CyTrue ; + break ; +#endif + case CY_RQT_ENABLE_USB_PATH: + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + if (ret == CY_AS_ERROR_SUCCESS) + dev_p->is_storage_only_mode = CyFalse ; + 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 ; + + if(!delay_callback) + { + node->cb_p((CyAsDeviceHandle)dev_p, stat, node->client_data, (CyAsFunctCBType)node->dataType, node->data) ; + CyAsRemoveCBNode(dev_p->func_cbs_mtp) ; + } +} + +CyAsReturnStatus_t +CyAsMTPStorageOnlyStart(CyAsDeviceHandle handle) +{ + 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->is_storage_only_mode = CyTrue ; + return CY_AS_ERROR_SUCCESS ; +} + +CyAsReturnStatus_t +CyAsMTPStorageOnlyStop(CyAsDeviceHandle handle, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p = (CyAsDevice *)handle ; + 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 ; + + 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 (dev_p->is_storage_only_mode == CyFalse) + return CY_AS_ERROR_SUCCESS ; + + if (CyAsDeviceIsInCallback(dev_p)) + return CY_AS_ERROR_INVALID_IN_CALLBACK ; + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_ENABLE_USB_PATH, CY_RQT_TUR_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 ; + } + + 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 (ret == CY_AS_ERROR_SUCCESS) + dev_p->is_storage_only_mode = CyFalse ; + return ret ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MTP_STOP_STORAGE_ONLY, + 0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMTPFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return ret ; + } + +destroy: + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +}