diff options
Diffstat (limited to 'drivers/staging/westbridge/astoria/api/src/cyasstorage.c')
-rw-r--r-- | drivers/staging/westbridge/astoria/api/src/cyasstorage.c | 4104 |
1 files changed, 4104 insertions, 0 deletions
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 0000000..083d869 --- /dev/null +++ b/drivers/staging/westbridge/astoria/api/src/cyasstorage.c @@ -0,0 +1,4104 @@ +/* Cypress West Bridge API source file (cyasstorage.c) +## =========================== +## Copyright (C) 2010 Cypress Semiconductor +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor +## Boston, MA 02110-1301, USA. +## =========================== +*/ + +/* +* Storage Design +* +* The storage module is fairly straight forward once the +* DMA and LOWLEVEL modules have been designed. The +* storage module simple takes requests from the user, queues +* the associated DMA requests for action, and then sends +* the low level requests to the West Bridge firmware. +* +*/ + +#include "../../include/linux/westbridge/cyashal.h" +#include "../../include/linux/westbridge/cyasstorage.h" +#include "../../include/linux/westbridge/cyaserr.h" +#include "../../include/linux/westbridge/cyasdevice.h" +#include "../../include/linux/westbridge/cyaslowlevel.h" +#include "../../include/linux/westbridge/cyasdma.h" +#include "../../include/linux/westbridge/cyasregs.h" + +/* Map a pre-V1.2 media type to the V1.2+ bus number */ +cy_as_return_status_t +cy_an_map_bus_from_media_type(cy_as_device *dev_p, + cy_as_media_type type, cy_as_bus_number_t *bus) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t code = (uint8_t)(1 << type); + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + if (!cy_as_device_is_configured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED; + + if (!cy_as_device_is_firmware_loaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE; + + + if (dev_p->media_supported[0] & code) { + if (dev_p->media_supported[1] & code) { + /* + * this media type could be supported on multiple + * buses. so, report an address resolution error. + */ + ret = CY_AS_ERROR_ADDRESS_RESOLUTION_ERROR; + } else + *bus = 0; + } else { + if (dev_p->media_supported[1] & code) + *bus = 1; + else + ret = CY_AS_ERROR_NO_SUCH_MEDIA; + } + + return ret; +} + +static uint16_t +create_address(cy_as_bus_number_t bus, uint32_t device, uint8_t unit) +{ + cy_as_hal_assert(bus >= 0 && bus < CY_AS_MAX_BUSES); + cy_as_hal_assert(device < 16); + + return (uint16_t)(((uint8_t)bus << 12) | (device << 8) | unit); +} + +cy_as_media_type +cy_as_storage_get_media_from_address(uint16_t v) +{ + cy_as_media_type media = cy_as_media_max_media_value; + + switch (v & 0xFF) { + case 0x00: + break; + case 0x01: + media = cy_as_media_nand; + break; + case 0x02: + media = cy_as_media_sd_flash; + break; + case 0x04: + media = cy_as_media_mmc_flash; + break; + case 0x08: + media = cy_as_media_ce_ata; + break; + case 0x10: + media = cy_as_media_sdio; + break; + default: + cy_as_hal_assert(0); + break; + } + + return media; +} + +cy_as_bus_number_t +cy_as_storage_get_bus_from_address(uint16_t v) +{ + cy_as_bus_number_t bus = (cy_as_bus_number_t)((v >> 12) & 0x0f); + cy_as_hal_assert(bus >= 0 && bus < CY_AS_MAX_BUSES); + return bus; +} + +uint32_t +cy_as_storage_get_device_from_address(uint16_t v) +{ + return (uint32_t)((v >> 8) & 0x0f); +} + +static uint8_t +get_unit_from_address(uint16_t v) +{ + return (uint8_t)(v & 0xff); +} + +static cy_as_return_status_t +cy_as_map_bad_addr(uint16_t val) +{ + cy_as_return_status_t ret = CY_AS_ERROR_INVALID_RESPONSE; + + switch (val) { + case 0: + ret = CY_AS_ERROR_NO_SUCH_BUS; + break; + case 1: + ret = CY_AS_ERROR_NO_SUCH_DEVICE; + break; + case 2: + ret = CY_AS_ERROR_NO_SUCH_UNIT; + break; + case 3: + ret = CY_AS_ERROR_INVALID_BLOCK; + break; + } + + return ret; +} + +static void +my_storage_request_callback(cy_as_device *dev_p, + uint8_t context, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *resp_p, + cy_as_return_status_t ret) +{ + uint16_t val; + uint16_t addr; + cy_as_bus_number_t bus; + uint32_t device; + cy_as_device_handle h = (cy_as_device_handle)dev_p; + cy_as_dma_end_point *ep_p = NULL; + + (void)resp_p; + (void)context; + (void)ret; + + switch (cy_as_ll_request_response__get_code(req_p)) { + case CY_RQT_MEDIA_CHANGED: + cy_as_ll_send_status_response(dev_p, + CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0); + + /* Media has either been inserted or removed */ + addr = cy_as_ll_request_response__get_word(req_p, 0); + + bus = cy_as_storage_get_bus_from_address(addr); + device = cy_as_storage_get_device_from_address(addr); + + /* Clear the entry for this device to force re-query later */ + cy_as_hal_mem_set(&(dev_p->storage_device_info[bus][device]), 0, + sizeof(dev_p->storage_device_info[bus][device])); + + val = cy_as_ll_request_response__get_word(req_p, 1); + if (dev_p->storage_event_cb_ms) { + if (val == 1) + dev_p->storage_event_cb_ms(h, bus, + device, cy_as_storage_removed, 0); + else + dev_p->storage_event_cb_ms(h, bus, + device, cy_as_storage_inserted, 0); + } else if (dev_p->storage_event_cb) { + if (val == 1) + dev_p->storage_event_cb(h, bus, + cy_as_storage_removed, 0); + else + dev_p->storage_event_cb(h, bus, + cy_as_storage_inserted, 0); + } + + break; + + case CY_RQT_ANTIOCH_CLAIM: + cy_as_ll_send_status_response(dev_p, + CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0); + if (dev_p->storage_event_cb || dev_p->storage_event_cb_ms) { + val = cy_as_ll_request_response__get_word(req_p, 0); + if (dev_p->storage_event_cb_ms) { + if (val & 0x0100) + dev_p->storage_event_cb_ms(h, 0, 0, + cy_as_storage_antioch, 0); + if (val & 0x0200) + dev_p->storage_event_cb_ms(h, 1, 0, + cy_as_storage_antioch, 0); + } else { + if (val & 0x01) + dev_p->storage_event_cb(h, + cy_as_media_nand, + cy_as_storage_antioch, 0); + if (val & 0x02) + dev_p->storage_event_cb(h, + cy_as_media_sd_flash, + cy_as_storage_antioch, 0); + if (val & 0x04) + dev_p->storage_event_cb(h, + cy_as_media_mmc_flash, + cy_as_storage_antioch, 0); + if (val & 0x08) + dev_p->storage_event_cb(h, + cy_as_media_ce_ata, + cy_as_storage_antioch, 0); + } + } + break; + + case CY_RQT_ANTIOCH_RELEASE: + cy_as_ll_send_status_response(dev_p, + CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0); + val = cy_as_ll_request_response__get_word(req_p, 0); + if (dev_p->storage_event_cb_ms) { + if (val & 0x0100) + dev_p->storage_event_cb_ms(h, 0, 0, + cy_as_storage_processor, 0); + if (val & 0x0200) + dev_p->storage_event_cb_ms(h, 1, 0, + cy_as_storage_processor, 0); + } else if (dev_p->storage_event_cb) { + if (val & 0x01) + dev_p->storage_event_cb(h, + cy_as_media_nand, + cy_as_storage_processor, 0); + if (val & 0x02) + dev_p->storage_event_cb(h, + cy_as_media_sd_flash, + cy_as_storage_processor, 0); + if (val & 0x04) + dev_p->storage_event_cb(h, + cy_as_media_mmc_flash, + cy_as_storage_processor, 0); + if (val & 0x08) + dev_p->storage_event_cb(h, + cy_as_media_ce_ata, + cy_as_storage_processor, 0); + } + break; + + + case CY_RQT_SDIO_INTR: + cy_as_ll_send_status_response(dev_p, + CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0); + val = cy_as_ll_request_response__get_word(req_p, 0); + if (dev_p->storage_event_cb_ms) { + if (val & 0x0100) + dev_p->storage_event_cb_ms(h, 1, 0, + cy_as_sdio_interrupt, 0); + else + dev_p->storage_event_cb_ms(h, 0, 0, + cy_as_sdio_interrupt, 0); + + } else if (dev_p->storage_event_cb) { + dev_p->storage_event_cb(h, + cy_as_media_sdio, cy_as_sdio_interrupt, 0); + } + break; + + case CY_RQT_P2S_DMA_START: + /* Do the DMA setup for the waiting operation. */ + cy_as_ll_send_status_response(dev_p, + CY_RQT_STORAGE_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0); + cy_as_device_set_p2s_dma_start_recvd(dev_p); + if (dev_p->storage_oper == cy_as_op_read) { + ep_p = CY_AS_NUM_EP(dev_p, CY_AS_P2S_READ_ENDPOINT); + cy_as_dma_end_point_set_stopped(ep_p); + cy_as_dma_kick_start(dev_p, CY_AS_P2S_READ_ENDPOINT); + } else { + ep_p = CY_AS_NUM_EP(dev_p, CY_AS_P2S_WRITE_ENDPOINT); + cy_as_dma_end_point_set_stopped(ep_p); + cy_as_dma_kick_start(dev_p, CY_AS_P2S_WRITE_ENDPOINT); + } + break; + + default: + cy_as_hal_print_message("invalid request received " + "on storage context\n"); + val = req_p->box0; + cy_as_ll_send_data_response(dev_p, CY_RQT_STORAGE_RQT_CONTEXT, + CY_RESP_INVALID_REQUEST, sizeof(val), &val); + break; + } +} + +static cy_as_return_status_t +is_storage_active(cy_as_device *dev_p) +{ + if (!cy_as_device_is_configured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED; + + if (!cy_as_device_is_firmware_loaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE; + + if (dev_p->storage_count == 0) + return CY_AS_ERROR_NOT_RUNNING; + + if (cy_as_device_is_in_suspend_mode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND; + + return CY_AS_ERROR_SUCCESS; +} + +static void +cy_as_storage_func_callback(cy_as_device *dev_p, + uint8_t context, + cy_as_ll_request_response *rqt, + cy_as_ll_request_response *resp, + cy_as_return_status_t ret); + +static cy_as_return_status_t +my_handle_response_no_data(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_SUCCESS_FAILURE) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + ret = cy_as_ll_request_response__get_word(reply_p, 0); + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +static cy_as_return_status_t +my_handle_response_storage_start(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p, + cy_as_return_status_t ret) +{ + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_SUCCESS_FAILURE) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + ret = cy_as_ll_request_response__get_word(reply_p, 0); + if (dev_p->storage_count > 0 && ret == + CY_AS_ERROR_ALREADY_RUNNING) + ret = CY_AS_ERROR_SUCCESS; + + ret = cy_as_dma_enable_end_point(dev_p, + CY_AS_P2S_WRITE_ENDPOINT, cy_true, cy_as_direction_in); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + ret = cy_as_dma_set_max_dma_size(dev_p, + CY_AS_P2S_WRITE_ENDPOINT, CY_AS_STORAGE_EP_SIZE); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + ret = cy_as_dma_enable_end_point(dev_p, + CY_AS_P2S_READ_ENDPOINT, cy_true, cy_as_direction_out); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + ret = cy_as_dma_set_max_dma_size(dev_p, + CY_AS_P2S_READ_ENDPOINT, CY_AS_STORAGE_EP_SIZE); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + cy_as_ll_register_request_callback(dev_p, + CY_RQT_STORAGE_RQT_CONTEXT, my_storage_request_callback); + + /* Create the request/response used for storage reads and writes. */ + dev_p->storage_rw_req_p = cy_as_ll_create_request(dev_p, + 0, CY_RQT_STORAGE_RQT_CONTEXT, 5); + if (dev_p->storage_rw_req_p == 0) { + ret = CY_AS_ERROR_OUT_OF_MEMORY; + goto destroy; + } + + dev_p->storage_rw_resp_p = cy_as_ll_create_response(dev_p, 5); + if (dev_p->storage_rw_resp_p == 0) { + cy_as_ll_destroy_request(dev_p, dev_p->storage_rw_req_p); + ret = CY_AS_ERROR_OUT_OF_MEMORY; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + /* Increment the storage count only if + * the above functionality succeeds.*/ + if (ret == CY_AS_ERROR_SUCCESS) { + if (dev_p->storage_count == 0) { + cy_as_hal_mem_set(dev_p->storage_device_info, + 0, sizeof(dev_p->storage_device_info)); + dev_p->is_storage_only_mode = cy_false; + } + + dev_p->storage_count++; + } + + cy_as_device_clear_s_s_s_pending(dev_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_start(cy_as_device_handle handle, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p, *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + if (!cy_as_device_is_configured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED; + + if (!cy_as_device_is_firmware_loaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE; + + if (cy_as_device_is_in_suspend_mode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND; + + if (cy_as_device_is_s_s_s_pending(dev_p)) + return CY_AS_ERROR_STARTSTOP_PENDING; + + cy_as_device_set_s_s_s_pending(dev_p); + + if (dev_p->storage_count == 0) { + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_START_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) { + cy_as_device_clear_s_s_s_pending(dev_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + /* Reserve space for the reply, the reply data + * will not exceed one word */ + reply_p = cy_as_ll_create_response(dev_p, 1); + if (reply_p == 0) { + cy_as_device_clear_s_s_s_pending(dev_p); + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, + req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + return my_handle_response_storage_start(dev_p, + req_p, reply_p, ret); + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_START, 0, dev_p->func_cbs_stor, + CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as + * part of the FuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + } else { + dev_p->storage_count++; + if (cb) + cb(handle, ret, client, CY_FUNCT_CB_STOR_START, 0); + } + + cy_as_device_clear_s_s_s_pending(dev_p); + + return ret; +} + + +static cy_as_return_status_t +my_handle_response_storage_stop(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p, + cy_as_return_status_t ret) +{ + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_SUCCESS_FAILURE) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + if (ret == CY_AS_ERROR_SUCCESS) { + cy_as_ll_destroy_request(dev_p, dev_p->storage_rw_req_p); + cy_as_ll_destroy_response(dev_p, dev_p->storage_rw_resp_p); + dev_p->storage_count--; + } + + cy_as_device_clear_s_s_s_pending(dev_p); + + return ret; +} +cy_as_return_status_t +cy_as_storage_stop(cy_as_device_handle handle, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (cy_as_device_is_storage_async_pending(dev_p)) + return CY_AS_ERROR_ASYNC_PENDING; + + if (cy_as_device_is_s_s_s_pending(dev_p)) + return CY_AS_ERROR_STARTSTOP_PENDING; + + cy_as_device_set_s_s_s_pending(dev_p); + + if (dev_p->storage_count == 1) { + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_STOP_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 0); + if (req_p == 0) { + cy_as_device_clear_s_s_s_pending(dev_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + /* Reserve space for the reply, the reply data + * will not exceed one word */ + reply_p = cy_as_ll_create_response(dev_p, 1); + if (reply_p == 0) { + cy_as_device_clear_s_s_s_pending(dev_p); + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, + req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + return my_handle_response_storage_stop(dev_p, + req_p, reply_p, ret); + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_STOP, 0, dev_p->func_cbs_stor, + CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed + * as part of the MiscFuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + } else if (dev_p->storage_count > 1) { + dev_p->storage_count--; + if (cb) + cb(handle, ret, client, CY_FUNCT_CB_STOR_STOP, 0); + } + + cy_as_device_clear_s_s_s_pending(dev_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_register_callback(cy_as_device_handle handle, + cy_as_storage_event_callback callback) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + if (!cy_as_device_is_configured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED; + + if (!cy_as_device_is_firmware_loaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE; + + if (dev_p->storage_count == 0) + return CY_AS_ERROR_NOT_RUNNING; + + dev_p->storage_event_cb = NULL; + dev_p->storage_event_cb_ms = callback; + + return CY_AS_ERROR_SUCCESS; +} + + + +static cy_as_return_status_t +my_handle_response_storage_claim(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + if (cy_as_ll_request_response__get_code(reply_p) == + CY_RESP_NO_SUCH_ADDRESS) { + ret = cy_as_map_bad_addr( + cy_as_ll_request_response__get_word(reply_p, 3)); + goto destroy; + } + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_MEDIA_CLAIMED_RELEASED) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + /* The response must be about the address I am + * trying to claim or the firmware is broken */ + if ((cy_as_storage_get_bus_from_address( + cy_as_ll_request_response__get_word(req_p, 0)) != + cy_as_storage_get_bus_from_address( + cy_as_ll_request_response__get_word(reply_p, 0))) || + (cy_as_storage_get_device_from_address( + cy_as_ll_request_response__get_word(req_p, 0)) != + cy_as_storage_get_device_from_address( + cy_as_ll_request_response__get_word(reply_p, 0)))) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + if (cy_as_ll_request_response__get_word(reply_p, 1) != 1) + ret = CY_AS_ERROR_NOT_ACQUIRED; + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +static cy_as_return_status_t +my_storage_claim(cy_as_device *dev_p, + void *data, + cy_as_bus_number_t bus, + uint32_t device, + uint16_t req_flags, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (dev_p->mtp_count > 0) + return CY_AS_ERROR_NOT_VALID_IN_MTP; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_CLAIM_STORAGE, CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word(req_p, + 0, create_address(bus, device, 0)); + + /* Reserve space for the reply, the reply data will + * not exceed one word */ + reply_p = cy_as_ll_create_response(dev_p, 4); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + return my_handle_response_storage_claim(dev_p, req_p, reply_p); + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_CLAIM, data, dev_p->func_cbs_stor, + req_flags, req_p, reply_p, + cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as part of + * the MiscFuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_claim(cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS; + + return my_storage_claim(dev_p, NULL, bus, device, + CY_AS_REQUEST_RESPONSE_MS, cb, client); +} + +static cy_as_return_status_t +my_handle_response_storage_release(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + if (cy_as_ll_request_response__get_code(reply_p) == + CY_RESP_NO_SUCH_ADDRESS) { + ret = cy_as_map_bad_addr( + cy_as_ll_request_response__get_word(reply_p, 3)); + goto destroy; + } + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_MEDIA_CLAIMED_RELEASED) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + /* The response must be about the address I am + * trying to release or the firmware is broken */ + if ((cy_as_storage_get_bus_from_address( + cy_as_ll_request_response__get_word(req_p, 0)) != + cy_as_storage_get_bus_from_address( + cy_as_ll_request_response__get_word(reply_p, 0))) || + (cy_as_storage_get_device_from_address( + cy_as_ll_request_response__get_word(req_p, 0)) != + cy_as_storage_get_device_from_address( + cy_as_ll_request_response__get_word(reply_p, 0)))) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + + if (cy_as_ll_request_response__get_word(reply_p, 1) != 0) + ret = CY_AS_ERROR_NOT_RELEASED; + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +static cy_as_return_status_t +my_storage_release(cy_as_device *dev_p, + void *data, + cy_as_bus_number_t bus, + uint32_t device, + uint16_t req_flags, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (dev_p->mtp_count > 0) + return CY_AS_ERROR_NOT_VALID_IN_MTP; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, CY_RQT_RELEASE_STORAGE, + CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word( + req_p, 0, create_address(bus, device, 0)); + + /* Reserve space for the reply, the reply + * data will not exceed one word */ + reply_p = cy_as_ll_create_response(dev_p, 4); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + return my_handle_response_storage_release( + dev_p, req_p, reply_p); + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_RELEASE, data, dev_p->func_cbs_stor, + req_flags, req_p, reply_p, + cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as + * part of the MiscFuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_release(cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS; + + return my_storage_release(dev_p, NULL, bus, device, + CY_AS_REQUEST_RESPONSE_MS, cb, client); +} + +static cy_as_return_status_t +my_handle_response_storage_query_bus(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p, + uint32_t *count) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t code = cy_as_ll_request_response__get_code(reply_p); + uint16_t v; + + if (code == CY_RESP_NO_SUCH_ADDRESS) { + ret = CY_AS_ERROR_NO_SUCH_BUS; + goto destroy; + } + + if (code != CY_RESP_BUS_DESCRIPTOR) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + /* + * verify that the response corresponds to the bus that was queried. + */ + if (cy_as_storage_get_bus_from_address( + cy_as_ll_request_response__get_word(req_p, 0)) != + cy_as_storage_get_bus_from_address( + cy_as_ll_request_response__get_word(reply_p, 0))) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + v = cy_as_ll_request_response__get_word(reply_p, 1); + if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) { + /* + * this request is only for the count of devices + * on the bus. there is no need to check the media type. + */ + if (v) + *count = 1; + else + *count = 0; + } else { + /* + * this request is for the count of devices of a + * particular type. we need to check whether the media + * type found matches the queried type. + */ + cy_as_media_type queried = (cy_as_media_type) + cy_as_ll_request_response__get_word(req_p, 1); + cy_as_media_type found = + cy_as_storage_get_media_from_address(v); + + if (queried == found) + *count = 1; + else + *count = 0; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +my_storage_query_bus(cy_as_device *dev_p, + cy_as_bus_number_t bus, + cy_as_media_type type, + uint16_t req_flags, + uint32_t *count, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_return_status_t ret; + cy_as_ll_request_response *req_p, *reply_p; + cy_as_funct_c_b_type cb_type = CY_FUNCT_CB_STOR_QUERYBUS; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + /* Create the request to send to the Antioch device */ + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_QUERY_BUS, CY_RQT_STORAGE_RQT_CONTEXT, 2); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word(req_p, + 0, create_address(bus, 0, 0)); + cy_as_ll_request_response__set_word(req_p, 1, (uint16_t)type); + + /* Reserve space for the reply, the reply data + * will not exceed two words. */ + reply_p = cy_as_ll_create_response(dev_p, 2); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, + req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + req_p->flags |= req_flags; + return my_handle_response_storage_query_bus(dev_p, + req_p, reply_p, count); + } else { + if (req_flags == CY_AS_REQUEST_RESPONSE_EX) + cb_type = CY_FUNCT_CB_STOR_QUERYMEDIA; + + ret = cy_as_misc_send_request(dev_p, cb, client, cb_type, + count, dev_p->func_cbs_stor, req_flags, + req_p, reply_p, cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as part of + * the MiscFuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_query_bus(cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t *count, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + + return my_storage_query_bus(dev_p, bus, cy_as_media_max_media_value, + CY_AS_REQUEST_RESPONSE_MS, count, cb, client); +} + +cy_as_return_status_t +cy_as_storage_query_media(cy_as_device_handle handle, + cy_as_media_type type, + uint32_t *count, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_bus_number_t bus; + + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + ret = cy_an_map_bus_from_media_type(dev_p, type, &bus); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + return my_storage_query_bus(dev_p, bus, type, CY_AS_REQUEST_RESPONSE_EX, + count, cb, client); +} + +static cy_as_return_status_t +my_handle_response_storage_query_device(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p, + void *data_p) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint16_t v; + cy_as_bus_number_t bus; + cy_as_media_type type; + uint32_t device; + cy_bool removable; + cy_bool writeable; + cy_bool locked; + uint16_t block_size; + uint32_t number_units; + uint32_t number_eus; + + if (cy_as_ll_request_response__get_code(reply_p) + == CY_RESP_NO_SUCH_ADDRESS) { + ret = cy_as_map_bad_addr( + cy_as_ll_request_response__get_word(reply_p, 3)); + goto destroy; + } + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_DEVICE_DESCRIPTOR) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + /* Unpack the response */ + v = cy_as_ll_request_response__get_word(reply_p, 0); + type = cy_as_storage_get_media_from_address(v); + bus = cy_as_storage_get_bus_from_address(v); + device = cy_as_storage_get_device_from_address(v); + + block_size = cy_as_ll_request_response__get_word(reply_p, 1); + + v = cy_as_ll_request_response__get_word(reply_p, 2); + removable = (v & 0x8000) ? cy_true : cy_false; + writeable = (v & 0x0100) ? cy_true : cy_false; + locked = (v & 0x0200) ? cy_true : cy_false; + number_units = (v & 0xff); + + number_eus = (cy_as_ll_request_response__get_word(reply_p, 3) << 16) + | cy_as_ll_request_response__get_word(reply_p, 4); + + /* Store the results based on the version of originating function */ + if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) { + cy_as_storage_query_device_data *store_p = + (cy_as_storage_query_device_data *)data_p; + + /* Make sure the response is about the address we asked + * about - if not, firmware error */ + if ((bus != store_p->bus) || (device != store_p->device)) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + store_p->desc_p.type = type; + store_p->desc_p.removable = removable; + store_p->desc_p.writeable = writeable; + store_p->desc_p.block_size = block_size; + store_p->desc_p.number_units = number_units; + store_p->desc_p.locked = locked; + store_p->desc_p.erase_unit_size = number_eus; + dev_p->storage_device_info[bus][device] = store_p->desc_p; + } else { + cy_as_storage_query_device_data_dep *store_p = + (cy_as_storage_query_device_data_dep *)data_p; + + /* Make sure the response is about the address we asked + * about - if not, firmware error */ + if ((type != store_p->type) || (device != store_p->device)) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + store_p->desc_p.type = type; + store_p->desc_p.removable = removable; + store_p->desc_p.writeable = writeable; + store_p->desc_p.block_size = block_size; + store_p->desc_p.number_units = number_units; + store_p->desc_p.locked = locked; + store_p->desc_p.erase_unit_size = number_eus; + dev_p->storage_device_info[bus][device] = store_p->desc_p; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +static cy_as_return_status_t +my_storage_query_device(cy_as_device *dev_p, + void *data_p, + uint16_t req_flags, + cy_as_bus_number_t bus, + uint32_t device, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + /* Create the request to send to the Antioch device */ + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_QUERY_DEVICE, CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, device, 0)); + + /* Reserve space for the reply, the reply data + * will not exceed five words. */ + reply_p = cy_as_ll_create_response(dev_p, 5); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + req_p->flags |= req_flags; + return my_handle_response_storage_query_device(dev_p, + req_p, reply_p, data_p); + } else { + + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_QUERYDEVICE, data_p, + dev_p->func_cbs_stor, req_flags, req_p, + reply_p, cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as part of the + * MiscFuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_query_device(cy_as_device_handle handle, + cy_as_storage_query_device_data *data_p, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + return my_storage_query_device(dev_p, data_p, + CY_AS_REQUEST_RESPONSE_MS, data_p->bus, + data_p->device, cb, client); +} + +static cy_as_return_status_t +my_handle_response_storage_query_unit(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p, + void *data_p) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_bus_number_t bus; + uint32_t device; + uint32_t unit; + cy_as_media_type type; + uint16_t block_size; + uint32_t start_block; + uint32_t unit_size; + uint16_t v; + + if (cy_as_ll_request_response__get_code(reply_p) == + CY_RESP_NO_SUCH_ADDRESS) { + ret = cy_as_map_bad_addr( + cy_as_ll_request_response__get_word(reply_p, 3)); + goto destroy; + } + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_UNIT_DESCRIPTOR) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + /* Unpack the response */ + v = cy_as_ll_request_response__get_word(reply_p, 0); + bus = cy_as_storage_get_bus_from_address(v); + device = cy_as_storage_get_device_from_address(v); + unit = get_unit_from_address(v); + + type = cy_as_storage_get_media_from_address( + cy_as_ll_request_response__get_word(reply_p, 1)); + + block_size = cy_as_ll_request_response__get_word(reply_p, 2); + start_block = cy_as_ll_request_response__get_word(reply_p, 3) + | (cy_as_ll_request_response__get_word(reply_p, 4) << 16); + unit_size = cy_as_ll_request_response__get_word(reply_p, 5) + | (cy_as_ll_request_response__get_word(reply_p, 6) << 16); + + /* Store the results based on the version of + * originating function */ + if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) { + cy_as_storage_query_unit_data *store_p = + (cy_as_storage_query_unit_data *)data_p; + + /* Make sure the response is about the address we + * asked about - if not, firmware error */ + if (bus != store_p->bus || device != store_p->device || + unit != store_p->unit) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + store_p->desc_p.type = type; + store_p->desc_p.block_size = block_size; + store_p->desc_p.start_block = start_block; + store_p->desc_p.unit_size = unit_size; + } else { + cy_as_storage_query_unit_data_dep *store_p = + (cy_as_storage_query_unit_data_dep *)data_p; + + /* Make sure the response is about the media type we asked + * about - if not, firmware error */ + if ((type != store_p->type) || (device != store_p->device) || + (unit != store_p->unit)) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + store_p->desc_p.type = type; + store_p->desc_p.block_size = block_size; + store_p->desc_p.start_block = start_block; + store_p->desc_p.unit_size = unit_size; + } + + dev_p->storage_device_info[bus][device].type = type; + dev_p->storage_device_info[bus][device].block_size = block_size; + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +static cy_as_return_status_t +my_storage_query_unit(cy_as_device *dev_p, + void *data_p, + uint16_t req_flags, + cy_as_bus_number_t bus, + uint32_t device, + uint32_t unit, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_QUERY_UNIT, CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + if (device > 255) + return CY_AS_ERROR_NO_SUCH_DEVICE; + + if (unit > 255) + return CY_AS_ERROR_NO_SUCH_UNIT; + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, device, (uint8_t)unit)); + + /* Reserve space for the reply, the reply data + * will be of seven words. */ + reply_p = cy_as_ll_create_response(dev_p, 7); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + req_p->flags |= req_flags; + return my_handle_response_storage_query_unit(dev_p, + req_p, reply_p, data_p); + } else { + + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_QUERYUNIT, data_p, + dev_p->func_cbs_stor, req_flags, req_p, reply_p, + cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed + * as part of the MiscFuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_query_unit(cy_as_device_handle handle, + cy_as_storage_query_unit_data *data_p, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + return my_storage_query_unit(dev_p, data_p, CY_AS_REQUEST_RESPONSE_MS, + data_p->bus, data_p->device, data_p->unit, cb, client); +} + + +static cy_as_return_status_t +cy_as_get_block_size(cy_as_device *dev_p, + cy_as_bus_number_t bus, + uint32_t device, + cy_as_function_callback cb) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, CY_RQT_QUERY_DEVICE, + CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, device, 0)); + + reply_p = cy_as_ll_create_response(dev_p, 4); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + if (cy_as_ll_request_response__get_code(reply_p) + == CY_RESP_NO_SUCH_ADDRESS) { + ret = CY_AS_ERROR_NO_SUCH_BUS; + goto destroy; + } + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_DEVICE_DESCRIPTOR) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + /* Make sure the response is about the media type we asked + * about - if not, firmware error */ + if ((cy_as_storage_get_bus_from_address + (cy_as_ll_request_response__get_word(reply_p, 0)) + != bus) || (cy_as_storage_get_device_from_address + (cy_as_ll_request_response__get_word(reply_p, 0)) + != device)) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + + dev_p->storage_device_info[bus][device].block_size = + cy_as_ll_request_response__get_word(reply_p, 1); + } else + ret = CY_AS_ERROR_INVALID_REQUEST; + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +my_storage_device_control( + cy_as_device *dev_p, + cy_as_bus_number_t bus, + uint32_t device, + cy_bool card_detect_en, + cy_bool write_prot_en, + cy_as_storage_card_detect config_detect, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret; + cy_bool use_gpio = cy_false; + + (void)device; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + if (!cy_as_device_is_configured(dev_p)) + return CY_AS_ERROR_NOT_CONFIGURED; + + if (!cy_as_device_is_firmware_loaded(dev_p)) + return CY_AS_ERROR_NO_FIRMWARE; + + if (cy_as_device_is_in_suspend_mode(dev_p)) + return CY_AS_ERROR_IN_SUSPEND; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE; + + /* If SD is not supported on the specified bus, + * then return ERROR */ + if ((dev_p->media_supported[bus] == 0) || + (dev_p->media_supported[bus] & (1<<cy_as_media_nand))) + return CY_AS_ERROR_NOT_SUPPORTED; + + if (config_detect == cy_as_storage_detect_GPIO) + use_gpio = cy_true; + else if (config_detect == cy_as_storage_detect_SDAT_3) + use_gpio = cy_false; + else + return CY_AS_ERROR_INVALID_PARAMETER; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_SD_INTERFACE_CONTROL, CY_RQT_STORAGE_RQT_CONTEXT, 2); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word(req_p, + 0, create_address(bus, device, 0)); + cy_as_ll_request_response__set_word(req_p, + 1, (((uint16_t)card_detect_en << 8) | + ((uint16_t)use_gpio << 1) | (uint16_t)write_prot_en)); + + reply_p = cy_as_ll_create_response(dev_p, 1); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + if (cy_as_ll_request_response__get_code(reply_p) != + CY_RESP_SUCCESS_FAILURE) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + ret = cy_as_ll_request_response__get_word(reply_p, 0); + } else { + + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_DEVICECONTROL, + 0, dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as part of the + * MiscFuncCallback */ + return ret; + } +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_device_control(cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + cy_bool card_detect_en, + cy_bool write_prot_en, + cy_as_storage_card_detect config_detect, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + + return my_storage_device_control(dev_p, bus, device, card_detect_en, + write_prot_en, config_detect, cb, client); +} + +static void +cy_as_async_storage_callback(cy_as_device *dev_p, + cy_as_end_point_number_t ep, void *buf_p, uint32_t size, + cy_as_return_status_t ret) +{ + cy_as_storage_callback_dep cb; + cy_as_storage_callback cb_ms; + + (void)size; + (void)buf_p; + (void)ep; + + cy_as_device_clear_storage_async_pending(dev_p); + + /* + * if the LL request callback has already been called, + * the user callback has to be called from here. + */ + if (!dev_p->storage_wait) { + cy_as_hal_assert(dev_p->storage_cb != NULL || + dev_p->storage_cb_ms != NULL); + cb = dev_p->storage_cb; + cb_ms = dev_p->storage_cb_ms; + + dev_p->storage_cb = 0; + dev_p->storage_cb_ms = 0; + + if (ret == CY_AS_ERROR_SUCCESS) + ret = dev_p->storage_error; + + if (cb_ms) { + cb_ms((cy_as_device_handle)dev_p, + dev_p->storage_bus_index, + dev_p->storage_device_index, + dev_p->storage_unit, + dev_p->storage_block_addr, + dev_p->storage_oper, ret); + } else { + cb((cy_as_device_handle)dev_p, + dev_p->storage_device_info + [dev_p->storage_bus_index] + [dev_p->storage_device_index].type, + dev_p->storage_device_index, + dev_p->storage_unit, + dev_p->storage_block_addr, + dev_p->storage_oper, ret); + } + } else + dev_p->storage_error = ret; +} + +static void +cy_as_async_storage_reply_callback( + cy_as_device *dev_p, + uint8_t context, + cy_as_ll_request_response *rqt, + cy_as_ll_request_response *resp, + cy_as_return_status_t ret) +{ + cy_as_storage_callback_dep cb; + cy_as_storage_callback cb_ms; + uint8_t reqtype; + (void)rqt; + (void)context; + + reqtype = cy_as_ll_request_response__get_code(rqt); + + if (ret == CY_AS_ERROR_SUCCESS) { + if (cy_as_ll_request_response__get_code(resp) == + CY_RESP_ANTIOCH_DEFERRED_ERROR) { + ret = cy_as_ll_request_response__get_word + (resp, 0) & 0x00FF; + } else if (cy_as_ll_request_response__get_code(resp) != + CY_RESP_SUCCESS_FAILURE) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + } + + if (ret != CY_AS_ERROR_SUCCESS) { + if (reqtype == CY_RQT_READ_BLOCK) + cy_as_dma_cancel(dev_p, + dev_p->storage_read_endpoint, ret); + else + cy_as_dma_cancel(dev_p, + dev_p->storage_write_endpoint, ret); + } + + dev_p->storage_wait = cy_false; + + /* + * if the DMA callback has already been called, the + * user callback has to be called from here. + */ + if (!cy_as_device_is_storage_async_pending(dev_p)) { + cy_as_hal_assert(dev_p->storage_cb != NULL || + dev_p->storage_cb_ms != NULL); + cb = dev_p->storage_cb; + cb_ms = dev_p->storage_cb_ms; + + dev_p->storage_cb = 0; + dev_p->storage_cb_ms = 0; + + if (ret == CY_AS_ERROR_SUCCESS) + ret = dev_p->storage_error; + + if (cb_ms) { + cb_ms((cy_as_device_handle)dev_p, + dev_p->storage_bus_index, + dev_p->storage_device_index, + dev_p->storage_unit, + dev_p->storage_block_addr, + dev_p->storage_oper, ret); + } else { + cb((cy_as_device_handle)dev_p, + dev_p->storage_device_info + [dev_p->storage_bus_index] + [dev_p->storage_device_index].type, + dev_p->storage_device_index, + dev_p->storage_unit, + dev_p->storage_block_addr, + dev_p->storage_oper, ret); + } + } else + dev_p->storage_error = ret; +} + +static cy_as_return_status_t +cy_as_storage_async_oper(cy_as_device *dev_p, cy_as_end_point_number_t ep, + uint8_t reqtype, uint16_t req_flags, cy_as_bus_number_t bus, + uint32_t device, uint32_t unit, uint32_t block, void *data_p, + uint16_t num_blocks, cy_as_storage_callback_dep callback, + cy_as_storage_callback callback_ms) +{ + uint32_t mask; + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE; + + if (unit > 255) + return CY_AS_ERROR_NO_SUCH_UNIT; + + /* We are supposed to return sucess if the number of + * blocks is zero + */ + if (num_blocks == 0) { + if (callback_ms) + callback_ms((cy_as_device_handle)dev_p, + bus, device, unit, block, + ((reqtype == CY_RQT_WRITE_BLOCK) + ? cy_as_op_write : cy_as_op_read), + CY_AS_ERROR_SUCCESS); + else + callback((cy_as_device_handle)dev_p, + dev_p->storage_device_info[bus][device].type, + device, unit, block, + ((reqtype == CY_RQT_WRITE_BLOCK) ? + cy_as_op_write : cy_as_op_read), + CY_AS_ERROR_SUCCESS); + + return CY_AS_ERROR_SUCCESS; + } + + if (dev_p->storage_device_info[bus][device].block_size == 0) + return CY_AS_ERROR_QUERY_DEVICE_NEEDED; + + /* + * since async operations can be triggered by interrupt + * code, we must insure that we do not get multiple + * async operations going at one time and protect this + * test and set operation from interrupts. also need to + * check for pending async MTP writes + */ + mask = cy_as_hal_disable_interrupts(); + if ((cy_as_device_is_storage_async_pending(dev_p)) || + (dev_p->storage_wait) || + (cy_as_device_is_usb_async_pending(dev_p, 6))) { + cy_as_hal_enable_interrupts(mask); + return CY_AS_ERROR_ASYNC_PENDING; + } + + cy_as_device_set_storage_async_pending(dev_p); + cy_as_device_clear_p2s_dma_start_recvd(dev_p); + cy_as_hal_enable_interrupts(mask); + + /* + * storage information about the currently outstanding request + */ + dev_p->storage_cb = callback; + dev_p->storage_cb_ms = callback_ms; + dev_p->storage_bus_index = bus; + dev_p->storage_device_index = device; + dev_p->storage_unit = unit; + dev_p->storage_block_addr = block; + + /* Initialise the request to send to the West Bridge. */ + req_p = dev_p->storage_rw_req_p; + cy_as_ll_init_request(req_p, reqtype, CY_RQT_STORAGE_RQT_CONTEXT, 5); + + /* Initialise the space for reply from the West Bridge. */ + reply_p = dev_p->storage_rw_resp_p; + cy_as_ll_init_response(reply_p, 5); + + /* Remember which version of the API originated the request */ + req_p->flags |= req_flags; + + /* Setup the DMA request and adjust the storage + * operation if we are reading */ + if (reqtype == CY_RQT_READ_BLOCK) { + ret = cy_as_dma_queue_request(dev_p, ep, data_p, + dev_p->storage_device_info[bus][device].block_size + * num_blocks, cy_false, cy_true, + cy_as_async_storage_callback); + dev_p->storage_oper = cy_as_op_read; + } else if (reqtype == CY_RQT_WRITE_BLOCK) { + ret = cy_as_dma_queue_request(dev_p, ep, data_p, + dev_p->storage_device_info[bus][device].block_size * + num_blocks, cy_false, cy_false, + cy_as_async_storage_callback); + dev_p->storage_oper = cy_as_op_write; + } + + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_device_clear_storage_async_pending(dev_p); + return ret; + } + + cy_as_ll_request_response__set_word(req_p, + 0, create_address(bus, (uint8_t)device, (uint8_t)unit)); + cy_as_ll_request_response__set_word(req_p, + 1, (uint16_t)((block >> 16) & 0xffff)); + cy_as_ll_request_response__set_word(req_p, + 2, (uint16_t)(block & 0xffff)); + cy_as_ll_request_response__set_word(req_p, + 3, (uint16_t)((num_blocks >> 8) & 0x00ff)); + cy_as_ll_request_response__set_word(req_p, + 4, (uint16_t)((num_blocks << 8) & 0xff00)); + + /* Set the burst mode flag. */ + if (dev_p->is_storage_only_mode) + req_p->data[4] |= 0x0001; + + /* Send the request and wait for completion + * of storage request */ + dev_p->storage_wait = cy_true; + ret = cy_as_ll_send_request(dev_p, req_p, reply_p, + cy_true, cy_as_async_storage_reply_callback); + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED); + cy_as_device_clear_storage_async_pending(dev_p); + } + + return ret; +} + +static void +cy_as_sync_storage_callback(cy_as_device *dev_p, + cy_as_end_point_number_t ep, void *buf_p, + uint32_t size, cy_as_return_status_t err) +{ + (void)ep; + (void)buf_p; + (void)size; + + dev_p->storage_error = err; +} + +static void +cy_as_sync_storage_reply_callback( + cy_as_device *dev_p, + uint8_t context, + cy_as_ll_request_response *rqt, + cy_as_ll_request_response *resp, + cy_as_return_status_t ret) +{ + uint8_t reqtype; + (void)rqt; + + reqtype = cy_as_ll_request_response__get_code(rqt); + + if (cy_as_ll_request_response__get_code(resp) == + CY_RESP_ANTIOCH_DEFERRED_ERROR) { + ret = cy_as_ll_request_response__get_word(resp, 0) & 0x00FF; + + if (ret != CY_AS_ERROR_SUCCESS) { + if (reqtype == CY_RQT_READ_BLOCK) + cy_as_dma_cancel(dev_p, + dev_p->storage_read_endpoint, ret); + else + cy_as_dma_cancel(dev_p, + dev_p->storage_write_endpoint, ret); + } + } else if (cy_as_ll_request_response__get_code(resp) != + CY_RESP_SUCCESS_FAILURE) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + + dev_p->storage_wait = cy_false; + dev_p->storage_error = ret; + + /* Wake any threads/processes that are waiting on + * the read/write completion. */ + cy_as_hal_wake(&dev_p->context[context]->channel); +} + +static cy_as_return_status_t +cy_as_storage_sync_oper(cy_as_device *dev_p, + cy_as_end_point_number_t ep, uint8_t reqtype, + cy_as_bus_number_t bus, uint32_t device, + uint32_t unit, uint32_t block, void *data_p, + uint16_t num_blocks) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_context *ctxt_p; + uint32_t loopcount = 200; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE; + + if (unit > 255) + return CY_AS_ERROR_NO_SUCH_UNIT; + + if ((cy_as_device_is_storage_async_pending(dev_p)) || + (dev_p->storage_wait)) + return CY_AS_ERROR_ASYNC_PENDING; + + /* Also need to check for pending Async MTP writes */ + if (cy_as_device_is_usb_async_pending(dev_p, 6)) + return CY_AS_ERROR_ASYNC_PENDING; + + /* We are supposed to return sucess if the number of + * blocks is zero + */ + if (num_blocks == 0) + return CY_AS_ERROR_SUCCESS; + + if (dev_p->storage_device_info[bus][device].block_size == 0) { + /* + * normally, a given device has been queried via + * the query device call before a read request is issued. + * therefore, this normally will not be run. + */ + ret = cy_as_get_block_size(dev_p, bus, device, 0); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + } + + /* Initialise the request to send to the West Bridge. */ + req_p = dev_p->storage_rw_req_p; + cy_as_ll_init_request(req_p, reqtype, + CY_RQT_STORAGE_RQT_CONTEXT, 5); + + /* Initialise the space for reply from + * the West Bridge. */ + reply_p = dev_p->storage_rw_resp_p; + cy_as_ll_init_response(reply_p, 5); + cy_as_device_clear_p2s_dma_start_recvd(dev_p); + + /* Setup the DMA request */ + if (reqtype == CY_RQT_READ_BLOCK) { + ret = cy_as_dma_queue_request(dev_p, ep, data_p, + dev_p->storage_device_info[bus][device].block_size * + num_blocks, cy_false, + cy_true, cy_as_sync_storage_callback); + dev_p->storage_oper = cy_as_op_read; + } else if (reqtype == CY_RQT_WRITE_BLOCK) { + ret = cy_as_dma_queue_request(dev_p, ep, data_p, + dev_p->storage_device_info[bus][device].block_size * + num_blocks, cy_false, cy_false, + cy_as_sync_storage_callback); + dev_p->storage_oper = cy_as_op_write; + } + + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, (uint8_t)unit)); + cy_as_ll_request_response__set_word(req_p, 1, + (uint16_t)((block >> 16) & 0xffff)); + cy_as_ll_request_response__set_word(req_p, 2, + (uint16_t)(block & 0xffff)); + cy_as_ll_request_response__set_word(req_p, 3, + (uint16_t)((num_blocks >> 8) & 0x00ff)); + cy_as_ll_request_response__set_word(req_p, 4, + (uint16_t)((num_blocks << 8) & 0xff00)); + + /* Set the burst mode flag. */ + if (dev_p->is_storage_only_mode) + req_p->data[4] |= 0x0001; + + /* Send the request and wait for + * completion of storage request */ + dev_p->storage_wait = cy_true; + ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_true, + cy_as_sync_storage_reply_callback); + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED); + } else { + /* Setup the DMA request */ + ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT]; + ret = cy_as_dma_drain_queue(dev_p, ep, cy_false); + + while (loopcount-- > 0) { + if (dev_p->storage_wait == cy_false) + break; + cy_as_hal_sleep_on(&ctxt_p->channel, 10); + } + + if (dev_p->storage_wait == cy_true) { + dev_p->storage_wait = cy_false; + cy_as_ll_remove_request(dev_p, ctxt_p, req_p, cy_true); + ret = CY_AS_ERROR_TIMEOUT; + } + + if (ret == CY_AS_ERROR_SUCCESS) + ret = dev_p->storage_error; + } + + return ret; +} + +cy_as_return_status_t +cy_as_storage_read(cy_as_device_handle handle, + cy_as_bus_number_t bus, uint32_t device, + uint32_t unit, uint32_t block, + void *data_p, uint16_t num_blocks) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + return cy_as_storage_sync_oper(dev_p, dev_p->storage_read_endpoint, + CY_RQT_READ_BLOCK, bus, device, + unit, block, data_p, num_blocks); +} + +cy_as_return_status_t +cy_as_storage_write(cy_as_device_handle handle, + cy_as_bus_number_t bus, uint32_t device, + uint32_t unit, uint32_t block, void *data_p, + uint16_t num_blocks) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + if (dev_p->mtp_turbo_active) + return CY_AS_ERROR_NOT_VALID_DURING_MTP; + + return cy_as_storage_sync_oper(dev_p, + dev_p->storage_write_endpoint, + CY_RQT_WRITE_BLOCK, bus, device, + unit, block, data_p, num_blocks); +} + + +cy_as_return_status_t +cy_as_storage_read_async(cy_as_device_handle handle, + cy_as_bus_number_t bus, uint32_t device, uint32_t unit, + uint32_t block, void *data_p, uint16_t num_blocks, + cy_as_storage_callback callback) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + if (callback == 0) + return CY_AS_ERROR_NULL_CALLBACK; + + return cy_as_storage_async_oper(dev_p, + dev_p->storage_read_endpoint, CY_RQT_READ_BLOCK, + CY_AS_REQUEST_RESPONSE_MS, bus, device, unit, + block, data_p, num_blocks, NULL, callback); +} + +cy_as_return_status_t +cy_as_storage_write_async(cy_as_device_handle handle, + cy_as_bus_number_t bus, uint32_t device, uint32_t unit, + uint32_t block, void *data_p, uint16_t num_blocks, + cy_as_storage_callback callback) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + if (callback == 0) + return CY_AS_ERROR_NULL_CALLBACK; + + if (dev_p->mtp_turbo_active) + return CY_AS_ERROR_NOT_VALID_DURING_MTP; + + return cy_as_storage_async_oper(dev_p, + dev_p->storage_write_endpoint, CY_RQT_WRITE_BLOCK, + CY_AS_REQUEST_RESPONSE_MS, bus, device, unit, block, + data_p, num_blocks, NULL, callback); +} + + +static void +my_storage_cancel_callback( + cy_as_device *dev_p, + uint8_t context, + cy_as_ll_request_response *rqt, + cy_as_ll_request_response *resp, + cy_as_return_status_t stat) +{ + (void)context; + (void)stat; + + /* Nothing to do here, except free up the + * request and response structures. */ + cy_as_ll_destroy_response(dev_p, resp); + cy_as_ll_destroy_request(dev_p, rqt); +} + + +cy_as_return_status_t +cy_as_storage_cancel_async(cy_as_device_handle handle) +{ + cy_as_return_status_t ret; + cy_as_ll_request_response *req_p , *reply_p; + + cy_as_device *dev_p = (cy_as_device *)handle; + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!cy_as_device_is_storage_async_pending(dev_p)) + return CY_AS_ERROR_ASYNC_NOT_PENDING; + + /* + * create and send a mailbox request to firmware + * asking it to abort processing of the current + * P2S operation. the rest of the cancel processing will be + * driven through the callbacks for the read/write call. + */ + req_p = cy_as_ll_create_request(dev_p, CY_RQT_ABORT_P2S_XFER, + CY_RQT_GENERAL_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + reply_p = cy_as_ll_create_response(dev_p, 1); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + ret = cy_as_ll_send_request(dev_p, req_p, + reply_p, cy_false, my_storage_cancel_callback); + if (ret) { + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + } + + return CY_AS_ERROR_SUCCESS; +} + +/* + * This function does all the API side clean-up associated with + * CyAsStorageStop, without any communication with the firmware. + */ +void cy_as_storage_cleanup(cy_as_device *dev_p) +{ + if (dev_p->storage_count) { + cy_as_ll_destroy_request(dev_p, dev_p->storage_rw_req_p); + cy_as_ll_destroy_response(dev_p, dev_p->storage_rw_resp_p); + dev_p->storage_count = 0; + cy_as_device_clear_scsi_messages(dev_p); + cy_as_hal_mem_set(dev_p->storage_device_info, + 0, sizeof(dev_p->storage_device_info)); + + cy_as_device_clear_storage_async_pending(dev_p); + dev_p->storage_cb = 0; + dev_p->storage_cb_ms = 0; + dev_p->storage_wait = cy_false; + } +} + +static cy_as_return_status_t +my_handle_response_sd_reg_read( + cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p, + cy_as_storage_sd_reg_read_data *info) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t resp_type, i; + uint16_t resp_len; + uint8_t length = info->length; + uint8_t *data_p = info->buf_p; + + resp_type = cy_as_ll_request_response__get_code(reply_p); + if (resp_type == CY_RESP_SD_REGISTER_DATA) { + uint16_t *resp_p = reply_p->data + 1; + uint16_t temp; + + resp_len = cy_as_ll_request_response__get_word(reply_p, 0); + cy_as_hal_assert(resp_len >= length); + + /* + * copy the values into the output buffer after doing the + * necessary bit shifting. the bit shifting is required because + * the data comes out of the west bridge with a 6 bit offset. + */ + i = 0; + while (length) { + temp = ((resp_p[i] << 6) | (resp_p[i + 1] >> 10)); + i++; + + *data_p++ = (uint8_t)(temp >> 8); + length--; + + if (length) { + *data_p++ = (uint8_t)(temp & 0xFF); + length--; + } + } + } else { + if (resp_type == CY_RESP_SUCCESS_FAILURE) + ret = cy_as_ll_request_response__get_word(reply_p, 0); + else + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + + cy_as_ll_destroy_response(dev_p, reply_p); + cy_as_ll_destroy_request(dev_p, req_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_sd_register_read( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint8_t device, + cy_as_sd_card_reg_type reg_type, + cy_as_storage_sd_reg_read_data *data_p, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t length; + + /* + * sanity checks required before sending the request to the + * firmware. + */ + cy_as_device *dev_p = (cy_as_device *)handle; + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE; + + if (reg_type > cy_as_sd_reg_CSD) + return CY_AS_ERROR_INVALID_PARAMETER; + + /* If SD/MMC media is not supported on the + * addressed bus, return error. */ + if ((dev_p->media_supported[bus] & (1 << cy_as_media_sd_flash)) == 0) + return CY_AS_ERROR_INVALID_PARAMETER; + + /* + * find the amount of data to be returned. this will be the minimum of + * the actual data length, and the length requested. + */ + switch (reg_type) { + case cy_as_sd_reg_OCR: + length = CY_AS_SD_REG_OCR_LENGTH; + break; + case cy_as_sd_reg_CID: + length = CY_AS_SD_REG_CID_LENGTH; + break; + case cy_as_sd_reg_CSD: + length = CY_AS_SD_REG_CSD_LENGTH; + break; + + default: + length = 0; + cy_as_hal_assert(0); + } + + if (length < data_p->length) + data_p->length = length; + length = data_p->length; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, CY_RQT_SD_REGISTER_READ, + CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word(req_p, 0, + (create_address(bus, device, 0) | (uint16_t)reg_type)); + + reply_p = cy_as_ll_create_response(dev_p, + CY_AS_SD_REG_MAX_RESP_LENGTH); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + return my_handle_response_sd_reg_read(dev_p, + req_p, reply_p, data_p); + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_SDREGISTERREAD, data_p, + dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as part of the + * MiscFuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_create_p_partition( + /* Handle to the device of interest */ + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + /* of P-port only partition in blocks */ + uint32_t size, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p, *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + /* Partitions cannot be created or deleted while + * the USB stack is active. */ + if (dev_p->usb_count) + return CY_AS_ERROR_USB_RUNNING; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, CY_RQT_PARTITION_STORAGE, + CY_RQT_STORAGE_RQT_CONTEXT, 3); + + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /* Reserve space for the reply, the reply + * data will not exceed one word */ + reply_p = cy_as_ll_create_response(dev_p, 1); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, 0x00)); + cy_as_ll_request_response__set_word(req_p, 1, + (uint16_t)((size >> 16) & 0xffff)); + cy_as_ll_request_response__set_word(req_p, 2, + (uint16_t)(size & 0xffff)); + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + return my_handle_response_no_data(dev_p, req_p, reply_p); + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_PARTITION, 0, dev_p->func_cbs_stor, + CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as part of the + * FuncCallback */ + return ret; + + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_remove_p_partition( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + cy_as_function_callback cb, + uint32_t client) +{ + cy_as_ll_request_response *req_p, *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + /* Partitions cannot be created or deleted while + * the USB stack is active. */ + if (dev_p->usb_count) + return CY_AS_ERROR_USB_RUNNING; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, CY_RQT_PARTITION_ERASE, + CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /* Reserve space for the reply, the reply + * data will not exceed one word */ + reply_p = cy_as_ll_create_response(dev_p, 1); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + cy_as_ll_request_response__set_word(req_p, + 0, create_address(bus, (uint8_t)device, 0x00)); + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + return my_handle_response_no_data(dev_p, req_p, reply_p); + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_NODATA, 0, dev_p->func_cbs_stor, + CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed + * as part of the FuncCallback */ + return ret; + + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +static cy_as_return_status_t +my_handle_response_get_transfer_amount(cy_as_device *dev_p, + cy_as_ll_request_response *req_p, + cy_as_ll_request_response *reply_p, + cy_as_m_s_c_progress_data *data) +{ + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t code = cy_as_ll_request_response__get_code(reply_p); + uint16_t v1, v2; + + if (code != CY_RESP_TRANSFER_COUNT) { + ret = CY_AS_ERROR_INVALID_RESPONSE; + goto destroy; + } + + v1 = cy_as_ll_request_response__get_word(reply_p, 0); + v2 = cy_as_ll_request_response__get_word(reply_p, 1); + data->wr_count = (uint32_t)((v1 << 16) | v2); + + v1 = cy_as_ll_request_response__get_word(reply_p, 2); + v2 = cy_as_ll_request_response__get_word(reply_p, 3); + data->rd_count = (uint32_t)((v1 << 16) | v2); + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +cy_as_return_status_t +cy_as_storage_get_transfer_amount( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + cy_as_m_s_c_progress_data *data_p, + cy_as_function_callback cb, + uint32_t client + ) +{ + cy_as_ll_request_response *req_p, *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + /* Check if the firmware image supports this feature. */ + if ((dev_p->media_supported[0]) && (dev_p->media_supported[0] + == (1 << cy_as_media_nand))) + return CY_AS_ERROR_NOT_SUPPORTED; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, CY_RQT_GET_TRANSFER_AMOUNT, + CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /* Reserve space for the reply, the reply data + * will not exceed four words. */ + reply_p = cy_as_ll_create_response(dev_p, 4); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, 0x00)); + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + return my_handle_response_get_transfer_amount(dev_p, + req_p, reply_p, data_p); + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_GETTRANSFERAMOUNT, (void *)data_p, + dev_p->func_cbs_stor, CY_AS_REQUEST_RESPONSE_EX, + req_p, reply_p, cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed as part of the + * FuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; + +} + +cy_as_return_status_t +cy_as_storage_erase( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint32_t erase_unit, + uint16_t num_erase_units, + cy_as_function_callback cb, + uint32_t client + ) +{ + cy_as_ll_request_response *req_p, *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_device *dev_p = (cy_as_device *)handle; + + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + ret = is_storage_active(dev_p); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE; + + if (dev_p->storage_device_info[bus][device].block_size == 0) + return CY_AS_ERROR_QUERY_DEVICE_NEEDED; + + /* If SD is not supported on the specified bus, then return ERROR */ + if (dev_p->storage_device_info[bus][device].type != + cy_as_media_sd_flash) + return CY_AS_ERROR_NOT_SUPPORTED; + + if (num_erase_units == 0) + return CY_AS_ERROR_SUCCESS; + + /* Create the request to send to the West Bridge device */ + req_p = cy_as_ll_create_request(dev_p, CY_RQT_ERASE, + CY_RQT_STORAGE_RQT_CONTEXT, 5); + + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /* Reserve space for the reply, the reply + * data will not exceed four words. */ + reply_p = cy_as_ll_create_response(dev_p, 4); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, 0x00)); + cy_as_ll_request_response__set_word(req_p, 1, + (uint16_t)((erase_unit >> 16) & 0xffff)); + cy_as_ll_request_response__set_word(req_p, 2, + (uint16_t)(erase_unit & 0xffff)); + cy_as_ll_request_response__set_word(req_p, 3, + (uint16_t)((num_erase_units >> 8) & 0x00ff)); + cy_as_ll_request_response__set_word(req_p, 4, + (uint16_t)((num_erase_units << 8) & 0xff00)); + + if (cb == 0) { + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + ret = my_handle_response_no_data(dev_p, req_p, reply_p); + + /* If error = "invalid response", this (very likely) means + * that we are not using the SD-only firmware module which + * is the only one supporting storage_erase. in this case + * force a "non supported" error code */ + if (ret == CY_AS_ERROR_INVALID_RESPONSE) + ret = CY_AS_ERROR_NOT_SUPPORTED; + + return ret; + } else { + ret = cy_as_misc_send_request(dev_p, cb, client, + CY_FUNCT_CB_STOR_ERASE, 0, dev_p->func_cbs_stor, + CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, + cy_as_storage_func_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /* The request and response are freed + * as part of the FuncCallback */ + return ret; + } + +destroy: + cy_as_ll_destroy_request(dev_p, req_p); + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +static void +cy_as_storage_func_callback(cy_as_device *dev_p, + uint8_t context, + cy_as_ll_request_response *rqt, + cy_as_ll_request_response *resp, + cy_as_return_status_t stat) +{ + cy_as_func_c_b_node *node = (cy_as_func_c_b_node *) + dev_p->func_cbs_stor->head_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX) + == CY_AS_REQUEST_RESPONSE_EX; + cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS) + == CY_AS_REQUEST_RESPONSE_MS; + uint8_t code; + uint8_t cntxt; + + cy_as_hal_assert(ex_request || ms_request); + cy_as_hal_assert(dev_p->func_cbs_stor->count != 0); + cy_as_hal_assert(dev_p->func_cbs_stor->type == CYAS_FUNC_CB); + (void) ex_request; + (void) ms_request; + + (void)context; + + cntxt = cy_as_ll_request_response__get_context(rqt); + cy_as_hal_assert(cntxt == CY_RQT_STORAGE_RQT_CONTEXT); + + code = cy_as_ll_request_response__get_code(rqt); + switch (code) { + case CY_RQT_START_STORAGE: + ret = my_handle_response_storage_start(dev_p, rqt, resp, stat); + break; + case CY_RQT_STOP_STORAGE: + ret = my_handle_response_storage_stop(dev_p, rqt, resp, stat); + break; + case CY_RQT_CLAIM_STORAGE: + ret = my_handle_response_storage_claim(dev_p, rqt, resp); + break; + case CY_RQT_RELEASE_STORAGE: + ret = my_handle_response_storage_release(dev_p, rqt, resp); + break; + case CY_RQT_QUERY_MEDIA: + cy_as_hal_assert(cy_false);/* Not used any more. */ + break; + case CY_RQT_QUERY_BUS: + cy_as_hal_assert(node->data != 0); + ret = my_handle_response_storage_query_bus(dev_p, + rqt, resp, (uint32_t *)node->data); + break; + case CY_RQT_QUERY_DEVICE: + cy_as_hal_assert(node->data != 0); + ret = my_handle_response_storage_query_device(dev_p, + rqt, resp, node->data); + break; + case CY_RQT_QUERY_UNIT: + cy_as_hal_assert(node->data != 0); + ret = my_handle_response_storage_query_unit(dev_p, + rqt, resp, node->data); + break; + case CY_RQT_SD_INTERFACE_CONTROL: + ret = my_handle_response_no_data(dev_p, rqt, resp); + break; + case CY_RQT_SD_REGISTER_READ: + cy_as_hal_assert(node->data != 0); + ret = my_handle_response_sd_reg_read(dev_p, rqt, resp, + (cy_as_storage_sd_reg_read_data *)node->data); + break; + case CY_RQT_PARTITION_STORAGE: + ret = my_handle_response_no_data(dev_p, rqt, resp); + break; + case CY_RQT_PARTITION_ERASE: + ret = my_handle_response_no_data(dev_p, rqt, resp); + break; + case CY_RQT_GET_TRANSFER_AMOUNT: + cy_as_hal_assert(node->data != 0); + ret = my_handle_response_get_transfer_amount(dev_p, + rqt, resp, (cy_as_m_s_c_progress_data *)node->data); + break; + case CY_RQT_ERASE: + ret = my_handle_response_no_data(dev_p, rqt, resp); + + /* If error = "invalid response", this (very likely) + * means that we are not using the SD-only firmware + * module which is the only one supporting storage_erase. + * in this case force a "non supported" error code */ + if (ret == CY_AS_ERROR_INVALID_RESPONSE) + ret = CY_AS_ERROR_NOT_SUPPORTED; + + break; + + default: + ret = CY_AS_ERROR_INVALID_RESPONSE; + cy_as_hal_assert(cy_false); + break; + } + + /* + * if the low level layer returns a direct error, use the + * corresponding error code. if not, use the error code + * based on the response from firmware. + */ + if (stat == CY_AS_ERROR_SUCCESS) + stat = ret; + + /* Call the user callback, if there is one */ + if (node->cb_p) + node->cb_p((cy_as_device_handle)dev_p, stat, + node->client_data, node->data_type, node->data); + cy_as_remove_c_b_node(dev_p->func_cbs_stor); +} + + +static void +cy_as_sdio_sync_reply_callback( + cy_as_device *dev_p, + uint8_t context, + cy_as_ll_request_response *rqt, + cy_as_ll_request_response *resp, + cy_as_return_status_t ret) +{ + (void)rqt; + + if ((cy_as_ll_request_response__get_code(resp) == + CY_RESP_SDIO_GET_TUPLE) || + (cy_as_ll_request_response__get_code(resp) == + CY_RESP_SDIO_EXT)) { + ret = cy_as_ll_request_response__get_word(resp, 0); + if ((ret & 0x00FF) != CY_AS_ERROR_SUCCESS) { + if (cy_as_ll_request_response__get_code(rqt) == + CY_RQT_SDIO_READ_EXTENDED) + cy_as_dma_cancel(dev_p, + dev_p->storage_read_endpoint, ret); + else + cy_as_dma_cancel(dev_p, + dev_p->storage_write_endpoint, ret); + } + } else { + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + + dev_p->storage_rw_resp_p = resp; + dev_p->storage_wait = cy_false; + if (((ret & 0x00FF) == CY_AS_ERROR_IO_ABORTED) || ((ret & 0x00FF) + == CY_AS_ERROR_IO_SUSPENDED)) + dev_p->storage_error = (ret & 0x00FF); + else + dev_p->storage_error = (ret & 0x00FF) ? + CY_AS_ERROR_INVALID_RESPONSE : CY_AS_ERROR_SUCCESS; + + /* Wake any threads/processes that are waiting on + * the read/write completion. */ + cy_as_hal_wake(&dev_p->context[context]->channel); +} + +cy_as_return_status_t +cy_as_sdio_device_check( + cy_as_device *dev_p, + cy_as_bus_number_t bus, + uint32_t device) +{ + if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) + return CY_AS_ERROR_INVALID_HANDLE; + + if (bus < 0 || bus >= CY_AS_MAX_BUSES) + return CY_AS_ERROR_NO_SUCH_BUS; + + if (device >= CY_AS_MAX_STORAGE_DEVICES) + return CY_AS_ERROR_NO_SUCH_DEVICE; + + if (!cy_as_device_is_astoria_dev(dev_p)) + return CY_AS_ERROR_NOT_SUPPORTED; + + return (is_storage_active(dev_p)); +} + +cy_as_return_status_t +cy_as_sdio_direct_io( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint32_t address, + uint8_t misc_buf, + uint16_t argument, + uint8_t is_write, + uint8_t *data_p) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint16_t resp_data; + + /* + * sanity checks required before sending the request to the + * firmware. + */ + cy_as_device *dev_p = (cy_as_device *)handle; + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + + if (!(cy_as_sdio_check_function_initialized(handle, + bus, n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + if (cy_as_sdio_check_function_suspended(handle, bus, n_function_no)) + return CY_AS_ERROR_FUNCTION_SUSPENDED; + + req_p = cy_as_ll_create_request(dev_p, (is_write == cy_true) ? + CY_RQT_SDIO_WRITE_DIRECT : CY_RQT_SDIO_READ_DIRECT, + CY_RQT_STORAGE_RQT_CONTEXT, 3); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /*Setting up request*/ + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, n_function_no)); + /* D1 */ + if (is_write == cy_true) { + cy_as_ll_request_response__set_word(req_p, 1, + ((argument<<8) | 0x0080 | (n_function_no<<4) | + ((misc_buf&CY_SDIO_RAW)<<3) | + ((misc_buf&CY_SDIO_REARM_INT)>>5) | + (uint16_t)(address>>15))); + } else { + cy_as_ll_request_response__set_word(req_p, 1, + (n_function_no<<4) | ((misc_buf&CY_SDIO_REARM_INT)>>5) | + (uint16_t)(address>>15)); + } + /* D2 */ + cy_as_ll_request_response__set_word(req_p, 2, + ((uint16_t)((address&0x00007fff)<<1))); + + /*Create response*/ + reply_p = cy_as_ll_create_response(dev_p, 2); + + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + /*Sending the request*/ + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + /*Check reply type*/ + if (cy_as_ll_request_response__get_code(reply_p) == + CY_RESP_SDIO_DIRECT) { + resp_data = cy_as_ll_request_response__get_word(reply_p, 0); + if (resp_data >> 8) + ret = CY_AS_ERROR_INVALID_RESPONSE; + else if (data_p != 0) + *(uint8_t *)(data_p) = (uint8_t)(resp_data&0x00ff); + } else { + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + +destroy: + if (req_p != 0) + cy_as_ll_destroy_request(dev_p, req_p); + if (reply_p != 0) + cy_as_ll_destroy_response(dev_p, reply_p); + return ret; +} + + +cy_as_return_status_t +cy_as_sdio_direct_read( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint32_t address, + uint8_t misc_buf, + uint8_t *data_p) +{ + return cy_as_sdio_direct_io(handle, bus, device, n_function_no, + address, misc_buf, 0x00, cy_false, data_p); +} + +cy_as_return_status_t +cy_as_sdio_direct_write( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint32_t address, + uint8_t misc_buf, + uint16_t argument, + uint8_t *data_p) +{ + return cy_as_sdio_direct_io(handle, bus, device, n_function_no, + address, misc_buf, argument, cy_true, data_p); +} + +/*Cmd53 IO*/ +cy_as_return_status_t +cy_as_sdio_extended_i_o( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint32_t address, + uint8_t misc_buf, + uint16_t argument, + uint8_t is_write, + uint8_t *data_p , + uint8_t is_resume) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t resp_type; + uint8_t reqtype; + uint16_t resp_data; + cy_as_context *ctxt_p; + uint32_t dmasize, loopcount = 200; + cy_as_end_point_number_t ep; + + cy_as_device *dev_p = (cy_as_device *)handle; + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized(handle, + bus, n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + if (cy_as_sdio_check_function_suspended(handle, bus, n_function_no)) + return CY_AS_ERROR_FUNCTION_SUSPENDED; + + + if ((cy_as_device_is_storage_async_pending(dev_p)) || + (dev_p->storage_wait)) + return CY_AS_ERROR_ASYNC_PENDING; + + /* Request for 0 bytes of blocks is returned as a success*/ + if (argument == 0) + return CY_AS_ERROR_SUCCESS; + + /* Initialise the request to send to the West Bridge device. */ + if (is_write == cy_true) { + reqtype = CY_RQT_SDIO_WRITE_EXTENDED; + ep = dev_p->storage_write_endpoint; + } else { + reqtype = CY_RQT_SDIO_READ_EXTENDED; + ep = dev_p->storage_read_endpoint; + } + + req_p = dev_p->storage_rw_req_p; + cy_as_ll_init_request(req_p, reqtype, CY_RQT_STORAGE_RQT_CONTEXT, 3); + + /* Initialise the space for reply from the Antioch. */ + reply_p = dev_p->storage_rw_resp_p; + cy_as_ll_init_response(reply_p, 2); + + /* Setup the DMA request */ + if (!(misc_buf&CY_SDIO_BLOCKMODE)) { + if (argument > + dev_p->sdiocard[bus]. + function[n_function_no-1].blocksize) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + + } else { + if (argument > 511) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + } + + if (argument == 512) + argument = 0; + + dmasize = ((misc_buf&CY_SDIO_BLOCKMODE) != 0) ? + dev_p->sdiocard[bus].function[n_function_no-1].blocksize + * argument : argument; + + ret = cy_as_dma_queue_request(dev_p, ep, (void *)(data_p), + dmasize, cy_false, (is_write & cy_true) ? cy_false : + cy_true, cy_as_sync_storage_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, + n_function_no | ((is_resume) ? 0x80 : 0x00))); + cy_as_ll_request_response__set_word(req_p, 1, + ((uint16_t)n_function_no)<<12| + ((uint16_t)(misc_buf & (CY_SDIO_BLOCKMODE|CY_SDIO_OP_INCR))) + << 9 | (uint16_t)(address >> 7) | + ((is_write == cy_true) ? 0x8000 : 0x0000)); + cy_as_ll_request_response__set_word(req_p, 2, + ((uint16_t)(address&0x0000ffff) << 9) | argument); + + + /* Send the request and wait for completion of storage request */ + dev_p->storage_wait = cy_true; + ret = cy_as_ll_send_request(dev_p, req_p, reply_p, + cy_true, cy_as_sdio_sync_reply_callback); + + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED); + } else { + /* Setup the DMA request */ + ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT]; + ret = cy_as_dma_drain_queue(dev_p, ep, cy_true); + + while (loopcount-- > 0) { + if (dev_p->storage_wait == cy_false) + break; + cy_as_hal_sleep_on(&ctxt_p->channel, 10); + } + if (dev_p->storage_wait == cy_true) { + dev_p->storage_wait = cy_false; + cy_as_ll_remove_request(dev_p, ctxt_p, req_p, cy_true); + dev_p->storage_error = CY_AS_ERROR_TIMEOUT; + } + + ret = dev_p->storage_error; + + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + resp_type = cy_as_ll_request_response__get_code( + dev_p->storage_rw_resp_p); + if (resp_type == CY_RESP_SDIO_EXT) { + resp_data = cy_as_ll_request_response__get_word + (reply_p, 0)&0x00ff; + if (resp_data) + ret = CY_AS_ERROR_INVALID_REQUEST; + + } else { + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + } + return ret; + +} + +static void +cy_as_sdio_async_reply_callback( + cy_as_device *dev_p, + uint8_t context, + cy_as_ll_request_response *rqt, + cy_as_ll_request_response *resp, + cy_as_return_status_t ret) +{ + cy_as_storage_callback cb_ms; + uint8_t reqtype; + uint32_t pendingblocks; + (void)rqt; + (void)context; + + pendingblocks = 0; + reqtype = cy_as_ll_request_response__get_code(rqt); + if (ret == CY_AS_ERROR_SUCCESS) { + if ((cy_as_ll_request_response__get_code(resp) == + CY_RESP_SUCCESS_FAILURE) || + (cy_as_ll_request_response__get_code(resp) == + CY_RESP_SDIO_EXT)) { + ret = cy_as_ll_request_response__get_word(resp, 0); + ret &= 0x00FF; + } else { + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + } + + if (ret != CY_AS_ERROR_SUCCESS) { + if (reqtype == CY_RQT_SDIO_READ_EXTENDED) + cy_as_dma_cancel(dev_p, + dev_p->storage_read_endpoint, ret); + else + cy_as_dma_cancel(dev_p, + dev_p->storage_write_endpoint, ret); + + dev_p->storage_error = ret; + } + + dev_p->storage_wait = cy_false; + + /* + * if the DMA callback has already been called, + * the user callback has to be called from here. + */ + if (!cy_as_device_is_storage_async_pending(dev_p)) { + cy_as_hal_assert(dev_p->storage_cb_ms != NULL); + cb_ms = dev_p->storage_cb_ms; + + dev_p->storage_cb = 0; + dev_p->storage_cb_ms = 0; + + if ((ret == CY_AS_ERROR_SUCCESS) || + (ret == CY_AS_ERROR_IO_ABORTED) || + (ret == CY_AS_ERROR_IO_SUSPENDED)) { + ret = dev_p->storage_error; + pendingblocks = ((uint32_t) + cy_as_ll_request_response__get_word + (resp, 1)) << 16; + } else + ret = CY_AS_ERROR_INVALID_RESPONSE; + + cb_ms((cy_as_device_handle)dev_p, dev_p->storage_bus_index, + dev_p->storage_device_index, + (dev_p->storage_unit | pendingblocks), + dev_p->storage_block_addr, dev_p->storage_oper, ret); + } else + dev_p->storage_error = ret; +} + + +cy_as_return_status_t +cy_as_sdio_extended_i_o_async( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint32_t address, + uint8_t misc_buf, + uint16_t argument, + uint8_t is_write, + uint8_t *data_p, + cy_as_storage_callback callback) +{ + + uint32_t mask; + uint32_t dmasize; + cy_as_ll_request_response *req_p , *reply_p; + uint8_t reqtype; + cy_as_end_point_number_t ep; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_device *dev_p = (cy_as_device *)handle; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized(handle, + bus, n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + if (cy_as_sdio_check_function_suspended(handle, bus, n_function_no)) + return CY_AS_ERROR_FUNCTION_SUSPENDED; + + if (callback == 0) + return CY_AS_ERROR_NULL_CALLBACK; + + /* We are supposed to return sucess if the number of + * blocks is zero + */ + if (((misc_buf&CY_SDIO_BLOCKMODE) != 0) && (argument == 0)) { + callback(handle, bus, device, n_function_no, address, + ((is_write) ? cy_as_op_write : cy_as_op_read), + CY_AS_ERROR_SUCCESS); + return CY_AS_ERROR_SUCCESS; + } + + + /* + * since async operations can be triggered by interrupt + * code, we must insure that we do not get multiple async + * operations going at one time and protect this test and + * set operation from interrupts. + */ + mask = cy_as_hal_disable_interrupts(); + if ((cy_as_device_is_storage_async_pending(dev_p)) || + (dev_p->storage_wait)) { + cy_as_hal_enable_interrupts(mask); + return CY_AS_ERROR_ASYNC_PENDING; + } + cy_as_device_set_storage_async_pending(dev_p); + cy_as_hal_enable_interrupts(mask); + + + /* + * storage information about the currently + * outstanding request + */ + dev_p->storage_cb_ms = callback; + dev_p->storage_bus_index = bus; + dev_p->storage_device_index = device; + dev_p->storage_unit = n_function_no; + dev_p->storage_block_addr = address; + + if (is_write == cy_true) { + reqtype = CY_RQT_SDIO_WRITE_EXTENDED; + ep = dev_p->storage_write_endpoint; + } else { + reqtype = CY_RQT_SDIO_READ_EXTENDED; + ep = dev_p->storage_read_endpoint; + } + + /* Initialise the request to send to the West Bridge. */ + req_p = dev_p->storage_rw_req_p; + cy_as_ll_init_request(req_p, reqtype, + CY_RQT_STORAGE_RQT_CONTEXT, 3); + + /* Initialise the space for reply from the West Bridge. */ + reply_p = dev_p->storage_rw_resp_p; + cy_as_ll_init_response(reply_p, 2); + + if (!(misc_buf&CY_SDIO_BLOCKMODE)) { + if (argument > + dev_p->sdiocard[bus].function[n_function_no-1].blocksize) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + + } else { + if (argument > 511) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + } + + if (argument == 512) + argument = 0; + dmasize = ((misc_buf&CY_SDIO_BLOCKMODE) != 0) ? + dev_p->sdiocard[bus].function[n_function_no-1].blocksize * + argument : argument; + + /* Setup the DMA request and adjust the storage + * operation if we are reading */ + if (reqtype == CY_RQT_SDIO_READ_EXTENDED) { + ret = cy_as_dma_queue_request(dev_p, ep, + (void *)data_p, dmasize , cy_false, cy_true, + cy_as_async_storage_callback); + dev_p->storage_oper = cy_as_op_read; + } else if (reqtype == CY_RQT_SDIO_WRITE_EXTENDED) { + ret = cy_as_dma_queue_request(dev_p, ep, (void *)data_p, + dmasize, cy_false, cy_false, cy_as_async_storage_callback); + dev_p->storage_oper = cy_as_op_write; + } + + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_device_clear_storage_async_pending(dev_p); + return ret; + } + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, n_function_no)); + cy_as_ll_request_response__set_word(req_p, 1, + ((uint16_t)n_function_no) << 12 | + ((uint16_t)(misc_buf & (CY_SDIO_BLOCKMODE | CY_SDIO_OP_INCR))) + << 9 | (uint16_t)(address>>7) | + ((is_write == cy_true) ? 0x8000 : 0x0000)); + cy_as_ll_request_response__set_word(req_p, 2, + ((uint16_t)(address&0x0000ffff) << 9) | argument); + + + /* Send the request and wait for completion of storage request */ + dev_p->storage_wait = cy_true; + ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_true, + cy_as_sdio_async_reply_callback); + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED); + cy_as_device_clear_storage_async_pending(dev_p); + } else { + cy_as_dma_kick_start(dev_p, ep); + } + + return ret; +} + +/* CMD53 Extended Read*/ +cy_as_return_status_t +cy_as_sdio_extended_read( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint32_t address, + uint8_t misc_buf, + uint16_t argument, + uint8_t *data_p, + cy_as_sdio_callback callback) +{ + if (callback == 0) + return cy_as_sdio_extended_i_o(handle, bus, device, + n_function_no, address, misc_buf, argument, + cy_false, data_p, 0); + + return cy_as_sdio_extended_i_o_async(handle, bus, device, + n_function_no, address, misc_buf, argument, cy_false, + data_p, callback); +} + +/* CMD53 Extended Write*/ +cy_as_return_status_t +cy_as_sdio_extended_write( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint32_t address, + uint8_t misc_buf, + uint16_t argument, + uint8_t *data_p, + cy_as_sdio_callback callback) +{ + if (callback == 0) + return cy_as_sdio_extended_i_o(handle, bus, device, + n_function_no, address, misc_buf, argument, cy_true, + data_p, 0); + + return cy_as_sdio_extended_i_o_async(handle, bus, device, + n_function_no, address, misc_buf, argument, cy_true, + data_p, callback); +} + + +/* Read the CIS info tuples for the given function and Tuple ID*/ +cy_as_return_status_t +cy_as_sdio_get_c_i_s_info( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint16_t tuple_id, + uint8_t *data_p) +{ + + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint16_t resp_data; + cy_as_context *ctxt_p; + uint32_t loopcount = 200; + + cy_as_device *dev_p = (cy_as_device *)handle; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized(handle, bus, 0))) + return CY_AS_ERROR_INVALID_FUNCTION; + + if ((cy_as_device_is_storage_async_pending(dev_p)) || + (dev_p->storage_wait)) + return CY_AS_ERROR_ASYNC_PENDING; + + + /* Initialise the request to send to the Antioch. */ + req_p = dev_p->storage_rw_req_p; + cy_as_ll_init_request(req_p, CY_RQT_SDIO_GET_TUPLE, + CY_RQT_STORAGE_RQT_CONTEXT, 2); + + /* Initialise the space for reply from the Antioch. */ + reply_p = dev_p->storage_rw_resp_p; + cy_as_ll_init_response(reply_p, 3); + + /* Setup the DMA request */ + ret = cy_as_dma_queue_request(dev_p, dev_p->storage_read_endpoint, + data_p+1, 255, cy_false, cy_true, cy_as_sync_storage_callback); + + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, n_function_no)); + + /* Set tuple id to fetch. */ + cy_as_ll_request_response__set_word(req_p, 1, tuple_id<<8); + + /* Send the request and wait for completion of storage request */ + dev_p->storage_wait = cy_true; + ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_true, + cy_as_sdio_sync_reply_callback); + + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_dma_cancel(dev_p, + dev_p->storage_read_endpoint, CY_AS_ERROR_CANCELED); + } else { + /* Setup the DMA request */ + ctxt_p = dev_p->context[CY_RQT_STORAGE_RQT_CONTEXT]; + ret = cy_as_dma_drain_queue(dev_p, + dev_p->storage_read_endpoint, cy_true); + + while (loopcount-- > 0) { + if (dev_p->storage_wait == cy_false) + break; + cy_as_hal_sleep_on(&ctxt_p->channel, 10); + } + + if (dev_p->storage_wait == cy_true) { + dev_p->storage_wait = cy_false; + cy_as_ll_remove_request(dev_p, ctxt_p, req_p, cy_true); + return CY_AS_ERROR_TIMEOUT; + } + ret = dev_p->storage_error; + + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (cy_as_ll_request_response__get_code + (dev_p->storage_rw_resp_p) == CY_RESP_SDIO_GET_TUPLE) { + resp_data = cy_as_ll_request_response__get_word + (reply_p, 0); + if (resp_data) { + ret = CY_AS_ERROR_INVALID_REQUEST; + } else if (data_p != 0) + *(uint8_t *)data_p = (uint8_t) + (cy_as_ll_request_response__get_word + (reply_p, 0)&0x00ff); + } else { + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + } + return ret; +} + +/*Query Device*/ +cy_as_return_status_t +cy_as_sdio_query_card( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + cy_as_sdio_card *data_p) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + + uint8_t resp_type; + cy_as_device *dev_p = (cy_as_device *)handle; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + /* Allocating memory to the SDIO device structure in dev_p */ + + cy_as_hal_mem_set(&dev_p->sdiocard[bus], 0, sizeof(cy_as_sdio_device)); + + req_p = cy_as_ll_create_request(dev_p, CY_RQT_SDIO_QUERY_CARD, + CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, 0)); + + reply_p = cy_as_ll_create_response(dev_p, 5); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + ret = cy_as_ll_send_request_wait_reply(dev_p, + req_p, reply_p); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + resp_type = cy_as_ll_request_response__get_code(reply_p); + if (resp_type == CY_RESP_SDIO_QUERY_CARD) { + dev_p->sdiocard[bus].card.num_functions = + (uint8_t)((reply_p->data[0]&0xff00)>>8); + dev_p->sdiocard[bus].card.memory_present = + (uint8_t)reply_p->data[0]&0x0001; + dev_p->sdiocard[bus].card.manufacturer__id = + reply_p->data[1]; + dev_p->sdiocard[bus].card.manufacturer_info = + reply_p->data[2]; + dev_p->sdiocard[bus].card.blocksize = + reply_p->data[3]; + dev_p->sdiocard[bus].card.maxblocksize = + reply_p->data[3]; + dev_p->sdiocard[bus].card.card_capability = + (uint8_t)((reply_p->data[4]&0xff00)>>8); + dev_p->sdiocard[bus].card.sdio_version = + (uint8_t)(reply_p->data[4]&0x00ff); + dev_p->sdiocard[bus].function_init_map = 0x01; + data_p->num_functions = + dev_p->sdiocard[bus].card.num_functions; + data_p->memory_present = + dev_p->sdiocard[bus].card.memory_present; + data_p->manufacturer__id = + dev_p->sdiocard[bus].card.manufacturer__id; + data_p->manufacturer_info = + dev_p->sdiocard[bus].card.manufacturer_info; + data_p->blocksize = dev_p->sdiocard[bus].card.blocksize; + data_p->maxblocksize = + dev_p->sdiocard[bus].card.maxblocksize; + data_p->card_capability = + dev_p->sdiocard[bus].card.card_capability; + data_p->sdio_version = + dev_p->sdiocard[bus].card.sdio_version; + } else { + if (resp_type == CY_RESP_SUCCESS_FAILURE) + ret = cy_as_ll_request_response__get_word(reply_p, 0); + else + ret = CY_AS_ERROR_INVALID_RESPONSE; + } +destroy: + if (req_p != 0) + cy_as_ll_destroy_request(dev_p, req_p); + if (reply_p != 0) + cy_as_ll_destroy_response(dev_p, reply_p); + return ret; +} + +/*Reset SDIO card. */ +cy_as_return_status_t +cy_as_sdio_reset_card( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device) +{ + + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t resp_type; + cy_as_device *dev_p = (cy_as_device *)handle; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (dev_p->sdiocard != 0) { + dev_p->sdiocard[bus].function_init_map = 0; + dev_p->sdiocard[bus].function_suspended_map = 0; + } + + req_p = cy_as_ll_create_request(dev_p, CY_RQT_SDIO_RESET_DEV, + CY_RQT_STORAGE_RQT_CONTEXT, 1); + + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /*Setup mailbox */ + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, 0)); + + reply_p = cy_as_ll_create_response(dev_p, 2); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + ret = cy_as_ll_send_request_wait_reply(dev_p, + req_p, reply_p); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + resp_type = cy_as_ll_request_response__get_code(reply_p); + + if (resp_type == CY_RESP_SUCCESS_FAILURE) { + ret = cy_as_ll_request_response__get_word(reply_p, 0); + if (ret == CY_AS_ERROR_SUCCESS) + ret = cy_as_sdio_query_card(handle, bus, device, 0); + } else + ret = CY_AS_ERROR_INVALID_RESPONSE; + +destroy: + if (req_p != 0) + cy_as_ll_destroy_request(dev_p, req_p); + if (reply_p != 0) + cy_as_ll_destroy_response(dev_p, reply_p); + return ret; +} + +/* Initialise an IO function*/ +cy_as_return_status_t +cy_as_sdio_init_function( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint8_t misc_buf) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t resp_type; + cy_as_device *dev_p = (cy_as_device *)handle; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized + (handle, bus, 0))) + return CY_AS_ERROR_NOT_RUNNING; + + if ((cy_as_sdio_check_function_initialized + (handle, bus, n_function_no))) { + if (misc_buf&CY_SDIO_FORCE_INIT) + dev_p->sdiocard[bus].function_init_map &= + (~(1 << n_function_no)); + else + return CY_AS_ERROR_ALREADY_RUNNING; + } + + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_SDIO_INIT_FUNCTION, CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, n_function_no)); + + reply_p = cy_as_ll_create_response(dev_p, 5); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + resp_type = cy_as_ll_request_response__get_code(reply_p); + + if (resp_type == CY_RESP_SDIO_INIT_FUNCTION) { + dev_p->sdiocard[bus].function[n_function_no-1].function_code = + (uint8_t)((reply_p->data[0]&0xff00)>>8); + dev_p->sdiocard[bus].function[n_function_no-1]. + extended_func_code = (uint8_t)reply_p->data[0]&0x00ff; + dev_p->sdiocard[bus].function[n_function_no-1].blocksize = + reply_p->data[1]; + dev_p->sdiocard[bus].function[n_function_no-1]. + maxblocksize = reply_p->data[1]; + dev_p->sdiocard[bus].function[n_function_no-1].card_psn = + (uint32_t)(reply_p->data[2])<<16; + dev_p->sdiocard[bus].function[n_function_no-1].card_psn |= + (uint32_t)(reply_p->data[3]); + dev_p->sdiocard[bus].function[n_function_no-1].csa_bits = + (uint8_t)((reply_p->data[4]&0xff00)>>8); + dev_p->sdiocard[bus].function[n_function_no-1].wakeup_support = + (uint8_t)(reply_p->data[4]&0x0001); + dev_p->sdiocard[bus].function_init_map |= (1 << n_function_no); + cy_as_sdio_clear_function_suspended(handle, bus, n_function_no); + + } else { + if (resp_type == CY_RESP_SUCCESS_FAILURE) + ret = cy_as_ll_request_response__get_word(reply_p, 0); + else + ret = CY_AS_ERROR_INVALID_FUNCTION; + } + +destroy: + if (req_p != 0) + cy_as_ll_destroy_request(dev_p, req_p); + if (reply_p != 0) + cy_as_ll_destroy_response(dev_p, reply_p); + return ret; +} + +/*Query individual functions. */ +cy_as_return_status_t +cy_as_sdio_query_function( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + cy_as_sdio_func *data_p) +{ + cy_as_device *dev_p = (cy_as_device *)handle; + cy_as_return_status_t ret; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized(handle, + bus, n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + + data_p->blocksize = + dev_p->sdiocard[bus].function[n_function_no-1].blocksize; + data_p->card_psn = + dev_p->sdiocard[bus].function[n_function_no-1].card_psn; + data_p->csa_bits = + dev_p->sdiocard[bus].function[n_function_no-1].csa_bits; + data_p->extended_func_code = + dev_p->sdiocard[bus].function[n_function_no-1]. + extended_func_code; + data_p->function_code = + dev_p->sdiocard[bus].function[n_function_no-1].function_code; + data_p->maxblocksize = + dev_p->sdiocard[bus].function[n_function_no-1].maxblocksize; + data_p->wakeup_support = + dev_p->sdiocard[bus].function[n_function_no-1].wakeup_support; + + return CY_AS_ERROR_SUCCESS; +} + +/* Abort the Current Extended IO Operation*/ +cy_as_return_status_t +cy_as_sdio_abort_function( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + uint8_t resp_type; + cy_as_device *dev_p = (cy_as_device *)handle; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized(handle, + bus, n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + + if ((cy_as_device_is_storage_async_pending(dev_p)) || + (dev_p->storage_wait)) { + if (!(cy_as_sdio_get_card_capability(handle, bus) & + CY_SDIO_SDC)) + return CY_AS_ERROR_INVALID_COMMAND; + } + + req_p = cy_as_ll_create_request(dev_p, CY_RQT_SDIO_ABORT_IO, + CY_RQT_GENERAL_RQT_CONTEXT, 1); + + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /*Setup mailbox */ + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, n_function_no)); + + reply_p = cy_as_ll_create_response(dev_p, 2); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + resp_type = cy_as_ll_request_response__get_code(reply_p); + + if (resp_type == CY_RESP_SUCCESS_FAILURE) + ret = cy_as_ll_request_response__get_word(reply_p, 0); + else + ret = CY_AS_ERROR_INVALID_RESPONSE; + + +destroy: + if (req_p != 0) + cy_as_ll_destroy_request(dev_p, req_p); + if (reply_p != 0) + cy_as_ll_destroy_response(dev_p, reply_p); + return ret; +} + +/* Suspend IO to current function*/ +cy_as_return_status_t +cy_as_sdio_suspend( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS; + cy_as_device *dev_p = (cy_as_device *)handle; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized(handle, bus, + n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + if (!(cy_as_sdio_check_support_bus_suspend(handle, bus))) + return CY_AS_ERROR_INVALID_FUNCTION; + if (!(cy_as_sdio_get_card_capability(handle, bus) & CY_SDIO_SDC)) + return CY_AS_ERROR_INVALID_FUNCTION; + if (cy_as_sdio_check_function_suspended(handle, bus, n_function_no)) + return CY_AS_ERROR_FUNCTION_SUSPENDED; + + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_SDIO_SUSPEND, CY_RQT_GENERAL_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /*Setup mailbox */ + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, n_function_no)); + + reply_p = cy_as_ll_create_response(dev_p, 2); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + + if (ret == CY_AS_ERROR_SUCCESS) { + ret = cy_as_ll_request_response__get_code(reply_p); + cy_as_sdio_set_function_suspended(handle, bus, n_function_no); + } + + if (req_p != 0) + cy_as_ll_destroy_request(dev_p, req_p); + if (reply_p != 0) + cy_as_ll_destroy_response(dev_p, reply_p); + + return ret; +} + +/*Resume suspended function*/ +cy_as_return_status_t +cy_as_sdio_resume( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + cy_as_oper_type op, + uint8_t misc_buf, + uint16_t pendingblockcount, + uint8_t *data_p + ) +{ + cy_as_ll_request_response *req_p , *reply_p; + cy_as_return_status_t resp_data, ret = CY_AS_ERROR_SUCCESS; + cy_as_device *dev_p = (cy_as_device *)handle; + + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized + (handle, bus, n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + + /* If suspend resume is not supported return */ + if (!(cy_as_sdio_check_support_bus_suspend(handle, bus))) + return CY_AS_ERROR_INVALID_FUNCTION; + + /* if the function is not suspended return. */ + if (!(cy_as_sdio_check_function_suspended + (handle, bus, n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + + req_p = cy_as_ll_create_request(dev_p, + CY_RQT_SDIO_RESUME, CY_RQT_STORAGE_RQT_CONTEXT, 1); + if (req_p == 0) + return CY_AS_ERROR_OUT_OF_MEMORY; + + /*Setup mailbox */ + cy_as_ll_request_response__set_word(req_p, 0, + create_address(bus, (uint8_t)device, n_function_no)); + + reply_p = cy_as_ll_create_response(dev_p, 2); + if (reply_p == 0) { + cy_as_ll_destroy_request(dev_p, req_p); + return CY_AS_ERROR_OUT_OF_MEMORY; + } + ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p); + + if (ret != CY_AS_ERROR_SUCCESS) + goto destroy; + + if (cy_as_ll_request_response__get_code(reply_p) == + CY_RESP_SDIO_RESUME) { + resp_data = cy_as_ll_request_response__get_word(reply_p, 0); + if (resp_data & 0x00ff) { + /* Send extended read request to resume the read. */ + if (op == cy_as_op_read) { + ret = cy_as_sdio_extended_i_o(handle, bus, + device, n_function_no, 0, misc_buf, + pendingblockcount, cy_false, data_p, 1); + } else { + ret = cy_as_sdio_extended_i_o(handle, bus, + device, n_function_no, 0, misc_buf, + pendingblockcount, cy_true, data_p, 1); + } + } else { + ret = CY_AS_ERROR_SUCCESS; + } + } else { + ret = CY_AS_ERROR_INVALID_RESPONSE; + } + +destroy: + cy_as_sdio_clear_function_suspended(handle, bus, n_function_no); + if (req_p != 0) + cy_as_ll_destroy_request(dev_p, req_p); + if (reply_p != 0) + cy_as_ll_destroy_response(dev_p, reply_p); + return ret; + +} + +/*Set function blocksize. Size cannot exceed max + * block size for the function*/ +cy_as_return_status_t +cy_as_sdio_set_blocksize( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no, + uint16_t blocksize) +{ + cy_as_return_status_t ret; + cy_as_device *dev_p = (cy_as_device *)handle; + ret = cy_as_sdio_device_check(dev_p, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized + (handle, bus, n_function_no))) + return CY_AS_ERROR_INVALID_FUNCTION; + if (n_function_no == 0) { + if (blocksize > cy_as_sdio_get_card_max_blocksize(handle, bus)) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + else if (blocksize == cy_as_sdio_get_card_blocksize + (handle, bus)) + return CY_AS_ERROR_SUCCESS; + } else { + if (blocksize > + cy_as_sdio_get_function_max_blocksize(handle, + bus, n_function_no)) + return CY_AS_ERROR_INVALID_BLOCKSIZE; + else if (blocksize == + cy_as_sdio_get_function_blocksize(handle, + bus, n_function_no)) + return CY_AS_ERROR_SUCCESS; + } + + ret = cy_as_sdio_direct_write(handle, bus, device, 0, + (uint16_t)(n_function_no << 8) | + 0x10, 0, blocksize & 0x00ff, 0); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + ret = cy_as_sdio_direct_write(handle, bus, device, 0, + (uint16_t)(n_function_no << 8) | + 0x11, 0, (blocksize & 0xff00) >> 8, 0); + + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (n_function_no == 0) + cy_as_sdio_set_card_block_size(handle, bus, blocksize); + else + cy_as_sdio_set_function_block_size(handle, + bus, n_function_no, blocksize); + return ret; +} + +/* Deinitialize an SDIO function*/ +cy_as_return_status_t +cy_as_sdio_de_init_function( + cy_as_device_handle handle, + cy_as_bus_number_t bus, + uint32_t device, + uint8_t n_function_no) +{ + cy_as_return_status_t ret; + uint8_t temp; + + if (n_function_no == 0) + return CY_AS_ERROR_INVALID_FUNCTION; + + ret = cy_as_sdio_device_check((cy_as_device *)handle, bus, device); + if (ret != CY_AS_ERROR_SUCCESS) + return ret; + + if (!(cy_as_sdio_check_function_initialized + (handle, bus, n_function_no))) + return CY_AS_ERROR_SUCCESS; + + temp = (uint8_t)(((cy_as_device *)handle)->sdiocard[bus]. + function_init_map & (~(1 << n_function_no))); + + cy_as_sdio_direct_write(handle, bus, device, 0, 0x02, 0, temp, 0); + + ((cy_as_device *)handle)->sdiocard[bus].function_init_map &= + (~(1 << n_function_no)); + + return CY_AS_ERROR_SUCCESS; +} + + +/*[]*/ |