diff -r b7e488c49d0d -r 117faf51deac omap3530/beagle_drivers/wb/api/src/cyasusb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omap3530/beagle_drivers/wb/api/src/cyasusb.c Wed Mar 03 13:10:32 2010 +0000 @@ -0,0 +1,3613 @@ +/* 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 +## +## /license/license.txt +## +## where 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 ; + uint16_t data ; + + 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 */ + data = (uint8_t)ep ; + 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" + +/*[]*/