blob: 083d869e57c65dedd604e2b68bac321e2e887f8e [file] [log] [blame]
/* 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;
}
/*[]*/