aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/westbridge/astoria/api/src
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/westbridge/astoria/api/src')
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyasdma.c1107
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyasintr.c143
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c358
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyaslowlevel.c1264
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyasmisc.c3474
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyasmtp.c1128
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyasstorage.c4104
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyasusb.c3718
8 files changed, 15296 insertions, 0 deletions
diff --git a/drivers/staging/westbridge/astoria/api/src/cyasdma.c b/drivers/staging/westbridge/astoria/api/src/cyasdma.c
new file mode 100644
index 000000000000..de67e1310503
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyasdma.c
@@ -0,0 +1,1107 @@
+/* Cypress West Bridge API source file (cyasdma.c)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyasdma.h"
+#include "../../include/linux/westbridge/cyaslowlevel.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+#include "../../include/linux/westbridge/cyasregs.h"
+
+/*
+ * Add the DMA queue entry to the free list to be re-used later
+ */
+static void
+cy_as_dma_add_request_to_free_queue(cy_as_device *dev_p,
+ cy_as_dma_queue_entry *req_p)
+{
+ uint32_t imask;
+ imask = cy_as_hal_disable_interrupts();
+
+ req_p->next_p = dev_p->dma_freelist_p;
+ dev_p->dma_freelist_p = req_p;
+
+ cy_as_hal_enable_interrupts(imask);
+}
+
+/*
+ * Get a DMA queue entry from the free list.
+ */
+static cy_as_dma_queue_entry *
+cy_as_dma_get_dma_queue_entry(cy_as_device *dev_p)
+{
+ cy_as_dma_queue_entry *req_p;
+ uint32_t imask;
+
+ cy_as_hal_assert(dev_p->dma_freelist_p != 0);
+
+ imask = cy_as_hal_disable_interrupts();
+ req_p = dev_p->dma_freelist_p;
+ dev_p->dma_freelist_p = req_p->next_p;
+ cy_as_hal_enable_interrupts(imask);
+
+ return req_p;
+}
+
+/*
+ * Set the maximum size that the West Bridge hardware
+ * can handle in a single DMA operation. This size
+ * may change for the P <-> U endpoints as a function
+ * of the endpoint type and whether we are running
+ * at full speed or high speed.
+ */
+cy_as_return_status_t
+cy_as_dma_set_max_dma_size(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, uint32_t size)
+{
+ /* In MTP mode, EP2 is allowed to have all max sizes. */
+ if ((!dev_p->is_mtp_firmware) || (ep != 0x02)) {
+ if (size < 64 || size > 1024)
+ return CY_AS_ERROR_INVALID_SIZE;
+ }
+
+ CY_AS_NUM_EP(dev_p, ep)->maxhwdata = (uint16_t)size;
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+ * The callback for requests sent to West Bridge
+ * to relay endpoint data. Endpoint data for EP0
+ * and EP1 are sent using mailbox requests. This
+ * is the callback that is called when a response
+ * to a mailbox request to send data is received.
+ */
+static void
+cy_as_dma_request_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *resp_p,
+ cy_as_return_status_t ret)
+{
+ uint16_t v;
+ uint16_t datacnt;
+ cy_as_end_point_number_t ep;
+
+ (void)context;
+
+ cy_as_log_debug_message(5, "cy_as_dma_request_callback called");
+
+ /*
+ * extract the return code from the firmware
+ */
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if (cy_as_ll_request_response__get_code(resp_p) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word(resp_p, 0);
+ }
+
+ /*
+ * extract the endpoint number and the transferred byte count
+ * from the request.
+ */
+ v = cy_as_ll_request_response__get_word(req_p, 0);
+ ep = (cy_as_end_point_number_t)((v >> 13) & 0x01);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ /*
+ * if the firmware returns success,
+ * all of the data requested was
+ * transferred. there are no partial
+ * transfers.
+ */
+ datacnt = v & 0x3FF;
+ } else {
+ /*
+ * if the firmware returned an error, no data was transferred.
+ */
+ datacnt = 0;
+ }
+
+ /*
+ * queue the request and response data structures for use with the
+ * next EP0 or EP1 request.
+ */
+ if (ep == 0) {
+ dev_p->usb_ep0_dma_req = req_p;
+ dev_p->usb_ep0_dma_resp = resp_p;
+ } else {
+ dev_p->usb_ep1_dma_req = req_p;
+ dev_p->usb_ep1_dma_resp = resp_p;
+ }
+
+ /*
+ * call the DMA complete function so we can
+ * signal that this portion of the transfer
+ * has completed. if the low level request
+ * was canceled, we do not need to signal
+ * the completed function as the only way a
+ * cancel can happen is via the DMA cancel
+ * function.
+ */
+ if (ret != CY_AS_ERROR_CANCELED)
+ cy_as_dma_completed_callback(dev_p->tag, ep, datacnt, ret);
+}
+
+/*
+ * Set the DRQ mask register for the given endpoint number. If state is
+ * CyTrue, the DRQ interrupt for the given endpoint is enabled, otherwise
+ * it is disabled.
+ */
+static void
+cy_as_dma_set_drq(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, cy_bool state)
+{
+ uint16_t mask;
+ uint16_t v;
+ uint32_t intval;
+
+ /*
+ * there are not DRQ register bits for EP0 and EP1
+ */
+ if (ep == 0 || ep == 1)
+ return;
+
+ /*
+ * disable interrupts while we do this to be sure the state of the
+ * DRQ mask register is always well defined.
+ */
+ intval = cy_as_hal_disable_interrupts();
+
+ /*
+ * set the DRQ bit to the given state for the ep given
+ */
+ mask = (1 << ep);
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_DRQ_MASK);
+
+ if (state)
+ v |= mask;
+ else
+ v &= ~mask;
+
+ cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_DRQ_MASK, v);
+ cy_as_hal_enable_interrupts(intval);
+}
+
+/*
+* Send the next DMA request for the endpoint given
+*/
+static void
+cy_as_dma_send_next_dma_request(cy_as_device *dev_p, cy_as_dma_end_point *ep_p)
+{
+ uint32_t datacnt;
+ void *buf_p;
+ cy_as_dma_queue_entry *dma_p;
+
+ cy_as_log_debug_message(6, "cy_as_dma_send_next_dma_request called");
+
+ /* If the queue is empty, nothing to do */
+ dma_p = ep_p->queue_p;
+ if (dma_p == 0) {
+ /*
+ * there are no pending DMA requests
+ * for this endpoint. disable the DRQ
+ * mask bits to insure no interrupts
+ * will be triggered by this endpoint
+ * until someone is interested in the data.
+ */
+ cy_as_dma_set_drq(dev_p, ep_p->ep, cy_false);
+ return;
+ }
+
+ cy_as_dma_end_point_set_running(ep_p);
+
+ /*
+ * get the number of words that still
+ * need to be xferred in this request.
+ */
+ datacnt = dma_p->size - dma_p->offset;
+ cy_as_hal_assert(datacnt >= 0);
+
+ /*
+ * the HAL layer should never limit the size
+ * of the transfer to something less than the
+ * maxhwdata otherwise, the data will be sent
+ * in packets that are not correct in size.
+ */
+ cy_as_hal_assert(ep_p->maxhaldata == CY_AS_DMA_MAX_SIZE_HW_SIZE
+ || ep_p->maxhaldata >= ep_p->maxhwdata);
+
+ /*
+ * update the number of words that need to be xferred yet
+ * based on the limits of the HAL layer.
+ */
+ if (ep_p->maxhaldata == CY_AS_DMA_MAX_SIZE_HW_SIZE) {
+ if (datacnt > ep_p->maxhwdata)
+ datacnt = ep_p->maxhwdata;
+ } else {
+ if (datacnt > ep_p->maxhaldata)
+ datacnt = ep_p->maxhaldata;
+ }
+
+ /*
+ * find a pointer to the data that needs to be transferred
+ */
+ buf_p = (((char *)dma_p->buf_p) + dma_p->offset);
+
+ /*
+ * mark a request in transit
+ */
+ cy_as_dma_end_point_set_in_transit(ep_p);
+
+ if (ep_p->ep == 0 || ep_p->ep == 1) {
+ /*
+ * if this is a WRITE request on EP0 and EP1
+ * we write the data via an EP_DATA request
+ * to west bridge via the mailbox registers.
+ * if this is a READ request, we do nothing
+ * and the data will arrive via an EP_DATA
+ * request from west bridge. in the request
+ * handler for the USB context we will pass
+ * the data back into the DMA module.
+ */
+ if (dma_p->readreq == cy_false) {
+ uint16_t v;
+ uint16_t len;
+ cy_as_ll_request_response *resp_p;
+ cy_as_ll_request_response *req_p;
+ cy_as_return_status_t ret;
+
+ len = (uint16_t)(datacnt / 2);
+ if (datacnt % 2)
+ len++;
+
+ len++;
+
+ if (ep_p->ep == 0) {
+ req_p = dev_p->usb_ep0_dma_req;
+ resp_p = dev_p->usb_ep0_dma_resp;
+ dev_p->usb_ep0_dma_req = 0;
+ dev_p->usb_ep0_dma_resp = 0;
+ } else {
+ req_p = dev_p->usb_ep1_dma_req;
+ resp_p = dev_p->usb_ep1_dma_resp;
+ dev_p->usb_ep1_dma_req = 0;
+ dev_p->usb_ep1_dma_resp = 0;
+ }
+
+ cy_as_hal_assert(req_p != 0);
+ cy_as_hal_assert(resp_p != 0);
+ cy_as_hal_assert(len <= 64);
+
+ cy_as_ll_init_request(req_p, CY_RQT_USB_EP_DATA,
+ CY_RQT_USB_RQT_CONTEXT, len);
+
+ v = (uint16_t)(datacnt | (ep_p->ep << 13) | (1 << 14));
+ if (dma_p->offset == 0)
+ v |= (1 << 12);/* Set the first packet bit */
+ if (dma_p->offset + datacnt == dma_p->size)
+ v |= (1 << 11);/* Set the last packet bit */
+
+ cy_as_ll_request_response__set_word(req_p, 0, v);
+ cy_as_ll_request_response__pack(req_p,
+ 1, datacnt, buf_p);
+
+ cy_as_ll_init_response(resp_p, 1);
+
+ ret = cy_as_ll_send_request(dev_p, req_p, resp_p,
+ cy_false, cy_as_dma_request_callback);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ cy_as_log_debug_message(5,
+ "+++ send EP 0/1 data via mailbox registers");
+ else
+ cy_as_log_debug_message(5,
+ "+++ error sending EP 0/1 data via mailbox "
+ "registers - CY_AS_ERROR_TIMEOUT");
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ cy_as_dma_completed_callback(dev_p->tag,
+ ep_p->ep, 0, ret);
+ }
+ } else {
+ /*
+ * this is a DMA request on an endpoint that is accessible
+ * via the P port. ask the HAL DMA capabilities to
+ * perform this. the amount of data sent is limited by the
+ * HAL max size as well as what we need to send. if the
+ * ep_p->maxhaldata is set to a value larger than the
+ * endpoint buffer size, then we will pass more than a
+ * single buffer worth of data to the HAL layer and expect
+ * the HAL layer to divide the data into packets. the last
+ * parameter here (ep_p->maxhwdata) gives the packet size for
+ * the data so the HAL layer knows what the packet size should
+ * be.
+ */
+ if (cy_as_dma_end_point_is_direction_in(ep_p))
+ cy_as_hal_dma_setup_write(dev_p->tag,
+ ep_p->ep, buf_p, datacnt, ep_p->maxhwdata);
+ else
+ cy_as_hal_dma_setup_read(dev_p->tag,
+ ep_p->ep, buf_p, datacnt, ep_p->maxhwdata);
+
+ /*
+ * the DRQ interrupt for this endpoint should be enabled
+ * so that the data transfer progresses at interrupt time.
+ */
+ cy_as_dma_set_drq(dev_p, ep_p->ep, cy_true);
+ }
+}
+
+/*
+ * This function is called when the HAL layer has
+ * completed the last requested DMA operation.
+ * This function sends/receives the next batch of
+ * data associated with the current DMA request,
+ * or it is is complete, moves to the next DMA request.
+ */
+void
+cy_as_dma_completed_callback(cy_as_hal_device_tag tag,
+ cy_as_end_point_number_t ep, uint32_t cnt, cy_as_return_status_t status)
+{
+ uint32_t mask;
+ cy_as_dma_queue_entry *req_p;
+ cy_as_dma_end_point *ep_p;
+ cy_as_device *dev_p = cy_as_device_find_from_tag(tag);
+
+ /* Make sure the HAL layer gave us good parameters */
+ cy_as_hal_assert(dev_p != 0);
+ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
+ cy_as_hal_assert(ep < 16);
+
+
+ /* Get the endpoint ptr */
+ ep_p = CY_AS_NUM_EP(dev_p, ep);
+ cy_as_hal_assert(ep_p->queue_p != 0);
+
+ /* Get a pointer to the current entry in the queue */
+ mask = cy_as_hal_disable_interrupts();
+ req_p = ep_p->queue_p;
+
+ /* Update the offset to reflect the data actually received or sent */
+ req_p->offset += cnt;
+
+ /*
+ * if we are still sending/receiving the current packet,
+ * send/receive the next chunk basically we keep going
+ * if we have not sent/received enough data, and we are
+ * not doing a packet operation, and the last packet
+ * sent or received was a full sized packet. in other
+ * words, when we are NOT doing a packet operation, a
+ * less than full size packet (a short packet) will
+ * terminate the operation.
+ *
+ * note: if this is EP1 request and the request has
+ * timed out, it means the buffer is not free.
+ * we have to resend the data.
+ *
+ * note: for the MTP data transfers, the DMA transfer
+ * for the next packet can only be started asynchronously,
+ * after a firmware event notifies that the device is ready.
+ */
+ if (((req_p->offset != req_p->size) && (req_p->packet == cy_false) &&
+ ((cnt == ep_p->maxhaldata) || ((cnt == ep_p->maxhwdata) &&
+ ((ep != CY_AS_MTP_READ_ENDPOINT) ||
+ (cnt == dev_p->usb_max_tx_size)))))
+ || ((ep == 1) && (status == CY_AS_ERROR_TIMEOUT))) {
+ cy_as_hal_enable_interrupts(mask);
+
+ /*
+ * and send the request again to send the next block of
+ * data. special handling for MTP transfers on E_ps 2
+ * and 6. the send_next_request will be processed based
+ * on the event sent by the firmware.
+ */
+ if ((ep == CY_AS_MTP_WRITE_ENDPOINT) || (
+ (ep == CY_AS_MTP_READ_ENDPOINT) &&
+ (!cy_as_dma_end_point_is_direction_in(ep_p))))
+ cy_as_dma_end_point_set_stopped(ep_p);
+ else
+ cy_as_dma_send_next_dma_request(dev_p, ep_p);
+ } else {
+ /*
+ * we get here if ...
+ * we have sent or received all of the data
+ * or
+ * we are doing a packet operation
+ * or
+ * we receive a short packet
+ */
+
+ /*
+ * remove this entry from the DMA queue for this endpoint.
+ */
+ cy_as_dma_end_point_clear_in_transit(ep_p);
+ ep_p->queue_p = req_p->next_p;
+ if (ep_p->last_p == req_p) {
+ /*
+ * we have removed the last packet from the DMA queue,
+ * disable the interrupt associated with this interrupt.
+ */
+ ep_p->last_p = 0;
+ cy_as_hal_enable_interrupts(mask);
+ cy_as_dma_set_drq(dev_p, ep, cy_false);
+ } else
+ cy_as_hal_enable_interrupts(mask);
+
+ if (req_p->cb) {
+ /*
+ * if the request has a callback associated with it,
+ * call the callback to tell the interested party that
+ * this DMA request has completed.
+ *
+ * note, we set the in_callback bit to insure that we
+ * cannot recursively call an API function that is
+ * synchronous only from a callback.
+ */
+ cy_as_device_set_in_callback(dev_p);
+ (*req_p->cb)(dev_p, ep, req_p->buf_p,
+ req_p->offset, status);
+ cy_as_device_clear_in_callback(dev_p);
+ }
+
+ /*
+ * we are done with this request, put it on the freelist to be
+ * reused at a later time.
+ */
+ cy_as_dma_add_request_to_free_queue(dev_p, req_p);
+
+ if (ep_p->queue_p == 0) {
+ /*
+ * if the endpoint is out of DMA entries, set the
+ * endpoint as stopped.
+ */
+ cy_as_dma_end_point_set_stopped(ep_p);
+
+ /*
+ * the DMA queue is empty, wake any task waiting on
+ * the QUEUE to drain.
+ */
+ if (cy_as_dma_end_point_is_sleeping(ep_p)) {
+ cy_as_dma_end_point_set_wake_state(ep_p);
+ cy_as_hal_wake(&ep_p->channel);
+ }
+ } else {
+ /*
+ * if the queued operation is a MTP transfer,
+ * wait until firmware event before sending
+ * down the next DMA request.
+ */
+ if ((ep == CY_AS_MTP_WRITE_ENDPOINT) ||
+ ((ep == CY_AS_MTP_READ_ENDPOINT) &&
+ (!cy_as_dma_end_point_is_direction_in(ep_p))) ||
+ ((ep == dev_p->storage_read_endpoint) &&
+ (!cy_as_device_is_p2s_dma_start_recvd(dev_p)))
+ || ((ep == dev_p->storage_write_endpoint) &&
+ (!cy_as_device_is_p2s_dma_start_recvd(dev_p))))
+ cy_as_dma_end_point_set_stopped(ep_p);
+ else
+ cy_as_dma_send_next_dma_request(dev_p, ep_p);
+ }
+ }
+}
+
+/*
+* This function is used to kick start DMA on a given
+* channel. If DMA is already running on the given
+* endpoint, nothing happens. If DMA is not running,
+* the first entry is pulled from the DMA queue and
+* sent/recevied to/from the West Bridge device.
+*/
+cy_as_return_status_t
+cy_as_dma_kick_start(cy_as_device *dev_p, cy_as_end_point_number_t ep)
+{
+ cy_as_dma_end_point *ep_p;
+ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
+
+ ep_p = CY_AS_NUM_EP(dev_p, ep);
+
+ /* We are already running */
+ if (cy_as_dma_end_point_is_running(ep_p))
+ return CY_AS_ERROR_SUCCESS;
+
+ cy_as_dma_send_next_dma_request(dev_p, ep_p);
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+ * This function stops the given endpoint. Stopping and endpoint cancels
+ * any pending DMA operations and frees all resources associated with the
+ * given endpoint.
+ */
+static cy_as_return_status_t
+cy_as_dma_stop_end_point(cy_as_device *dev_p, cy_as_end_point_number_t ep)
+{
+ cy_as_return_status_t ret;
+ cy_as_dma_end_point *ep_p = CY_AS_NUM_EP(dev_p, ep);
+
+ /*
+ * cancel any pending DMA requests associated with this endpoint. this
+ * cancels any DMA requests at the HAL layer as well as dequeues any
+ * request that is currently pending.
+ */
+ ret = cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /*
+ * destroy the sleep channel
+ */
+ if (!cy_as_hal_destroy_sleep_channel(&ep_p->channel)
+ && ret == CY_AS_ERROR_SUCCESS)
+ ret = CY_AS_ERROR_DESTROY_SLEEP_CHANNEL_FAILED;
+
+ /*
+ * free the memory associated with this endpoint
+ */
+ cy_as_hal_free(ep_p);
+
+ /*
+ * set the data structure ptr to something sane since the
+ * previous pointer is now free.
+ */
+ dev_p->endp[ep] = 0;
+
+ return ret;
+}
+
+/*
+ * This method stops the USB stack. This is an internal function that does
+ * all of the work of destroying the USB stack without the protections that
+ * we provide to the API (i.e. stopping at stack that is not running).
+ */
+static cy_as_return_status_t
+cy_as_dma_stop_internal(cy_as_device *dev_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_return_status_t lret;
+ cy_as_end_point_number_t i;
+
+ /*
+ * stop all of the endpoints. this cancels all DMA requests, and
+ * frees all resources associated with each endpoint.
+ */
+ for (i = 0; i < sizeof(dev_p->endp)/(sizeof(dev_p->endp[0])); i++) {
+ lret = cy_as_dma_stop_end_point(dev_p, i);
+ if (lret != CY_AS_ERROR_SUCCESS && ret == CY_AS_ERROR_SUCCESS)
+ ret = lret;
+ }
+
+ /*
+ * now, free the list of DMA requests structures that we use to manage
+ * DMA requests.
+ */
+ while (dev_p->dma_freelist_p) {
+ cy_as_dma_queue_entry *req_p;
+ uint32_t imask = cy_as_hal_disable_interrupts();
+
+ req_p = dev_p->dma_freelist_p;
+ dev_p->dma_freelist_p = req_p->next_p;
+
+ cy_as_hal_enable_interrupts(imask);
+
+ cy_as_hal_free(req_p);
+ }
+
+ cy_as_ll_destroy_request(dev_p, dev_p->usb_ep0_dma_req);
+ cy_as_ll_destroy_request(dev_p, dev_p->usb_ep1_dma_req);
+ cy_as_ll_destroy_response(dev_p, dev_p->usb_ep0_dma_resp);
+ cy_as_ll_destroy_response(dev_p, dev_p->usb_ep1_dma_resp);
+
+ return ret;
+}
+
+
+/*
+ * CyAsDmaStop()
+ *
+ * This function shuts down the DMA module. All resources
+ * associated with the DMA module will be freed. This
+ * routine is the API stop function. It insures that we
+ * are stopping a stack that is actually running and then
+ * calls the internal function to do the work.
+ */
+cy_as_return_status_t
+cy_as_dma_stop(cy_as_device *dev_p)
+{
+ cy_as_return_status_t ret;
+
+ ret = cy_as_dma_stop_internal(dev_p);
+ cy_as_device_set_dma_stopped(dev_p);
+
+ return ret;
+}
+
+/*
+ * CyAsDmaStart()
+ *
+ * This function intializes the DMA module to insure it is up and running.
+ */
+cy_as_return_status_t
+cy_as_dma_start(cy_as_device *dev_p)
+{
+ cy_as_end_point_number_t i;
+ uint16_t cnt;
+
+ if (cy_as_device_is_dma_running(dev_p))
+ return CY_AS_ERROR_ALREADY_RUNNING;
+
+ /*
+ * pre-allocate DMA queue structures to be used in the interrupt context
+ */
+ for (cnt = 0; cnt < 32; cnt++) {
+ cy_as_dma_queue_entry *entry_p = (cy_as_dma_queue_entry *)
+ cy_as_hal_alloc(sizeof(cy_as_dma_queue_entry));
+ if (entry_p == 0) {
+ cy_as_dma_stop_internal(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+ cy_as_dma_add_request_to_free_queue(dev_p, entry_p);
+ }
+
+ /*
+ * pre-allocate the DMA requests for sending EP0
+ * and EP1 data to west bridge
+ */
+ dev_p->usb_ep0_dma_req = cy_as_ll_create_request(dev_p,
+ CY_RQT_USB_EP_DATA, CY_RQT_USB_RQT_CONTEXT, 64);
+ dev_p->usb_ep1_dma_req = cy_as_ll_create_request(dev_p,
+ CY_RQT_USB_EP_DATA, CY_RQT_USB_RQT_CONTEXT, 64);
+
+ if (dev_p->usb_ep0_dma_req == 0 || dev_p->usb_ep1_dma_req == 0) {
+ cy_as_dma_stop_internal(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+ dev_p->usb_ep0_dma_req_save = dev_p->usb_ep0_dma_req;
+
+ dev_p->usb_ep0_dma_resp = cy_as_ll_create_response(dev_p, 1);
+ dev_p->usb_ep1_dma_resp = cy_as_ll_create_response(dev_p, 1);
+ if (dev_p->usb_ep0_dma_resp == 0 || dev_p->usb_ep1_dma_resp == 0) {
+ cy_as_dma_stop_internal(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+ dev_p->usb_ep0_dma_resp_save = dev_p->usb_ep0_dma_resp;
+
+ /*
+ * set the dev_p->endp to all zeros to insure cleanup is possible if
+ * an error occurs during initialization.
+ */
+ cy_as_hal_mem_set(dev_p->endp, 0, sizeof(dev_p->endp));
+
+ /*
+ * now, iterate through each of the endpoints and initialize each
+ * one.
+ */
+ for (i = 0; i < sizeof(dev_p->endp)/sizeof(dev_p->endp[0]); i++) {
+ dev_p->endp[i] = (cy_as_dma_end_point *)
+ cy_as_hal_alloc(sizeof(cy_as_dma_end_point));
+ if (dev_p->endp[i] == 0) {
+ cy_as_dma_stop_internal(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+ cy_as_hal_mem_set(dev_p->endp[i], 0,
+ sizeof(cy_as_dma_end_point));
+
+ dev_p->endp[i]->ep = i;
+ dev_p->endp[i]->queue_p = 0;
+ dev_p->endp[i]->last_p = 0;
+
+ cy_as_dma_set_drq(dev_p, i, cy_false);
+
+ if (!cy_as_hal_create_sleep_channel(&dev_p->endp[i]->channel))
+ return CY_AS_ERROR_CREATE_SLEEP_CHANNEL_FAILED;
+ }
+
+ /*
+ * tell the HAL layer who to call when the
+ * HAL layer completes a DMA request
+ */
+ cy_as_hal_dma_register_callback(dev_p->tag,
+ cy_as_dma_completed_callback);
+
+ /*
+ * mark DMA as up and running on this device
+ */
+ cy_as_device_set_dma_running(dev_p);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+* Wait for all entries in the DMA queue associated
+* the given endpoint to be drained. This function
+* will not return until all the DMA data has been
+* transferred.
+*/
+cy_as_return_status_t
+cy_as_dma_drain_queue(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, cy_bool kickstart)
+{
+ cy_as_dma_end_point *ep_p;
+ int loopcount = 1000;
+ uint32_t mask;
+
+ /*
+ * make sure the endpoint is valid
+ */
+ if (ep >= sizeof(dev_p->endp)/sizeof(dev_p->endp[0]))
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* Get the endpoint pointer based on the endpoint number */
+ ep_p = CY_AS_NUM_EP(dev_p, ep);
+
+ /*
+ * if the endpoint is empty of traffic, we return
+ * with success immediately
+ */
+ mask = cy_as_hal_disable_interrupts();
+ if (ep_p->queue_p == 0) {
+ cy_as_hal_enable_interrupts(mask);
+ return CY_AS_ERROR_SUCCESS;
+ } else {
+ /*
+ * add 10 seconds to the time out value for each 64 KB segment
+ * of data to be transferred.
+ */
+ if (ep_p->queue_p->size > 0x10000)
+ loopcount += ((ep_p->queue_p->size / 0x10000) * 1000);
+ }
+ cy_as_hal_enable_interrupts(mask);
+
+ /* If we are already sleeping on this endpoint, it is an error */
+ if (cy_as_dma_end_point_is_sleeping(ep_p))
+ return CY_AS_ERROR_NESTED_SLEEP;
+
+ /*
+ * we disable the endpoint while the queue drains to
+ * prevent any additional requests from being queued while we are waiting
+ */
+ cy_as_dma_enable_end_point(dev_p, ep,
+ cy_false, cy_as_direction_dont_change);
+
+ if (kickstart) {
+ /*
+ * now, kick start the DMA if necessary
+ */
+ cy_as_dma_kick_start(dev_p, ep);
+ }
+
+ /*
+ * check one last time before we begin sleeping to see if the
+ * queue is drained.
+ */
+ if (ep_p->queue_p == 0) {
+ cy_as_dma_enable_end_point(dev_p, ep, cy_true,
+ cy_as_direction_dont_change);
+ return CY_AS_ERROR_SUCCESS;
+ }
+
+ while (loopcount-- > 0) {
+ /*
+ * sleep for 10 ms maximum (per loop) while
+ * waiting for the transfer to complete.
+ */
+ cy_as_dma_end_point_set_sleep_state(ep_p);
+ cy_as_hal_sleep_on(&ep_p->channel, 10);
+
+ /* If we timed out, the sleep bit will still be set */
+ cy_as_dma_end_point_set_wake_state(ep_p);
+
+ /* Check the queue to see if is drained */
+ if (ep_p->queue_p == 0) {
+ /*
+ * clear the endpoint running and in transit flags
+ * for the endpoint, now that its DMA queue is empty.
+ */
+ cy_as_dma_end_point_clear_in_transit(ep_p);
+ cy_as_dma_end_point_set_stopped(ep_p);
+
+ cy_as_dma_enable_end_point(dev_p, ep,
+ cy_true, cy_as_direction_dont_change);
+ return CY_AS_ERROR_SUCCESS;
+ }
+ }
+
+ /*
+ * the DMA operation that has timed out can be cancelled, so that later
+ * operations on this queue can proceed.
+ */
+ cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_TIMEOUT);
+ cy_as_dma_enable_end_point(dev_p, ep,
+ cy_true, cy_as_direction_dont_change);
+ return CY_AS_ERROR_TIMEOUT;
+}
+
+/*
+* This function queues a write request in the DMA queue
+* for a given endpoint. The direction of the
+* entry will be inferred from the endpoint direction.
+*/
+cy_as_return_status_t
+cy_as_dma_queue_request(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, void *mem_p,
+ uint32_t size, cy_bool pkt, cy_bool readreq, cy_as_dma_callback cb)
+{
+ uint32_t mask;
+ cy_as_dma_queue_entry *entry_p;
+ cy_as_dma_end_point *ep_p;
+
+ /*
+ * make sure the endpoint is valid
+ */
+ if (ep >= sizeof(dev_p->endp)/sizeof(dev_p->endp[0]))
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* Get the endpoint pointer based on the endpoint number */
+ ep_p = CY_AS_NUM_EP(dev_p, ep);
+
+ if (!cy_as_dma_end_point_is_enabled(ep_p))
+ return CY_AS_ERROR_ENDPOINT_DISABLED;
+
+ entry_p = cy_as_dma_get_dma_queue_entry(dev_p);
+
+ entry_p->buf_p = mem_p;
+ entry_p->cb = cb;
+ entry_p->size = size;
+ entry_p->offset = 0;
+ entry_p->packet = pkt;
+ entry_p->readreq = readreq;
+
+ mask = cy_as_hal_disable_interrupts();
+ entry_p->next_p = 0;
+ if (ep_p->last_p)
+ ep_p->last_p->next_p = entry_p;
+ ep_p->last_p = entry_p;
+ if (ep_p->queue_p == 0)
+ ep_p->queue_p = entry_p;
+ cy_as_hal_enable_interrupts(mask);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+* This function enables or disables and endpoint for DMA
+* queueing. If an endpoint is disabled, any queue requests
+* continue to be processed, but no new requests can be queued.
+*/
+cy_as_return_status_t
+cy_as_dma_enable_end_point(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, cy_bool enable, cy_as_dma_direction dir)
+{
+ cy_as_dma_end_point *ep_p;
+
+ /*
+ * make sure the endpoint is valid
+ */
+ if (ep >= sizeof(dev_p->endp)/sizeof(dev_p->endp[0]))
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* Get the endpoint pointer based on the endpoint number */
+ ep_p = CY_AS_NUM_EP(dev_p, ep);
+
+ if (dir == cy_as_direction_out)
+ cy_as_dma_end_point_set_direction_out(ep_p);
+ else if (dir == cy_as_direction_in)
+ cy_as_dma_end_point_set_direction_in(ep_p);
+
+ /*
+ * get the maximum size of data buffer the HAL
+ * layer can accept. this is used when the DMA
+ * module is sending DMA requests to the HAL.
+ * the DMA module will never send down a request
+ * that is greater than this value.
+ *
+ * for EP0 and EP1, we can send no more than 64
+ * bytes of data at one time as this is the maximum
+ * size of a packet that can be sent via these
+ * endpoints.
+ */
+ if (ep == 0 || ep == 1)
+ ep_p->maxhaldata = 64;
+ else
+ ep_p->maxhaldata = cy_as_hal_dma_max_request_size(
+ dev_p->tag, ep);
+
+ if (enable)
+ cy_as_dma_end_point_enable(ep_p);
+ else
+ cy_as_dma_end_point_disable(ep_p);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+ * This function cancels any DMA operations pending with the HAL layer as well
+ * as any DMA operation queued on the endpoint.
+ */
+cy_as_return_status_t
+cy_as_dma_cancel(
+ cy_as_device *dev_p,
+ cy_as_end_point_number_t ep,
+ cy_as_return_status_t err)
+{
+ uint32_t mask;
+ cy_as_dma_end_point *ep_p;
+ cy_as_dma_queue_entry *entry_p;
+ cy_bool epstate;
+
+ /*
+ * make sure the endpoint is valid
+ */
+ if (ep >= sizeof(dev_p->endp)/sizeof(dev_p->endp[0]))
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* Get the endpoint pointer based on the endpoint number */
+ ep_p = CY_AS_NUM_EP(dev_p, ep);
+
+ if (ep_p) {
+ /* Remember the state of the endpoint */
+ epstate = cy_as_dma_end_point_is_enabled(ep_p);
+
+ /*
+ * disable the endpoint so no more DMA packets can be
+ * queued.
+ */
+ cy_as_dma_enable_end_point(dev_p, ep,
+ cy_false, cy_as_direction_dont_change);
+
+ /*
+ * don't allow any interrupts from this endpoint
+ * while we get the most current request off of
+ * the queue.
+ */
+ cy_as_dma_set_drq(dev_p, ep, cy_false);
+
+ /*
+ * cancel any pending request queued in the HAL layer
+ */
+ if (cy_as_dma_end_point_in_transit(ep_p))
+ cy_as_hal_dma_cancel_request(dev_p->tag, ep_p->ep);
+
+ /*
+ * shutdown the DMA for this endpoint so no
+ * more data is transferred
+ */
+ cy_as_dma_end_point_set_stopped(ep_p);
+
+ /*
+ * mark the endpoint as not in transit, because we are
+ * going to consume any queued requests
+ */
+ cy_as_dma_end_point_clear_in_transit(ep_p);
+
+ /*
+ * now, remove each entry in the queue and call the
+ * associated callback stating that the request was
+ * canceled.
+ */
+ ep_p->last_p = 0;
+ while (ep_p->queue_p != 0) {
+ /* Disable interrupts to manipulate the queue */
+ mask = cy_as_hal_disable_interrupts();
+
+ /* Remove an entry from the queue */
+ entry_p = ep_p->queue_p;
+ ep_p->queue_p = entry_p->next_p;
+
+ /* Ok, the queue has been updated, we can
+ * turn interrupts back on */
+ cy_as_hal_enable_interrupts(mask);
+
+ /* Call the callback indicating we have
+ * canceled the DMA */
+ if (entry_p->cb)
+ entry_p->cb(dev_p, ep,
+ entry_p->buf_p, entry_p->size, err);
+
+ cy_as_dma_add_request_to_free_queue(dev_p, entry_p);
+ }
+
+ if (ep == 0 || ep == 1) {
+ /*
+ * if this endpoint is zero or one, we need to
+ * clear the queue of any pending CY_RQT_USB_EP_DATA
+ * requests as these are pending requests to send
+ * data to the west bridge device.
+ */
+ cy_as_ll_remove_ep_data_requests(dev_p, ep);
+ }
+
+ if (epstate) {
+ /*
+ * the endpoint started out enabled, so we
+ * re-enable the endpoint here.
+ */
+ cy_as_dma_enable_end_point(dev_p, ep,
+ cy_true, cy_as_direction_dont_change);
+ }
+ }
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+cy_as_return_status_t
+cy_as_dma_received_data(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, uint32_t dsize, void *data)
+{
+ cy_as_dma_queue_entry *dma_p;
+ uint8_t *src_p, *dest_p;
+ cy_as_dma_end_point *ep_p;
+ uint32_t xfersize;
+
+ /*
+ * make sure the endpoint is valid
+ */
+ if (ep != 0 && ep != 1)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* Get the endpoint pointer based on the endpoint number */
+ ep_p = CY_AS_NUM_EP(dev_p, ep);
+ dma_p = ep_p->queue_p;
+ if (dma_p == 0)
+ return CY_AS_ERROR_SUCCESS;
+
+ /*
+ * if the data received exceeds the size of the DMA buffer,
+ * clip the data to the size of the buffer. this can lead
+ * to loosing some data, but is not different than doing
+ * non-packet reads on the other endpoints.
+ */
+ if (dsize > dma_p->size - dma_p->offset)
+ dsize = dma_p->size - dma_p->offset;
+
+ /*
+ * copy the data from the request packet to the DMA buffer
+ * for the endpoint
+ */
+ src_p = (uint8_t *)data;
+ dest_p = ((uint8_t *)(dma_p->buf_p)) + dma_p->offset;
+ xfersize = dsize;
+ while (xfersize-- > 0)
+ *dest_p++ = *src_p++;
+
+ /* Signal the DMA module that we have
+ * received data for this EP request */
+ cy_as_dma_completed_callback(dev_p->tag,
+ ep, dsize, CY_AS_ERROR_SUCCESS);
+
+ return CY_AS_ERROR_SUCCESS;
+}
diff --git a/drivers/staging/westbridge/astoria/api/src/cyasintr.c b/drivers/staging/westbridge/astoria/api/src/cyasintr.c
new file mode 100644
index 000000000000..b60f69ce5985
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyasintr.c
@@ -0,0 +1,143 @@
+/* Cypress West Bridge API source file (cyasintr.c)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyasdevice.h"
+#include "../../include/linux/westbridge/cyasregs.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+
+extern void cy_as_mail_box_interrupt_handler(cy_as_device *);
+
+void
+cy_as_mcu_interrupt_handler(cy_as_device *dev_p)
+{
+ /* Read and clear the interrupt. */
+ uint16_t v;
+
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_MCU_STAT);
+ v = v;
+}
+
+void
+cy_as_power_management_interrupt_handler(cy_as_device *dev_p)
+{
+ uint16_t v;
+
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PWR_MAGT_STAT);
+ v = v;
+}
+
+void
+cy_as_pll_lock_loss_interrupt_handler(cy_as_device *dev_p)
+{
+ uint16_t v;
+
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PLL_LOCK_LOSS_STAT);
+ v = v;
+}
+
+uint32_t cy_as_intr_start(cy_as_device *dev_p, cy_bool dmaintr)
+{
+ uint16_t v;
+
+ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
+
+ if (cy_as_device_is_intr_running(dev_p) != 0)
+ return CY_AS_ERROR_ALREADY_RUNNING;
+
+ v = CY_AS_MEM_P0_INT_MASK_REG_MMCUINT |
+ CY_AS_MEM_P0_INT_MASK_REG_MMBINT |
+ CY_AS_MEM_P0_INT_MASK_REG_MPMINT;
+
+ if (dmaintr)
+ v |= CY_AS_MEM_P0_INT_MASK_REG_MDRQINT;
+
+ /* Enable the interrupts of interest */
+ cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_INT_MASK_REG, v);
+
+ /* Mark the interrupt module as initialized */
+ cy_as_device_set_intr_running(dev_p);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+uint32_t cy_as_intr_stop(cy_as_device *dev_p)
+{
+ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
+
+ if (cy_as_device_is_intr_running(dev_p) == 0)
+ return CY_AS_ERROR_NOT_RUNNING;
+
+ cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_INT_MASK_REG, 0);
+ cy_as_device_set_intr_stopped(dev_p);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+void cy_as_intr_service_interrupt(cy_as_hal_device_tag tag)
+{
+ uint16_t v;
+ cy_as_device *dev_p;
+
+ dev_p = cy_as_device_find_from_tag(tag);
+
+ /*
+ * only power management interrupts can occur before the
+ * antioch API setup is complete. if this is a PM interrupt
+ * handle it here; otherwise output a warning message.
+ */
+ if (dev_p == 0) {
+ v = cy_as_hal_read_register(tag, CY_AS_MEM_P0_INTR_REG);
+ if (v == CY_AS_MEM_P0_INTR_REG_PMINT) {
+ /* Read the PWR_MAGT_STAT register
+ * to clear this interrupt. */
+ v = cy_as_hal_read_register(tag,
+ CY_AS_MEM_PWR_MAGT_STAT);
+ } else
+ cy_as_hal_print_message("stray antioch "
+ "interrupt detected"
+ ", tag not associated "
+ "with any created device.");
+ return;
+ }
+
+ /* Make sure we got a valid object from CyAsDeviceFindFromTag */
+ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
+
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_INTR_REG);
+
+ if (v & CY_AS_MEM_P0_INTR_REG_MCUINT)
+ cy_as_mcu_interrupt_handler(dev_p);
+
+ if (v & CY_AS_MEM_P0_INTR_REG_PMINT)
+ cy_as_power_management_interrupt_handler(dev_p);
+
+ if (v & CY_AS_MEM_P0_INTR_REG_PLLLOCKINT)
+ cy_as_pll_lock_loss_interrupt_handler(dev_p);
+
+ /* If the interrupt module is not running, no mailbox
+ * interrupts are expected from the west bridge. */
+ if (cy_as_device_is_intr_running(dev_p) == 0)
+ return;
+
+ if (v & CY_AS_MEM_P0_INTR_REG_MBINT)
+ cy_as_mail_box_interrupt_handler(dev_p);
+}
diff --git a/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c b/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c
new file mode 100644
index 000000000000..60b6f3525332
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c
@@ -0,0 +1,358 @@
+/* Cypress West Bridge API source file (cyaslep2pep.c)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyasusb.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+#include "../../include/linux/westbridge/cyaslowlevel.h"
+#include "../../include/linux/westbridge/cyasdma.h"
+
+typedef enum cy_as_physical_endpoint_state {
+ cy_as_e_p_free,
+ cy_as_e_p_in,
+ cy_as_e_p_out,
+ cy_as_e_p_iso_in,
+ cy_as_e_p_iso_out
+} cy_as_physical_endpoint_state;
+
+
+/*
+* This map is used to map an index between 1 and 10
+* to a logical endpoint number. This is used to map
+* LEP register indexes into actual EP numbers.
+*/
+static cy_as_end_point_number_t end_point_map[] = {
+ 3, 5, 7, 9, 10, 11, 12, 13, 14, 15 };
+
+#define CY_AS_EPCFG_1024 (1 << 3)
+#define CY_AS_EPCFG_DBL (0x02)
+#define CY_AS_EPCFG_TRIPLE (0x03)
+#define CY_AS_EPCFG_QUAD (0x00)
+
+/*
+ * NB: This table contains the register values for PEP1
+ * and PEP3. PEP2 and PEP4 only have a bit to change the
+ * direction of the PEP and therefre are not represented
+ * in this table.
+ */
+static uint8_t pep_register_values[12][4] = {
+ /* Bit 1:0 buffering, 0 = quad, 2 = double, 3 = triple */
+ /* Bit 3 size, 0 = 512, 1 = 1024 */
+ {
+ CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_DBL,
+ },/* Config 1 - PEP1 (2 * 512), PEP2 (2 * 512),
+ * PEP3 (2 * 512), PEP4 (2 * 512) */
+ {
+ CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_QUAD,
+ }, /* Config 2 - PEP1 (2 * 512), PEP2 (2 * 512),
+ * PEP3 (4 * 512), PEP4 (N/A) */
+ {
+ CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_DBL | CY_AS_EPCFG_1024,
+ },/* Config 3 - PEP1 (2 * 512), PEP2 (2 * 512),
+ * PEP3 (2 * 1024), PEP4(N/A) */
+ {
+ CY_AS_EPCFG_QUAD,
+ CY_AS_EPCFG_DBL,
+ },/* Config 4 - PEP1 (4 * 512), PEP2 (N/A),
+ * PEP3 (2 * 512), PEP4 (2 * 512) */
+ {
+ CY_AS_EPCFG_QUAD,
+ CY_AS_EPCFG_QUAD,
+ },/* Config 5 - PEP1 (4 * 512), PEP2 (N/A),
+ * PEP3 (4 * 512), PEP4 (N/A) */
+ {
+ CY_AS_EPCFG_QUAD,
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ },/* Config 6 - PEP1 (4 * 512), PEP2 (N/A),
+ * PEP3 (2 * 1024), PEP4 (N/A) */
+ {
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_DBL,
+ },/* Config 7 - PEP1 (2 * 1024), PEP2 (N/A),
+ * PEP3 (2 * 512), PEP4 (2 * 512) */
+ {
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_QUAD,
+ },/* Config 8 - PEP1 (2 * 1024), PEP2 (N/A),
+ * PEP3 (4 * 512), PEP4 (N/A) */
+ {
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ },/* Config 9 - PEP1 (2 * 1024), PEP2 (N/A),
+ * PEP3 (2 * 1024), PEP4 (N/A)*/
+ {
+ CY_AS_EPCFG_TRIPLE,
+ CY_AS_EPCFG_TRIPLE,
+ },/* Config 10 - PEP1 (3 * 512), PEP2 (N/A),
+ * PEP3 (3 * 512), PEP4 (2 * 512)*/
+ {
+ CY_AS_EPCFG_TRIPLE | CY_AS_EPCFG_1024,
+ CY_AS_EPCFG_DBL,
+ },/* Config 11 - PEP1 (3 * 1024), PEP2 (N/A),
+ * PEP3 (N/A), PEP4 (2 * 512) */
+ {
+ CY_AS_EPCFG_QUAD | CY_AS_EPCFG_1024,
+ CY_AS_EPCFG_DBL,
+ },/* Config 12 - PEP1 (4 * 1024), PEP2 (N/A),
+ * PEP3 (N/A), PEP4 (N/A) */
+};
+
+static cy_as_return_status_t
+find_endpoint_directions(cy_as_device *dev_p,
+ cy_as_physical_endpoint_state epstate[4])
+{
+ int i;
+ cy_as_physical_endpoint_state desired;
+
+ /*
+ * note, there is no error checking here becuase
+ * ISO error checking happens when the API is called.
+ */
+ for (i = 0; i < 10; i++) {
+ int epno = end_point_map[i];
+ if (dev_p->usb_config[epno].enabled) {
+ int pep = dev_p->usb_config[epno].physical;
+ if (dev_p->usb_config[epno].type == cy_as_usb_iso) {
+ /*
+ * marking this as an ISO endpoint, removes the
+ * physical EP from consideration when
+ * mapping the remaining E_ps.
+ */
+ if (dev_p->usb_config[epno].dir == cy_as_usb_in)
+ desired = cy_as_e_p_iso_in;
+ else
+ desired = cy_as_e_p_iso_out;
+ } else {
+ if (dev_p->usb_config[epno].dir == cy_as_usb_in)
+ desired = cy_as_e_p_in;
+ else
+ desired = cy_as_e_p_out;
+ }
+
+ /*
+ * NB: Note the API calls insure that an ISO endpoint
+ * has a physical and logical EP number that are the
+ * same, therefore this condition is not enforced here.
+ */
+ if (epstate[pep - 1] !=
+ cy_as_e_p_free && epstate[pep - 1] != desired)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ epstate[pep - 1] = desired;
+ }
+ }
+
+ /*
+ * create the EP1 config values directly.
+ * both EP1OUT and EP1IN are invalid by default.
+ */
+ dev_p->usb_ep1cfg[0] = 0;
+ dev_p->usb_ep1cfg[1] = 0;
+ if (dev_p->usb_config[1].enabled) {
+ if ((dev_p->usb_config[1].dir == cy_as_usb_out) ||
+ (dev_p->usb_config[1].dir == cy_as_usb_in_out)) {
+ /* Set the valid bit and type field. */
+ dev_p->usb_ep1cfg[0] = (1 << 7);
+ if (dev_p->usb_config[1].type == cy_as_usb_bulk)
+ dev_p->usb_ep1cfg[0] |= (2 << 4);
+ else
+ dev_p->usb_ep1cfg[0] |= (3 << 4);
+ }
+
+ if ((dev_p->usb_config[1].dir == cy_as_usb_in) ||
+ (dev_p->usb_config[1].dir == cy_as_usb_in_out)) {
+ /* Set the valid bit and type field. */
+ dev_p->usb_ep1cfg[1] = (1 << 7);
+ if (dev_p->usb_config[1].type == cy_as_usb_bulk)
+ dev_p->usb_ep1cfg[1] |= (2 << 4);
+ else
+ dev_p->usb_ep1cfg[1] |= (3 << 4);
+ }
+ }
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+create_register_settings(cy_as_device *dev_p,
+ cy_as_physical_endpoint_state epstate[4])
+{
+ int i;
+ uint8_t v;
+
+ for (i = 0; i < 4; i++) {
+ if (i == 0) {
+ /* Start with the values that specify size */
+ dev_p->usb_pepcfg[i] =
+ pep_register_values
+ [dev_p->usb_phy_config - 1][0];
+ } else if (i == 2) {
+ /* Start with the values that specify size */
+ dev_p->usb_pepcfg[i] =
+ pep_register_values
+ [dev_p->usb_phy_config - 1][1];
+ } else
+ dev_p->usb_pepcfg[i] = 0;
+
+ /* Adjust direction if it is in */
+ if (epstate[i] == cy_as_e_p_iso_in ||
+ epstate[i] == cy_as_e_p_in)
+ dev_p->usb_pepcfg[i] |= (1 << 6);
+ }
+
+ /* Configure the logical EP registers */
+ for (i = 0; i < 10; i++) {
+ int val;
+ int epnum = end_point_map[i];
+
+ v = 0x10; /* PEP 1, Bulk Endpoint, EP not valid */
+ if (dev_p->usb_config[epnum].enabled) {
+ v |= (1 << 7); /* Enabled */
+
+ val = dev_p->usb_config[epnum].physical - 1;
+ cy_as_hal_assert(val >= 0 && val <= 3);
+ v |= (val << 5);
+
+ switch (dev_p->usb_config[epnum].type) {
+ case cy_as_usb_bulk:
+ val = 2;
+ break;
+ case cy_as_usb_int:
+ val = 3;
+ break;
+ case cy_as_usb_iso:
+ val = 1;
+ break;
+ default:
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+ v |= (val << 3);
+ }
+
+ dev_p->usb_lepcfg[i] = v;
+ }
+}
+
+
+cy_as_return_status_t
+cy_as_usb_map_logical2_physical(cy_as_device *dev_p)
+{
+ cy_as_return_status_t ret;
+
+ /* Physical EPs 3 5 7 9 respectively in the array */
+ cy_as_physical_endpoint_state epstate[4] = {
+ cy_as_e_p_free, cy_as_e_p_free,
+ cy_as_e_p_free, cy_as_e_p_free };
+
+ /* Find the direction for the endpoints */
+ ret = find_endpoint_directions(dev_p, epstate);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /*
+ * now create the register settings based on the given
+ * assigned of logical E_ps to physical endpoints.
+ */
+ create_register_settings(dev_p, epstate);
+
+ return ret;
+}
+
+static uint16_t
+get_max_dma_size(cy_as_device *dev_p, cy_as_end_point_number_t ep)
+{
+ uint16_t size = dev_p->usb_config[ep].size;
+
+ if (size == 0) {
+ switch (dev_p->usb_config[ep].type) {
+ case cy_as_usb_control:
+ size = 64;
+ break;
+
+ case cy_as_usb_bulk:
+ size = cy_as_device_is_usb_high_speed(dev_p) ?
+ 512 : 64;
+ break;
+
+ case cy_as_usb_int:
+ size = cy_as_device_is_usb_high_speed(dev_p) ?
+ 1024 : 64;
+ break;
+
+ case cy_as_usb_iso:
+ size = cy_as_device_is_usb_high_speed(dev_p) ?
+ 1024 : 1023;
+ break;
+ }
+ }
+
+ return size;
+}
+
+cy_as_return_status_t
+cy_as_usb_set_dma_sizes(cy_as_device *dev_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint32_t i;
+
+ for (i = 0; i < 10; i++) {
+ cy_as_usb_end_point_config *config_p =
+ &dev_p->usb_config[end_point_map[i]];
+ if (config_p->enabled) {
+ ret = cy_as_dma_set_max_dma_size(dev_p,
+ end_point_map[i],
+ get_max_dma_size(dev_p, end_point_map[i]));
+ if (ret != CY_AS_ERROR_SUCCESS)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_usb_setup_dma(cy_as_device *dev_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint32_t i;
+
+ for (i = 0; i < 10; i++) {
+ cy_as_usb_end_point_config *config_p =
+ &dev_p->usb_config[end_point_map[i]];
+ if (config_p->enabled) {
+ /* Map the endpoint direction to the DMA direction */
+ cy_as_dma_direction dir = cy_as_direction_out;
+ if (config_p->dir == cy_as_usb_in)
+ dir = cy_as_direction_in;
+
+ ret = cy_as_dma_enable_end_point(dev_p,
+ end_point_map[i], cy_true, dir);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ break;
+ }
+ }
+
+ return ret;
+}
diff --git a/drivers/staging/westbridge/astoria/api/src/cyaslowlevel.c b/drivers/staging/westbridge/astoria/api/src/cyaslowlevel.c
new file mode 100644
index 000000000000..d43dd858de58
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyaslowlevel.c
@@ -0,0 +1,1264 @@
+/* Cypress West Bridge API source file (cyaslowlevel.c)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyascast.h"
+#include "../../include/linux/westbridge/cyasdevice.h"
+#include "../../include/linux/westbridge/cyaslowlevel.h"
+#include "../../include/linux/westbridge/cyasintr.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+#include "../../include/linux/westbridge/cyasregs.h"
+
+static const uint32_t cy_as_low_level_timeout_count = 65536 * 4;
+
+/* Forward declaration */
+static cy_as_return_status_t cy_as_send_one(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p);
+
+/*
+* This array holds the size of the largest request we will ever recevie from
+* the West Bridge device per context. The size is in 16 bit words. Note a
+* size of 0xffff indicates that there will be no requests on this context
+* from West Bridge.
+*/
+static uint16_t max_request_length[CY_RQT_CONTEXT_COUNT] = {
+ 8, /* CY_RQT_GENERAL_RQT_CONTEXT - CY_RQT_INITIALIZATION_COMPLETE */
+ 8, /* CY_RQT_RESOURCE_RQT_CONTEXT - none */
+ 8, /* CY_RQT_STORAGE_RQT_CONTEXT - CY_RQT_MEDIA_CHANGED */
+ 128, /* CY_RQT_USB_RQT_CONTEXT - CY_RQT_USB_EVENT */
+ 8 /* CY_RQT_TUR_RQT_CONTEXT - CY_RQT_TURBO_CMD_FROM_HOST */
+};
+
+/*
+* For the given context, this function removes the request node at the head
+* of the queue from the context. This is called after all processing has
+* occurred on the given request and response and we are ready to remove this
+* entry from the queue.
+*/
+static void
+cy_as_ll_remove_request_queue_head(cy_as_device *dev_p, cy_as_context *ctxt_p)
+{
+ uint32_t mask, state;
+ cy_as_ll_request_list_node *node_p;
+
+ (void)dev_p;
+ cy_as_hal_assert(ctxt_p->request_queue_p != 0);
+
+ mask = cy_as_hal_disable_interrupts();
+ node_p = ctxt_p->request_queue_p;
+ ctxt_p->request_queue_p = node_p->next;
+ cy_as_hal_enable_interrupts(mask);
+
+ node_p->callback = 0;
+ node_p->rqt = 0;
+ node_p->resp = 0;
+
+ /*
+ * note that the caller allocates and destroys the request and
+ * response. generally the destroy happens in the callback for
+ * async requests and after the wait returns for sync. the
+ * request and response may not actually be destroyed but may be
+ * managed in other ways as well. it is the responsibilty of
+ * the caller to deal with these in any case. the caller can do
+ * this in the request/response callback function.
+ */
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(node_p);
+ cy_as_hal_enable_interrupts(state);
+}
+
+/*
+* For the context given, this function sends the next request to
+* West Bridge via the mailbox register, if the next request is
+* ready to be sent and has not already been sent.
+*/
+static void
+cy_as_ll_send_next_request(cy_as_device *dev_p, cy_as_context *ctxt_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ /*
+ * ret == ret is equivalent to while (1) but eliminates compiler
+ * warnings for some compilers.
+ */
+ while (ret == ret) {
+ cy_as_ll_request_list_node *node_p = ctxt_p->request_queue_p;
+ if (node_p == 0)
+ break;
+
+ if (cy_as_request_get_node_state(node_p) !=
+ CY_AS_REQUEST_LIST_STATE_QUEUED)
+ break;
+
+ cy_as_request_set_node_state(node_p,
+ CY_AS_REQUEST_LIST_STATE_WAITING);
+ ret = cy_as_send_one(dev_p, node_p->rqt);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ break;
+
+ /*
+ * if an error occurs in sending the request, tell the requester
+ * about the error and remove the request from the queue.
+ */
+ cy_as_request_set_node_state(node_p,
+ CY_AS_REQUEST_LIST_STATE_RECEIVED);
+ node_p->callback(dev_p, ctxt_p->number,
+ node_p->rqt, node_p->resp, ret);
+ cy_as_ll_remove_request_queue_head(dev_p, ctxt_p);
+
+ /*
+ * this falls through to the while loop to send the next request
+ * since the previous request did not get sent.
+ */
+ }
+}
+
+/*
+* This method removes an entry from the request queue of a given context.
+* The entry is removed only if it is not in transit.
+*/
+cy_as_remove_request_result_t
+cy_as_ll_remove_request(cy_as_device *dev_p, cy_as_context *ctxt_p,
+ cy_as_ll_request_response *req_p, cy_bool force)
+{
+ uint32_t imask;
+ cy_as_ll_request_list_node *node_p;
+ cy_as_ll_request_list_node *tmp_p;
+ uint32_t state;
+
+ imask = cy_as_hal_disable_interrupts();
+ if (ctxt_p->request_queue_p != 0 &&
+ ctxt_p->request_queue_p->rqt == req_p) {
+ node_p = ctxt_p->request_queue_p;
+ if ((cy_as_request_get_node_state(node_p) ==
+ CY_AS_REQUEST_LIST_STATE_WAITING) && (!force)) {
+ cy_as_hal_enable_interrupts(imask);
+ return cy_as_remove_request_in_transit;
+ }
+
+ ctxt_p->request_queue_p = node_p->next;
+ } else {
+ tmp_p = ctxt_p->request_queue_p;
+ while (tmp_p != 0 && tmp_p->next != 0 &&
+ tmp_p->next->rqt != req_p)
+ tmp_p = tmp_p->next;
+
+ if (tmp_p == 0 || tmp_p->next == 0) {
+ cy_as_hal_enable_interrupts(imask);
+ return cy_as_remove_request_not_found;
+ }
+
+ node_p = tmp_p->next;
+ tmp_p->next = node_p->next;
+ }
+
+ if (node_p->callback)
+ node_p->callback(dev_p, ctxt_p->number, node_p->rqt,
+ node_p->resp, CY_AS_ERROR_CANCELED);
+
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(node_p);
+ cy_as_hal_enable_interrupts(state);
+
+ cy_as_hal_enable_interrupts(imask);
+ return cy_as_remove_request_sucessful;
+}
+
+void
+cy_as_ll_remove_all_requests(cy_as_device *dev_p, cy_as_context *ctxt_p)
+{
+ cy_as_ll_request_list_node *node = ctxt_p->request_queue_p;
+
+ while (node) {
+ if (cy_as_request_get_node_state(ctxt_p->request_queue_p) !=
+ CY_AS_REQUEST_LIST_STATE_RECEIVED)
+ cy_as_ll_remove_request(dev_p, ctxt_p,
+ node->rqt, cy_true);
+ node = node->next;
+ }
+}
+
+static cy_bool
+cy_as_ll_is_in_queue(cy_as_context *ctxt_p, cy_as_ll_request_response *req_p)
+{
+ uint32_t mask;
+ cy_as_ll_request_list_node *node_p;
+
+ mask = cy_as_hal_disable_interrupts();
+ node_p = ctxt_p->request_queue_p;
+ while (node_p) {
+ if (node_p->rqt == req_p) {
+ cy_as_hal_enable_interrupts(mask);
+ return cy_true;
+ }
+ node_p = node_p->next;
+ }
+ cy_as_hal_enable_interrupts(mask);
+ return cy_false;
+}
+
+/*
+* This is the handler for mailbox data when we are trying to send data
+* to the West Bridge firmware. The firmware may be trying to send us
+* data and we need to queue this data to allow the firmware to move
+* forward and be in a state to receive our request. Here we just queue
+* the data and it is processed at a later time by the mailbox interrupt
+* handler.
+*/
+void
+cy_as_ll_queue_mailbox_data(cy_as_device *dev_p)
+{
+ cy_as_context *ctxt_p;
+ uint8_t context;
+ uint16_t data[4];
+ int32_t i;
+
+ /* Read the data from mailbox 0 to determine what to do with the data */
+ for (i = 3; i >= 0; i--)
+ data[i] = cy_as_hal_read_register(dev_p->tag,
+ cy_cast_int2U_int16(CY_AS_MEM_P0_MAILBOX0 + i));
+
+ context = cy_as_mbox_get_context(data[0]);
+ if (context >= CY_RQT_CONTEXT_COUNT) {
+ cy_as_hal_print_message("mailbox request/response received "
+ "with invalid context value (%d)\n", context);
+ return;
+ }
+
+ ctxt_p = dev_p->context[context];
+
+ /*
+ * if we have queued too much data, drop future data.
+ */
+ cy_as_hal_assert(ctxt_p->queue_index * sizeof(uint16_t) +
+ sizeof(data) <= sizeof(ctxt_p->data_queue));
+
+ for (i = 0; i < 4; i++)
+ ctxt_p->data_queue[ctxt_p->queue_index++] = data[i];
+
+ cy_as_hal_assert((ctxt_p->queue_index % 4) == 0);
+ dev_p->ll_queued_data = cy_true;
+}
+
+void
+cy_as_mail_box_process_data(cy_as_device *dev_p, uint16_t *data)
+{
+ cy_as_context *ctxt_p;
+ uint8_t context;
+ uint16_t *len_p;
+ cy_as_ll_request_response *rec_p;
+ uint8_t st;
+ uint16_t src, dest;
+
+ context = cy_as_mbox_get_context(data[0]);
+ if (context >= CY_RQT_CONTEXT_COUNT) {
+ cy_as_hal_print_message("mailbox request/response received "
+ "with invalid context value (%d)\n", context);
+ return;
+ }
+
+ ctxt_p = dev_p->context[context];
+
+ if (cy_as_mbox_is_request(data[0])) {
+ cy_as_hal_assert(ctxt_p->req_p != 0);
+ rec_p = ctxt_p->req_p;
+ len_p = &ctxt_p->request_length;
+
+ } else {
+ if (ctxt_p->request_queue_p == 0 ||
+ cy_as_request_get_node_state(ctxt_p->request_queue_p)
+ != CY_AS_REQUEST_LIST_STATE_WAITING) {
+ cy_as_hal_print_message("mailbox response received on "
+ "context that was not expecting a response\n");
+ cy_as_hal_print_message(" context: %d\n", context);
+ cy_as_hal_print_message(" contents: 0x%04x 0x%04x "
+ "0x%04x 0x%04x\n",
+ data[0], data[1], data[2], data[3]);
+ if (ctxt_p->request_queue_p != 0)
+ cy_as_hal_print_message(" state: 0x%02x\n",
+ ctxt_p->request_queue_p->state);
+ return;
+ }
+
+ /* Make sure the request has an associated response */
+ cy_as_hal_assert(ctxt_p->request_queue_p->resp != 0);
+
+ rec_p = ctxt_p->request_queue_p->resp;
+ len_p = &ctxt_p->request_queue_p->length;
+ }
+
+ if (rec_p->stored == 0) {
+ /*
+ * this is the first cycle of the response
+ */
+ cy_as_ll_request_response__set_code(rec_p,
+ cy_as_mbox_get_code(data[0]));
+ cy_as_ll_request_response__set_context(rec_p, context);
+
+ if (cy_as_mbox_is_last(data[0])) {
+ /* This is a single cycle response */
+ *len_p = rec_p->length;
+ st = 1;
+ } else {
+ /* Ensure that enough memory has been
+ * reserved for the response. */
+ cy_as_hal_assert(rec_p->length >= data[1]);
+ *len_p = (data[1] < rec_p->length) ?
+ data[1] : rec_p->length;
+ st = 2;
+ }
+ } else
+ st = 1;
+
+ /* Trasnfer the data from the mailboxes to the response */
+ while (rec_p->stored < *len_p && st < 4)
+ rec_p->data[rec_p->stored++] = data[st++];
+
+ if (cy_as_mbox_is_last(data[0])) {
+ /* NB: The call-back that is made below can cause the
+ * addition of more data in this queue, thus causing
+ * a recursive overflow of the queue. this is prevented
+ * by removing the request entry that is currently
+ * being passed up from the data queue. if this is done,
+ * the queue only needs to be as long as two request
+ * entries from west bridge.
+ */
+ if ((ctxt_p->rqt_index > 0) &&
+ (ctxt_p->rqt_index <= ctxt_p->queue_index)) {
+ dest = 0;
+ src = ctxt_p->rqt_index;
+
+ while (src < ctxt_p->queue_index)
+ ctxt_p->data_queue[dest++] =
+ ctxt_p->data_queue[src++];
+
+ ctxt_p->rqt_index = 0;
+ ctxt_p->queue_index = dest;
+ cy_as_hal_assert((ctxt_p->queue_index % 4) == 0);
+ }
+
+ if (ctxt_p->request_queue_p != 0 && rec_p ==
+ ctxt_p->request_queue_p->resp) {
+ /*
+ * if this is the last cycle of the response, call the
+ * callback and reset for the next response.
+ */
+ cy_as_ll_request_response *resp_p =
+ ctxt_p->request_queue_p->resp;
+ resp_p->length = ctxt_p->request_queue_p->length;
+ cy_as_request_set_node_state(ctxt_p->request_queue_p,
+ CY_AS_REQUEST_LIST_STATE_RECEIVED);
+
+ cy_as_device_set_in_callback(dev_p);
+ ctxt_p->request_queue_p->callback(dev_p, context,
+ ctxt_p->request_queue_p->rqt,
+ resp_p, CY_AS_ERROR_SUCCESS);
+
+ cy_as_device_clear_in_callback(dev_p);
+
+ cy_as_ll_remove_request_queue_head(dev_p, ctxt_p);
+ cy_as_ll_send_next_request(dev_p, ctxt_p);
+ } else {
+ /* Send the request to the appropriate
+ * module to handle */
+ cy_as_ll_request_response *request_p = ctxt_p->req_p;
+ ctxt_p->req_p = 0;
+ if (ctxt_p->request_callback) {
+ cy_as_device_set_in_callback(dev_p);
+ ctxt_p->request_callback(dev_p, context,
+ request_p, 0, CY_AS_ERROR_SUCCESS);
+ cy_as_device_clear_in_callback(dev_p);
+ }
+ cy_as_ll_init_request(request_p, 0,
+ context, request_p->length);
+ ctxt_p->req_p = request_p;
+ }
+ }
+}
+
+/*
+* This is the handler for processing queued mailbox data
+*/
+void
+cy_as_mail_box_queued_data_handler(cy_as_device *dev_p)
+{
+ uint16_t i;
+
+ /*
+ * if more data gets queued in between our entering this call
+ * and the end of the iteration on all contexts; we should
+ * continue processing the queued data.
+ */
+ while (dev_p->ll_queued_data) {
+ dev_p->ll_queued_data = cy_false;
+ for (i = 0; i < CY_RQT_CONTEXT_COUNT; i++) {
+ uint16_t offset;
+ cy_as_context *ctxt_p = dev_p->context[i];
+ cy_as_hal_assert((ctxt_p->queue_index % 4) == 0);
+
+ offset = 0;
+ while (offset < ctxt_p->queue_index) {
+ ctxt_p->rqt_index = offset + 4;
+ cy_as_mail_box_process_data(dev_p,
+ ctxt_p->data_queue + offset);
+ offset = ctxt_p->rqt_index;
+ }
+ ctxt_p->queue_index = 0;
+ }
+ }
+}
+
+/*
+* This is the handler for the mailbox interrupt. This function reads
+* data from the mailbox registers until a complete request or response
+* is received. When a complete request is received, the callback
+* associated with requests on that context is called. When a complete
+* response is recevied, the callback associated with the request that
+* generated the reponse is called.
+*/
+void
+cy_as_mail_box_interrupt_handler(cy_as_device *dev_p)
+{
+ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
+
+ /*
+ * queue the mailbox data to preserve
+ * order for later processing.
+ */
+ cy_as_ll_queue_mailbox_data(dev_p);
+
+ /*
+ * process what was queued and anything that may be pending
+ */
+ cy_as_mail_box_queued_data_handler(dev_p);
+}
+
+cy_as_return_status_t
+cy_as_ll_start(cy_as_device *dev_p)
+{
+ uint16_t i;
+
+ if (cy_as_device_is_low_level_running(dev_p))
+ return CY_AS_ERROR_ALREADY_RUNNING;
+
+ dev_p->ll_sending_rqt = cy_false;
+ dev_p->ll_abort_curr_rqt = cy_false;
+
+ for (i = 0; i < CY_RQT_CONTEXT_COUNT; i++) {
+ dev_p->context[i] = (cy_as_context *)
+ cy_as_hal_alloc(sizeof(cy_as_context));
+ if (dev_p->context[i] == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ dev_p->context[i]->number = (uint8_t)i;
+ dev_p->context[i]->request_callback = 0;
+ dev_p->context[i]->request_queue_p = 0;
+ dev_p->context[i]->last_node_p = 0;
+ dev_p->context[i]->req_p = cy_as_ll_create_request(dev_p,
+ 0, (uint8_t)i, max_request_length[i]);
+ dev_p->context[i]->queue_index = 0;
+
+ if (!cy_as_hal_create_sleep_channel
+ (&dev_p->context[i]->channel))
+ return CY_AS_ERROR_CREATE_SLEEP_CHANNEL_FAILED;
+ }
+
+ cy_as_device_set_low_level_running(dev_p);
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+* Shutdown the low level communications module. This operation will
+* also cancel any queued low level requests.
+*/
+cy_as_return_status_t
+cy_as_ll_stop(cy_as_device *dev_p)
+{
+ uint8_t i;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_context *ctxt_p;
+ uint32_t mask;
+
+ for (i = 0; i < CY_RQT_CONTEXT_COUNT; i++) {
+ ctxt_p = dev_p->context[i];
+ if (!cy_as_hal_destroy_sleep_channel(&ctxt_p->channel))
+ return CY_AS_ERROR_DESTROY_SLEEP_CHANNEL_FAILED;
+
+ /*
+ * now, free any queued requests and assocaited responses
+ */
+ while (ctxt_p->request_queue_p) {
+ uint32_t state;
+ cy_as_ll_request_list_node *node_p =
+ ctxt_p->request_queue_p;
+
+ /* Mark this pair as in a cancel operation */
+ cy_as_request_set_node_state(node_p,
+ CY_AS_REQUEST_LIST_STATE_CANCELING);
+
+ /* Tell the caller that we are canceling this request */
+ /* NB: The callback is responsible for destroying the
+ * request and the response. we cannot count on the
+ * contents of these two after calling the callback.
+ */
+ node_p->callback(dev_p, i, node_p->rqt,
+ node_p->resp, CY_AS_ERROR_CANCELED);
+
+ /* Remove the pair from the queue */
+ mask = cy_as_hal_disable_interrupts();
+ ctxt_p->request_queue_p = node_p->next;
+ cy_as_hal_enable_interrupts(mask);
+
+ /* Free the list node */
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(node_p);
+ cy_as_hal_enable_interrupts(state);
+ }
+
+ cy_as_ll_destroy_request(dev_p, dev_p->context[i]->req_p);
+ cy_as_hal_free(dev_p->context[i]);
+ dev_p->context[i] = 0;
+
+ }
+ cy_as_device_set_low_level_stopped(dev_p);
+
+ return ret;
+}
+
+void
+cy_as_ll_init_request(cy_as_ll_request_response *req_p,
+ uint16_t code, uint16_t context, uint16_t length)
+{
+ uint16_t totallen = sizeof(cy_as_ll_request_response) +
+ (length - 1) * sizeof(uint16_t);
+
+ cy_as_hal_mem_set(req_p, 0, totallen);
+ req_p->length = length;
+ cy_as_ll_request_response__set_code(req_p, code);
+ cy_as_ll_request_response__set_context(req_p, context);
+ cy_as_ll_request_response__set_request(req_p);
+}
+
+/*
+* Create a new request.
+*/
+cy_as_ll_request_response *
+cy_as_ll_create_request(cy_as_device *dev_p, uint16_t code,
+ uint8_t context, uint16_t length)
+{
+ cy_as_ll_request_response *req_p;
+ uint32_t state;
+ uint16_t totallen = sizeof(cy_as_ll_request_response) +
+ (length - 1) * sizeof(uint16_t);
+
+ (void)dev_p;
+
+ state = cy_as_hal_disable_interrupts();
+ req_p = cy_as_hal_c_b_alloc(totallen);
+ cy_as_hal_enable_interrupts(state);
+ if (req_p)
+ cy_as_ll_init_request(req_p, code, context, length);
+
+ return req_p;
+}
+
+/*
+* Destroy a request.
+*/
+void
+cy_as_ll_destroy_request(cy_as_device *dev_p, cy_as_ll_request_response *req_p)
+{
+ uint32_t state;
+ (void)dev_p;
+ (void)req_p;
+
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(req_p);
+ cy_as_hal_enable_interrupts(state);
+
+}
+
+void
+cy_as_ll_init_response(cy_as_ll_request_response *req_p, uint16_t length)
+{
+ uint16_t totallen = sizeof(cy_as_ll_request_response) +
+ (length - 1) * sizeof(uint16_t);
+
+ cy_as_hal_mem_set(req_p, 0, totallen);
+ req_p->length = length;
+ cy_as_ll_request_response__set_response(req_p);
+}
+
+/*
+* Create a new response
+*/
+cy_as_ll_request_response *
+cy_as_ll_create_response(cy_as_device *dev_p, uint16_t length)
+{
+ cy_as_ll_request_response *req_p;
+ uint32_t state;
+ uint16_t totallen = sizeof(cy_as_ll_request_response) +
+ (length - 1) * sizeof(uint16_t);
+
+ (void)dev_p;
+
+ state = cy_as_hal_disable_interrupts();
+ req_p = cy_as_hal_c_b_alloc(totallen);
+ cy_as_hal_enable_interrupts(state);
+ if (req_p)
+ cy_as_ll_init_response(req_p, length);
+
+ return req_p;
+}
+
+/*
+* Destroy the new response
+*/
+void
+cy_as_ll_destroy_response(cy_as_device *dev_p, cy_as_ll_request_response *req_p)
+{
+ uint32_t state;
+ (void)dev_p;
+ (void)req_p;
+
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(req_p);
+ cy_as_hal_enable_interrupts(state);
+}
+
+static uint16_t
+cy_as_read_intr_status(
+ cy_as_device *dev_p)
+{
+ uint32_t mask;
+ cy_bool bloop = cy_true;
+ uint16_t v = 0, last = 0xffff;
+
+ /*
+ * before determining if the mailboxes are ready for more data,
+ * we first check the mailbox interrupt to see if we need to
+ * receive data. this prevents a dead-lock condition that can
+ * occur when both sides are trying to receive data.
+ */
+ while (last == last) {
+ /*
+ * disable interrupts to be sure we don't process the mailbox
+ * here and have the interrupt routine try to read this data
+ * as well.
+ */
+ mask = cy_as_hal_disable_interrupts();
+
+ /*
+ * see if there is data to be read.
+ */
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_INTR_REG);
+ if ((v & CY_AS_MEM_P0_INTR_REG_MBINT) == 0) {
+ cy_as_hal_enable_interrupts(mask);
+ break;
+ }
+
+ /*
+ * queue the mailbox data for later processing.
+ * this allows the firmware to move forward and
+ * service the requst from the P port.
+ */
+ cy_as_ll_queue_mailbox_data(dev_p);
+
+ /*
+ * enable interrupts again to service mailbox
+ * interrupts appropriately
+ */
+ cy_as_hal_enable_interrupts(mask);
+ }
+
+ /*
+ * now, all data is received
+ */
+ last = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MB_STAT) & CY_AS_MEM_P0_MCU_MBNOTRD;
+ while (bloop) {
+ v = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MB_STAT) & CY_AS_MEM_P0_MCU_MBNOTRD;
+ if (v == last)
+ break;
+
+ last = v;
+ }
+
+ return v;
+}
+
+/*
+* Send a single request or response using the mail box register.
+* This function does not deal with the internal queues at all,
+* but only sends the request or response across to the firmware
+*/
+static cy_as_return_status_t
+cy_as_send_one(
+ cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p)
+{
+ int i;
+ uint16_t mb0, v;
+ int32_t loopcount;
+ uint32_t int_stat;
+
+#ifdef _DEBUG
+ if (cy_as_ll_request_response__is_request(req_p)) {
+ switch (cy_as_ll_request_response__get_context(req_p)) {
+ case CY_RQT_GENERAL_RQT_CONTEXT:
+ cy_as_hal_assert(req_p->length * 2 + 2 <
+ CY_CTX_GEN_MAX_DATA_SIZE);
+ break;
+
+ case CY_RQT_RESOURCE_RQT_CONTEXT:
+ cy_as_hal_assert(req_p->length * 2 + 2 <
+ CY_CTX_RES_MAX_DATA_SIZE);
+ break;
+
+ case CY_RQT_STORAGE_RQT_CONTEXT:
+ cy_as_hal_assert(req_p->length * 2 + 2 <
+ CY_CTX_STR_MAX_DATA_SIZE);
+ break;
+
+ case CY_RQT_USB_RQT_CONTEXT:
+ cy_as_hal_assert(req_p->length * 2 + 2 <
+ CY_CTX_USB_MAX_DATA_SIZE);
+ break;
+ }
+ }
+#endif
+
+ /* Write the request to the mail box registers */
+ if (req_p->length > 3) {
+ uint16_t length = req_p->length;
+ int which = 0;
+ int st = 1;
+
+ dev_p->ll_sending_rqt = cy_true;
+ while (which < length) {
+ loopcount = cy_as_low_level_timeout_count;
+ do {
+ v = cy_as_read_intr_status(dev_p);
+
+ } while (v && loopcount-- > 0);
+
+ if (v) {
+ cy_as_hal_print_message(
+ ">>>>>> LOW LEVEL TIMEOUT "
+ "%x %x %x %x\n",
+ cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX0),
+ cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX1),
+ cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX2),
+ cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX3));
+ return CY_AS_ERROR_TIMEOUT;
+ }
+
+ if (dev_p->ll_abort_curr_rqt) {
+ dev_p->ll_sending_rqt = cy_false;
+ dev_p->ll_abort_curr_rqt = cy_false;
+ return CY_AS_ERROR_CANCELED;
+ }
+
+ int_stat = cy_as_hal_disable_interrupts();
+
+ /*
+ * check again whether the mailbox is free.
+ * it is possible that an ISR came in and
+ * wrote into the mailboxes since we last
+ * checked the status.
+ */
+ v = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MB_STAT) &
+ CY_AS_MEM_P0_MCU_MBNOTRD;
+ if (v) {
+ /* Go back to the original check since
+ * the mailbox is not free. */
+ cy_as_hal_enable_interrupts(int_stat);
+ continue;
+ }
+
+ if (which == 0) {
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX1, length);
+ st = 2;
+ } else {
+ st = 1;
+ }
+
+ while ((which < length) && (st < 4)) {
+ cy_as_hal_write_register(dev_p->tag,
+ cy_cast_int2U_int16
+ (CY_AS_MEM_MCU_MAILBOX0 + st),
+ req_p->data[which++]);
+ st++;
+ }
+
+ mb0 = req_p->box0;
+ if (which == length) {
+ dev_p->ll_sending_rqt = cy_false;
+ mb0 |= CY_AS_REQUEST_RESPONSE_LAST_MASK;
+ }
+
+ if (dev_p->ll_abort_curr_rqt) {
+ dev_p->ll_sending_rqt = cy_false;
+ dev_p->ll_abort_curr_rqt = cy_false;
+ cy_as_hal_enable_interrupts(int_stat);
+ return CY_AS_ERROR_CANCELED;
+ }
+
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX0, mb0);
+
+ /* Wait for the MBOX interrupt to be high */
+ cy_as_hal_sleep150();
+ cy_as_hal_enable_interrupts(int_stat);
+ }
+ } else {
+check_mailbox_availability:
+ /*
+ * wait for the mailbox registers to become available. this
+ * should be a very quick wait as the firmware is designed
+ * to accept requests at interrupt time and queue them for
+ * future processing.
+ */
+ loopcount = cy_as_low_level_timeout_count;
+ do {
+ v = cy_as_read_intr_status(dev_p);
+
+ } while (v && loopcount-- > 0);
+
+ if (v) {
+ cy_as_hal_print_message(
+ ">>>>>> LOW LEVEL TIMEOUT %x %x %x %x\n",
+ cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX0),
+ cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX1),
+ cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX2),
+ cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_MCU_MAILBOX3));
+ return CY_AS_ERROR_TIMEOUT;
+ }
+
+ int_stat = cy_as_hal_disable_interrupts();
+
+ /*
+ * check again whether the mailbox is free. it is
+ * possible that an ISR came in and wrote into the
+ * mailboxes since we last checked the status.
+ */
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_MCU_MB_STAT) &
+ CY_AS_MEM_P0_MCU_MBNOTRD;
+ if (v) {
+ /* Go back to the original check
+ * since the mailbox is not free. */
+ cy_as_hal_enable_interrupts(int_stat);
+ goto check_mailbox_availability;
+ }
+
+ /* Write the data associated with the request
+ * into the mbox registers 1 - 3 */
+ v = 0;
+ for (i = req_p->length - 1; i >= 0; i--)
+ cy_as_hal_write_register(dev_p->tag,
+ cy_cast_int2U_int16(CY_AS_MEM_MCU_MAILBOX1 + i),
+ req_p->data[i]);
+
+ /* Write the mbox register 0 to trigger the interrupt */
+ cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_MCU_MAILBOX0,
+ req_p->box0 | CY_AS_REQUEST_RESPONSE_LAST_MASK);
+
+ cy_as_hal_sleep150();
+ cy_as_hal_enable_interrupts(int_stat);
+ }
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+* This function queues a single request to be sent to the firmware.
+*/
+extern cy_as_return_status_t
+cy_as_ll_send_request(
+ cy_as_device *dev_p,
+ /* The request to send */
+ cy_as_ll_request_response *req,
+ /* Storage for a reply, must be sure
+ * it is of sufficient size */
+ cy_as_ll_request_response *resp,
+ /* If true, this is a synchronous request */
+ cy_bool sync,
+ /* Callback to call when reply is received */
+ cy_as_response_callback cb
+)
+{
+ cy_as_context *ctxt_p;
+ uint16_t box0 = req->box0;
+ uint8_t context;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_ll_request_list_node *node_p;
+ uint32_t mask, state;
+
+ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
+
+ context = cy_as_mbox_get_context(box0);
+ cy_as_hal_assert(context < CY_RQT_CONTEXT_COUNT);
+ ctxt_p = dev_p->context[context];
+
+ /* Allocate the list node */
+ state = cy_as_hal_disable_interrupts();
+ node_p = cy_as_hal_c_b_alloc(sizeof(cy_as_ll_request_list_node));
+ cy_as_hal_enable_interrupts(state);
+
+ if (node_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* Initialize the list node */
+ node_p->callback = cb;
+ node_p->length = 0;
+ node_p->next = 0;
+ node_p->resp = resp;
+ node_p->rqt = req;
+ node_p->state = CY_AS_REQUEST_LIST_STATE_QUEUED;
+ if (sync)
+ cy_as_request_node_set_sync(node_p);
+
+ /* Put the request into the queue */
+ mask = cy_as_hal_disable_interrupts();
+ if (ctxt_p->request_queue_p == 0) {
+ /* Empty queue */
+ ctxt_p->request_queue_p = node_p;
+ ctxt_p->last_node_p = node_p;
+ } else {
+ ctxt_p->last_node_p->next = node_p;
+ ctxt_p->last_node_p = node_p;
+ }
+ cy_as_hal_enable_interrupts(mask);
+ cy_as_ll_send_next_request(dev_p, ctxt_p);
+
+ if (!cy_as_device_is_in_callback(dev_p)) {
+ mask = cy_as_hal_disable_interrupts();
+ cy_as_mail_box_queued_data_handler(dev_p);
+ cy_as_hal_enable_interrupts(mask);
+ }
+
+ return ret;
+}
+
+static void
+cy_as_ll_send_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ (void)rqt;
+ (void)resp;
+ (void)ret;
+
+
+ cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
+
+ /*
+ * storage the state to return to the caller
+ */
+ dev_p->ll_error = ret;
+
+ /*
+ * now wake the caller
+ */
+ cy_as_hal_wake(&dev_p->context[context]->channel);
+}
+
+cy_as_return_status_t
+cy_as_ll_send_request_wait_reply(
+ cy_as_device *dev_p,
+ /* The request to send */
+ cy_as_ll_request_response *req,
+ /* Storage for a reply, must be
+ * sure it is of sufficient size */
+ cy_as_ll_request_response *resp
+ )
+{
+ cy_as_return_status_t ret;
+ uint8_t context;
+ /* Larger 8 sec time-out to handle the init
+ * delay for slower storage devices in USB FS. */
+ uint32_t loopcount = 800;
+ cy_as_context *ctxt_p;
+
+ /* Get the context for the request */
+ context = cy_as_ll_request_response__get_context(req);
+ cy_as_hal_assert(context < CY_RQT_CONTEXT_COUNT);
+ ctxt_p = dev_p->context[context];
+
+ ret = cy_as_ll_send_request(dev_p, req, resp,
+ cy_true, cy_as_ll_send_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ while (loopcount-- > 0) {
+ /*
+ * sleep while we wait on the response. receiving the reply will
+ * wake this thread. we will wait, at most 2 seconds (10 ms*200
+ * tries) before we timeout. note if the reply arrives, we will
+ * not sleep the entire 10 ms, just til the reply arrives.
+ */
+ cy_as_hal_sleep_on(&ctxt_p->channel, 10);
+
+ /*
+ * if the request has left the queue, it means the request has
+ * been sent and the reply has been received. this means we can
+ * return to the caller and be sure the reply has been received.
+ */
+ if (!cy_as_ll_is_in_queue(ctxt_p, req))
+ return dev_p->ll_error;
+ }
+
+ /* Remove the QueueListNode for this request. */
+ cy_as_ll_remove_request(dev_p, ctxt_p, req, cy_true);
+
+ return CY_AS_ERROR_TIMEOUT;
+}
+
+cy_as_return_status_t
+cy_as_ll_register_request_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_response_callback cb)
+{
+ cy_as_context *ctxt_p;
+ cy_as_hal_assert(context < CY_RQT_CONTEXT_COUNT);
+ ctxt_p = dev_p->context[context];
+
+ ctxt_p->request_callback = cb;
+ return CY_AS_ERROR_SUCCESS;
+}
+
+void
+cy_as_ll_request_response__pack(
+ cy_as_ll_request_response *req_p,
+ uint32_t offset,
+ uint32_t length,
+ void *data_p)
+{
+ uint16_t dt;
+ uint8_t *dp = (uint8_t *)data_p;
+
+ while (length > 1) {
+ dt = ((*dp++) << 8);
+ dt |= (*dp++);
+ cy_as_ll_request_response__set_word(req_p, offset, dt);
+ offset++;
+ length -= 2;
+ }
+
+ if (length == 1) {
+ dt = (*dp << 8);
+ cy_as_ll_request_response__set_word(req_p, offset, dt);
+ }
+}
+
+void
+cy_as_ll_request_response__unpack(
+ cy_as_ll_request_response *req_p,
+ uint32_t offset,
+ uint32_t length,
+ void *data_p)
+{
+ uint8_t *dp = (uint8_t *)data_p;
+
+ while (length-- > 0) {
+ uint16_t val = cy_as_ll_request_response__get_word
+ (req_p, offset++);
+ *dp++ = (uint8_t)((val >> 8) & 0xff);
+
+ if (length) {
+ length--;
+ *dp++ = (uint8_t)(val & 0xff);
+ }
+ }
+}
+
+extern cy_as_return_status_t
+cy_as_ll_send_status_response(
+ cy_as_device *dev_p,
+ uint8_t context,
+ uint16_t code,
+ uint8_t clear_storage)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response resp;
+ cy_as_ll_request_response *resp_p = &resp;
+
+ cy_as_hal_mem_set(resp_p, 0, sizeof(resp));
+ resp_p->length = 1;
+ cy_as_ll_request_response__set_response(resp_p);
+ cy_as_ll_request_response__set_context(resp_p, context);
+
+ if (clear_storage)
+ cy_as_ll_request_response__set_clear_storage_flag(resp_p);
+
+ cy_as_ll_request_response__set_code(resp_p, CY_RESP_SUCCESS_FAILURE);
+ cy_as_ll_request_response__set_word(resp_p, 0, code);
+
+ ret = cy_as_send_one(dev_p, resp_p);
+
+ return ret;
+}
+
+extern cy_as_return_status_t
+cy_as_ll_send_data_response(
+ cy_as_device *dev_p,
+ uint8_t context,
+ uint16_t code,
+ uint16_t length,
+ void *data)
+{
+ cy_as_ll_request_response *resp_p;
+ uint16_t wlen;
+ uint8_t respbuf[256];
+
+ if (length > 192)
+ return CY_AS_ERROR_INVALID_SIZE;
+
+ /* Word length for bytes */
+ wlen = length / 2;
+
+ /* If byte length odd, add one more */
+ if (length % 2)
+ wlen++;
+
+ /* One for the length of field */
+ wlen++;
+
+ resp_p = (cy_as_ll_request_response *)respbuf;
+ cy_as_hal_mem_set(resp_p, 0, sizeof(respbuf));
+ resp_p->length = wlen;
+ cy_as_ll_request_response__set_context(resp_p, context);
+ cy_as_ll_request_response__set_code(resp_p, code);
+
+ cy_as_ll_request_response__set_word(resp_p, 0, length);
+ cy_as_ll_request_response__pack(resp_p, 1, length, data);
+
+ return cy_as_send_one(dev_p, resp_p);
+}
+
+static cy_bool
+cy_as_ll_is_e_p_transfer_related_request(cy_as_ll_request_response *rqt_p,
+ cy_as_end_point_number_t ep)
+{
+ uint16_t v;
+ uint8_t type = cy_as_ll_request_response__get_code(rqt_p);
+
+ if (cy_as_ll_request_response__get_context(rqt_p) !=
+ CY_RQT_USB_RQT_CONTEXT)
+ return cy_false;
+
+ /*
+ * when cancelling outstanding EP0 data transfers, any pending
+ * setup ACK requests also need to be cancelled.
+ */
+ if ((ep == 0) && (type == CY_RQT_ACK_SETUP_PACKET))
+ return cy_true;
+
+ if (type != CY_RQT_USB_EP_DATA)
+ return cy_false;
+
+ v = cy_as_ll_request_response__get_word(rqt_p, 0);
+ if ((cy_as_end_point_number_t)((v >> 13) & 1) != ep)
+ return cy_false;
+
+ return cy_true;
+}
+
+cy_as_return_status_t
+cy_as_ll_remove_ep_data_requests(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep)
+{
+ cy_as_context *ctxt_p;
+ cy_as_ll_request_list_node *node_p;
+ uint32_t imask;
+
+ /*
+ * first, remove any queued requests
+ */
+ ctxt_p = dev_p->context[CY_RQT_USB_RQT_CONTEXT];
+ if (ctxt_p) {
+ for (node_p = ctxt_p->request_queue_p; node_p;
+ node_p = node_p->next) {
+ if (cy_as_ll_is_e_p_transfer_related_request
+ (node_p->rqt, ep)) {
+ cy_as_ll_remove_request(dev_p, ctxt_p,
+ node_p->rqt, cy_false);
+ break;
+ }
+ }
+
+ /*
+ * now, deal with any request that may be in transit
+ */
+ imask = cy_as_hal_disable_interrupts();
+
+ if (ctxt_p->request_queue_p != 0 &&
+ cy_as_ll_is_e_p_transfer_related_request
+ (ctxt_p->request_queue_p->rqt, ep) &&
+ cy_as_request_get_node_state(ctxt_p->request_queue_p) ==
+ CY_AS_REQUEST_LIST_STATE_WAITING) {
+ cy_as_hal_print_message("need to remove an in-transit "
+ "request to antioch\n");
+
+ /*
+ * if the request has not been fully sent to west bridge
+ * yet, abort sending. otherwise, terminate the request
+ * with a CANCELED status. firmware will already have
+ * terminated this transfer.
+ */
+ if (dev_p->ll_sending_rqt)
+ dev_p->ll_abort_curr_rqt = cy_true;
+ else {
+ uint32_t state;
+
+ node_p = ctxt_p->request_queue_p;
+ if (node_p->callback)
+ node_p->callback(dev_p, ctxt_p->number,
+ node_p->rqt, node_p->resp,
+ CY_AS_ERROR_CANCELED);
+
+ ctxt_p->request_queue_p = node_p->next;
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(node_p);
+ cy_as_hal_enable_interrupts(state);
+ }
+ }
+
+ cy_as_hal_enable_interrupts(imask);
+ }
+
+ return CY_AS_ERROR_SUCCESS;
+}
diff --git a/drivers/staging/westbridge/astoria/api/src/cyasmisc.c b/drivers/staging/westbridge/astoria/api/src/cyasmisc.c
new file mode 100644
index 000000000000..10a52a1ac6fb
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyasmisc.c
@@ -0,0 +1,3474 @@
+/* Cypress West Bridge API source file (cyasmisc.c)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyasmisc.h"
+#include "../../include/linux/westbridge/cyasdma.h"
+#include "../../include/linux/westbridge/cyasintr.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+#include "../../include/linux/westbridge/cyasregs.h"
+#include "../../include/linux/westbridge/cyaslowlevel.h"
+#include "../../include/linux/westbridge/cyasprotocol.h"
+
+/*
+* The device list, the only global in the API
+*/
+static cy_as_device *g_device_list;
+
+/*
+ * The current debug level
+ */
+static uint8_t debug_level;
+
+/*
+ * This function sets the debug level for the API
+ *
+ */
+void
+cy_as_misc_set_log_level(uint8_t level)
+{
+ debug_level = level;
+}
+
+#ifdef CY_AS_LOG_SUPPORT
+
+/*
+ * This function is a low level logger for the API.
+ */
+void
+cy_as_log_debug_message(int level, const char *str)
+{
+ if (level <= debug_level)
+ cy_as_hal_print_message("log %d: %s\n", level, str);
+}
+
+#endif
+
+#define cy_as_check_device_ready(dev_p) \
+{\
+ if (!(dev_p) || ((dev_p)->sig != \
+ CY_AS_DEVICE_HANDLE_SIGNATURE)) \
+ return CY_AS_ERROR_INVALID_HANDLE; \
+\
+ if (!cy_as_device_is_configured(dev_p)) \
+ return CY_AS_ERROR_NOT_CONFIGURED; \
+\
+ if (!cy_as_device_is_firmware_loaded(dev_p))\
+ return CY_AS_ERROR_NO_FIRMWARE; \
+}
+
+/* Find an West Bridge device based on a TAG */
+cy_as_device *
+cy_as_device_find_from_tag(cy_as_hal_device_tag tag)
+{
+ cy_as_device *dev_p;
+
+ for (dev_p = g_device_list; 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
+cy_as_bus_from_media_type(cy_as_media_type type,
+ cy_as_bus_number_t *bus)
+{
+ if (type == cy_as_media_nand)
+ *bus = 0;
+ else
+ *bus = 1;
+}
+
+static cy_as_return_status_t
+my_handle_response_no_data(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+/*
+* Create a new West Bridge device
+*/
+cy_as_return_status_t
+cy_as_misc_create_device(cy_as_device_handle *handle_p,
+ cy_as_hal_device_tag tag)
+{
+ cy_as_device *dev_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_log_debug_message(6, "cy_as_misc_create_device called");
+
+ dev_p = (cy_as_device *)cy_as_hal_alloc(sizeof(cy_as_device));
+ if (dev_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ cy_as_hal_mem_set(dev_p, 0, sizeof(cy_as_device));
+
+ /*
+ * dynamically allocating this buffer to ensure that it is
+ * word aligned.
+ */
+ dev_p->usb_ep_data = (uint8_t *)cy_as_hal_alloc(64 * sizeof(uint8_t));
+ if (dev_p->usb_ep_data == 0) {
+ cy_as_hal_free(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 = cy_as_create_c_b_queue(CYAS_FUNC_CB);
+ if (dev_p->func_cbs_misc == 0)
+ goto destroy;
+
+ dev_p->func_cbs_res = cy_as_create_c_b_queue(CYAS_FUNC_CB);
+ if (dev_p->func_cbs_res == 0)
+ goto destroy;
+
+ dev_p->func_cbs_stor = cy_as_create_c_b_queue(CYAS_FUNC_CB);
+ if (dev_p->func_cbs_stor == 0)
+ goto destroy;
+
+ dev_p->func_cbs_usb = cy_as_create_c_b_queue(CYAS_FUNC_CB);
+ if (dev_p->func_cbs_usb == 0)
+ goto destroy;
+
+ dev_p->func_cbs_mtp = cy_as_create_c_b_queue(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 cy_as_misc_configure_device is called.
+ */
+ ret = cy_as_dma_start(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ cy_as_device_set_dma_stopped(dev_p);
+
+ /*
+ * allocate memory for the low level module here. this module is also
+ * activated only when cy_as_misc_configure_device is called.
+ */
+ ret = cy_as_ll_start(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ cy_as_device_set_low_level_stopped(dev_p);
+
+ dev_p->next_p = g_device_list;
+ g_device_list = dev_p;
+
+ *handle_p = dev_p;
+ cy_as_hal_init_dev_registers(tag, cy_false);
+ return CY_AS_ERROR_SUCCESS;
+
+destroy:
+ /* Free any queues that were successfully allocated. */
+ if (dev_p->func_cbs_misc)
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_misc);
+
+ if (dev_p->func_cbs_res)
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_res);
+
+ if (dev_p->func_cbs_stor)
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_stor);
+
+ if (dev_p->func_cbs_usb)
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_usb);
+
+ if (dev_p->func_cbs_mtp)
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_mtp);
+
+ cy_as_hal_free(dev_p->usb_ep_data);
+ cy_as_hal_free(dev_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ else
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+}
+
+/*
+* Destroy an existing West Bridge device
+*/
+cy_as_return_status_t
+cy_as_misc_destroy_device(cy_as_device_handle handle)
+{
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_destroy_device called");
+
+ dev_p = (cy_as_device *)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 (cy_as_device_is_intr_running(dev_p))
+ ret = cy_as_intr_stop(dev_p);
+
+ ret = cy_as_ll_stop(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_intr_start(dev_p, dev_p->use_int_drq);
+ return ret;
+ }
+
+ ret = cy_as_dma_stop(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_intr_start(dev_p, dev_p->use_int_drq);
+ return ret;
+ }
+
+ /* Reset the West Bridge device. */
+ cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_RST_CTRL_REG,
+ CY_AS_MEM_RST_CTRL_REG_HARD);
+
+ /*
+ * remove the device from the device list
+ */
+ if (g_device_list == dev_p) {
+ g_device_list = dev_p->next_p;
+ } else {
+ cy_as_device *tmp_p = g_device_list;
+ while (tmp_p && tmp_p->next_p != dev_p)
+ tmp_p = tmp_p->next_p;
+
+ cy_as_hal_assert(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;
+
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_misc);
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_res);
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_stor);
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_usb);
+ cy_as_destroy_c_b_queue(dev_p->func_cbs_mtp);
+
+ /*
+ * free the memory associated with the device
+ */
+ cy_as_hal_free(dev_p->usb_ep_data);
+ cy_as_hal_free(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
+cy_as_setup_endian_mode(cy_as_device *dev_p)
+{
+ /*
+ * In general, we always set west bridge intothe 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.
+ */
+ cy_as_hal_write_register(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
+*/
+cy_as_return_status_t
+cy_as_misc_in_standby(cy_as_device_handle handle, cy_bool *standby)
+{
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_in_standby called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (cy_as_device_is_pin_standby(dev_p) ||
+ cy_as_device_is_register_standby(dev_p)) {
+ *standby = cy_true;
+ } else
+ *standby = cy_false;
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+cy_as_misc_func_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret);
+
+
+static void
+my_misc_callback(cy_as_device *dev_p, uint8_t context,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *resp_p,
+ cy_as_return_status_t ret)
+{
+ (void)resp_p;
+ (void)context;
+ (void)ret;
+
+ switch (cy_as_ll_request_response__get_code(req_p)) {
+ case CY_RQT_INITIALIZATION_COMPLETE:
+ {
+ uint16_t v;
+
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_GENERAL_RQT_CONTEXT,
+ CY_AS_ERROR_SUCCESS, 0);
+ cy_as_device_set_firmware_loaded(dev_p);
+
+ if (cy_as_device_is_waking(dev_p)) {
+ /*
+ * this is a callback from a
+ * cy_as_misc_leave_standby()
+ * 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(
+ (cy_as_device_handle)dev_p,
+ cy_as_event_misc_awake, 0);
+ cy_as_device_clear_waking(dev_p);
+ } else {
+ v = cy_as_ll_request_response__get_word
+ (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 = cy_as_ll_request_response__get_word
+ (req_p, 4);
+
+ dev_p->is_mtp_firmware =
+ (cy_bool)((v >> 8) & 0xFF);
+
+ if (dev_p->misc_event_cb)
+ dev_p->misc_event_cb(
+ (cy_as_device_handle)dev_p,
+ cy_as_event_misc_initialized, 0);
+ }
+
+ v = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_P0_VM_SET);
+
+ if (v & CY_AS_MEM_P0_VM_SET_CFGMODE)
+ cy_as_hal_print_message(
+ "initialization message "
+ "recieved, but config bit "
+ "still set\n");
+
+ v = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_RST_CTRL_REG);
+ if ((v & CY_AS_MEM_RST_RSTCMPT) == 0)
+ cy_as_hal_print_message(
+ "initialization message "
+ "recieved, but reset complete "
+ "bit still not set\n");
+ }
+ break;
+
+ case CY_RQT_OUT_OF_SUSPEND:
+ cy_as_ll_send_status_response(dev_p, CY_RQT_GENERAL_RQT_CONTEXT,
+ CY_AS_ERROR_SUCCESS, 0);
+ cy_as_device_clear_suspend_mode(dev_p);
+
+ /*
+ * if the wakeup was caused by an async cy_as_misc_leave_suspend
+ * call, we have to call the corresponding callback.
+ */
+ if (dev_p->func_cbs_misc->count > 0) {
+ cy_as_func_c_b_node *node = (cy_as_func_c_b_node *)
+ dev_p->func_cbs_misc->head_p;
+ cy_as_hal_assert(node);
+
+ if (cy_as_funct_c_b_type_get_type(node->data_type) ==
+ CY_FUNCT_CB_MISC_LEAVESUSPEND) {
+ cy_as_hal_assert(node->cb_p != 0);
+
+ node->cb_p((cy_as_device_handle)dev_p,
+ CY_AS_ERROR_SUCCESS, node->client_data,
+ CY_FUNCT_CB_MISC_LEAVESUSPEND, 0);
+ cy_as_remove_c_b_node(dev_p->func_cbs_misc);
+ }
+ }
+
+ if (dev_p->misc_event_cb)
+ dev_p->misc_event_cb((cy_as_device_handle)dev_p,
+ cy_as_event_misc_wakeup, 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((cy_as_device_handle)dev_p,
+ cy_as_event_misc_heart_beat, 0);
+ } else {
+ cy_as_hal_print_message(
+ "**** 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((cy_as_device_handle)dev_p,
+ cy_as_event_misc_device_mismatch, 0);
+ }
+ break;
+
+ case CY_RQT_BOOTLOAD_NO_FIRMWARE:
+ {
+ /* TODO Handle case when firmware is
+ * not found during bootloading. */
+ cy_as_hal_print_message("no firmware image found "
+ "during bootload. device not started\n");
+ }
+ break;
+
+ default:
+ cy_as_hal_assert(0);
+ }
+}
+
+static cy_bool
+is_valid_silicon_id(uint16_t v)
+{
+ cy_bool idok = cy_false;
+
+ /*
+ * 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 = cy_true;
+
+ return idok;
+}
+
+/*
+* Configure the West Bridge device hardware
+*/
+cy_as_return_status_t
+cy_as_misc_configure_device(cy_as_device_handle handle,
+ cy_as_device_config *config_p)
+{
+ cy_as_return_status_t ret;
+ cy_bool standby;
+ cy_as_device *dev_p;
+ uint16_t v;
+ uint16_t fw_present;
+ cy_as_log_debug_message(6, "cy_as_misc_configure_device called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ /* Setup big endian vs little endian */
+ cy_as_setup_endian_mode(dev_p);
+
+ /* Now, confirm that we can talk to the West Bridge device */
+ dev_p->silicon_id = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_CM_WB_CFG_ID);
+ fw_present = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_RST_CTRL_REG);
+ if (!(fw_present & CY_AS_MEM_RST_RSTCMPT)) {
+ if (!is_valid_silicon_id(dev_p->silicon_id))
+ return CY_AS_ERROR_NO_ANTIOCH;
+ }
+ /* Check for standby mode */
+ ret = cy_as_misc_in_standby(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 (cy_as_device_is_astoria_dev(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 == cy_as_device_dack_ack)
+ 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;
+ cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_VM_SET, v);
+
+ if (config_p->crystal)
+ cy_as_device_set_crystal(dev_p);
+ else
+ cy_as_device_set_external_clock(dev_p);
+
+ /* Register a callback to handle MISC requests from the firmware */
+ cy_as_ll_register_request_callback(dev_p,
+ CY_RQT_GENERAL_RQT_CONTEXT, my_misc_callback);
+
+ /* Now mark the DMA and low level modules as active. */
+ cy_as_device_set_dma_running(dev_p);
+ cy_as_device_set_low_level_running(dev_p);
+
+ /* Now, initialize the interrupt module */
+ dev_p->use_int_drq = config_p->dmaintr;
+ ret = cy_as_intr_start(dev_p, config_p->dmaintr);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Mark the interface as initialized */
+ cy_as_device_set_configured(dev_p);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+my_dma_callback(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep,
+ void *mem_p,
+ uint32_t size,
+ cy_as_return_status_t ret
+ )
+{
+ cy_as_dma_end_point *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) {
+ cy_as_func_c_b_node *node =
+ (cy_as_func_c_b_node *)dev_p->func_cbs_misc->head_p;
+
+ cy_as_hal_assert(node);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ /*
+ * disable endpoint 2. the storage module
+ * will enable this EP if necessary.
+ */
+ cy_as_dma_enable_end_point(dev_p,
+ CY_AS_FIRMWARE_ENDPOINT,
+ cy_false, cy_as_direction_in);
+
+ /*
+ * clear the reset register. this releases the
+ * antioch micro-controller from reset and begins
+ * running the code at address zero.
+ */
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_RST_CTRL_REG, 0x00);
+ }
+
+ /* Call the user Callback */
+ node->cb_p((cy_as_device_handle)dev_p, ret, node->client_data,
+ node->data_type, node->data);
+ cy_as_remove_c_b_node(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 = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(mem_p);
+ cy_as_hal_enable_interrupts(state);
+ }
+}
+
+cy_as_return_status_t
+cy_as_misc_download_firmware(cy_as_device_handle handle,
+ const void *mem_p,
+ uint16_t size,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ uint8_t *header;
+ cy_as_return_status_t ret;
+ cy_bool standby;
+ cy_as_device *dev_p;
+ cy_as_dma_callback dmacb = 0;
+ uint32_t state;
+
+ cy_as_log_debug_message(6, "cy_as_misc_download_firmware called");
+
+ /* Make sure we have a valid device */
+ dev_p = (cy_as_device *)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 (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ /*
+ * make sure west bridge is not in standby
+ */
+ ret = cy_as_misc_in_standby(dev_p, &standby);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (standby)
+ return CY_AS_ERROR_IN_STANDBY;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /*
+ * make sure we are in configuration mode
+ */
+ if ((cy_as_hal_read_register(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 = cy_as_hal_disable_interrupts();
+ header = (uint8_t *)cy_as_hal_c_b_alloc(4);
+ cy_as_hal_enable_interrupts(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 = cy_as_dma_enable_end_point(dev_p, CY_AS_FIRMWARE_ENDPOINT,
+ cy_true, cy_as_direction_in);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /*
+ * setup DMA for 64 byte packets. this is the requirement for downloading
+ * firmware to west bridge.
+ */
+ cy_as_dma_set_max_dma_size(dev_p, CY_AS_FIRMWARE_ENDPOINT, 64);
+
+ if (cb)
+ dmacb = my_dma_callback;
+
+ ret = cy_as_dma_queue_request(dev_p, CY_AS_FIRMWARE_ENDPOINT, header,
+ 4, cy_false, cy_false, dmacb);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /*
+ * write the firmware image to the west bridge device
+ */
+ ret = cy_as_dma_queue_request(dev_p, CY_AS_FIRMWARE_ENDPOINT,
+ (void *)mem_p, size, cy_false, cy_false, dmacb);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cb) {
+ cy_as_func_c_b_node *cbnode = cy_as_create_func_c_b_node_data(
+ cb, client, CY_FUNCT_CB_MISC_DOWNLOADFIRMWARE, 0);
+
+ if (cbnode == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ else
+ cy_as_insert_c_b_node(dev_p->func_cbs_misc, cbnode);
+
+ ret = cy_as_dma_kick_start(dev_p, CY_AS_FIRMWARE_ENDPOINT);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ } else {
+ ret = cy_as_dma_drain_queue(dev_p,
+ CY_AS_FIRMWARE_ENDPOINT, cy_true);
+
+ /* Free the header memory that was allocated earlier. */
+ cy_as_hal_c_b_free(header);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /*
+ * disable EP 2. the storage module will
+ * enable this EP if necessary.
+ */
+ cy_as_dma_enable_end_point(dev_p, CY_AS_FIRMWARE_ENDPOINT,
+ cy_false, cy_as_direction_in);
+
+ /*
+ * clear the reset register. this releases the west bridge
+ * micro-controller from reset and begins running the code at
+ * address zero.
+ */
+ cy_as_hal_write_register(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 cy_as_return_status_t
+my_handle_response_get_firmware_version(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_get_firmware_version_data *data_p)
+{
+
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint16_t val;
+
+ if (cy_as_ll_request_response__get_code(reply_p)
+ != CY_RESP_FIRMWARE_VERSION) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ data_p->major = cy_as_ll_request_response__get_word(reply_p, 0);
+ data_p->minor = cy_as_ll_request_response__get_word(reply_p, 1);
+ data_p->build = cy_as_ll_request_response__get_word(reply_p, 2);
+ val = cy_as_ll_request_response__get_word(reply_p, 3);
+ data_p->media_type = (uint8_t)(((val >> 8) & 0xFF) | (val & 0xFF));
+ val = cy_as_ll_request_response__get_word(reply_p, 4);
+ data_p->is_debug_mode = (cy_bool)(val & 0xFF);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_get_firmware_version(cy_as_device_handle handle,
+ cy_as_get_firmware_version_data *data,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_bool standby;
+ cy_as_ll_request_response *req_p, *reply_p;
+
+ cy_as_device *dev_p;
+
+ (void)client;
+
+ cy_as_log_debug_message(6, "cy_as_misc_get_firmware_version called");
+
+ /* Make sure we have a valid device */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /*
+ * make sure antioch is not in standby
+ */
+ ret = cy_as_misc_in_standby(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 (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 5);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* Request and response are freed in
+ * MyHandleResponseGetFirmwareVersion. */
+ ret = my_handle_response_get_firmware_version(dev_p,
+ req_p, reply_p, data);
+ return ret;
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_GETFIRMWAREVERSION, data,
+ dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+static cy_as_return_status_t
+my_handle_response_read_m_c_u_register(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ uint8_t *data_p)
+{
+
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p)
+ != CY_RESP_MCU_REGISTER_DATA) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ *data_p = (uint8_t)
+ (cy_as_ll_request_response__get_word(reply_p, 0));
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_get_gpio_value(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ uint8_t *data_p)
+{
+
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p)
+ != CY_RESP_GPIO_STATE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ } else
+ *data_p = (uint8_t)
+ (cy_as_ll_request_response__get_word(reply_p, 0));
+
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+
+cy_as_return_status_t cy_as_misc_set_sd_power_polarity(
+ cy_as_device_handle handle,
+ cy_as_misc_signal_polarity polarity,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_SDPOLARITY,
+ CY_RQT_GENERAL_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)polarity);
+
+ /*
+ * Reserve space for the reply, the reply data will
+ * not exceed one word
+ */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return (my_handle_response_no_data(dev_p, req_p, reply_p));
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_SETSDPOLARITY, 0, dev_p->func_cbs_misc,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the FuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ return ret;
+}
+
+
+cy_as_return_status_t
+cy_as_misc_read_m_c_u_register(cy_as_device_handle handle,
+ uint16_t address,
+ uint8_t *value,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_ll_request_response *req_p, *reply_p;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_read_m_c_u_register called");
+
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /* Check whether the firmware supports this command. */
+ if (cy_as_device_is_nand_storage_supported(dev_p))
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ /* Make sure the Antioch is not in suspend mode. */
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_READ_MCU_REGISTER,
+ CY_RQT_GENERAL_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)address);
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_MCU_REGISTER_DATA) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ *value = (uint8_t)(cy_as_ll_request_response__get_word
+ (reply_p, 0));
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_READMCUREGISTER, value,
+ dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the MiscFuncCallback */
+ return ret;
+ }
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+
+cy_as_return_status_t
+cy_as_misc_write_m_c_u_register(cy_as_device_handle handle,
+ uint16_t address,
+ uint8_t mask,
+ uint8_t value,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_write_m_c_u_register called");
+
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /* Check whether the firmware supports this command. */
+ if (cy_as_device_is_nand_storage_supported(dev_p))
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ /* Make sure the Antioch is not in suspend mode. */
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_WRITE_MCU_REGISTER,
+ CY_RQT_GENERAL_RQT_CONTEXT, 2);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)address);
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)((mask << 8) | value));
+
+ /*
+ * Reserve space for the reply, the reply data
+ * will not exceed one word
+ */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_WRITEMCUREGISTER, 0,
+ dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /*
+ * The request and response are freed as part of the
+ * MiscFuncCallback
+ */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+my_handle_response_reset(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_reset_type 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 (cy_as_device_is_in_suspend_mode(dev_p)) {
+ v = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_CM_WB_CFG_ID);
+ cy_as_hal_sleep(1);
+ }
+
+ if (type == cy_as_reset_hard) {
+ cy_as_misc_cancel_ex_requests(dev_p);
+ cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_RST_CTRL_REG,
+ CY_AS_MEM_RST_CTRL_REG_HARD);
+ cy_as_device_set_unconfigured(dev_p);
+ cy_as_device_set_firmware_not_loaded(dev_p);
+ cy_as_device_set_dma_stopped(dev_p);
+ cy_as_device_set_low_level_stopped(dev_p);
+ cy_as_device_set_intr_stopped(dev_p);
+ cy_as_device_clear_suspend_mode(dev_p);
+ cy_as_usb_cleanup(dev_p);
+ cy_as_storage_cleanup(dev_p);
+
+ /*
+ * wait for a small amount of time to
+ * allow reset to be complete.
+ */
+ cy_as_hal_sleep(100);
+ }
+
+ cy_as_device_clear_reset_pending(dev_p);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+cy_as_return_status_t
+cy_as_misc_reset(cy_as_device_handle handle,
+ cy_as_reset_type type,
+ cy_bool flush,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+ cy_as_end_point_number_t i;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ (void)client;
+ (void)cb;
+
+ cy_as_log_debug_message(6, "cy_as_misc_reset_e_x called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /*
+ * soft reset is not supported until we close on the issues
+ * in the firmware with what needs to happen.
+ */
+ if (type == cy_as_reset_soft)
+ return CY_AS_ERROR_NOT_YET_SUPPORTED;
+
+ cy_as_device_set_reset_pending(dev_p);
+
+ if (flush) {
+ /* Unable to DrainQueues in polling mode */
+ if ((dev_p->storage_cb || dev_p->storage_cb_ms) &&
+ cy_as_hal_is_polling())
+ return CY_AS_ERROR_ASYNC_PENDING;
+
+ /*
+ * shutdown the endpoints so no more traffic can be queued
+ */
+ for (i = 0; i < 15; i++)
+ cy_as_dma_enable_end_point(dev_p, i, cy_false,
+ cy_as_direction_dont_change);
+
+ /*
+ * 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
+ * cancelled.
+ */
+ if (cy_as_device_is_in_suspend_mode(dev_p)) {
+ for (i = 0; i < 15; i++)
+ cy_as_dma_cancel(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))
+ cy_as_dma_drain_queue(dev_p, i,
+ cy_false);
+ else
+ cy_as_dma_drain_queue(dev_p, i,
+ cy_true);
+ }
+ }
+ } else {
+ /* No flush was requested, so cancel any outstanding DMAs
+ * so the user callbacks are called as needed
+ */
+ if (cy_as_device_is_storage_async_pending(dev_p)) {
+ for (i = 0; i < 15; i++)
+ cy_as_dma_cancel(dev_p, i,
+ CY_AS_ERROR_CANCELED);
+ }
+ }
+
+ ret = my_handle_response_reset(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((cy_as_device_handle)dev_p, ret, client,
+ CY_FUNCT_CB_MISC_RESET, 0);
+
+ /*
+ * initialize any registers that may have been
+ * changed when the device was reset.
+ */
+ cy_as_hal_init_dev_registers(dev_p->tag, cy_false);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+get_unallocated_resource(cy_as_device *dev_p, cy_as_resource_type resource)
+{
+ uint8_t shift = 0;
+ uint16_t v;
+ cy_as_return_status_t ret = CY_AS_ERROR_NOT_ACQUIRED;
+
+ switch (resource) {
+ case cy_as_bus_u_s_b:
+ shift = 4;
+ break;
+ case cy_as_bus_1:
+ shift = 0;
+ break;
+ case cy_as_bus_0:
+ shift = 2;
+ break;
+ default:
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+
+ /* Get the semaphore value for this resource */
+ v = cy_as_hal_read_register(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 */
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_P0_RSE_MASK, (0x03 << shift));
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_RSE_MASK);
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_P0_RSE_ALLOCATE, (0x01 << shift));
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_RSE_MASK);
+
+ v = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_P0_RSE_ALLOCATE);
+ v = (v >> shift) & 0x03;
+ if (v == 0x03)
+ ret = CY_AS_ERROR_SUCCESS;
+ }
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_acquire_resource(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_resource_type *resource)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ ret = get_unallocated_resource(dev_p, *resource);
+ if (ret != CY_AS_ERROR_NOT_ACQUIRED)
+ ret = CY_AS_ERROR_SUCCESS;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_acquire_resource(cy_as_device_handle handle,
+ cy_as_resource_type *resource,
+ cy_bool force,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret;
+
+ cy_as_device *dev_p;
+
+ (void)client;
+
+ cy_as_log_debug_message(6, "cy_as_misc_acquire_resource called");
+
+ if (*resource != cy_as_bus_u_s_b && *resource !=
+ cy_as_bus_0 && *resource != cy_as_bus_1)
+ return CY_AS_ERROR_INVALID_RESOURCE;
+
+
+ /* Make sure the device is ready to accept the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+
+ ret = get_unallocated_resource(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 = cy_as_ll_create_request(dev_p, CY_RQT_ACQUIRE_RESOURCE,
+ CY_RQT_RESOURCE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)(*resource));
+
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_ACQUIRERESOURCE, resource,
+ dev_p->func_cbs_res, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ ret = get_unallocated_resource(dev_p, *resource);
+ if (ret != CY_AS_ERROR_NOT_ACQUIRED)
+ ret = CY_AS_ERROR_SUCCESS;
+ }
+
+ return ret;
+}
+cy_as_return_status_t
+cy_as_misc_release_resource(cy_as_device_handle handle,
+ cy_as_resource_type resource)
+{
+ uint8_t shift = 0;
+ uint16_t v;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_release_resource called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ if (resource != cy_as_bus_u_s_b && resource !=
+ cy_as_bus_0 && resource != cy_as_bus_1)
+ return CY_AS_ERROR_INVALID_RESOURCE;
+
+ switch (resource) {
+ case cy_as_bus_u_s_b:
+ shift = 4;
+ break;
+ case cy_as_bus_1:
+ shift = 0;
+ break;
+ case cy_as_bus_0:
+ shift = 2;
+ break;
+ default:
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+
+ /* Get the semaphore value for this resource */
+ v = (cy_as_hal_read_register(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;
+
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_P0_RSE_MASK, (0x03 << shift));
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_P0_RSE_ALLOCATE, (0x02 << shift));
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_P0_RSE_MASK, 0);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+cy_as_return_status_t
+cy_as_misc_set_trace_level(cy_as_device_handle handle,
+ uint8_t level,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint32_t unit,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_set_trace_level called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ if (cy_as_device_is_in_suspend_mode(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 = cy_as_ll_create_request(dev_p, CY_RQT_SET_TRACE_LEVEL,
+ CY_RQT_GENERAL_RQT_CONTEXT, 2);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)level);
+ cy_as_ll_request_response__set_word(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 = cy_as_ll_create_response(dev_p, 2);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_NOT_SUPPORTED;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_SETTRACELEVEL, 0, dev_p->func_cbs_misc,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_heart_beat_control(cy_as_device_handle handle,
+ cy_bool enable,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_heart_beat_control called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_CONTROL_ANTIOCH_HEARTBEAT,
+ CY_RQT_GENERAL_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)enable);
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_HEARTBEATCONTROL, 0,
+ dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_set_sd_clock_freq(
+ cy_as_device *dev_p,
+ uint8_t card_type,
+ uint8_t setting,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_ll_request_response *req_p, *reply_p;
+
+ if (cy_as_device_is_in_callback(dev_p) && (cb == 0))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ req_p = cy_as_ll_create_request(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;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)((card_type << 8) | setting));
+
+ /* Reserve space for the reply, which will not exceed one word. */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_SETSDFREQ, 0, dev_p->func_cbs_misc,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_set_low_speed_sd_freq(
+ cy_as_device_handle handle,
+ cy_as_low_speed_sd_freq setting,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_set_low_speed_sd_freq called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ if (cy_as_device_is_in_suspend_mode(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 my_set_sd_clock_freq(dev_p, 0, (uint8_t)setting, cb, client);
+}
+
+cy_as_return_status_t
+cy_as_misc_set_high_speed_sd_freq(
+ cy_as_device_handle handle,
+ cy_as_high_speed_sd_freq setting,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_set_high_speed_sd_freq called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ if (cy_as_device_is_in_suspend_mode(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 my_set_sd_clock_freq(dev_p, 1, (uint8_t)setting, cb, client);
+}
+
+cy_as_return_status_t
+cy_as_misc_get_gpio_value(cy_as_device_handle handle,
+ cy_as_misc_gpio pin,
+ uint8_t *value,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_device *dev_p;
+ uint16_t v;
+
+ cy_as_log_debug_message(6, "cy_as_misc_get_gpio_value called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /* If the pin specified is UVALID, there is no need
+ * for firmware to be loaded. */
+ if (pin == cy_as_misc_gpio_U_valid) {
+ v = cy_as_hal_read_register(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 (cy_as_device_is_nand_storage_supported(dev_p))
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /* Make sure the pin selected is valid */
+ if ((pin != cy_as_misc_gpio_1) && (pin != cy_as_misc_gpio_0))
+ return CY_AS_ERROR_INVALID_PARAMETER;
+
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_GET_GPIO_STATE,
+ CY_RQT_GENERAL_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0, ((uint8_t)pin << 8));
+
+ /* Reserve space for the reply, which will not exceed one word. */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_GPIO_STATE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ *value = (uint8_t)
+ cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_GETGPIOVALUE, value,
+ dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+
+cy_as_return_status_t
+cy_as_misc_set_gpio_value(cy_as_device_handle handle,
+ cy_as_misc_gpio pin,
+ uint8_t value,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_device *dev_p;
+ uint16_t v;
+
+ cy_as_log_debug_message(6, "cy_as_misc_set_gpio_value called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /* If the pin specified is UVALID, there is
+ * no need for firmware to be loaded. */
+ if (pin == cy_as_misc_gpio_U_valid) {
+ v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PMU_UPDATE);
+ if (value)
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_PMU_UPDATE,
+ (v | CY_AS_MEM_PMU_UPDATE_UVALID));
+ else
+ cy_as_hal_write_register(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 (cy_as_device_is_nand_storage_supported(dev_p))
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /* Make sure the pin selected is valid */
+ if ((pin < cy_as_misc_gpio_0) || (pin > cy_as_misc_gpio_U_valid))
+ return CY_AS_ERROR_INVALID_PARAMETER;
+
+ /* Create and initialize the low level request to the firmware. */
+ req_p = cy_as_ll_create_request(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));
+ cy_as_ll_request_response__set_word(req_p, 0, v);
+
+ /* Reserve space for the reply, which will not exceed one word. */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_SETGPIOVALUE, 0,
+ dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_enter_standby(cy_as_device *dev_p, cy_bool pin)
+{
+ cy_as_misc_cancel_ex_requests(dev_p);
+
+ /* Save the current values in the critical P-port
+ * registers, where necessary. */
+ cy_as_hal_read_regs_before_standby(dev_p->tag);
+
+ if (pin) {
+ if (cy_as_hal_set_wakeup_pin(dev_p->tag, cy_false))
+ cy_as_device_set_pin_standby(dev_p);
+ else
+ return CY_AS_ERROR_SETTING_WAKEUP_PIN;
+ } else {
+ /*
+ * put antioch in the standby mode
+ */
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_PWR_MAGT_STAT, 0x02);
+ cy_as_device_set_register_standby(dev_p);
+ }
+
+ /*
+ * when the antioch comes out of standby, we have to wait until
+ * the firmware initialization completes before sending other
+ * requests down.
+ */
+ cy_as_device_set_firmware_not_loaded(dev_p);
+
+ /*
+ * keep west bridge interrupt disabled until the device is being woken
+ * up from standby.
+ */
+ dev_p->stby_int_mask = cy_as_hal_disable_interrupts();
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static cy_as_return_status_t
+my_handle_response_enter_standby(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_bool pin)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ ret = my_enter_standby(dev_p, pin);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_enter_standby(cy_as_device_handle handle,
+ cy_bool pin,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_bool standby;
+
+ cy_as_log_debug_message(6, "cy_as_misc_enter_standby called");
+
+ /* Make sure we have a valid device */
+ dev_p = (cy_as_device *)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 = cy_as_misc_in_standby(handle, &standby);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (standby == cy_true)
+ 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 (cy_as_device_is_in_suspend_mode(dev_p))
+ cy_as_misc_leave_suspend(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 (cy_as_device_is_storage_async_pending(dev_p)) {
+ /* DrainQueue will not work in polling mode */
+ if (cy_as_hal_is_polling())
+ return CY_AS_ERROR_ASYNC_PENDING;
+
+ cy_as_dma_drain_queue(dev_p,
+ CY_AS_P2S_READ_ENDPOINT, cy_false);
+ cy_as_dma_drain_queue(dev_p,
+ CY_AS_P2S_WRITE_ENDPOINT, cy_false);
+
+ /*
+ * if more storage operations were queued
+ * at this stage, return an error.
+ */
+ if (cy_as_device_is_storage_async_pending(dev_p))
+ return CY_AS_ERROR_ASYNC_PENDING;
+ }
+
+ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (!cb) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * in the HandleResponse */
+ return my_handle_response_enter_standby(dev_p,
+ req_p, reply_p, pin);
+
+ } else {
+ ret = cy_as_misc_send_request(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, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the MiscFuncCallback */
+ return ret;
+ }
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ } else {
+ ret = my_enter_standby(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((cy_as_device_handle)dev_p, ret, client,
+ CY_FUNCT_CB_MISC_ENTERSTANDBY, 0);
+ }
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_enter_standby_e_x_u(cy_as_device_handle handle,
+ cy_bool pin,
+ cy_bool uvalid_special,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+
+ dev_p = (cy_as_device *)handle;
+ if (uvalid_special)
+ cy_as_hal_write_register(dev_p->tag, 0xc5, 0x4);
+
+ return cy_as_misc_enter_standby(handle, pin, cb, client);
+}
+
+cy_as_return_status_t
+cy_as_misc_leave_standby(cy_as_device_handle handle,
+ cy_as_resource_type resource)
+{
+ cy_as_device *dev_p;
+ uint16_t v;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint32_t count = 8;
+ uint8_t retry = 1;
+
+ cy_as_log_debug_message(6, "cy_as_misc_leave_standby called");
+ (void)resource;
+
+ /* Make sure we have a valid device */
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (cy_as_device_is_register_standby(dev_p)) {
+ /*
+ * set a flag to indicate that the west bridge is waking
+ * up from standby.
+ */
+ cy_as_device_set_waking(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 = cy_as_hal_read_register(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 (cy_as_device_is_crystal(dev_p))
+ cy_as_hal_sleep(
+ CY_AS_LEAVE_STANDBY_DELAY_CRYSTAL);
+ else
+ cy_as_hal_sleep(
+ CY_AS_LEAVE_STANDBY_DELAY_CLOCK);
+ v = cy_as_hal_read_register(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 (!is_valid_silicon_id(v)) {
+ if (cy_as_hal_sync_device_clocks(dev_p->tag) !=
+ cy_true) {
+ cy_as_hal_enable_interrupts(
+ dev_p->stby_int_mask);
+ return CY_AS_ERROR_TIMEOUT;
+ }
+ }
+ } while (!is_valid_silicon_id(v) && count-- > 0);
+
+ /*
+ * if we tried to read the register and could not,
+ * return a timeout
+ */
+ if (count == 0) {
+ cy_as_hal_enable_interrupts(
+ 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.
+ */
+ cy_as_device_clear_register_standby(dev_p);
+
+ /*
+ * initialize any registers that may have been changed
+ * while the device was in standby mode.
+ */
+ cy_as_hal_init_dev_registers(dev_p->tag, cy_true);
+ } else if (cy_as_device_is_pin_standby(dev_p)) {
+ /*
+ * set a flag to indicate that the west bridge is waking
+ * up from standby.
+ */
+ cy_as_device_set_waking(dev_p);
+
+try_wakeup_again:
+ /*
+ * try to set the wakeup pin, if this fails in the HAL
+ * layer, return this failure to the user.
+ */
+ if (!cy_as_hal_set_wakeup_pin(dev_p->tag, cy_true)) {
+ cy_as_hal_enable_interrupts(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 PL_ls have locked
+ * and we can talk to the device.
+ */
+ if (cy_as_device_is_crystal(dev_p))
+ cy_as_hal_sleep(CY_AS_LEAVE_STANDBY_DELAY_CRYSTAL);
+ else
+ cy_as_hal_sleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK);
+
+ /*
+ * initialize any registers that may have been changed
+ * while the device was in standby mode.
+ */
+ cy_as_hal_init_dev_registers(dev_p->tag, cy_true);
+
+ /*
+ * 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.
+ */
+ cy_as_device_clear_pin_standby(dev_p);
+ } else {
+ return CY_AS_ERROR_NOT_IN_STANDBY;
+ }
+
+ /*
+ * the west bridge interrupt can be enabled now.
+ */
+ cy_as_hal_enable_interrupts(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)) {
+ cy_as_hal_write_register(dev_p->tag,
+ CY_AS_MEM_RST_CTRL_REG, 0x00);
+ v = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_RST_CTRL_REG);
+ count--;
+ }
+
+ if (v & 0x03) {
+ cy_as_hal_print_message("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 (cy_as_device_is_firmware_loaded(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 = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_P0_INTR_REG);
+ if (v & CY_AS_MEM_P0_INTR_REG_MBINT)
+ break;
+
+ cy_as_hal_sleep(10);
+ count--;
+ }
+
+ if (!count) {
+ retry = 0;
+ dev_p->stby_int_mask = cy_as_hal_disable_interrupts();
+ cy_as_hal_set_wakeup_pin(dev_p->tag, cy_false);
+ cy_as_hal_sleep(10);
+ goto try_wakeup_again;
+ }
+ }
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_register_callback(
+ /* Handle to the West Bridge device */
+ cy_as_device_handle handle,
+ /* The function to call */
+ cy_as_misc_event_callback callback
+ )
+{
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_register_callback called");
+
+ /* Make sure we have a valid device */
+ dev_p = (cy_as_device *)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;
+}
+
+cy_as_return_status_t
+cy_as_misc_storage_changed(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_bool standby;
+ cy_as_ll_request_response *req_p, *reply_p;
+
+ cy_as_log_debug_message(6, "cy_as_misc_storage_changed called");
+
+ /* Make sure the device is ready for the command. */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /*
+ * make sure antioch is not in standby
+ */
+ ret = cy_as_misc_in_standby(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 (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_STORAGECHANGED, 0,
+ dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+
+cy_as_return_status_t
+cy_as_misc_enter_suspend(
+ cy_as_device_handle handle,
+ cy_bool usb_wakeup_en,
+ cy_bool gpio_wakeup_en,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_bool standby;
+ cy_as_ll_request_response *req_p, *reply_p;
+ uint16_t value;
+ uint32_t int_state;
+
+ cy_as_log_debug_message(6, "cy_as_misc_enter_suspend called");
+
+ /*
+ * basic sanity checks to ensure that the device is initialised.
+ */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /*
+ * make sure west bridge is not already in standby
+ */
+ cy_as_misc_in_standby(dev_p, &standby);
+ if (standby)
+ return CY_AS_ERROR_IN_STANDBY;
+
+ /*
+ * make sure that the device is not already in suspend mode.
+ */
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /*
+ * make sure there is no active USB connection.
+ */
+ if ((cy_as_device_is_usb_connected(dev_p)) && (dev_p->usb_last_event
+ != cy_as_event_usb_suspend))
+ return CY_AS_ERROR_USB_CONNECTED;
+
+ /*
+ * make sure that there are no async requests at this point in time.
+ */
+ int_state = cy_as_hal_disable_interrupts();
+ 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)) {
+ cy_as_hal_enable_interrupts(int_state);
+ return CY_AS_ERROR_ASYNC_PENDING;
+ }
+ cy_as_hal_enable_interrupts(int_state);
+
+ /* Create the request to send to the Antioch device */
+ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(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;
+ cy_as_ll_request_response__set_word(req_p, 0, value);
+
+ if (cb != 0) {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_ENTERSUSPEND,
+ 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p,
+ cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return CY_AS_ERROR_SUCCESS;
+ } else {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ }
+
+destroy:
+ if (ret == CY_AS_ERROR_SUCCESS)
+ cy_as_device_set_suspend_mode(dev_p);
+
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_leave_suspend(
+ cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+ uint16_t v, count;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_log_debug_message(6, "cy_as_misc_leave_suspend called");
+
+ /* Make sure we have a valid device */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /* Make sure we are in suspend mode. */
+ if (cy_as_device_is_in_suspend_mode(dev_p)) {
+ if (cb) {
+ cy_as_func_c_b_node *cbnode =
+ cy_as_create_func_c_b_node_data(cb, client,
+ CY_FUNCT_CB_MISC_LEAVESUSPEND, 0);
+ if (cbnode == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_insert_c_b_node(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 = cy_as_hal_read_register(dev_p->tag,
+ CY_AS_MEM_CM_WB_CFG_ID);
+
+ while (!is_valid_silicon_id(v) && count-- > 0) {
+ cy_as_hal_sleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK);
+ v = cy_as_hal_read_register(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 ((cy_as_device_is_in_suspend_mode(dev_p))
+ && (count--)) {
+ cy_as_hal_sleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK);
+ }
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ ret = CY_AS_ERROR_TIMEOUT;
+ }
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_misc_reserve_l_n_a_boot_area(cy_as_device_handle handle,
+ uint8_t numzones,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_bool standby;
+ cy_as_ll_request_response *req_p, *reply_p;
+
+ cy_as_device *dev_p;
+
+ (void)client;
+
+ cy_as_log_debug_message(6, "cy_as_misc_switch_pnand_mode called");
+
+ /* Make sure we have a valid device */
+ dev_p = (cy_as_device *)handle;
+ cy_as_check_device_ready(dev_p);
+
+ /*
+ * make sure antioch is not in standby
+ */
+ ret = cy_as_misc_in_standby(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 (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(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;
+ cy_as_ll_request_response__set_word(req_p,
+ 0, (uint16_t)numzones);
+
+ /* Reserve space for the reply, the reply data will not
+ * exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MISC_RESERVELNABOOTAREA,
+ 0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_misc_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_func_c_b_node*
+cy_as_create_func_c_b_node_data(cy_as_function_callback cb,
+ uint32_t client,
+ cy_as_funct_c_b_type type,
+ void *data)
+{
+ uint32_t state = cy_as_hal_disable_interrupts();
+ cy_as_func_c_b_node *node = cy_as_hal_c_b_alloc(
+ sizeof(cy_as_func_c_b_node));
+ cy_as_hal_enable_interrupts(state);
+ if (node != 0) {
+ node->node_type = CYAS_FUNC_CB;
+ node->cb_p = cb;
+ node->client_data = client;
+ node->data_type = type;
+ if (data != 0)
+ node->data_type |= CY_FUNCT_CB_DATA;
+ else
+ node->data_type |= CY_FUNCT_CB_NODATA;
+ node->data = data;
+ node->next_p = 0;
+ }
+ return node;
+}
+
+cy_as_func_c_b_node*
+cy_as_create_func_c_b_node(cy_as_function_callback cb,
+ uint32_t client)
+{
+ return cy_as_create_func_c_b_node_data(cb, client,
+ CY_FUNCT_CB_NODATA, 0);
+}
+
+void
+cy_as_destroy_func_c_b_node(cy_as_func_c_b_node *node)
+{
+ uint32_t state;
+
+ node->node_type = CYAS_INVALID;
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(node);
+ cy_as_hal_enable_interrupts(state);
+}
+
+cy_as_usb_func_c_b_node*
+cy_as_create_usb_func_c_b_node(
+ cy_as_usb_function_callback cb, uint32_t client)
+{
+ uint32_t state = cy_as_hal_disable_interrupts();
+ cy_as_usb_func_c_b_node *node = cy_as_hal_c_b_alloc(
+ sizeof(cy_as_usb_func_c_b_node));
+ cy_as_hal_enable_interrupts(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
+cy_as_destroy_usb_func_c_b_node(cy_as_usb_func_c_b_node *node)
+{
+ uint32_t state;
+
+ node->type = CYAS_INVALID;
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(node);
+ cy_as_hal_enable_interrupts(state);
+}
+
+cy_as_usb_io_c_b_node*
+cy_as_create_usb_io_c_b_node(cy_as_usb_io_callback cb)
+{
+ uint32_t state = cy_as_hal_disable_interrupts();
+ cy_as_usb_io_c_b_node *node = cy_as_hal_c_b_alloc(
+ sizeof(cy_as_usb_io_c_b_node));
+ cy_as_hal_enable_interrupts(state);
+ if (node != 0) {
+ node->type = CYAS_USB_IO_CB;
+ node->cb_p = cb;
+ node->next_p = 0;
+ }
+ return node;
+}
+
+void
+cy_as_destroy_usb_io_c_b_node(cy_as_usb_io_c_b_node *node)
+{
+ uint32_t state;
+
+ node->type = CYAS_INVALID;
+
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(node);
+ cy_as_hal_enable_interrupts(state);
+}
+
+cy_as_storage_io_c_b_node*
+cy_as_create_storage_io_c_b_node(cy_as_storage_callback cb,
+ cy_as_media_type media, uint32_t device_index,
+ uint32_t unit, uint32_t block_addr, cy_as_oper_type oper,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p)
+{
+ uint32_t state = cy_as_hal_disable_interrupts();
+ cy_as_storage_io_c_b_node *node = cy_as_hal_c_b_alloc(
+ sizeof(cy_as_storage_io_c_b_node));
+ cy_as_hal_enable_interrupts(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
+cy_as_destroy_storage_io_c_b_node(cy_as_storage_io_c_b_node *node)
+{
+ uint32_t state;
+ node->type = CYAS_INVALID;
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(node);
+ cy_as_hal_enable_interrupts(state);
+}
+
+cy_as_c_b_queue *
+cy_as_create_c_b_queue(cy_as_c_b_node_type type)
+{
+ uint32_t state = cy_as_hal_disable_interrupts();
+ cy_as_c_b_queue *queue = cy_as_hal_c_b_alloc(
+ sizeof(cy_as_c_b_queue));
+ cy_as_hal_enable_interrupts(state);
+ if (queue) {
+ queue->type = type;
+ queue->head_p = 0;
+ queue->tail_p = 0;
+ queue->count = 0;
+ }
+
+ return queue;
+}
+
+void
+cy_as_destroy_c_b_queue(cy_as_c_b_queue *queue)
+{
+ uint32_t state;
+ queue->type = CYAS_INVALID;
+ queue->head_p = 0;
+ queue->tail_p = 0;
+ queue->count = 0;
+ state = cy_as_hal_disable_interrupts();
+ cy_as_hal_c_b_free(queue);
+ cy_as_hal_enable_interrupts(state);
+}
+
+/* Inserts a CyAsCBNode into the queue, the
+ * node type must match the queue type*/
+void
+cy_as_insert_c_b_node(cy_as_c_b_queue *queue_p, void*cbnode)
+{
+ uint32_t int_state;
+
+ int_state = cy_as_hal_disable_interrupts();
+
+ cy_as_hal_assert(queue_p != 0);
+
+ switch (queue_p->type) {
+ case CYAS_USB_FUNC_CB:
+ {
+ cy_as_usb_func_c_b_node *node =
+ (cy_as_usb_func_c_b_node *)cbnode;
+ cy_as_usb_func_c_b_node *tail =
+ (cy_as_usb_func_c_b_node *)queue_p->tail_p;
+
+ cy_as_hal_assert(node->type == CYAS_USB_FUNC_CB);
+ cy_as_hal_assert(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:
+ {
+ cy_as_usb_io_c_b_node *node =
+ (cy_as_usb_io_c_b_node *)cbnode;
+ cy_as_usb_io_c_b_node *tail =
+ (cy_as_usb_io_c_b_node *)queue_p->tail_p;
+
+ cy_as_hal_assert(node->type == CYAS_USB_IO_CB);
+ cy_as_hal_assert(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:
+ {
+ cy_as_storage_io_c_b_node *node =
+ (cy_as_storage_io_c_b_node *)cbnode;
+ cy_as_storage_io_c_b_node *tail =
+ (cy_as_storage_io_c_b_node *)queue_p->tail_p;
+
+ cy_as_hal_assert(node->type == CYAS_STORAGE_IO_CB);
+ cy_as_hal_assert(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:
+ {
+ cy_as_func_c_b_node *node =
+ (cy_as_func_c_b_node *)cbnode;
+ cy_as_func_c_b_node *tail =
+ (cy_as_func_c_b_node *)queue_p->tail_p;
+
+ cy_as_hal_assert(node->node_type == CYAS_FUNC_CB);
+ cy_as_hal_assert(tail == 0 ||
+ tail->node_type == 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:
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+
+ queue_p->count++;
+
+ cy_as_hal_enable_interrupts(int_state);
+}
+
+/* Removes the tail node from the queue and frees it */
+void
+cy_as_remove_c_b_tail_node(cy_as_c_b_queue *queue_p)
+{
+ uint32_t int_state;
+
+ int_state = cy_as_hal_disable_interrupts();
+
+ 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:
+ {
+ cy_as_func_c_b_node *node =
+ (cy_as_func_c_b_node *)
+ queue_p->head_p;
+ cy_as_func_c_b_node *tail =
+ (cy_as_func_c_b_node *)
+ 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;
+ }
+ cy_as_destroy_func_c_b_node(tail);
+ }
+ break;
+
+ case CYAS_USB_FUNC_CB:
+ {
+ cy_as_usb_func_c_b_node *node =
+ (cy_as_usb_func_c_b_node *)
+ queue_p->head_p;
+ cy_as_usb_func_c_b_node *tail =
+ (cy_as_usb_func_c_b_node *)
+ 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;
+ }
+
+ cy_as_destroy_usb_func_c_b_node(tail);
+ }
+ break;
+
+ case CYAS_USB_IO_CB:
+ {
+ cy_as_usb_io_c_b_node *node =
+ (cy_as_usb_io_c_b_node *)
+ queue_p->head_p;
+ cy_as_usb_io_c_b_node *tail =
+ (cy_as_usb_io_c_b_node *)
+ 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;
+ }
+ cy_as_destroy_usb_io_c_b_node(tail);
+ }
+ break;
+
+ case CYAS_STORAGE_IO_CB:
+ {
+ cy_as_storage_io_c_b_node *node =
+ (cy_as_storage_io_c_b_node *)
+ queue_p->head_p;
+ cy_as_storage_io_c_b_node *tail =
+ (cy_as_storage_io_c_b_node *)
+ 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;
+ }
+ cy_as_destroy_storage_io_c_b_node(tail);
+ }
+ break;
+
+ default:
+ cy_as_hal_assert(cy_false);
+ }
+
+ queue_p->count--;
+ if (queue_p->count == 0) {
+ queue_p->head_p = 0;
+ queue_p->tail_p = 0;
+ }
+ }
+
+ cy_as_hal_enable_interrupts(int_state);
+}
+
+/* Removes the first CyAsCBNode from the queue and frees it */
+void
+cy_as_remove_c_b_node(cy_as_c_b_queue *queue_p)
+{
+ uint32_t int_state;
+
+ int_state = cy_as_hal_disable_interrupts();
+
+ cy_as_hal_assert(queue_p->count >= 0);
+ if (queue_p->count > 0) {
+ if (queue_p->type == CYAS_USB_FUNC_CB) {
+ cy_as_usb_func_c_b_node *node =
+ (cy_as_usb_func_c_b_node *)
+ queue_p->head_p;
+ queue_p->head_p = node->next_p;
+ cy_as_destroy_usb_func_c_b_node(node);
+ } else if (queue_p->type == CYAS_USB_IO_CB) {
+ cy_as_usb_io_c_b_node *node =
+ (cy_as_usb_io_c_b_node *)
+ queue_p->head_p;
+ queue_p->head_p = node->next_p;
+ cy_as_destroy_usb_io_c_b_node(node);
+ } else if (queue_p->type == CYAS_STORAGE_IO_CB) {
+ cy_as_storage_io_c_b_node *node =
+ (cy_as_storage_io_c_b_node *)
+ queue_p->head_p;
+ queue_p->head_p = node->next_p;
+ cy_as_destroy_storage_io_c_b_node(node);
+ } else if (queue_p->type == CYAS_FUNC_CB) {
+ cy_as_func_c_b_node *node =
+ (cy_as_func_c_b_node *)
+ queue_p->head_p;
+ queue_p->head_p = node->next_p;
+ cy_as_destroy_func_c_b_node(node);
+ } else {
+ cy_as_hal_assert(cy_false);
+ }
+
+ queue_p->count--;
+ if (queue_p->count == 0) {
+ queue_p->head_p = 0;
+ queue_p->tail_p = 0;
+ }
+ }
+
+ cy_as_hal_enable_interrupts(int_state);
+}
+
+void my_print_func_c_b_node(cy_as_func_c_b_node *node)
+{
+ cy_as_funct_c_b_type type =
+ cy_as_funct_c_b_type_get_type(node->data_type);
+ cy_as_hal_print_message("[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->node_type);
+}
+
+void my_print_c_b_queue(cy_as_c_b_queue *queue_p)
+{
+ uint32_t i = 0;
+
+ cy_as_hal_print_message("| count: %u type: ", queue_p->count);
+
+ if (queue_p->type == CYAS_USB_FUNC_CB) {
+ cy_as_hal_print_message("USB_FUNC_CB\n");
+ } else if (queue_p->type == CYAS_USB_IO_CB) {
+ cy_as_hal_print_message("USB_IO_CB\n");
+ } else if (queue_p->type == CYAS_STORAGE_IO_CB) {
+ cy_as_hal_print_message("STORAGE_IO_CB\n");
+ } else if (queue_p->type == CYAS_FUNC_CB) {
+ cy_as_func_c_b_node *node = queue_p->head_p;
+ cy_as_hal_print_message("FUNC_CB\n");
+ if (queue_p->count > 0) {
+ cy_as_hal_print_message("| head->");
+
+ for (i = 0; i < queue_p->count; i++) {
+ if (node) {
+ cy_as_hal_print_message("->");
+ my_print_func_c_b_node(node);
+ node = node->next_p;
+ } else
+ cy_as_hal_print_message("->[NULL]\n");
+ }
+
+ cy_as_hal_print_message("\n| tail->");
+ my_print_func_c_b_node(queue_p->tail_p);
+ cy_as_hal_print_message("\n");
+ }
+ } else {
+ cy_as_hal_print_message("INVALID\n");
+ }
+
+ cy_as_hal_print_message("|----------\n");
+}
+
+
+/* Removes and frees all pending callbacks */
+void
+cy_as_clear_c_b_queue(cy_as_c_b_queue *queue_p)
+{
+ uint32_t int_state = cy_as_hal_disable_interrupts();
+
+ while (queue_p->count != 0)
+ cy_as_remove_c_b_node(queue_p);
+
+ cy_as_hal_enable_interrupts(int_state);
+}
+
+cy_as_return_status_t
+cy_as_misc_send_request(cy_as_device *dev_p,
+ cy_as_function_callback cb,
+ uint32_t client,
+ cy_as_funct_c_b_type type,
+ void *data,
+ cy_as_c_b_queue *queue,
+ uint16_t req_type,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_response_callback rcb)
+{
+
+ cy_as_func_c_b_node *cbnode = cy_as_create_func_c_b_node_data(cb,
+ client, type, data);
+ cy_as_return_status_t ret;
+
+ if (cbnode == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ else
+ cy_as_insert_c_b_node(queue, cbnode);
+
+ req_p->flags |= req_type;
+
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_false, rcb);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ cy_as_remove_c_b_tail_node(queue);
+
+ return ret;
+}
+
+void
+cy_as_misc_cancel_ex_requests(cy_as_device *dev_p)
+{
+ int i;
+ for (i = 0; i < CY_RQT_CONTEXT_COUNT; i++)
+ cy_as_ll_remove_all_requests(dev_p, dev_p->context[i]);
+}
+
+
+static void
+cy_as_misc_func_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t stat)
+{
+ cy_as_func_c_b_node *node = NULL;
+ cy_as_return_status_t ret;
+
+ cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX)
+ == CY_AS_REQUEST_RESPONSE_EX;
+ cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS)
+ == CY_AS_REQUEST_RESPONSE_MS;
+ uint8_t code;
+ uint32_t type;
+ uint8_t cntxt;
+
+ cy_as_hal_assert(ex_request || ms_request);
+ (void) ex_request;
+ (void) ms_request;
+ (void)context;
+
+ cntxt = cy_as_ll_request_response__get_context(rqt);
+ code = cy_as_ll_request_response__get_code(rqt);
+
+ switch (cntxt) {
+ case CY_RQT_GENERAL_RQT_CONTEXT:
+ cy_as_hal_assert(dev_p->func_cbs_misc->count != 0);
+ cy_as_hal_assert(dev_p->func_cbs_misc->type == CYAS_FUNC_CB);
+ node = (cy_as_func_c_b_node *)dev_p->func_cbs_misc->head_p;
+ type = cy_as_funct_c_b_type_get_type(node->data_type);
+
+ switch (code) {
+ case CY_RQT_GET_FIRMWARE_VERSION:
+ cy_as_hal_assert(node->data != 0);
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_GETFIRMWAREVERSION);
+ ret = my_handle_response_get_firmware_version(dev_p,
+ rqt, resp,
+ (cy_as_get_firmware_version_data *)node->data);
+ break;
+ case CY_RQT_READ_MCU_REGISTER:
+ cy_as_hal_assert(node->data != 0);
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_READMCUREGISTER);
+ ret = my_handle_response_read_m_c_u_register(dev_p, rqt,
+ resp, (uint8_t *)node->data);
+ break;
+ case CY_RQT_GET_GPIO_STATE:
+ cy_as_hal_assert(node->data != 0);
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_GETGPIOVALUE);
+ ret = my_handle_response_get_gpio_value(dev_p, rqt,
+ resp, (uint8_t *)node->data);
+ break;
+ case CY_RQT_SET_SD_CLOCK_FREQ:
+ cy_as_hal_assert(type == CY_FUNCT_CB_MISC_SETSDFREQ);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_CONTROL_ANTIOCH_HEARTBEAT:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_HEARTBEATCONTROL);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_WRITE_MCU_REGISTER:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_WRITEMCUREGISTER);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_STORAGE_MEDIA_CHANGED:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_STORAGECHANGED);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_SET_GPIO_STATE:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_SETGPIOVALUE);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_SET_TRACE_LEVEL:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_SETTRACELEVEL);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ if (ret == CY_AS_ERROR_INVALID_RESPONSE)
+ ret = CY_AS_ERROR_NOT_SUPPORTED;
+ break;
+ case CY_RQT_PREPARE_FOR_STANDBY:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_ENTERSTANDBY);
+ ret = my_handle_response_enter_standby(dev_p, rqt, resp,
+ (cy_bool)node->data);
+ break;
+ case CY_RQT_ENTER_SUSPEND_MODE:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_ENTERSUSPEND);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ cy_as_device_set_suspend_mode(dev_p);
+
+ break;
+ case CY_RQT_RESERVE_LNA_BOOT_AREA:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_RESERVELNABOOTAREA);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_SDPOLARITY:
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_SETSDPOLARITY);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ default:
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+ break;
+
+ case CY_RQT_RESOURCE_RQT_CONTEXT:
+ cy_as_hal_assert(dev_p->func_cbs_res->count != 0);
+ cy_as_hal_assert(dev_p->func_cbs_res->type == CYAS_FUNC_CB);
+ node = (cy_as_func_c_b_node *)dev_p->func_cbs_res->head_p;
+ type = cy_as_funct_c_b_type_get_type(node->data_type);
+
+ 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 */
+ cy_as_hal_assert(type ==
+ CY_FUNCT_CB_MISC_ACQUIRERESOURCE);
+ ret = my_handle_response_acquire_resource(dev_p, rqt,
+ resp, (cy_as_resource_type *)node->data);
+ break;
+ default:
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+ break;
+
+ default:
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ cy_as_hal_assert(cy_false);
+ 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((cy_as_device_handle)dev_p, stat, node->client_data,
+ node->data_type, node->data);
+ if (cntxt == CY_RQT_GENERAL_RQT_CONTEXT)
+ cy_as_remove_c_b_node(dev_p->func_cbs_misc);
+ else
+ cy_as_remove_c_b_node(dev_p->func_cbs_res);
+
+}
+
+
+
+/*[]*/
diff --git a/drivers/staging/westbridge/astoria/api/src/cyasmtp.c b/drivers/staging/westbridge/astoria/api/src/cyasmtp.c
new file mode 100644
index 000000000000..d5a8e45010dc
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyasmtp.c
@@ -0,0 +1,1128 @@
+/* Cypress West Bridge API header file (cyasmtp.h)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyasmtp.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+#include "../../include/linux/westbridge/cyasdma.h"
+#include "../../include/linux/westbridge/cyaslowlevel.h"
+
+static void
+cy_as_mtp_func_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t stat);
+
+static cy_as_return_status_t
+is_mtp_active(cy_as_device *dev_p)
+{
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (dev_p->mtp_count == 0)
+ return CY_AS_ERROR_NOT_RUNNING;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+my_mtp_request_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *resp_p,
+ cy_as_return_status_t ret)
+{
+ uint16_t val, ev, status;
+ uint16_t mtp_datalen = 0;
+ uint32_t bytecount_l, bytecount_h;
+ cy_as_mtp_send_object_complete_data send_obj_data;
+ cy_as_mtp_get_object_complete_data get_obj_data;
+ cy_as_dma_end_point *ep_p;
+
+ uint8_t code = cy_as_ll_request_response__get_code(req_p);
+
+ (void)resp_p;
+ (void)context;
+ (void)ret;
+
+ switch (code) {
+ case CY_RQT_MTP_EVENT:
+ val = cy_as_ll_request_response__get_word(req_p, 0);
+ /* MSB indicates status of read/write */
+ status = (val >> 8) & 0xFF;
+ /* event type */
+ ev = val & 0xFF;
+ switch (ev) {
+ case 0: /* SendObject Complete */
+ {
+ bytecount_l =
+ cy_as_ll_request_response__get_word
+ (req_p, 1);
+ bytecount_h =
+ cy_as_ll_request_response__get_word
+ (req_p, 2);
+ send_obj_data.byte_count =
+ (bytecount_h << 16) | bytecount_l;
+
+ send_obj_data.status = status;
+
+ /* use the byte count again */
+ bytecount_l =
+ cy_as_ll_request_response__get_word
+ (req_p, 3);
+ bytecount_h =
+ cy_as_ll_request_response__get_word
+ (req_p, 4);
+ send_obj_data.transaction_id =
+ (bytecount_h << 16) | bytecount_l;
+
+ dev_p->mtp_turbo_active = cy_false;
+
+ if (dev_p->mtp_event_cb)
+ dev_p->mtp_event_cb(
+ (cy_as_device_handle) dev_p,
+ cy_as_mtp_send_object_complete,
+ &send_obj_data);
+ }
+ break;
+
+ case 1: /* GetObject Complete */
+ {
+ bytecount_l =
+ cy_as_ll_request_response__get_word
+ (req_p, 1);
+ bytecount_h =
+ cy_as_ll_request_response__get_word
+ (req_p, 2);
+
+ get_obj_data.byte_count =
+ (bytecount_h << 16) | bytecount_l;
+
+ get_obj_data.status = status;
+
+ dev_p->mtp_turbo_active = cy_false;
+
+ if (dev_p->mtp_event_cb)
+ dev_p->mtp_event_cb(
+ (cy_as_device_handle) dev_p,
+ cy_as_mtp_get_object_complete,
+ &get_obj_data);
+ }
+ break;
+
+ case 2: /* BlockTable Needed */
+ {
+ if (dev_p->mtp_event_cb)
+ dev_p->mtp_event_cb(
+ (cy_as_device_handle) dev_p,
+ cy_as_mtp_block_table_needed, 0);
+ }
+ break;
+ default:
+ cy_as_hal_print_message("invalid event type\n");
+ cy_as_ll_send_data_response(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 =
+ cy_as_ll_request_response__get_word(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. */
+ cy_as_hal_assert(ep_p->queue_p != 0);
+
+ /* Put the len in ep data information in
+ * dmaqueue and kick start the queue */
+ cy_as_hal_assert(ep_p->queue_p->size >= mtp_datalen);
+
+ if (mtp_datalen == 0) {
+ cy_as_dma_completed_callback(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
+ * cy_as_dma_kick_start 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.
+ */
+ cy_as_dma_end_point_set_stopped(ep_p);
+
+ /* Kick start the queue if it is not running */
+ cy_as_dma_kick_start(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.
+ */
+ cy_as_ll_send_status_response(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);
+ cy_as_hal_assert(ep_p->queue_p != 0);
+
+ cy_as_dma_end_point_set_stopped(ep_p);
+ cy_as_dma_kick_start(dev_p, CY_AS_MTP_WRITE_ENDPOINT);
+ }
+ break;
+
+ default:
+ cy_as_hal_print_message("invalid request received "
+ "on TUR context\n");
+ val = req_p->box0;
+ cy_as_ll_send_data_response(dev_p, CY_RQT_TUR_RQT_CONTEXT,
+ CY_RESP_INVALID_REQUEST, sizeof(val), &val);
+ break;
+ }
+}
+
+static cy_as_return_status_t
+my_handle_response_no_data(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_mtp_start(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ dev_p->mtp_count++;
+
+ cy_as_dma_enable_end_point(dev_p, CY_AS_MTP_READ_ENDPOINT,
+ cy_true, cy_as_direction_out);
+ dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].enabled = cy_true;
+ dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].dir = cy_as_usb_out;
+ dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].type = cy_as_usb_bulk;
+
+ cy_as_dma_enable_end_point(dev_p, CY_AS_MTP_WRITE_ENDPOINT,
+ cy_true, cy_as_direction_in);
+ dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].enabled = cy_true;
+ dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].dir = cy_as_usb_in;
+ dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].type = cy_as_usb_bulk;
+
+ /* Packet size is 512 bytes */
+ cy_as_dma_set_max_dma_size(dev_p, 0x02, 0x0200);
+ /* Packet size is 64 bytes until a switch to high speed happens.*/
+ cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x40);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ cy_as_ll_register_request_callback(dev_p,
+ CY_RQT_TUR_RQT_CONTEXT, 0);
+
+ cy_as_device_clear_m_s_s_pending(dev_p);
+
+ return ret;
+}
+
+
+cy_as_return_status_t
+cy_as_mtp_start(cy_as_device_handle handle,
+ cy_as_mtp_event_callback event_c_b,
+ cy_as_function_callback cb,
+ uint32_t client
+ )
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p;
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (cy_as_device_is_m_s_s_pending(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;
+
+ cy_as_device_set_m_s_s_pending(dev_p);
+
+ if (dev_p->mtp_count == 0) {
+
+ dev_p->mtp_event_cb = event_c_b;
+ /*
+ * we register here becuase the start request may cause
+ * events to occur before the response to the start request.
+ */
+ cy_as_ll_register_request_callback(dev_p,
+ CY_RQT_TUR_RQT_CONTEXT, my_mtp_request_callback);
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_START_MTP, CY_RQT_TUR_RQT_CONTEXT, 0);
+ if (req_p == 0) {
+ cy_as_device_clear_m_s_s_pending(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* Reserve space for the reply, the reply data will
+ * not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_device_clear_m_s_s_pending(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_mtp_start(dev_p, req_p,
+ reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MTP_START, 0, dev_p->func_cbs_mtp,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_mtp_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ } else {
+ dev_p->mtp_count++;
+ if (cb)
+ cb(handle, ret, client, CY_FUNCT_CB_MTP_START, 0);
+ }
+
+ cy_as_device_clear_m_s_s_pending(dev_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_mtp_stop(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(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:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ cy_as_ll_register_request_callback(dev_p,
+ CY_RQT_TUR_RQT_CONTEXT, 0);
+
+ cy_as_device_clear_m_s_s_pending(dev_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_mtp_stop(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client
+ )
+{
+ cy_as_ll_request_response *req_p = 0, *reply_p = 0;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_mtp_stop called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_mtp_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (cy_as_device_is_m_s_s_pending(dev_p))
+ return CY_AS_ERROR_STARTSTOP_PENDING;
+
+ cy_as_device_set_m_s_s_pending(dev_p);
+
+ if (dev_p->mtp_count == 1) {
+ /* Create the request to send to the West
+ * Bridge device */
+ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ ret = CY_AS_ERROR_OUT_OF_MEMORY;
+ goto destroy;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_mtp_stop(dev_p, req_p,
+ reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_MTP_STOP, 0, dev_p->func_cbs_mtp,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_mtp_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(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);
+ }
+
+ cy_as_device_clear_m_s_s_pending(dev_p);
+
+ return ret;
+}
+
+static void
+mtp_write_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if (cy_as_ll_request_response__get_code(resp) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word(resp, 0);
+ }
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ /* Firmware failed the request. Cancel the DMA transfer. */
+ cy_as_dma_cancel(dev_p, 0x04, CY_AS_ERROR_CANCELED);
+ cy_as_device_clear_storage_async_pending(dev_p);
+ }
+
+ cy_as_ll_destroy_response(dev_p, resp);
+ cy_as_ll_destroy_request(dev_p, rqt);
+}
+
+static void
+async_write_request_callback(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, void *buf_p, uint32_t size,
+ cy_as_return_status_t err)
+{
+ cy_as_device_handle h;
+ cy_as_function_callback cb;
+
+ (void)size;
+ (void)buf_p;
+ (void)ep;
+
+
+ cy_as_log_debug_message(6, "async_write_request_callback called");
+
+ h = (cy_as_device_handle)dev_p;
+
+ cb = dev_p->mtp_cb;
+ dev_p->mtp_cb = 0;
+
+ cy_as_device_clear_storage_async_pending(dev_p);
+
+ if (cb)
+ cb(h, err, dev_p->mtp_client, dev_p->mtp_op, 0);
+
+}
+
+static void
+sync_mtp_callback(cy_as_device *dev_p, cy_as_end_point_number_t ep,
+ void *buf_p, uint32_t size, cy_as_return_status_t err)
+{
+ (void)ep;
+ (void)buf_p;
+ (void)size;
+
+ dev_p->mtp_error = err;
+}
+
+static cy_as_return_status_t
+cy_as_mtp_operation(cy_as_device *dev_p,
+ cy_as_mtp_block_table *blk_table,
+ uint32_t num_bytes,
+ uint32_t transaction_id,
+ cy_as_function_callback cb,
+ uint32_t client,
+ uint8_t rqttype
+ )
+{
+ cy_as_ll_request_response *req_p = 0, *reply_p = 0;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint32_t mask = 0;
+ cy_as_funct_c_b_type mtp_cb_op = 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 = cy_true;
+ } else if (rqttype == CY_RQT_INIT_GET_OBJECT) {
+ mtp_cb_op = CY_FUNCT_CB_MTP_INIT_GET_OBJECT;
+ dev_p->mtp_turbo_active = cy_true;
+ } else
+ mtp_cb_op = CY_FUNCT_CB_MTP_SEND_BLOCK_TABLE;
+
+ ret = is_mtp_active(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 = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ ret = CY_AS_ERROR_OUT_OF_MEMORY;
+ goto destroy;
+ }
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)(num_bytes & 0xFFFF));
+ cy_as_ll_request_response__set_word(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) {
+ cy_as_ll_request_response__set_word(req_p, 2,
+ (uint16_t)(transaction_id & 0xFFFF));
+ cy_as_ll_request_response__set_word(req_p, 3,
+ (uint16_t)((transaction_id >> 16) & 0xFFFF));
+ }
+
+ if (cb == 0) {
+ /* Queue the DMA request for block table write */
+ ret = cy_as_dma_queue_request(dev_p, 4, blk_table,
+ sizeof(cy_as_mtp_block_table), cy_false,
+ cy_false, sync_mtp_callback);
+
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p, 4, CY_AS_ERROR_CANCELED);
+ cy_as_device_clear_storage_async_pending(dev_p);
+
+ goto destroy;
+ }
+
+ ret = cy_as_dma_drain_queue(dev_p, 4, cy_true);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ ret = dev_p->mtp_error;
+ goto destroy;
+ } else {
+#if 0
+ ret = cy_as_misc_send_request(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, cy_as_mtp_func_callback);
+
+ 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 = cy_as_hal_disable_interrupts();
+ if ((cy_as_device_is_storage_async_pending(dev_p)) ||
+ (dev_p->storage_wait)) {
+ cy_as_hal_enable_interrupts(mask);
+ return CY_AS_ERROR_ASYNC_PENDING;
+ }
+ cy_as_device_set_storage_async_pending(dev_p);
+ cy_as_hal_enable_interrupts(mask);
+
+ dev_p->mtp_cb = cb;
+ dev_p->mtp_client = client;
+ dev_p->mtp_op = mtp_cb_op;
+
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
+ cy_false, mtp_write_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ ret = cy_as_dma_queue_request(dev_p, 4, blk_table,
+ sizeof(cy_as_mtp_block_table), cy_false, cy_false,
+ async_write_request_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Kick start the queue if it is not running */
+ cy_as_dma_kick_start(dev_p, 4);
+
+ return CY_AS_ERROR_SUCCESS;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_mtp_init_send_object(cy_as_device_handle handle,
+ cy_as_mtp_block_table *blk_table,
+ uint32_t num_bytes,
+ cy_as_function_callback cb,
+ uint32_t client
+ )
+{
+ cy_as_device *dev_p;
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ return cy_as_mtp_operation(dev_p, blk_table, num_bytes, 0, cb,
+ client, CY_RQT_INIT_SEND_OBJECT);
+
+}
+
+cy_as_return_status_t
+cy_as_mtp_init_get_object(cy_as_device_handle handle,
+ cy_as_mtp_block_table *blk_table,
+ uint32_t num_bytes,
+ uint32_t transaction_id,
+ cy_as_function_callback cb,
+ uint32_t client
+ )
+{
+ cy_as_device *dev_p;
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ return cy_as_mtp_operation(dev_p, blk_table, num_bytes,
+ transaction_id, cb, client, CY_RQT_INIT_GET_OBJECT);
+
+}
+
+static cy_as_return_status_t
+my_handle_response_cancel_send_object(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_mtp_cancel_send_object(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client
+ )
+{
+ cy_as_ll_request_response *req_p = 0, *reply_p = 0;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p;
+
+ dev_p = (cy_as_device *)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 = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ ret = CY_AS_ERROR_OUT_OF_MEMORY;
+ goto destroy;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_cancel_send_object(dev_p,
+ req_p, reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(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, cy_as_mtp_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_cancel_get_object(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_mtp_cancel_get_object(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client
+ )
+{
+ cy_as_ll_request_response *req_p = 0, *reply_p = 0;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p;
+
+ dev_p = (cy_as_device *)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 = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ ret = CY_AS_ERROR_OUT_OF_MEMORY;
+ goto destroy;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_cancel_get_object(dev_p,
+ req_p, reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(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, cy_as_mtp_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_mtp_send_block_table(cy_as_device_handle handle,
+ cy_as_mtp_block_table *blk_table,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p;
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ return cy_as_mtp_operation(dev_p, blk_table, 0, 0, cb,
+ client, CY_RQT_SEND_BLOCK_TABLE);
+}
+
+static void
+cy_as_mtp_func_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t stat)
+{
+ cy_as_func_c_b_node* node = (cy_as_func_c_b_node *)
+ dev_p->func_cbs_mtp->head_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t code;
+ cy_bool delay_callback = cy_false;
+
+ cy_as_hal_assert(dev_p->func_cbs_mtp->count != 0);
+ cy_as_hal_assert(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 = cy_as_ll_request_response__get_code(rqt);
+ switch (code) {
+ case CY_RQT_START_MTP:
+ ret = my_handle_response_mtp_start(dev_p, rqt,
+ resp, stat);
+ break;
+ case CY_RQT_STOP_MTP:
+ ret = my_handle_response_mtp_stop(dev_p, rqt,
+ resp, stat);
+ break;
+#if 0
+ case CY_RQT_INIT_SEND_OBJECT:
+ ret = my_handle_response_init_send_object(dev_p,
+ rqt, resp, stat, cy_true);
+ delay_callback = cy_true;
+ break;
+#endif
+ case CY_RQT_CANCEL_SEND_OBJECT:
+ ret = my_handle_response_cancel_send_object(dev_p,
+ rqt, resp, stat);
+ break;
+#if 0
+ case CY_RQT_INIT_GET_OBJECT:
+ ret = my_handle_response_init_get_object(dev_p,
+ rqt, resp, stat, cy_true);
+ delay_callback = cy_true;
+ break;
+#endif
+ case CY_RQT_CANCEL_GET_OBJECT:
+ ret = my_handle_response_cancel_get_object(dev_p,
+ rqt, resp, stat);
+ break;
+#if 0
+ case CY_RQT_SEND_BLOCK_TABLE:
+ ret = my_handle_response_send_block_table(dev_p, rqt,
+ resp, stat, cy_true);
+ delay_callback = cy_true;
+ break;
+#endif
+ case CY_RQT_ENABLE_USB_PATH:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ dev_p->is_storage_only_mode = cy_false;
+ break;
+ default:
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ cy_as_hal_assert(cy_false);
+ 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((cy_as_device_handle)dev_p, stat, node->client_data,
+ node->data_type, node->data);
+ cy_as_remove_c_b_node(dev_p->func_cbs_mtp);
+ }
+}
+
+cy_as_return_status_t
+cy_as_mtp_storage_only_start(cy_as_device_handle handle)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(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 = cy_true;
+ return CY_AS_ERROR_SUCCESS;
+}
+
+cy_as_return_status_t
+cy_as_mtp_storage_only_stop(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(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 == cy_false)
+ return CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ ret = my_handle_response_no_data(dev_p, req_p,
+ reply_p);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ dev_p->is_storage_only_mode = cy_false;
+ return ret;
+ } else {
+ ret = cy_as_misc_send_request(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, cy_as_mtp_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
diff --git a/drivers/staging/westbridge/astoria/api/src/cyasstorage.c b/drivers/staging/westbridge/astoria/api/src/cyasstorage.c
new file mode 100644
index 000000000000..083d869e57c6
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyasstorage.c
@@ -0,0 +1,4104 @@
+/* Cypress West Bridge API source file (cyasstorage.c)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+/*
+* Storage Design
+*
+* The storage module is fairly straight forward once the
+* DMA and LOWLEVEL modules have been designed. The
+* storage module simple takes requests from the user, queues
+* the associated DMA requests for action, and then sends
+* the low level requests to the West Bridge firmware.
+*
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyasstorage.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+#include "../../include/linux/westbridge/cyasdevice.h"
+#include "../../include/linux/westbridge/cyaslowlevel.h"
+#include "../../include/linux/westbridge/cyasdma.h"
+#include "../../include/linux/westbridge/cyasregs.h"
+
+/* Map a pre-V1.2 media type to the V1.2+ bus number */
+cy_as_return_status_t
+cy_an_map_bus_from_media_type(cy_as_device *dev_p,
+ cy_as_media_type type, cy_as_bus_number_t *bus)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t code = (uint8_t)(1 << type);
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+
+ if (dev_p->media_supported[0] & code) {
+ if (dev_p->media_supported[1] & code) {
+ /*
+ * this media type could be supported on multiple
+ * buses. so, report an address resolution error.
+ */
+ ret = CY_AS_ERROR_ADDRESS_RESOLUTION_ERROR;
+ } else
+ *bus = 0;
+ } else {
+ if (dev_p->media_supported[1] & code)
+ *bus = 1;
+ else
+ ret = CY_AS_ERROR_NO_SUCH_MEDIA;
+ }
+
+ return ret;
+}
+
+static uint16_t
+create_address(cy_as_bus_number_t bus, uint32_t device, uint8_t unit)
+{
+ cy_as_hal_assert(bus >= 0 && bus < CY_AS_MAX_BUSES);
+ cy_as_hal_assert(device < 16);
+
+ return (uint16_t)(((uint8_t)bus << 12) | (device << 8) | unit);
+}
+
+cy_as_media_type
+cy_as_storage_get_media_from_address(uint16_t v)
+{
+ cy_as_media_type media = cy_as_media_max_media_value;
+
+ switch (v & 0xFF) {
+ case 0x00:
+ break;
+ case 0x01:
+ media = cy_as_media_nand;
+ break;
+ case 0x02:
+ media = cy_as_media_sd_flash;
+ break;
+ case 0x04:
+ media = cy_as_media_mmc_flash;
+ break;
+ case 0x08:
+ media = cy_as_media_ce_ata;
+ break;
+ case 0x10:
+ media = cy_as_media_sdio;
+ break;
+ default:
+ cy_as_hal_assert(0);
+ break;
+ }
+
+ return media;
+}
+
+cy_as_bus_number_t
+cy_as_storage_get_bus_from_address(uint16_t v)
+{
+ cy_as_bus_number_t bus = (cy_as_bus_number_t)((v >> 12) & 0x0f);
+ cy_as_hal_assert(bus >= 0 && bus < CY_AS_MAX_BUSES);
+ return bus;
+}
+
+uint32_t
+cy_as_storage_get_device_from_address(uint16_t v)
+{
+ return (uint32_t)((v >> 8) & 0x0f);
+}
+
+static uint8_t
+get_unit_from_address(uint16_t v)
+{
+ return (uint8_t)(v & 0xff);
+}
+
+static cy_as_return_status_t
+cy_as_map_bad_addr(uint16_t val)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_INVALID_RESPONSE;
+
+ switch (val) {
+ case 0:
+ ret = CY_AS_ERROR_NO_SUCH_BUS;
+ break;
+ case 1:
+ ret = CY_AS_ERROR_NO_SUCH_DEVICE;
+ break;
+ case 2:
+ ret = CY_AS_ERROR_NO_SUCH_UNIT;
+ break;
+ case 3:
+ ret = CY_AS_ERROR_INVALID_BLOCK;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+my_storage_request_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *resp_p,
+ cy_as_return_status_t ret)
+{
+ uint16_t val;
+ uint16_t addr;
+ cy_as_bus_number_t bus;
+ uint32_t device;
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+ cy_as_dma_end_point *ep_p = NULL;
+
+ (void)resp_p;
+ (void)context;
+ (void)ret;
+
+ switch (cy_as_ll_request_response__get_code(req_p)) {
+ case CY_RQT_MEDIA_CHANGED:
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+
+ /* Media has either been inserted or removed */
+ addr = cy_as_ll_request_response__get_word(req_p, 0);
+
+ bus = cy_as_storage_get_bus_from_address(addr);
+ device = cy_as_storage_get_device_from_address(addr);
+
+ /* Clear the entry for this device to force re-query later */
+ cy_as_hal_mem_set(&(dev_p->storage_device_info[bus][device]), 0,
+ sizeof(dev_p->storage_device_info[bus][device]));
+
+ val = cy_as_ll_request_response__get_word(req_p, 1);
+ if (dev_p->storage_event_cb_ms) {
+ if (val == 1)
+ dev_p->storage_event_cb_ms(h, bus,
+ device, cy_as_storage_removed, 0);
+ else
+ dev_p->storage_event_cb_ms(h, bus,
+ device, cy_as_storage_inserted, 0);
+ } else if (dev_p->storage_event_cb) {
+ if (val == 1)
+ dev_p->storage_event_cb(h, bus,
+ cy_as_storage_removed, 0);
+ else
+ dev_p->storage_event_cb(h, bus,
+ cy_as_storage_inserted, 0);
+ }
+
+ break;
+
+ case CY_RQT_ANTIOCH_CLAIM:
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ if (dev_p->storage_event_cb || dev_p->storage_event_cb_ms) {
+ val = cy_as_ll_request_response__get_word(req_p, 0);
+ if (dev_p->storage_event_cb_ms) {
+ if (val & 0x0100)
+ dev_p->storage_event_cb_ms(h, 0, 0,
+ cy_as_storage_antioch, 0);
+ if (val & 0x0200)
+ dev_p->storage_event_cb_ms(h, 1, 0,
+ cy_as_storage_antioch, 0);
+ } else {
+ if (val & 0x01)
+ dev_p->storage_event_cb(h,
+ cy_as_media_nand,
+ cy_as_storage_antioch, 0);
+ if (val & 0x02)
+ dev_p->storage_event_cb(h,
+ cy_as_media_sd_flash,
+ cy_as_storage_antioch, 0);
+ if (val & 0x04)
+ dev_p->storage_event_cb(h,
+ cy_as_media_mmc_flash,
+ cy_as_storage_antioch, 0);
+ if (val & 0x08)
+ dev_p->storage_event_cb(h,
+ cy_as_media_ce_ata,
+ cy_as_storage_antioch, 0);
+ }
+ }
+ break;
+
+ case CY_RQT_ANTIOCH_RELEASE:
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ val = cy_as_ll_request_response__get_word(req_p, 0);
+ if (dev_p->storage_event_cb_ms) {
+ if (val & 0x0100)
+ dev_p->storage_event_cb_ms(h, 0, 0,
+ cy_as_storage_processor, 0);
+ if (val & 0x0200)
+ dev_p->storage_event_cb_ms(h, 1, 0,
+ cy_as_storage_processor, 0);
+ } else if (dev_p->storage_event_cb) {
+ if (val & 0x01)
+ dev_p->storage_event_cb(h,
+ cy_as_media_nand,
+ cy_as_storage_processor, 0);
+ if (val & 0x02)
+ dev_p->storage_event_cb(h,
+ cy_as_media_sd_flash,
+ cy_as_storage_processor, 0);
+ if (val & 0x04)
+ dev_p->storage_event_cb(h,
+ cy_as_media_mmc_flash,
+ cy_as_storage_processor, 0);
+ if (val & 0x08)
+ dev_p->storage_event_cb(h,
+ cy_as_media_ce_ata,
+ cy_as_storage_processor, 0);
+ }
+ break;
+
+
+ case CY_RQT_SDIO_INTR:
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ val = cy_as_ll_request_response__get_word(req_p, 0);
+ if (dev_p->storage_event_cb_ms) {
+ if (val & 0x0100)
+ dev_p->storage_event_cb_ms(h, 1, 0,
+ cy_as_sdio_interrupt, 0);
+ else
+ dev_p->storage_event_cb_ms(h, 0, 0,
+ cy_as_sdio_interrupt, 0);
+
+ } else if (dev_p->storage_event_cb) {
+ dev_p->storage_event_cb(h,
+ cy_as_media_sdio, cy_as_sdio_interrupt, 0);
+ }
+ break;
+
+ case CY_RQT_P2S_DMA_START:
+ /* Do the DMA setup for the waiting operation. */
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ cy_as_device_set_p2s_dma_start_recvd(dev_p);
+ if (dev_p->storage_oper == cy_as_op_read) {
+ ep_p = CY_AS_NUM_EP(dev_p, CY_AS_P2S_READ_ENDPOINT);
+ cy_as_dma_end_point_set_stopped(ep_p);
+ cy_as_dma_kick_start(dev_p, CY_AS_P2S_READ_ENDPOINT);
+ } else {
+ ep_p = CY_AS_NUM_EP(dev_p, CY_AS_P2S_WRITE_ENDPOINT);
+ cy_as_dma_end_point_set_stopped(ep_p);
+ cy_as_dma_kick_start(dev_p, CY_AS_P2S_WRITE_ENDPOINT);
+ }
+ break;
+
+ default:
+ cy_as_hal_print_message("invalid request received "
+ "on storage context\n");
+ val = req_p->box0;
+ cy_as_ll_send_data_response(dev_p, CY_RQT_STORAGE_RQT_CONTEXT,
+ CY_RESP_INVALID_REQUEST, sizeof(val), &val);
+ break;
+ }
+}
+
+static cy_as_return_status_t
+is_storage_active(cy_as_device *dev_p)
+{
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (dev_p->storage_count == 0)
+ return CY_AS_ERROR_NOT_RUNNING;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+cy_as_storage_func_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret);
+
+static cy_as_return_status_t
+my_handle_response_no_data(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_storage_start(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (dev_p->storage_count > 0 && ret ==
+ CY_AS_ERROR_ALREADY_RUNNING)
+ ret = CY_AS_ERROR_SUCCESS;
+
+ ret = cy_as_dma_enable_end_point(dev_p,
+ CY_AS_P2S_WRITE_ENDPOINT, cy_true, cy_as_direction_in);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ ret = cy_as_dma_set_max_dma_size(dev_p,
+ CY_AS_P2S_WRITE_ENDPOINT, CY_AS_STORAGE_EP_SIZE);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ ret = cy_as_dma_enable_end_point(dev_p,
+ CY_AS_P2S_READ_ENDPOINT, cy_true, cy_as_direction_out);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ ret = cy_as_dma_set_max_dma_size(dev_p,
+ CY_AS_P2S_READ_ENDPOINT, CY_AS_STORAGE_EP_SIZE);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ cy_as_ll_register_request_callback(dev_p,
+ CY_RQT_STORAGE_RQT_CONTEXT, my_storage_request_callback);
+
+ /* Create the request/response used for storage reads and writes. */
+ dev_p->storage_rw_req_p = cy_as_ll_create_request(dev_p,
+ 0, CY_RQT_STORAGE_RQT_CONTEXT, 5);
+ if (dev_p->storage_rw_req_p == 0) {
+ ret = CY_AS_ERROR_OUT_OF_MEMORY;
+ goto destroy;
+ }
+
+ dev_p->storage_rw_resp_p = cy_as_ll_create_response(dev_p, 5);
+ if (dev_p->storage_rw_resp_p == 0) {
+ cy_as_ll_destroy_request(dev_p, dev_p->storage_rw_req_p);
+ ret = CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ /* Increment the storage count only if
+ * the above functionality succeeds.*/
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if (dev_p->storage_count == 0) {
+ cy_as_hal_mem_set(dev_p->storage_device_info,
+ 0, sizeof(dev_p->storage_device_info));
+ dev_p->is_storage_only_mode = cy_false;
+ }
+
+ dev_p->storage_count++;
+ }
+
+ cy_as_device_clear_s_s_s_pending(dev_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_start(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ if (cy_as_device_is_s_s_s_pending(dev_p))
+ return CY_AS_ERROR_STARTSTOP_PENDING;
+
+ cy_as_device_set_s_s_s_pending(dev_p);
+
+ if (dev_p->storage_count == 0) {
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_START_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0) {
+ cy_as_device_clear_s_s_s_pending(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* Reserve space for the reply, the reply data
+ * will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_device_clear_s_s_s_pending(dev_p);
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_storage_start(dev_p,
+ req_p, reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_START, 0, dev_p->func_cbs_stor,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as
+ * part of the FuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ } else {
+ dev_p->storage_count++;
+ if (cb)
+ cb(handle, ret, client, CY_FUNCT_CB_STOR_START, 0);
+ }
+
+ cy_as_device_clear_s_s_s_pending(dev_p);
+
+ return ret;
+}
+
+
+static cy_as_return_status_t
+my_handle_response_storage_stop(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ cy_as_ll_destroy_request(dev_p, dev_p->storage_rw_req_p);
+ cy_as_ll_destroy_response(dev_p, dev_p->storage_rw_resp_p);
+ dev_p->storage_count--;
+ }
+
+ cy_as_device_clear_s_s_s_pending(dev_p);
+
+ return ret;
+}
+cy_as_return_status_t
+cy_as_storage_stop(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_storage_async_pending(dev_p))
+ return CY_AS_ERROR_ASYNC_PENDING;
+
+ if (cy_as_device_is_s_s_s_pending(dev_p))
+ return CY_AS_ERROR_STARTSTOP_PENDING;
+
+ cy_as_device_set_s_s_s_pending(dev_p);
+
+ if (dev_p->storage_count == 1) {
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_STOP_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 0);
+ if (req_p == 0) {
+ cy_as_device_clear_s_s_s_pending(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* Reserve space for the reply, the reply data
+ * will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_device_clear_s_s_s_pending(dev_p);
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_storage_stop(dev_p,
+ req_p, reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_STOP, 0, dev_p->func_cbs_stor,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ } else if (dev_p->storage_count > 1) {
+ dev_p->storage_count--;
+ if (cb)
+ cb(handle, ret, client, CY_FUNCT_CB_STOR_STOP, 0);
+ }
+
+ cy_as_device_clear_s_s_s_pending(dev_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_register_callback(cy_as_device_handle handle,
+ cy_as_storage_event_callback callback)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (dev_p->storage_count == 0)
+ return CY_AS_ERROR_NOT_RUNNING;
+
+ dev_p->storage_event_cb = NULL;
+ dev_p->storage_event_cb_ms = callback;
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+
+
+static cy_as_return_status_t
+my_handle_response_storage_claim(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_NO_SUCH_ADDRESS) {
+ ret = cy_as_map_bad_addr(
+ cy_as_ll_request_response__get_word(reply_p, 3));
+ goto destroy;
+ }
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_MEDIA_CLAIMED_RELEASED) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ /* The response must be about the address I am
+ * trying to claim or the firmware is broken */
+ if ((cy_as_storage_get_bus_from_address(
+ cy_as_ll_request_response__get_word(req_p, 0)) !=
+ cy_as_storage_get_bus_from_address(
+ cy_as_ll_request_response__get_word(reply_p, 0))) ||
+ (cy_as_storage_get_device_from_address(
+ cy_as_ll_request_response__get_word(req_p, 0)) !=
+ cy_as_storage_get_device_from_address(
+ cy_as_ll_request_response__get_word(reply_p, 0)))) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ if (cy_as_ll_request_response__get_word(reply_p, 1) != 1)
+ ret = CY_AS_ERROR_NOT_ACQUIRED;
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_storage_claim(cy_as_device *dev_p,
+ void *data,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint16_t req_flags,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (dev_p->mtp_count > 0)
+ return CY_AS_ERROR_NOT_VALID_IN_MTP;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_CLAIM_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p,
+ 0, create_address(bus, device, 0));
+
+ /* Reserve space for the reply, the reply data will
+ * not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 4);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_storage_claim(dev_p, req_p, reply_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_CLAIM, data, dev_p->func_cbs_stor,
+ req_flags, req_p, reply_p,
+ cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of
+ * the MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_claim(cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (bus < 0 || bus >= CY_AS_MAX_BUSES)
+ return CY_AS_ERROR_NO_SUCH_BUS;
+
+ return my_storage_claim(dev_p, NULL, bus, device,
+ CY_AS_REQUEST_RESPONSE_MS, cb, client);
+}
+
+static cy_as_return_status_t
+my_handle_response_storage_release(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_NO_SUCH_ADDRESS) {
+ ret = cy_as_map_bad_addr(
+ cy_as_ll_request_response__get_word(reply_p, 3));
+ goto destroy;
+ }
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_MEDIA_CLAIMED_RELEASED) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ /* The response must be about the address I am
+ * trying to release or the firmware is broken */
+ if ((cy_as_storage_get_bus_from_address(
+ cy_as_ll_request_response__get_word(req_p, 0)) !=
+ cy_as_storage_get_bus_from_address(
+ cy_as_ll_request_response__get_word(reply_p, 0))) ||
+ (cy_as_storage_get_device_from_address(
+ cy_as_ll_request_response__get_word(req_p, 0)) !=
+ cy_as_storage_get_device_from_address(
+ cy_as_ll_request_response__get_word(reply_p, 0)))) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+
+ if (cy_as_ll_request_response__get_word(reply_p, 1) != 0)
+ ret = CY_AS_ERROR_NOT_RELEASED;
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_storage_release(cy_as_device *dev_p,
+ void *data,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint16_t req_flags,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (dev_p->mtp_count > 0)
+ return CY_AS_ERROR_NOT_VALID_IN_MTP;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_RELEASE_STORAGE,
+ CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(
+ req_p, 0, create_address(bus, device, 0));
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 4);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_storage_release(
+ dev_p, req_p, reply_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_RELEASE, data, dev_p->func_cbs_stor,
+ req_flags, req_p, reply_p,
+ cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as
+ * part of the MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_release(cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (bus < 0 || bus >= CY_AS_MAX_BUSES)
+ return CY_AS_ERROR_NO_SUCH_BUS;
+
+ return my_storage_release(dev_p, NULL, bus, device,
+ CY_AS_REQUEST_RESPONSE_MS, cb, client);
+}
+
+static cy_as_return_status_t
+my_handle_response_storage_query_bus(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ uint32_t *count)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t code = cy_as_ll_request_response__get_code(reply_p);
+ uint16_t v;
+
+ if (code == CY_RESP_NO_SUCH_ADDRESS) {
+ ret = CY_AS_ERROR_NO_SUCH_BUS;
+ goto destroy;
+ }
+
+ if (code != CY_RESP_BUS_DESCRIPTOR) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ /*
+ * verify that the response corresponds to the bus that was queried.
+ */
+ if (cy_as_storage_get_bus_from_address(
+ cy_as_ll_request_response__get_word(req_p, 0)) !=
+ cy_as_storage_get_bus_from_address(
+ cy_as_ll_request_response__get_word(reply_p, 0))) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ v = cy_as_ll_request_response__get_word(reply_p, 1);
+ if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) {
+ /*
+ * this request is only for the count of devices
+ * on the bus. there is no need to check the media type.
+ */
+ if (v)
+ *count = 1;
+ else
+ *count = 0;
+ } else {
+ /*
+ * this request is for the count of devices of a
+ * particular type. we need to check whether the media
+ * type found matches the queried type.
+ */
+ cy_as_media_type queried = (cy_as_media_type)
+ cy_as_ll_request_response__get_word(req_p, 1);
+ cy_as_media_type found =
+ cy_as_storage_get_media_from_address(v);
+
+ if (queried == found)
+ *count = 1;
+ else
+ *count = 0;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+my_storage_query_bus(cy_as_device *dev_p,
+ cy_as_bus_number_t bus,
+ cy_as_media_type type,
+ uint16_t req_flags,
+ uint32_t *count,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_funct_c_b_type cb_type = CY_FUNCT_CB_STOR_QUERYBUS;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Create the request to send to the Antioch device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_QUERY_BUS, CY_RQT_STORAGE_RQT_CONTEXT, 2);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p,
+ 0, create_address(bus, 0, 0));
+ cy_as_ll_request_response__set_word(req_p, 1, (uint16_t)type);
+
+ /* Reserve space for the reply, the reply data
+ * will not exceed two words. */
+ reply_p = cy_as_ll_create_response(dev_p, 2);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ req_p->flags |= req_flags;
+ return my_handle_response_storage_query_bus(dev_p,
+ req_p, reply_p, count);
+ } else {
+ if (req_flags == CY_AS_REQUEST_RESPONSE_EX)
+ cb_type = CY_FUNCT_CB_STOR_QUERYMEDIA;
+
+ ret = cy_as_misc_send_request(dev_p, cb, client, cb_type,
+ count, dev_p->func_cbs_stor, req_flags,
+ req_p, reply_p, cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of
+ * the MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_query_bus(cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t *count,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ return my_storage_query_bus(dev_p, bus, cy_as_media_max_media_value,
+ CY_AS_REQUEST_RESPONSE_MS, count, cb, client);
+}
+
+cy_as_return_status_t
+cy_as_storage_query_media(cy_as_device_handle handle,
+ cy_as_media_type type,
+ uint32_t *count,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_bus_number_t bus;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ ret = cy_an_map_bus_from_media_type(dev_p, type, &bus);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ return my_storage_query_bus(dev_p, bus, type, CY_AS_REQUEST_RESPONSE_EX,
+ count, cb, client);
+}
+
+static cy_as_return_status_t
+my_handle_response_storage_query_device(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ void *data_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint16_t v;
+ cy_as_bus_number_t bus;
+ cy_as_media_type type;
+ uint32_t device;
+ cy_bool removable;
+ cy_bool writeable;
+ cy_bool locked;
+ uint16_t block_size;
+ uint32_t number_units;
+ uint32_t number_eus;
+
+ if (cy_as_ll_request_response__get_code(reply_p)
+ == CY_RESP_NO_SUCH_ADDRESS) {
+ ret = cy_as_map_bad_addr(
+ cy_as_ll_request_response__get_word(reply_p, 3));
+ goto destroy;
+ }
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_DEVICE_DESCRIPTOR) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ /* Unpack the response */
+ v = cy_as_ll_request_response__get_word(reply_p, 0);
+ type = cy_as_storage_get_media_from_address(v);
+ bus = cy_as_storage_get_bus_from_address(v);
+ device = cy_as_storage_get_device_from_address(v);
+
+ block_size = cy_as_ll_request_response__get_word(reply_p, 1);
+
+ v = cy_as_ll_request_response__get_word(reply_p, 2);
+ removable = (v & 0x8000) ? cy_true : cy_false;
+ writeable = (v & 0x0100) ? cy_true : cy_false;
+ locked = (v & 0x0200) ? cy_true : cy_false;
+ number_units = (v & 0xff);
+
+ number_eus = (cy_as_ll_request_response__get_word(reply_p, 3) << 16)
+ | cy_as_ll_request_response__get_word(reply_p, 4);
+
+ /* Store the results based on the version of originating function */
+ if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) {
+ cy_as_storage_query_device_data *store_p =
+ (cy_as_storage_query_device_data *)data_p;
+
+ /* Make sure the response is about the address we asked
+ * about - if not, firmware error */
+ if ((bus != store_p->bus) || (device != store_p->device)) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ store_p->desc_p.type = type;
+ store_p->desc_p.removable = removable;
+ store_p->desc_p.writeable = writeable;
+ store_p->desc_p.block_size = block_size;
+ store_p->desc_p.number_units = number_units;
+ store_p->desc_p.locked = locked;
+ store_p->desc_p.erase_unit_size = number_eus;
+ dev_p->storage_device_info[bus][device] = store_p->desc_p;
+ } else {
+ cy_as_storage_query_device_data_dep *store_p =
+ (cy_as_storage_query_device_data_dep *)data_p;
+
+ /* Make sure the response is about the address we asked
+ * about - if not, firmware error */
+ if ((type != store_p->type) || (device != store_p->device)) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ store_p->desc_p.type = type;
+ store_p->desc_p.removable = removable;
+ store_p->desc_p.writeable = writeable;
+ store_p->desc_p.block_size = block_size;
+ store_p->desc_p.number_units = number_units;
+ store_p->desc_p.locked = locked;
+ store_p->desc_p.erase_unit_size = number_eus;
+ dev_p->storage_device_info[bus][device] = store_p->desc_p;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_storage_query_device(cy_as_device *dev_p,
+ void *data_p,
+ uint16_t req_flags,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Create the request to send to the Antioch device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_QUERY_DEVICE, CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, device, 0));
+
+ /* Reserve space for the reply, the reply data
+ * will not exceed five words. */
+ reply_p = cy_as_ll_create_response(dev_p, 5);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ req_p->flags |= req_flags;
+ return my_handle_response_storage_query_device(dev_p,
+ req_p, reply_p, data_p);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_QUERYDEVICE, data_p,
+ dev_p->func_cbs_stor, req_flags, req_p,
+ reply_p, cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_query_device(cy_as_device_handle handle,
+ cy_as_storage_query_device_data *data_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ return my_storage_query_device(dev_p, data_p,
+ CY_AS_REQUEST_RESPONSE_MS, data_p->bus,
+ data_p->device, cb, client);
+}
+
+static cy_as_return_status_t
+my_handle_response_storage_query_unit(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ void *data_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_bus_number_t bus;
+ uint32_t device;
+ uint32_t unit;
+ cy_as_media_type type;
+ uint16_t block_size;
+ uint32_t start_block;
+ uint32_t unit_size;
+ uint16_t v;
+
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_NO_SUCH_ADDRESS) {
+ ret = cy_as_map_bad_addr(
+ cy_as_ll_request_response__get_word(reply_p, 3));
+ goto destroy;
+ }
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_UNIT_DESCRIPTOR) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ /* Unpack the response */
+ v = cy_as_ll_request_response__get_word(reply_p, 0);
+ bus = cy_as_storage_get_bus_from_address(v);
+ device = cy_as_storage_get_device_from_address(v);
+ unit = get_unit_from_address(v);
+
+ type = cy_as_storage_get_media_from_address(
+ cy_as_ll_request_response__get_word(reply_p, 1));
+
+ block_size = cy_as_ll_request_response__get_word(reply_p, 2);
+ start_block = cy_as_ll_request_response__get_word(reply_p, 3)
+ | (cy_as_ll_request_response__get_word(reply_p, 4) << 16);
+ unit_size = cy_as_ll_request_response__get_word(reply_p, 5)
+ | (cy_as_ll_request_response__get_word(reply_p, 6) << 16);
+
+ /* Store the results based on the version of
+ * originating function */
+ if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) {
+ cy_as_storage_query_unit_data *store_p =
+ (cy_as_storage_query_unit_data *)data_p;
+
+ /* Make sure the response is about the address we
+ * asked about - if not, firmware error */
+ if (bus != store_p->bus || device != store_p->device ||
+ unit != store_p->unit) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ store_p->desc_p.type = type;
+ store_p->desc_p.block_size = block_size;
+ store_p->desc_p.start_block = start_block;
+ store_p->desc_p.unit_size = unit_size;
+ } else {
+ cy_as_storage_query_unit_data_dep *store_p =
+ (cy_as_storage_query_unit_data_dep *)data_p;
+
+ /* Make sure the response is about the media type we asked
+ * about - if not, firmware error */
+ if ((type != store_p->type) || (device != store_p->device) ||
+ (unit != store_p->unit)) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ store_p->desc_p.type = type;
+ store_p->desc_p.block_size = block_size;
+ store_p->desc_p.start_block = start_block;
+ store_p->desc_p.unit_size = unit_size;
+ }
+
+ dev_p->storage_device_info[bus][device].type = type;
+ dev_p->storage_device_info[bus][device].block_size = block_size;
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_storage_query_unit(cy_as_device *dev_p,
+ void *data_p,
+ uint16_t req_flags,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint32_t unit,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_QUERY_UNIT, CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ if (device > 255)
+ return CY_AS_ERROR_NO_SUCH_DEVICE;
+
+ if (unit > 255)
+ return CY_AS_ERROR_NO_SUCH_UNIT;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, device, (uint8_t)unit));
+
+ /* Reserve space for the reply, the reply data
+ * will be of seven words. */
+ reply_p = cy_as_ll_create_response(dev_p, 7);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ req_p->flags |= req_flags;
+ return my_handle_response_storage_query_unit(dev_p,
+ req_p, reply_p, data_p);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_QUERYUNIT, data_p,
+ dev_p->func_cbs_stor, req_flags, req_p, reply_p,
+ cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_query_unit(cy_as_device_handle handle,
+ cy_as_storage_query_unit_data *data_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ return my_storage_query_unit(dev_p, data_p, CY_AS_REQUEST_RESPONSE_MS,
+ data_p->bus, data_p->device, data_p->unit, cb, client);
+}
+
+
+static cy_as_return_status_t
+cy_as_get_block_size(cy_as_device *dev_p,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_as_function_callback cb)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_QUERY_DEVICE,
+ CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, device, 0));
+
+ reply_p = cy_as_ll_create_response(dev_p, 4);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p)
+ == CY_RESP_NO_SUCH_ADDRESS) {
+ ret = CY_AS_ERROR_NO_SUCH_BUS;
+ goto destroy;
+ }
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_DEVICE_DESCRIPTOR) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ /* Make sure the response is about the media type we asked
+ * about - if not, firmware error */
+ if ((cy_as_storage_get_bus_from_address
+ (cy_as_ll_request_response__get_word(reply_p, 0))
+ != bus) || (cy_as_storage_get_device_from_address
+ (cy_as_ll_request_response__get_word(reply_p, 0))
+ != device)) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+
+ dev_p->storage_device_info[bus][device].block_size =
+ cy_as_ll_request_response__get_word(reply_p, 1);
+ } else
+ ret = CY_AS_ERROR_INVALID_REQUEST;
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+my_storage_device_control(
+ cy_as_device *dev_p,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_bool card_detect_en,
+ cy_bool write_prot_en,
+ cy_as_storage_card_detect config_detect,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret;
+ cy_bool use_gpio = cy_false;
+
+ (void)device;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ if (bus < 0 || bus >= CY_AS_MAX_BUSES)
+ return CY_AS_ERROR_NO_SUCH_BUS;
+
+ if (device >= CY_AS_MAX_STORAGE_DEVICES)
+ return CY_AS_ERROR_NO_SUCH_DEVICE;
+
+ /* If SD is not supported on the specified bus,
+ * then return ERROR */
+ if ((dev_p->media_supported[bus] == 0) ||
+ (dev_p->media_supported[bus] & (1<<cy_as_media_nand)))
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ if (config_detect == cy_as_storage_detect_GPIO)
+ use_gpio = cy_true;
+ else if (config_detect == cy_as_storage_detect_SDAT_3)
+ use_gpio = cy_false;
+ else
+ return CY_AS_ERROR_INVALID_PARAMETER;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_SD_INTERFACE_CONTROL, CY_RQT_STORAGE_RQT_CONTEXT, 2);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p,
+ 0, create_address(bus, device, 0));
+ cy_as_ll_request_response__set_word(req_p,
+ 1, (((uint16_t)card_detect_en << 8) |
+ ((uint16_t)use_gpio << 1) | (uint16_t)write_prot_en));
+
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ } else {
+
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_DEVICECONTROL,
+ 0, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_device_control(cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_bool card_detect_en,
+ cy_bool write_prot_en,
+ cy_as_storage_card_detect config_detect,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ return my_storage_device_control(dev_p, bus, device, card_detect_en,
+ write_prot_en, config_detect, cb, client);
+}
+
+static void
+cy_as_async_storage_callback(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, void *buf_p, uint32_t size,
+ cy_as_return_status_t ret)
+{
+ cy_as_storage_callback_dep cb;
+ cy_as_storage_callback cb_ms;
+
+ (void)size;
+ (void)buf_p;
+ (void)ep;
+
+ cy_as_device_clear_storage_async_pending(dev_p);
+
+ /*
+ * if the LL request callback has already been called,
+ * the user callback has to be called from here.
+ */
+ if (!dev_p->storage_wait) {
+ cy_as_hal_assert(dev_p->storage_cb != NULL ||
+ dev_p->storage_cb_ms != NULL);
+ cb = dev_p->storage_cb;
+ cb_ms = dev_p->storage_cb_ms;
+
+ dev_p->storage_cb = 0;
+ dev_p->storage_cb_ms = 0;
+
+ if (ret == CY_AS_ERROR_SUCCESS)
+ ret = dev_p->storage_error;
+
+ if (cb_ms) {
+ cb_ms((cy_as_device_handle)dev_p,
+ dev_p->storage_bus_index,
+ dev_p->storage_device_index,
+ dev_p->storage_unit,
+ dev_p->storage_block_addr,
+ dev_p->storage_oper, ret);
+ } else {
+ cb((cy_as_device_handle)dev_p,
+ dev_p->storage_device_info
+ [dev_p->storage_bus_index]
+ [dev_p->storage_device_index].type,
+ dev_p->storage_device_index,
+ dev_p->storage_unit,
+ dev_p->storage_block_addr,
+ dev_p->storage_oper, ret);
+ }
+ } else
+ dev_p->storage_error = ret;
+}
+
+static void
+cy_as_async_storage_reply_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ cy_as_storage_callback_dep cb;
+ cy_as_storage_callback cb_ms;
+ uint8_t reqtype;
+ (void)rqt;
+ (void)context;
+
+ reqtype = cy_as_ll_request_response__get_code(rqt);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if (cy_as_ll_request_response__get_code(resp) ==
+ CY_RESP_ANTIOCH_DEFERRED_ERROR) {
+ ret = cy_as_ll_request_response__get_word
+ (resp, 0) & 0x00FF;
+ } else if (cy_as_ll_request_response__get_code(resp) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+ }
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ if (reqtype == CY_RQT_READ_BLOCK)
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_read_endpoint, ret);
+ else
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_write_endpoint, ret);
+ }
+
+ dev_p->storage_wait = cy_false;
+
+ /*
+ * if the DMA callback has already been called, the
+ * user callback has to be called from here.
+ */
+ if (!cy_as_device_is_storage_async_pending(dev_p)) {
+ cy_as_hal_assert(dev_p->storage_cb != NULL ||
+ dev_p->storage_cb_ms != NULL);
+ cb = dev_p->storage_cb;
+ cb_ms = dev_p->storage_cb_ms;
+
+ dev_p->storage_cb = 0;
+ dev_p->storage_cb_ms = 0;
+
+ if (ret == CY_AS_ERROR_SUCCESS)
+ ret = dev_p->storage_error;
+
+ if (cb_ms) {
+ cb_ms((cy_as_device_handle)dev_p,
+ dev_p->storage_bus_index,
+ dev_p->storage_device_index,
+ dev_p->storage_unit,
+ dev_p->storage_block_addr,
+ dev_p->storage_oper, ret);
+ } else {
+ cb((cy_as_device_handle)dev_p,
+ dev_p->storage_device_info
+ [dev_p->storage_bus_index]
+ [dev_p->storage_device_index].type,
+ dev_p->storage_device_index,
+ dev_p->storage_unit,
+ dev_p->storage_block_addr,
+ dev_p->storage_oper, ret);
+ }
+ } else
+ dev_p->storage_error = ret;
+}
+
+static cy_as_return_status_t
+cy_as_storage_async_oper(cy_as_device *dev_p, cy_as_end_point_number_t ep,
+ uint8_t reqtype, uint16_t req_flags, cy_as_bus_number_t bus,
+ uint32_t device, uint32_t unit, uint32_t block, void *data_p,
+ uint16_t num_blocks, cy_as_storage_callback_dep callback,
+ cy_as_storage_callback callback_ms)
+{
+ uint32_t mask;
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (bus < 0 || bus >= CY_AS_MAX_BUSES)
+ return CY_AS_ERROR_NO_SUCH_BUS;
+
+ if (device >= CY_AS_MAX_STORAGE_DEVICES)
+ return CY_AS_ERROR_NO_SUCH_DEVICE;
+
+ if (unit > 255)
+ return CY_AS_ERROR_NO_SUCH_UNIT;
+
+ /* We are supposed to return sucess if the number of
+ * blocks is zero
+ */
+ if (num_blocks == 0) {
+ if (callback_ms)
+ callback_ms((cy_as_device_handle)dev_p,
+ bus, device, unit, block,
+ ((reqtype == CY_RQT_WRITE_BLOCK)
+ ? cy_as_op_write : cy_as_op_read),
+ CY_AS_ERROR_SUCCESS);
+ else
+ callback((cy_as_device_handle)dev_p,
+ dev_p->storage_device_info[bus][device].type,
+ device, unit, block,
+ ((reqtype == CY_RQT_WRITE_BLOCK) ?
+ cy_as_op_write : cy_as_op_read),
+ CY_AS_ERROR_SUCCESS);
+
+ return CY_AS_ERROR_SUCCESS;
+ }
+
+ if (dev_p->storage_device_info[bus][device].block_size == 0)
+ return CY_AS_ERROR_QUERY_DEVICE_NEEDED;
+
+ /*
+ * since async operations can be triggered by interrupt
+ * code, we must insure that we do not get multiple
+ * async operations going at one time and protect this
+ * test and set operation from interrupts. also need to
+ * check for pending async MTP writes
+ */
+ mask = cy_as_hal_disable_interrupts();
+ if ((cy_as_device_is_storage_async_pending(dev_p)) ||
+ (dev_p->storage_wait) ||
+ (cy_as_device_is_usb_async_pending(dev_p, 6))) {
+ cy_as_hal_enable_interrupts(mask);
+ return CY_AS_ERROR_ASYNC_PENDING;
+ }
+
+ cy_as_device_set_storage_async_pending(dev_p);
+ cy_as_device_clear_p2s_dma_start_recvd(dev_p);
+ cy_as_hal_enable_interrupts(mask);
+
+ /*
+ * storage information about the currently outstanding request
+ */
+ dev_p->storage_cb = callback;
+ dev_p->storage_cb_ms = callback_ms;
+ dev_p->storage_bus_index = bus;
+ dev_p->storage_device_index = device;
+ dev_p->storage_unit = unit;
+ dev_p->storage_block_addr = block;
+
+ /* Initialise the request to send to the West Bridge. */
+ req_p = dev_p->storage_rw_req_p;
+ cy_as_ll_init_request(req_p, reqtype, CY_RQT_STORAGE_RQT_CONTEXT, 5);
+
+ /* Initialise the space for reply from the West Bridge. */
+ reply_p = dev_p->storage_rw_resp_p;
+ cy_as_ll_init_response(reply_p, 5);
+
+ /* Remember which version of the API originated the request */
+ req_p->flags |= req_flags;
+
+ /* Setup the DMA request and adjust the storage
+ * operation if we are reading */
+ if (reqtype == CY_RQT_READ_BLOCK) {
+ ret = cy_as_dma_queue_request(dev_p, ep, data_p,
+ dev_p->storage_device_info[bus][device].block_size
+ * num_blocks, cy_false, cy_true,
+ cy_as_async_storage_callback);
+ dev_p->storage_oper = cy_as_op_read;
+ } else if (reqtype == CY_RQT_WRITE_BLOCK) {
+ ret = cy_as_dma_queue_request(dev_p, ep, data_p,
+ dev_p->storage_device_info[bus][device].block_size *
+ num_blocks, cy_false, cy_false,
+ cy_as_async_storage_callback);
+ dev_p->storage_oper = cy_as_op_write;
+ }
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_device_clear_storage_async_pending(dev_p);
+ return ret;
+ }
+
+ cy_as_ll_request_response__set_word(req_p,
+ 0, create_address(bus, (uint8_t)device, (uint8_t)unit));
+ cy_as_ll_request_response__set_word(req_p,
+ 1, (uint16_t)((block >> 16) & 0xffff));
+ cy_as_ll_request_response__set_word(req_p,
+ 2, (uint16_t)(block & 0xffff));
+ cy_as_ll_request_response__set_word(req_p,
+ 3, (uint16_t)((num_blocks >> 8) & 0x00ff));
+ cy_as_ll_request_response__set_word(req_p,
+ 4, (uint16_t)((num_blocks << 8) & 0xff00));
+
+ /* Set the burst mode flag. */
+ if (dev_p->is_storage_only_mode)
+ req_p->data[4] |= 0x0001;
+
+ /* Send the request and wait for completion
+ * of storage request */
+ dev_p->storage_wait = cy_true;
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
+ cy_true, cy_as_async_storage_reply_callback);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
+ cy_as_device_clear_storage_async_pending(dev_p);
+ }
+
+ return ret;
+}
+
+static void
+cy_as_sync_storage_callback(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, void *buf_p,
+ uint32_t size, cy_as_return_status_t err)
+{
+ (void)ep;
+ (void)buf_p;
+ (void)size;
+
+ dev_p->storage_error = err;
+}
+
+static void
+cy_as_sync_storage_reply_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ uint8_t reqtype;
+ (void)rqt;
+
+ reqtype = cy_as_ll_request_response__get_code(rqt);
+
+ if (cy_as_ll_request_response__get_code(resp) ==
+ CY_RESP_ANTIOCH_DEFERRED_ERROR) {
+ ret = cy_as_ll_request_response__get_word(resp, 0) & 0x00FF;
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ if (reqtype == CY_RQT_READ_BLOCK)
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_read_endpoint, ret);
+ else
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_write_endpoint, ret);
+ }
+ } else if (cy_as_ll_request_response__get_code(resp) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+
+ dev_p->storage_wait = cy_false;
+ dev_p->storage_error = ret;
+
+ /* Wake any threads/processes that are waiting on
+ * the read/write completion. */
+ cy_as_hal_wake(&dev_p->context[context]->channel);
+}
+
+static cy_as_return_status_t
+cy_as_storage_sync_oper(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, uint8_t reqtype,
+ cy_as_bus_number_t bus, uint32_t device,
+ uint32_t unit, uint32_t block, void *data_p,
+ uint16_t num_blocks)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_context *ctxt_p;
+ uint32_t loopcount = 200;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (bus < 0 || bus >= CY_AS_MAX_BUSES)
+ return CY_AS_ERROR_NO_SUCH_BUS;
+
+ if (device >= CY_AS_MAX_STORAGE_DEVICES)
+ return CY_AS_ERROR_NO_SUCH_DEVICE;
+
+ if (unit > 255)
+ return CY_AS_ERROR_NO_SUCH_UNIT;
+
+ if ((cy_as_device_is_storage_async_pending(dev_p)) ||
+ (dev_p->storage_wait))
+ return CY_AS_ERROR_ASYNC_PENDING;
+
+ /* Also need to check for pending Async MTP writes */
+ if (cy_as_device_is_usb_async_pending(dev_p, 6))
+ return CY_AS_ERROR_ASYNC_PENDING;
+
+ /* We are supposed to return sucess if the number of
+ * blocks is zero
+ */
+ if (num_blocks == 0)
+ return CY_AS_ERROR_SUCCESS;
+
+ if (dev_p->storage_device_info[bus][device].block_size == 0) {
+ /*
+ * normally, a given device has been queried via
+ * the query device call before a read request is issued.
+ * therefore, this normally will not be run.
+ */
+ ret = cy_as_get_block_size(dev_p, bus, device, 0);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ }
+
+ /* Initialise the request to send to the West Bridge. */
+ req_p = dev_p->storage_rw_req_p;
+ cy_as_ll_init_request(req_p, reqtype,
+ CY_RQT_STORAGE_RQT_CONTEXT, 5);
+
+ /* Initialise the space for reply from
+ * the West Bridge. */
+ reply_p = dev_p->storage_rw_resp_p;
+ cy_as_ll_init_response(reply_p, 5);
+ cy_as_device_clear_p2s_dma_start_recvd(dev_p);
+
+ /* Setup the DMA request */
+ if (reqtype == CY_RQT_READ_BLOCK) {
+ ret = cy_as_dma_queue_request(dev_p, ep, data_p,
+ dev_p->storage_device_info[bus][device].block_size *
+ num_blocks, cy_false,
+ cy_true, cy_as_sync_storage_callback);
+ dev_p->storage_oper = cy_as_op_read;
+ } else if (reqtype == CY_RQT_WRITE_BLOCK) {
+ ret = cy_as_dma_queue_request(dev_p, ep, data_p,
+ dev_p->storage_device_info[bus][device].block_size *
+ num_blocks, cy_false, cy_false,
+ cy_as_sync_storage_callback);
+ dev_p->storage_oper = cy_as_op_write;
+ }
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, (uint8_t)unit));
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)((block >> 16) & 0xffff));
+ cy_as_ll_request_response__set_word(req_p, 2,
+ (uint16_t)(block & 0xffff));
+ cy_as_ll_request_response__set_word(req_p, 3,
+ (uint16_t)((num_blocks >> 8) & 0x00ff));
+ cy_as_ll_request_response__set_word(req_p, 4,
+ (uint16_t)((num_blocks << 8) & 0xff00));
+
+ /* Set the burst mode flag. */
+ if (dev_p->is_storage_only_mode)
+ req_p->data[4] |= 0x0001;
+
+ /* Send the request and wait for
+ * completion of storage request */
+ dev_p->storage_wait = cy_true;
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_true,
+ cy_as_sync_storage_reply_callback);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
+ } else {
+ /* Setup the DMA request */
+ ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT];
+ ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
+
+ while (loopcount-- > 0) {
+ if (dev_p->storage_wait == cy_false)
+ break;
+ cy_as_hal_sleep_on(&ctxt_p->channel, 10);
+ }
+
+ if (dev_p->storage_wait == cy_true) {
+ dev_p->storage_wait = cy_false;
+ cy_as_ll_remove_request(dev_p, ctxt_p, req_p, cy_true);
+ ret = CY_AS_ERROR_TIMEOUT;
+ }
+
+ if (ret == CY_AS_ERROR_SUCCESS)
+ ret = dev_p->storage_error;
+ }
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_read(cy_as_device_handle handle,
+ cy_as_bus_number_t bus, uint32_t device,
+ uint32_t unit, uint32_t block,
+ void *data_p, uint16_t num_blocks)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ return cy_as_storage_sync_oper(dev_p, dev_p->storage_read_endpoint,
+ CY_RQT_READ_BLOCK, bus, device,
+ unit, block, data_p, num_blocks);
+}
+
+cy_as_return_status_t
+cy_as_storage_write(cy_as_device_handle handle,
+ cy_as_bus_number_t bus, uint32_t device,
+ uint32_t unit, uint32_t block, void *data_p,
+ uint16_t num_blocks)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (dev_p->mtp_turbo_active)
+ return CY_AS_ERROR_NOT_VALID_DURING_MTP;
+
+ return cy_as_storage_sync_oper(dev_p,
+ dev_p->storage_write_endpoint,
+ CY_RQT_WRITE_BLOCK, bus, device,
+ unit, block, data_p, num_blocks);
+}
+
+
+cy_as_return_status_t
+cy_as_storage_read_async(cy_as_device_handle handle,
+ cy_as_bus_number_t bus, uint32_t device, uint32_t unit,
+ uint32_t block, void *data_p, uint16_t num_blocks,
+ cy_as_storage_callback callback)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (callback == 0)
+ return CY_AS_ERROR_NULL_CALLBACK;
+
+ return cy_as_storage_async_oper(dev_p,
+ dev_p->storage_read_endpoint, CY_RQT_READ_BLOCK,
+ CY_AS_REQUEST_RESPONSE_MS, bus, device, unit,
+ block, data_p, num_blocks, NULL, callback);
+}
+
+cy_as_return_status_t
+cy_as_storage_write_async(cy_as_device_handle handle,
+ cy_as_bus_number_t bus, uint32_t device, uint32_t unit,
+ uint32_t block, void *data_p, uint16_t num_blocks,
+ cy_as_storage_callback callback)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (callback == 0)
+ return CY_AS_ERROR_NULL_CALLBACK;
+
+ if (dev_p->mtp_turbo_active)
+ return CY_AS_ERROR_NOT_VALID_DURING_MTP;
+
+ return cy_as_storage_async_oper(dev_p,
+ dev_p->storage_write_endpoint, CY_RQT_WRITE_BLOCK,
+ CY_AS_REQUEST_RESPONSE_MS, bus, device, unit, block,
+ data_p, num_blocks, NULL, callback);
+}
+
+
+static void
+my_storage_cancel_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t stat)
+{
+ (void)context;
+ (void)stat;
+
+ /* Nothing to do here, except free up the
+ * request and response structures. */
+ cy_as_ll_destroy_response(dev_p, resp);
+ cy_as_ll_destroy_request(dev_p, rqt);
+}
+
+
+cy_as_return_status_t
+cy_as_storage_cancel_async(cy_as_device_handle handle)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!cy_as_device_is_storage_async_pending(dev_p))
+ return CY_AS_ERROR_ASYNC_NOT_PENDING;
+
+ /*
+ * create and send a mailbox request to firmware
+ * asking it to abort processing of the current
+ * P2S operation. the rest of the cancel processing will be
+ * driven through the callbacks for the read/write call.
+ */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_ABORT_P2S_XFER,
+ CY_RQT_GENERAL_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = cy_as_ll_send_request(dev_p, req_p,
+ reply_p, cy_false, my_storage_cancel_callback);
+ if (ret) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ }
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+ * This function does all the API side clean-up associated with
+ * CyAsStorageStop, without any communication with the firmware.
+ */
+void cy_as_storage_cleanup(cy_as_device *dev_p)
+{
+ if (dev_p->storage_count) {
+ cy_as_ll_destroy_request(dev_p, dev_p->storage_rw_req_p);
+ cy_as_ll_destroy_response(dev_p, dev_p->storage_rw_resp_p);
+ dev_p->storage_count = 0;
+ cy_as_device_clear_scsi_messages(dev_p);
+ cy_as_hal_mem_set(dev_p->storage_device_info,
+ 0, sizeof(dev_p->storage_device_info));
+
+ cy_as_device_clear_storage_async_pending(dev_p);
+ dev_p->storage_cb = 0;
+ dev_p->storage_cb_ms = 0;
+ dev_p->storage_wait = cy_false;
+ }
+}
+
+static cy_as_return_status_t
+my_handle_response_sd_reg_read(
+ cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_storage_sd_reg_read_data *info)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t resp_type, i;
+ uint16_t resp_len;
+ uint8_t length = info->length;
+ uint8_t *data_p = info->buf_p;
+
+ resp_type = cy_as_ll_request_response__get_code(reply_p);
+ if (resp_type == CY_RESP_SD_REGISTER_DATA) {
+ uint16_t *resp_p = reply_p->data + 1;
+ uint16_t temp;
+
+ resp_len = cy_as_ll_request_response__get_word(reply_p, 0);
+ cy_as_hal_assert(resp_len >= length);
+
+ /*
+ * copy the values into the output buffer after doing the
+ * necessary bit shifting. the bit shifting is required because
+ * the data comes out of the west bridge with a 6 bit offset.
+ */
+ i = 0;
+ while (length) {
+ temp = ((resp_p[i] << 6) | (resp_p[i + 1] >> 10));
+ i++;
+
+ *data_p++ = (uint8_t)(temp >> 8);
+ length--;
+
+ if (length) {
+ *data_p++ = (uint8_t)(temp & 0xFF);
+ length--;
+ }
+ }
+ } else {
+ if (resp_type == CY_RESP_SUCCESS_FAILURE)
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ else
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ cy_as_ll_destroy_request(dev_p, req_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_sd_register_read(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint8_t device,
+ cy_as_sd_card_reg_type reg_type,
+ cy_as_storage_sd_reg_read_data *data_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t length;
+
+ /*
+ * sanity checks required before sending the request to the
+ * firmware.
+ */
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (device >= CY_AS_MAX_STORAGE_DEVICES)
+ return CY_AS_ERROR_NO_SUCH_DEVICE;
+
+ if (reg_type > cy_as_sd_reg_CSD)
+ return CY_AS_ERROR_INVALID_PARAMETER;
+
+ /* If SD/MMC media is not supported on the
+ * addressed bus, return error. */
+ if ((dev_p->media_supported[bus] & (1 << cy_as_media_sd_flash)) == 0)
+ return CY_AS_ERROR_INVALID_PARAMETER;
+
+ /*
+ * find the amount of data to be returned. this will be the minimum of
+ * the actual data length, and the length requested.
+ */
+ switch (reg_type) {
+ case cy_as_sd_reg_OCR:
+ length = CY_AS_SD_REG_OCR_LENGTH;
+ break;
+ case cy_as_sd_reg_CID:
+ length = CY_AS_SD_REG_CID_LENGTH;
+ break;
+ case cy_as_sd_reg_CSD:
+ length = CY_AS_SD_REG_CSD_LENGTH;
+ break;
+
+ default:
+ length = 0;
+ cy_as_hal_assert(0);
+ }
+
+ if (length < data_p->length)
+ data_p->length = length;
+ length = data_p->length;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_SD_REGISTER_READ,
+ CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (create_address(bus, device, 0) | (uint16_t)reg_type));
+
+ reply_p = cy_as_ll_create_response(dev_p,
+ CY_AS_SD_REG_MAX_RESP_LENGTH);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_sd_reg_read(dev_p,
+ req_p, reply_p, data_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_SDREGISTERREAD, data_p,
+ dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * MiscFuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_create_p_partition(
+ /* Handle to the device of interest */
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ /* of P-port only partition in blocks */
+ uint32_t size,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Partitions cannot be created or deleted while
+ * the USB stack is active. */
+ if (dev_p->usb_count)
+ return CY_AS_ERROR_USB_RUNNING;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_PARTITION_STORAGE,
+ CY_RQT_STORAGE_RQT_CONTEXT, 3);
+
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, 0x00));
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)((size >> 16) & 0xffff));
+ cy_as_ll_request_response__set_word(req_p, 2,
+ (uint16_t)(size & 0xffff));
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_no_data(dev_p, req_p, reply_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_PARTITION, 0, dev_p->func_cbs_stor,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * FuncCallback */
+ return ret;
+
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_remove_p_partition(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Partitions cannot be created or deleted while
+ * the USB stack is active. */
+ if (dev_p->usb_count)
+ return CY_AS_ERROR_USB_RUNNING;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_PARTITION_ERASE,
+ CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ cy_as_ll_request_response__set_word(req_p,
+ 0, create_address(bus, (uint8_t)device, 0x00));
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_no_data(dev_p, req_p, reply_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_NODATA, 0, dev_p->func_cbs_stor,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the FuncCallback */
+ return ret;
+
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_get_transfer_amount(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_m_s_c_progress_data *data)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t code = cy_as_ll_request_response__get_code(reply_p);
+ uint16_t v1, v2;
+
+ if (code != CY_RESP_TRANSFER_COUNT) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ v1 = cy_as_ll_request_response__get_word(reply_p, 0);
+ v2 = cy_as_ll_request_response__get_word(reply_p, 1);
+ data->wr_count = (uint32_t)((v1 << 16) | v2);
+
+ v1 = cy_as_ll_request_response__get_word(reply_p, 2);
+ v2 = cy_as_ll_request_response__get_word(reply_p, 3);
+ data->rd_count = (uint32_t)((v1 << 16) | v2);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_storage_get_transfer_amount(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_as_m_s_c_progress_data *data_p,
+ cy_as_function_callback cb,
+ uint32_t client
+ )
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Check if the firmware image supports this feature. */
+ if ((dev_p->media_supported[0]) && (dev_p->media_supported[0]
+ == (1 << cy_as_media_nand)))
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_GET_TRANSFER_AMOUNT,
+ CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* Reserve space for the reply, the reply data
+ * will not exceed four words. */
+ reply_p = cy_as_ll_create_response(dev_p, 4);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, 0x00));
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_get_transfer_amount(dev_p,
+ req_p, reply_p, data_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_GETTRANSFERAMOUNT, (void *)data_p,
+ dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed as part of the
+ * FuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+
+}
+
+cy_as_return_status_t
+cy_as_storage_erase(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint32_t erase_unit,
+ uint16_t num_erase_units,
+ cy_as_function_callback cb,
+ uint32_t client
+ )
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_storage_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (bus < 0 || bus >= CY_AS_MAX_BUSES)
+ return CY_AS_ERROR_NO_SUCH_BUS;
+
+ if (device >= CY_AS_MAX_STORAGE_DEVICES)
+ return CY_AS_ERROR_NO_SUCH_DEVICE;
+
+ if (dev_p->storage_device_info[bus][device].block_size == 0)
+ return CY_AS_ERROR_QUERY_DEVICE_NEEDED;
+
+ /* If SD is not supported on the specified bus, then return ERROR */
+ if (dev_p->storage_device_info[bus][device].type !=
+ cy_as_media_sd_flash)
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ if (num_erase_units == 0)
+ return CY_AS_ERROR_SUCCESS;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_ERASE,
+ CY_RQT_STORAGE_RQT_CONTEXT, 5);
+
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed four words. */
+ reply_p = cy_as_ll_create_response(dev_p, 4);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, 0x00));
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)((erase_unit >> 16) & 0xffff));
+ cy_as_ll_request_response__set_word(req_p, 2,
+ (uint16_t)(erase_unit & 0xffff));
+ cy_as_ll_request_response__set_word(req_p, 3,
+ (uint16_t)((num_erase_units >> 8) & 0x00ff));
+ cy_as_ll_request_response__set_word(req_p, 4,
+ (uint16_t)((num_erase_units << 8) & 0xff00));
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ ret = my_handle_response_no_data(dev_p, req_p, reply_p);
+
+ /* If error = "invalid response", this (very likely) means
+ * that we are not using the SD-only firmware module which
+ * is the only one supporting storage_erase. in this case
+ * force a "non supported" error code */
+ if (ret == CY_AS_ERROR_INVALID_RESPONSE)
+ ret = CY_AS_ERROR_NOT_SUPPORTED;
+
+ return ret;
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_STOR_ERASE, 0, dev_p->func_cbs_stor,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_storage_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* The request and response are freed
+ * as part of the FuncCallback */
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static void
+cy_as_storage_func_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t stat)
+{
+ cy_as_func_c_b_node *node = (cy_as_func_c_b_node *)
+ dev_p->func_cbs_stor->head_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX)
+ == CY_AS_REQUEST_RESPONSE_EX;
+ cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS)
+ == CY_AS_REQUEST_RESPONSE_MS;
+ uint8_t code;
+ uint8_t cntxt;
+
+ cy_as_hal_assert(ex_request || ms_request);
+ cy_as_hal_assert(dev_p->func_cbs_stor->count != 0);
+ cy_as_hal_assert(dev_p->func_cbs_stor->type == CYAS_FUNC_CB);
+ (void) ex_request;
+ (void) ms_request;
+
+ (void)context;
+
+ cntxt = cy_as_ll_request_response__get_context(rqt);
+ cy_as_hal_assert(cntxt == CY_RQT_STORAGE_RQT_CONTEXT);
+
+ code = cy_as_ll_request_response__get_code(rqt);
+ switch (code) {
+ case CY_RQT_START_STORAGE:
+ ret = my_handle_response_storage_start(dev_p, rqt, resp, stat);
+ break;
+ case CY_RQT_STOP_STORAGE:
+ ret = my_handle_response_storage_stop(dev_p, rqt, resp, stat);
+ break;
+ case CY_RQT_CLAIM_STORAGE:
+ ret = my_handle_response_storage_claim(dev_p, rqt, resp);
+ break;
+ case CY_RQT_RELEASE_STORAGE:
+ ret = my_handle_response_storage_release(dev_p, rqt, resp);
+ break;
+ case CY_RQT_QUERY_MEDIA:
+ cy_as_hal_assert(cy_false);/* Not used any more. */
+ break;
+ case CY_RQT_QUERY_BUS:
+ cy_as_hal_assert(node->data != 0);
+ ret = my_handle_response_storage_query_bus(dev_p,
+ rqt, resp, (uint32_t *)node->data);
+ break;
+ case CY_RQT_QUERY_DEVICE:
+ cy_as_hal_assert(node->data != 0);
+ ret = my_handle_response_storage_query_device(dev_p,
+ rqt, resp, node->data);
+ break;
+ case CY_RQT_QUERY_UNIT:
+ cy_as_hal_assert(node->data != 0);
+ ret = my_handle_response_storage_query_unit(dev_p,
+ rqt, resp, node->data);
+ break;
+ case CY_RQT_SD_INTERFACE_CONTROL:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_SD_REGISTER_READ:
+ cy_as_hal_assert(node->data != 0);
+ ret = my_handle_response_sd_reg_read(dev_p, rqt, resp,
+ (cy_as_storage_sd_reg_read_data *)node->data);
+ break;
+ case CY_RQT_PARTITION_STORAGE:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_PARTITION_ERASE:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_GET_TRANSFER_AMOUNT:
+ cy_as_hal_assert(node->data != 0);
+ ret = my_handle_response_get_transfer_amount(dev_p,
+ rqt, resp, (cy_as_m_s_c_progress_data *)node->data);
+ break;
+ case CY_RQT_ERASE:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+
+ /* If error = "invalid response", this (very likely)
+ * means that we are not using the SD-only firmware
+ * module which is the only one supporting storage_erase.
+ * in this case force a "non supported" error code */
+ if (ret == CY_AS_ERROR_INVALID_RESPONSE)
+ ret = CY_AS_ERROR_NOT_SUPPORTED;
+
+ break;
+
+ default:
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+
+ /*
+ * if the low level layer returns a direct error, use the
+ * corresponding error code. if not, use the error code
+ * based on the response from firmware.
+ */
+ if (stat == CY_AS_ERROR_SUCCESS)
+ stat = ret;
+
+ /* Call the user callback, if there is one */
+ if (node->cb_p)
+ node->cb_p((cy_as_device_handle)dev_p, stat,
+ node->client_data, node->data_type, node->data);
+ cy_as_remove_c_b_node(dev_p->func_cbs_stor);
+}
+
+
+static void
+cy_as_sdio_sync_reply_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ (void)rqt;
+
+ if ((cy_as_ll_request_response__get_code(resp) ==
+ CY_RESP_SDIO_GET_TUPLE) ||
+ (cy_as_ll_request_response__get_code(resp) ==
+ CY_RESP_SDIO_EXT)) {
+ ret = cy_as_ll_request_response__get_word(resp, 0);
+ if ((ret & 0x00FF) != CY_AS_ERROR_SUCCESS) {
+ if (cy_as_ll_request_response__get_code(rqt) ==
+ CY_RQT_SDIO_READ_EXTENDED)
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_read_endpoint, ret);
+ else
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_write_endpoint, ret);
+ }
+ } else {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+
+ dev_p->storage_rw_resp_p = resp;
+ dev_p->storage_wait = cy_false;
+ if (((ret & 0x00FF) == CY_AS_ERROR_IO_ABORTED) || ((ret & 0x00FF)
+ == CY_AS_ERROR_IO_SUSPENDED))
+ dev_p->storage_error = (ret & 0x00FF);
+ else
+ dev_p->storage_error = (ret & 0x00FF) ?
+ CY_AS_ERROR_INVALID_RESPONSE : CY_AS_ERROR_SUCCESS;
+
+ /* Wake any threads/processes that are waiting on
+ * the read/write completion. */
+ cy_as_hal_wake(&dev_p->context[context]->channel);
+}
+
+cy_as_return_status_t
+cy_as_sdio_device_check(
+ cy_as_device *dev_p,
+ cy_as_bus_number_t bus,
+ uint32_t device)
+{
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (bus < 0 || bus >= CY_AS_MAX_BUSES)
+ return CY_AS_ERROR_NO_SUCH_BUS;
+
+ if (device >= CY_AS_MAX_STORAGE_DEVICES)
+ return CY_AS_ERROR_NO_SUCH_DEVICE;
+
+ if (!cy_as_device_is_astoria_dev(dev_p))
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ return (is_storage_active(dev_p));
+}
+
+cy_as_return_status_t
+cy_as_sdio_direct_io(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint32_t address,
+ uint8_t misc_buf,
+ uint16_t argument,
+ uint8_t is_write,
+ uint8_t *data_p)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint16_t resp_data;
+
+ /*
+ * sanity checks required before sending the request to the
+ * firmware.
+ */
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+
+ if (!(cy_as_sdio_check_function_initialized(handle,
+ bus, n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+ if (cy_as_sdio_check_function_suspended(handle, bus, n_function_no))
+ return CY_AS_ERROR_FUNCTION_SUSPENDED;
+
+ req_p = cy_as_ll_create_request(dev_p, (is_write == cy_true) ?
+ CY_RQT_SDIO_WRITE_DIRECT : CY_RQT_SDIO_READ_DIRECT,
+ CY_RQT_STORAGE_RQT_CONTEXT, 3);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /*Setting up request*/
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, n_function_no));
+ /* D1 */
+ if (is_write == cy_true) {
+ cy_as_ll_request_response__set_word(req_p, 1,
+ ((argument<<8) | 0x0080 | (n_function_no<<4) |
+ ((misc_buf&CY_SDIO_RAW)<<3) |
+ ((misc_buf&CY_SDIO_REARM_INT)>>5) |
+ (uint16_t)(address>>15)));
+ } else {
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (n_function_no<<4) | ((misc_buf&CY_SDIO_REARM_INT)>>5) |
+ (uint16_t)(address>>15));
+ }
+ /* D2 */
+ cy_as_ll_request_response__set_word(req_p, 2,
+ ((uint16_t)((address&0x00007fff)<<1)));
+
+ /*Create response*/
+ reply_p = cy_as_ll_create_response(dev_p, 2);
+
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /*Sending the request*/
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /*Check reply type*/
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_SDIO_DIRECT) {
+ resp_data = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (resp_data >> 8)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else if (data_p != 0)
+ *(uint8_t *)(data_p) = (uint8_t)(resp_data&0x00ff);
+ } else {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+
+destroy:
+ if (req_p != 0)
+ cy_as_ll_destroy_request(dev_p, req_p);
+ if (reply_p != 0)
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ return ret;
+}
+
+
+cy_as_return_status_t
+cy_as_sdio_direct_read(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint32_t address,
+ uint8_t misc_buf,
+ uint8_t *data_p)
+{
+ return cy_as_sdio_direct_io(handle, bus, device, n_function_no,
+ address, misc_buf, 0x00, cy_false, data_p);
+}
+
+cy_as_return_status_t
+cy_as_sdio_direct_write(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint32_t address,
+ uint8_t misc_buf,
+ uint16_t argument,
+ uint8_t *data_p)
+{
+ return cy_as_sdio_direct_io(handle, bus, device, n_function_no,
+ address, misc_buf, argument, cy_true, data_p);
+}
+
+/*Cmd53 IO*/
+cy_as_return_status_t
+cy_as_sdio_extended_i_o(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint32_t address,
+ uint8_t misc_buf,
+ uint16_t argument,
+ uint8_t is_write,
+ uint8_t *data_p ,
+ uint8_t is_resume)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t resp_type;
+ uint8_t reqtype;
+ uint16_t resp_data;
+ cy_as_context *ctxt_p;
+ uint32_t dmasize, loopcount = 200;
+ cy_as_end_point_number_t ep;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized(handle,
+ bus, n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+ if (cy_as_sdio_check_function_suspended(handle, bus, n_function_no))
+ return CY_AS_ERROR_FUNCTION_SUSPENDED;
+
+
+ if ((cy_as_device_is_storage_async_pending(dev_p)) ||
+ (dev_p->storage_wait))
+ return CY_AS_ERROR_ASYNC_PENDING;
+
+ /* Request for 0 bytes of blocks is returned as a success*/
+ if (argument == 0)
+ return CY_AS_ERROR_SUCCESS;
+
+ /* Initialise the request to send to the West Bridge device. */
+ if (is_write == cy_true) {
+ reqtype = CY_RQT_SDIO_WRITE_EXTENDED;
+ ep = dev_p->storage_write_endpoint;
+ } else {
+ reqtype = CY_RQT_SDIO_READ_EXTENDED;
+ ep = dev_p->storage_read_endpoint;
+ }
+
+ req_p = dev_p->storage_rw_req_p;
+ cy_as_ll_init_request(req_p, reqtype, CY_RQT_STORAGE_RQT_CONTEXT, 3);
+
+ /* Initialise the space for reply from the Antioch. */
+ reply_p = dev_p->storage_rw_resp_p;
+ cy_as_ll_init_response(reply_p, 2);
+
+ /* Setup the DMA request */
+ if (!(misc_buf&CY_SDIO_BLOCKMODE)) {
+ if (argument >
+ dev_p->sdiocard[bus].
+ function[n_function_no-1].blocksize)
+ return CY_AS_ERROR_INVALID_BLOCKSIZE;
+
+ } else {
+ if (argument > 511)
+ return CY_AS_ERROR_INVALID_BLOCKSIZE;
+ }
+
+ if (argument == 512)
+ argument = 0;
+
+ dmasize = ((misc_buf&CY_SDIO_BLOCKMODE) != 0) ?
+ dev_p->sdiocard[bus].function[n_function_no-1].blocksize
+ * argument : argument;
+
+ ret = cy_as_dma_queue_request(dev_p, ep, (void *)(data_p),
+ dmasize, cy_false, (is_write & cy_true) ? cy_false :
+ cy_true, cy_as_sync_storage_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device,
+ n_function_no | ((is_resume) ? 0x80 : 0x00)));
+ cy_as_ll_request_response__set_word(req_p, 1,
+ ((uint16_t)n_function_no)<<12|
+ ((uint16_t)(misc_buf & (CY_SDIO_BLOCKMODE|CY_SDIO_OP_INCR)))
+ << 9 | (uint16_t)(address >> 7) |
+ ((is_write == cy_true) ? 0x8000 : 0x0000));
+ cy_as_ll_request_response__set_word(req_p, 2,
+ ((uint16_t)(address&0x0000ffff) << 9) | argument);
+
+
+ /* Send the request and wait for completion of storage request */
+ dev_p->storage_wait = cy_true;
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
+ cy_true, cy_as_sdio_sync_reply_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
+ } else {
+ /* Setup the DMA request */
+ ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT];
+ ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
+
+ while (loopcount-- > 0) {
+ if (dev_p->storage_wait == cy_false)
+ break;
+ cy_as_hal_sleep_on(&ctxt_p->channel, 10);
+ }
+ if (dev_p->storage_wait == cy_true) {
+ dev_p->storage_wait = cy_false;
+ cy_as_ll_remove_request(dev_p, ctxt_p, req_p, cy_true);
+ dev_p->storage_error = CY_AS_ERROR_TIMEOUT;
+ }
+
+ ret = dev_p->storage_error;
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ resp_type = cy_as_ll_request_response__get_code(
+ dev_p->storage_rw_resp_p);
+ if (resp_type == CY_RESP_SDIO_EXT) {
+ resp_data = cy_as_ll_request_response__get_word
+ (reply_p, 0)&0x00ff;
+ if (resp_data)
+ ret = CY_AS_ERROR_INVALID_REQUEST;
+
+ } else {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+ }
+ return ret;
+
+}
+
+static void
+cy_as_sdio_async_reply_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ cy_as_storage_callback cb_ms;
+ uint8_t reqtype;
+ uint32_t pendingblocks;
+ (void)rqt;
+ (void)context;
+
+ pendingblocks = 0;
+ reqtype = cy_as_ll_request_response__get_code(rqt);
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if ((cy_as_ll_request_response__get_code(resp) ==
+ CY_RESP_SUCCESS_FAILURE) ||
+ (cy_as_ll_request_response__get_code(resp) ==
+ CY_RESP_SDIO_EXT)) {
+ ret = cy_as_ll_request_response__get_word(resp, 0);
+ ret &= 0x00FF;
+ } else {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+ }
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ if (reqtype == CY_RQT_SDIO_READ_EXTENDED)
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_read_endpoint, ret);
+ else
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_write_endpoint, ret);
+
+ dev_p->storage_error = ret;
+ }
+
+ dev_p->storage_wait = cy_false;
+
+ /*
+ * if the DMA callback has already been called,
+ * the user callback has to be called from here.
+ */
+ if (!cy_as_device_is_storage_async_pending(dev_p)) {
+ cy_as_hal_assert(dev_p->storage_cb_ms != NULL);
+ cb_ms = dev_p->storage_cb_ms;
+
+ dev_p->storage_cb = 0;
+ dev_p->storage_cb_ms = 0;
+
+ if ((ret == CY_AS_ERROR_SUCCESS) ||
+ (ret == CY_AS_ERROR_IO_ABORTED) ||
+ (ret == CY_AS_ERROR_IO_SUSPENDED)) {
+ ret = dev_p->storage_error;
+ pendingblocks = ((uint32_t)
+ cy_as_ll_request_response__get_word
+ (resp, 1)) << 16;
+ } else
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+
+ cb_ms((cy_as_device_handle)dev_p, dev_p->storage_bus_index,
+ dev_p->storage_device_index,
+ (dev_p->storage_unit | pendingblocks),
+ dev_p->storage_block_addr, dev_p->storage_oper, ret);
+ } else
+ dev_p->storage_error = ret;
+}
+
+
+cy_as_return_status_t
+cy_as_sdio_extended_i_o_async(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint32_t address,
+ uint8_t misc_buf,
+ uint16_t argument,
+ uint8_t is_write,
+ uint8_t *data_p,
+ cy_as_storage_callback callback)
+{
+
+ uint32_t mask;
+ uint32_t dmasize;
+ cy_as_ll_request_response *req_p , *reply_p;
+ uint8_t reqtype;
+ cy_as_end_point_number_t ep;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized(handle,
+ bus, n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+ if (cy_as_sdio_check_function_suspended(handle, bus, n_function_no))
+ return CY_AS_ERROR_FUNCTION_SUSPENDED;
+
+ if (callback == 0)
+ return CY_AS_ERROR_NULL_CALLBACK;
+
+ /* We are supposed to return sucess if the number of
+ * blocks is zero
+ */
+ if (((misc_buf&CY_SDIO_BLOCKMODE) != 0) && (argument == 0)) {
+ callback(handle, bus, device, n_function_no, address,
+ ((is_write) ? cy_as_op_write : cy_as_op_read),
+ CY_AS_ERROR_SUCCESS);
+ return CY_AS_ERROR_SUCCESS;
+ }
+
+
+ /*
+ * since async operations can be triggered by interrupt
+ * code, we must insure that we do not get multiple async
+ * operations going at one time and protect this test and
+ * set operation from interrupts.
+ */
+ mask = cy_as_hal_disable_interrupts();
+ if ((cy_as_device_is_storage_async_pending(dev_p)) ||
+ (dev_p->storage_wait)) {
+ cy_as_hal_enable_interrupts(mask);
+ return CY_AS_ERROR_ASYNC_PENDING;
+ }
+ cy_as_device_set_storage_async_pending(dev_p);
+ cy_as_hal_enable_interrupts(mask);
+
+
+ /*
+ * storage information about the currently
+ * outstanding request
+ */
+ dev_p->storage_cb_ms = callback;
+ dev_p->storage_bus_index = bus;
+ dev_p->storage_device_index = device;
+ dev_p->storage_unit = n_function_no;
+ dev_p->storage_block_addr = address;
+
+ if (is_write == cy_true) {
+ reqtype = CY_RQT_SDIO_WRITE_EXTENDED;
+ ep = dev_p->storage_write_endpoint;
+ } else {
+ reqtype = CY_RQT_SDIO_READ_EXTENDED;
+ ep = dev_p->storage_read_endpoint;
+ }
+
+ /* Initialise the request to send to the West Bridge. */
+ req_p = dev_p->storage_rw_req_p;
+ cy_as_ll_init_request(req_p, reqtype,
+ CY_RQT_STORAGE_RQT_CONTEXT, 3);
+
+ /* Initialise the space for reply from the West Bridge. */
+ reply_p = dev_p->storage_rw_resp_p;
+ cy_as_ll_init_response(reply_p, 2);
+
+ if (!(misc_buf&CY_SDIO_BLOCKMODE)) {
+ if (argument >
+ dev_p->sdiocard[bus].function[n_function_no-1].blocksize)
+ return CY_AS_ERROR_INVALID_BLOCKSIZE;
+
+ } else {
+ if (argument > 511)
+ return CY_AS_ERROR_INVALID_BLOCKSIZE;
+ }
+
+ if (argument == 512)
+ argument = 0;
+ dmasize = ((misc_buf&CY_SDIO_BLOCKMODE) != 0) ?
+ dev_p->sdiocard[bus].function[n_function_no-1].blocksize *
+ argument : argument;
+
+ /* Setup the DMA request and adjust the storage
+ * operation if we are reading */
+ if (reqtype == CY_RQT_SDIO_READ_EXTENDED) {
+ ret = cy_as_dma_queue_request(dev_p, ep,
+ (void *)data_p, dmasize , cy_false, cy_true,
+ cy_as_async_storage_callback);
+ dev_p->storage_oper = cy_as_op_read;
+ } else if (reqtype == CY_RQT_SDIO_WRITE_EXTENDED) {
+ ret = cy_as_dma_queue_request(dev_p, ep, (void *)data_p,
+ dmasize, cy_false, cy_false, cy_as_async_storage_callback);
+ dev_p->storage_oper = cy_as_op_write;
+ }
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_device_clear_storage_async_pending(dev_p);
+ return ret;
+ }
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, n_function_no));
+ cy_as_ll_request_response__set_word(req_p, 1,
+ ((uint16_t)n_function_no) << 12 |
+ ((uint16_t)(misc_buf & (CY_SDIO_BLOCKMODE | CY_SDIO_OP_INCR)))
+ << 9 | (uint16_t)(address>>7) |
+ ((is_write == cy_true) ? 0x8000 : 0x0000));
+ cy_as_ll_request_response__set_word(req_p, 2,
+ ((uint16_t)(address&0x0000ffff) << 9) | argument);
+
+
+ /* Send the request and wait for completion of storage request */
+ dev_p->storage_wait = cy_true;
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_true,
+ cy_as_sdio_async_reply_callback);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
+ cy_as_device_clear_storage_async_pending(dev_p);
+ } else {
+ cy_as_dma_kick_start(dev_p, ep);
+ }
+
+ return ret;
+}
+
+/* CMD53 Extended Read*/
+cy_as_return_status_t
+cy_as_sdio_extended_read(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint32_t address,
+ uint8_t misc_buf,
+ uint16_t argument,
+ uint8_t *data_p,
+ cy_as_sdio_callback callback)
+{
+ if (callback == 0)
+ return cy_as_sdio_extended_i_o(handle, bus, device,
+ n_function_no, address, misc_buf, argument,
+ cy_false, data_p, 0);
+
+ return cy_as_sdio_extended_i_o_async(handle, bus, device,
+ n_function_no, address, misc_buf, argument, cy_false,
+ data_p, callback);
+}
+
+/* CMD53 Extended Write*/
+cy_as_return_status_t
+cy_as_sdio_extended_write(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint32_t address,
+ uint8_t misc_buf,
+ uint16_t argument,
+ uint8_t *data_p,
+ cy_as_sdio_callback callback)
+{
+ if (callback == 0)
+ return cy_as_sdio_extended_i_o(handle, bus, device,
+ n_function_no, address, misc_buf, argument, cy_true,
+ data_p, 0);
+
+ return cy_as_sdio_extended_i_o_async(handle, bus, device,
+ n_function_no, address, misc_buf, argument, cy_true,
+ data_p, callback);
+}
+
+
+/* Read the CIS info tuples for the given function and Tuple ID*/
+cy_as_return_status_t
+cy_as_sdio_get_c_i_s_info(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint16_t tuple_id,
+ uint8_t *data_p)
+{
+
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint16_t resp_data;
+ cy_as_context *ctxt_p;
+ uint32_t loopcount = 200;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized(handle, bus, 0)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+
+ if ((cy_as_device_is_storage_async_pending(dev_p)) ||
+ (dev_p->storage_wait))
+ return CY_AS_ERROR_ASYNC_PENDING;
+
+
+ /* Initialise the request to send to the Antioch. */
+ req_p = dev_p->storage_rw_req_p;
+ cy_as_ll_init_request(req_p, CY_RQT_SDIO_GET_TUPLE,
+ CY_RQT_STORAGE_RQT_CONTEXT, 2);
+
+ /* Initialise the space for reply from the Antioch. */
+ reply_p = dev_p->storage_rw_resp_p;
+ cy_as_ll_init_response(reply_p, 3);
+
+ /* Setup the DMA request */
+ ret = cy_as_dma_queue_request(dev_p, dev_p->storage_read_endpoint,
+ data_p+1, 255, cy_false, cy_true, cy_as_sync_storage_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, n_function_no));
+
+ /* Set tuple id to fetch. */
+ cy_as_ll_request_response__set_word(req_p, 1, tuple_id<<8);
+
+ /* Send the request and wait for completion of storage request */
+ dev_p->storage_wait = cy_true;
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_true,
+ cy_as_sdio_sync_reply_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p,
+ dev_p->storage_read_endpoint, CY_AS_ERROR_CANCELED);
+ } else {
+ /* Setup the DMA request */
+ ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT];
+ ret = cy_as_dma_drain_queue(dev_p,
+ dev_p->storage_read_endpoint, cy_true);
+
+ while (loopcount-- > 0) {
+ if (dev_p->storage_wait == cy_false)
+ break;
+ cy_as_hal_sleep_on(&ctxt_p->channel, 10);
+ }
+
+ if (dev_p->storage_wait == cy_true) {
+ dev_p->storage_wait = cy_false;
+ cy_as_ll_remove_request(dev_p, ctxt_p, req_p, cy_true);
+ return CY_AS_ERROR_TIMEOUT;
+ }
+ ret = dev_p->storage_error;
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_ll_request_response__get_code
+ (dev_p->storage_rw_resp_p) == CY_RESP_SDIO_GET_TUPLE) {
+ resp_data = cy_as_ll_request_response__get_word
+ (reply_p, 0);
+ if (resp_data) {
+ ret = CY_AS_ERROR_INVALID_REQUEST;
+ } else if (data_p != 0)
+ *(uint8_t *)data_p = (uint8_t)
+ (cy_as_ll_request_response__get_word
+ (reply_p, 0)&0x00ff);
+ } else {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+ }
+ return ret;
+}
+
+/*Query Device*/
+cy_as_return_status_t
+cy_as_sdio_query_card(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_as_sdio_card *data_p)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ uint8_t resp_type;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* Allocating memory to the SDIO device structure in dev_p */
+
+ cy_as_hal_mem_set(&dev_p->sdiocard[bus], 0, sizeof(cy_as_sdio_device));
+
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_SDIO_QUERY_CARD,
+ CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, 0));
+
+ reply_p = cy_as_ll_create_response(dev_p, 5);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ resp_type = cy_as_ll_request_response__get_code(reply_p);
+ if (resp_type == CY_RESP_SDIO_QUERY_CARD) {
+ dev_p->sdiocard[bus].card.num_functions =
+ (uint8_t)((reply_p->data[0]&0xff00)>>8);
+ dev_p->sdiocard[bus].card.memory_present =
+ (uint8_t)reply_p->data[0]&0x0001;
+ dev_p->sdiocard[bus].card.manufacturer__id =
+ reply_p->data[1];
+ dev_p->sdiocard[bus].card.manufacturer_info =
+ reply_p->data[2];
+ dev_p->sdiocard[bus].card.blocksize =
+ reply_p->data[3];
+ dev_p->sdiocard[bus].card.maxblocksize =
+ reply_p->data[3];
+ dev_p->sdiocard[bus].card.card_capability =
+ (uint8_t)((reply_p->data[4]&0xff00)>>8);
+ dev_p->sdiocard[bus].card.sdio_version =
+ (uint8_t)(reply_p->data[4]&0x00ff);
+ dev_p->sdiocard[bus].function_init_map = 0x01;
+ data_p->num_functions =
+ dev_p->sdiocard[bus].card.num_functions;
+ data_p->memory_present =
+ dev_p->sdiocard[bus].card.memory_present;
+ data_p->manufacturer__id =
+ dev_p->sdiocard[bus].card.manufacturer__id;
+ data_p->manufacturer_info =
+ dev_p->sdiocard[bus].card.manufacturer_info;
+ data_p->blocksize = dev_p->sdiocard[bus].card.blocksize;
+ data_p->maxblocksize =
+ dev_p->sdiocard[bus].card.maxblocksize;
+ data_p->card_capability =
+ dev_p->sdiocard[bus].card.card_capability;
+ data_p->sdio_version =
+ dev_p->sdiocard[bus].card.sdio_version;
+ } else {
+ if (resp_type == CY_RESP_SUCCESS_FAILURE)
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ else
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+destroy:
+ if (req_p != 0)
+ cy_as_ll_destroy_request(dev_p, req_p);
+ if (reply_p != 0)
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ return ret;
+}
+
+/*Reset SDIO card. */
+cy_as_return_status_t
+cy_as_sdio_reset_card(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device)
+{
+
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t resp_type;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (dev_p->sdiocard != 0) {
+ dev_p->sdiocard[bus].function_init_map = 0;
+ dev_p->sdiocard[bus].function_suspended_map = 0;
+ }
+
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_SDIO_RESET_DEV,
+ CY_RQT_STORAGE_RQT_CONTEXT, 1);
+
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /*Setup mailbox */
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, 0));
+
+ reply_p = cy_as_ll_create_response(dev_p, 2);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ resp_type = cy_as_ll_request_response__get_code(reply_p);
+
+ if (resp_type == CY_RESP_SUCCESS_FAILURE) {
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ ret = cy_as_sdio_query_card(handle, bus, device, 0);
+ } else
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+
+destroy:
+ if (req_p != 0)
+ cy_as_ll_destroy_request(dev_p, req_p);
+ if (reply_p != 0)
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ return ret;
+}
+
+/* Initialise an IO function*/
+cy_as_return_status_t
+cy_as_sdio_init_function(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint8_t misc_buf)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t resp_type;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized
+ (handle, bus, 0)))
+ return CY_AS_ERROR_NOT_RUNNING;
+
+ if ((cy_as_sdio_check_function_initialized
+ (handle, bus, n_function_no))) {
+ if (misc_buf&CY_SDIO_FORCE_INIT)
+ dev_p->sdiocard[bus].function_init_map &=
+ (~(1 << n_function_no));
+ else
+ return CY_AS_ERROR_ALREADY_RUNNING;
+ }
+
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_SDIO_INIT_FUNCTION, CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, n_function_no));
+
+ reply_p = cy_as_ll_create_response(dev_p, 5);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ resp_type = cy_as_ll_request_response__get_code(reply_p);
+
+ if (resp_type == CY_RESP_SDIO_INIT_FUNCTION) {
+ dev_p->sdiocard[bus].function[n_function_no-1].function_code =
+ (uint8_t)((reply_p->data[0]&0xff00)>>8);
+ dev_p->sdiocard[bus].function[n_function_no-1].
+ extended_func_code = (uint8_t)reply_p->data[0]&0x00ff;
+ dev_p->sdiocard[bus].function[n_function_no-1].blocksize =
+ reply_p->data[1];
+ dev_p->sdiocard[bus].function[n_function_no-1].
+ maxblocksize = reply_p->data[1];
+ dev_p->sdiocard[bus].function[n_function_no-1].card_psn =
+ (uint32_t)(reply_p->data[2])<<16;
+ dev_p->sdiocard[bus].function[n_function_no-1].card_psn |=
+ (uint32_t)(reply_p->data[3]);
+ dev_p->sdiocard[bus].function[n_function_no-1].csa_bits =
+ (uint8_t)((reply_p->data[4]&0xff00)>>8);
+ dev_p->sdiocard[bus].function[n_function_no-1].wakeup_support =
+ (uint8_t)(reply_p->data[4]&0x0001);
+ dev_p->sdiocard[bus].function_init_map |= (1 << n_function_no);
+ cy_as_sdio_clear_function_suspended(handle, bus, n_function_no);
+
+ } else {
+ if (resp_type == CY_RESP_SUCCESS_FAILURE)
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ else
+ ret = CY_AS_ERROR_INVALID_FUNCTION;
+ }
+
+destroy:
+ if (req_p != 0)
+ cy_as_ll_destroy_request(dev_p, req_p);
+ if (reply_p != 0)
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ return ret;
+}
+
+/*Query individual functions. */
+cy_as_return_status_t
+cy_as_sdio_query_function(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ cy_as_sdio_func *data_p)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ cy_as_return_status_t ret;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized(handle,
+ bus, n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+
+ data_p->blocksize =
+ dev_p->sdiocard[bus].function[n_function_no-1].blocksize;
+ data_p->card_psn =
+ dev_p->sdiocard[bus].function[n_function_no-1].card_psn;
+ data_p->csa_bits =
+ dev_p->sdiocard[bus].function[n_function_no-1].csa_bits;
+ data_p->extended_func_code =
+ dev_p->sdiocard[bus].function[n_function_no-1].
+ extended_func_code;
+ data_p->function_code =
+ dev_p->sdiocard[bus].function[n_function_no-1].function_code;
+ data_p->maxblocksize =
+ dev_p->sdiocard[bus].function[n_function_no-1].maxblocksize;
+ data_p->wakeup_support =
+ dev_p->sdiocard[bus].function[n_function_no-1].wakeup_support;
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/* Abort the Current Extended IO Operation*/
+cy_as_return_status_t
+cy_as_sdio_abort_function(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t resp_type;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized(handle,
+ bus, n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+
+ if ((cy_as_device_is_storage_async_pending(dev_p)) ||
+ (dev_p->storage_wait)) {
+ if (!(cy_as_sdio_get_card_capability(handle, bus) &
+ CY_SDIO_SDC))
+ return CY_AS_ERROR_INVALID_COMMAND;
+ }
+
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_SDIO_ABORT_IO,
+ CY_RQT_GENERAL_RQT_CONTEXT, 1);
+
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /*Setup mailbox */
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, n_function_no));
+
+ reply_p = cy_as_ll_create_response(dev_p, 2);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ resp_type = cy_as_ll_request_response__get_code(reply_p);
+
+ if (resp_type == CY_RESP_SUCCESS_FAILURE)
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ else
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+
+
+destroy:
+ if (req_p != 0)
+ cy_as_ll_destroy_request(dev_p, req_p);
+ if (reply_p != 0)
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ return ret;
+}
+
+/* Suspend IO to current function*/
+cy_as_return_status_t
+cy_as_sdio_suspend(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized(handle, bus,
+ n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+ if (!(cy_as_sdio_check_support_bus_suspend(handle, bus)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+ if (!(cy_as_sdio_get_card_capability(handle, bus) & CY_SDIO_SDC))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+ if (cy_as_sdio_check_function_suspended(handle, bus, n_function_no))
+ return CY_AS_ERROR_FUNCTION_SUSPENDED;
+
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_SDIO_SUSPEND, CY_RQT_GENERAL_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /*Setup mailbox */
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, n_function_no));
+
+ reply_p = cy_as_ll_create_response(dev_p, 2);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ ret = cy_as_ll_request_response__get_code(reply_p);
+ cy_as_sdio_set_function_suspended(handle, bus, n_function_no);
+ }
+
+ if (req_p != 0)
+ cy_as_ll_destroy_request(dev_p, req_p);
+ if (reply_p != 0)
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+/*Resume suspended function*/
+cy_as_return_status_t
+cy_as_sdio_resume(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ cy_as_oper_type op,
+ uint8_t misc_buf,
+ uint16_t pendingblockcount,
+ uint8_t *data_p
+ )
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t resp_data, ret = CY_AS_ERROR_SUCCESS;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized
+ (handle, bus, n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+
+ /* If suspend resume is not supported return */
+ if (!(cy_as_sdio_check_support_bus_suspend(handle, bus)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+
+ /* if the function is not suspended return. */
+ if (!(cy_as_sdio_check_function_suspended
+ (handle, bus, n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_SDIO_RESUME, CY_RQT_STORAGE_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /*Setup mailbox */
+ cy_as_ll_request_response__set_word(req_p, 0,
+ create_address(bus, (uint8_t)device, n_function_no));
+
+ reply_p = cy_as_ll_create_response(dev_p, 2);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_SDIO_RESUME) {
+ resp_data = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (resp_data & 0x00ff) {
+ /* Send extended read request to resume the read. */
+ if (op == cy_as_op_read) {
+ ret = cy_as_sdio_extended_i_o(handle, bus,
+ device, n_function_no, 0, misc_buf,
+ pendingblockcount, cy_false, data_p, 1);
+ } else {
+ ret = cy_as_sdio_extended_i_o(handle, bus,
+ device, n_function_no, 0, misc_buf,
+ pendingblockcount, cy_true, data_p, 1);
+ }
+ } else {
+ ret = CY_AS_ERROR_SUCCESS;
+ }
+ } else {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ }
+
+destroy:
+ cy_as_sdio_clear_function_suspended(handle, bus, n_function_no);
+ if (req_p != 0)
+ cy_as_ll_destroy_request(dev_p, req_p);
+ if (reply_p != 0)
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ return ret;
+
+}
+
+/*Set function blocksize. Size cannot exceed max
+ * block size for the function*/
+cy_as_return_status_t
+cy_as_sdio_set_blocksize(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no,
+ uint16_t blocksize)
+{
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ ret = cy_as_sdio_device_check(dev_p, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized
+ (handle, bus, n_function_no)))
+ return CY_AS_ERROR_INVALID_FUNCTION;
+ if (n_function_no == 0) {
+ if (blocksize > cy_as_sdio_get_card_max_blocksize(handle, bus))
+ return CY_AS_ERROR_INVALID_BLOCKSIZE;
+ else if (blocksize == cy_as_sdio_get_card_blocksize
+ (handle, bus))
+ return CY_AS_ERROR_SUCCESS;
+ } else {
+ if (blocksize >
+ cy_as_sdio_get_function_max_blocksize(handle,
+ bus, n_function_no))
+ return CY_AS_ERROR_INVALID_BLOCKSIZE;
+ else if (blocksize ==
+ cy_as_sdio_get_function_blocksize(handle,
+ bus, n_function_no))
+ return CY_AS_ERROR_SUCCESS;
+ }
+
+ ret = cy_as_sdio_direct_write(handle, bus, device, 0,
+ (uint16_t)(n_function_no << 8) |
+ 0x10, 0, blocksize & 0x00ff, 0);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ ret = cy_as_sdio_direct_write(handle, bus, device, 0,
+ (uint16_t)(n_function_no << 8) |
+ 0x11, 0, (blocksize & 0xff00) >> 8, 0);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (n_function_no == 0)
+ cy_as_sdio_set_card_block_size(handle, bus, blocksize);
+ else
+ cy_as_sdio_set_function_block_size(handle,
+ bus, n_function_no, blocksize);
+ return ret;
+}
+
+/* Deinitialize an SDIO function*/
+cy_as_return_status_t
+cy_as_sdio_de_init_function(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ uint8_t n_function_no)
+{
+ cy_as_return_status_t ret;
+ uint8_t temp;
+
+ if (n_function_no == 0)
+ return CY_AS_ERROR_INVALID_FUNCTION;
+
+ ret = cy_as_sdio_device_check((cy_as_device *)handle, bus, device);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (!(cy_as_sdio_check_function_initialized
+ (handle, bus, n_function_no)))
+ return CY_AS_ERROR_SUCCESS;
+
+ temp = (uint8_t)(((cy_as_device *)handle)->sdiocard[bus].
+ function_init_map & (~(1 << n_function_no)));
+
+ cy_as_sdio_direct_write(handle, bus, device, 0, 0x02, 0, temp, 0);
+
+ ((cy_as_device *)handle)->sdiocard[bus].function_init_map &=
+ (~(1 << n_function_no));
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+
+/*[]*/
diff --git a/drivers/staging/westbridge/astoria/api/src/cyasusb.c b/drivers/staging/westbridge/astoria/api/src/cyasusb.c
new file mode 100644
index 000000000000..5a2197012065
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyasusb.c
@@ -0,0 +1,3718 @@
+/* Cypress West Bridge API source file (cyasusb.c)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyasusb.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+#include "../../include/linux/westbridge/cyasdma.h"
+#include "../../include/linux/westbridge/cyaslowlevel.h"
+#include "../../include/linux/westbridge/cyaslep2pep.h"
+#include "../../include/linux/westbridge/cyasregs.h"
+#include "../../include/linux/westbridge/cyasstorage.h"
+
+static cy_as_return_status_t
+cy_as_usb_ack_setup_packet(
+ /* Handle to the West Bridge device */
+ cy_as_device_handle handle,
+ /* The callback if async call */
+ cy_as_function_callback cb,
+ /* Client supplied data */
+ uint32_t client
+ );
+
+static void
+cy_as_usb_func_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret);
+/*
+* Reset the USB EP0 state
+*/
+static void
+cy_as_usb_reset_e_p0_state(cy_as_device *dev_p)
+{
+ cy_as_log_debug_message(6, "cy_as_usb_reset_e_p0_state called");
+
+ cy_as_device_clear_ack_delayed(dev_p);
+ cy_as_device_clear_setup_packet(dev_p);
+ if (cy_as_device_is_usb_async_pending(dev_p, 0))
+ cy_as_usb_cancel_async((cy_as_device_handle)dev_p, 0);
+
+ dev_p->usb_pending_buffer = 0;
+}
+
+/*
+* External function to map logical endpoints to physical endpoints
+*/
+static cy_as_return_status_t
+is_usb_active(cy_as_device *dev_p)
+{
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (dev_p->usb_count == 0)
+ return CY_AS_ERROR_NOT_RUNNING;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+usb_ack_callback(cy_as_device_handle h,
+ cy_as_return_status_t status,
+ uint32_t client,
+ cy_as_funct_c_b_type type,
+ void *data)
+{
+ cy_as_device *dev_p = (cy_as_device *)h;
+
+ (void)client;
+ (void)status;
+ (void)data;
+
+ cy_as_hal_assert(type == CY_FUNCT_CB_NODATA);
+
+ if (dev_p->usb_pending_buffer) {
+ cy_as_usb_io_callback cb;
+
+ cb = dev_p->usb_cb[0];
+ dev_p->usb_cb[0] = 0;
+ cy_as_device_clear_usb_async_pending(dev_p, 0);
+ if (cb)
+ cb(h, 0, dev_p->usb_pending_size,
+ dev_p->usb_pending_buffer, dev_p->usb_error);
+
+ dev_p->usb_pending_buffer = 0;
+ }
+
+ cy_as_device_clear_setup_packet(dev_p);
+}
+
+static void
+my_usb_request_callback_usb_event(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p)
+{
+ uint16_t ev;
+ uint16_t val;
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+
+ ev = cy_as_ll_request_response__get_word(req_p, 0);
+ switch (ev) {
+ case 0: /* Reserved */
+ cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
+ CY_AS_ERROR_INVALID_REQUEST, 0);
+ break;
+
+ case 1: /* Reserved */
+ cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
+ CY_AS_ERROR_INVALID_REQUEST, 0);
+ break;
+
+ case 2: /* USB Suspend */
+ dev_p->usb_last_event = cy_as_event_usb_suspend;
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h, cy_as_event_usb_suspend, 0);
+ else if (dev_p->usb_event_cb)
+ dev_p->usb_event_cb(h, cy_as_event_usb_suspend, 0);
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ break;
+
+ case 3: /* USB Resume */
+ dev_p->usb_last_event = cy_as_event_usb_resume;
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h, cy_as_event_usb_resume, 0);
+ else if (dev_p->usb_event_cb)
+ dev_p->usb_event_cb(h, cy_as_event_usb_resume, 0);
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ break;
+
+ case 4: /* USB Reset */
+ /*
+ * if we get a USB reset, the USB host did not understand
+ * our response or we timed out for some reason. reset
+ * our internal state to be ready for another set of
+ * enumeration based requests.
+ */
+ if (cy_as_device_is_ack_delayed(dev_p))
+ cy_as_usb_reset_e_p0_state(dev_p);
+
+ dev_p->usb_last_event = cy_as_event_usb_reset;
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h, cy_as_event_usb_reset, 0);
+ else if (dev_p->usb_event_cb)
+ dev_p->usb_event_cb(h, cy_as_event_usb_reset, 0);
+
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ cy_as_device_clear_usb_high_speed(dev_p);
+ cy_as_usb_set_dma_sizes(dev_p);
+ dev_p->usb_max_tx_size = 0x40;
+ cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x40);
+ break;
+
+ case 5: /* USB Set Configuration */
+ /* The configuration to set */
+ val = cy_as_ll_request_response__get_word(req_p, 1);
+ dev_p->usb_last_event = cy_as_event_usb_set_config;
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_set_config, &val);
+ else if (dev_p->usb_event_cb)
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_set_config, &val);
+
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ break;
+
+ case 6: /* USB Speed change */
+ /* Connect speed */
+ val = cy_as_ll_request_response__get_word(req_p, 1);
+ dev_p->usb_last_event = cy_as_event_usb_speed_change;
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_speed_change, &val);
+ else if (dev_p->usb_event_cb)
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_speed_change, &val);
+
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ cy_as_device_set_usb_high_speed(dev_p);
+ cy_as_usb_set_dma_sizes(dev_p);
+ dev_p->usb_max_tx_size = 0x200;
+ cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x200);
+ break;
+
+ case 7: /* USB Clear Feature */
+ /* EP Number */
+ val = cy_as_ll_request_response__get_word(req_p, 1);
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_clear_feature, &val);
+ if (dev_p->usb_event_cb)
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_clear_feature, &val);
+
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ break;
+
+ default:
+ cy_as_hal_print_message("invalid event type\n");
+ cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
+ CY_RESP_USB_INVALID_EVENT, sizeof(ev), &ev);
+ break;
+ }
+}
+
+static void
+my_usb_request_callback_usb_data(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p)
+{
+ cy_as_end_point_number_t ep;
+ uint8_t type;
+ uint16_t len;
+ uint16_t val;
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+
+ val = cy_as_ll_request_response__get_word(req_p, 0);
+ ep = (cy_as_end_point_number_t)((val >> 13) & 0x01);
+ len = (val & 0x1ff);
+
+ cy_as_hal_assert(len <= 64);
+ cy_as_ll_request_response__unpack(req_p,
+ 1, len, dev_p->usb_ep_data);
+
+ type = (uint8_t)((val >> 14) & 0x03);
+ if (type == 0) {
+ if (cy_as_device_is_ack_delayed(dev_p)) {
+ /*
+ * A setup packet has arrived while we are
+ * processing a previous setup packet. reset
+ * our state with respect to EP0 to be ready
+ * to process the new packet.
+ */
+ cy_as_usb_reset_e_p0_state(dev_p);
+ }
+
+ if (len != 8)
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT,
+ CY_AS_ERROR_INVALID_REQUEST, 0);
+ else {
+ cy_as_device_clear_ep0_stalled(dev_p);
+ cy_as_device_set_setup_packet(dev_p);
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT,
+ CY_AS_ERROR_SUCCESS, 0);
+
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_setup_packet,
+ dev_p->usb_ep_data);
+ else
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_setup_packet,
+ dev_p->usb_ep_data);
+
+ if ((!cy_as_device_is_ack_delayed(dev_p)) &&
+ (!cy_as_device_is_ep0_stalled(dev_p)))
+ cy_as_usb_ack_setup_packet(h,
+ usb_ack_callback, 0);
+ }
+ } else if (type == 2) {
+ if (len != 0)
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT,
+ CY_AS_ERROR_INVALID_REQUEST, 0);
+ else {
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_status_packet, 0);
+ else
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_status_packet, 0);
+
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT,
+ CY_AS_ERROR_SUCCESS, 0);
+ }
+ } else if (type == 1) {
+ /*
+ * we need to hand the data associated with these
+ * endpoints to the DMA module.
+ */
+ cy_as_dma_received_data(dev_p, ep, len, dev_p->usb_ep_data);
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+ }
+}
+
+static void
+my_usb_request_callback_inquiry(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p)
+{
+ cy_as_usb_inquiry_data_dep cbdata;
+ cy_as_usb_inquiry_data cbdata_ms;
+ void *data;
+ uint16_t val;
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+ uint8_t def_inq_data[64];
+ uint8_t evpd;
+ uint8_t codepage;
+ cy_bool updated;
+ uint16_t length;
+
+ cy_as_bus_number_t bus;
+ uint32_t device;
+ cy_as_media_type media;
+
+ val = cy_as_ll_request_response__get_word(req_p, 0);
+ bus = cy_as_storage_get_bus_from_address(val);
+ device = cy_as_storage_get_device_from_address(val);
+ media = cy_as_storage_get_media_from_address(val);
+
+ val = cy_as_ll_request_response__get_word(req_p, 1);
+ evpd = (uint8_t)((val >> 8) & 0x01);
+ codepage = (uint8_t)(val & 0xff);
+
+ length = cy_as_ll_request_response__get_word(req_p, 2);
+ data = (void *)def_inq_data;
+
+ updated = cy_false;
+
+ if (dev_p->usb_event_cb_ms) {
+ cbdata_ms.bus = bus;
+ cbdata_ms.device = device;
+ cbdata_ms.updated = updated;
+ cbdata_ms.evpd = evpd;
+ cbdata_ms.codepage = codepage;
+ cbdata_ms.length = length;
+ cbdata_ms.data = data;
+
+ cy_as_hal_assert(cbdata_ms.length <= sizeof(def_inq_data));
+ cy_as_ll_request_response__unpack(req_p,
+ 3, cbdata_ms.length, cbdata_ms.data);
+
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_inquiry_before, &cbdata_ms);
+
+ updated = cbdata_ms.updated;
+ data = cbdata_ms.data;
+ length = cbdata_ms.length;
+ } else if (dev_p->usb_event_cb) {
+ cbdata.media = media;
+ cbdata.updated = updated;
+ cbdata.evpd = evpd;
+ cbdata.codepage = codepage;
+ cbdata.length = length;
+ cbdata.data = data;
+
+ cy_as_hal_assert(cbdata.length <=
+ sizeof(def_inq_data));
+ cy_as_ll_request_response__unpack(req_p, 3,
+ cbdata.length, cbdata.data);
+
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_inquiry_before, &cbdata);
+
+ updated = cbdata.updated;
+ data = cbdata.data;
+ length = cbdata.length;
+ }
+
+ if (updated && length > 192)
+ cy_as_hal_print_message("an inquiry result from a "
+ "cy_as_event_usb_inquiry_before event "
+ "was greater than 192 bytes.");
+
+ /* Now send the reply with the data back
+ * to the West Bridge device */
+ if (updated && length <= 192) {
+ /*
+ * the callback function modified the inquiry
+ * data, ship the data back to the west bridge firmware.
+ */
+ cy_as_ll_send_data_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT,
+ CY_RESP_INQUIRY_DATA, length, data);
+ } else {
+ /*
+ * the callback did not modify the data, just acknowledge
+ * that we processed the request
+ */
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1);
+ }
+
+ if (dev_p->usb_event_cb_ms)
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_inquiry_after, &cbdata_ms);
+ else if (dev_p->usb_event_cb)
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_inquiry_after, &cbdata);
+}
+
+static void
+my_usb_request_callback_start_stop(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p)
+{
+ cy_as_bus_number_t bus;
+ cy_as_media_type media;
+ uint32_t device;
+ uint16_t val;
+
+ if (dev_p->usb_event_cb_ms || dev_p->usb_event_cb) {
+ cy_bool loej;
+ cy_bool start;
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+
+ val = cy_as_ll_request_response__get_word(req_p, 0);
+ bus = cy_as_storage_get_bus_from_address(val);
+ device = cy_as_storage_get_device_from_address(val);
+ media = cy_as_storage_get_media_from_address(val);
+
+ val = cy_as_ll_request_response__get_word(req_p, 1);
+ loej = (val & 0x02) ? cy_true : cy_false;
+ start = (val & 0x01) ? cy_true : cy_false;
+
+ if (dev_p->usb_event_cb_ms) {
+ cy_as_usb_start_stop_data cbdata_ms;
+
+ cbdata_ms.bus = bus;
+ cbdata_ms.device = device;
+ cbdata_ms.loej = loej;
+ cbdata_ms.start = start;
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_start_stop, &cbdata_ms);
+
+ } else if (dev_p->usb_event_cb) {
+ cy_as_usb_start_stop_data_dep cbdata;
+
+ cbdata.media = media;
+ cbdata.loej = loej;
+ cbdata.start = start;
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_start_stop, &cbdata);
+ }
+ }
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1);
+}
+
+static void
+my_usb_request_callback_uknown_c_b_w(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p)
+{
+ uint16_t val;
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+ uint8_t buf[16];
+
+ uint8_t response[4];
+ uint16_t reqlen;
+ void *request;
+ uint8_t status;
+ uint8_t key;
+ uint8_t asc;
+ uint8_t ascq;
+
+ val = cy_as_ll_request_response__get_word(req_p, 0);
+ /* Failed by default */
+ status = 1;
+ /* Invalid command */
+ key = 0x05;
+ /* Invalid command */
+ asc = 0x20;
+ /* Invalid command */
+ ascq = 0x00;
+ reqlen = cy_as_ll_request_response__get_word(req_p, 1);
+ request = buf;
+
+ cy_as_hal_assert(reqlen <= sizeof(buf));
+ cy_as_ll_request_response__unpack(req_p, 2, reqlen, request);
+
+ if (dev_p->usb_event_cb_ms) {
+ cy_as_usb_unknown_command_data cbdata_ms;
+ cbdata_ms.bus = cy_as_storage_get_bus_from_address(val);
+ cbdata_ms.device =
+ cy_as_storage_get_device_from_address(val);
+ cbdata_ms.reqlen = reqlen;
+ cbdata_ms.request = request;
+ cbdata_ms.status = status;
+ cbdata_ms.key = key;
+ cbdata_ms.asc = asc;
+ cbdata_ms.ascq = ascq;
+
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_unknown_storage, &cbdata_ms);
+ status = cbdata_ms.status;
+ key = cbdata_ms.key;
+ asc = cbdata_ms.asc;
+ ascq = cbdata_ms.ascq;
+ } else if (dev_p->usb_event_cb) {
+ cy_as_usb_unknown_command_data_dep cbdata;
+ cbdata.media =
+ cy_as_storage_get_media_from_address(val);
+ cbdata.reqlen = reqlen;
+ cbdata.request = request;
+ cbdata.status = status;
+ cbdata.key = key;
+ cbdata.asc = asc;
+ cbdata.ascq = ascq;
+
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_unknown_storage, &cbdata);
+ status = cbdata.status;
+ key = cbdata.key;
+ asc = cbdata.asc;
+ ascq = cbdata.ascq;
+ }
+
+ response[0] = status;
+ response[1] = key;
+ response[2] = asc;
+ response[3] = ascq;
+ cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
+ CY_RESP_UNKNOWN_SCSI_COMMAND, sizeof(response), response);
+}
+
+static void
+my_usb_request_callback_m_s_c_progress(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p)
+{
+ uint16_t val1, val2;
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+
+ if ((dev_p->usb_event_cb) || (dev_p->usb_event_cb_ms)) {
+ cy_as_m_s_c_progress_data cbdata;
+
+ val1 = cy_as_ll_request_response__get_word(req_p, 0);
+ val2 = cy_as_ll_request_response__get_word(req_p, 1);
+ cbdata.wr_count = (uint32_t)((val1 << 16) | val2);
+
+ val1 = cy_as_ll_request_response__get_word(req_p, 2);
+ val2 = cy_as_ll_request_response__get_word(req_p, 3);
+ cbdata.rd_count = (uint32_t)((val1 << 16) | val2);
+
+ if (dev_p->usb_event_cb)
+ dev_p->usb_event_cb(h,
+ cy_as_event_usb_m_s_c_progress, &cbdata);
+ else
+ dev_p->usb_event_cb_ms(h,
+ cy_as_event_usb_m_s_c_progress, &cbdata);
+ }
+
+ cy_as_ll_send_status_response(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
+}
+
+/*
+* This function processes the requests delivered from the
+* firmware within the West Bridge device that are delivered
+* in the USB context. These requests generally are EP0 and
+* EP1 related requests or USB events.
+*/
+static void
+my_usb_request_callback(cy_as_device *dev_p, uint8_t context,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *resp_p,
+ cy_as_return_status_t ret)
+{
+ uint16_t val;
+ uint8_t code = cy_as_ll_request_response__get_code(req_p);
+
+ (void)resp_p;
+ (void)context;
+ (void)ret;
+
+ switch (code) {
+ case CY_RQT_USB_EVENT:
+ my_usb_request_callback_usb_event(dev_p, req_p);
+ break;
+
+ case CY_RQT_USB_EP_DATA:
+ dev_p->usb_last_event = cy_as_event_usb_setup_packet;
+ my_usb_request_callback_usb_data(dev_p, req_p);
+ break;
+
+ case CY_RQT_SCSI_INQUIRY_COMMAND:
+ dev_p->usb_last_event = cy_as_event_usb_inquiry_after;
+ my_usb_request_callback_inquiry(dev_p, req_p);
+ break;
+
+ case CY_RQT_SCSI_START_STOP_COMMAND:
+ dev_p->usb_last_event = cy_as_event_usb_start_stop;
+ my_usb_request_callback_start_stop(dev_p, req_p);
+ break;
+
+ case CY_RQT_SCSI_UNKNOWN_COMMAND:
+ dev_p->usb_last_event = cy_as_event_usb_unknown_storage;
+ my_usb_request_callback_uknown_c_b_w(dev_p, req_p);
+ break;
+
+ case CY_RQT_USB_ACTIVITY_UPDATE:
+ dev_p->usb_last_event = cy_as_event_usb_m_s_c_progress;
+ my_usb_request_callback_m_s_c_progress(dev_p, req_p);
+ break;
+
+ default:
+ cy_as_hal_print_message("invalid request "
+ "received on USB context\n");
+ val = req_p->box0;
+ cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
+ CY_RESP_INVALID_REQUEST, sizeof(val), &val);
+ break;
+ }
+}
+
+static cy_as_return_status_t
+my_handle_response_usb_start(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /*
+ * mark EP 0 and EP1 as 64 byte endpoints
+ */
+ cy_as_dma_set_max_dma_size(dev_p, 0, 64);
+ cy_as_dma_set_max_dma_size(dev_p, 1, 64);
+
+ dev_p->usb_count++;
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
+ cy_as_ll_register_request_callback(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, 0);
+ }
+
+ cy_as_device_clear_u_s_s_pending(dev_p);
+
+ return ret;
+
+}
+
+/*
+* This function starts the USB stack. The stack is reference
+* counted so if the stack is already started, this function
+* just increments the count. If the stack has not been started,
+* a start request is sent to the West Bridge device.
+*
+* Note: Starting the USB stack does not cause the USB signals
+* to be connected to the USB pins. To do this and therefore
+* initiate enumeration, CyAsUsbConnect() must be called.
+*/
+cy_as_return_status_t
+cy_as_usb_start(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p, *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_start called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (cy_as_device_is_u_s_s_pending(dev_p))
+ return CY_AS_ERROR_STARTSTOP_PENDING;
+
+ cy_as_device_set_u_s_s_pending(dev_p);
+
+ if (dev_p->usb_count == 0) {
+ /*
+ * since we are just starting the stack,
+ * mark USB as not connected to the remote host
+ */
+ cy_as_device_clear_usb_connected(dev_p);
+ dev_p->usb_phy_config = 0;
+
+ /* Queue for 1.0 Async Requests, kept for
+ * backwards compatibility */
+ dev_p->usb_func_cbs = cy_as_create_c_b_queue(CYAS_USB_FUNC_CB);
+ if (dev_p->usb_func_cbs == 0) {
+ cy_as_device_clear_u_s_s_pending(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* Reset the EP0 state */
+ cy_as_usb_reset_e_p0_state(dev_p);
+
+ /*
+ * we register here becuase the start request may cause
+ * events to occur before the response to the start request.
+ */
+ cy_as_ll_register_request_callback(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, my_usb_request_callback);
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_START_USB, CY_RQT_USB_RQT_CONTEXT, 0);
+ if (req_p == 0) {
+ cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
+ dev_p->usb_func_cbs = 0;
+ cy_as_device_clear_u_s_s_pending(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* Reserve space for the reply, the reply data
+ * will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
+ dev_p->usb_func_cbs = 0;
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_device_clear_u_s_s_pending(dev_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_usb_start(dev_p,
+ req_p, reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb,
+ client, CY_FUNCT_CB_USB_START, 0,
+ dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ } else {
+ dev_p->usb_count++;
+ if (cb)
+ cb(handle, ret, client, CY_FUNCT_CB_USB_START, 0);
+ }
+
+ cy_as_device_clear_u_s_s_pending(dev_p);
+
+ return ret;
+}
+
+void
+cy_as_usb_reset(cy_as_device *dev_p)
+{
+ int i;
+
+ cy_as_device_clear_usb_connected(dev_p);
+
+ for (i = 0; i < sizeof(dev_p->usb_config) /
+ sizeof(dev_p->usb_config[0]); i++) {
+ /*
+ * cancel all pending USB read/write operations, as it is
+ * possible that the USB stack comes up in a different
+ * configuration with a different set of endpoints.
+ */
+ if (cy_as_device_is_usb_async_pending(dev_p, i))
+ cy_as_usb_cancel_async(dev_p,
+ (cy_as_end_point_number_t)i);
+
+ dev_p->usb_cb[i] = 0;
+ dev_p->usb_config[i].enabled = cy_false;
+ }
+
+ dev_p->usb_phy_config = 0;
+}
+
+/*
+ * This function does all the API side clean-up associated
+ * with CyAsUsbStop, without any communication with firmware.
+ * This needs to be done when the device is being reset while
+ * the USB stack is active.
+ */
+void
+cy_as_usb_cleanup(cy_as_device *dev_p)
+{
+ if (dev_p->usb_count) {
+ cy_as_usb_reset_e_p0_state(dev_p);
+ cy_as_usb_reset(dev_p);
+ cy_as_hal_mem_set(dev_p->usb_config, 0,
+ sizeof(dev_p->usb_config));
+ cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
+
+ dev_p->usb_count = 0;
+ }
+}
+
+static cy_as_return_status_t
+my_handle_response_usb_stop(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /*
+ * we sucessfully shutdown the stack, so
+ * decrement to make the count zero.
+ */
+ cy_as_usb_cleanup(dev_p);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ cy_as_ll_register_request_callback(dev_p,
+ CY_RQT_USB_RQT_CONTEXT, 0);
+
+ cy_as_device_clear_u_s_s_pending(dev_p);
+
+ return ret;
+}
+
+/*
+* This function stops the USB stack. The USB stack is reference
+* counted so first is reference count is decremented. If the
+* reference count is then zero, a request is sent to the West
+* Bridge device to stop the USB stack on the West Bridge device.
+*/
+cy_as_return_status_t
+cy_as_usb_stop(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p = 0, *reply_p = 0;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_stop called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_usb_connected(dev_p))
+ return CY_AS_ERROR_USB_CONNECTED;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (cy_as_device_is_u_s_s_pending(dev_p))
+ return CY_AS_ERROR_STARTSTOP_PENDING;
+
+ cy_as_device_set_u_s_s_pending(dev_p);
+
+ if (dev_p->usb_count == 1) {
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_STOP_USB,
+ CY_RQT_USB_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 = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ ret = CY_AS_ERROR_OUT_OF_MEMORY;
+ goto destroy;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_usb_stop(dev_p,
+ req_p, reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_STOP, 0, dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ } else if (dev_p->usb_count > 1) {
+ /*
+ * reset all LE_ps to inactive state, after cleaning
+ * up any pending async read/write calls.
+ */
+ cy_as_usb_reset(dev_p);
+ dev_p->usb_count--;
+
+ if (cb)
+ cb(handle, ret, client, CY_FUNCT_CB_USB_STOP, 0);
+ }
+
+ cy_as_device_clear_u_s_s_pending(dev_p);
+
+ return ret;
+}
+
+/*
+* This function registers a callback to be called when
+* USB events are processed
+*/
+cy_as_return_status_t
+cy_as_usb_register_callback(cy_as_device_handle handle,
+ cy_as_usb_event_callback callback)
+{
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_register_callback called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (!cy_as_device_is_configured(dev_p))
+ return CY_AS_ERROR_NOT_CONFIGURED;
+
+ if (!cy_as_device_is_firmware_loaded(dev_p))
+ return CY_AS_ERROR_NO_FIRMWARE;
+
+ dev_p->usb_event_cb = NULL;
+ dev_p->usb_event_cb_ms = callback;
+ return CY_AS_ERROR_SUCCESS;
+}
+
+
+static cy_as_return_status_t
+my_handle_response_no_data(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_connect(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ cy_as_device_set_usb_connected(dev_p);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+
+/*
+* This method asks the West Bridge device to connect the
+* internal USB D+ and D- signals to the USB pins, thus
+* starting the enumeration processes if the external pins
+* are connnected to a USB host. If the external pins are
+* not connect to a USB host, enumeration will begin as soon
+* as the USB pins are connected to a host.
+*/
+cy_as_return_status_t
+cy_as_usb_connect(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_connect called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* 1 = Connect request */
+ cy_as_ll_request_response__set_word(req_p, 0, 1);
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_connect(dev_p, req_p, reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_CONNECT, 0, dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_disconnect(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_return_status_t ret)
+{
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ cy_as_device_clear_usb_connected(dev_p);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+/*
+* This method forces a disconnect of the D+ and D- pins
+* external to the West Bridge device from the D+ and D-
+* signals internally, effectively disconnecting the West
+* Bridge device from any connected USB host.
+*/
+cy_as_return_status_t
+cy_as_usb_disconnect(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_disconnect called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (!cy_as_device_is_usb_connected(dev_p))
+ return CY_AS_ERROR_USB_NOT_CONNECTED;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0, 0);
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed two bytes */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_disconnect(dev_p,
+ req_p, reply_p, ret);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_DISCONNECT, 0, dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_set_enum_config(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ /*
+ * we configured the west bridge device and
+ * enumeration is going to happen on the P port
+ * processor. now we must enable endpoint zero
+ */
+ cy_as_usb_end_point_config config;
+
+ config.dir = cy_as_usb_in_out;
+ config.type = cy_as_usb_control;
+ config.enabled = cy_true;
+
+ ret = cy_as_usb_set_end_point_config((cy_as_device_handle *)
+ dev_p, 0, &config);
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+/*
+* This method sets how the USB is enumerated and should
+* be called before the CyAsUsbConnect() is called.
+*/
+static cy_as_return_status_t
+my_usb_set_enum_config(cy_as_device *dev_p,
+ uint8_t bus_mask,
+ uint8_t media_mask,
+ cy_bool use_antioch_enumeration,
+ uint8_t mass_storage_interface,
+ uint8_t mtp_interface,
+ cy_bool mass_storage_callbacks,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_log_debug_message(6, "cy_as_usb_set_enum_config called");
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_usb_connected(dev_p))
+ return CY_AS_ERROR_USB_CONNECTED;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ /* if we are using MTP firmware: */
+ if (dev_p->is_mtp_firmware == 1) {
+ /* we cannot enumerate MSC */
+ if (mass_storage_interface != 0)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ if (bus_mask == 0) {
+ if (mtp_interface != 0)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+ } else if (bus_mask == 2) {
+ /* enable EP 1 as it will be used */
+ cy_as_dma_enable_end_point(dev_p, 1, cy_true,
+ cy_as_direction_in);
+ dev_p->usb_config[1].enabled = cy_true;
+ dev_p->usb_config[1].dir = cy_as_usb_in;
+ dev_p->usb_config[1].type = cy_as_usb_int;
+ } else {
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+ }
+ /* if we are not using MTP firmware, we cannot enumerate MTP */
+ } else if (mtp_interface != 0)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ /*
+ * if we are not enumerating mass storage, we should
+ * not be providing an interface number.
+ */
+ if (bus_mask == 0 && mass_storage_interface != 0)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ /*
+ * if we are going to use mtp_interface, bus mask must be 2.
+ */
+ if (mtp_interface != 0 && bus_mask != 2)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_SET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 4);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* Marshal the structure */
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)((media_mask << 8) | bus_mask));
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)use_antioch_enumeration);
+ cy_as_ll_request_response__set_word(req_p, 2,
+ dev_p->is_mtp_firmware ? mtp_interface :
+ mass_storage_interface);
+ cy_as_ll_request_response__set_word(req_p, 3,
+ (uint16_t)mass_storage_callbacks);
+
+ /* Reserve space for the reply, the reply
+ * data will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_set_enum_config(dev_p,
+ req_p, reply_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_SETENUMCONFIG, 0, dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+/*
+ * This method sets how the USB is enumerated and should
+ * be called before the CyAsUsbConnect() is called.
+ */
+cy_as_return_status_t
+cy_as_usb_set_enum_config(cy_as_device_handle handle,
+ cy_as_usb_enum_control *config_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ uint8_t bus_mask, media_mask;
+ uint32_t bus, device;
+ cy_as_return_status_t ret;
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if ((cy_as_device_is_in_callback(dev_p)) && (cb != 0))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ /* Since we are mapping the media types to bus with NAND to 0
+ * and the rest to 1, and we are only allowing for enumerating
+ * all the devices on a bus we just scan the array for any
+ * positions where there a device is enabled and mark the bus
+ * to be enumerated.
+ */
+ bus_mask = 0;
+ media_mask = 0;
+ media_mask = 0;
+ for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
+ for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++) {
+ if (config_p->devices_to_enumerate[bus][device] ==
+ cy_true) {
+ bus_mask |= (0x01 << bus);
+ media_mask |= dev_p->media_supported[bus];
+ media_mask |= dev_p->media_supported[bus];
+ }
+ }
+ }
+
+ return my_usb_set_enum_config(dev_p, bus_mask, media_mask,
+ config_p->antioch_enumeration,
+ config_p->mass_storage_interface,
+ config_p->mtp_interface,
+ config_p->mass_storage_callbacks,
+ cb,
+ client
+ );
+}
+
+
+static cy_as_return_status_t
+my_handle_response_get_enum_config(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ void *config_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint16_t val;
+ uint8_t bus_mask;
+ uint32_t bus;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_USB_CONFIG) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ /* Marshal the reply */
+ if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) {
+ uint32_t device;
+ cy_bool state;
+ cy_as_usb_enum_control *ms_config_p =
+ (cy_as_usb_enum_control *)config_p;
+
+ bus_mask = (uint8_t)
+ (cy_as_ll_request_response__get_word
+ (reply_p, 0) & 0xFF);
+ for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
+ if (bus_mask & (1 << bus))
+ state = cy_true;
+ else
+ state = cy_false;
+
+ for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES;
+ device++)
+ ms_config_p->devices_to_enumerate[bus][device]
+ = state;
+ }
+
+ ms_config_p->antioch_enumeration =
+ (cy_bool)cy_as_ll_request_response__get_word
+ (reply_p, 1);
+
+ val = cy_as_ll_request_response__get_word(reply_p, 2);
+ if (dev_p->is_mtp_firmware) {
+ ms_config_p->mass_storage_interface = 0;
+ ms_config_p->mtp_interface = (uint8_t)(val & 0xFF);
+ } else {
+ ms_config_p->mass_storage_interface =
+ (uint8_t)(val & 0xFF);
+ ms_config_p->mtp_interface = 0;
+ }
+ ms_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
+
+ /*
+ * firmware returns an invalid interface number for mass storage,
+ * if mass storage is not enabled. this needs to be converted to
+ * zero to match the input configuration.
+ */
+ if (bus_mask == 0) {
+ if (dev_p->is_mtp_firmware)
+ ms_config_p->mtp_interface = 0;
+ else
+ ms_config_p->mass_storage_interface = 0;
+ }
+ } else {
+ cy_as_usb_enum_control_dep *ex_config_p =
+ (cy_as_usb_enum_control_dep *)config_p;
+
+ ex_config_p->enum_mass_storage = (uint8_t)
+ ((cy_as_ll_request_response__get_word
+ (reply_p, 0) >> 8) & 0xFF);
+ ex_config_p->antioch_enumeration = (cy_bool)
+ cy_as_ll_request_response__get_word(reply_p, 1);
+
+ val = cy_as_ll_request_response__get_word(reply_p, 2);
+ ex_config_p->mass_storage_interface = (uint8_t)(val & 0xFF);
+ ex_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
+
+ /*
+ * firmware returns an invalid interface number for mass
+ * storage, if mass storage is not enabled. this needs to
+ * be converted to zero to match the input configuration.
+ */
+ if (ex_config_p->enum_mass_storage == 0)
+ ex_config_p->mass_storage_interface = 0;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+/*
+* This sets up the request for the enumerateion configuration
+* information, based on if the request is from the old pre-1.2
+* functions.
+*/
+static cy_as_return_status_t
+my_usb_get_enum_config(cy_as_device_handle handle,
+ uint16_t req_flags,
+ void *config_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_get_enum_config called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_GET_USB_CONFIG, CY_RQT_USB_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 two bytes */
+ reply_p = cy_as_ll_create_response(dev_p, 3);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ /* we need to know the type of request to
+ * know how to manage the data */
+ req_p->flags |= req_flags;
+ return my_handle_response_get_enum_config(dev_p,
+ req_p, reply_p, config_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_GETENUMCONFIG, config_p,
+ dev_p->func_cbs_usb, req_flags, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+/*
+ * This method returns the enumerateion configuration information
+ * from the West Bridge device. Generally this is not used by
+ * client software but is provided mostly for debug information.
+ * We want a method to read all state information from the device.
+ */
+cy_as_return_status_t
+cy_as_usb_get_enum_config(cy_as_device_handle handle,
+ cy_as_usb_enum_control *config_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ return my_usb_get_enum_config(handle,
+ CY_AS_REQUEST_RESPONSE_MS, config_p, cb, client);
+}
+
+
+/*
+* This method sets the USB descriptor for a given entity.
+*/
+cy_as_return_status_t
+cy_as_usb_set_descriptor(cy_as_device_handle handle,
+ cy_as_usb_desc_type type,
+ uint8_t index,
+ void *desc_p,
+ uint16_t length,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint16_t pktlen;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_set_descriptor called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (length > CY_AS_MAX_USB_DESCRIPTOR_SIZE)
+ return CY_AS_ERROR_INVALID_DESCRIPTOR;
+
+ pktlen = (uint16_t)length / 2;
+ if (length % 2)
+ pktlen++;
+ pktlen += 2; /* 1 for type, 1 for length */
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_DESCRIPTOR,
+ CY_RQT_USB_RQT_CONTEXT, (uint16_t)pktlen);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)((uint8_t)type | (index << 8)));
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)length);
+ cy_as_ll_request_response__pack(req_p, 2, length, desc_p);
+
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_no_data(dev_p, req_p, reply_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_SETDESCRIPTOR, 0, dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+/*
+ * This method clears all descriptors that were previously
+ * stored on the West Bridge through CyAsUsbSetDescriptor calls.
+ */
+cy_as_return_status_t
+cy_as_usb_clear_descriptors(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_clear_descriptors called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if ((cy_as_device_is_in_callback(dev_p)) && (cb == 0))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_CLEAR_DESCRIPTORS, CY_RQT_USB_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_no_data(dev_p, req_p, reply_p);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_CLEARDESCRIPTORS, 0,
+ dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_get_descriptor(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_as_get_descriptor_data *data)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint32_t retlen;
+
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ goto destroy;
+ } else if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_USB_DESCRIPTOR) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ retlen = cy_as_ll_request_response__get_word(reply_p, 0);
+ if (retlen > data->length) {
+ ret = CY_AS_ERROR_INVALID_SIZE;
+ goto destroy;
+ }
+
+ ret = CY_AS_ERROR_SUCCESS;
+ cy_as_ll_request_response__unpack(reply_p, 1,
+ retlen, data->desc_p);
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+/*
+* This method retreives the USB descriptor for a given type.
+*/
+cy_as_return_status_t
+cy_as_usb_get_descriptor(cy_as_device_handle handle,
+ cy_as_usb_desc_type type,
+ uint8_t index,
+ cy_as_get_descriptor_data *data,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_get_descriptor called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_GET_DESCRIPTOR, CY_RQT_USB_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)((uint8_t)type | (index << 8)));
+
+ /* Add one for the length field */
+ reply_p = cy_as_ll_create_response(dev_p,
+ CY_AS_MAX_USB_DESCRIPTOR_SIZE + 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(
+ dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return my_handle_response_get_descriptor(dev_p,
+ req_p, reply_p, data);
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_GETDESCRIPTOR, data,
+ dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p,
+ reply_p, cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_usb_set_physical_configuration(cy_as_device_handle handle,
+ uint8_t config)
+{
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6,
+ "cy_as_usb_set_physical_configuration called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_usb_connected(dev_p))
+ return CY_AS_ERROR_USB_CONNECTED;
+
+ if (config < 1 || config > 12)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ dev_p->usb_phy_config = config;
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static cy_bool
+is_physical_valid(uint8_t config, cy_as_end_point_number_t ep)
+{
+ static uint8_t validmask[12] = {
+ 0x0f, /* Config 1 - 1, 2, 3, 4 */
+ 0x07, /* Config 2 - 1, 2, 3 */
+ 0x07, /* Config 3 - 1, 2, 3 */
+ 0x0d, /* Config 4 - 1, 3, 4 */
+ 0x05, /* Config 5 - 1, 3 */
+ 0x05, /* Config 6 - 1, 3 */
+ 0x0d, /* Config 7 - 1, 3, 4 */
+ 0x05, /* Config 8 - 1, 3 */
+ 0x05, /* Config 9 - 1, 3 */
+ 0x0d, /* Config 10 - 1, 3, 4 */
+ 0x09, /* Config 11 - 1, 4 */
+ 0x01 /* Config 12 - 1 */
+ };
+
+ return (validmask[config - 1] & (1 << (ep - 1))) ? cy_true : cy_false;
+}
+
+/*
+* This method sets the configuration for an endpoint
+*/
+cy_as_return_status_t
+cy_as_usb_set_end_point_config(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
+{
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_set_end_point_config called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_usb_connected(dev_p))
+ return CY_AS_ERROR_USB_CONNECTED;
+
+ if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ if (ep == 0) {
+ /* Endpoint 0 must be 64 byte, dir IN/OUT,
+ * and control type */
+ if (config_p->dir != cy_as_usb_in_out ||
+ config_p->type != cy_as_usb_control)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+ } else if (ep == 1) {
+ if ((dev_p->is_mtp_firmware == 1) &&
+ (dev_p->usb_config[1].enabled == cy_true)) {
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+ }
+
+ /*
+ * EP1 can only be used either as an OUT ep, or as an IN ep.
+ */
+ if ((config_p->type == cy_as_usb_control) ||
+ (config_p->type == cy_as_usb_iso) ||
+ (config_p->dir == cy_as_usb_in_out))
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+ } else {
+ if (config_p->dir == cy_as_usb_in_out ||
+ config_p->type == cy_as_usb_control)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ if (!is_physical_valid(dev_p->usb_phy_config,
+ config_p->physical))
+ return CY_AS_ERROR_INVALID_PHYSICAL_ENDPOINT;
+
+ /*
+ * ISO endpoints must be on E_ps 3, 5, 7 or 9 as
+ * they need to align directly with the underlying
+ * physical endpoint.
+ */
+ if (config_p->type == cy_as_usb_iso) {
+ if (ep != 3 && ep != 5 && ep != 7 && ep != 9)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ if (ep == 3 && config_p->physical != 1)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ if (ep == 5 && config_p->physical != 2)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ if (ep == 7 && config_p->physical != 3)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ if (ep == 9 && config_p->physical != 4)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+ }
+ }
+
+ /* Store the configuration information until a
+ * CyAsUsbCommitConfig is done */
+ dev_p->usb_config[ep] = *config_p;
+
+ /* If the endpoint is enabled, enable DMA associated
+ * with the endpoint */
+ /*
+ * we make some assumptions that we check here. we assume
+ * that the direction fields for the DMA module are the same
+ * values as the direction values for the USB module.
+ */
+ cy_as_hal_assert((int)cy_as_usb_in == (int)cy_as_direction_in);
+ cy_as_hal_assert((int)cy_as_usb_out == (int)cy_as_direction_out);
+ cy_as_hal_assert((int)cy_as_usb_in_out == (int)cy_as_direction_in_out);
+
+ return cy_as_dma_enable_end_point(dev_p, ep,
+ config_p->enabled, (cy_as_dma_direction)config_p->dir);
+}
+
+cy_as_return_status_t
+cy_as_usb_get_end_point_config(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
+{
+ cy_as_return_status_t ret;
+
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_get_end_point_config called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ *config_p = dev_p->usb_config[ep];
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+/*
+* Commit the configuration of the various endpoints to the hardware.
+*/
+cy_as_return_status_t
+cy_as_usb_commit_config(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ uint32_t i;
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+ cy_as_device *dev_p;
+ uint16_t data;
+
+ cy_as_log_debug_message(6, "cy_as_usb_commit_config called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_usb_connected(dev_p))
+ return CY_AS_ERROR_USB_CONNECTED;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ /*
+ * this performs the mapping based on informatation that was
+ * previously stored on the device about the various endpoints
+ * and how they are configured. the output of this mapping is
+ * setting the the 14 register values contained in usb_lepcfg
+ * and usb_pepcfg
+ */
+ ret = cy_as_usb_map_logical2_physical(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /*
+ * now, package the information about the various logical and
+ * physical endpoint configuration registers and send it
+ * across to the west bridge device.
+ */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_SET_USB_CONFIG_REGISTERS, CY_RQT_USB_RQT_CONTEXT, 8);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_hal_print_message("USB configuration: %d\n",
+ dev_p->usb_phy_config);
+ cy_as_hal_print_message("EP1OUT: 0x%02x EP1IN: 0x%02x\n",
+ dev_p->usb_ep1cfg[0], dev_p->usb_ep1cfg[1]);
+ cy_as_hal_print_message("PEP registers: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ dev_p->usb_pepcfg[0], dev_p->usb_pepcfg[1],
+ dev_p->usb_pepcfg[2], dev_p->usb_pepcfg[3]);
+
+ cy_as_hal_print_message("LEP registers: 0x%02x 0x%02x 0x%02x "
+ "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ dev_p->usb_lepcfg[0], dev_p->usb_lepcfg[1],
+ dev_p->usb_lepcfg[2], dev_p->usb_lepcfg[3],
+ dev_p->usb_lepcfg[4], dev_p->usb_lepcfg[5],
+ dev_p->usb_lepcfg[6], dev_p->usb_lepcfg[7],
+ dev_p->usb_lepcfg[8], dev_p->usb_lepcfg[9]);
+
+ /* Write the EP1OUTCFG and EP1INCFG data in the first word. */
+ data = (uint16_t)((dev_p->usb_ep1cfg[0] << 8) |
+ dev_p->usb_ep1cfg[1]);
+ cy_as_ll_request_response__set_word(req_p, 0, data);
+
+ /* Write the PEP CFG data in the next 2 words */
+ for (i = 0; i < 4; i += 2) {
+ data = (uint16_t)((dev_p->usb_pepcfg[i] << 8) |
+ dev_p->usb_pepcfg[i + 1]);
+ cy_as_ll_request_response__set_word(req_p,
+ 1 + i / 2, data);
+ }
+
+ /* Write the LEP CFG data in the next 5 words */
+ for (i = 0; i < 10; i += 2) {
+ data = (uint16_t)((dev_p->usb_lepcfg[i] << 8) |
+ dev_p->usb_lepcfg[i + 1]);
+ cy_as_ll_request_response__set_word(req_p,
+ 3 + i / 2, data);
+ }
+
+ /* A single status word response type */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ ret = my_handle_response_no_data(dev_p,
+ req_p, reply_p);
+
+ if (ret == CY_AS_ERROR_SUCCESS)
+ ret = cy_as_usb_setup_dma(dev_p);
+
+ return ret;
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_COMMITCONFIG, 0, dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static void
+sync_request_callback(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, void *buf_p,
+ uint32_t size, cy_as_return_status_t err)
+{
+ (void)ep;
+ (void)buf_p;
+
+ dev_p->usb_error = err;
+ dev_p->usb_actual_cnt = size;
+}
+
+static void
+async_read_request_callback(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, void *buf_p,
+ uint32_t size, cy_as_return_status_t err)
+{
+ cy_as_device_handle h;
+
+ cy_as_log_debug_message(6,
+ "async_read_request_callback called");
+
+ h = (cy_as_device_handle)dev_p;
+
+ if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
+ dev_p->usb_pending_buffer = buf_p;
+ dev_p->usb_pending_size = size;
+ dev_p->usb_error = err;
+ cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
+ } else {
+ cy_as_usb_io_callback cb;
+
+ cb = dev_p->usb_cb[ep];
+ dev_p->usb_cb[ep] = 0;
+ cy_as_device_clear_usb_async_pending(dev_p, ep);
+ if (cb)
+ cb(h, ep, size, buf_p, err);
+ }
+}
+
+static void
+async_write_request_callback(cy_as_device *dev_p,
+ cy_as_end_point_number_t ep, void *buf_p,
+ uint32_t size, cy_as_return_status_t err)
+{
+ cy_as_device_handle h;
+
+ cy_as_log_debug_message(6,
+ "async_write_request_callback called");
+
+ h = (cy_as_device_handle)dev_p;
+
+ if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
+ dev_p->usb_pending_buffer = buf_p;
+ dev_p->usb_pending_size = size;
+ dev_p->usb_error = err;
+
+ /* The west bridge protocol generates ZLPs as required. */
+ cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
+ } else {
+ cy_as_usb_io_callback cb;
+
+ cb = dev_p->usb_cb[ep];
+ dev_p->usb_cb[ep] = 0;
+
+ cy_as_device_clear_usb_async_pending(dev_p, ep);
+ if (cb)
+ cb(h, ep, size, buf_p, err);
+ }
+}
+
+static void
+my_turbo_rqt_callback(cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t stat)
+{
+ uint8_t code;
+
+ (void)context;
+ (void)stat;
+
+ /* The Handlers are responsible for Deleting the rqt and resp when
+ * they are finished
+ */
+ code = cy_as_ll_request_response__get_code(rqt);
+ switch (code) {
+ case CY_RQT_TURBO_SWITCH_ENDPOINT:
+ cy_as_hal_assert(stat == CY_AS_ERROR_SUCCESS);
+ cy_as_ll_destroy_request(dev_p, rqt);
+ cy_as_ll_destroy_response(dev_p, resp);
+ break;
+ default:
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+}
+
+/* Send a mailbox request to prepare the endpoint for switching */
+static cy_as_return_status_t
+my_send_turbo_switch(cy_as_device *dev_p, uint32_t size, cy_bool pktread)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+
+ /* Create the request to send to the West Bridge device */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_TURBO_SWITCH_ENDPOINT, CY_RQT_TUR_RQT_CONTEXT, 3);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* Reserve space for the reply, the reply data will
+ * not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)pktread);
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)((size >> 16) & 0xFFFF));
+ cy_as_ll_request_response__set_word(req_p, 2,
+ (uint16_t)(size & 0xFFFF));
+
+ ret = cy_as_ll_send_request(dev_p, req_p,
+ reply_p, cy_false, my_turbo_rqt_callback);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_request(dev_p, reply_p);
+ return ret;
+ }
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+cy_as_return_status_t
+cy_as_usb_read_data(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep, cy_bool pktread,
+ uint32_t dsize, uint32_t *dataread, void *data)
+{
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_read_data called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* EP2 is available for reading when MTP is active */
+ if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* If the endpoint is disabled, we cannot
+ * write data to the endpoint */
+ if (!dev_p->usb_config[ep].enabled)
+ return CY_AS_ERROR_ENDPOINT_DISABLED;
+
+ if (dev_p->usb_config[ep].dir != cy_as_usb_out)
+ return CY_AS_ERROR_USB_BAD_DIRECTION;
+
+ ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
+ pktread, cy_true, sync_request_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (ep == CY_AS_MTP_READ_ENDPOINT) {
+ ret = my_send_turbo_switch(dev_p, dsize, pktread);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p, ep, ret);
+ return ret;
+ }
+
+ ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ } else {
+ ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ }
+
+ ret = dev_p->usb_error;
+ *dataread = dev_p->usb_actual_cnt;
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_usb_read_data_async(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep, cy_bool pktread,
+ uint32_t dsize, void *data, cy_as_usb_io_callback cb)
+{
+ cy_as_return_status_t ret;
+ uint32_t mask;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_read_data_async called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* EP2 is available for reading when MTP is active */
+ if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* If the endpoint is disabled, we cannot
+ * write data to the endpoint */
+ if (!dev_p->usb_config[ep].enabled)
+ return CY_AS_ERROR_ENDPOINT_DISABLED;
+
+ if (dev_p->usb_config[ep].dir != cy_as_usb_out &&
+ dev_p->usb_config[ep].dir != cy_as_usb_in_out)
+ return CY_AS_ERROR_USB_BAD_DIRECTION;
+
+ /*
+ * since async operations can be triggered by interrupt
+ * code, we must insure that we do not get multiple async
+ * operations going at one time and protect this test and
+ * set operation from interrupts.
+ */
+ mask = cy_as_hal_disable_interrupts();
+ if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
+ cy_as_hal_enable_interrupts(mask);
+ return CY_AS_ERROR_ASYNC_PENDING;
+ }
+ cy_as_device_set_usb_async_pending(dev_p, ep);
+
+ /*
+ * if this is for EP0, we set this bit to delay the
+ * ACK response until after this read has completed.
+ */
+ if (ep == 0)
+ cy_as_device_set_ack_delayed(dev_p);
+
+ cy_as_hal_enable_interrupts(mask);
+
+ cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
+ dev_p->usb_cb[ep] = cb;
+
+ ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
+ pktread, cy_true, async_read_request_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (ep == CY_AS_MTP_READ_ENDPOINT) {
+ ret = my_send_turbo_switch(dev_p, dsize, pktread);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p, ep, ret);
+ return ret;
+ }
+ } else {
+ /* Kick start the queue if it is not running */
+ cy_as_dma_kick_start(dev_p, ep);
+ }
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_usb_write_data(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep, uint32_t dsize, void *data)
+{
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_write_data called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* EP6 is available for writing when MTP is active */
+ if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* If the endpoint is disabled, we cannot
+ * write data to the endpoint */
+ if (!dev_p->usb_config[ep].enabled)
+ return CY_AS_ERROR_ENDPOINT_DISABLED;
+
+ if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
+ dev_p->usb_config[ep].dir != cy_as_usb_in_out)
+ return CY_AS_ERROR_USB_BAD_DIRECTION;
+
+ /* Write on Turbo endpoint */
+ if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
+ cy_as_ll_request_response *req_p, *reply_p;
+
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
+ CY_RQT_TUR_RQT_CONTEXT, 3);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p,
+ 0, 0x0006); /* EP number to use. */
+ cy_as_ll_request_response__set_word(req_p,
+ 1, (uint16_t)((dsize >> 16) & 0xFFFF));
+ cy_as_ll_request_response__set_word(req_p,
+ 2, (uint16_t)(dsize & 0xFFFF));
+
+ /* Reserve space for the reply, the reply data
+ * will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (dsize) {
+ ret = cy_as_dma_queue_request(dev_p,
+ ep, data, dsize, cy_false,
+ cy_false, sync_request_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ }
+
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word
+ (reply_p, 0);
+ }
+
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ if (dsize)
+ cy_as_dma_cancel(dev_p, ep, ret);
+ return ret;
+ }
+
+ /* If this is a zero-byte write, firmware will
+ * handle it. there is no need to do any work here.
+ */
+ if (!dsize)
+ return CY_AS_ERROR_SUCCESS;
+ } else {
+ ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
+ cy_false, cy_false, sync_request_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ }
+
+ if (ep != CY_AS_MTP_WRITE_ENDPOINT)
+ ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
+ else
+ ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ ret = dev_p->usb_error;
+ return ret;
+}
+
+static void
+mtp_write_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ cy_as_usb_io_callback cb;
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+
+ cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if (cy_as_ll_request_response__get_code(resp) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word(resp, 0);
+ }
+
+ /* If this was a zero byte transfer request, we can
+ * call the callback from here. */
+ if ((cy_as_ll_request_response__get_word(rqt, 1) == 0) &&
+ (cy_as_ll_request_response__get_word(rqt, 2) == 0)) {
+ cb = dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT];
+ dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] = 0;
+ cy_as_device_clear_usb_async_pending(dev_p,
+ CY_AS_MTP_WRITE_ENDPOINT);
+ if (cb)
+ cb(h, CY_AS_MTP_WRITE_ENDPOINT, 0, 0, ret);
+
+ goto destroy;
+ }
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ /* Firmware failed the request. Cancel the DMA transfer. */
+ cy_as_dma_cancel(dev_p, 0x06, CY_AS_ERROR_CANCELED);
+ dev_p->usb_cb[0x06] = 0;
+ cy_as_device_clear_usb_async_pending(dev_p, 0x06);
+ }
+
+destroy:
+ cy_as_ll_destroy_response(dev_p, resp);
+ cy_as_ll_destroy_request(dev_p, rqt);
+}
+
+cy_as_return_status_t
+cy_as_usb_write_data_async(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep, uint32_t dsize, void *data,
+ cy_bool spacket, cy_as_usb_io_callback cb)
+{
+ uint32_t mask;
+ cy_as_return_status_t ret;
+ cy_as_device *dev_p;
+
+ cy_as_log_debug_message(6, "cy_as_usb_write_data_async called");
+
+ dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* EP6 is available for writing when MTP is active */
+ if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
+ return CY_AS_ERROR_INVALID_ENDPOINT;
+
+ /* If the endpoint is disabled, we cannot
+ * write data to the endpoint */
+ if (!dev_p->usb_config[ep].enabled)
+ return CY_AS_ERROR_ENDPOINT_DISABLED;
+
+ if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
+ dev_p->usb_config[ep].dir != cy_as_usb_in_out)
+ return CY_AS_ERROR_USB_BAD_DIRECTION;
+
+ /*
+ * since async operations can be triggered by interrupt
+ * code, we must insure that we do not get multiple
+ * async operations going at one time and
+ * protect this test and set operation from interrupts.
+ */
+ mask = cy_as_hal_disable_interrupts();
+ if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
+ cy_as_hal_enable_interrupts(mask);
+ return CY_AS_ERROR_ASYNC_PENDING;
+ }
+
+ cy_as_device_set_usb_async_pending(dev_p, ep);
+
+ if (ep == 0)
+ cy_as_device_set_ack_delayed(dev_p);
+
+ cy_as_hal_enable_interrupts(mask);
+
+ cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
+ dev_p->usb_cb[ep] = cb;
+ dev_p->usb_spacket[ep] = spacket;
+
+ /* Write on Turbo endpoint */
+ if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
+ cy_as_ll_request_response *req_p, *reply_p;
+
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
+ CY_RQT_TUR_RQT_CONTEXT, 3);
+
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ 0x0006); /* EP number to use. */
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)((dsize >> 16) & 0xFFFF));
+ cy_as_ll_request_response__set_word(req_p, 2,
+ (uint16_t)(dsize & 0xFFFF));
+
+ /* Reserve space for the reply, the reply data
+ * will not exceed one word */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (dsize) {
+ ret = cy_as_dma_queue_request(dev_p, ep, data,
+ dsize, cy_false, cy_false,
+ async_write_request_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ }
+
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
+ cy_false, mtp_write_callback);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ if (dsize)
+ cy_as_dma_cancel(dev_p, ep, ret);
+ return ret;
+ }
+
+ /* Firmware will handle a zero byte transfer
+ * without any DMA transfers. */
+ if (!dsize)
+ return CY_AS_ERROR_SUCCESS;
+ } else {
+ ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
+ cy_false, cy_false, async_write_request_callback);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+ }
+
+ /* Kick start the queue if it is not running */
+ if (ep != CY_AS_MTP_WRITE_ENDPOINT)
+ cy_as_dma_kick_start(dev_p, ep);
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+my_usb_cancel_async_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ uint8_t ep;
+ (void)context;
+
+ ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if (cy_as_ll_request_response__get_code(resp) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word(resp, 0);
+ }
+
+ cy_as_ll_destroy_request(dev_p, rqt);
+ cy_as_ll_destroy_response(dev_p, resp);
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
+ dev_p->usb_cb[ep] = 0;
+ cy_as_device_clear_usb_async_pending(dev_p, ep);
+ }
+}
+
+cy_as_return_status_t
+cy_as_usb_cancel_async(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p, *reply_p;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ep &= 0x7F; /* Remove the direction bit. */
+ if (!cy_as_device_is_usb_async_pending(dev_p, ep))
+ return CY_AS_ERROR_ASYNC_NOT_PENDING;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_suspend_mode(dev_p))
+ return CY_AS_ERROR_IN_SUSPEND;
+
+ if ((ep == CY_AS_MTP_WRITE_ENDPOINT) ||
+ (ep == CY_AS_MTP_READ_ENDPOINT)) {
+ /* Need firmware support for the cancel operation. */
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_CANCEL_ASYNC_TRANSFER,
+ CY_RQT_TUR_RQT_CONTEXT, 1);
+
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)ep);
+
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
+ cy_false, my_usb_cancel_async_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ return ret;
+ }
+ } else {
+ ret = cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ dev_p->usb_cb[ep] = 0;
+ cy_as_device_clear_usb_async_pending(dev_p, ep);
+ }
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+cy_as_usb_ack_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t ret)
+{
+ cy_as_func_c_b_node *node = (cy_as_func_c_b_node *)
+ dev_p->func_cbs_usb->head_p;
+
+ (void)context;
+
+ if (ret == CY_AS_ERROR_SUCCESS) {
+ if (cy_as_ll_request_response__get_code(resp) !=
+ CY_RESP_SUCCESS_FAILURE)
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ else
+ ret = cy_as_ll_request_response__get_word(resp, 0);
+ }
+
+ node->cb_p((cy_as_device_handle)dev_p, ret,
+ node->client_data, node->data_type, node->data);
+ cy_as_remove_c_b_node(dev_p->func_cbs_usb);
+
+ cy_as_ll_destroy_request(dev_p, rqt);
+ cy_as_ll_destroy_response(dev_p, resp);
+ cy_as_device_clear_ack_delayed(dev_p);
+}
+
+static cy_as_return_status_t
+cy_as_usb_ack_setup_packet(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p;
+ cy_as_ll_request_response *reply_p;
+ cy_as_func_c_b_node *cbnode;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p) && cb == 0)
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ cy_as_hal_assert(cb != 0);
+
+ cbnode = cy_as_create_func_c_b_node(cb, client);
+ if (cbnode == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ req_p = cy_as_ll_create_request(dev_p, 0,
+ CY_RQT_USB_RQT_CONTEXT, 2);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ cy_as_ll_init_request(req_p, CY_RQT_ACK_SETUP_PACKET,
+ CY_RQT_USB_RQT_CONTEXT, 1);
+ cy_as_ll_init_response(reply_p, 1);
+
+ req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
+
+ cy_as_insert_c_b_node(dev_p->func_cbs_usb, cbnode);
+
+ ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
+ cy_false, cy_as_usb_ack_callback);
+
+ return ret;
+}
+
+/*
+ * Flush all data in logical EP that is being NAK-ed or
+ * Stall-ed, so that this does not continue to block data
+ * on other LEPs that use the same physical EP.
+ */
+static void
+cy_as_usb_flush_logical_e_p(
+ cy_as_device *dev_p,
+ uint16_t ep)
+{
+ uint16_t addr, val, count;
+
+ addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
+ val = cy_as_hal_read_register(dev_p->tag, addr);
+
+ while (val) {
+ count = ((val & 0xFFF) + 1) / 2;
+ while (count--)
+ val = cy_as_hal_read_register(dev_p->tag, ep);
+
+ cy_as_hal_write_register(dev_p->tag, addr, 0);
+ val = cy_as_hal_read_register(dev_p->tag, addr);
+ }
+}
+
+static cy_as_return_status_t
+cy_as_usb_nak_stall_request(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep,
+ uint16_t request,
+ cy_bool state,
+ cy_as_usb_function_callback cb,
+ cy_as_function_callback fcb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+ uint16_t data;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ if (cb)
+ cy_as_hal_assert(fcb == 0);
+ if (fcb)
+ cy_as_hal_assert(cb == 0);
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p) && cb == 0 && fcb == 0)
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ req_p = cy_as_ll_create_request(dev_p,
+ request, CY_RQT_USB_RQT_CONTEXT, 2);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* A single status word response type */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* Set the endpoint */
+ data = (uint8_t)ep;
+ cy_as_ll_request_response__set_word(req_p, 0, data);
+
+ /* Set stall state to stalled */
+ cy_as_ll_request_response__set_word(req_p, 1, (uint8_t)state);
+
+ if (cb || fcb) {
+ void *cbnode;
+ cy_as_c_b_queue *queue;
+ if (cb) {
+ cbnode = cy_as_create_usb_func_c_b_node(cb, client);
+ queue = dev_p->usb_func_cbs;
+ } else {
+ cbnode = cy_as_create_func_c_b_node(fcb, client);
+ queue = dev_p->func_cbs_usb;
+ req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
+ }
+
+ if (cbnode == 0) {
+ ret = CY_AS_ERROR_OUT_OF_MEMORY;
+ goto destroy;
+ } else
+ cy_as_insert_c_b_node(queue, cbnode);
+
+
+ if (cy_as_device_is_setup_packet(dev_p)) {
+ /* No Ack is needed on a stall request on EP0 */
+ if ((state == cy_true) && (ep == 0)) {
+ cy_as_device_set_ep0_stalled(dev_p);
+ } else {
+ cy_as_device_set_ack_delayed(dev_p);
+ req_p->flags |=
+ CY_AS_REQUEST_RESPONSE_DELAY_ACK;
+ }
+ }
+
+ ret = cy_as_ll_send_request(dev_p, req_p,
+ reply_p, cy_false, cy_as_usb_func_callback);
+ if (ret != CY_AS_ERROR_SUCCESS) {
+ if (req_p->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
+ cy_as_device_rem_ack_delayed(dev_p);
+ cy_as_remove_c_b_tail_node(queue);
+
+ goto destroy;
+ }
+ } else {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) !=
+ CY_RESP_SUCCESS_FAILURE) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+
+ if ((ret == CY_AS_ERROR_SUCCESS) &&
+ (request == CY_RQT_STALL_ENDPOINT)) {
+ if ((ep > 1) && (state != 0) &&
+ (dev_p->usb_config[ep].dir == cy_as_usb_out))
+ cy_as_usb_flush_logical_e_p(dev_p, ep);
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+ }
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_get_stall(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_bool *state_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t code = cy_as_ll_request_response__get_code(reply_p);
+
+ if (code == CY_RESP_SUCCESS_FAILURE) {
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ goto destroy;
+ } else if (code != CY_RESP_ENDPOINT_STALL) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
+ ret = CY_AS_ERROR_SUCCESS;
+
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+my_handle_response_get_nak(cy_as_device *dev_p,
+ cy_as_ll_request_response *req_p,
+ cy_as_ll_request_response *reply_p,
+ cy_bool *state_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint8_t code = cy_as_ll_request_response__get_code(reply_p);
+
+ if (code == CY_RESP_SUCCESS_FAILURE) {
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ goto destroy;
+ } else if (code != CY_RESP_ENDPOINT_NAK) {
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ goto destroy;
+ }
+
+ *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
+ ret = CY_AS_ERROR_SUCCESS;
+
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static cy_as_return_status_t
+cy_as_usb_get_nak_stall(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep,
+ uint16_t request,
+ uint16_t response,
+ cy_bool *state_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+ uint16_t data;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+
+ (void)response;
+
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p) && !cb)
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ req_p = cy_as_ll_create_request(dev_p, request,
+ CY_RQT_USB_RQT_CONTEXT, 1);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* Set the endpoint */
+ data = (uint8_t)ep;
+ cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)ep);
+
+ /* A single status word response type */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p,
+ req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (request == CY_RQT_GET_STALL)
+ return my_handle_response_get_stall(dev_p,
+ req_p, reply_p, state_p);
+ else
+ return my_handle_response_get_nak(dev_p,
+ req_p, reply_p, state_p);
+
+ } else {
+ cy_as_funct_c_b_type type;
+
+ if (request == CY_RQT_GET_STALL)
+ type = CY_FUNCT_CB_USB_GETSTALL;
+ else
+ type = CY_FUNCT_CB_USB_GETNAK;
+
+ ret = cy_as_misc_send_request(dev_p, cb, client, type,
+ state_p, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_usb_set_nak(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ /*
+ * we send the firmware the EP# with the appropriate direction
+ * bit, regardless of what the user gave us.
+ */
+ ep &= 0x0f;
+ if (dev_p->usb_config[ep].dir == cy_as_usb_in)
+ ep |= 0x80;
+
+ if (dev_p->mtp_count > 0)
+ return CY_AS_ERROR_NOT_VALID_IN_MTP;
+
+ return cy_as_usb_nak_stall_request(handle, ep,
+ CY_RQT_ENDPOINT_SET_NAK, cy_true, 0, cb, client);
+}
+
+
+cy_as_return_status_t
+cy_as_usb_clear_nak(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ /*
+ * we send the firmware the EP# with the appropriate
+ * direction bit, regardless of what the user gave us.
+ */
+ ep &= 0x0f;
+ if (dev_p->usb_config[ep].dir == cy_as_usb_in)
+ ep |= 0x80;
+
+ if (dev_p->mtp_count > 0)
+ return CY_AS_ERROR_NOT_VALID_IN_MTP;
+
+ return cy_as_usb_nak_stall_request(handle, ep,
+ CY_RQT_ENDPOINT_SET_NAK, cy_false, 0, cb, client);
+}
+
+cy_as_return_status_t
+cy_as_usb_get_nak(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep,
+ cy_bool *nak_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ /*
+ * we send the firmware the EP# with the appropriate
+ * direction bit, regardless of what the user gave us.
+ */
+ ep &= 0x0f;
+ if (dev_p->usb_config[ep].dir == cy_as_usb_in)
+ ep |= 0x80;
+
+ if (dev_p->mtp_count > 0)
+ return CY_AS_ERROR_NOT_VALID_IN_MTP;
+
+ return cy_as_usb_get_nak_stall(handle, ep,
+ CY_RQT_GET_ENDPOINT_NAK, CY_RESP_ENDPOINT_NAK,
+ nak_p, cb, client);
+}
+
+
+cy_as_return_status_t
+cy_as_usb_set_stall(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ /*
+ * we send the firmware the EP# with the appropriate
+ * direction bit, regardless of what the user gave us.
+ */
+ ep &= 0x0f;
+ if (dev_p->usb_config[ep].dir == cy_as_usb_in)
+ ep |= 0x80;
+
+ if (dev_p->mtp_turbo_active)
+ return CY_AS_ERROR_NOT_VALID_DURING_MTP;
+
+ return cy_as_usb_nak_stall_request(handle, ep,
+ CY_RQT_STALL_ENDPOINT, cy_true, 0, cb, client);
+}
+
+cy_as_return_status_t
+cy_as_usb_clear_stall(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ /*
+ * we send the firmware the EP# with the appropriate
+ * direction bit, regardless of what the user gave us.
+ */
+ ep &= 0x0f;
+ if (dev_p->usb_config[ep].dir == cy_as_usb_in)
+ ep |= 0x80;
+
+ if (dev_p->mtp_turbo_active)
+ return CY_AS_ERROR_NOT_VALID_DURING_MTP;
+
+ return cy_as_usb_nak_stall_request(handle, ep,
+ CY_RQT_STALL_ENDPOINT, cy_false, 0, cb, client);
+}
+
+cy_as_return_status_t
+cy_as_usb_get_stall(cy_as_device_handle handle,
+ cy_as_end_point_number_t ep,
+ cy_bool *stall_p,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ /*
+ * we send the firmware the EP# with the appropriate
+ * direction bit, regardless of what the user gave us.
+ */
+ ep &= 0x0f;
+ if (dev_p->usb_config[ep].dir == cy_as_usb_in)
+ ep |= 0x80;
+
+ if (dev_p->mtp_turbo_active)
+ return CY_AS_ERROR_NOT_VALID_DURING_MTP;
+
+ return cy_as_usb_get_nak_stall(handle, ep,
+ CY_RQT_GET_STALL, CY_RESP_ENDPOINT_STALL, stall_p, cb, client);
+}
+
+cy_as_return_status_t
+cy_as_usb_signal_remote_wakeup(cy_as_device_handle handle,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if (cy_as_device_is_in_callback(dev_p))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ if (dev_p->usb_last_event != cy_as_event_usb_suspend)
+ return CY_AS_ERROR_NOT_IN_SUSPEND;
+
+ req_p = cy_as_ll_create_request(dev_p,
+ CY_RQT_USB_REMOTE_WAKEUP, CY_RQT_USB_RQT_CONTEXT, 0);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* A single status word response type */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_SUCCESS_FAILURE)
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ else
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_SIGNALREMOTEWAKEUP, 0,
+ dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p,
+ reply_p, cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_usb_set_m_s_report_threshold(cy_as_device_handle handle,
+ uint32_t wr_sectors,
+ uint32_t rd_sectors,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ /* Check if the firmware version supports this feature. */
+ if ((dev_p->media_supported[0]) && (dev_p->media_supported[0] ==
+ (1 << cy_as_media_nand)))
+ return CY_AS_ERROR_NOT_SUPPORTED;
+
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_USB_STORAGE_MONITOR,
+ CY_RQT_USB_RQT_CONTEXT, 4);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* A single status word response type */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* Set the read and write count parameters into
+ * the request structure. */
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)((wr_sectors >> 16) & 0xFFFF));
+ cy_as_ll_request_response__set_word(req_p, 1,
+ (uint16_t)(wr_sectors & 0xFFFF));
+ cy_as_ll_request_response__set_word(req_p, 2,
+ (uint16_t)((rd_sectors >> 16) & 0xFFFF));
+ cy_as_ll_request_response__set_word(req_p, 3,
+ (uint16_t)(rd_sectors & 0xFFFF));
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_SUCCESS_FAILURE)
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ else
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_USB_SET_MSREPORT_THRESHOLD, 0,
+ dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
+ req_p, reply_p, cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_usb_select_m_s_partitions(
+ cy_as_device_handle handle,
+ cy_as_bus_number_t bus,
+ uint32_t device,
+ cy_as_usb_m_s_type_t type,
+ cy_as_function_callback cb,
+ uint32_t client)
+{
+ cy_as_return_status_t ret;
+ cy_as_ll_request_response *req_p , *reply_p;
+ uint16_t val;
+
+ cy_as_device *dev_p = (cy_as_device *)handle;
+ if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
+ return CY_AS_ERROR_INVALID_HANDLE;
+
+ ret = is_usb_active(dev_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /* This API has to be made before SetEnumConfig is called. */
+ if (dev_p->usb_config[0].enabled)
+ return CY_AS_ERROR_INVALID_CALL_SEQUENCE;
+
+ if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
+ return CY_AS_ERROR_INVALID_IN_CALLBACK;
+
+ req_p = cy_as_ll_create_request(dev_p, CY_RQT_MS_PARTITION_SELECT,
+ CY_RQT_USB_RQT_CONTEXT, 2);
+ if (req_p == 0)
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+
+ /* A single status word response type */
+ reply_p = cy_as_ll_create_response(dev_p, 1);
+ if (reply_p == 0) {
+ cy_as_ll_destroy_request(dev_p, req_p);
+ return CY_AS_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* Set the read and write count parameters into
+ * the request structure. */
+ cy_as_ll_request_response__set_word(req_p, 0,
+ (uint16_t)((bus << 8) | device));
+
+ val = 0;
+ if ((type == cy_as_usb_m_s_unit0) || (type == cy_as_usb_m_s_both))
+ val |= 1;
+ if ((type == cy_as_usb_m_s_unit1) || (type == cy_as_usb_m_s_both))
+ val |= (1 << 8);
+
+ cy_as_ll_request_response__set_word(req_p, 1, val);
+
+ if (cb == 0) {
+ ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+
+ if (cy_as_ll_request_response__get_code(reply_p) ==
+ CY_RESP_SUCCESS_FAILURE)
+ ret = cy_as_ll_request_response__get_word(reply_p, 0);
+ else
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ } else {
+ ret = cy_as_misc_send_request(dev_p, cb, client,
+ CY_FUNCT_CB_NODATA, 0, dev_p->func_cbs_usb,
+ CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
+ cy_as_usb_func_callback);
+
+ if (ret != CY_AS_ERROR_SUCCESS)
+ goto destroy;
+ return ret;
+ }
+
+destroy:
+ cy_as_ll_destroy_request(dev_p, req_p);
+ cy_as_ll_destroy_response(dev_p, reply_p);
+
+ return ret;
+}
+
+static void
+cy_as_usb_func_callback(
+ cy_as_device *dev_p,
+ uint8_t context,
+ cy_as_ll_request_response *rqt,
+ cy_as_ll_request_response *resp,
+ cy_as_return_status_t stat)
+{
+ cy_as_usb_func_c_b_node* node = (cy_as_usb_func_c_b_node *)
+ dev_p->usb_func_cbs->head_p;
+ cy_as_func_c_b_node* fnode = (cy_as_func_c_b_node *)
+ dev_p->func_cbs_usb->head_p;
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+
+ cy_as_device_handle h = (cy_as_device_handle)dev_p;
+ cy_bool delayed_ack = (rqt->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
+ == CY_AS_REQUEST_RESPONSE_DELAY_ACK;
+ cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX)
+ == CY_AS_REQUEST_RESPONSE_EX;
+ cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS)
+ == CY_AS_REQUEST_RESPONSE_MS;
+ uint8_t code;
+ uint8_t ep, state;
+
+ if (!ex_request && !ms_request) {
+ cy_as_hal_assert(dev_p->usb_func_cbs->count != 0);
+ cy_as_hal_assert(dev_p->usb_func_cbs->type ==
+ CYAS_USB_FUNC_CB);
+ } else {
+ cy_as_hal_assert(dev_p->func_cbs_usb->count != 0);
+ cy_as_hal_assert(dev_p->func_cbs_usb->type == CYAS_FUNC_CB);
+ }
+
+ (void)context;
+
+ /* The Handlers are responsible for Deleting the rqt and resp when
+ * they are finished
+ */
+ code = cy_as_ll_request_response__get_code(rqt);
+ switch (code) {
+ case CY_RQT_START_USB:
+ ret = my_handle_response_usb_start(dev_p, rqt, resp, stat);
+ break;
+ case CY_RQT_STOP_USB:
+ ret = my_handle_response_usb_stop(dev_p, rqt, resp, stat);
+ break;
+ case CY_RQT_SET_CONNECT_STATE:
+ if (!cy_as_ll_request_response__get_word(rqt, 0))
+ ret = my_handle_response_disconnect(
+ dev_p, rqt, resp, stat);
+ else
+ ret = my_handle_response_connect(
+ dev_p, rqt, resp, stat);
+ break;
+ case CY_RQT_GET_CONNECT_STATE:
+ break;
+ case CY_RQT_SET_USB_CONFIG:
+ ret = my_handle_response_set_enum_config(dev_p, rqt, resp);
+ break;
+ case CY_RQT_GET_USB_CONFIG:
+ cy_as_hal_assert(fnode->data != 0);
+ ret = my_handle_response_get_enum_config(dev_p,
+ rqt, resp, fnode->data);
+ break;
+ case CY_RQT_STALL_ENDPOINT:
+ ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
+ state = (uint8_t)cy_as_ll_request_response__get_word(rqt, 1);
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ if ((ret == CY_AS_ERROR_SUCCESS) && (ep > 1) && (state != 0)
+ && (dev_p->usb_config[ep].dir == cy_as_usb_out))
+ cy_as_usb_flush_logical_e_p(dev_p, ep);
+ break;
+ case CY_RQT_GET_STALL:
+ cy_as_hal_assert(fnode->data != 0);
+ ret = my_handle_response_get_stall(dev_p,
+ rqt, resp, (cy_bool *)fnode->data);
+ break;
+ case CY_RQT_SET_DESCRIPTOR:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_GET_DESCRIPTOR:
+ cy_as_hal_assert(fnode->data != 0);
+ ret = my_handle_response_get_descriptor(dev_p,
+ rqt, resp, (cy_as_get_descriptor_data *)fnode->data);
+ break;
+ case CY_RQT_SET_USB_CONFIG_REGISTERS:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ if (ret == CY_AS_ERROR_SUCCESS)
+ ret = cy_as_usb_setup_dma(dev_p);
+ break;
+ case CY_RQT_ENDPOINT_SET_NAK:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_GET_ENDPOINT_NAK:
+ cy_as_hal_assert(fnode->data != 0);
+ ret = my_handle_response_get_nak(dev_p,
+ rqt, resp, (cy_bool *)fnode->data);
+ break;
+ case CY_RQT_ACK_SETUP_PACKET:
+ break;
+ case CY_RQT_USB_REMOTE_WAKEUP:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_CLEAR_DESCRIPTORS:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_USB_STORAGE_MONITOR:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ case CY_RQT_MS_PARTITION_SELECT:
+ ret = my_handle_response_no_data(dev_p, rqt, resp);
+ break;
+ default:
+ ret = CY_AS_ERROR_INVALID_RESPONSE;
+ cy_as_hal_assert(cy_false);
+ 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 (ex_request || ms_request) {
+ fnode->cb_p((cy_as_device_handle)dev_p, stat,
+ fnode->client_data, fnode->data_type, fnode->data);
+ cy_as_remove_c_b_node(dev_p->func_cbs_usb);
+ } else {
+ node->cb_p((cy_as_device_handle)dev_p, stat,
+ node->client_data);
+ cy_as_remove_c_b_node(dev_p->usb_func_cbs);
+ }
+
+ if (delayed_ack) {
+ cy_as_hal_assert(cy_as_device_is_ack_delayed(dev_p));
+ cy_as_device_rem_ack_delayed(dev_p);
+
+ /*
+ * send the ACK if required.
+ */
+ if (!cy_as_device_is_ack_delayed(dev_p))
+ cy_as_usb_ack_setup_packet(h,
+ usb_ack_callback, 0);
+ }
+}
+
+
+/*[]*/