omap3530/beagle_drivers/wb/api/src/cyasmtp.c
author arunabha
Thu, 16 Sep 2010 14:35:26 +0100
changeset 70 ed23a53a5ee2
parent 23 117faf51deac
permissions -rw-r--r--
Fixing issues in base_beagle.iby which had references to DEBUG_DIR

/* 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
##
##     <install>/license/license.txt
##
##  where <install> 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 ;
}