diff -r b7e488c49d0d -r 117faf51deac omap3530/beagle_drivers/wb/api/src/cyasmisc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omap3530/beagle_drivers/wb/api/src/cyasmisc.c Wed Mar 03 13:10:32 2010 +0000 @@ -0,0 +1,3359 @@ +/* Cypress West Bridge API source file (cyasmisc.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. +## +## =========================== +*/ + +#include "cyashal.h" +#include "cyasmisc.h" +#include "cyasdma.h" +#include "cyasintr.h" +#include "cyaserr.h" +#include "cyasregs.h" +#include "cyaslowlevel.h" +#include "cyasprotocol.h" + +/* +* The device list, the only global in the API +*/ +static CyAsDevice *gDeviceList = 0 ; + +/* + * The current debug level + */ +static uint8_t DebugLevel = 0 ; + +/* + * This function sets the debug level for the API + * + */ +void +CyAsMiscSetLogLevel(uint8_t level) +{ + DebugLevel = level ; +} + +#ifdef CY_AS_LOG_SUPPORT + +/* + * This function is a low level logger for the API. + */ +void +CyAsLogDebugMessage(int level, const char *str) +{ + if (level <= DebugLevel) + CyAsHalPrintMessage("Log %d: %s\n", level, str) ; +} + +#endif + +#define CyAsCheckDeviceReady(dev_p) \ +{ \ + 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 ; \ +} + +/* Find an West Bridge device based on a TAG */ +CyAsDevice * +CyAsDeviceFindFromTag(CyAsHalDeviceTag tag) +{ + CyAsDevice *dev_p ; + + for(dev_p = gDeviceList; dev_p != 0; dev_p = dev_p->next_p) + { + if (dev_p->tag == tag) + return dev_p ; + } + + return 0 ; +} + +/* Map a pre-V1.2 media type to the V1.2+ bus number */ +static void +CyAsBusFromMediaType(CyAsMediaType type, + CyAsBusNumber_t* bus) +{ + if (type == CyAsMediaNand) + { + *bus = 0 ; + } + else + { + *bus = 1 ; + } +} + +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 ; + else + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +/* +* Create a new West Bridge device +*/ +CyAsReturnStatus_t +CyAsMiscCreateDevice(CyAsDeviceHandle *handle_p, CyAsHalDeviceTag tag) +{ + CyAsDevice *dev_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + CyAsLogDebugMessage(6, "CyAsMiscCreateDevice called") ; + + dev_p = (CyAsDevice *)CyAsHalAlloc(sizeof(CyAsDevice)) ; + if (dev_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + CyAsHalMemSet(dev_p, 0, sizeof(CyAsDevice)) ; + + /* + * Dynamically allocating this buffer to ensure that it is + * word aligned. + */ + dev_p->usb_ep_data = (uint8_t *)CyAsHalAlloc(64 * sizeof(uint8_t)) ; + if (dev_p->usb_ep_data == 0) + { + CyAsHalFree(dev_p) ; + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + + dev_p->sig = CY_AS_DEVICE_HANDLE_SIGNATURE ; + dev_p->tag = tag ; + dev_p->usb_max_tx_size = 0x40 ; + + dev_p->storage_write_endpoint = CY_AS_P2S_WRITE_ENDPOINT ; + dev_p->storage_read_endpoint = CY_AS_P2S_READ_ENDPOINT ; + + dev_p->func_cbs_misc = CyAsCreateCBQueue(CYAS_FUNC_CB) ; + if(dev_p->func_cbs_misc == 0) + goto destroy ; + + dev_p->func_cbs_res = CyAsCreateCBQueue(CYAS_FUNC_CB) ; + if(dev_p->func_cbs_res == 0) + goto destroy ; + + dev_p->func_cbs_stor = CyAsCreateCBQueue(CYAS_FUNC_CB) ; + if(dev_p->func_cbs_stor == 0) + goto destroy ; + + dev_p->func_cbs_usb = CyAsCreateCBQueue(CYAS_FUNC_CB) ; + if(dev_p->func_cbs_usb == 0) + goto destroy ; + + dev_p->func_cbs_mtp = CyAsCreateCBQueue(CYAS_FUNC_CB) ; + if(dev_p->func_cbs_mtp == 0) + goto destroy ; + + /* + * Allocate memory for the DMA module here. It is then marked idle, and + * will be activated when CyAsMiscConfigureDevice is called. + */ + ret = CyAsDmaStart(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + CyAsDeviceSetDmaStopped(dev_p) ; + + /* + * Allocate memory for the low level module here. This module is also + * activated only when CyAsMiscConfigureDevice is called. + */ + ret = CyAsLLStart(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + CyAsDeviceSetLowLevelStopped(dev_p) ; + + dev_p->next_p = gDeviceList ; + gDeviceList = dev_p ; + + *handle_p = dev_p ; + CyAsHalInitDevRegisters(tag, CyFalse) ; + return CY_AS_ERROR_SUCCESS ; + +destroy: + /* Free any queues that were successfully allocated. */ + if (dev_p->func_cbs_misc) CyAsDestroyCBQueue(dev_p->func_cbs_misc) ; + if (dev_p->func_cbs_res) CyAsDestroyCBQueue(dev_p->func_cbs_res) ; + if (dev_p->func_cbs_stor) CyAsDestroyCBQueue(dev_p->func_cbs_stor) ; + if (dev_p->func_cbs_usb) CyAsDestroyCBQueue(dev_p->func_cbs_usb) ; + if (dev_p->func_cbs_mtp) CyAsDestroyCBQueue(dev_p->func_cbs_mtp) ; + + CyAsHalFree(dev_p->usb_ep_data) ; + CyAsHalFree(dev_p) ; + + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + else + return CY_AS_ERROR_OUT_OF_MEMORY ; +} + +/* +* Destroy an existing West Bridge device +*/ +CyAsReturnStatus_t +CyAsMiscDestroyDevice(CyAsDeviceHandle handle) +{ + CyAsReturnStatus_t ret ; + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscDestroyDevice called") ; + + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + /* + * If the USB stack is still running, it must be stopped first + */ + if (dev_p->usb_count > 0) + return CY_AS_ERROR_STILL_RUNNING ; + + /* + * If the STORAGE stack is still running, it must be stopped first + */ + if (dev_p->storage_count > 0) + return CY_AS_ERROR_STILL_RUNNING ; + + if(CyAsDeviceIsIntrRunning(dev_p)) + ret = CyAsIntrStop(dev_p) ; + + ret = CyAsLLStop(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsIntrStart(dev_p, dev_p->use_int_drq) ; + return ret ; + } + + ret = CyAsDmaStop(dev_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsIntrStart(dev_p, dev_p->use_int_drq) ; + return ret ; + } + + /* Reset the West Bridge device. */ + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_RST_CTRL_REG, CY_AS_MEM_RST_CTRL_REG_HARD) ; + + /* + * Remove the device from the device list + */ + if (gDeviceList == dev_p) + { + gDeviceList = dev_p->next_p ; + } + else + { + CyAsDevice *tmp_p = gDeviceList ; + while (tmp_p && tmp_p->next_p != dev_p) + tmp_p = tmp_p->next_p ; + + CyAsHalAssert(tmp_p != 0) ; + tmp_p->next_p = dev_p->next_p ; + } + + /* + * Reset the signature so this will not be detected + * as a valid handle + */ + dev_p->sig = 0 ; + + CyAsDestroyCBQueue(dev_p->func_cbs_misc) ; + CyAsDestroyCBQueue(dev_p->func_cbs_res) ; + CyAsDestroyCBQueue(dev_p->func_cbs_stor) ; + CyAsDestroyCBQueue(dev_p->func_cbs_usb) ; + CyAsDestroyCBQueue(dev_p->func_cbs_mtp) ; + + /* + * Free the memory associated with the device + */ + CyAsHalFree(dev_p->usb_ep_data) ; + CyAsHalFree(dev_p) ; + + return CY_AS_ERROR_SUCCESS ; +} + +/* +* Determine the endian mode for the processor we are running on, then +* set the endian mode register +*/ +static void +CyAsSetupEndianMode(CyAsDevice *dev_p) +{ + /* + * BWG: In general, we always set West Bridge into the little endian mode. This + * causes the data on bit 0 internally to come out on data line 0 externally + * and it is generally what we want regardless of the endian mode of the + * processor. This capability in West Bridge should be labeled as a "SWAP" capability + * and can be used to swap the bytes of data in and out of West Bridge. This is + * useful if there is DMA hardware that requires this for some reason I cannot + * imagine at this time. Basically if the wires are connected correctly, we should + * never need to change the endian-ness of West Bridge. + */ + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_P0_ENDIAN, CY_AS_LITTLE_ENDIAN) ; +} + +/* +* Query the West Bridge device and determine if we are an standby mode +*/ +CyAsReturnStatus_t +CyAsMiscInStandby(CyAsDeviceHandle handle, CyBool *standby) +{ + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscInStandby called") ; + + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (CyAsDeviceIsPinStandby(dev_p) || CyAsDeviceIsRegisterStandby(dev_p)) + { + *standby = CyTrue ; + } + else + *standby = CyFalse ; + + return CY_AS_ERROR_SUCCESS ; +} + +static void +CyAsMiscFuncCallback(CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t ret) ; + + +static void +MyMiscCallback(CyAsDevice *dev_p, uint8_t context, CyAsLLRequestResponse *req_p, CyAsLLRequestResponse *resp_p, + CyAsReturnStatus_t ret) +{ + (void)resp_p ; + (void)context ; + (void)ret ; + + switch (CyAsLLRequestResponse_GetCode(req_p)) + { + case CY_RQT_INITIALIZATION_COMPLETE: + { + uint16_t v ; + + CyAsLLSendStatusResponse(dev_p, CY_RQT_GENERAL_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; + CyAsDeviceSetFirmwareLoaded(dev_p) ; + + if (CyAsDeviceIsWaking(dev_p)) + { + /* + * This is a callback from a CyAsMiscLeaveStandby() request. In this case we call the + * standby callback and clear the waking state. + */ + if (dev_p->misc_event_cb) + dev_p->misc_event_cb((CyAsDeviceHandle)dev_p, CyAsEventMiscAwake, 0) ; + CyAsDeviceClearWaking(dev_p) ; + } + else + { + v = CyAsLLRequestResponse_GetWord(req_p, 3) ; + + /* + * Store the media supported on each of the device buses. + */ + dev_p->media_supported[0] = (uint8_t)(v & 0xFF) ; + dev_p->media_supported[1] = (uint8_t)((v >> 8) & 0xFF) ; + + v = CyAsLLRequestResponse_GetWord(req_p, 4) ; + dev_p->is_mtp_firmware = (CyBool)((v >> 8) & 0xFF) ; + + if (dev_p->misc_event_cb) + dev_p->misc_event_cb((CyAsDeviceHandle)dev_p, CyAsEventMiscInitialized, 0) ; + } + + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_VM_SET) ; + if (v & CY_AS_MEM_P0_VM_SET_CFGMODE) + CyAsHalPrintMessage("Initialization Message Recieved, but config bit still set\n") ; + + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_RST_CTRL_REG) ; + if ((v & CY_AS_MEM_RST_RSTCMPT) ==0) + CyAsHalPrintMessage("Initialization Message Recieved, but reset complete bit still not set\n") ; + } + break ; + + case CY_RQT_OUT_OF_SUSPEND: + CyAsLLSendStatusResponse(dev_p, CY_RQT_GENERAL_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; + CyAsDeviceClearSuspendMode(dev_p) ; + + /* + * If the wakeup was caused by an async CyAsMiscLeaveSuspend call, we have to + * call the corresponding callback. + */ + if (dev_p->func_cbs_misc->count > 0) + { + CyAsFuncCBNode *node = (CyAsFuncCBNode*)dev_p->func_cbs_misc->head_p ; + CyAsHalAssert(node) ; + + if (CyAsFunctCBTypeGetType(node->dataType) == CY_FUNCT_CB_MISC_LEAVESUSPEND) + { + CyAsHalAssert(node->cb_p != 0) ; + node->cb_p((CyAsDeviceHandle)dev_p, CY_AS_ERROR_SUCCESS, node->client_data, + CY_FUNCT_CB_MISC_LEAVESUSPEND, 0) ; + CyAsRemoveCBNode(dev_p->func_cbs_misc) ; + } + } + + if (dev_p->misc_event_cb) + dev_p->misc_event_cb((CyAsDeviceHandle)dev_p, CyAsEventMiscWakeup, 0) ; + break ; + + case CY_RQT_DEBUG_MESSAGE: + if ((req_p->data[0] == 0) && (req_p->data[1] == 0) && (req_p->data[2] == 0)) + { + if (dev_p->misc_event_cb) + dev_p->misc_event_cb((CyAsDeviceHandle)dev_p, CyAsEventMiscHeartBeat, 0) ; + } + else + { + CyAsHalPrintMessage("**** Debug Message: %02x %02x %02x %02x %02x %02x\n", + req_p->data[0] & 0xff, (req_p->data[0] >> 8) & 0xff, + req_p->data[1] & 0xff, (req_p->data[1] >> 8) & 0xff, + req_p->data[2] & 0xff, (req_p->data[2] >> 8) & 0xff) ; + } + break ; + + case CY_RQT_WB_DEVICE_MISMATCH: + { + if (dev_p->misc_event_cb) + dev_p->misc_event_cb((CyAsDeviceHandle)dev_p, CyAsEventMiscDeviceMismatch, 0) ; + } + break ; + + case CY_RQT_BOOTLOAD_NO_FIRMWARE: + { + /* TODO Handle case when firmware is not found during bootloading. */ + CyAsHalPrintMessage("No firmware image found during bootload. Device not started\n") ; + } + break ; + + default: + CyAsHalAssert (0) ; + } +} + +static CyBool +IsValidSiliconId(uint16_t v) +{ + CyBool idok = CyFalse ; + + /* + * Remove the revision number from the ID value + */ + v = v & CY_AS_MEM_CM_WB_CFG_ID_HDID_MASK ; + + /* + * If this is West Bridge, then we are OK. + */ + if (v == CY_AS_MEM_CM_WB_CFG_ID_HDID_ANTIOCH_VALUE || + v == CY_AS_MEM_CM_WB_CFG_ID_HDID_ASTORIA_FPGA_VALUE || + v == CY_AS_MEM_CM_WB_CFG_ID_HDID_ASTORIA_VALUE) + idok = CyTrue ; + + return idok ; +} + +/* +* Configure the West Bridge device hardware +*/ +CyAsReturnStatus_t +CyAsMiscConfigureDevice(CyAsDeviceHandle handle, CyAsDeviceConfig *config_p) +{ + CyAsReturnStatus_t ret ; + CyBool standby ; + CyAsDevice *dev_p ; + uint16_t v ; + uint16_t fw_present; + CyAsLogDebugMessage(6, "CyAsMiscConfigureDevice called") ; + + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + /* Setup big endian vs little endian */ + CyAsSetupEndianMode(dev_p) ; + + /* Now, confirm that we can talk to the West Bridge device */ + dev_p->silicon_id = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_CM_WB_CFG_ID) ; + fw_present = CyAsHalReadRegister(dev_p->tag,CY_AS_MEM_RST_CTRL_REG ) ; + if (!(fw_present & CY_AS_MEM_RST_RSTCMPT)) + { + if (!IsValidSiliconId(dev_p->silicon_id)) + return CY_AS_ERROR_NO_ANTIOCH ; + } + /* Check for standby mode */ + ret = CyAsMiscInStandby(handle, &standby) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + if (ret) + return CY_AS_ERROR_IN_STANDBY ; + + /* Setup P-port interface mode (CRAM / SRAM). */ + if (CyAsDeviceIsAstoriaDev(dev_p)) + { + if (config_p->srammode) + v = CY_AS_MEM_P0_VM_SET_VMTYPE_SRAM ; + else + v = CY_AS_MEM_P0_VM_SET_VMTYPE_RAM ; + } + else + v = CY_AS_MEM_P0_VM_SET_VMTYPE_RAM ; + + /* Setup synchronous versus asynchronous mode */ + if (config_p->sync) + v |= CY_AS_MEM_P0_VM_SET_IFMODE ; + if (config_p->dackmode == CyAsDeviceDackAck) + v |= CY_AS_MEM_P0_VM_SET_DACKEOB ; + if (config_p->drqpol) + v |= CY_AS_MEM_P0_VM_SET_DRQPOL ; + if (config_p->dackpol) + v |= CY_AS_MEM_P0_VM_SET_DACKPOL ; + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_P0_VM_SET, v) ; + + if (config_p->crystal) + CyAsDeviceSetCrystal(dev_p) ; + else + CyAsDeviceSetExternalClock(dev_p) ; + + /* Register a callback to handle MISC requests from the firmware */ + CyAsLLRegisterRequestCallback(dev_p, CY_RQT_GENERAL_RQT_CONTEXT, MyMiscCallback) ; + + /* Now mark the DMA and low level modules as active. */ + CyAsDeviceSetDmaRunning(dev_p) ; + CyAsDeviceSetLowLevelRunning(dev_p) ; + + /* Now, initialize the interrupt module */ + dev_p->use_int_drq = config_p->dmaintr ; + + ret = CyAsIntrStart(dev_p, config_p->dmaintr) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* Mark the interface as initialized */ + CyAsDeviceSetConfigured(dev_p) ; + + return CY_AS_ERROR_SUCCESS ; +} + +static void +MyDmaCallback(CyAsDevice * dev_p, + CyAsEndPointNumber_t ep, + void * mem_p, + uint32_t size, + CyAsReturnStatus_t ret + ) +{ + CyAsDmaEndPoint *ep_p ; + + (void)size ; + + /* Get the endpoint pointer based on the endpoint number */ + ep_p = CY_AS_NUM_EP(dev_p, ep) ; + + /* Check the queue to see if is drained */ + if (ep_p->queue_p == 0) + { + CyAsFuncCBNode* node = (CyAsFuncCBNode*)dev_p->func_cbs_misc->head_p ; + + CyAsHalAssert(node) ; + + if (ret == CY_AS_ERROR_SUCCESS) + { + /* + * Disable endpoint 2. The storage module will enable this EP if necessary. + */ + CyAsDmaEnableEndPoint(dev_p, CY_AS_FIRMWARE_ENDPOINT, CyFalse, CyAsDirectionIn) ; + + /* + * Clear the reset register. This releases the Antioch micro-controller from + * reset and begins running the code at address zero. + */ + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_RST_CTRL_REG, 0x00) ; + } + + /* Call the user Callback */ + node->cb_p((CyAsDeviceHandle)dev_p, ret, node->client_data, (CyAsFunctCBType)node->dataType, node->data) ; + CyAsRemoveCBNode(dev_p->func_cbs_misc) ; + } + else + { + /* This is the header data that was allocated in the download firmware function, + * and can be safely freed here. */ + uint32_t state = CyAsHalDisableInterrupts() ; + CyAsHalCBFree(mem_p) ; + CyAsHalEnableInterrupts(state) ; + } +} + +CyAsReturnStatus_t +CyAsMiscDownloadFirmware(CyAsDeviceHandle handle, + const void *mem_p, + uint16_t size, + CyAsFunctionCallback cb, + uint32_t client) +{ + uint8_t *header ; + CyAsReturnStatus_t ret ; + CyBool standby ; + CyAsDevice *dev_p ; + CyAsDmaCallback dmacb = 0 ; + uint32_t state ; + + CyAsLogDebugMessage(6, "CyAsMiscDownloadFirmware called") ; + + /* Make sure we have a valid device */ + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + /* + * If the device has not been initialized, we cannot download firmware + * to the device. + */ + if (!CyAsDeviceIsConfigured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED ; + + /* + * Make sure West Bridge is not in standby + */ + ret = CyAsMiscInStandby(dev_p, &standby) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (standby) + return CY_AS_ERROR_IN_STANDBY ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* + * Make sure we are in configuration mode + */ + if ((CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_VM_SET) & CY_AS_MEM_P0_VM_SET_CFGMODE) == 0) + return CY_AS_ERROR_NOT_IN_CONFIG_MODE ; + + /* Maximum firmware size is 24k */ + if (size > CY_AS_MAXIMUM_FIRMWARE_SIZE) + return CY_AS_ERROR_INVALID_SIZE ; + + /* Make sure the size is an even number of bytes as well */ + if (size & 0x01) + return CY_AS_ERROR_ALIGNMENT_ERROR ; + + /* + * Write the two word header that gives the base address and + * size of the firmware image to download + */ + state = CyAsHalDisableInterrupts() ; + header = (uint8_t *)CyAsHalCBAlloc(4) ; + CyAsHalEnableInterrupts(state) ; + if (header == NULL) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + header[0] = 0x00 ; + header[1] = 0x00 ; + header[2] = (uint8_t)(size & 0xff) ; + header[3] = (uint8_t)((size >> 8) & 0xff) ; + + /* Enable the firmware endpoint */ + ret = CyAsDmaEnableEndPoint(dev_p, CY_AS_FIRMWARE_ENDPOINT, CyTrue, CyAsDirectionIn) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* + * Setup DMA for 64 byte packets. This is the requirement for downloading + * firmware to West Bridge. + */ + CyAsDmaSetMaxDmaSize(dev_p, CY_AS_FIRMWARE_ENDPOINT, 64) ; + + if(cb) + { + dmacb = MyDmaCallback ; + } + + ret = CyAsDmaQueueRequest(dev_p, CY_AS_FIRMWARE_ENDPOINT, header, 4, CyFalse, CyFalse, dmacb) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + /* + * Write the firmware image to the West Bridge device + */ + ret = CyAsDmaQueueRequest(dev_p, CY_AS_FIRMWARE_ENDPOINT, (void *)mem_p, size, CyFalse, CyFalse, dmacb) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if(cb) + { + CyAsFuncCBNode* cbnode = CyAsCreateFuncCBNodeData(cb, client, CY_FUNCT_CB_MISC_DOWNLOADFIRMWARE, 0) ; + + if(cbnode == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + else + CyAsInsertCBNode(dev_p->func_cbs_misc, cbnode) ; + + ret = CyAsDmaKickStart(dev_p, CY_AS_FIRMWARE_ENDPOINT) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + } + else + { + + ret = CyAsDmaDrainQueue(dev_p, CY_AS_FIRMWARE_ENDPOINT, CyTrue) ; + + /* Free the header memory that was allocated earlier. */ + CyAsHalCBFree(header) ; + + if (ret != CY_AS_ERROR_SUCCESS) + { + return ret ; + } + /* + * Disable endpoint 2. The storage module will enable this EP if necessary. + */ + CyAsDmaEnableEndPoint(dev_p, CY_AS_FIRMWARE_ENDPOINT, CyFalse, CyAsDirectionIn) ; + + /* + * Clear the reset register. This releases the West Bridge micro-controller from + * reset and begins running the code at address zero. + */ + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_RST_CTRL_REG, 0x00) ; + } + + /* + * The firmware is not marked as loaded until the firmware initializes West Bridge and a request + * is sent from West Bridge to the P port processor indicating that West Bridge is ready. + */ + return CY_AS_ERROR_SUCCESS ; +} + + +static CyAsReturnStatus_t +MyHandleResponseGetFirmwareVersion(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyAsGetFirmwareVersionData *data_p) +{ + + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint16_t val ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_FIRMWARE_VERSION) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + data_p->major = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + data_p->minor = CyAsLLRequestResponse_GetWord(reply_p, 1) ; + data_p->build = CyAsLLRequestResponse_GetWord(reply_p, 2) ; + val = CyAsLLRequestResponse_GetWord(reply_p, 3) ; + data_p->mediaType = (uint8_t)(((val >> 8) & 0xFF) | (val & 0xFF)) ; + val = CyAsLLRequestResponse_GetWord(reply_p, 4) ; + data_p->isDebugMode = (CyBool)(val & 0xFF) ; + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMiscGetFirmwareVersion(CyAsDeviceHandle handle, + CyAsGetFirmwareVersionData* data, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyBool standby ; + CyAsLLRequestResponse *req_p, *reply_p ; + + CyAsDevice *dev_p ; + + (void)client ; + + CyAsLogDebugMessage(6, "CyAsMiscGetFirmwareVersion called") ; + + /* Make sure we have a valid device */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* + * Make sure Antioch is not in standby + */ + ret = CyAsMiscInStandby(dev_p, &standby) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + if (standby) + return CY_AS_ERROR_IN_STANDBY ; + + /* Make sure the Antioch is not in suspend mode. */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_GET_FIRMWARE_VERSION, CY_RQT_GENERAL_RQT_CONTEXT, 0) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + /* Reserve space for the reply, the reply data will not exceed three 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 ; + + /* Request and response are freed in MyHandleResponseGetFirmwareVersion. */ + ret = MyHandleResponseGetFirmwareVersion(dev_p, req_p, reply_p, data) ; + return ret ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_GETFIRMWAREVERSION, + data, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, + reply_p, CyAsMiscFuncCallback) ; + + 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 ; +} +static CyAsReturnStatus_t +MyHandleResponseReadMCURegister(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + uint8_t *data_p) +{ + + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_MCU_REGISTER_DATA) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + *data_p = (uint8_t)(CyAsLLRequestResponse_GetWord(reply_p, 0)) ; + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +static CyAsReturnStatus_t +MyHandleResponseGetGpioValue(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + uint8_t *data_p) +{ + + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_GPIO_STATE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + } + else + *data_p = (uint8_t)(CyAsLLRequestResponse_GetWord(reply_p, 0)) ; + + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + + +CyAsReturnStatus_t CyAsMiscSetSDPowerPolarity( + CyAsDeviceHandle handle, + CyAsMiscSignalPolarity polarity, + 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 ; + + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SDPOLARITY , CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + { + + return CY_AS_ERROR_OUT_OF_MEMORY ; + } + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)polarity) ; + + /* 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 ; + } + + 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_MISC_SETSDPOLARITY, + 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, CyAsMiscFuncCallback) ; + + 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 +CyAsMiscReadMCURegister(CyAsDeviceHandle handle, + uint16_t address, + uint8_t *value, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsLLRequestResponse *req_p, *reply_p ; + + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscReadMCURegister called") ; + + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* Check whether the firmware supports this command. */ + if (CyAsDeviceIsNandStorageSupported(dev_p)) + return CY_AS_ERROR_NOT_SUPPORTED ; + + /* Make sure the Antioch is not in suspend mode. */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_READ_MCU_REGISTER, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)address) ; + + /* 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 ; + } + + 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_MCU_REGISTER_DATA) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + *value = (uint8_t)(CyAsLLRequestResponse_GetWord(reply_p, 0)) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_READMCUREGISTER, + value, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMiscFuncCallback) ; + + 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 +CyAsMiscWriteMCURegister(CyAsDeviceHandle handle, + uint16_t address, + uint8_t mask, + uint8_t value, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscWriteMCURegister called") ; + + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* Check whether the firmware supports this command. */ + if (CyAsDeviceIsNandStorageSupported(dev_p)) + return CY_AS_ERROR_NOT_SUPPORTED ; + + /* Make sure the Antioch is not in suspend mode. */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_WRITE_MCU_REGISTER, CY_RQT_GENERAL_RQT_CONTEXT, 2) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)address) ; + CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((mask << 8) | value)) ; + + /* 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 ; + } + + 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_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_WRITEMCUREGISTER, + 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMiscFuncCallback) ; + + 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 +MyHandleResponseReset(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyAsResetType type) +{ + uint16_t v ; + + (void)req_p ; + (void)reply_p ; + + /* + * If the device is in suspend mode, it needs to be woken up so that the write + * to the reset control register succeeds. We need not however wait for the + * wake up procedure to be complete. + */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + { + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_CM_WB_CFG_ID) ; + CyAsHalSleep (1) ; + } + + if (type == CyAsResetHard) + { + CyAsMiscCancelExRequests(dev_p) ; + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_RST_CTRL_REG, CY_AS_MEM_RST_CTRL_REG_HARD) ; + CyAsDeviceSetUnconfigured(dev_p) ; + CyAsDeviceSetFirmwareNotLoaded(dev_p) ; + CyAsDeviceSetDmaStopped(dev_p) ; + CyAsDeviceSetLowLevelStopped(dev_p) ; + CyAsDeviceSetIntrStopped(dev_p) ; + CyAsDeviceClearSuspendMode(dev_p) ; + CyAsUsbCleanup(dev_p) ; + CyAsStorageCleanup(dev_p) ; + + /* + * Wait for a small amount of time to allow reset to be complete. + */ + CyAsHalSleep(100) ; + } + + CyAsDeviceClearResetPending(dev_p) ; + + return CY_AS_ERROR_SUCCESS ; +} + +CyAsReturnStatus_t +CyAsMiscReset(CyAsDeviceHandle handle, + CyAsResetType type, + CyBool flush, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p ; + CyAsEndPointNumber_t i ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + (void)client ; + (void)cb ; + + CyAsLogDebugMessage(6, "CyAsMiscResetEX called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* + * Soft reset is not supported until we close on the issues in the + * firmware with what needs to happen. + */ + if (type == CyAsResetSoft) + return CY_AS_ERROR_NOT_YET_SUPPORTED ; + + CyAsDeviceSetResetPending(dev_p) ; + + if (flush) + { + + /* Unable to DrainQueues in polling mode */ + if((dev_p->storage_cb || dev_p->storage_cb_ms) && CyAsHalIsPolling()) + return CY_AS_ERROR_ASYNC_PENDING ; + + /* + * Shutdown the endpoints so no more traffic can be queued + */ + for(i = 0; i < 15; i++) + CyAsDmaEnableEndPoint(dev_p, i, CyFalse, CyAsDirectionDontChange) ; + + /* + * If we are in normal mode, drain all traffic across all endpoints to be sure all traffic + * is flushed. If the device is suspended, data will not be coming in on any endpoint and + * all outstanding DMA operations can be canceled. + */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + { + for(i = 0; i < 15; i++) + { + CyAsDmaCancel(dev_p, i, CY_AS_ERROR_CANCELED) ; + } + } + else + { + for(i = 0; i < 15; i++) + { + if ((i == CY_AS_P2S_WRITE_ENDPOINT) || (i == CY_AS_P2S_READ_ENDPOINT)) + CyAsDmaDrainQueue(dev_p, i, CyFalse) ; + else + CyAsDmaDrainQueue(dev_p, i, CyTrue) ; + } + } + } + else + { + /* No flush was requested, so cancel any outstanding DMAs + * so the user callbacks are called as needed + */ + if(CyAsDeviceIsStorageAsyncPending(dev_p)) + { + for(i = 0; i < 15; i++) + CyAsDmaCancel(dev_p, i, CY_AS_ERROR_CANCELED) ; + } + } + + ret = MyHandleResponseReset(dev_p, 0, 0, type) ; + + if(cb) + /* Even though no mailbox communication was needed, issue the callback so the + * user does not need to special case their code. */ + cb((CyAsDeviceHandle)dev_p, ret, client, CY_FUNCT_CB_MISC_RESET, 0) ; + + /* + * Initialize any registers that may have been changed when the device was reset. + */ + CyAsHalInitDevRegisters(dev_p->tag, CyFalse) ; + + return ret ; +} + +static CyAsReturnStatus_t +GetUnallocatedResource(CyAsDevice *dev_p, CyAsResourceType resource) +{ + uint8_t shift = 0 ; + uint16_t v ; + CyAsReturnStatus_t ret = CY_AS_ERROR_NOT_ACQUIRED ; + + switch(resource) + { + case CyAsBusUSB: + shift = 4 ; + break ; + case CyAsBus_1: + shift = 0 ; + break ; + case CyAsBus_0: + shift = 2 ; + break ; + default: + CyAsHalAssert(CyFalse) ; + break ; + } + + /* Get the semaphore value for this resource */ + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_RSE_ALLOCATE) ; + v = (v >> shift) & 0x03 ; + + if (v == 0x03) + { + ret = CY_AS_ERROR_RESOURCE_ALREADY_OWNED ; + } + else if ((v & 0x01) == 0) + { + /* The resource is not owned by anyone, we can try to get it */ + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_P0_RSE_MASK, (0x03 << shift)) ; + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_RSE_MASK) ; + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_P0_RSE_ALLOCATE, (0x01 << shift)) ; + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_RSE_MASK) ; + + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_RSE_ALLOCATE) ; + v = (v >> shift) & 0x03 ; + if (v == 0x03) + ret = CY_AS_ERROR_SUCCESS ; + } + + return ret ; +} + +static CyAsReturnStatus_t +MyHandleResponseAcquireResource(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyAsResourceType *resource) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + if (ret == CY_AS_ERROR_SUCCESS) + { + ret = GetUnallocatedResource(dev_p, *resource) ; + if (ret != CY_AS_ERROR_NOT_ACQUIRED) + ret = CY_AS_ERROR_SUCCESS ; + } + +destroy : + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMiscAcquireResource(CyAsDeviceHandle handle, + CyAsResourceType *resource, + CyBool force, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret ; + + CyAsDevice *dev_p ; + + (void)client ; + + CyAsLogDebugMessage(6, "CyAsMiscAcquireResource called") ; + + if (*resource != CyAsBusUSB && *resource != CyAsBus_0 && *resource != CyAsBus_1) + return CY_AS_ERROR_INVALID_RESOURCE ; + + + /* Make sure the device is ready to accept the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + + ret = GetUnallocatedResource(dev_p, *resource) ; + + /* + * Make sure that the callback is called if the resource is successfully + * acquired at this point. + */ + if ((ret == CY_AS_ERROR_SUCCESS) && (cb != 0)) + cb(handle, ret, client, CY_FUNCT_CB_MISC_ACQUIRERESOURCE, resource) ; + + if (ret != CY_AS_ERROR_NOT_ACQUIRED) + return ret ; + + if (!force) + return CY_AS_ERROR_NOT_ACQUIRED ; + + /* Create the request to acquire the resource */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_ACQUIRE_RESOURCE, CY_RQT_RESOURCE_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)(*resource)) ; + + 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 ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_ACQUIRERESOURCE, + resource, dev_p->func_cbs_res, CY_AS_REQUEST_RESPONSE_EX, req_p, + reply_p, CyAsMiscFuncCallback) ; + + 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) ; + + if (ret == CY_AS_ERROR_SUCCESS) + { + ret = GetUnallocatedResource(dev_p, *resource) ; + if (ret != CY_AS_ERROR_NOT_ACQUIRED) + ret = CY_AS_ERROR_SUCCESS ; + } + + return ret ; +} +CyAsReturnStatus_t +CyAsMiscReleaseResource(CyAsDeviceHandle handle, CyAsResourceType resource) +{ + uint8_t shift = 0 ; + uint16_t v ; + + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscReleaseResource called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + if (resource != CyAsBusUSB && resource != CyAsBus_0 && resource != CyAsBus_1) + return CY_AS_ERROR_INVALID_RESOURCE ; + + switch(resource) + { + case CyAsBusUSB: + shift = 4 ; + break ; + case CyAsBus_1: + shift = 0 ; + break ; + case CyAsBus_0: + shift = 2 ; + break ; + default: + CyAsHalAssert(CyFalse) ; + break ; + } + + /* Get the semaphore value for this resource */ + v = (CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_RSE_ALLOCATE) >> shift) & 0x03 ; + if (v == 0 || v == 1 || v == 2) + return CY_AS_ERROR_RESOURCE_NOT_OWNED ; + + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_P0_RSE_MASK, (0x03 << shift)) ; + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_P0_RSE_ALLOCATE, (0x02 << shift)) ; + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_P0_RSE_MASK, 0) ; + + return CY_AS_ERROR_SUCCESS ; +} + +CyAsReturnStatus_t +CyAsMiscSetTraceLevel(CyAsDeviceHandle handle, + uint8_t level, + CyAsBusNumber_t bus, + uint32_t device, + uint32_t unit, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret ; + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscSetTraceLevel called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + 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 (unit > 255) + return CY_AS_ERROR_NO_SUCH_UNIT ; + + if (level >= CYAS_FW_TRACE_MAX_LEVEL) + return CY_AS_ERROR_INVALID_TRACE_LEVEL ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SET_TRACE_LEVEL, CY_RQT_GENERAL_RQT_CONTEXT, 2) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)level) ; + CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((bus << 12) | (device << 8) | (unit))) ; + + /* Reserve space for the reply, the reply data will not exceed three 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 ; + + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_NOT_SUPPORTED ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_SETTRACELEVEL, + 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMiscFuncCallback) ; + + 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 +CyAsMiscHeartBeatControl(CyAsDeviceHandle handle, + CyBool enable, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsReturnStatus_t ret ; + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscHeartBeatControl called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_CONTROL_ANTIOCH_HEARTBEAT, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)enable) ; + + /* 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 ; + } + + 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_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_HEARTBEATCONTROL, + 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMiscFuncCallback) ; + + 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 ; +} + +static CyAsReturnStatus_t +MySetSDClockFreq ( + CyAsDevice *dev_p, + uint8_t cardType, + uint8_t setting, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsLLRequestResponse *req_p, *reply_p ; + + if (CyAsDeviceIsInCallback(dev_p) && (cb == 0)) + return CY_AS_ERROR_INVALID_IN_CALLBACK ; + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SET_SD_CLOCK_FREQ, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)((cardType << 8) | setting)) ; + + /* Reserve space for the reply, which 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 ; + } + + 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_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_SETSDFREQ, 0, + dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, CyAsMiscFuncCallback) ; + + 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 +CyAsMiscSetLowSpeedSDFreq( + CyAsDeviceHandle handle, + CyAsLowSpeedSDFreq setting, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscSetLowSpeedSDFreq called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + if ((setting != CY_AS_SD_DEFAULT_FREQ) && (setting != CY_AS_SD_RATED_FREQ)) + return CY_AS_ERROR_INVALID_PARAMETER ; + + return MySetSDClockFreq(dev_p, 0, (uint8_t)setting, cb, client) ; +} + +CyAsReturnStatus_t +CyAsMiscSetHighSpeedSDFreq( + CyAsDeviceHandle handle, + CyAsHighSpeedSDFreq setting, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscSetHighSpeedSDFreq called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + if ((setting != CY_AS_HS_SD_FREQ_24) && (setting != CY_AS_HS_SD_FREQ_48)) + return CY_AS_ERROR_INVALID_PARAMETER ; + + return MySetSDClockFreq(dev_p, 1, (uint8_t)setting, cb, client) ; +} + +CyAsReturnStatus_t +CyAsMiscGetGpioValue(CyAsDeviceHandle handle, + CyAsMiscGpio pin, + uint8_t *value, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsDevice *dev_p ; + uint16_t v ; + + CyAsLogDebugMessage(6, "CyAsMiscGetGpioValue called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* If the pin specified is UVALID, there is no need for firmware to be loaded. */ + if (pin == CyAsMiscGpio_UValid) + { + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_PMU_UPDATE) ; + *value = (uint8_t)(v & CY_AS_MEM_PMU_UPDATE_UVALID) ; + + if (cb != 0) + cb(dev_p, ret, client, CY_FUNCT_CB_MISC_GETGPIOVALUE, value) ; + + return ret ; + } + + /* Check whether the firmware supports this command. */ + if (CyAsDeviceIsNandStorageSupported(dev_p)) + return CY_AS_ERROR_NOT_SUPPORTED ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* Make sure the pin selected is valid */ + if ((pin != CyAsMiscGpio_1) && (pin != CyAsMiscGpio_0)) + return CY_AS_ERROR_INVALID_PARAMETER ; + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_GET_GPIO_STATE, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsLLRequestResponse_SetWord(req_p, 0, ((uint8_t)pin << 8)) ; + + /* Reserve space for the reply, which 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 ; + } + + 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_GPIO_STATE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + *value = (uint8_t)CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_GETGPIOVALUE, + value, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMiscFuncCallback) ; + + 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 +CyAsMiscSetGpioValue(CyAsDeviceHandle handle, + CyAsMiscGpio pin, + uint8_t value, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsLLRequestResponse *req_p, *reply_p ; + CyAsDevice *dev_p ; + uint16_t v ; + + CyAsLogDebugMessage(6, "CyAsMiscSetGpioValue called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* If the pin specified is UVALID, there is no need for firmware to be loaded. */ + if (pin == CyAsMiscGpio_UValid) + { + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_PMU_UPDATE) ; + if (value) + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_PMU_UPDATE, (v | CY_AS_MEM_PMU_UPDATE_UVALID)) ; + else + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_PMU_UPDATE, (v & ~CY_AS_MEM_PMU_UPDATE_UVALID)) ; + + if (cb != 0) + cb(dev_p, ret, client, CY_FUNCT_CB_MISC_SETGPIOVALUE, 0) ; + return ret ; + } + + /* Check whether the firmware supports this command. */ + if (CyAsDeviceIsNandStorageSupported(dev_p)) + return CY_AS_ERROR_NOT_SUPPORTED ; + + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* Make sure the pin selected is valid */ + if ((pin < CyAsMiscGpio_0) || (pin > CyAsMiscGpio_UValid)) + return CY_AS_ERROR_INVALID_PARAMETER ; + + /* Create and initialize the low level request to the firmware. */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SET_GPIO_STATE, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + v = (uint16_t)(((uint8_t)pin << 8) | (value > 0)) ; + CyAsLLRequestResponse_SetWord(req_p, 0, v) ; + + /* Reserve space for the reply, which 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 ; + } + + 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_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_SETGPIOVALUE, + 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMiscFuncCallback) ; + + 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 ; +} + +static CyAsReturnStatus_t +MyEnterStandby(CyAsDevice *dev_p, CyBool pin) +{ + CyAsMiscCancelExRequests(dev_p) ; + + /* Save the current values in the critical P-port registers, where necessary. */ + CyAsHalReadRegsBeforeStandby(dev_p->tag) ; + + if (pin) + { + if (CyAsHalSetWakeupPin(dev_p->tag, CyFalse)) + CyAsDeviceSetPinStandby(dev_p) ; + else + return CY_AS_ERROR_SETTING_WAKEUP_PIN ; + } + else + { + /* + * Put antioch in the standby mode + */ + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_PWR_MAGT_STAT, 0x02) ; + CyAsDeviceSetRegisterStandby(dev_p) ; + } + + /* + * When the Antioch comes out of standby, we have to wait until + * the firmware initialization completes before sending other + * requests down. + */ + CyAsDeviceSetFirmwareNotLoaded(dev_p) ; + + /* + * Keep West Bridge interrupt disabled until the device is being woken + * up from standby. + */ + dev_p->stby_int_mask = CyAsHalDisableInterrupts (); + + return CY_AS_ERROR_SUCCESS ; +} + +static CyAsReturnStatus_t +MyHandleResponseEnterStandby(CyAsDevice* dev_p, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyBool pin) +{ + 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) ; + + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + ret = MyEnterStandby(dev_p, pin) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMiscEnterStandby(CyAsDeviceHandle handle, + CyBool pin, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyAsLLRequestResponse *req_p, *reply_p ; + CyBool standby ; + + CyAsLogDebugMessage(6, "CyAsMiscEnterStandby called") ; + + /* Make sure we have a valid device */ + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + /* + * If we already are in standby, do not do it again and let the + * user know via the error return. + */ + ret = CyAsMiscInStandby(handle, &standby) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (standby == CyTrue) + return CY_AS_ERROR_ALREADY_STANDBY ; + + /* + * If the user wants to transition from suspend mode to standby mode, + * the device needs to be woken up so that it can complete all pending + * operations. + */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + CyAsMiscLeaveSuspend(dev_p, 0, 0) ; + + if (dev_p->usb_count) + { + /* + * We do not allow West Bridge to go into standby mode when the + * USB stack is initialized. You must stop the USB stack in + * order to enter standby mode. + */ + return CY_AS_ERROR_USB_RUNNING ; + } + + /* + * If the storage stack is not running, the device can directly be put into + * sleep mode. Otherwise, the firmware needs to be signaled to prepare for + * going into sleep mode. + */ + if (dev_p->storage_count) + { + /* + * If there are async storage operations pending, make one attempt to + * complete them. + */ + if (CyAsDeviceIsStorageAsyncPending(dev_p)) + { + /* DrainQueue will not work in polling mode */ + if(CyAsHalIsPolling()) + return CY_AS_ERROR_ASYNC_PENDING ; + + CyAsDmaDrainQueue(dev_p, CY_AS_P2S_READ_ENDPOINT, CyFalse) ; + CyAsDmaDrainQueue(dev_p, CY_AS_P2S_WRITE_ENDPOINT, CyFalse) ; + + /* + * If more storage operations were queued at this stage, return + * an error. + */ + if (CyAsDeviceIsStorageAsyncPending(dev_p)) + return CY_AS_ERROR_ASYNC_PENDING ; + } + + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_PREPARE_FOR_STANDBY, 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 ; + } + + if(!cb) + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + /* The request and response are freed in the HandleResponse */ + return MyHandleResponseEnterStandby(dev_p, req_p, reply_p, pin) ; + + } + else + { + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_ENTERSTANDBY, + (void*)pin, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, + reply_p, CyAsMiscFuncCallback) ; + + 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 + { + ret = MyEnterStandby(dev_p, pin) ; + if(cb) + /* Even though no mailbox communication was needed, issue the callback so the + * user does not need to special case their code. */ + cb((CyAsDeviceHandle)dev_p, ret, client, CY_FUNCT_CB_MISC_ENTERSTANDBY, 0) ; + } + + return ret ; +} + +CyAsReturnStatus_t +CyAsMiscEnterStandbyEXU(CyAsDeviceHandle handle, + CyBool pin, + CyBool uvalid_special, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p ; + + dev_p = (CyAsDevice *)handle ; + if(uvalid_special) + { + CyAsHalWriteRegister(dev_p->tag, 0xc5, 0x4) ; + } + + return CyAsMiscEnterStandby(handle, pin, cb, client) ; +} + +CyAsReturnStatus_t +CyAsMiscLeaveStandby(CyAsDeviceHandle handle, CyAsResourceType resource) +{ + CyAsDevice *dev_p ; + uint16_t v ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + uint32_t count = 8 ; + uint8_t retry = 1 ; + + CyAsLogDebugMessage(6, "CyAsMiscLeaveStandby called") ; + (void)resource ; + + /* Make sure we have a valid device */ + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + if (CyAsDeviceIsRegisterStandby(dev_p)) + { + /* + * Set a flag to indicate that the West Bridge is waking up from standby. + */ + CyAsDeviceSetWaking(dev_p) ; + + /* + * The initial read will not succeed, but will just wake the West Bridge + * device from standby. Successive reads should succeed and in that way + * we know West Bridge is awake. + */ + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_CM_WB_CFG_ID) ; + + do + { + /* + * We have initiated the operation to leave standby, now we need to wait at least + * N ms before trying to access the West Bridge device to insure the PLLs have locked and we + * can talk to the device. + */ + if (CyAsDeviceIsCrystal(dev_p)) + CyAsHalSleep(CY_AS_LEAVE_STANDBY_DELAY_CRYSTAL) ; + else + CyAsHalSleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK) ; + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_CM_WB_CFG_ID) ; + + /* + * If the P-SPI interface mode is in use, there may be a need to re-synchronise the + * serial clock used for Astoria access. + */ + if (!IsValidSiliconId(v)) + { + if (CyAsHalSyncDeviceClocks(dev_p->tag) != CyTrue) + { + CyAsHalEnableInterrupts (dev_p->stby_int_mask) ; + return CY_AS_ERROR_TIMEOUT ; + } + } + } while (!IsValidSiliconId(v) && count-- > 0) ; + + /* + * If we tried to read the register and could not, return a timeout + */ + if (count == 0) + { + CyAsHalEnableInterrupts (dev_p->stby_int_mask) ; + return CY_AS_ERROR_TIMEOUT ; + } + + /* + * The standby flag is cleared here, after the action to exit standby has + * been taken. The wait for firmware initialization, is ensured by marking + * the firmware as not loaded until the init event is received. + */ + CyAsDeviceClearRegisterStandby(dev_p) ; + + /* + * Initialize any registers that may have been changed while the device was in standby mode. + */ + CyAsHalInitDevRegisters(dev_p->tag, CyTrue) ; + } + else if (CyAsDeviceIsPinStandby(dev_p)) + { + /* + * Set a flag to indicate that the West Bridge is waking up from standby. + */ + CyAsDeviceSetWaking(dev_p) ; + +TryWakeupAgain: + /* + * Try to set the wakeup pin, if this fails in the HAL layer, return this + * failure to the user. + */ + if (!CyAsHalSetWakeupPin(dev_p->tag, CyTrue)) + { + CyAsHalEnableInterrupts (dev_p->stby_int_mask) ; + return CY_AS_ERROR_SETTING_WAKEUP_PIN ; + } + + /* + * We have initiated the operation to leave standby, now we need to wait at least + * N ms before trying to access the West Bridge device to insure the PLLs have locked and we + * can talk to the device. + */ + if (CyAsDeviceIsCrystal(dev_p)) + CyAsHalSleep(CY_AS_LEAVE_STANDBY_DELAY_CRYSTAL) ; + else + CyAsHalSleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK) ; + + /* + * Initialize any registers that may have been changed while the device was in standby mode. + */ + CyAsHalInitDevRegisters(dev_p->tag, CyTrue) ; + + /* + * The standby flag is cleared here, after the action to exit standby has + * been taken. The wait for firmware initialization, is ensured by marking + * the firmware as not loaded until the init event is received. + */ + CyAsDeviceClearPinStandby(dev_p) ; + } + else + { + return CY_AS_ERROR_NOT_IN_STANDBY ; + } + + /* + * The West Bridge interrupt can be enabled now. + */ + CyAsHalEnableInterrupts (dev_p->stby_int_mask) ; + + /* + * Release the West Bridge Micro-Controller from reset, so that firmware initialization + * can complete. + * The attempt to release Antioch reset is made upto 8 times. + */ + v = 0x03 ; + count = 0x08 ; + while ((v & 0x03) && (count)) + { + CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_RST_CTRL_REG, 0x00) ; + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_RST_CTRL_REG) ; + count-- ; + } + + if (v & 0x03) + { + CyAsHalPrintMessage("Failed to clear Antioch reset\n") ; + return CY_AS_ERROR_TIMEOUT ; + } + + /* + * If the wake-up pin is being used, wait here to make sure that the wake-up event + * is received within a reasonable delay. Otherwise, toggle the wake-up pin again + * in an attempt to start the firmware properly. + */ + if (retry) + { + count = 10 ; + while (count) + { + /* If the wake-up event has been received, we can return. */ + if (CyAsDeviceIsFirmwareLoaded (dev_p)) + break ; + /* If we are in polling mode, the interrupt may not have been serviced as yet. + * Read the interrupt status register. If a pending mailbox interrupt is seen, + * we can assume that the wake-up event will be received soon. */ + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_INTR_REG) ; + if (v & CY_AS_MEM_P0_INTR_REG_MBINT) + break ; + + CyAsHalSleep (10) ; + count-- ; + } + + if (!count) + { + retry = 0 ; + dev_p->stby_int_mask = CyAsHalDisableInterrupts() ; + CyAsHalSetWakeupPin(dev_p->tag, CyFalse) ; + CyAsHalSleep (10) ; + goto TryWakeupAgain ; + } + } + + return ret ; +} + +CyAsReturnStatus_t +CyAsMiscRegisterCallback( + CyAsDeviceHandle handle, /* Handle to the West Bridge device */ + CyAsMiscEventCallback callback /* The function to call */ + ) +{ + CyAsDevice *dev_p ; + + CyAsLogDebugMessage(6, "CyAsMiscRegisterCallback called") ; + + /* Make sure we have a valid device */ + dev_p = (CyAsDevice *)handle ; + if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE ; + + dev_p->misc_event_cb = callback ; + return CY_AS_ERROR_SUCCESS ; +} + +CyAsReturnStatus_t +CyAsMiscStorageChanged(CyAsDeviceHandle handle, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyBool standby ; + CyAsLLRequestResponse *req_p, *reply_p ; + + CyAsLogDebugMessage(6, "CyAsMiscStorageChanged called") ; + + /* Make sure the device is ready for the command. */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* + * Make sure Antioch is not in standby + */ + ret = CyAsMiscInStandby(dev_p, &standby) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + + if (standby) + return CY_AS_ERROR_IN_STANDBY ; + + /* + * Make sure Westbridge is not in suspend mode. + */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_STORAGE_MEDIA_CHANGED, CY_RQT_GENERAL_RQT_CONTEXT, 0) ; + 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 ; + } + + 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_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_STORAGECHANGED, + 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMiscFuncCallback) ; + + 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 +CyAsMiscEnterSuspend( + CyAsDeviceHandle handle, + CyBool usb_wakeup_en, + CyBool gpio_wakeup_en, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyBool standby ; + CyAsLLRequestResponse *req_p, *reply_p ; + uint16_t value ; + uint32_t int_state ; + + CyAsLogDebugMessage(6, "CyAsMiscEnterSuspend called") ; + + /* + * Basic sanity checks to ensure that the device is initialised. + */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* + * Make sure West Bridge is not already in standby + */ + CyAsMiscInStandby(dev_p, &standby) ; + if (standby) + return CY_AS_ERROR_IN_STANDBY ; + + /* + * Make sure that the device is not already in suspend mode. + */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* + * Make sure there is no active USB connection. + */ + if ((CyAsDeviceIsUsbConnected(dev_p)) && (dev_p->usb_last_event != CyAsEventUsbSuspend)) + return CY_AS_ERROR_USB_CONNECTED ; + + /* + * Make sure that there are no async requests at this point in time. + */ + int_state = CyAsHalDisableInterrupts() ; + if ((dev_p->func_cbs_misc->count) || (dev_p->func_cbs_res->count) || + (dev_p->func_cbs_stor->count) || (dev_p->func_cbs_usb->count)) + { + CyAsHalEnableInterrupts(int_state) ; + return CY_AS_ERROR_ASYNC_PENDING ; + } + CyAsHalEnableInterrupts(int_state) ; + + /* Create the request to send to the Antioch device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_ENTER_SUSPEND_MODE, CY_RQT_GENERAL_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 ; + } + + /* Wakeup control flags. */ + value = 0x0001 ; + if (usb_wakeup_en) + value |= 0x04 ; + if (gpio_wakeup_en) + value |= 0x02 ; + CyAsLLRequestResponse_SetWord(req_p, 0, value) ; + + if (cb != 0) + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_ENTERSUSPEND, + 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + CyAsMiscFuncCallback) ; + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy ; + + return CY_AS_ERROR_SUCCESS ; + } + else + { + ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ; + if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE) + ret = CY_AS_ERROR_INVALID_RESPONSE ; + else + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + +destroy: + if (ret == CY_AS_ERROR_SUCCESS) + CyAsDeviceSetSuspendMode(dev_p) ; + + CyAsLLDestroyRequest(dev_p, req_p) ; + CyAsLLDestroyResponse(dev_p, reply_p) ; + + return ret ; +} + +CyAsReturnStatus_t +CyAsMiscLeaveSuspend( + CyAsDeviceHandle handle, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsDevice *dev_p ; + uint16_t v, count ; + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + + CyAsLogDebugMessage(6, "CyAsMiscLeaveSuspend called") ; + + /* Make sure we have a valid device */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* Make sure we are in suspend mode. */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + { + if (cb) + { + CyAsFuncCBNode *cbnode = CyAsCreateFuncCBNodeData(cb, client, CY_FUNCT_CB_MISC_LEAVESUSPEND, 0) ; + if (cbnode == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + + CyAsInsertCBNode(dev_p->func_cbs_misc, cbnode) ; + } + + /* + * Do a read from the ID register so that the CE assertion will wake West Bridge. + * The read is repeated until the read comes back with valid data. + */ + count = 8 ; + + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_CM_WB_CFG_ID) ; + + while (!IsValidSiliconId(v) && count-- > 0) + { + CyAsHalSleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK) ; + v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_CM_WB_CFG_ID) ; + } + + /* + * If we tried to read the register and could not, return a timeout + */ + if (count == 0) + return CY_AS_ERROR_TIMEOUT ; + } + else + return CY_AS_ERROR_NOT_IN_SUSPEND ; + + if (cb == 0) + { + /* + * Wait until the in suspend mode flag is cleared. + */ + count = 20 ; + while ((CyAsDeviceIsInSuspendMode(dev_p)) && (count--)) + { + CyAsHalSleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK) ; + } + + if (CyAsDeviceIsInSuspendMode(dev_p)) + ret = CY_AS_ERROR_TIMEOUT ; + } + + return ret ; +} + +CyAsReturnStatus_t +CyAsMiscReserveLNABootArea(CyAsDeviceHandle handle, + uint8_t numzones, + CyAsFunctionCallback cb, + uint32_t client) +{ + CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ; + CyBool standby ; + CyAsLLRequestResponse *req_p, *reply_p ; + + CyAsDevice *dev_p ; + + (void)client ; + + CyAsLogDebugMessage(6, "CyAsMiscSwitchPnandMode called") ; + + /* Make sure we have a valid device */ + dev_p = (CyAsDevice *)handle ; + CyAsCheckDeviceReady(dev_p) ; + + /* + * Make sure Antioch is not in standby + */ + ret = CyAsMiscInStandby(dev_p, &standby) ; + if (ret != CY_AS_ERROR_SUCCESS) + return ret ; + if (standby) + return CY_AS_ERROR_IN_STANDBY ; + + /* Make sure the Antioch is not in suspend mode. */ + if (CyAsDeviceIsInSuspendMode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND ; + + /* Create the request to send to the West Bridge device */ + req_p = CyAsLLCreateRequest(dev_p, CY_RQT_RESERVE_LNA_BOOT_AREA, CY_RQT_GENERAL_RQT_CONTEXT, 1) ; + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)numzones) ; + + /* 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 ; + } + + 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_SUCCESS_FAILURE) + { + ret = CY_AS_ERROR_INVALID_RESPONSE ; + goto destroy ; + } + + ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ; + } + else + { + + ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_MISC_RESERVELNABOOTAREA, + 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX, req_p, + reply_p, CyAsMiscFuncCallback) ; + + 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 ; +} + +CyAsFuncCBNode* +CyAsCreateFuncCBNodeData(CyAsFunctionCallback cb, + uint32_t client, + CyAsFunctCBType type, + void* data) +{ + uint32_t state = CyAsHalDisableInterrupts() ; + CyAsFuncCBNode* node = (CyAsFuncCBNode*)CyAsHalCBAlloc(sizeof(CyAsFuncCBNode)) ; + CyAsHalEnableInterrupts(state) ; + if(node != 0) + { + node->nodeType = CYAS_FUNC_CB ; + node->cb_p = cb ; + node->client_data = client ; + node->dataType = type ; + if(data != 0) + node->dataType |= CY_FUNCT_CB_DATA ; + else + node->dataType |= CY_FUNCT_CB_NODATA ; + node->data = data ; + node->next_p = 0 ; + } + return node ; +} + +CyAsFuncCBNode* +CyAsCreateFuncCBNode(CyAsFunctionCallback cb, + uint32_t client) +{ + return CyAsCreateFuncCBNodeData(cb, client, CY_FUNCT_CB_NODATA, 0) ; +} + +void +CyAsDestroyFuncCBNode(CyAsFuncCBNode* node) +{ + uint32_t state ; + + node->nodeType = CYAS_INVALID ; + state = CyAsHalDisableInterrupts() ; + CyAsHalCBFree(node) ; + CyAsHalEnableInterrupts(state) ; +} + +CyAsUsbFuncCBNode* +CyAsCreateUsbFuncCBNode(CyAsUsbFunctionCallback cb, uint32_t client) +{ + uint32_t state = CyAsHalDisableInterrupts() ; + CyAsUsbFuncCBNode * node = (CyAsUsbFuncCBNode *)CyAsHalCBAlloc(sizeof(CyAsUsbFuncCBNode)) ; + CyAsHalEnableInterrupts(state) ; + if(node != 0) + { + node->type = CYAS_USB_FUNC_CB ; + node->cb_p = cb ; + node->client_data = client ; + node->next_p = 0 ; + } + return node ; +} + +void +CyAsDestroyUsbFuncCBNode(CyAsUsbFuncCBNode* node) +{ + uint32_t state ; + + node->type = CYAS_INVALID ; + state = CyAsHalDisableInterrupts() ; + CyAsHalCBFree(node) ; + CyAsHalEnableInterrupts(state) ; +} + +CyAsUsbIoCBNode* +CyAsCreateUsbIoCBNode(CyAsUsbIoCallback cb) +{ + uint32_t state = CyAsHalDisableInterrupts() ; + CyAsUsbIoCBNode * node = (CyAsUsbIoCBNode *)CyAsHalCBAlloc(sizeof(CyAsUsbIoCBNode)) ; + CyAsHalEnableInterrupts(state) ; + if(node != 0) + { + node->type = CYAS_USB_IO_CB ; + node->cb_p = cb ; + node->next_p = 0 ; + } + return node ; +} + +void +CyAsDestroyUsbIoCBNode(CyAsUsbIoCBNode* node) +{ + uint32_t state ; + + node->type = CYAS_INVALID ; + + state = CyAsHalDisableInterrupts() ; + CyAsHalCBFree(node) ; + CyAsHalEnableInterrupts(state) ; +} + +CyAsStorageIoCBNode* +CyAsCreateStorageIoCBNode(CyAsStorageCallback cb, CyAsMediaType media, uint32_t device_index, + uint32_t unit, uint32_t block_addr, CyAsOperType oper, + CyAsLLRequestResponse* req_p, CyAsLLRequestResponse* reply_p) +{ + uint32_t state = CyAsHalDisableInterrupts() ; + CyAsStorageIoCBNode * node = (CyAsStorageIoCBNode *)CyAsHalCBAlloc(sizeof(CyAsStorageIoCBNode)) ; + CyAsHalEnableInterrupts(state) ; + if(node != 0) + { + node->type = CYAS_STORAGE_IO_CB ; + node->cb_p = cb ; + node->media = media ; + node->device_index = device_index ; + node->unit = unit ; + node->block_addr = block_addr ; + node->oper = oper ; + node->req_p = req_p ; + node->reply_p = reply_p ; + node->next_p = 0 ; + } + return node ; +} + +void +CyAsDestroyStorageIoCBNode(CyAsStorageIoCBNode* node) +{ + uint32_t state ; + node->type = CYAS_INVALID ; + state = CyAsHalDisableInterrupts() ; + CyAsHalCBFree(node) ; + CyAsHalEnableInterrupts(state) ; +} + +CyAsCBQueue * +CyAsCreateCBQueue(CyAsCBNodeType type) +{ + uint32_t state = CyAsHalDisableInterrupts() ; + CyAsCBQueue * queue = (CyAsCBQueue *)CyAsHalCBAlloc(sizeof(CyAsCBQueue)) ; + CyAsHalEnableInterrupts(state) ; + if(queue) + { + queue->type = type ; + queue->head_p = 0 ; + queue->tail_p = 0 ; + queue->count = 0 ; + } + + return queue ; +} + +void +CyAsDestroyCBQueue(CyAsCBQueue* queue) +{ + uint32_t state ; + queue->type = CYAS_INVALID ; + queue->head_p = 0 ; + queue->tail_p = 0 ; + queue->count = 0 ; + state = CyAsHalDisableInterrupts() ; + CyAsHalCBFree(queue) ; + CyAsHalEnableInterrupts(state) ; +} + +/* Inserts a CyAsCBNode into the queue, the node type must match the queue type*/ +void +CyAsInsertCBNode(CyAsCBQueue * queue_p, void* cbnode) +{ + uint32_t int_state ; + + int_state = CyAsHalDisableInterrupts() ; + + CyAsHalAssert(queue_p != 0) ; + + switch (queue_p->type) + { + case CYAS_USB_FUNC_CB: + { + CyAsUsbFuncCBNode* node = (CyAsUsbFuncCBNode*)cbnode ; + CyAsUsbFuncCBNode* tail = (CyAsUsbFuncCBNode*)queue_p->tail_p ; + + CyAsHalAssert(node->type == CYAS_USB_FUNC_CB) ; + CyAsHalAssert(tail == 0 || tail->type == CYAS_USB_FUNC_CB) ; + if(queue_p->head_p == 0) + queue_p->head_p = node ; + else + tail->next_p = node ; + + queue_p->tail_p = node ; + } + break ; + + case CYAS_USB_IO_CB: + { + CyAsUsbIoCBNode* node = (CyAsUsbIoCBNode*)cbnode ; + CyAsUsbIoCBNode* tail = (CyAsUsbIoCBNode*)queue_p->tail_p ; + + CyAsHalAssert(node->type == CYAS_USB_IO_CB) ; + CyAsHalAssert(tail == 0 || tail->type == CYAS_USB_IO_CB) ; + if(queue_p->head_p == 0) + queue_p->head_p = node ; + else + tail->next_p = node ; + + queue_p->tail_p = node ; + } + break ; + + case CYAS_STORAGE_IO_CB: + { + CyAsStorageIoCBNode* node = (CyAsStorageIoCBNode*)cbnode ; + CyAsStorageIoCBNode* tail = (CyAsStorageIoCBNode*)queue_p->tail_p ; + + CyAsHalAssert(node->type == CYAS_STORAGE_IO_CB) ; + CyAsHalAssert(tail == 0 || tail->type == CYAS_STORAGE_IO_CB) ; + if(queue_p->head_p == 0) + queue_p->head_p = node ; + else + tail->next_p = node ; + + queue_p->tail_p = node ; + } + break ; + + case CYAS_FUNC_CB: + { + CyAsFuncCBNode* node = (CyAsFuncCBNode*)cbnode ; + CyAsFuncCBNode* tail = (CyAsFuncCBNode*)queue_p->tail_p ; + + CyAsHalAssert(node->nodeType == CYAS_FUNC_CB) ; + CyAsHalAssert(tail == 0 || tail->nodeType == CYAS_FUNC_CB) ; + if(queue_p->head_p == 0) + queue_p->head_p = node ; + else + tail->next_p = node ; + + queue_p->tail_p = node ; + } + break ; + + default: + CyAsHalAssert(CyFalse) ; + break ; + } + + queue_p->count++ ; + + CyAsHalEnableInterrupts(int_state) ; +} + +/* Removes the tail node from the queue and frees it */ +void +CyAsRemoveCBTailNode(CyAsCBQueue *queue_p) +{ + uint32_t int_state ; + + int_state = CyAsHalDisableInterrupts () ; + + if (queue_p->count > 0) + { + /* + * The worst case length of the queue should be under 10 elements, and the average + * case should be just 1 element. So, we just employ a linear search to find the node + * to be freed. + */ + switch (queue_p->type) + { + case CYAS_FUNC_CB: + { + CyAsFuncCBNode* node = (CyAsFuncCBNode*)queue_p->head_p ; + CyAsFuncCBNode* tail = (CyAsFuncCBNode*)queue_p->tail_p ; + if (node != tail) + { + while (node->next_p != tail) + node = node->next_p ; + node->next_p = 0 ; + queue_p->tail_p = node ; + } + CyAsDestroyFuncCBNode (tail) ; + } + break ; + + case CYAS_USB_FUNC_CB: + { + CyAsUsbFuncCBNode* node = (CyAsUsbFuncCBNode*)queue_p->head_p ; + CyAsUsbFuncCBNode* tail = (CyAsUsbFuncCBNode*)queue_p->tail_p ; + if (node != tail) + { + while (node->next_p != tail) + node = node->next_p ; + node->next_p = 0 ; + queue_p->tail_p = node ; + } + + CyAsDestroyUsbFuncCBNode (tail) ; + } + break ; + + case CYAS_USB_IO_CB: + { + CyAsUsbIoCBNode* node = (CyAsUsbIoCBNode*)queue_p->head_p ; + CyAsUsbIoCBNode* tail = (CyAsUsbIoCBNode*)queue_p->tail_p ; + if (node != tail) + { + while (node->next_p != tail) + node = node->next_p ; + node->next_p = 0 ; + queue_p->tail_p = node ; + } + CyAsDestroyUsbIoCBNode (tail) ; + } + break ; + + case CYAS_STORAGE_IO_CB: + { + CyAsStorageIoCBNode* node = (CyAsStorageIoCBNode*)queue_p->head_p ; + CyAsStorageIoCBNode* tail = (CyAsStorageIoCBNode*)queue_p->tail_p ; + if (node != tail) + { + while (node->next_p != tail) + node = node->next_p ; + node->next_p = 0 ; + queue_p->tail_p = node ; + } + CyAsDestroyStorageIoCBNode (tail) ; + } + break ; + + default: + CyAsHalAssert (CyFalse) ; + } + + queue_p->count-- ; + if (queue_p->count == 0) + { + queue_p->head_p = 0 ; + queue_p->tail_p = 0 ; + } + } + + CyAsHalEnableInterrupts (int_state) ; +} + +/* Removes the first CyAsCBNode from the queue and frees it */ +void +CyAsRemoveCBNode(CyAsCBQueue * queue_p) +{ + uint32_t int_state ; + + int_state = CyAsHalDisableInterrupts() ; + + CyAsHalAssert(queue_p->count >= 0) ; + if(queue_p->count > 0) + { + if(queue_p->type == CYAS_USB_FUNC_CB) + { + CyAsUsbFuncCBNode* node = (CyAsUsbFuncCBNode*)queue_p->head_p ; + queue_p->head_p = node->next_p ; + CyAsDestroyUsbFuncCBNode(node) ; + } + else if(queue_p->type == CYAS_USB_IO_CB) + { + CyAsUsbIoCBNode* node = (CyAsUsbIoCBNode*)queue_p->head_p ; + queue_p->head_p = node->next_p ; + CyAsDestroyUsbIoCBNode(node) ; + } + else if(queue_p->type == CYAS_STORAGE_IO_CB) + { + CyAsStorageIoCBNode* node = (CyAsStorageIoCBNode*)queue_p->head_p ; + queue_p->head_p = node->next_p ; + CyAsDestroyStorageIoCBNode(node) ; + } + else if(queue_p->type == CYAS_FUNC_CB) + { + CyAsFuncCBNode* node = (CyAsFuncCBNode*)queue_p->head_p ; + queue_p->head_p = node->next_p ; + CyAsDestroyFuncCBNode(node) ; + } + else + { + CyAsHalAssert(CyFalse) ; + } + + queue_p->count-- ; + if(queue_p->count == 0) + { + queue_p->head_p = 0 ; + queue_p->tail_p = 0 ; + } + } + + CyAsHalEnableInterrupts(int_state) ; +} + +void MyPrintFuncCBNode(CyAsFuncCBNode* node) +{ + CyAsFunctCBType type = CyAsFunctCBTypeGetType(node->dataType) ; + CyAsHalPrintMessage("[cd:%2u dt:%2u cb:0x%08x d:0x%08x nt:%1i]", + node->client_data, type, (uint32_t)node->cb_p, (uint32_t)node->data, node->nodeType) ; +} + +void MyPrintCBQueue(CyAsCBQueue* queue_p) +{ + uint32_t i = 0 ; + + CyAsHalPrintMessage("| Count: %u Type: ", queue_p->count) ; + + if(queue_p->type == CYAS_USB_FUNC_CB) + { + CyAsHalPrintMessage("USB_FUNC_CB\n") ; + } + else if(queue_p->type == CYAS_USB_IO_CB) + { + CyAsHalPrintMessage("USB_IO_CB\n") ; + } + else if(queue_p->type == CYAS_STORAGE_IO_CB) + { + CyAsHalPrintMessage("STORAGE_IO_CB\n") ; + } + else if(queue_p->type == CYAS_FUNC_CB) + { + CyAsFuncCBNode* node = (CyAsFuncCBNode*)queue_p->head_p ; + CyAsHalPrintMessage("FUNC_CB\n") ; + if(queue_p->count > 0) + { + CyAsHalPrintMessage("| Head->") ; + + for(i = 0; i < queue_p->count; i++) + { + if(node) + { + CyAsHalPrintMessage("->") ; + MyPrintFuncCBNode(node) ; + node = node->next_p ; + } + else + CyAsHalPrintMessage("->[NULL]\n") ; + } + + CyAsHalPrintMessage("\n| Tail->") ; + MyPrintFuncCBNode((CyAsFuncCBNode*)queue_p->tail_p) ; + CyAsHalPrintMessage("\n") ; + } + } + else + { + CyAsHalPrintMessage("INVALID\n") ; + } + + CyAsHalPrintMessage("|----------\n") ; +} + + +/* Removes and frees all pending callbacks */ +void +CyAsClearCBQueue(CyAsCBQueue * queue_p) +{ + uint32_t int_state = CyAsHalDisableInterrupts() ; + + while(queue_p->count != 0) + CyAsRemoveCBNode(queue_p) ; + + CyAsHalEnableInterrupts(int_state) ; +} + +CyAsReturnStatus_t +CyAsMiscSendRequest(CyAsDevice* dev_p, + CyAsFunctionCallback cb, + uint32_t client, + CyAsFunctCBType type, + void* data, + CyAsCBQueue* queue, + uint16_t req_type, + CyAsLLRequestResponse *req_p, + CyAsLLRequestResponse *reply_p, + CyAsResponseCallback rcb) +{ + + CyAsFuncCBNode* cbnode = CyAsCreateFuncCBNodeData(cb, client, type, data) ; + CyAsReturnStatus_t ret ; + + if(cbnode == 0) + return CY_AS_ERROR_OUT_OF_MEMORY ; + else + CyAsInsertCBNode(queue, cbnode) ; + + req_p->flags |= req_type ; + + ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyFalse, rcb) ; + if (ret != CY_AS_ERROR_SUCCESS) + { + CyAsRemoveCBTailNode(queue) ; + } + + return ret ; +} + +void +CyAsMiscCancelExRequests(CyAsDevice *dev_p) +{ + int i ; + for(i = 0; i < CY_RQT_CONTEXT_COUNT; i++) + CyAsLLRemoveAllRequests(dev_p, dev_p->context[i]) ; +} + + +static void +CyAsMiscFuncCallback(CyAsDevice *dev_p, + uint8_t context, + CyAsLLRequestResponse *rqt, + CyAsLLRequestResponse *resp, + CyAsReturnStatus_t stat) +{ + CyAsFuncCBNode* node = NULL ; + CyAsReturnStatus_t ret ; + + 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 ; + uint32_t type ; + uint8_t cntxt ; + + CyAsHalAssert(exRequest || msRequest) ; + (void) exRequest; + (void) msRequest; + (void)context ; + + cntxt = CyAsLLRequestResponse_GetContext(rqt) ; + code = CyAsLLRequestResponse_GetCode(rqt) ; + + switch(cntxt) + { + case CY_RQT_GENERAL_RQT_CONTEXT: + CyAsHalAssert(dev_p->func_cbs_misc->count != 0) ; + CyAsHalAssert(dev_p->func_cbs_misc->type == CYAS_FUNC_CB) ; + node = (CyAsFuncCBNode*)dev_p->func_cbs_misc->head_p ; + type = CyAsFunctCBTypeGetType(node->dataType) ; + + switch(code) + { + case CY_RQT_GET_FIRMWARE_VERSION: + CyAsHalAssert(node->data != 0) ; + CyAsHalAssert(type == CY_FUNCT_CB_MISC_GETFIRMWAREVERSION) ; + ret = MyHandleResponseGetFirmwareVersion(dev_p, rqt, resp, (CyAsGetFirmwareVersionData*)node->data) ; + break ; + case CY_RQT_READ_MCU_REGISTER: + CyAsHalAssert(node->data != 0) ; + CyAsHalAssert(type == CY_FUNCT_CB_MISC_READMCUREGISTER) ; + ret = MyHandleResponseReadMCURegister(dev_p, rqt, resp, (uint8_t*)node->data) ; + break ; + case CY_RQT_GET_GPIO_STATE: + CyAsHalAssert(node->data != 0) ; + CyAsHalAssert(type == CY_FUNCT_CB_MISC_GETGPIOVALUE) ; + ret = MyHandleResponseGetGpioValue(dev_p, rqt, resp, (uint8_t*)node->data) ; + break ; + case CY_RQT_SET_SD_CLOCK_FREQ: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_SETSDFREQ) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + case CY_RQT_CONTROL_ANTIOCH_HEARTBEAT: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_HEARTBEATCONTROL) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + case CY_RQT_WRITE_MCU_REGISTER: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_WRITEMCUREGISTER) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + case CY_RQT_STORAGE_MEDIA_CHANGED: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_STORAGECHANGED) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + case CY_RQT_SET_GPIO_STATE: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_SETGPIOVALUE) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + case CY_RQT_SET_TRACE_LEVEL: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_SETTRACELEVEL) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + if (ret == CY_AS_ERROR_INVALID_RESPONSE) + ret = CY_AS_ERROR_NOT_SUPPORTED ; + break ; + case CY_RQT_PREPARE_FOR_STANDBY: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_ENTERSTANDBY) ; + ret = MyHandleResponseEnterStandby(dev_p, rqt, resp, (CyBool)node->data) ; + break ; + case CY_RQT_ENTER_SUSPEND_MODE: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_ENTERSUSPEND) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + if (ret == CY_AS_ERROR_SUCCESS) + { + CyAsDeviceSetSuspendMode(dev_p) ; + } + break ; + case CY_RQT_RESERVE_LNA_BOOT_AREA: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_RESERVELNABOOTAREA) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + case CY_RQT_SDPOLARITY: + CyAsHalAssert(type == CY_FUNCT_CB_MISC_SETSDPOLARITY) ; + ret = MyHandleResponseNoData(dev_p, rqt, resp) ; + break ; + + + default: + ret = CY_AS_ERROR_INVALID_RESPONSE ; + CyAsHalAssert(CyFalse) ; + break ; + } + break ; + + case CY_RQT_RESOURCE_RQT_CONTEXT: + CyAsHalAssert(dev_p->func_cbs_res->count != 0) ; + CyAsHalAssert(dev_p->func_cbs_res->type == CYAS_FUNC_CB) ; + node = (CyAsFuncCBNode*)dev_p->func_cbs_res->head_p ; + type = CyAsFunctCBTypeGetType(node->dataType) ; + + switch(code) + { + case CY_RQT_ACQUIRE_RESOURCE: + /* The node->data field is actually an enum value which could be + 0, thus no assert is done */ + CyAsHalAssert(type == CY_FUNCT_CB_MISC_ACQUIRERESOURCE) ; + ret = MyHandleResponseAcquireResource(dev_p, rqt, resp, (CyAsResourceType*)node->data) ; + break ; + default: + ret = CY_AS_ERROR_INVALID_RESPONSE ; + CyAsHalAssert(CyFalse) ; + break ; + } + 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 */ + node->cb_p((CyAsDeviceHandle)dev_p, stat, node->client_data, (CyAsFunctCBType)node->dataType, node->data) ; + if(cntxt == CY_RQT_GENERAL_RQT_CONTEXT) + CyAsRemoveCBNode(dev_p->func_cbs_misc) ; + else + CyAsRemoveCBNode(dev_p->func_cbs_res) ; + +} + + +/* This includes the implementation of the deprecated functions for backward + * compatibility + */ +#include "cyasmisc_dep_impl.h" + +/*[]*/ +