From 81eb669b9516b85a2acf4c342db2322bed37d70c Mon Sep 17 00:00:00 2001 From: David Cross Date: Fri, 6 Aug 2010 17:29:03 -0700 Subject: Staging: add West Bridge Astoria Driver This is a driver for the Cypress West Bridge companion chip. Its function is analogous to the North/South Bridges of PC environments applied to embedded devices, in that it expands I/O and storage capabilities of an embedded processor. The Astoria version, which this driver applies to, functions as a USB, embedded memory and SDIO controller. The kernel that this patch was applied to is linux-2.6.35, although it was tested using the android kernel 2.6.29 running on the Zoom 2 platform. In this system, it was used primarily as a sideloading accelerator enabling direct data transfers between a USB host PC and embedded memory without system overheads. Minor modifications were also made to the kernel for this patch. These include changes such as EXPORTing of fat_get_block in the kernel code. Another function, mpage_cleardirty was also added to the memory management code. This function is used to clear the dirty pages from a specific inode. This allows for direct, file based DMA. None of these changes are believed to have any negative impact on the kernel and may provide additional benefit for other developers and drivers. The driver, as submitted, was placed into the drivers/staging/westbridge folder as the directory structure it will eventually reside in is not yet defined. The driver, as placed in staging is divided into four parts: 1) gadget - this implements a gadget peripheral controller and includes IOCTLs for MTP transfers 2) block -this implements a generic block device driver to enable access to embedded memory 3) api -this is the Cypress SDK, and includes USB and Storage specific functions. In addition, it includes common code for low level routines such as message passing and common data transfer routines 4) hal - this should likely be included in the arch directory as it needs to be modified for a given platform. The directory structure in the staging area is meant to reflect the eventual location of where this code likely should be. It is platform specific. In this case, the HAL included is for the Android Zoom 2 platform. Here, West Bridge is connected to the GPMC (general purpose memory controller) of the OMAP3. Specific timing needs to be enabled to ensure reliable communication. Many thanks to Greg KH for conducting initial reviews and providing pointers. Please contact david.cross@cypress.com for questions, concerns or feedback. Signed-off-by: David Cross Signed-off-by: Greg Kroah-Hartman --- .../westbridge/astoria/api/src/cyasstorage.c | 4104 ++++++++++++++++++++ 1 file changed, 4104 insertions(+) create mode 100644 drivers/staging/westbridge/astoria/api/src/cyasstorage.c (limited to 'drivers/staging/westbridge/astoria/api/src/cyasstorage.c') 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 00000000000..c7c3cda261d --- /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<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; +} + + +/*[]*/ -- cgit v1.2.3