Merged bootstrp reversion from GCC_MERGE branch as it's affecting mainstream S^3 builds too
/* Cypress West Bridge API source file (cyasusb.c)
## ===========================
##
## Copyright Cypress Semiconductor Corporation, 2006-2009,
## All Rights Reserved
## UNPUBLISHED, LICENSED SOFTWARE.
##
## CONFIDENTIAL AND PROPRIETARY INFORMATION
## WHICH IS THE PROPERTY OF CYPRESS.
##
## Use of this file is governed
## by the license agreement included in the file
##
## <install>/license/license.txt
##
## where <install> is the Cypress software
## installation root directory path.
##
## ===========================
*/
#include "cyashal.h"
#include "cyasusb.h"
#include "cyaserr.h"
#include "cyasdma.h"
#include "cyaslowlevel.h"
#include "cyaslep2pep.h"
#include "cyasregs.h"
#include "cyasstorage.h"
extern CyAsMediaType
CyAsStorageGetMediaFromAddress(uint16_t v) ;
extern CyAsBusNumber_t
CyAsStorageGetBusFromAddress(uint16_t v) ;
extern uint32_t
CyAsStorageGetDeviceFromAddress(uint16_t v) ;
static CyAsReturnStatus_t
CyAsUsbAckSetupPacket(
CyAsDeviceHandle handle, /* Handle to the West Bridge device */
CyAsFunctionCallback cb, /* The callback if async call */
uint32_t client /* Client supplied data */
) ;
static void
CyAsUsbFuncCallback(
CyAsDevice *dev_p,
uint8_t context,
CyAsLLRequestResponse *rqt,
CyAsLLRequestResponse *resp,
CyAsReturnStatus_t ret) ;
/*
* Reset the USB EP0 state
*/
static void
CyAsUsbResetEP0State(CyAsDevice *dev_p)
{
CyAsLogDebugMessage(6, "CyAsUsbResetEP0State called") ;
CyAsDeviceClearAckDelayed(dev_p) ;
CyAsDeviceClearSetupPacket(dev_p) ;
if (CyAsDeviceIsUsbAsyncPending(dev_p, 0))
CyAsUsbCancelAsync((CyAsDeviceHandle)dev_p, 0) ;
dev_p->usb_pending_buffer = 0 ;
}
/*
* External function to map logical endpoints to physical endpoints
*/
static CyAsReturnStatus_t
IsUsbActive(CyAsDevice *dev_p)
{
if (!CyAsDeviceIsConfigured(dev_p))
return CY_AS_ERROR_NOT_CONFIGURED ;
if (!CyAsDeviceIsFirmwareLoaded(dev_p))
return CY_AS_ERROR_NO_FIRMWARE ;
if (dev_p->usb_count == 0)
return CY_AS_ERROR_NOT_RUNNING ;
if (CyAsDeviceIsInSuspendMode(dev_p))
return CY_AS_ERROR_IN_SUSPEND ;
return CY_AS_ERROR_SUCCESS ;
}
static void
UsbAckCallback(CyAsDeviceHandle h,
CyAsReturnStatus_t status,
uint32_t client,
CyAsFunctCBType type,
void* data)
{
CyAsDevice *dev_p = (CyAsDevice *)h ;
(void)client ;
(void)status ;
(void)data ;
CyAsHalAssert(type == CY_FUNCT_CB_NODATA) ;
if (dev_p->usb_pending_buffer)
{
CyAsUsbIoCallback cb ;
cb = dev_p->usb_cb[0] ;
dev_p->usb_cb[0] = 0 ;
CyAsDeviceClearUsbAsyncPending(dev_p, 0) ;
if (cb)
cb(h, 0, dev_p->usb_pending_size, dev_p->usb_pending_buffer, dev_p->usb_error) ;
dev_p->usb_pending_buffer = 0 ;
}
CyAsDeviceClearSetupPacket(dev_p) ;
}
static void
MyUsbRequestCallbackUsbEvent(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p)
{
uint16_t ev ;
uint16_t val ;
CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ;
ev = CyAsLLRequestResponse_GetWord(req_p, 0) ;
switch(ev)
{
case 0: /* Reserved */
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_INVALID_REQUEST, 0) ;
break ;
case 1: /* Reserved */
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_INVALID_REQUEST, 0) ;
break ;
case 2: /* USB Suspend */
dev_p->usb_last_event = CyAsEventUsbSuspend ;
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbSuspend, 0) ;
else if (dev_p->usb_event_cb)
dev_p->usb_event_cb(h, CyAsEventUsbSuspend, 0) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
break;
case 3: /* USB Resume */
dev_p->usb_last_event = CyAsEventUsbResume ;
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbResume, 0) ;
else if (dev_p->usb_event_cb)
dev_p->usb_event_cb(h, CyAsEventUsbResume, 0) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
break ;
case 4: /* USB Reset */
/*
* If we get a USB reset, the USB host did not understand our response
* or we timed out for some reason. Reset our internal state to be ready for
* another set of enumeration based requests.
*/
if (CyAsDeviceIsAckDelayed(dev_p))
{
CyAsUsbResetEP0State(dev_p) ;
}
dev_p->usb_last_event = CyAsEventUsbReset ;
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbReset, 0) ;
else if (dev_p->usb_event_cb)
dev_p->usb_event_cb(h, CyAsEventUsbReset, 0) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
CyAsDeviceClearUsbHighSpeed(dev_p) ;
CyAsUsbSetDmaSizes(dev_p) ;
dev_p->usb_max_tx_size = 0x40 ;
CyAsDmaSetMaxDmaSize(dev_p, 0x06, 0x40) ;
break ;
case 5: /* USB Set Configuration */
val = CyAsLLRequestResponse_GetWord(req_p, 1) ; /* The configuration to set */
dev_p->usb_last_event = CyAsEventUsbSetConfig ;
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbSetConfig, &val) ;
else if (dev_p->usb_event_cb)
dev_p->usb_event_cb(h, CyAsEventUsbSetConfig, &val) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
break ;
case 6: /* USB Speed change */
val = CyAsLLRequestResponse_GetWord(req_p, 1) ; /* Connect speed */
dev_p->usb_last_event = CyAsEventUsbSpeedChange ;
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbSpeedChange, &val) ;
else if (dev_p->usb_event_cb)
dev_p->usb_event_cb(h, CyAsEventUsbSpeedChange, &val) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
CyAsDeviceSetUsbHighSpeed(dev_p) ;
CyAsUsbSetDmaSizes(dev_p) ;
dev_p->usb_max_tx_size = 0x200 ;
CyAsDmaSetMaxDmaSize(dev_p, 0x06, 0x200) ;
break ;
case 7: /* USB Clear Feature */
val = CyAsLLRequestResponse_GetWord(req_p, 1) ; /* EP Number */
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbClearFeature, &val) ;
if (dev_p->usb_event_cb)
dev_p->usb_event_cb(h, CyAsEventUsbClearFeature, &val) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
break ;
default:
CyAsHalPrintMessage("Invalid event type\n") ;
CyAsLLSendDataResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_RESP_USB_INVALID_EVENT, sizeof(ev), &ev) ;
break ;
}
}
static void
MyUsbRequestCallbackUsbData(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p)
{
CyAsEndPointNumber_t ep ;
uint8_t type ;
uint16_t len ;
uint16_t val ;
CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ;
val = CyAsLLRequestResponse_GetWord(req_p, 0) ;
ep = (CyAsEndPointNumber_t)((val >> 13) & 0x01) ;
len = (val & 0x1ff) ;
CyAsHalAssert(len <= 64) ;
CyAsLLRequestResponse_Unpack(req_p, 1, len, dev_p->usb_ep_data) ;
type = (uint8_t)((val >> 14) & 0x03) ;
if (type == 0)
{
if (CyAsDeviceIsAckDelayed(dev_p))
{
/*
* A setup packet has arrived while we are processing a previous setup packet.
* Reset our state with respect to EP0 to be ready to process the new packet.
*/
CyAsUsbResetEP0State(dev_p) ;
}
if (len != 8)
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_INVALID_REQUEST, 0) ;
else
{
CyAsDeviceClearEp0Stalled(dev_p) ;
CyAsDeviceSetSetupPacket(dev_p) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbSetupPacket, dev_p->usb_ep_data) ;
else
dev_p->usb_event_cb(h, CyAsEventUsbSetupPacket, dev_p->usb_ep_data) ;
if ((!CyAsDeviceIsAckDelayed(dev_p)) && (!CyAsDeviceIsEp0Stalled(dev_p)))
{
CyAsUsbAckSetupPacket(h, UsbAckCallback, 0) ;
}
}
}
else if (type == 2)
{
if (len != 0)
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_INVALID_REQUEST, 0) ;
else
{
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbStatusPacket, 0) ;
else
dev_p->usb_event_cb(h, CyAsEventUsbStatusPacket, 0) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
}
}
else if (type == 1)
{
/*
* We need to hand the data associated with these endpoints to the DMA
* module.
*/
CyAsDmaReceivedData(dev_p, ep, len, dev_p->usb_ep_data) ;
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
}
}
static void
MyUsbRequestCallbackInquiry(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p)
{
CyAsUsbInquiryData_dep cbdata ;
CyAsUsbInquiryData cbdata_ms ;
void *data ;
uint16_t val ;
CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ;
uint8_t def_inq_data[64] ;
uint8_t evpd ;
uint8_t codepage ;
CyBool updated ;
uint16_t length ;
CyAsBusNumber_t bus ;
uint32_t device ;
CyAsMediaType media ;
val = CyAsLLRequestResponse_GetWord(req_p, 0) ;
bus = CyAsStorageGetBusFromAddress(val) ;
device = CyAsStorageGetDeviceFromAddress(val) ;
media = CyAsStorageGetMediaFromAddress(val) ;
val = CyAsLLRequestResponse_GetWord(req_p, 1) ;
evpd = (uint8_t)((val >> 8) & 0x01) ;
codepage = (uint8_t)(val & 0xff) ;
length = CyAsLLRequestResponse_GetWord(req_p, 2) ;
data = (void *)def_inq_data ;
updated = CyFalse ;
if (dev_p->usb_event_cb_ms)
{
cbdata_ms.bus = bus ;
cbdata_ms.device = device ;
cbdata_ms.updated = updated ;
cbdata_ms.evpd = evpd ;
cbdata_ms.codepage = codepage ;
cbdata_ms.length = length ;
cbdata_ms.data = data ;
CyAsHalAssert(cbdata_ms.length <= sizeof(def_inq_data)) ;
CyAsLLRequestResponse_Unpack(req_p, 3, cbdata_ms.length, cbdata_ms.data) ;
dev_p->usb_event_cb_ms(h, CyAsEventUsbInquiryBefore, &cbdata_ms) ;
updated = cbdata_ms.updated;
data = cbdata_ms.data ;
length = cbdata_ms.length ;
}
else if (dev_p->usb_event_cb)
{
cbdata.media = media ;
cbdata.updated = updated ;
cbdata.evpd = evpd ;
cbdata.codepage = codepage ;
cbdata.length = length ;
cbdata.data = data ;
CyAsHalAssert(cbdata.length <= sizeof(def_inq_data)) ;
CyAsLLRequestResponse_Unpack(req_p, 3, cbdata.length, cbdata.data) ;
dev_p->usb_event_cb(h, CyAsEventUsbInquiryBefore, &cbdata) ;
updated = cbdata.updated ;
data = cbdata.data ;
length = cbdata.length ;
}
if (updated && length > 192)
CyAsHalPrintMessage("An inquiry result from a CyAsEventUsbInquiryBefore event was greater than 192 bytes.") ;
/* Now send the reply with the data back to the West Bridge device */
if (updated && length <= 192)
{
/*
* The callback function modified the inquiry data, ship the data back
* to the West Bridge firmware.
*/
CyAsLLSendDataResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_RESP_INQUIRY_DATA, length, data) ;
}
else
{
/*
* The callback did not modify the data, just acknowledge that we
* processed the request
*/
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1) ;
}
if (dev_p->usb_event_cb_ms)
dev_p->usb_event_cb_ms(h, CyAsEventUsbInquiryAfter, &cbdata_ms) ;
else if (dev_p->usb_event_cb)
dev_p->usb_event_cb(h, CyAsEventUsbInquiryAfter, &cbdata) ;
}
static void
MyUsbRequestCallbackStartStop(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p)
{
CyAsBusNumber_t bus ;
CyAsMediaType media ;
uint32_t device ;
uint16_t val ;
if (dev_p->usb_event_cb_ms || dev_p->usb_event_cb)
{
CyBool loej ;
CyBool start ;
CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ;
val = CyAsLLRequestResponse_GetWord(req_p, 0) ;
bus = CyAsStorageGetBusFromAddress(val) ;
device = CyAsStorageGetDeviceFromAddress(val) ;
media = CyAsStorageGetMediaFromAddress(val) ;
val = CyAsLLRequestResponse_GetWord(req_p, 1) ;
loej = (val & 0x02) ? CyTrue : CyFalse ;
start = (val & 0x01) ? CyTrue: CyFalse ;
if (dev_p->usb_event_cb_ms)
{
CyAsUsbStartStopData cbdata_ms ;
cbdata_ms.bus = bus ;
cbdata_ms.device = device ;
cbdata_ms.loej = loej ;
cbdata_ms.start = start ;
dev_p->usb_event_cb_ms(h, CyAsEventUsbStartStop, &cbdata_ms) ;
}
else if (dev_p->usb_event_cb)
{
CyAsUsbStartStopData_dep cbdata ;
cbdata.media = media ;
cbdata.loej = loej ;
cbdata.start = start ;
dev_p->usb_event_cb(h, CyAsEventUsbStartStop, &cbdata) ;
}
}
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1) ;
}
static void
MyUsbRequestCallbackUknownCBW(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p)
{
uint16_t val ;
CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ;
uint8_t buf[16] ;
uint8_t response[4] ;
uint16_t reqlen ;
void *request ;
uint8_t status ;
uint8_t key ;
uint8_t asc ;
uint8_t ascq ;
val = CyAsLLRequestResponse_GetWord(req_p, 0) ;
status = 1 ; /* Failed by default */
key = 0x05 ; /* Invalid command */
asc = 0x20 ; /* Invalid command */
ascq = 0x00 ; /* Invalid command */
reqlen = CyAsLLRequestResponse_GetWord(req_p, 1) ;
request = buf ;
CyAsHalAssert(reqlen <= sizeof(buf)) ;
CyAsLLRequestResponse_Unpack(req_p, 2, reqlen, request) ;
if (dev_p->usb_event_cb_ms)
{
CyAsUsbUnknownCommandData cbdata_ms ;
cbdata_ms.bus = CyAsStorageGetBusFromAddress(val) ;
cbdata_ms.device = CyAsStorageGetDeviceFromAddress(val) ;
cbdata_ms.reqlen = reqlen ;
cbdata_ms.request = request ;
cbdata_ms.status = status ;
cbdata_ms.key = key ;
cbdata_ms.asc = asc ;
cbdata_ms.ascq = ascq ;
dev_p->usb_event_cb_ms(h, CyAsEventUsbUnknownStorage, &cbdata_ms) ;
status = cbdata_ms.status ;
key = cbdata_ms.key ;
asc = cbdata_ms.asc ;
ascq = cbdata_ms.ascq ;
}
else if (dev_p->usb_event_cb)
{
CyAsUsbUnknownCommandData_dep cbdata ;
cbdata.media = CyAsStorageGetMediaFromAddress(val) ;
cbdata.reqlen = reqlen ;
cbdata.request = request ;
cbdata.status = status ;
cbdata.key = key ;
cbdata.asc = asc ;
cbdata.ascq = ascq ;
dev_p->usb_event_cb(h, CyAsEventUsbUnknownStorage, &cbdata) ;
status = cbdata.status ;
key = cbdata.key ;
asc = cbdata.asc ;
ascq = cbdata.ascq ;
}
response[0] = status ;
response[1] = key ;
response[2] = asc ;
response[3] = ascq ;
CyAsLLSendDataResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_RESP_UNKNOWN_SCSI_COMMAND, sizeof(response), response) ;
}
static void
MyUsbRequestCallbackMSCProgress(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p)
{
uint16_t val1, val2 ;
CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ;
if ((dev_p->usb_event_cb) || (dev_p->usb_event_cb_ms))
{
CyAsMSCProgressData cbdata ;
val1 = CyAsLLRequestResponse_GetWord(req_p, 0) ;
val2 = CyAsLLRequestResponse_GetWord(req_p, 1) ;
cbdata.wr_count = (uint32_t)((val1 << 16) | val2) ;
val1 = CyAsLLRequestResponse_GetWord(req_p, 2) ;
val2 = CyAsLLRequestResponse_GetWord(req_p, 3) ;
cbdata.rd_count = (uint32_t)((val1 << 16) | val2) ;
if (dev_p->usb_event_cb)
dev_p->usb_event_cb(h, CyAsEventUsbMSCProgress, &cbdata) ;
else
dev_p->usb_event_cb_ms(h, CyAsEventUsbMSCProgress, &cbdata) ;
}
CyAsLLSendStatusResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ;
}
/*
* This function processes the requests delivered from the firmware within the West Bridge
* device that are delivered in the USB context. These requests generally are EP0 and
* EP1 related requests or USB events.
*/
static void
MyUsbRequestCallback(CyAsDevice *dev_p, uint8_t context, CyAsLLRequestResponse *req_p, CyAsLLRequestResponse *resp_p,
CyAsReturnStatus_t ret)
{
uint16_t val ;
uint8_t code = CyAsLLRequestResponse_GetCode(req_p) ;
(void)resp_p ;
(void)context ;
(void)ret ;
switch(code)
{
case CY_RQT_USB_EVENT:
MyUsbRequestCallbackUsbEvent(dev_p, req_p) ;
break ;
case CY_RQT_USB_EP_DATA:
dev_p->usb_last_event = CyAsEventUsbSetupPacket ;
MyUsbRequestCallbackUsbData(dev_p, req_p) ;
break ;
case CY_RQT_SCSI_INQUIRY_COMMAND:
dev_p->usb_last_event = CyAsEventUsbInquiryAfter ;
MyUsbRequestCallbackInquiry(dev_p, req_p) ;
break ;
case CY_RQT_SCSI_START_STOP_COMMAND:
dev_p->usb_last_event = CyAsEventUsbStartStop ;
MyUsbRequestCallbackStartStop(dev_p, req_p) ;
break ;
case CY_RQT_SCSI_UNKNOWN_COMMAND:
dev_p->usb_last_event = CyAsEventUsbUnknownStorage ;
MyUsbRequestCallbackUknownCBW(dev_p, req_p) ;
break ;
case CY_RQT_USB_ACTIVITY_UPDATE:
dev_p->usb_last_event = CyAsEventUsbMSCProgress ;
MyUsbRequestCallbackMSCProgress(dev_p, req_p) ;
break ;
default:
CyAsHalPrintMessage("Invalid request received on USB context\n") ;
val = req_p->box0 ;
CyAsLLSendDataResponse(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_RESP_INVALID_REQUEST, sizeof(val), &val) ;
break ;
}
}
static CyAsReturnStatus_t
MyHandleResponseUsbStart(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p,
CyAsReturnStatus_t ret)
{
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
/*
* Mark EP 0 and EP1 as 64 byte endpoints
*/
CyAsDmaSetMaxDmaSize(dev_p, 0, 64) ;
CyAsDmaSetMaxDmaSize(dev_p, 1, 64) ;
dev_p->usb_count++ ;
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
{
CyAsDestroyCBQueue(dev_p->usb_func_cbs) ;
CyAsLLRegisterRequestCallback(dev_p, CY_RQT_USB_RQT_CONTEXT, 0) ;
}
CyAsDeviceClearUSSPending(dev_p) ;
return ret ;
}
/*
* This function starts the USB stack. The stack is reference counted so if the stack is already
* started, this function just increments the count. If the stack has not been started, a start
* request is sent to the West Bridge device.
*
* Note: Starting the USB stack does not cause the USB signals to be connected to the USB pins. To do
* this and therefore initiate enumeration, CyAsUsbConnect() must be called.
*/
CyAsReturnStatus_t
CyAsUsbStart(CyAsDeviceHandle handle,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsLLRequestResponse *req_p, *reply_p ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbStart called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
if (!CyAsDeviceIsConfigured(dev_p))
return CY_AS_ERROR_NOT_CONFIGURED ;
if (!CyAsDeviceIsFirmwareLoaded(dev_p))
return CY_AS_ERROR_NO_FIRMWARE ;
if (CyAsDeviceIsInSuspendMode(dev_p))
return CY_AS_ERROR_IN_SUSPEND ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
if(CyAsDeviceIsUSSPending(dev_p))
return CY_AS_ERROR_STARTSTOP_PENDING ;
CyAsDeviceSetUSSPending(dev_p) ;
if (dev_p->usb_count == 0)
{
/*
* Since we are just starting the stack, mark USB as not connected to the
* remote host
*/
CyAsDeviceClearUsbConnected(dev_p) ;
dev_p->usb_phy_config = 0 ;
/* Queue for 1.0 Async Requests, kept for backwards compatibility */
dev_p->usb_func_cbs = CyAsCreateCBQueue(CYAS_USB_FUNC_CB) ;
if(dev_p->usb_func_cbs == 0)
{
CyAsDeviceClearUSSPending(dev_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
/* Reset the EP0 state */
CyAsUsbResetEP0State(dev_p) ;
/*
* We register here becuase the start request may cause events to occur before the
* response to the start request.
*/
CyAsLLRegisterRequestCallback(dev_p, CY_RQT_USB_RQT_CONTEXT, MyUsbRequestCallback) ;
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_START_USB, CY_RQT_USB_RQT_CONTEXT, 0) ;
if (req_p == 0)
{
CyAsDestroyCBQueue(dev_p->usb_func_cbs) ;
dev_p->usb_func_cbs = 0 ;
CyAsDeviceClearUSSPending(dev_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
/* Reserve space for the reply, the reply data will not exceed one word */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsDestroyCBQueue(dev_p->usb_func_cbs) ;
dev_p->usb_func_cbs = 0 ;
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsDeviceClearUSSPending(dev_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return MyHandleResponseUsbStart(dev_p, req_p, reply_p, ret) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_START,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
}
else
{
dev_p->usb_count++ ;
if (cb)
cb(handle, ret, client, CY_FUNCT_CB_USB_START, 0) ;
}
CyAsDeviceClearUSSPending(dev_p) ;
return ret ;
}
void
CyAsUsbReset(CyAsDevice *dev_p)
{
int i ;
CyAsDeviceClearUsbConnected(dev_p) ;
for(i = 0 ; i < sizeof(dev_p->usb_config)/sizeof(dev_p->usb_config[0]) ; i++)
{
/*
* Cancel all pending USB read/write operations, as it is possible
* that the USB stack comes up in a different configuration with a
* different set of endpoints.
*/
if (CyAsDeviceIsUsbAsyncPending(dev_p, i))
CyAsUsbCancelAsync(dev_p, (CyAsEndPointNumber_t)i) ;
dev_p->usb_cb[i] = 0 ;
dev_p->usb_config[i].enabled = CyFalse ;
}
dev_p->usb_phy_config = 0 ;
}
/*
* This function does all the API side clean-up associated with CyAsUsbStop,
* without any communication with firmware. This needs to be done when the
* device is being reset while the USB stack is active.
*/
void
CyAsUsbCleanup(CyAsDevice *dev_p)
{
if (dev_p->usb_count)
{
CyAsUsbResetEP0State(dev_p) ;
CyAsUsbReset(dev_p) ;
CyAsHalMemSet(dev_p->usb_config, 0, sizeof(dev_p->usb_config)) ;
CyAsDestroyCBQueue(dev_p->usb_func_cbs) ;
dev_p->usb_count = 0 ;
}
}
static CyAsReturnStatus_t
MyHandleResponseUsbStop(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p,
CyAsReturnStatus_t ret)
{
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
/*
* We sucessfully shutdown the stack, so decrement to make the count
* zero.
*/
CyAsUsbCleanup(dev_p) ;
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
CyAsLLRegisterRequestCallback(dev_p, CY_RQT_USB_RQT_CONTEXT, 0) ;
CyAsDeviceClearUSSPending(dev_p) ;
return ret ;
}
/*
* This function stops the USB stack. The USB stack is reference counted so first is reference count is
* decremented. If the reference count is then zero, a request is sent to the West Bridge device to stop the USB
* stack on the West Bridge device.
*/
CyAsReturnStatus_t
CyAsUsbStop(CyAsDeviceHandle handle,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsLLRequestResponse *req_p = 0, *reply_p = 0 ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbStop called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsUsbConnected(dev_p))
return CY_AS_ERROR_USB_CONNECTED ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
if(CyAsDeviceIsUSSPending(dev_p))
return CY_AS_ERROR_STARTSTOP_PENDING ;
CyAsDeviceSetUSSPending(dev_p) ;
if (dev_p->usb_count == 1)
{
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_STOP_USB, CY_RQT_USB_RQT_CONTEXT, 0) ;
if (req_p == 0)
{
ret = CY_AS_ERROR_OUT_OF_MEMORY ;
goto destroy ;
}
/* Reserve space for the reply, the reply data will not exceed one word */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
ret = CY_AS_ERROR_OUT_OF_MEMORY ;
goto destroy ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return MyHandleResponseUsbStop(dev_p, req_p, reply_p, ret) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_STOP,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
}
else if (dev_p->usb_count > 1)
{
/*
* Reset all LEPs to inactive state, after cleaning up any
* pending async read/write calls.
*/
CyAsUsbReset(dev_p) ;
dev_p->usb_count-- ;
if (cb)
cb(handle, ret, client, CY_FUNCT_CB_USB_STOP, 0) ;
}
CyAsDeviceClearUSSPending(dev_p) ;
return ret ;
}
/*
* This function registers a callback to be called when USB events are processed
*/
CyAsReturnStatus_t
CyAsUsbRegisterCallback(CyAsDeviceHandle handle, CyAsUsbEventCallback callback)
{
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbRegisterCallback called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
if (!CyAsDeviceIsConfigured(dev_p))
return CY_AS_ERROR_NOT_CONFIGURED ;
if (!CyAsDeviceIsFirmwareLoaded(dev_p))
return CY_AS_ERROR_NO_FIRMWARE ;
dev_p->usb_event_cb = NULL ;
dev_p->usb_event_cb_ms = callback ;
return CY_AS_ERROR_SUCCESS ;
}
static CyAsReturnStatus_t
MyHandleResponseNoData(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p)
{
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE)
ret = CY_AS_ERROR_INVALID_RESPONSE ;
else
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
static CyAsReturnStatus_t
MyHandleResponseConnect(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p,
CyAsReturnStatus_t ret)
{
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
if (ret == CY_AS_ERROR_SUCCESS)
CyAsDeviceSetUsbConnected(dev_p) ;
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
/*
* This method asks the West Bridge device to connect the internal USB D+ and D- signals to the USB
* pins, thus starting the enumeration processes if the external pins are connnected to a USB host.
* If the external pins are not connect to a USB host, enumeration will begin as soon as the USB
* pins are connected to a host.
*/
CyAsReturnStatus_t
CyAsUsbConnect(CyAsDeviceHandle handle,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbConnect called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* 1 = Connect request */
CyAsLLRequestResponse_SetWord(req_p, 0, 1) ;
/* Reserve space for the reply, the reply data will not exceed one word */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return MyHandleResponseConnect(dev_p, req_p, reply_p, ret) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_CONNECT,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
static CyAsReturnStatus_t
MyHandleResponseDisconnect(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p,
CyAsReturnStatus_t ret)
{
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
if (ret == CY_AS_ERROR_SUCCESS)
CyAsDeviceClearUsbConnected(dev_p) ;
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
/*
* This method forces a disconnect of the D+ and D- pins external to the West Bridge device from the
* D+ and D- signals internally, effectively disconnecting the West Bridge device from any connectec
* USB host.
*/
CyAsReturnStatus_t
CyAsUsbDisconnect(CyAsDeviceHandle handle,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbDisconnect called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
if (!CyAsDeviceIsUsbConnected(dev_p))
return CY_AS_ERROR_USB_NOT_CONNECTED ;
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
CyAsLLRequestResponse_SetWord(req_p, 0, 0) ;
/* Reserve space for the reply, the reply data will not exceed two bytes */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return MyHandleResponseDisconnect(dev_p, req_p, reply_p, ret) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_DISCONNECT,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
static CyAsReturnStatus_t
MyHandleResponseSetEnumConfig(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p)
{
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
if (ret == CY_AS_ERROR_SUCCESS)
{
/*
* We configured the West Bridge device and enumeration is going to happen
* on the P port processor. Now we must enable endpoint zero
*/
CyAsUsbEndPointConfig config ;
config.dir = CyAsUsbInOut ;
config.type = CyAsUsbControl ;
config.enabled = CyTrue ;
ret = CyAsUsbSetEndPointConfig((CyAsDeviceHandle*)dev_p, 0, &config) ;
}
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
/*
* This method sets how the USB is enumerated and should be called before the
* CyAsUsbConnect() is called.
*/
static CyAsReturnStatus_t
MyUsbSetEnumConfig(CyAsDevice *dev_p,
uint8_t bus_mask,
uint8_t media_mask,
CyBool use_antioch_enumeration,
uint8_t mass_storage_interface,
uint8_t mtp_interface,
CyBool mass_storage_callbacks,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
CyAsLogDebugMessage(6, "CyAsUsbSetEnumConfig called") ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsUsbConnected(dev_p))
return CY_AS_ERROR_USB_CONNECTED ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
/* if we are using MTP firmware: */
if (dev_p->is_mtp_firmware == 1)
{
if (mass_storage_interface != 0) /* we can not enemurate MSC */
return CY_AS_ERROR_INVALID_CONFIGURATION ;
if (bus_mask == 0)
{
if (mtp_interface != 0)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
}
else if (bus_mask == 2)
{
/* enable EP 1 as it will be used */
CyAsDmaEnableEndPoint(dev_p, 1, CyTrue, CyAsDirectionIn) ;
dev_p->usb_config[1].enabled = CyTrue ;
dev_p->usb_config[1].dir = CyAsUsbIn ;
dev_p->usb_config[1].type = CyAsUsbInt ;
}
else
{
return CY_AS_ERROR_INVALID_CONFIGURATION ;
}
}
else if (mtp_interface != 0) /* if we are not using MTP firmware, we can not enumerate MTP */
return CY_AS_ERROR_INVALID_CONFIGURATION ;
/*
* If we are not enumerating mass storage, we should not be providing an interface
* number.
*/
if (bus_mask == 0 && mass_storage_interface != 0)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
/*
* If we are going to use mtp_interface, bus mask must be 2.
*/
if (mtp_interface != 0 && bus_mask != 2)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 4) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* Marshal the structure */
CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)((media_mask << 8) | bus_mask)) ;
CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)use_antioch_enumeration) ;
CyAsLLRequestResponse_SetWord(req_p, 2, dev_p->is_mtp_firmware ? mtp_interface : mass_storage_interface) ;
CyAsLLRequestResponse_SetWord(req_p, 3, (uint16_t)mass_storage_callbacks) ;
/* Reserve space for the reply, the reply data will not exceed one word */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return MyHandleResponseSetEnumConfig(dev_p, req_p, reply_p) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_SETENUMCONFIG,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
/*
* This method sets how the USB is enumerated and should be called before the
* CyAsUsbConnect() is called.
*/
CyAsReturnStatus_t
CyAsUsbSetEnumConfig(CyAsDeviceHandle handle,
CyAsUsbEnumControl *config_p,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsDevice *dev_p = (CyAsDevice *)handle ;
uint8_t bus_mask, media_mask ;
uint32_t bus, device ;
CyAsReturnStatus_t ret ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if ((CyAsDeviceIsInCallback(dev_p)) && (cb != 0))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
/* Since we are mapping the media types to bus with NAND to 0 and the rest
* to 1, and we are only allowing for enumerating all the devices on a bus
* we just scan the array for any positions where there a device is enabled
* and mark the bus to be enumerated.
*/
bus_mask = 0 ;
media_mask = 0 ;
media_mask = 0 ;
for( bus = 0; bus < CY_AS_MAX_BUSES; bus++)
{
for( device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++)
{
if (config_p->devices_to_enumerate[bus][device] == CyTrue)
{
bus_mask |= (0x01 << bus) ;
media_mask |= dev_p->media_supported[bus] ;
media_mask |= dev_p->media_supported[bus] ;
}
}
}
return MyUsbSetEnumConfig(dev_p, bus_mask,media_mask,
config_p->antioch_enumeration,
config_p->mass_storage_interface,
config_p->mtp_interface,
config_p->mass_storage_callbacks,
cb,
client
) ;
}
static CyAsReturnStatus_t
MyHandleResponseGetEnumConfig(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p,
void* config_p)
{
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
uint16_t val ;
uint8_t bus_mask ;
uint32_t bus ;
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_USB_CONFIG)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
/* Marshal the reply */
if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS)
{
uint32_t device ;
CyBool state;
CyAsUsbEnumControl *ms_config_p = (CyAsUsbEnumControl*)config_p;
bus_mask = (uint8_t)(CyAsLLRequestResponse_GetWord(reply_p, 0) & 0xFF) ;
for( bus = 0; bus < CY_AS_MAX_BUSES; bus++)
{
if (bus_mask & (1 << bus))
state = CyTrue ;
else
state = CyFalse ;
for( device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++)
{
ms_config_p->devices_to_enumerate[bus][device] = state ;
}
}
ms_config_p->antioch_enumeration = (CyBool)CyAsLLRequestResponse_GetWord(reply_p, 1) ;
val = CyAsLLRequestResponse_GetWord(reply_p, 2) ;
if (dev_p->is_mtp_firmware)
{
ms_config_p->mass_storage_interface = 0 ;
ms_config_p->mtp_interface = (uint8_t)(val & 0xFF) ;
}
else
{
ms_config_p->mass_storage_interface = (uint8_t)(val & 0xFF) ;
ms_config_p->mtp_interface = 0 ;
}
ms_config_p->mass_storage_callbacks = (CyBool)(val >> 8) ;
/*
* Firmware returns an invalid interface number for mass storage,
* if mass storage is not enabled. This needs to be converted to zero
* to match the input configuration.
*/
if (bus_mask == 0)
{
if (dev_p->is_mtp_firmware)
ms_config_p->mtp_interface = 0 ;
else
ms_config_p->mass_storage_interface = 0 ;
}
}
else
{
CyAsUsbEnumControl_dep *ex_config_p = (CyAsUsbEnumControl_dep*)config_p;
ex_config_p->enum_mass_storage = (uint8_t)((CyAsLLRequestResponse_GetWord(reply_p, 0) >> 8) & 0xFF) ;
ex_config_p->antioch_enumeration = (CyBool)CyAsLLRequestResponse_GetWord(reply_p, 1) ;
val = CyAsLLRequestResponse_GetWord(reply_p, 2) ;
ex_config_p->mass_storage_interface = (uint8_t)(val & 0xFF) ;
ex_config_p->mass_storage_callbacks = (CyBool)(val >> 8) ;
/*
* Firmware returns an invalid interface number for mass storage,
* if mass storage is not enabled. This needs to be converted to zero
* to match the input configuration.
*/
if (ex_config_p->enum_mass_storage == 0)
ex_config_p->mass_storage_interface = 0 ;
}
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
/*
* This sets up the request for the enumerateion configuration information, based on if the request is from
* the old pre-1.2 functions.
*/
static CyAsReturnStatus_t
MyUsbGetEnumConfig(CyAsDeviceHandle handle,
uint16_t req_flags,
void* config_p,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbGetEnumConfig called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_GET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 0) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* Reserve space for the reply, the reply data will not exceed two bytes */
reply_p = CyAsLLCreateResponse(dev_p, 3) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
/* we need to know the type of request to know how to manage the data */
req_p->flags |= req_flags;
return MyHandleResponseGetEnumConfig(dev_p, req_p, reply_p, config_p) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_GETENUMCONFIG,
config_p, dev_p->func_cbs_usb, req_flags, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
/*
* This method returns the enumerateion configuration information from the West Bridge device.
* Generally this is not used by client software but is provided mostly for debug information.
* We want a method to read all state information from the device.
*/
CyAsReturnStatus_t
CyAsUsbGetEnumConfig(CyAsDeviceHandle handle,
CyAsUsbEnumControl *config_p,
CyAsFunctionCallback cb,
uint32_t client)
{
return MyUsbGetEnumConfig(handle, CY_AS_REQUEST_RESPONSE_MS, config_p, cb, client);
}
/*
* This method sets the USB descriptor for a given entity.
*/
CyAsReturnStatus_t
CyAsUsbSetDescriptor(CyAsDeviceHandle handle,
CyAsUsbDescType type,
uint8_t index,
void *desc_p,
uint16_t length,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
uint16_t pktlen ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbSetDescriptor called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
if (length > CY_AS_MAX_USB_DESCRIPTOR_SIZE)
return CY_AS_ERROR_INVALID_DESCRIPTOR ;
pktlen = (uint16_t)length / 2 ;
if (length % 2)
pktlen++ ;
pktlen += 2 ; /* 1 for type, 1 for length */
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SET_DESCRIPTOR, CY_RQT_USB_RQT_CONTEXT, (uint16_t)pktlen) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)((uint8_t)type | (index << 8))) ;
CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)length) ;
CyAsLLRequestResponse_Pack(req_p, 2, length, desc_p) ;
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return MyHandleResponseNoData(dev_p, req_p, reply_p) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_SETDESCRIPTOR,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
/*
* This method clears all descriptors that were previously stored on the West Bridge
* through CyAsUsbSetDescriptor calls.
*/
CyAsReturnStatus_t
CyAsUsbClearDescriptors(CyAsDeviceHandle handle,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbClearDescriptors called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if ((CyAsDeviceIsInCallback(dev_p)) && (cb == 0))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_CLEAR_DESCRIPTORS, CY_RQT_USB_RQT_CONTEXT, 1) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return MyHandleResponseNoData(dev_p, req_p, reply_p) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_CLEARDESCRIPTORS,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
static CyAsReturnStatus_t
MyHandleResponseGetDescriptor(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p,
CyAsGetDescriptorData* data)
{
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
uint32_t retlen ;
if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_SUCCESS_FAILURE)
{
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
goto destroy ;
}
else if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_USB_DESCRIPTOR)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
retlen = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
if (retlen > data->length)
{
ret = CY_AS_ERROR_INVALID_SIZE ;
goto destroy ;
}
ret = CY_AS_ERROR_SUCCESS ;
CyAsLLRequestResponse_Unpack(reply_p, 1, retlen, data->desc_p) ;
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
/*
* This method retreives the USB descriptor for a given type.
*/
CyAsReturnStatus_t
CyAsUsbGetDescriptor(CyAsDeviceHandle handle,
CyAsUsbDescType type,
uint8_t index,
CyAsGetDescriptorData* data,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbGetDescriptor called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_GET_DESCRIPTOR, CY_RQT_USB_RQT_CONTEXT, 1) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)((uint8_t)type | (index << 8))) ;
/* Add one for the length field */
reply_p = CyAsLLCreateResponse(dev_p, CY_AS_MAX_USB_DESCRIPTOR_SIZE + 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return MyHandleResponseGetDescriptor(dev_p, req_p, reply_p, data) ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_GETDESCRIPTOR,
data, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
CyAsReturnStatus_t
CyAsUsbSetPhysicalConfiguration(CyAsDeviceHandle handle, uint8_t config)
{
CyAsReturnStatus_t ret ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbSetPhysicalConfiguration called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsUsbConnected(dev_p))
return CY_AS_ERROR_USB_CONNECTED ;
if (config < 1 || config > 12)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
dev_p->usb_phy_config = config ;
return CY_AS_ERROR_SUCCESS ;
}
static CyBool
IsPhysicalValid(uint8_t config, CyAsEndPointNumber_t ep)
{
static uint8_t validmask[12] =
{
0x0f, /* Config 1 - 1, 2, 3, 4 */
0x07, /* Config 2 - 1, 2, 3 */
0x07, /* Config 3 - 1, 2, 3 */
0x0d, /* Config 4 - 1, 3, 4 */
0x05, /* Config 5 - 1, 3 */
0x05, /* Config 6 - 1, 3 */
0x0d, /* Config 7 - 1, 3, 4 */
0x05, /* Config 8 - 1, 3 */
0x05, /* Config 9 - 1, 3 */
0x0d, /* Config 10 - 1, 3, 4 */
0x09, /* Config 11 - 1, 4 */
0x01 /* Config 12 - 1 */
} ;
return (validmask[config - 1] & (1 << (ep - 1))) ? CyTrue : CyFalse ;
}
/*
* This method sets the configuration for an endpoint
*/
CyAsReturnStatus_t
CyAsUsbSetEndPointConfig(CyAsDeviceHandle handle, CyAsEndPointNumber_t ep, CyAsUsbEndPointConfig *config_p)
{
CyAsReturnStatus_t ret ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbSetEndPointConfig called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsUsbConnected(dev_p))
return CY_AS_ERROR_USB_CONNECTED ;
if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
return CY_AS_ERROR_INVALID_ENDPOINT ;
if (ep == 0)
{
/* Endpoint 0 must be 64 byte, dir IN/OUT, and control type */
if (config_p->dir != CyAsUsbInOut || config_p->type != CyAsUsbControl)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
}
else if (ep == 1)
{
if ((dev_p->is_mtp_firmware == 1) && (dev_p->usb_config[1].enabled == CyTrue))
{
return CY_AS_ERROR_INVALID_ENDPOINT ;
}
/*
* EP1 can only be used either as an OUT ep, or as an IN ep.
*/
if ((config_p->type == CyAsUsbControl) || (config_p->type == CyAsUsbIso) || (config_p->dir == CyAsUsbInOut))
return CY_AS_ERROR_INVALID_CONFIGURATION ;
}
else
{
if (config_p->dir == CyAsUsbInOut || config_p->type == CyAsUsbControl)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
if (!IsPhysicalValid(dev_p->usb_phy_config, config_p->physical))
return CY_AS_ERROR_INVALID_PHYSICAL_ENDPOINT ;
/*
* ISO endpoints must be on EPs 3, 5, 7 or 9 as they need to align directly
* with the underlying physical endpoint.
*/
if (config_p->type == CyAsUsbIso)
{
if (ep != 3 && ep != 5 && ep != 7 && ep != 9)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
if (ep == 3 && config_p->physical != 1)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
if (ep == 5 && config_p->physical != 2)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
if (ep == 7 && config_p->physical != 3)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
if (ep == 9 && config_p->physical != 4)
return CY_AS_ERROR_INVALID_CONFIGURATION ;
}
}
/* Store the configuration information until a CyAsUsbCommitConfig is done */
dev_p->usb_config[ep] = *config_p ;
/* If the endpoint is enabled, enable DMA associated with the endpoint */
/*
* We make some assumptions that we check here. We assume that the direction fields for the
* DMA module are the same values as the direction values for the USB module. At some point these should
* be consolidated into a single enumerated type. - BWG
*/
CyAsHalAssert((int)CyAsUsbIn == (int)CyAsDirectionIn);
CyAsHalAssert((int)CyAsUsbOut == (int)CyAsDirectionOut);
CyAsHalAssert((int)CyAsUsbInOut == (int)CyAsDirectionInOut) ;
return CyAsDmaEnableEndPoint(dev_p, ep, config_p->enabled, (CyAsDmaDirection)config_p->dir) ;
}
CyAsReturnStatus_t
CyAsUsbGetEndPointConfig(CyAsDeviceHandle handle, CyAsEndPointNumber_t ep, CyAsUsbEndPointConfig *config_p)
{
CyAsReturnStatus_t ret ;
CyAsDevice*dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbGetEndPointConfig called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
return CY_AS_ERROR_INVALID_ENDPOINT ;
*config_p = dev_p->usb_config[ep] ;
return CY_AS_ERROR_SUCCESS ;
}
/*
* Commit the configuration of the various endpoints to the hardware.
*/
CyAsReturnStatus_t
CyAsUsbCommitConfig(CyAsDeviceHandle handle,
CyAsFunctionCallback cb,
uint32_t client)
{
uint32_t i ;
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsDevice*dev_p ;
uint16_t data ;
CyAsLogDebugMessage(6, "CyAsUsbCommitConfig called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsUsbConnected(dev_p))
return CY_AS_ERROR_USB_CONNECTED ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
/*
* This performs the mapping based on informatation that was previously
* stored on the device about the various endpoints and how they are configured. The
* output of this mapping is setting the the 14 register values contained in usb_lepcfg
* and usb_pepcfg
*/
ret = CyAsUsbMapLogical2Physical(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
/*
* Now, package the information about the various logical and physical
* endpoint configuration registers and send it across to the West Bridge
* device.
*/
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_SET_USB_CONFIG_REGISTERS, CY_RQT_USB_RQT_CONTEXT, 8) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
CyAsHalPrintMessage("USB Configuration: %d\n", dev_p->usb_phy_config) ;
CyAsHalPrintMessage("EP1OUT: 0x%02x EP1IN: 0x%02x\n", dev_p->usb_ep1cfg[0], dev_p->usb_ep1cfg[1]) ;
CyAsHalPrintMessage("PEP Registers: 0x%02x 0x%02x 0x%02x 0x%02x\n", dev_p->usb_pepcfg[0],
dev_p->usb_pepcfg[1], dev_p->usb_pepcfg[2], dev_p->usb_pepcfg[3]) ;
CyAsHalPrintMessage("LEP Registers: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
dev_p->usb_lepcfg[0],dev_p->usb_lepcfg[1], dev_p->usb_lepcfg[2], dev_p->usb_lepcfg[3],
dev_p->usb_lepcfg[4],dev_p->usb_lepcfg[5], dev_p->usb_lepcfg[6], dev_p->usb_lepcfg[7],
dev_p->usb_lepcfg[8],dev_p->usb_lepcfg[9]) ;
/* Write the EP1OUTCFG and EP1INCFG data in the first word. */
data = (uint16_t)((dev_p->usb_ep1cfg[0] << 8) | dev_p->usb_ep1cfg[1]) ;
CyAsLLRequestResponse_SetWord(req_p, 0, data) ;
/* Write the PEP CFG data in the next 2 words */
for(i = 0 ; i < 4 ; i += 2)
{
data = (uint16_t)((dev_p->usb_pepcfg[i] << 8) | dev_p->usb_pepcfg[i + 1]) ;
CyAsLLRequestResponse_SetWord(req_p, 1 + i / 2, data) ;
}
/* Write the LEP CFG data in the next 5 words */
for(i = 0 ; i < 10 ; i += 2)
{
data = (uint16_t)((dev_p->usb_lepcfg[i] << 8) | dev_p->usb_lepcfg[i + 1]) ;
CyAsLLRequestResponse_SetWord(req_p, 3 + i / 2, data) ;
}
/* A single status word response type */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
ret = MyHandleResponseNoData(dev_p, req_p, reply_p) ;
if (ret == CY_AS_ERROR_SUCCESS)
ret = CyAsUsbSetupDma(dev_p) ;
return ret ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_COMMITCONFIG,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
static void
SyncRequestCallback(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, void *buf_p, uint32_t size, CyAsReturnStatus_t err)
{
(void)ep ;
(void)buf_p ;
dev_p->usb_error = err ;
dev_p->usb_actual_cnt = size ;
}
static void
AsyncReadRequestCallback(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, void *buf_p, uint32_t size, CyAsReturnStatus_t err)
{
CyAsDeviceHandle h ;
CyAsLogDebugMessage(6, "AsyncReadRequestCallback called") ;
h = (CyAsDeviceHandle)dev_p ;
if (ep == 0 && CyAsDeviceIsAckDelayed(dev_p))
{
dev_p->usb_pending_buffer = buf_p ;
dev_p->usb_pending_size = size ;
dev_p->usb_error = err ;
CyAsUsbAckSetupPacket(h, UsbAckCallback, 0) ;
}
else
{
CyAsUsbIoCallback cb ;
cb = dev_p->usb_cb[ep] ;
dev_p->usb_cb[ep] = 0 ;
CyAsDeviceClearUsbAsyncPending(dev_p, ep) ;
if (cb)
cb(h, ep, size, buf_p, err) ;
}
}
static void
AsyncWriteRequestCallback(CyAsDevice *dev_p, CyAsEndPointNumber_t ep, void *buf_p, uint32_t size, CyAsReturnStatus_t err)
{
CyAsDeviceHandle h ;
CyAsLogDebugMessage(6, "AsyncWriteRequestCallback called") ;
h = (CyAsDeviceHandle)dev_p ;
if (ep == 0 && CyAsDeviceIsAckDelayed(dev_p))
{
dev_p->usb_pending_buffer = buf_p ;
dev_p->usb_pending_size = size ;
dev_p->usb_error = err ;
/* The west bridge protocol generates ZLPs as required. */
CyAsUsbAckSetupPacket(h, UsbAckCallback, 0) ;
}
else
{
CyAsUsbIoCallback cb ;
cb = dev_p->usb_cb[ep] ;
dev_p->usb_cb[ep] = 0 ;
CyAsDeviceClearUsbAsyncPending(dev_p, ep) ;
if (cb)
cb(h, ep, size, buf_p, err) ;
}
}
static void
MyTurboRqtCallback(CyAsDevice *dev_p,
uint8_t context,
CyAsLLRequestResponse *rqt,
CyAsLLRequestResponse *resp,
CyAsReturnStatus_t stat)
{
uint8_t code ;
(void)context ;
(void)stat ;
/* The Handlers are responsible for Deleting the rqt and resp when
* they are finished
*/
code = CyAsLLRequestResponse_GetCode(rqt) ;
switch(code)
{
case CY_RQT_TURBO_SWITCH_ENDPOINT:
CyAsHalAssert(stat == CY_AS_ERROR_SUCCESS) ;
CyAsLLDestroyRequest(dev_p, rqt) ;
CyAsLLDestroyResponse(dev_p, resp) ;
break;
default:
CyAsHalAssert(CyFalse) ;
break ;
}
}
/* Send a mailbox request to prepare the endpoint for switching */
static CyAsReturnStatus_t
MySendTurboSwitch(CyAsDevice* dev_p, uint32_t size, CyBool pktread)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p , *reply_p ;
/* Create the request to send to the West Bridge device */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_TURBO_SWITCH_ENDPOINT, CY_RQT_TUR_RQT_CONTEXT, 3) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* Reserve space for the reply, the reply data will not exceed one word */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)pktread) ;
CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((size >> 16) & 0xFFFF)) ;
CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)(size & 0xFFFF)) ;
ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyFalse, MyTurboRqtCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyRequest(dev_p, reply_p) ;
return ret ;
}
return CY_AS_ERROR_SUCCESS ;
}
CyAsReturnStatus_t
CyAsUsbReadData(CyAsDeviceHandle handle, CyAsEndPointNumber_t ep, CyBool pktread, uint32_t dsize, uint32_t *dataread, void *data)
{
CyAsReturnStatus_t ret ;
CyAsDevice *dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbReadData called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
return CY_AS_ERROR_INVALID_ENDPOINT ;
/* EP2 is available for reading when MTP is active */
if(dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
return CY_AS_ERROR_INVALID_ENDPOINT ;
/* If the endpoint is disabled, we cannot write data to the endpoint */
if (!dev_p->usb_config[ep].enabled)
return CY_AS_ERROR_ENDPOINT_DISABLED ;
if (dev_p->usb_config[ep].dir != CyAsUsbOut)
return CY_AS_ERROR_USB_BAD_DIRECTION ;
ret = CyAsDmaQueueRequest(dev_p, ep, data, dsize, pktread, CyTrue, SyncRequestCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (ep == CY_AS_MTP_READ_ENDPOINT )
{
ret = MySendTurboSwitch(dev_p, dsize, pktread) ;
if (ret != CY_AS_ERROR_SUCCESS)
{
CyAsDmaCancel(dev_p, ep, ret) ;
return ret ;
}
ret = CyAsDmaDrainQueue(dev_p, ep, CyFalse) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
}
else
{
ret = CyAsDmaDrainQueue(dev_p, ep, CyTrue) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
}
ret = dev_p->usb_error ;
*dataread = dev_p->usb_actual_cnt ;
return ret ;
}
CyAsReturnStatus_t
CyAsUsbReadDataAsync(CyAsDeviceHandle handle, CyAsEndPointNumber_t ep, CyBool pktread, uint32_t dsize, void *data, CyAsUsbIoCallback cb)
{
CyAsReturnStatus_t ret ;
uint32_t mask ;
CyAsDevice *dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbReadDataAsync called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
return CY_AS_ERROR_INVALID_ENDPOINT ;
/* EP2 is available for reading when MTP is active */
if(dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
return CY_AS_ERROR_INVALID_ENDPOINT ;
/* If the endpoint is disabled, we cannot write data to the endpoint */
if (!dev_p->usb_config[ep].enabled)
return CY_AS_ERROR_ENDPOINT_DISABLED ;
if (dev_p->usb_config[ep].dir != CyAsUsbOut && dev_p->usb_config[ep].dir != CyAsUsbInOut)
return CY_AS_ERROR_USB_BAD_DIRECTION ;
/*
* Since async operations can be triggered by interrupt code, we must
* insure that we do not get multiple async operations going at one time and
* protect this test and set operation from interrupts.
*/
mask = CyAsHalDisableInterrupts() ;
if (CyAsDeviceIsUsbAsyncPending(dev_p, ep))
{
CyAsHalEnableInterrupts(mask) ;
return CY_AS_ERROR_ASYNC_PENDING ;
}
CyAsDeviceSetUsbAsyncPending(dev_p, ep) ;
/*
* If this is for EP0, we set this bit to delay the ACK response
* until after this read has completed.
*/
if (ep == 0)
CyAsDeviceSetAckDelayed(dev_p) ;
CyAsHalEnableInterrupts(mask) ;
CyAsHalAssert(dev_p->usb_cb[ep] == 0) ;
dev_p->usb_cb[ep] = cb ;
ret = CyAsDmaQueueRequest(dev_p, ep, data, dsize, pktread, CyTrue, AsyncReadRequestCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (ep == CY_AS_MTP_READ_ENDPOINT)
{
ret = MySendTurboSwitch(dev_p, dsize, pktread) ;
if (ret != CY_AS_ERROR_SUCCESS)
{
CyAsDmaCancel(dev_p, ep, ret) ;
return ret ;
}
}
else
{
/* Kick start the queue if it is not running */
CyAsDmaKickStart(dev_p, ep) ;
}
return ret ;
}
CyAsReturnStatus_t
CyAsUsbWriteData(CyAsDeviceHandle handle, CyAsEndPointNumber_t ep, uint32_t dsize, void *data)
{
CyAsReturnStatus_t ret ;
CyAsDevice *dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbWriteData called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
return CY_AS_ERROR_INVALID_ENDPOINT ;
/* EP6 is available for writing when MTP is active */
if(dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
return CY_AS_ERROR_INVALID_ENDPOINT ;
/* If the endpoint is disabled, we cannot write data to the endpoint */
if (!dev_p->usb_config[ep].enabled)
return CY_AS_ERROR_ENDPOINT_DISABLED ;
if (dev_p->usb_config[ep].dir != CyAsUsbIn && dev_p->usb_config[ep].dir != CyAsUsbInOut)
return CY_AS_ERROR_USB_BAD_DIRECTION ;
/* Write on Turbo endpoint */
if (ep == CY_AS_MTP_WRITE_ENDPOINT)
{
CyAsLLRequestResponse *req_p, *reply_p ;
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST, CY_RQT_TUR_RQT_CONTEXT, 3) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
CyAsLLRequestResponse_SetWord(req_p, 0, 0x0006) ; /* EP number to use. */
CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((dsize >> 16) & 0xFFFF)) ;
CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)(dsize & 0xFFFF)) ;
/* Reserve space for the reply, the reply data will not exceed one word */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if (dsize)
{
ret = CyAsDmaQueueRequest(dev_p, ep, data, dsize, CyFalse, CyFalse, SyncRequestCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
}
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret == CY_AS_ERROR_SUCCESS)
{
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE)
ret = CY_AS_ERROR_INVALID_RESPONSE ;
else
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
}
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
{
if (dsize)
CyAsDmaCancel(dev_p, ep, ret) ;
return ret ;
}
/* If this is a zero-byte write, firmware will handle it.
* There is no need to do any work here.
*/
if (!dsize)
return CY_AS_ERROR_SUCCESS ;
}
else
{
ret = CyAsDmaQueueRequest(dev_p, ep, data, dsize, CyFalse, CyFalse, SyncRequestCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
}
if (ep != CY_AS_MTP_WRITE_ENDPOINT)
ret = CyAsDmaDrainQueue(dev_p, ep, CyTrue) ;
else
ret = CyAsDmaDrainQueue(dev_p, ep, CyFalse) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
ret = dev_p->usb_error ;
return ret ;
}
static void
MtpWriteCallback(
CyAsDevice *dev_p,
uint8_t context,
CyAsLLRequestResponse *rqt,
CyAsLLRequestResponse *resp,
CyAsReturnStatus_t ret)
{
CyAsUsbIoCallback cb ;
CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ;
CyAsHalAssert(context == CY_RQT_TUR_RQT_CONTEXT) ;
if (ret == CY_AS_ERROR_SUCCESS)
{
if (CyAsLLRequestResponse_GetCode(resp) != CY_RESP_SUCCESS_FAILURE)
ret = CY_AS_ERROR_INVALID_RESPONSE ;
else
ret = CyAsLLRequestResponse_GetWord(resp, 0) ;
}
/* If this was a zero byte transfer request, we can call the callback from
* here. */
if ((CyAsLLRequestResponse_GetWord(rqt, 1) == 0) &&
(CyAsLLRequestResponse_GetWord(rqt, 2) == 0))
{
cb = dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] ;
dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] = 0 ;
CyAsDeviceClearUsbAsyncPending(dev_p, CY_AS_MTP_WRITE_ENDPOINT) ;
if (cb)
cb(h, CY_AS_MTP_WRITE_ENDPOINT, 0, 0, ret) ;
goto destroy ;
}
if (ret != CY_AS_ERROR_SUCCESS)
{
/* Firmware failed the request. Cancel the DMA transfer. */
CyAsDmaCancel(dev_p, 0x06, CY_AS_ERROR_CANCELED) ;
dev_p->usb_cb[0x06] = 0 ;
CyAsDeviceClearUsbAsyncPending(dev_p, 0x06) ;
}
destroy:
CyAsLLDestroyResponse(dev_p, resp) ;
CyAsLLDestroyRequest(dev_p, rqt) ;
}
CyAsReturnStatus_t
CyAsUsbWriteDataAsync(CyAsDeviceHandle handle, CyAsEndPointNumber_t ep, uint32_t dsize, void *data, CyBool spacket, CyAsUsbIoCallback cb)
{
uint32_t mask ;
CyAsReturnStatus_t ret ;
CyAsDevice *dev_p ;
CyAsLogDebugMessage(6, "CyAsUsbWriteDataAsync called") ;
dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
return CY_AS_ERROR_INVALID_ENDPOINT ;
/* EP6 is available for writing when MTP is active */
if(dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
return CY_AS_ERROR_INVALID_ENDPOINT ;
/* If the endpoint is disabled, we cannot write data to the endpoint */
if (!dev_p->usb_config[ep].enabled)
return CY_AS_ERROR_ENDPOINT_DISABLED ;
if (dev_p->usb_config[ep].dir != CyAsUsbIn && dev_p->usb_config[ep].dir != CyAsUsbInOut)
return CY_AS_ERROR_USB_BAD_DIRECTION ;
/*
* Since async operations can be triggered by interrupt code, we must
* insure that we do not get multiple async operations going at one time and
* protect this test and set operation from interrupts.
*/
mask = CyAsHalDisableInterrupts() ;
if (CyAsDeviceIsUsbAsyncPending(dev_p, ep))
{
CyAsHalEnableInterrupts(mask) ;
return CY_AS_ERROR_ASYNC_PENDING ;
}
CyAsDeviceSetUsbAsyncPending(dev_p, ep) ;
if (ep == 0)
CyAsDeviceSetAckDelayed(dev_p) ;
CyAsHalEnableInterrupts(mask) ;
CyAsHalAssert(dev_p->usb_cb[ep] == 0) ;
dev_p->usb_cb[ep] = cb ;
dev_p->usb_spacket[ep] = spacket ;
/* Write on Turbo endpoint */
if (ep == CY_AS_MTP_WRITE_ENDPOINT)
{
CyAsLLRequestResponse *req_p, *reply_p ;
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST, CY_RQT_TUR_RQT_CONTEXT, 3) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
CyAsLLRequestResponse_SetWord(req_p, 0, 0x0006) ; /* EP number to use. */
CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)((dsize >> 16) & 0xFFFF)) ;
CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)(dsize & 0xFFFF)) ;
/* Reserve space for the reply, the reply data will not exceed one word */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if (dsize)
{
ret = CyAsDmaQueueRequest(dev_p, ep, data, dsize, CyFalse, CyFalse, AsyncWriteRequestCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
}
ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyFalse, MtpWriteCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
{
if (dsize)
CyAsDmaCancel(dev_p, ep, ret) ;
return ret ;
}
/* Firmware will handle a zero byte transfer without any DMA transfers. */
if (!dsize)
return CY_AS_ERROR_SUCCESS ;
}
else
{
ret = CyAsDmaQueueRequest(dev_p, ep, data, dsize, CyFalse, CyFalse, AsyncWriteRequestCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
}
/* Kick start the queue if it is not running */
if (ep != CY_AS_MTP_WRITE_ENDPOINT)
{
CyAsDmaKickStart(dev_p, ep) ;
}
return CY_AS_ERROR_SUCCESS ;
}
static void
MyUsbCancelAsyncCallback(
CyAsDevice *dev_p,
uint8_t context,
CyAsLLRequestResponse *rqt,
CyAsLLRequestResponse *resp,
CyAsReturnStatus_t ret)
{
uint8_t ep ;
(void)context ;
ep = (uint8_t)CyAsLLRequestResponse_GetWord(rqt, 0) ;
if (ret == CY_AS_ERROR_SUCCESS)
{
if (CyAsLLRequestResponse_GetCode(resp) != CY_RESP_SUCCESS_FAILURE)
ret = CY_AS_ERROR_INVALID_RESPONSE ;
else
ret = CyAsLLRequestResponse_GetWord(resp, 0) ;
}
CyAsLLDestroyRequest(dev_p, rqt) ;
CyAsLLDestroyResponse(dev_p, resp) ;
if (ret == CY_AS_ERROR_SUCCESS)
{
CyAsDmaCancel(dev_p, ep, CY_AS_ERROR_CANCELED) ;
dev_p->usb_cb[ep] = 0 ;
CyAsDeviceClearUsbAsyncPending(dev_p, ep) ;
}
}
CyAsReturnStatus_t
CyAsUsbCancelAsync(CyAsDeviceHandle handle, CyAsEndPointNumber_t ep)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p, *reply_p ;
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ep &= 0x7F; /* Remove the direction bit. */
if (!CyAsDeviceIsUsbAsyncPending(dev_p, ep))
return CY_AS_ERROR_ASYNC_NOT_PENDING;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInSuspendMode(dev_p))
return CY_AS_ERROR_IN_SUSPEND ;
if ((ep == CY_AS_MTP_WRITE_ENDPOINT) || (ep == CY_AS_MTP_READ_ENDPOINT))
{
/* Need firmware support for the cancel operation. */
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_CANCEL_ASYNC_TRANSFER, CY_RQT_TUR_RQT_CONTEXT, 1) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)ep) ;
ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyFalse, MyUsbCancelAsyncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
}
else
{
ret = CyAsDmaCancel(dev_p, ep, CY_AS_ERROR_CANCELED) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
dev_p->usb_cb[ep] = 0 ;
CyAsDeviceClearUsbAsyncPending(dev_p, ep) ;
}
return CY_AS_ERROR_SUCCESS ;
}
static void
CyAsUsbAckCallback(
CyAsDevice *dev_p,
uint8_t context,
CyAsLLRequestResponse *rqt,
CyAsLLRequestResponse *resp,
CyAsReturnStatus_t ret)
{
CyAsFuncCBNode* node = (CyAsFuncCBNode*)dev_p->func_cbs_usb->head_p ;
(void)context ;
if (ret == CY_AS_ERROR_SUCCESS)
{
if (CyAsLLRequestResponse_GetCode(resp) != CY_RESP_SUCCESS_FAILURE)
ret = CY_AS_ERROR_INVALID_RESPONSE ;
else
ret = CyAsLLRequestResponse_GetWord(resp, 0) ;
}
node->cb_p((CyAsDeviceHandle)dev_p, ret, node->client_data, (CyAsFunctCBType)node->dataType, node->data) ;
CyAsRemoveCBNode(dev_p->func_cbs_usb) ;
CyAsLLDestroyRequest(dev_p, rqt) ;
CyAsLLDestroyResponse(dev_p, resp) ;
CyAsDeviceClearAckDelayed(dev_p) ;
}
static CyAsReturnStatus_t
CyAsUsbAckSetupPacket(CyAsDeviceHandle handle,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p ;
CyAsLLRequestResponse *reply_p ;
CyAsFuncCBNode* cbnode ;
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p) && cb == 0)
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
CyAsHalAssert(cb != 0) ;
cbnode = CyAsCreateFuncCBNode(cb, client);
if( cbnode == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
req_p = CyAsLLCreateRequest(dev_p, 0, CY_RQT_USB_RQT_CONTEXT, 2) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if(reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
CyAsLLInitRequest(req_p, CY_RQT_ACK_SETUP_PACKET, CY_RQT_USB_RQT_CONTEXT, 1) ;
CyAsLLInitResponse(reply_p, 1) ;
req_p->flags |= CY_AS_REQUEST_RESPONSE_EX ;
CyAsInsertCBNode(dev_p->func_cbs_usb, cbnode) ;
ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyFalse, CyAsUsbAckCallback) ;
return ret ;
}
/*
* Flush all data in logical EP that is being NAK-ed or Stall-ed,
* so that this does not continue to block data on other LEPs that
* use the same physical EP.
*/
static void
CyAsUsbFlushLogicalEP(
CyAsDevice *dev_p,
uint16_t ep)
{
uint16_t addr, val, count ;
addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2 ;
val = CyAsHalReadRegister(dev_p->tag, addr) ;
while (val)
{
count = ((val & 0xFFF) + 1) / 2 ;
while (count--)
{
val = CyAsHalReadRegister(dev_p->tag, ep) ;
}
CyAsHalWriteRegister(dev_p->tag, addr, 0) ;
val = CyAsHalReadRegister(dev_p->tag, addr) ;
}
}
static CyAsReturnStatus_t
CyAsUsbNakStallRequest(CyAsDeviceHandle handle,
CyAsEndPointNumber_t ep,
uint16_t request,
CyBool state,
CyAsUsbFunctionCallback cb,
CyAsFunctionCallback fcb,
uint32_t client)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p , *reply_p ;
uint16_t data ;
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
if(cb)
CyAsHalAssert(fcb == 0) ;
if(fcb)
CyAsHalAssert(cb == 0) ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p) && cb == 0 && fcb == 0)
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
req_p = CyAsLLCreateRequest(dev_p, request, CY_RQT_USB_RQT_CONTEXT, 2) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* A single status word response type */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
/* Set the endpoint */
data = (uint8_t)ep ;
CyAsLLRequestResponse_SetWord(req_p, 0, data) ;
/* Set stall state to stalled */
CyAsLLRequestResponse_SetWord(req_p, 1, (uint8_t)state) ;
if (cb || fcb)
{
void * cbnode ;
CyAsCBQueue* queue ;
if(cb)
{
cbnode = CyAsCreateUsbFuncCBNode(cb, client) ;
queue = dev_p->usb_func_cbs ;
}
else
{
cbnode = CyAsCreateFuncCBNode(fcb, client) ;
queue = dev_p->func_cbs_usb ;
req_p->flags |= CY_AS_REQUEST_RESPONSE_EX ;
}
if(cbnode == 0)
{
ret = CY_AS_ERROR_OUT_OF_MEMORY ;
goto destroy ;
}
else
CyAsInsertCBNode(queue, cbnode) ;
if (CyAsDeviceIsSetupPacket(dev_p))
{
/* No Ack is needed on a stall request on EP0 */
if ((state == CyTrue) && (ep == 0))
{
CyAsDeviceSetEp0Stalled(dev_p) ;
}
else
{
CyAsDeviceSetAckDelayed(dev_p) ;
req_p->flags |= CY_AS_REQUEST_RESPONSE_DELAY_ACK ;
}
}
ret = CyAsLLSendRequest(dev_p, req_p, reply_p, CyFalse, CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
{
if (req_p->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
CyAsDeviceRemAckDelayed(dev_p) ;
CyAsRemoveCBTailNode(queue) ;
goto destroy ;
}
}
else
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if (CyAsLLRequestResponse_GetCode(reply_p) != CY_RESP_SUCCESS_FAILURE)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
if ((ret == CY_AS_ERROR_SUCCESS) && (request == CY_RQT_STALL_ENDPOINT))
{
if ((ep > 1) && (state != 0) && (dev_p->usb_config[ep].dir == CyAsUsbOut))
CyAsUsbFlushLogicalEP(dev_p, ep) ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
}
return ret ;
}
static CyAsReturnStatus_t
MyHandleResponseGetStall(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p,
CyBool *state_p)
{
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
uint8_t code = CyAsLLRequestResponse_GetCode(reply_p) ;
if (code == CY_RESP_SUCCESS_FAILURE)
{
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
goto destroy ;
}
else if (code != CY_RESP_ENDPOINT_STALL)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
*state_p = (CyBool)CyAsLLRequestResponse_GetWord(reply_p, 0) ;
ret = CY_AS_ERROR_SUCCESS ;
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
static CyAsReturnStatus_t
MyHandleResponseGetNak(CyAsDevice* dev_p,
CyAsLLRequestResponse *req_p,
CyAsLLRequestResponse *reply_p,
CyBool *state_p)
{
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
uint8_t code = CyAsLLRequestResponse_GetCode(reply_p) ;
if (code == CY_RESP_SUCCESS_FAILURE)
{
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
goto destroy ;
}
else if (code != CY_RESP_ENDPOINT_NAK)
{
ret = CY_AS_ERROR_INVALID_RESPONSE ;
goto destroy ;
}
*state_p = (CyBool)CyAsLLRequestResponse_GetWord(reply_p, 0) ;
ret = CY_AS_ERROR_SUCCESS ;
destroy :
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
static CyAsReturnStatus_t
CyAsUsbGetNakStall(CyAsDeviceHandle handle,
CyAsEndPointNumber_t ep,
uint16_t request,
uint16_t response,
CyBool *state_p,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsDevice *dev_p = (CyAsDevice *)handle ;
(void)response ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p) && !cb)
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
req_p = CyAsLLCreateRequest(dev_p, request, CY_RQT_USB_RQT_CONTEXT, 1) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* Set the endpoint */
CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)ep) ;
/* A single status word response type */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if(cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if(request == CY_RQT_GET_STALL)
return MyHandleResponseGetStall(dev_p, req_p, reply_p, state_p) ;
else
return MyHandleResponseGetNak(dev_p, req_p, reply_p, state_p) ;
}
else
{
CyAsFunctCBType type ;
if(request == CY_RQT_GET_STALL)
type = CY_FUNCT_CB_USB_GETSTALL ;
else
type = CY_FUNCT_CB_USB_GETNAK ;
ret = CyAsMiscSendRequest(dev_p, cb, client, type,
state_p, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
CyAsReturnStatus_t
CyAsUsbSetNak(CyAsDeviceHandle handle,
CyAsEndPointNumber_t ep,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
/*
* We send the firmware the EP# with the appropriate direction bit, regardless
* of what the user gave us.
*/
ep &= 0x0f ;
if (dev_p->usb_config[ep].dir == CyAsUsbIn)
ep |= 0x80 ;
if(dev_p->mtp_count > 0)
return CY_AS_ERROR_NOT_VALID_IN_MTP ;
return CyAsUsbNakStallRequest(handle, ep, CY_RQT_ENDPOINT_SET_NAK, CyTrue, 0, cb, client) ;
}
CyAsReturnStatus_t
CyAsUsbClearNak(CyAsDeviceHandle handle,
CyAsEndPointNumber_t ep,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
/*
* We send the firmware the EP# with the appropriate direction bit, regardless
* of what the user gave us.
*/
ep &= 0x0f ;
if (dev_p->usb_config[ep].dir == CyAsUsbIn)
ep |= 0x80 ;
if(dev_p->mtp_count > 0)
return CY_AS_ERROR_NOT_VALID_IN_MTP ;
return CyAsUsbNakStallRequest(handle, ep, CY_RQT_ENDPOINT_SET_NAK, CyFalse, 0, cb, client) ;
}
CyAsReturnStatus_t
CyAsUsbGetNak(CyAsDeviceHandle handle,
CyAsEndPointNumber_t ep,
CyBool *nak_p,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
/*
* We send the firmware the EP# with the appropriate direction bit, regardless
* of what the user gave us.
*/
ep &= 0x0f ;
if (dev_p->usb_config[ep].dir == CyAsUsbIn)
ep |= 0x80 ;
if(dev_p->mtp_count > 0)
return CY_AS_ERROR_NOT_VALID_IN_MTP ;
return CyAsUsbGetNakStall(handle, ep, CY_RQT_GET_ENDPOINT_NAK, CY_RESP_ENDPOINT_NAK, nak_p, cb, client ) ;
}
CyAsReturnStatus_t
CyAsUsbSetStall(CyAsDeviceHandle handle,
CyAsEndPointNumber_t ep,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
/*
* We send the firmware the EP# with the appropriate direction bit, regardless
* of what the user gave us.
*/
ep &= 0x0f ;
if (dev_p->usb_config[ep].dir == CyAsUsbIn)
ep |= 0x80 ;
if(dev_p->mtp_turbo_active)
return CY_AS_ERROR_NOT_VALID_DURING_MTP ;
return CyAsUsbNakStallRequest(handle, ep, CY_RQT_STALL_ENDPOINT, CyTrue, 0, cb, client) ;
}
CyAsReturnStatus_t
CyAsUsbClearStall(CyAsDeviceHandle handle,
CyAsEndPointNumber_t ep,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
/*
* We send the firmware the EP# with the appropriate direction bit, regardless
* of what the user gave us.
*/
ep &= 0x0f ;
if (dev_p->usb_config[ep].dir == CyAsUsbIn)
ep |= 0x80 ;
if(dev_p->mtp_turbo_active)
return CY_AS_ERROR_NOT_VALID_DURING_MTP ;
return CyAsUsbNakStallRequest(handle, ep, CY_RQT_STALL_ENDPOINT, CyFalse, 0, cb, client) ;
}
CyAsReturnStatus_t
CyAsUsbGetStall(CyAsDeviceHandle handle,
CyAsEndPointNumber_t ep,
CyBool *stall_p,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
/*
* We send the firmware the EP# with the appropriate direction bit, regardless
* of what the user gave us.
*/
ep &= 0x0f ;
if (dev_p->usb_config[ep].dir == CyAsUsbIn)
ep |= 0x80 ;
if(dev_p->mtp_turbo_active)
return CY_AS_ERROR_NOT_VALID_DURING_MTP ;
return CyAsUsbGetNakStall(handle, ep, CY_RQT_GET_STALL, CY_RESP_ENDPOINT_STALL, stall_p, cb, client) ;
}
CyAsReturnStatus_t
CyAsUsbSignalRemoteWakeup(CyAsDeviceHandle handle,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if (CyAsDeviceIsInCallback(dev_p))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
if (dev_p->usb_last_event != CyAsEventUsbSuspend)
return CY_AS_ERROR_NOT_IN_SUSPEND ;
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_USB_REMOTE_WAKEUP, CY_RQT_USB_RQT_CONTEXT, 0) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* A single status word response type */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
if (cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_SUCCESS_FAILURE)
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
else
ret = CY_AS_ERROR_INVALID_RESPONSE ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_SIGNALREMOTEWAKEUP,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
CyAsReturnStatus_t
CyAsUsbSetMSReportThreshold(CyAsDeviceHandle handle,
uint32_t wr_sectors,
uint32_t rd_sectors,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p , *reply_p ;
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
if ((cb == 0) && (CyAsDeviceIsInCallback(dev_p)))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
/* Check if the firmware version supports this feature. */
if ((dev_p->media_supported[0]) && (dev_p->media_supported[0] == (1 << CyAsMediaNand)))
return CY_AS_ERROR_NOT_SUPPORTED ;
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_USB_STORAGE_MONITOR, CY_RQT_USB_RQT_CONTEXT, 4) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* A single status word response type */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
/* Set the read and write count parameters into the request structure. */
CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)((wr_sectors >> 16) & 0xFFFF)) ;
CyAsLLRequestResponse_SetWord(req_p, 1, (uint16_t)(wr_sectors & 0xFFFF)) ;
CyAsLLRequestResponse_SetWord(req_p, 2, (uint16_t)((rd_sectors >> 16) & 0xFFFF)) ;
CyAsLLRequestResponse_SetWord(req_p, 3, (uint16_t)(rd_sectors & 0xFFFF)) ;
if (cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_SUCCESS_FAILURE)
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
else
ret = CY_AS_ERROR_INVALID_RESPONSE ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_USB_SET_MSREPORT_THRESHOLD,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
CyAsReturnStatus_t
CyAsUsbSelectMSPartitions (
CyAsDeviceHandle handle,
CyAsBusNumber_t bus,
uint32_t device,
CyAsUsbMSType_t type,
CyAsFunctionCallback cb,
uint32_t client)
{
CyAsReturnStatus_t ret ;
CyAsLLRequestResponse *req_p , *reply_p ;
uint16_t val ;
CyAsDevice *dev_p = (CyAsDevice *)handle ;
if (!dev_p ||(dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
return CY_AS_ERROR_INVALID_HANDLE ;
ret = IsUsbActive(dev_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
return ret ;
/* This API has to be made before SetEnumConfig is called. */
if (dev_p->usb_config[0].enabled)
return CY_AS_ERROR_INVALID_CALL_SEQUENCE ;
if ((cb == 0) && (CyAsDeviceIsInCallback(dev_p)))
return CY_AS_ERROR_INVALID_IN_CALLBACK ;
req_p = CyAsLLCreateRequest(dev_p, CY_RQT_MS_PARTITION_SELECT, CY_RQT_USB_RQT_CONTEXT, 2) ;
if (req_p == 0)
return CY_AS_ERROR_OUT_OF_MEMORY ;
/* A single status word response type */
reply_p = CyAsLLCreateResponse(dev_p, 1) ;
if (reply_p == 0)
{
CyAsLLDestroyRequest(dev_p, req_p) ;
return CY_AS_ERROR_OUT_OF_MEMORY ;
}
/* Set the read and write count parameters into the request structure. */
CyAsLLRequestResponse_SetWord(req_p, 0, (uint16_t)((bus << 8) | device)) ;
val = 0 ;
if ((type == CyAsUsbMSUnit0) || (type == CyAsUsbMSBoth))
val |= 1 ;
if ((type == CyAsUsbMSUnit1) || (type == CyAsUsbMSBoth))
val |= (1 << 8) ;
CyAsLLRequestResponse_SetWord(req_p, 1, val) ;
if (cb == 0)
{
ret = CyAsLLSendRequestWaitReply(dev_p, req_p, reply_p) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
if (CyAsLLRequestResponse_GetCode(reply_p) == CY_RESP_SUCCESS_FAILURE)
ret = CyAsLLRequestResponse_GetWord(reply_p, 0) ;
else
ret = CY_AS_ERROR_INVALID_RESPONSE ;
}
else
{
ret = CyAsMiscSendRequest(dev_p, cb, client, CY_FUNCT_CB_NODATA,
0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
CyAsUsbFuncCallback) ;
if (ret != CY_AS_ERROR_SUCCESS)
goto destroy ;
return ret ;
}
destroy:
CyAsLLDestroyRequest(dev_p, req_p) ;
CyAsLLDestroyResponse(dev_p, reply_p) ;
return ret ;
}
static void
CyAsUsbFuncCallback(
CyAsDevice *dev_p,
uint8_t context,
CyAsLLRequestResponse *rqt,
CyAsLLRequestResponse *resp,
CyAsReturnStatus_t stat)
{
CyAsUsbFuncCBNode* node = (CyAsUsbFuncCBNode*)dev_p->usb_func_cbs->head_p ;
CyAsFuncCBNode* fnode = (CyAsFuncCBNode*)dev_p->func_cbs_usb->head_p ;
CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
CyAsDeviceHandle h = (CyAsDeviceHandle)dev_p ;
CyBool delayed_ack = (rqt->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK) == CY_AS_REQUEST_RESPONSE_DELAY_ACK;
CyBool exRequest = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX) == CY_AS_REQUEST_RESPONSE_EX ;
CyBool msRequest = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS) == CY_AS_REQUEST_RESPONSE_MS ;
uint8_t code ;
uint8_t ep, state ;
if(!exRequest && !msRequest)
{
CyAsHalAssert(dev_p->usb_func_cbs->count != 0) ;
CyAsHalAssert(dev_p->usb_func_cbs->type == CYAS_USB_FUNC_CB) ;
}
else
{
CyAsHalAssert(dev_p->func_cbs_usb->count != 0) ;
CyAsHalAssert(dev_p->func_cbs_usb->type == CYAS_FUNC_CB) ;
}
(void)context ;
/* The Handlers are responsible for Deleting the rqt and resp when
* they are finished
*/
code = CyAsLLRequestResponse_GetCode(rqt) ;
switch(code)
{
case CY_RQT_START_USB:
ret = MyHandleResponseUsbStart(dev_p, rqt, resp, stat) ;
break ;
case CY_RQT_STOP_USB:
ret = MyHandleResponseUsbStop(dev_p, rqt, resp, stat) ;
break ;
case CY_RQT_SET_CONNECT_STATE:
if(!CyAsLLRequestResponse_GetWord(rqt, 0))
ret = MyHandleResponseDisconnect(dev_p, rqt, resp, stat) ;
else
ret = MyHandleResponseConnect(dev_p, rqt, resp, stat) ;
break ;
case CY_RQT_GET_CONNECT_STATE:
break ;
case CY_RQT_SET_USB_CONFIG:
ret = MyHandleResponseSetEnumConfig(dev_p, rqt, resp) ;
break ;
case CY_RQT_GET_USB_CONFIG:
CyAsHalAssert(fnode->data != 0) ;
ret = MyHandleResponseGetEnumConfig(dev_p, rqt, resp, fnode->data) ;
break ;
case CY_RQT_STALL_ENDPOINT:
ep = (uint8_t)CyAsLLRequestResponse_GetWord(rqt, 0) ;
state = (uint8_t)CyAsLLRequestResponse_GetWord(rqt, 1) ;
ret = MyHandleResponseNoData(dev_p, rqt, resp) ;
if ((ret == CY_AS_ERROR_SUCCESS) && (ep > 1) && (state != 0) && (dev_p->usb_config[ep].dir == CyAsUsbOut))
CyAsUsbFlushLogicalEP(dev_p, ep) ;
break ;
case CY_RQT_GET_STALL:
CyAsHalAssert(fnode->data != 0) ;
ret = MyHandleResponseGetStall(dev_p, rqt, resp, (CyBool*)fnode->data) ;
break ;
case CY_RQT_SET_DESCRIPTOR:
ret = MyHandleResponseNoData(dev_p, rqt, resp) ;
break ;
case CY_RQT_GET_DESCRIPTOR:
CyAsHalAssert(fnode->data != 0) ;
ret = MyHandleResponseGetDescriptor(dev_p, rqt, resp, (CyAsGetDescriptorData*)fnode->data) ;
break;
case CY_RQT_SET_USB_CONFIG_REGISTERS:
ret = MyHandleResponseNoData(dev_p, rqt, resp) ;
if (ret == CY_AS_ERROR_SUCCESS)
ret = CyAsUsbSetupDma(dev_p) ;
break ;
case CY_RQT_ENDPOINT_SET_NAK:
ret = MyHandleResponseNoData(dev_p, rqt, resp) ;
break ;
case CY_RQT_GET_ENDPOINT_NAK:
CyAsHalAssert(fnode->data != 0) ;
ret = MyHandleResponseGetNak(dev_p, rqt, resp, (CyBool*)fnode->data) ;
break ;
case CY_RQT_ACK_SETUP_PACKET:
break ;
case CY_RQT_USB_REMOTE_WAKEUP:
ret = MyHandleResponseNoData(dev_p, rqt, resp) ;
break ;
case CY_RQT_CLEAR_DESCRIPTORS:
ret = MyHandleResponseNoData(dev_p, rqt, resp) ;
break ;
case CY_RQT_USB_STORAGE_MONITOR:
ret = MyHandleResponseNoData(dev_p, rqt, resp) ;
break ;
case CY_RQT_MS_PARTITION_SELECT:
ret = MyHandleResponseNoData(dev_p, rqt, resp) ;
break ;
default:
ret = CY_AS_ERROR_INVALID_RESPONSE ;
CyAsHalAssert(CyFalse) ;
break ;
}
/*
* If the low level layer returns a direct error, use the corresponding error code.
* If not, use the error code based on the response from firmware.
*/
if (stat == CY_AS_ERROR_SUCCESS)
stat = ret ;
if(exRequest || msRequest)
{
fnode->cb_p((CyAsDeviceHandle)dev_p, stat, fnode->client_data, (CyAsFunctCBType)fnode->dataType, fnode->data) ;
CyAsRemoveCBNode(dev_p->func_cbs_usb) ;
}
else
{
node->cb_p((CyAsDeviceHandle)dev_p, stat, node->client_data) ;
CyAsRemoveCBNode(dev_p->usb_func_cbs) ;
}
if(delayed_ack)
{
CyAsHalAssert(CyAsDeviceIsAckDelayed(dev_p)) ;
CyAsDeviceRemAckDelayed(dev_p) ;
/*
* Send the ACK if required.
*/
if (!CyAsDeviceIsAckDelayed(dev_p))
CyAsUsbAckSetupPacket(h, UsbAckCallback, 0) ;
}
}
/* This includes the implementation of the deprecated functions for backward
* compatibility
*/
#include "cyasusb_dep_impl.h"
/*[]*/