/* Cypress West Bridge API source file (cyasusb.c) ## =========================== ## Copyright (C) 2010 Cypress Semiconductor ## ## This program is free software; you can redistribute it and/or ## modify it under the terms of the GNU General Public License ## as published by the Free Software Foundation; either version 2 ## of the License, or (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 51 Franklin Street, Fifth Floor ## Boston, MA 02110-1301, USA. ## =========================== */ #include "../../include/linux/westbridge/cyashal.h" #include "../../include/linux/westbridge/cyasusb.h" #include "../../include/linux/westbridge/cyaserr.h" #include "../../include/linux/westbridge/cyasdma.h" #include "../../include/linux/westbridge/cyaslowlevel.h" #include "../../include/linux/westbridge/cyaslep2pep.h" #include "../../include/linux/westbridge/cyasregs.h" #include "../../include/linux/westbridge/cyasstorage.h" static cy_as_return_status_t cy_as_usb_ack_setup_packet( /* Handle to the West Bridge device */ cy_as_device_handle handle, /* The callback if async call */ cy_as_function_callback cb, /* Client supplied data */ uint32_t client ) ; static void cy_as_usb_func_callback( cy_as_device *dev_p, uint8_t context, cy_as_ll_request_response *rqt, cy_as_ll_request_response *resp, cy_as_return_status_t ret) ; /* * Reset the USB EP0 state */ static void cy_as_usb_reset_e_p0_state(cy_as_device *dev_p) { cy_as_log_debug_message(6, "cy_as_usb_reset_e_p0_state called") ; cy_as_device_clear_ack_delayed(dev_p) ; cy_as_device_clear_setup_packet(dev_p) ; if (cy_as_device_is_usb_async_pending(dev_p, 0)) cy_as_usb_cancel_async((cy_as_device_handle)dev_p, 0) ; dev_p->usb_pending_buffer = 0 ; } /* * External function to map logical endpoints to physical endpoints */ static cy_as_return_status_t is_usb_active(cy_as_device *dev_p) { if (!cy_as_device_is_configured(dev_p)) return CY_AS_ERROR_NOT_CONFIGURED ; if (!cy_as_device_is_firmware_loaded(dev_p)) return CY_AS_ERROR_NO_FIRMWARE ; if (dev_p->usb_count == 0) return CY_AS_ERROR_NOT_RUNNING ; if (cy_as_device_is_in_suspend_mode(dev_p)) return CY_AS_ERROR_IN_SUSPEND ; return CY_AS_ERROR_SUCCESS ; } static void usb_ack_callback(cy_as_device_handle h, cy_as_return_status_t status, uint32_t client, cy_as_funct_c_b_type type, void *data) { cy_as_device *dev_p = (cy_as_device *)h ; (void)client ; (void)status ; (void)data ; cy_as_hal_assert(type == CY_FUNCT_CB_NODATA) ; if (dev_p->usb_pending_buffer) { cy_as_usb_io_callback cb ; cb = dev_p->usb_cb[0] ; dev_p->usb_cb[0] = 0 ; cy_as_device_clear_usb_async_pending(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 ; } cy_as_device_clear_setup_packet(dev_p) ; } static void my_usb_request_callback_usb_event(cy_as_device *dev_p, cy_as_ll_request_response *req_p) { uint16_t ev ; uint16_t val ; cy_as_device_handle h = (cy_as_device_handle)dev_p ; ev = cy_as_ll_request_response__get_word(req_p, 0) ; switch (ev) { case 0: /* Reserved */ cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_INVALID_REQUEST, 0) ; break ; case 1: /* Reserved */ cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_INVALID_REQUEST, 0) ; break ; case 2: /* USB Suspend */ dev_p->usb_last_event = cy_as_event_usb_suspend ; if (dev_p->usb_event_cb_ms) dev_p->usb_event_cb_ms(h, cy_as_event_usb_suspend, 0) ; else if (dev_p->usb_event_cb) dev_p->usb_event_cb(h, cy_as_event_usb_suspend, 0) ; cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; break; case 3: /* USB Resume */ dev_p->usb_last_event = cy_as_event_usb_resume ; if (dev_p->usb_event_cb_ms) dev_p->usb_event_cb_ms(h, cy_as_event_usb_resume, 0) ; else if (dev_p->usb_event_cb) dev_p->usb_event_cb(h, cy_as_event_usb_resume, 0) ; cy_as_ll_send_status_response(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 (cy_as_device_is_ack_delayed(dev_p)) cy_as_usb_reset_e_p0_state(dev_p) ; dev_p->usb_last_event = cy_as_event_usb_reset ; if (dev_p->usb_event_cb_ms) dev_p->usb_event_cb_ms(h, cy_as_event_usb_reset, 0) ; else if (dev_p->usb_event_cb) dev_p->usb_event_cb(h, cy_as_event_usb_reset, 0) ; cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; cy_as_device_clear_usb_high_speed(dev_p) ; cy_as_usb_set_dma_sizes(dev_p) ; dev_p->usb_max_tx_size = 0x40 ; cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x40) ; break ; case 5: /* USB Set Configuration */ /* The configuration to set */ val = cy_as_ll_request_response__get_word(req_p, 1) ; dev_p->usb_last_event = cy_as_event_usb_set_config ; if (dev_p->usb_event_cb_ms) dev_p->usb_event_cb_ms(h, cy_as_event_usb_set_config, &val) ; else if (dev_p->usb_event_cb) dev_p->usb_event_cb(h, cy_as_event_usb_set_config, &val) ; cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; break ; case 6: /* USB Speed change */ /* Connect speed */ val = cy_as_ll_request_response__get_word(req_p, 1) ; dev_p->usb_last_event = cy_as_event_usb_speed_change ; if (dev_p->usb_event_cb_ms) dev_p->usb_event_cb_ms(h, cy_as_event_usb_speed_change, &val) ; else if (dev_p->usb_event_cb) dev_p->usb_event_cb(h, cy_as_event_usb_speed_change, &val) ; cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; cy_as_device_set_usb_high_speed(dev_p) ; cy_as_usb_set_dma_sizes(dev_p) ; dev_p->usb_max_tx_size = 0x200 ; cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x200) ; break ; case 7: /* USB Clear Feature */ /* EP Number */ val = cy_as_ll_request_response__get_word(req_p, 1) ; if (dev_p->usb_event_cb_ms) dev_p->usb_event_cb_ms(h, cy_as_event_usb_clear_feature, &val) ; if (dev_p->usb_event_cb) dev_p->usb_event_cb(h, cy_as_event_usb_clear_feature, &val) ; cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; break ; default: cy_as_hal_print_message("invalid event type\n") ; cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_RESP_USB_INVALID_EVENT, sizeof(ev), &ev) ; break ; } } static void my_usb_request_callback_usb_data(cy_as_device *dev_p, cy_as_ll_request_response *req_p) { cy_as_end_point_number_t ep ; uint8_t type ; uint16_t len ; uint16_t val ; cy_as_device_handle h = (cy_as_device_handle)dev_p ; val = cy_as_ll_request_response__get_word(req_p, 0) ; ep = (cy_as_end_point_number_t)((val >> 13) & 0x01) ; len = (val & 0x1ff) ; cy_as_hal_assert(len <= 64) ; cy_as_ll_request_response__unpack(req_p, 1, len, dev_p->usb_ep_data) ; type = (uint8_t)((val >> 14) & 0x03) ; if (type == 0) { if (cy_as_device_is_ack_delayed(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. */ cy_as_usb_reset_e_p0_state(dev_p) ; } if (len != 8) cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_INVALID_REQUEST, 0) ; else { cy_as_device_clear_ep0_stalled(dev_p) ; cy_as_device_set_setup_packet(dev_p) ; cy_as_ll_send_status_response(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, cy_as_event_usb_setup_packet, dev_p->usb_ep_data) ; else dev_p->usb_event_cb(h, cy_as_event_usb_setup_packet, dev_p->usb_ep_data) ; if ((!cy_as_device_is_ack_delayed(dev_p)) && (!cy_as_device_is_ep0_stalled(dev_p))) cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0) ; } } else if (type == 2) { if (len != 0) cy_as_ll_send_status_response(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, cy_as_event_usb_status_packet, 0) ; else dev_p->usb_event_cb(h, cy_as_event_usb_status_packet, 0) ; cy_as_ll_send_status_response(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. */ cy_as_dma_received_data(dev_p, ep, len, dev_p->usb_ep_data) ; cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0) ; } } static void my_usb_request_callback_inquiry(cy_as_device *dev_p, cy_as_ll_request_response *req_p) { cy_as_usb_inquiry_data_dep cbdata ; cy_as_usb_inquiry_data cbdata_ms ; void *data ; uint16_t val ; cy_as_device_handle h = (cy_as_device_handle)dev_p ; uint8_t def_inq_data[64] ; uint8_t evpd ; uint8_t codepage ; cy_bool updated ; uint16_t length ; cy_as_bus_number_t bus ; uint32_t device ; cy_as_media_type media ; val = cy_as_ll_request_response__get_word(req_p, 0) ; bus = cy_as_storage_get_bus_from_address(val) ; device = cy_as_storage_get_device_from_address(val) ; media = cy_as_storage_get_media_from_address(val) ; val = cy_as_ll_request_response__get_word(req_p, 1) ; evpd = (uint8_t)((val >> 8) & 0x01) ; codepage = (uint8_t)(val & 0xff) ; length = cy_as_ll_request_response__get_word(req_p, 2) ; data = (void *)def_inq_data ; updated = cy_false ; 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 ; cy_as_hal_assert(cbdata_ms.length <= sizeof(def_inq_data)) ; cy_as_ll_request_response__unpack(req_p, 3, cbdata_ms.length, cbdata_ms.data) ; dev_p->usb_event_cb_ms(h, cy_as_event_usb_inquiry_before, &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 ; cy_as_hal_assert(cbdata.length <= sizeof(def_inq_data)) ; cy_as_ll_request_response__unpack(req_p, 3, cbdata.length, cbdata.data) ; dev_p->usb_event_cb(h, cy_as_event_usb_inquiry_before, &cbdata) ; updated = cbdata.updated ; data = cbdata.data ; length = cbdata.length ; } if (updated && length > 192) cy_as_hal_print_message("an inquiry result from a " "cy_as_event_usb_inquiry_before 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. */ cy_as_ll_send_data_response(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 */ cy_as_ll_send_status_response(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, cy_as_event_usb_inquiry_after, &cbdata_ms) ; else if (dev_p->usb_event_cb) dev_p->usb_event_cb(h, cy_as_event_usb_inquiry_after, &cbdata) ; } static void my_usb_request_callback_start_stop(cy_as_device *dev_p, cy_as_ll_request_response *req_p) { cy_as_bus_number_t bus ; cy_as_media_type media ; uint32_t device ; uint16_t val ; if (dev_p->usb_event_cb_ms || dev_p->usb_event_cb) { cy_bool loej ; cy_bool start ; cy_as_device_handle h = (cy_as_device_handle)dev_p ; val = cy_as_ll_request_response__get_word(req_p, 0) ; bus = cy_as_storage_get_bus_from_address(val) ; device = cy_as_storage_get_device_from_address(val) ; media = cy_as_storage_get_media_from_address(val) ; val = cy_as_ll_request_response__get_word(req_p, 1) ; loej = (val & 0x02) ? cy_true : cy_false ; start = (val & 0x01) ? cy_true : cy_false ; if (dev_p->usb_event_cb_ms) { cy_as_usb_start_stop_data 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, cy_as_event_usb_start_stop, &cbdata_ms) ; } else if (dev_p->usb_event_cb) { cy_as_usb_start_stop_data_dep cbdata ; cbdata.media = media ; cbdata.loej = loej ; cbdata.start = start ; dev_p->usb_event_cb(h, cy_as_event_usb_start_stop, &cbdata) ; } } cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1) ; } static void my_usb_request_callback_uknown_c_b_w(cy_as_device *dev_p, cy_as_ll_request_response *req_p) { uint16_t val ; cy_as_device_handle h = (cy_as_device_handle)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 = cy_as_ll_request_response__get_word(req_p, 0) ; /* Failed by default */ status = 1 ; /* Invalid command */ key = 0x05 ; /* Invalid command */ asc = 0x20 ; /* Invalid command */ ascq = 0x00 ; reqlen = cy_as_ll_request_response__get_word(req_p, 1) ; request = buf ; cy_as_hal_assert(reqlen <= sizeof(buf)) ; cy_as_ll_request_response__unpack(req_p, 2, reqlen, request) ; if (dev_p->usb_event_cb_ms) { cy_as_usb_unknown_command_data cbdata_ms ; cbdata_ms.bus = cy_as_storage_get_bus_from_address(val) ; cbdata_ms.device = cy_as_storage_get_device_from_address(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, cy_as_event_usb_unknown_storage, &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) { cy_as_usb_unknown_command_data_dep cbdata ; cbdata.media = cy_as_storage_get_media_from_address(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, cy_as_event_usb_unknown_storage, &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 ; cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_RESP_UNKNOWN_SCSI_COMMAND, sizeof(response), response) ; } static void my_usb_request_callback_m_s_c_progress(cy_as_device *dev_p, cy_as_ll_request_response *req_p) { uint16_t val1, val2 ; cy_as_device_handle h = (cy_as_device_handle)dev_p ; if ((dev_p->usb_event_cb) || (dev_p->usb_event_cb_ms)) { cy_as_m_s_c_progress_data cbdata ; val1 = cy_as_ll_request_response__get_word(req_p, 0) ; val2 = cy_as_ll_request_response__get_word(req_p, 1) ; cbdata.wr_count = (uint32_t)((val1 << 16) | val2) ; val1 = cy_as_ll_request_response__get_word(req_p, 2) ; val2 = cy_as_ll_request_response__get_word(req_p, 3) ; cbdata.rd_count = (uint32_t)((val1 << 16) | val2) ; if (dev_p->usb_event_cb) dev_p->usb_event_cb(h, cy_as_event_usb_m_s_c_progress, &cbdata) ; else dev_p->usb_event_cb_ms(h, cy_as_event_usb_m_s_c_progress, &cbdata) ; } cy_as_ll_send_status_response(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 my_usb_request_callback(cy_as_device *dev_p, uint8_t context, cy_as_ll_request_response *req_p, cy_as_ll_request_response *resp_p, cy_as_return_status_t ret) { uint16_t val ; uint8_t code = cy_as_ll_request_response__get_code(req_p) ; (void)resp_p ; (void)context ; (void)ret ; switch (code) { case CY_RQT_USB_EVENT: my_usb_request_callback_usb_event(dev_p, req_p) ; break ; case CY_RQT_USB_EP_DATA: dev_p->usb_last_event = cy_as_event_usb_setup_packet ; my_usb_request_callback_usb_data(dev_p, req_p) ; break ; case CY_RQT_SCSI_INQUIRY_COMMAND: dev_p->usb_last_event = cy_as_event_usb_inquiry_after ; my_usb_request_callback_inquiry(dev_p, req_p) ; break ; case CY_RQT_SCSI_START_STOP_COMMAND: dev_p->usb_last_event = cy_as_event_usb_start_stop ; my_usb_request_callback_start_stop(dev_p, req_p) ; break ; case CY_RQT_SCSI_UNKNOWN_COMMAND: dev_p->usb_last_event = cy_as_event_usb_unknown_storage ; my_usb_request_callback_uknown_c_b_w(dev_p, req_p) ; break ; case CY_RQT_USB_ACTIVITY_UPDATE: dev_p->usb_last_event = cy_as_event_usb_m_s_c_progress ; my_usb_request_callback_m_s_c_progress(dev_p, req_p) ; break ; default: cy_as_hal_print_message("invalid request " "received on USB context\n") ; val = req_p->box0 ; cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT, CY_RESP_INVALID_REQUEST, sizeof(val), &val) ; break ; } } static cy_as_return_status_t my_handle_response_usb_start(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p, cy_as_return_status_t ret) { if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_SUCCESS_FAILURE) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } ret = cy_as_ll_request_response__get_word(reply_p, 0) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; /* * mark EP 0 and EP1 as 64 byte endpoints */ cy_as_dma_set_max_dma_size(dev_p, 0, 64) ; cy_as_dma_set_max_dma_size(dev_p, 1, 64) ; dev_p->usb_count++ ; destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) { cy_as_destroy_c_b_queue(dev_p->usb_func_cbs) ; cy_as_ll_register_request_callback(dev_p, CY_RQT_USB_RQT_CONTEXT, 0) ; } cy_as_device_clear_u_s_s_pending(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. */ cy_as_return_status_t cy_as_usb_start(cy_as_device_handle handle, cy_as_function_callback cb, uint32_t client) { cy_as_ll_request_response *req_p, *reply_p ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_start called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; if (!cy_as_device_is_configured(dev_p)) return CY_AS_ERROR_NOT_CONFIGURED ; if (!cy_as_device_is_firmware_loaded(dev_p)) return CY_AS_ERROR_NO_FIRMWARE ; if (cy_as_device_is_in_suspend_mode(dev_p)) return CY_AS_ERROR_IN_SUSPEND ; if (cy_as_device_is_in_callback(dev_p)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; if (cy_as_device_is_u_s_s_pending(dev_p)) return CY_AS_ERROR_STARTSTOP_PENDING ; cy_as_device_set_u_s_s_pending(dev_p) ; if (dev_p->usb_count == 0) { /* * since we are just starting the stack, * mark USB as not connected to the remote host */ cy_as_device_clear_usb_connected(dev_p) ; dev_p->usb_phy_config = 0 ; /* Queue for 1.0 Async Requests, kept for * backwards compatibility */ dev_p->usb_func_cbs = cy_as_create_c_b_queue(CYAS_USB_FUNC_CB) ; if (dev_p->usb_func_cbs == 0) { cy_as_device_clear_u_s_s_pending(dev_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } /* Reset the EP0 state */ cy_as_usb_reset_e_p0_state(dev_p) ; /* * we register here becuase the start request may cause * events to occur before the response to the start request. */ cy_as_ll_register_request_callback(dev_p, CY_RQT_USB_RQT_CONTEXT, my_usb_request_callback) ; /* Create the request to send to the West Bridge device */ req_p = cy_as_ll_create_request(dev_p, CY_RQT_START_USB, CY_RQT_USB_RQT_CONTEXT, 0) ; if (req_p == 0) { cy_as_destroy_c_b_queue(dev_p->usb_func_cbs) ; dev_p->usb_func_cbs = 0 ; cy_as_device_clear_u_s_s_pending(dev_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } /* Reserve space for the reply, the reply data * will not exceed one word */ reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_destroy_c_b_queue(dev_p->usb_func_cbs) ; dev_p->usb_func_cbs = 0 ; cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_device_clear_u_s_s_pending(dev_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return my_handle_response_usb_start(dev_p, req_p, reply_p, ret) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_START, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; } else { dev_p->usb_count++ ; if (cb) cb(handle, ret, client, CY_FUNCT_CB_USB_START, 0) ; } cy_as_device_clear_u_s_s_pending(dev_p) ; return ret ; } void cy_as_usb_reset(cy_as_device *dev_p) { int i ; cy_as_device_clear_usb_connected(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 (cy_as_device_is_usb_async_pending(dev_p, i)) cy_as_usb_cancel_async(dev_p, (cy_as_end_point_number_t)i) ; dev_p->usb_cb[i] = 0 ; dev_p->usb_config[i].enabled = cy_false ; } 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 cy_as_usb_cleanup(cy_as_device *dev_p) { if (dev_p->usb_count) { cy_as_usb_reset_e_p0_state(dev_p) ; cy_as_usb_reset(dev_p) ; cy_as_hal_mem_set(dev_p->usb_config, 0, sizeof(dev_p->usb_config)) ; cy_as_destroy_c_b_queue(dev_p->usb_func_cbs) ; dev_p->usb_count = 0 ; } } static cy_as_return_status_t my_handle_response_usb_stop(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p, cy_as_return_status_t ret) { if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_SUCCESS_FAILURE) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } ret = cy_as_ll_request_response__get_word(reply_p, 0) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; /* * we sucessfully shutdown the stack, so * decrement to make the count zero. */ cy_as_usb_cleanup(dev_p) ; destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) cy_as_ll_register_request_callback(dev_p, CY_RQT_USB_RQT_CONTEXT, 0) ; cy_as_device_clear_u_s_s_pending(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. */ cy_as_return_status_t cy_as_usb_stop(cy_as_device_handle handle, cy_as_function_callback cb, uint32_t client) { cy_as_ll_request_response *req_p = 0, *reply_p = 0 ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_stop called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_usb_connected(dev_p)) return CY_AS_ERROR_USB_CONNECTED ; if (cy_as_device_is_in_callback(dev_p)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; if (cy_as_device_is_u_s_s_pending(dev_p)) return CY_AS_ERROR_STARTSTOP_PENDING ; cy_as_device_set_u_s_s_pending(dev_p) ; if (dev_p->usb_count == 1) { /* Create the request to send to the West Bridge device */ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { ret = CY_AS_ERROR_OUT_OF_MEMORY ; goto destroy ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return my_handle_response_usb_stop(dev_p, req_p, reply_p, ret) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_STOP, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; } else if (dev_p->usb_count > 1) { /* * reset all LE_ps to inactive state, after cleaning * up any pending async read/write calls. */ cy_as_usb_reset(dev_p) ; dev_p->usb_count-- ; if (cb) cb(handle, ret, client, CY_FUNCT_CB_USB_STOP, 0) ; } cy_as_device_clear_u_s_s_pending(dev_p) ; return ret ; } /* * This function registers a callback to be called when * USB events are processed */ cy_as_return_status_t cy_as_usb_register_callback(cy_as_device_handle handle, cy_as_usb_event_callback callback) { cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_register_callback called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; if (!cy_as_device_is_configured(dev_p)) return CY_AS_ERROR_NOT_CONFIGURED ; if (!cy_as_device_is_firmware_loaded(dev_p)) return CY_AS_ERROR_NO_FIRMWARE ; dev_p->usb_event_cb = NULL ; dev_p->usb_event_cb_ms = callback ; return CY_AS_ERROR_SUCCESS ; } static cy_as_return_status_t my_handle_response_no_data(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p) { cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_SUCCESS_FAILURE) ret = CY_AS_ERROR_INVALID_RESPONSE ; else ret = cy_as_ll_request_response__get_word(reply_p, 0) ; cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } static cy_as_return_status_t my_handle_response_connect(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p, cy_as_return_status_t ret) { if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_SUCCESS_FAILURE) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } ret = cy_as_ll_request_response__get_word(reply_p, 0) ; if (ret == CY_AS_ERROR_SUCCESS) cy_as_device_set_usb_connected(dev_p) ; destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(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. */ cy_as_return_status_t cy_as_usb_connect(cy_as_device_handle handle, cy_as_function_callback cb, uint32_t client) { cy_as_ll_request_response *req_p , *reply_p ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_connect called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(dev_p)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; /* Create the request to send to the West Bridge device */ req_p = cy_as_ll_create_request(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 */ cy_as_ll_request_response__set_word(req_p, 0, 1) ; /* Reserve space for the reply, the reply * data will not exceed one word */ reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return my_handle_response_connect(dev_p, req_p, reply_p, ret) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_CONNECT, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } static cy_as_return_status_t my_handle_response_disconnect(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p, cy_as_return_status_t ret) { if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_SUCCESS_FAILURE) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } ret = cy_as_ll_request_response__get_word(reply_p, 0) ; if (ret == CY_AS_ERROR_SUCCESS) cy_as_device_clear_usb_connected(dev_p) ; destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(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 connected USB host. */ cy_as_return_status_t cy_as_usb_disconnect(cy_as_device_handle handle, cy_as_function_callback cb, uint32_t client) { cy_as_ll_request_response *req_p , *reply_p ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_disconnect called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(dev_p)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; if (!cy_as_device_is_usb_connected(dev_p)) return CY_AS_ERROR_USB_NOT_CONNECTED ; /* Create the request to send to the West Bridge device */ req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1) ; if (req_p == 0) return CY_AS_ERROR_OUT_OF_MEMORY ; cy_as_ll_request_response__set_word(req_p, 0, 0) ; /* Reserve space for the reply, the reply * data will not exceed two bytes */ reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return my_handle_response_disconnect(dev_p, req_p, reply_p, ret) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_DISCONNECT, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } static cy_as_return_status_t my_handle_response_set_enum_config(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p) { cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_SUCCESS_FAILURE) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } ret = cy_as_ll_request_response__get_word(reply_p, 0) ; 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 */ cy_as_usb_end_point_config config ; config.dir = cy_as_usb_in_out ; config.type = cy_as_usb_control ; config.enabled = cy_true ; ret = cy_as_usb_set_end_point_config((cy_as_device_handle *) dev_p, 0, &config) ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } /* * This method sets how the USB is enumerated and should * be called before the CyAsUsbConnect() is called. */ static cy_as_return_status_t my_usb_set_enum_config(cy_as_device *dev_p, uint8_t bus_mask, uint8_t media_mask, cy_bool use_antioch_enumeration, uint8_t mass_storage_interface, uint8_t mtp_interface, cy_bool mass_storage_callbacks, cy_as_function_callback cb, uint32_t client) { cy_as_ll_request_response *req_p , *reply_p ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; cy_as_log_debug_message(6, "cy_as_usb_set_enum_config called") ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_usb_connected(dev_p)) return CY_AS_ERROR_USB_CONNECTED ; if (cy_as_device_is_in_callback(dev_p)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; /* if we are using MTP firmware: */ if (dev_p->is_mtp_firmware == 1) { /* we cannot enumerate MSC */ if (mass_storage_interface != 0) 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 */ cy_as_dma_enable_end_point(dev_p, 1, cy_true, cy_as_direction_in) ; dev_p->usb_config[1].enabled = cy_true ; dev_p->usb_config[1].dir = cy_as_usb_in ; dev_p->usb_config[1].type = cy_as_usb_int ; } else { return CY_AS_ERROR_INVALID_CONFIGURATION ; } /* if we are not using MTP firmware, we cannot enumerate MTP */ } else if (mtp_interface != 0) 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 = cy_as_ll_create_request(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 */ cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)((media_mask << 8) | bus_mask)) ; cy_as_ll_request_response__set_word(req_p, 1, (uint16_t)use_antioch_enumeration) ; cy_as_ll_request_response__set_word(req_p, 2, dev_p->is_mtp_firmware ? mtp_interface : mass_storage_interface) ; cy_as_ll_request_response__set_word(req_p, 3, (uint16_t)mass_storage_callbacks) ; /* Reserve space for the reply, the reply * data will not exceed one word */ reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return my_handle_response_set_enum_config(dev_p, req_p, reply_p) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_SETENUMCONFIG, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } /* * This method sets how the USB is enumerated and should * be called before the CyAsUsbConnect() is called. */ cy_as_return_status_t cy_as_usb_set_enum_config(cy_as_device_handle handle, cy_as_usb_enum_control *config_p, cy_as_function_callback cb, uint32_t client) { cy_as_device *dev_p = (cy_as_device *)handle ; uint8_t bus_mask, media_mask ; uint32_t bus, device ; cy_as_return_status_t ret ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if ((cy_as_device_is_in_callback(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] == cy_true) { bus_mask |= (0x01 << bus) ; media_mask |= dev_p->media_supported[bus] ; media_mask |= dev_p->media_supported[bus] ; } } } return my_usb_set_enum_config(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 cy_as_return_status_t my_handle_response_get_enum_config(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p, void *config_p) { cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; uint16_t val ; uint8_t bus_mask ; uint32_t bus ; if (cy_as_ll_request_response__get_code(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 ; cy_bool state; cy_as_usb_enum_control *ms_config_p = (cy_as_usb_enum_control *)config_p; bus_mask = (uint8_t) (cy_as_ll_request_response__get_word (reply_p, 0) & 0xFF) ; for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) { if (bus_mask & (1 << bus)) state = cy_true ; else state = cy_false ; for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++) ms_config_p->devices_to_enumerate[bus][device] = state ; } ms_config_p->antioch_enumeration = (cy_bool)cy_as_ll_request_response__get_word (reply_p, 1) ; val = cy_as_ll_request_response__get_word(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 = (cy_bool)(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 { cy_as_usb_enum_control_dep *ex_config_p = (cy_as_usb_enum_control_dep *)config_p; ex_config_p->enum_mass_storage = (uint8_t) ((cy_as_ll_request_response__get_word (reply_p, 0) >> 8) & 0xFF) ; ex_config_p->antioch_enumeration = (cy_bool) cy_as_ll_request_response__get_word(reply_p, 1) ; val = cy_as_ll_request_response__get_word(reply_p, 2) ; ex_config_p->mass_storage_interface = (uint8_t)(val & 0xFF) ; ex_config_p->mass_storage_callbacks = (cy_bool)(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: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(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 cy_as_return_status_t my_usb_get_enum_config(cy_as_device_handle handle, uint16_t req_flags, void *config_p, cy_as_function_callback cb, uint32_t client) { cy_as_ll_request_response *req_p , *reply_p ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_get_enum_config called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(dev_p)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; /* Create the request to send to the West Bridge device */ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 3) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; /* we need to know the type of request to * know how to manage the data */ req_p->flags |= req_flags; return my_handle_response_get_enum_config(dev_p, req_p, reply_p, config_p) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_GETENUMCONFIG, config_p, dev_p->func_cbs_usb, req_flags, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(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. */ cy_as_return_status_t cy_as_usb_get_enum_config(cy_as_device_handle handle, cy_as_usb_enum_control *config_p, cy_as_function_callback cb, uint32_t client) { return my_usb_get_enum_config(handle, CY_AS_REQUEST_RESPONSE_MS, config_p, cb, client); } /* * This method sets the USB descriptor for a given entity. */ cy_as_return_status_t cy_as_usb_set_descriptor(cy_as_device_handle handle, cy_as_usb_desc_type type, uint8_t index, void *desc_p, uint16_t length, cy_as_function_callback cb, uint32_t client) { cy_as_ll_request_response *req_p , *reply_p ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; uint16_t pktlen ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_set_descriptor called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(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 = cy_as_ll_create_request(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 ; cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)((uint8_t)type | (index << 8))) ; cy_as_ll_request_response__set_word(req_p, 1, (uint16_t)length) ; cy_as_ll_request_response__pack(req_p, 2, length, desc_p) ; reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return my_handle_response_no_data(dev_p, req_p, reply_p) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_SETDESCRIPTOR, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } /* * This method clears all descriptors that were previously * stored on the West Bridge through CyAsUsbSetDescriptor calls. */ cy_as_return_status_t cy_as_usb_clear_descriptors(cy_as_device_handle handle, cy_as_function_callback cb, uint32_t client) { cy_as_ll_request_response *req_p , *reply_p ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_clear_descriptors called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if ((cy_as_device_is_in_callback(dev_p)) && (cb == 0)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; /* Create the request to send to the West Bridge device */ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return my_handle_response_no_data(dev_p, req_p, reply_p) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_CLEARDESCRIPTORS, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } static cy_as_return_status_t my_handle_response_get_descriptor(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p, cy_as_get_descriptor_data *data) { cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; uint32_t retlen ; if (cy_as_ll_request_response__get_code(reply_p) == CY_RESP_SUCCESS_FAILURE) { ret = cy_as_ll_request_response__get_word(reply_p, 0) ; goto destroy ; } else if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_USB_DESCRIPTOR) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } retlen = cy_as_ll_request_response__get_word(reply_p, 0) ; if (retlen > data->length) { ret = CY_AS_ERROR_INVALID_SIZE ; goto destroy ; } ret = CY_AS_ERROR_SUCCESS ; cy_as_ll_request_response__unpack(reply_p, 1, retlen, data->desc_p) ; destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } /* * This method retreives the USB descriptor for a given type. */ cy_as_return_status_t cy_as_usb_get_descriptor(cy_as_device_handle handle, cy_as_usb_desc_type type, uint8_t index, cy_as_get_descriptor_data *data, cy_as_function_callback cb, uint32_t client) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p , *reply_p ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_get_descriptor called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(dev_p)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; /* Create the request to send to the West Bridge device */ req_p = cy_as_ll_create_request(dev_p, CY_RQT_GET_DESCRIPTOR, CY_RQT_USB_RQT_CONTEXT, 1) ; if (req_p == 0) return CY_AS_ERROR_OUT_OF_MEMORY ; cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)((uint8_t)type | (index << 8))) ; /* Add one for the length field */ reply_p = cy_as_ll_create_response(dev_p, CY_AS_MAX_USB_DESCRIPTOR_SIZE + 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply( dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return my_handle_response_get_descriptor(dev_p, req_p, reply_p, data) ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_GETDESCRIPTOR, data, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } cy_as_return_status_t cy_as_usb_set_physical_configuration(cy_as_device_handle handle, uint8_t config) { cy_as_return_status_t ret ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_set_physical_configuration called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_usb_connected(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 cy_bool is_physical_valid(uint8_t config, cy_as_end_point_number_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))) ? cy_true : cy_false ; } /* * This method sets the configuration for an endpoint */ cy_as_return_status_t cy_as_usb_set_end_point_config(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p) { cy_as_return_status_t ret ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_set_end_point_config called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_usb_connected(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 != cy_as_usb_in_out || config_p->type != cy_as_usb_control) return CY_AS_ERROR_INVALID_CONFIGURATION ; } else if (ep == 1) { if ((dev_p->is_mtp_firmware == 1) && (dev_p->usb_config[1].enabled == cy_true)) { 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 == cy_as_usb_control) || (config_p->type == cy_as_usb_iso) || (config_p->dir == cy_as_usb_in_out)) return CY_AS_ERROR_INVALID_CONFIGURATION ; } else { if (config_p->dir == cy_as_usb_in_out || config_p->type == cy_as_usb_control) return CY_AS_ERROR_INVALID_CONFIGURATION ; if (!is_physical_valid(dev_p->usb_phy_config, config_p->physical)) return CY_AS_ERROR_INVALID_PHYSICAL_ENDPOINT ; /* * ISO endpoints must be on E_ps 3, 5, 7 or 9 as * they need to align directly with the underlying * physical endpoint. */ if (config_p->type == cy_as_usb_iso) { 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. */ cy_as_hal_assert((int)cy_as_usb_in == (int)cy_as_direction_in); cy_as_hal_assert((int)cy_as_usb_out == (int)cy_as_direction_out); cy_as_hal_assert((int)cy_as_usb_in_out == (int)cy_as_direction_in_out) ; return cy_as_dma_enable_end_point(dev_p, ep, config_p->enabled, (cy_as_dma_direction)config_p->dir) ; } cy_as_return_status_t cy_as_usb_get_end_point_config(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p) { cy_as_return_status_t ret ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_get_end_point_config called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(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. */ cy_as_return_status_t cy_as_usb_commit_config(cy_as_device_handle handle, cy_as_function_callback cb, uint32_t client) { uint32_t i ; cy_as_return_status_t ret ; cy_as_ll_request_response *req_p , *reply_p ; cy_as_device *dev_p ; uint16_t data ; cy_as_log_debug_message(6, "cy_as_usb_commit_config called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_usb_connected(dev_p)) return CY_AS_ERROR_USB_CONNECTED ; if (cy_as_device_is_in_callback(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 = cy_as_usb_map_logical2_physical(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 = cy_as_ll_create_request(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 ; cy_as_hal_print_message("USB configuration: %d\n", dev_p->usb_phy_config) ; cy_as_hal_print_message("EP1OUT: 0x%02x EP1IN: 0x%02x\n", dev_p->usb_ep1cfg[0], dev_p->usb_ep1cfg[1]) ; cy_as_hal_print_message("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]) ; cy_as_hal_print_message("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]) ; cy_as_ll_request_response__set_word(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]) ; cy_as_ll_request_response__set_word(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]) ; cy_as_ll_request_response__set_word(req_p, 3 + i / 2, data) ; } /* A single status word response type */ reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; ret = my_handle_response_no_data(dev_p, req_p, reply_p) ; if (ret == CY_AS_ERROR_SUCCESS) ret = cy_as_usb_setup_dma(dev_p) ; return ret ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_COMMITCONFIG, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } static void sync_request_callback(cy_as_device *dev_p, cy_as_end_point_number_t ep, void *buf_p, uint32_t size, cy_as_return_status_t err) { (void)ep ; (void)buf_p ; dev_p->usb_error = err ; dev_p->usb_actual_cnt = size ; } static void async_read_request_callback(cy_as_device *dev_p, cy_as_end_point_number_t ep, void *buf_p, uint32_t size, cy_as_return_status_t err) { cy_as_device_handle h ; cy_as_log_debug_message(6, "async_read_request_callback called") ; h = (cy_as_device_handle)dev_p ; if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) { dev_p->usb_pending_buffer = buf_p ; dev_p->usb_pending_size = size ; dev_p->usb_error = err ; cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0) ; } else { cy_as_usb_io_callback cb ; cb = dev_p->usb_cb[ep] ; dev_p->usb_cb[ep] = 0 ; cy_as_device_clear_usb_async_pending(dev_p, ep) ; if (cb) cb(h, ep, size, buf_p, err) ; } } static void async_write_request_callback(cy_as_device *dev_p, cy_as_end_point_number_t ep, void *buf_p, uint32_t size, cy_as_return_status_t err) { cy_as_device_handle h ; cy_as_log_debug_message(6, "async_write_request_callback called") ; h = (cy_as_device_handle)dev_p ; if (ep == 0 && cy_as_device_is_ack_delayed(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. */ cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0) ; } else { cy_as_usb_io_callback cb ; cb = dev_p->usb_cb[ep] ; dev_p->usb_cb[ep] = 0 ; cy_as_device_clear_usb_async_pending(dev_p, ep) ; if (cb) cb(h, ep, size, buf_p, err) ; } } static void my_turbo_rqt_callback(cy_as_device *dev_p, uint8_t context, cy_as_ll_request_response *rqt, cy_as_ll_request_response *resp, cy_as_return_status_t stat) { uint8_t code ; (void)context ; (void)stat ; /* The Handlers are responsible for Deleting the rqt and resp when * they are finished */ code = cy_as_ll_request_response__get_code(rqt) ; switch (code) { case CY_RQT_TURBO_SWITCH_ENDPOINT: cy_as_hal_assert(stat == CY_AS_ERROR_SUCCESS) ; cy_as_ll_destroy_request(dev_p, rqt) ; cy_as_ll_destroy_response(dev_p, resp) ; break; default: cy_as_hal_assert(cy_false) ; break ; } } /* Send a mailbox request to prepare the endpoint for switching */ static cy_as_return_status_t my_send_turbo_switch(cy_as_device *dev_p, uint32_t size, cy_bool pktread) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p , *reply_p ; /* Create the request to send to the West Bridge device */ req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)pktread) ; cy_as_ll_request_response__set_word(req_p, 1, (uint16_t)((size >> 16) & 0xFFFF)) ; cy_as_ll_request_response__set_word(req_p, 2, (uint16_t)(size & 0xFFFF)) ; ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_false, my_turbo_rqt_callback) ; if (ret != CY_AS_ERROR_SUCCESS) { cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_request(dev_p, reply_p) ; return ret ; } return CY_AS_ERROR_SUCCESS ; } cy_as_return_status_t cy_as_usb_read_data(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_bool pktread, uint32_t dsize, uint32_t *dataread, void *data) { cy_as_return_status_t ret ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_read_data called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(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 != cy_as_usb_out) return CY_AS_ERROR_USB_BAD_DIRECTION ; ret = cy_as_dma_queue_request(dev_p, ep, data, dsize, pktread, cy_true, sync_request_callback) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (ep == CY_AS_MTP_READ_ENDPOINT) { ret = my_send_turbo_switch(dev_p, dsize, pktread) ; if (ret != CY_AS_ERROR_SUCCESS) { cy_as_dma_cancel(dev_p, ep, ret) ; return ret ; } ret = cy_as_dma_drain_queue(dev_p, ep, cy_false) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; } else { ret = cy_as_dma_drain_queue(dev_p, ep, cy_true) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; } ret = dev_p->usb_error ; *dataread = dev_p->usb_actual_cnt ; return ret ; } cy_as_return_status_t cy_as_usb_read_data_async(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_bool pktread, uint32_t dsize, void *data, cy_as_usb_io_callback cb) { cy_as_return_status_t ret ; uint32_t mask ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_read_data_async called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(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 != cy_as_usb_out && dev_p->usb_config[ep].dir != cy_as_usb_in_out) 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 = cy_as_hal_disable_interrupts() ; if (cy_as_device_is_usb_async_pending(dev_p, ep)) { cy_as_hal_enable_interrupts(mask) ; return CY_AS_ERROR_ASYNC_PENDING ; } cy_as_device_set_usb_async_pending(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) cy_as_device_set_ack_delayed(dev_p) ; cy_as_hal_enable_interrupts(mask) ; cy_as_hal_assert(dev_p->usb_cb[ep] == 0) ; dev_p->usb_cb[ep] = cb ; ret = cy_as_dma_queue_request(dev_p, ep, data, dsize, pktread, cy_true, async_read_request_callback) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (ep == CY_AS_MTP_READ_ENDPOINT) { ret = my_send_turbo_switch(dev_p, dsize, pktread) ; if (ret != CY_AS_ERROR_SUCCESS) { cy_as_dma_cancel(dev_p, ep, ret) ; return ret ; } } else { /* Kick start the queue if it is not running */ cy_as_dma_kick_start(dev_p, ep) ; } return ret ; } cy_as_return_status_t cy_as_usb_write_data(cy_as_device_handle handle, cy_as_end_point_number_t ep, uint32_t dsize, void *data) { cy_as_return_status_t ret ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_write_data called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(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 != cy_as_usb_in && dev_p->usb_config[ep].dir != cy_as_usb_in_out) return CY_AS_ERROR_USB_BAD_DIRECTION ; /* Write on Turbo endpoint */ if (ep == CY_AS_MTP_WRITE_ENDPOINT) { cy_as_ll_request_response *req_p, *reply_p ; req_p = cy_as_ll_create_request(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 ; cy_as_ll_request_response__set_word(req_p, 0, 0x0006) ; /* EP number to use. */ cy_as_ll_request_response__set_word(req_p, 1, (uint16_t)((dsize >> 16) & 0xFFFF)) ; cy_as_ll_request_response__set_word(req_p, 2, (uint16_t)(dsize & 0xFFFF)) ; /* Reserve space for the reply, the reply data * will not exceed one word */ reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (dsize) { ret = cy_as_dma_queue_request(dev_p, ep, data, dsize, cy_false, cy_false, sync_request_callback) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; } ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret == CY_AS_ERROR_SUCCESS) { if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_SUCCESS_FAILURE) ret = CY_AS_ERROR_INVALID_RESPONSE ; else ret = cy_as_ll_request_response__get_word (reply_p, 0); } cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) { if (dsize) cy_as_dma_cancel(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 = cy_as_dma_queue_request(dev_p, ep, data, dsize, cy_false, cy_false, sync_request_callback) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; } if (ep != CY_AS_MTP_WRITE_ENDPOINT) ret = cy_as_dma_drain_queue(dev_p, ep, cy_true) ; else ret = cy_as_dma_drain_queue(dev_p, ep, cy_false) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; ret = dev_p->usb_error ; return ret ; } static void mtp_write_callback( cy_as_device *dev_p, uint8_t context, cy_as_ll_request_response *rqt, cy_as_ll_request_response *resp, cy_as_return_status_t ret) { cy_as_usb_io_callback cb ; cy_as_device_handle h = (cy_as_device_handle)dev_p ; cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT) ; if (ret == CY_AS_ERROR_SUCCESS) { if (cy_as_ll_request_response__get_code(resp) != CY_RESP_SUCCESS_FAILURE) ret = CY_AS_ERROR_INVALID_RESPONSE ; else ret = cy_as_ll_request_response__get_word(resp, 0) ; } /* If this was a zero byte transfer request, we can * call the callback from here. */ if ((cy_as_ll_request_response__get_word(rqt, 1) == 0) && (cy_as_ll_request_response__get_word(rqt, 2) == 0)) { cb = dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] ; dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] = 0 ; cy_as_device_clear_usb_async_pending(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. */ cy_as_dma_cancel(dev_p, 0x06, CY_AS_ERROR_CANCELED) ; dev_p->usb_cb[0x06] = 0 ; cy_as_device_clear_usb_async_pending(dev_p, 0x06) ; } destroy: cy_as_ll_destroy_response(dev_p, resp) ; cy_as_ll_destroy_request(dev_p, rqt) ; } cy_as_return_status_t cy_as_usb_write_data_async(cy_as_device_handle handle, cy_as_end_point_number_t ep, uint32_t dsize, void *data, cy_bool spacket, cy_as_usb_io_callback cb) { uint32_t mask ; cy_as_return_status_t ret ; cy_as_device *dev_p ; cy_as_log_debug_message(6, "cy_as_usb_write_data_async called") ; dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(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 != cy_as_usb_in && dev_p->usb_config[ep].dir != cy_as_usb_in_out) 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 = cy_as_hal_disable_interrupts() ; if (cy_as_device_is_usb_async_pending(dev_p, ep)) { cy_as_hal_enable_interrupts(mask) ; return CY_AS_ERROR_ASYNC_PENDING ; } cy_as_device_set_usb_async_pending(dev_p, ep) ; if (ep == 0) cy_as_device_set_ack_delayed(dev_p) ; cy_as_hal_enable_interrupts(mask) ; cy_as_hal_assert(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) { cy_as_ll_request_response *req_p, *reply_p ; req_p = cy_as_ll_create_request(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 ; cy_as_ll_request_response__set_word(req_p, 0, 0x0006) ; /* EP number to use. */ cy_as_ll_request_response__set_word(req_p, 1, (uint16_t)((dsize >> 16) & 0xFFFF)) ; cy_as_ll_request_response__set_word(req_p, 2, (uint16_t)(dsize & 0xFFFF)) ; /* Reserve space for the reply, the reply data * will not exceed one word */ reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (dsize) { ret = cy_as_dma_queue_request(dev_p, ep, data, dsize, cy_false, cy_false, async_write_request_callback) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; } ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_false, mtp_write_callback) ; if (ret != CY_AS_ERROR_SUCCESS) { if (dsize) cy_as_dma_cancel(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 = cy_as_dma_queue_request(dev_p, ep, data, dsize, cy_false, cy_false, async_write_request_callback) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; } /* Kick start the queue if it is not running */ if (ep != CY_AS_MTP_WRITE_ENDPOINT) cy_as_dma_kick_start(dev_p, ep) ; return CY_AS_ERROR_SUCCESS ; } static void my_usb_cancel_async_callback( cy_as_device *dev_p, uint8_t context, cy_as_ll_request_response *rqt, cy_as_ll_request_response *resp, cy_as_return_status_t ret) { uint8_t ep ; (void)context ; ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0) ; if (ret == CY_AS_ERROR_SUCCESS) { if (cy_as_ll_request_response__get_code(resp) != CY_RESP_SUCCESS_FAILURE) ret = CY_AS_ERROR_INVALID_RESPONSE ; else ret = cy_as_ll_request_response__get_word(resp, 0) ; } cy_as_ll_destroy_request(dev_p, rqt) ; cy_as_ll_destroy_response(dev_p, resp) ; if (ret == CY_AS_ERROR_SUCCESS) { cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED) ; dev_p->usb_cb[ep] = 0 ; cy_as_device_clear_usb_async_pending(dev_p, ep) ; } } cy_as_return_status_t cy_as_usb_cancel_async(cy_as_device_handle handle, cy_as_end_point_number_t ep) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p, *reply_p ; cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ep &= 0x7F; /* Remove the direction bit. */ if (!cy_as_device_is_usb_async_pending(dev_p, ep)) return CY_AS_ERROR_ASYNC_NOT_PENDING; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_suspend_mode(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 = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)ep) ; ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_false, my_usb_cancel_async_callback) ; if (ret != CY_AS_ERROR_SUCCESS) { cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } } else { ret = cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; dev_p->usb_cb[ep] = 0 ; cy_as_device_clear_usb_async_pending(dev_p, ep) ; } return CY_AS_ERROR_SUCCESS ; } static void cy_as_usb_ack_callback( cy_as_device *dev_p, uint8_t context, cy_as_ll_request_response *rqt, cy_as_ll_request_response *resp, cy_as_return_status_t ret) { cy_as_func_c_b_node *node = (cy_as_func_c_b_node *) dev_p->func_cbs_usb->head_p ; (void)context ; if (ret == CY_AS_ERROR_SUCCESS) { if (cy_as_ll_request_response__get_code(resp) != CY_RESP_SUCCESS_FAILURE) ret = CY_AS_ERROR_INVALID_RESPONSE ; else ret = cy_as_ll_request_response__get_word(resp, 0) ; } node->cb_p((cy_as_device_handle)dev_p, ret, node->client_data, node->data_type, node->data) ; cy_as_remove_c_b_node(dev_p->func_cbs_usb) ; cy_as_ll_destroy_request(dev_p, rqt) ; cy_as_ll_destroy_response(dev_p, resp) ; cy_as_device_clear_ack_delayed(dev_p) ; } static cy_as_return_status_t cy_as_usb_ack_setup_packet(cy_as_device_handle handle, cy_as_function_callback cb, uint32_t client) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p ; cy_as_ll_request_response *reply_p ; cy_as_func_c_b_node *cbnode ; cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(dev_p) && cb == 0) return CY_AS_ERROR_INVALID_IN_CALLBACK ; cy_as_hal_assert(cb != 0) ; cbnode = cy_as_create_func_c_b_node(cb, client); if (cbnode == 0) return CY_AS_ERROR_OUT_OF_MEMORY ; req_p = cy_as_ll_create_request(dev_p, 0, CY_RQT_USB_RQT_CONTEXT, 2) ; if (req_p == 0) return CY_AS_ERROR_OUT_OF_MEMORY ; reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } cy_as_ll_init_request(req_p, CY_RQT_ACK_SETUP_PACKET, CY_RQT_USB_RQT_CONTEXT, 1) ; cy_as_ll_init_response(reply_p, 1) ; req_p->flags |= CY_AS_REQUEST_RESPONSE_EX ; cy_as_insert_c_b_node(dev_p->func_cbs_usb, cbnode) ; ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_false, cy_as_usb_ack_callback) ; 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 cy_as_usb_flush_logical_e_p( cy_as_device *dev_p, uint16_t ep) { uint16_t addr, val, count ; addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2 ; val = cy_as_hal_read_register(dev_p->tag, addr) ; while (val) { count = ((val & 0xFFF) + 1) / 2 ; while (count--) val = cy_as_hal_read_register(dev_p->tag, ep) ; cy_as_hal_write_register(dev_p->tag, addr, 0) ; val = cy_as_hal_read_register(dev_p->tag, addr) ; } } static cy_as_return_status_t cy_as_usb_nak_stall_request(cy_as_device_handle handle, cy_as_end_point_number_t ep, uint16_t request, cy_bool state, cy_as_usb_function_callback cb, cy_as_function_callback fcb, uint32_t client) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p , *reply_p ; uint16_t data ; cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; if (cb) cy_as_hal_assert(fcb == 0) ; if (fcb) cy_as_hal_assert(cb == 0) ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(dev_p) && cb == 0 && fcb == 0) return CY_AS_ERROR_INVALID_IN_CALLBACK ; req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } /* Set the endpoint */ data = (uint8_t)ep ; cy_as_ll_request_response__set_word(req_p, 0, data) ; /* Set stall state to stalled */ cy_as_ll_request_response__set_word(req_p, 1, (uint8_t)state) ; if (cb || fcb) { void *cbnode ; cy_as_c_b_queue *queue ; if (cb) { cbnode = cy_as_create_usb_func_c_b_node(cb, client) ; queue = dev_p->usb_func_cbs ; } else { cbnode = cy_as_create_func_c_b_node(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 cy_as_insert_c_b_node(queue, cbnode) ; if (cy_as_device_is_setup_packet(dev_p)) { /* No Ack is needed on a stall request on EP0 */ if ((state == cy_true) && (ep == 0)) { cy_as_device_set_ep0_stalled(dev_p) ; } else { cy_as_device_set_ack_delayed(dev_p) ; req_p->flags |= CY_AS_REQUEST_RESPONSE_DELAY_ACK ; } } ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_false, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) { if (req_p->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK) cy_as_device_rem_ack_delayed(dev_p) ; cy_as_remove_c_b_tail_node(queue) ; goto destroy ; } } else { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (cy_as_ll_request_response__get_code(reply_p) != CY_RESP_SUCCESS_FAILURE) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } ret = cy_as_ll_request_response__get_word(reply_p, 0) ; if ((ret == CY_AS_ERROR_SUCCESS) && (request == CY_RQT_STALL_ENDPOINT)) { if ((ep > 1) && (state != 0) && (dev_p->usb_config[ep].dir == cy_as_usb_out)) cy_as_usb_flush_logical_e_p(dev_p, ep) ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; } return ret ; } static cy_as_return_status_t my_handle_response_get_stall(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p, cy_bool *state_p) { cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; uint8_t code = cy_as_ll_request_response__get_code(reply_p) ; if (code == CY_RESP_SUCCESS_FAILURE) { ret = cy_as_ll_request_response__get_word(reply_p, 0) ; goto destroy ; } else if (code != CY_RESP_ENDPOINT_STALL) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0) ; ret = CY_AS_ERROR_SUCCESS ; destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } static cy_as_return_status_t my_handle_response_get_nak(cy_as_device *dev_p, cy_as_ll_request_response *req_p, cy_as_ll_request_response *reply_p, cy_bool *state_p) { cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; uint8_t code = cy_as_ll_request_response__get_code(reply_p) ; if (code == CY_RESP_SUCCESS_FAILURE) { ret = cy_as_ll_request_response__get_word(reply_p, 0) ; goto destroy ; } else if (code != CY_RESP_ENDPOINT_NAK) { ret = CY_AS_ERROR_INVALID_RESPONSE ; goto destroy ; } *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0) ; ret = CY_AS_ERROR_SUCCESS ; destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } static cy_as_return_status_t cy_as_usb_get_nak_stall(cy_as_device_handle handle, cy_as_end_point_number_t ep, uint16_t request, uint16_t response, cy_bool *state_p, cy_as_function_callback cb, uint32_t client) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p , *reply_p ; uint16_t data ; cy_as_device *dev_p = (cy_as_device *)handle ; (void)response ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(dev_p) && !cb) return CY_AS_ERROR_INVALID_IN_CALLBACK ; req_p = cy_as_ll_create_request(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 ; cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)ep) ; /* A single status word response type */ reply_p = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (request == CY_RQT_GET_STALL) return my_handle_response_get_stall(dev_p, req_p, reply_p, state_p) ; else return my_handle_response_get_nak(dev_p, req_p, reply_p, state_p) ; } else { cy_as_funct_c_b_type type ; if (request == CY_RQT_GET_STALL) type = CY_FUNCT_CB_USB_GETSTALL ; else type = CY_FUNCT_CB_USB_GETNAK ; ret = cy_as_misc_send_request(dev_p, cb, client, type, state_p, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } cy_as_return_status_t cy_as_usb_set_nak(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_as_function_callback cb, uint32_t client) { cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; /* * 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 == cy_as_usb_in) ep |= 0x80 ; if (dev_p->mtp_count > 0) return CY_AS_ERROR_NOT_VALID_IN_MTP ; return cy_as_usb_nak_stall_request(handle, ep, CY_RQT_ENDPOINT_SET_NAK, cy_true, 0, cb, client) ; } cy_as_return_status_t cy_as_usb_clear_nak(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_as_function_callback cb, uint32_t client) { cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; /* * 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 == cy_as_usb_in) ep |= 0x80 ; if (dev_p->mtp_count > 0) return CY_AS_ERROR_NOT_VALID_IN_MTP ; return cy_as_usb_nak_stall_request(handle, ep, CY_RQT_ENDPOINT_SET_NAK, cy_false, 0, cb, client) ; } cy_as_return_status_t cy_as_usb_get_nak(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_bool *nak_p, cy_as_function_callback cb, uint32_t client) { cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; /* * 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 == cy_as_usb_in) ep |= 0x80 ; if (dev_p->mtp_count > 0) return CY_AS_ERROR_NOT_VALID_IN_MTP ; return cy_as_usb_get_nak_stall(handle, ep, CY_RQT_GET_ENDPOINT_NAK, CY_RESP_ENDPOINT_NAK, nak_p, cb, client) ; } cy_as_return_status_t cy_as_usb_set_stall(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_as_function_callback cb, uint32_t client) { cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; /* * 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 == cy_as_usb_in) ep |= 0x80 ; if (dev_p->mtp_turbo_active) return CY_AS_ERROR_NOT_VALID_DURING_MTP ; return cy_as_usb_nak_stall_request(handle, ep, CY_RQT_STALL_ENDPOINT, cy_true, 0, cb, client) ; } cy_as_return_status_t cy_as_usb_clear_stall(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_as_function_callback cb, uint32_t client) { cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; /* * 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 == cy_as_usb_in) ep |= 0x80 ; if (dev_p->mtp_turbo_active) return CY_AS_ERROR_NOT_VALID_DURING_MTP ; return cy_as_usb_nak_stall_request(handle, ep, CY_RQT_STALL_ENDPOINT, cy_false, 0, cb, client) ; } cy_as_return_status_t cy_as_usb_get_stall(cy_as_device_handle handle, cy_as_end_point_number_t ep, cy_bool *stall_p, cy_as_function_callback cb, uint32_t client) { cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; /* * 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 == cy_as_usb_in) ep |= 0x80 ; if (dev_p->mtp_turbo_active) return CY_AS_ERROR_NOT_VALID_DURING_MTP ; return cy_as_usb_get_nak_stall(handle, ep, CY_RQT_GET_STALL, CY_RESP_ENDPOINT_STALL, stall_p, cb, client) ; } cy_as_return_status_t cy_as_usb_signal_remote_wakeup(cy_as_device_handle handle, cy_as_function_callback cb, uint32_t client) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p , *reply_p ; cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if (cy_as_device_is_in_callback(dev_p)) return CY_AS_ERROR_INVALID_IN_CALLBACK ; if (dev_p->usb_last_event != cy_as_event_usb_suspend) return CY_AS_ERROR_NOT_IN_SUSPEND ; req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (cy_as_ll_request_response__get_code(reply_p) == CY_RESP_SUCCESS_FAILURE) ret = cy_as_ll_request_response__get_word(reply_p, 0) ; else ret = CY_AS_ERROR_INVALID_RESPONSE ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_USB_SIGNALREMOTEWAKEUP, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } cy_as_return_status_t cy_as_usb_set_m_s_report_threshold(cy_as_device_handle handle, uint32_t wr_sectors, uint32_t rd_sectors, cy_as_function_callback cb, uint32_t client) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p , *reply_p ; cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(dev_p) ; if (ret != CY_AS_ERROR_SUCCESS) return ret ; if ((cb == 0) && (cy_as_device_is_in_callback(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 << cy_as_media_nand))) return CY_AS_ERROR_NOT_SUPPORTED ; req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } /* Set the read and write count parameters into * the request structure. */ cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)((wr_sectors >> 16) & 0xFFFF)) ; cy_as_ll_request_response__set_word(req_p, 1, (uint16_t)(wr_sectors & 0xFFFF)) ; cy_as_ll_request_response__set_word(req_p, 2, (uint16_t)((rd_sectors >> 16) & 0xFFFF)) ; cy_as_ll_request_response__set_word(req_p, 3, (uint16_t)(rd_sectors & 0xFFFF)) ; if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (cy_as_ll_request_response__get_code(reply_p) == CY_RESP_SUCCESS_FAILURE) ret = cy_as_ll_request_response__get_word(reply_p, 0) ; else ret = CY_AS_ERROR_INVALID_RESPONSE ; } else { ret = cy_as_misc_send_request(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, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } cy_as_return_status_t cy_as_usb_select_m_s_partitions( cy_as_device_handle handle, cy_as_bus_number_t bus, uint32_t device, cy_as_usb_m_s_type_t type, cy_as_function_callback cb, uint32_t client) { cy_as_return_status_t ret ; cy_as_ll_request_response *req_p , *reply_p ; uint16_t val ; cy_as_device *dev_p = (cy_as_device *)handle ; if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE)) return CY_AS_ERROR_INVALID_HANDLE ; ret = is_usb_active(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) && (cy_as_device_is_in_callback(dev_p))) return CY_AS_ERROR_INVALID_IN_CALLBACK ; req_p = cy_as_ll_create_request(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 = cy_as_ll_create_response(dev_p, 1) ; if (reply_p == 0) { cy_as_ll_destroy_request(dev_p, req_p) ; return CY_AS_ERROR_OUT_OF_MEMORY ; } /* Set the read and write count parameters into * the request structure. */ cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)((bus << 8) | device)) ; val = 0 ; if ((type == cy_as_usb_m_s_unit0) || (type == cy_as_usb_m_s_both)) val |= 1 ; if ((type == cy_as_usb_m_s_unit1) || (type == cy_as_usb_m_s_both)) val |= (1 << 8) ; cy_as_ll_request_response__set_word(req_p, 1, val) ; if (cb == 0) { ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; if (cy_as_ll_request_response__get_code(reply_p) == CY_RESP_SUCCESS_FAILURE) ret = cy_as_ll_request_response__get_word(reply_p, 0) ; else ret = CY_AS_ERROR_INVALID_RESPONSE ; } else { ret = cy_as_misc_send_request(dev_p, cb, client, CY_FUNCT_CB_NODATA, 0, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p, cy_as_usb_func_callback) ; if (ret != CY_AS_ERROR_SUCCESS) goto destroy ; return ret ; } destroy: cy_as_ll_destroy_request(dev_p, req_p) ; cy_as_ll_destroy_response(dev_p, reply_p) ; return ret ; } static void cy_as_usb_func_callback( cy_as_device *dev_p, uint8_t context, cy_as_ll_request_response *rqt, cy_as_ll_request_response *resp, cy_as_return_status_t stat) { cy_as_usb_func_c_b_node* node = (cy_as_usb_func_c_b_node *) dev_p->usb_func_cbs->head_p ; cy_as_func_c_b_node* fnode = (cy_as_func_c_b_node *) dev_p->func_cbs_usb->head_p ; cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS ; cy_as_device_handle h = (cy_as_device_handle)dev_p ; cy_bool delayed_ack = (rqt->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK) == CY_AS_REQUEST_RESPONSE_DELAY_ACK; cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX) == CY_AS_REQUEST_RESPONSE_EX ; cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS) == CY_AS_REQUEST_RESPONSE_MS ; uint8_t code ; uint8_t ep, state ; if (!ex_request && !ms_request) { cy_as_hal_assert(dev_p->usb_func_cbs->count != 0) ; cy_as_hal_assert(dev_p->usb_func_cbs->type == CYAS_USB_FUNC_CB) ; } else { cy_as_hal_assert(dev_p->func_cbs_usb->count != 0) ; cy_as_hal_assert(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 = cy_as_ll_request_response__get_code(rqt) ; switch (code) { case CY_RQT_START_USB: ret = my_handle_response_usb_start(dev_p, rqt, resp, stat) ; break ; case CY_RQT_STOP_USB: ret = my_handle_response_usb_stop(dev_p, rqt, resp, stat) ; break ; case CY_RQT_SET_CONNECT_STATE: if (!cy_as_ll_request_response__get_word(rqt, 0)) ret = my_handle_response_disconnect( dev_p, rqt, resp, stat) ; else ret = my_handle_response_connect( dev_p, rqt, resp, stat) ; break ; case CY_RQT_GET_CONNECT_STATE: break ; case CY_RQT_SET_USB_CONFIG: ret = my_handle_response_set_enum_config(dev_p, rqt, resp) ; break ; case CY_RQT_GET_USB_CONFIG: cy_as_hal_assert(fnode->data != 0) ; ret = my_handle_response_get_enum_config(dev_p, rqt, resp, fnode->data) ; break ; case CY_RQT_STALL_ENDPOINT: ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0) ; state = (uint8_t)cy_as_ll_request_response__get_word(rqt, 1) ; ret = my_handle_response_no_data(dev_p, rqt, resp) ; if ((ret == CY_AS_ERROR_SUCCESS) && (ep > 1) && (state != 0) && (dev_p->usb_config[ep].dir == cy_as_usb_out)) cy_as_usb_flush_logical_e_p(dev_p, ep) ; break ; case CY_RQT_GET_STALL: cy_as_hal_assert(fnode->data != 0) ; ret = my_handle_response_get_stall(dev_p, rqt, resp, (cy_bool *)fnode->data) ; break ; case CY_RQT_SET_DESCRIPTOR: ret = my_handle_response_no_data(dev_p, rqt, resp) ; break ; case CY_RQT_GET_DESCRIPTOR: cy_as_hal_assert(fnode->data != 0) ; ret = my_handle_response_get_descriptor(dev_p, rqt, resp, (cy_as_get_descriptor_data *)fnode->data) ; break; case CY_RQT_SET_USB_CONFIG_REGISTERS: ret = my_handle_response_no_data(dev_p, rqt, resp) ; if (ret == CY_AS_ERROR_SUCCESS) ret = cy_as_usb_setup_dma(dev_p) ; break ; case CY_RQT_ENDPOINT_SET_NAK: ret = my_handle_response_no_data(dev_p, rqt, resp) ; break ; case CY_RQT_GET_ENDPOINT_NAK: cy_as_hal_assert(fnode->data != 0) ; ret = my_handle_response_get_nak(dev_p, rqt, resp, (cy_bool *)fnode->data) ; break ; case CY_RQT_ACK_SETUP_PACKET: break ; case CY_RQT_USB_REMOTE_WAKEUP: ret = my_handle_response_no_data(dev_p, rqt, resp) ; break ; case CY_RQT_CLEAR_DESCRIPTORS: ret = my_handle_response_no_data(dev_p, rqt, resp) ; break ; case CY_RQT_USB_STORAGE_MONITOR: ret = my_handle_response_no_data(dev_p, rqt, resp) ; break ; case CY_RQT_MS_PARTITION_SELECT: ret = my_handle_response_no_data(dev_p, rqt, resp) ; break ; default: ret = CY_AS_ERROR_INVALID_RESPONSE ; cy_as_hal_assert(cy_false) ; break ; } /* * if the low level layer returns a direct error, use * the corresponding error code. if not, use the error * code based on the response from firmware. */ if (stat == CY_AS_ERROR_SUCCESS) stat = ret ; if (ex_request || ms_request) { fnode->cb_p((cy_as_device_handle)dev_p, stat, fnode->client_data, fnode->data_type, fnode->data) ; cy_as_remove_c_b_node(dev_p->func_cbs_usb) ; } else { node->cb_p((cy_as_device_handle)dev_p, stat, node->client_data) ; cy_as_remove_c_b_node(dev_p->usb_func_cbs) ; } if (delayed_ack) { cy_as_hal_assert(cy_as_device_is_ack_delayed(dev_p)) ; cy_as_device_rem_ack_delayed(dev_p) ; /* * send the ACK if required. */ if (!cy_as_device_is_ack_delayed(dev_p)) cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0) ; } } /*[]*/