| /*******************************************************************************
|
|
|
| This software file (the "File") is distributed by Marvell International Ltd.
|
| or its affiliate(s) under the terms of the GNU General Public License Version 2,
|
| June 1991 (the "License"). You may use, redistribute and/or modify this File
|
| in accordance with the terms and conditions of the License, a copy of which
|
| is available along with the File in the license.txt file or by writing to the
|
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
| or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
|
|
|
| THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
|
| WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
|
| DISCLAIMED. The GPL License provides additional details about this warranty
|
| disclaimer.
|
|
|
| (C) Copyright 2004 - 2007 Marvell Semiconductor Israel Ltd. All Rights Reserved.
|
| (C) Copyright 1999 - 2004 Chipidea Microelectronica, S.A. All Rights Reserved.
|
|
|
| *******************************************************************************/
|
| |
| #include "usb/api/mvUsbDevApi.h" |
| #include "usb/device/mvUsbDevPrv.h" |
| #include "usb/api/mvUsbCh9.h" |
| |
| static volatile boolean ENTER_TEST_MODE = FALSE; |
| static volatile uint_16 test_mode_index = 0; |
| |
| |
| void mvUsbCh9GetStatus(_usb_device_handle handle, boolean setup, |
| SETUP_STRUCT* ctrl_req) |
| { /* Body */ |
| uint_8 endpoint, direction;
|
| uint_16 usb_status;
|
| USB_DEV_STATE_STRUCT* usb_dev_ptr = (USB_DEV_STATE_STRUCT*)handle;
|
| |
| ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "%s: setup=%d\n", __FUNCTION__, (int)setup); |
| |
| if(!setup) |
| return; |
| |
| switch (ctrl_req->REQUESTTYPE) |
| { |
| case (REQ_DIR_IN | REQ_RECIP_DEVICE): |
| /* Device request */ |
| _usb_device_get_status(handle, ARC_USB_STATUS_DEVICE, &usb_status); |
| break; |
| |
| case (REQ_DIR_IN | REQ_RECIP_INTERFACE): |
| /* Interface request */ |
| _usb_device_get_status(handle, ARC_USB_STATUS_INTERFACE, &usb_status); |
| break; |
| |
| case (REQ_DIR_IN | REQ_RECIP_ENDPOINT): |
| /* Endpoint request */ |
| endpoint = ctrl_req->INDEX & ARC_USB_STATUS_ENDPOINT_NUMBER_MASK;
|
| if( (ctrl_req->INDEX & (1 << REQ_DIR_OFFSET)) == REQ_DIR_IN)
|
| direction = ARC_USB_SEND;
|
| else
|
| direction = ARC_USB_RECV; |
| |
| usb_status = _usb_device_is_endpoint_stalled(handle, endpoint, direction);
|
| break; |
| |
| default: |
| /* Unknown request */ |
| USB_printf("GetStatus: Unknown request type 0x%x\n", ctrl_req->REQUESTTYPE); |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endswitch */ |
| |
| /* Send the requested data */ |
| *usb_dev_ptr->STATUS_PTR = USB_16BIT_LE(usb_status); |
| _usb_device_send_data(handle, 0, (uint_8_ptr)usb_dev_ptr->STATUS_PTR, sizeof(uint_16)); |
| |
| /* status phase */ |
| _usb_device_recv_data(handle, 0, NULL, 0); |
| |
| return; |
| } /* Endbody */ |
| |
| void mvUsbCh9ClearFeature(_usb_device_handle handle, boolean setup, |
| SETUP_STRUCT* setup_ptr) |
| { /* Body */ |
| uint_8 endpoint, direction; |
| uint_16 usb_status; |
| |
| ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "%s: setup=%d\n", __FUNCTION__, (int)setup); |
| |
| _usb_device_get_status(handle, ARC_USB_STATUS_DEVICE_STATE, &usb_status); |
| if ((usb_status != ARC_USB_STATE_CONFIG) && (usb_status != ARC_USB_STATE_ADDRESS)) |
| { |
| USB_printf("ClearFeature: Wrong USB state %d\n", usb_status); |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endif */ |
| |
| if(!setup) |
| return; |
| |
| switch (setup_ptr->REQUESTTYPE) |
| { |
| case (REQ_DIR_OUT | REQ_RECIP_DEVICE): |
| /* DEVICE */ |
| switch(setup_ptr->VALUE) |
| { |
| case DEVICE_REMOTE_WAKEUP: |
| /* clear remote wakeup */ |
| _usb_device_get_status(handle, ARC_USB_STATUS_DEVICE, &usb_status); |
| usb_status &= ~ARC_USB_REMOTE_WAKEUP; |
| _usb_device_set_status(handle, ARC_USB_STATUS_DEVICE, usb_status); |
| USB_printf("Clear REMOTE_WAKEUP feature\n"); |
| break; |
| |
| case DEVICE_TEST_MODE: |
| /* Exit Test Mode */ |
| _usb_device_set_status(handle, ARC_USB_STATUS_TEST_MODE, 0); |
| break; |
| |
| default: |
| USB_printf("ClearFeature: Unknown Device feature %d\n", |
| setup_ptr->VALUE); |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endif */ |
| break; |
| |
| case (REQ_DIR_OUT | REQ_RECIP_ENDPOINT): |
| /* ENDPOINT */ |
| if (setup_ptr->VALUE != ENDPOINT_HALT) |
| { |
| USB_printf("ClearFeature: Wrong Endpoint feature %d\n", |
| setup_ptr->VALUE); |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endif */ |
| |
| endpoint = setup_ptr->INDEX & ARC_USB_STATUS_ENDPOINT_NUMBER_MASK; |
| if( (setup_ptr->INDEX & (1 << REQ_DIR_OFFSET)) == REQ_DIR_IN)
|
| direction = ARC_USB_SEND;
|
| else
|
| direction = ARC_USB_RECV;
|
|
|
| _usb_device_unstall_endpoint(handle, endpoint, direction);
|
| break; |
| |
| default: |
| USB_printf("ClearFeature: Unknown REQUEST_TYPE %d\n", |
| setup_ptr->REQUESTTYPE); |
| |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endswitch */ |
| |
| /* status phase */ |
| _usb_device_send_data(handle, 0, 0, 0); |
| } |
| |
| void mvUsbCh9SetFeature(_usb_device_handle handle, boolean setup, |
| SETUP_STRUCT* setup_ptr) |
| { |
| uint_16 usb_status; |
| uint_8 endpoint, direction; |
| USB_DEV_STATE_STRUCT* usb_dev_ptr = (USB_DEV_STATE_STRUCT*)handle; |
| |
| ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_SETUP, "%s: setup=%d\n", __FUNCTION__, (int)setup); |
| |
| if (setup) |
| { |
| switch (setup_ptr->REQUESTTYPE) |
| { |
| case (REQ_DIR_OUT | REQ_RECIP_DEVICE): |
| /* DEVICE */ |
| switch (setup_ptr->VALUE) |
| { |
| case DEVICE_REMOTE_WAKEUP: |
| /* set remote wakeup */ |
| _usb_device_get_status(handle, ARC_USB_STATUS_DEVICE, &usb_status); |
| usb_status |= ARC_USB_REMOTE_WAKEUP; |
| _usb_device_set_status(handle, ARC_USB_STATUS_DEVICE, usb_status); |
| USB_printf("Set REMOTE_WAKEUP feature\n"); |
| break; |
| |
| case DEVICE_TEST_MODE: |
| /* Test Mode */ |
| if( (setup_ptr->INDEX & 0x00FF) || (usb_dev_ptr->SPEED != ARC_USB_SPEED_HIGH) ) |
| { |
| USB_printf("SetFeature: Wrong Test mode parameters: mode=%d, speed=%d\n", |
| (setup_ptr->INDEX & 0x00FF), usb_dev_ptr->SPEED); |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endif */ |
| |
| _usb_device_get_status(handle, ARC_USB_STATUS_DEVICE_STATE, &usb_status); |
| if( (usb_status == ARC_USB_STATE_CONFIG) || |
| (usb_status == ARC_USB_STATE_ADDRESS) || |
| (usb_status == ARC_USB_STATE_DEFAULT)) |
| { |
| /* wait with Set Test mode */ |
| ENTER_TEST_MODE = TRUE; |
| test_mode_index = (setup_ptr->INDEX & 0xFF00); |
| USB_printf("SetFeature: Prepare for Test mode 0x%x\n", test_mode_index); |
| } |
| else |
| { |
| USB_printf("SetFeature: Wrong USB state for Test mode: state=%d\n", |
| usb_status); |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endif */ |
| break; |
| |
| default: |
| USB_printf("SetFeature: Unknown Device feature %d\n", |
| setup_ptr->VALUE); |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endswitch */ |
| break; |
| |
| case (REQ_DIR_OUT | REQ_RECIP_ENDPOINT): |
| /* ENDPOINT */ |
| if (setup_ptr->VALUE != ENDPOINT_HALT) |
| { |
| USB_printf("SetFeature: Unknown Endpoint feature %d\n", |
| setup_ptr->VALUE); |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endif */ |
| |
| endpoint = setup_ptr->INDEX & ARC_USB_STATUS_ENDPOINT_NUMBER_MASK; |
| if( (setup_ptr->INDEX & (1 << REQ_DIR_OFFSET)) == REQ_DIR_IN)
|
| direction = ARC_USB_SEND;
|
| else
|
| direction = ARC_USB_RECV;
|
|
|
| _usb_device_stall_endpoint(handle, endpoint, direction);
|
| break; |
| |
| default: |
| USB_printf("SetFeature: Unknown REQUEST_TYPE %d\n", |
| setup_ptr->REQUESTTYPE); |
| |
| _usb_device_stall_endpoint(handle, 0, ARC_USB_RECV); |
| return; |
| } /* Endswitch */ |
| |
| /* status phase */ |
| _usb_device_send_data(handle, 0, 0, 0); |
| } |
| else |
| { |
| if (ENTER_TEST_MODE) |
| { |
| /* Enter Test Mode */ |
| USB_printf("SetFeature: Activate Test mode 0x%x\n", test_mode_index); |
| _usb_device_set_status(handle, ARC_USB_STATUS_TEST_MODE, test_mode_index); |
| } /* Endif */ |
| } /* Endif */ |
| } |
| |
| /*FUNCTION*---------------------------------------------------------------- |
| * |
| * Function Name : ch9SetAddress |
| * Returned Value : None |
| * Comments : |
| * Chapter 9 SetAddress command |
| * We setup a TX packet of 0 length ready for the IN token |
| * Once we get the TOK_DNE interrupt for the IN token, then |
| * we change the ADDR register and go to the ADDRESS state. |
| * |
| *END*--------------------------------------------------------------------*/ |
| void mvUsbCh9SetAddress(_usb_device_handle handle, |
| boolean setup, SETUP_STRUCT* setup_ptr) |
| { /* Body */ |
| static uint_8 new_address; |
| |
| ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ADDR, "usbDisk %s: setup=%d, address=%d\n", |
| __FUNCTION__, (int)setup, setup_ptr->VALUE); |
| |
| if (setup) |
| { |
| new_address = setup_ptr->VALUE; |
| /******************************************************* |
| * if hardware assitance is enabled for set_address (see |
| * hardware rev for details) we need to do the set_address |
| * before queuing the status phase. |
| *******************************************************/ |
| #ifdef SET_ADDRESS_HARDWARE_ASSISTANCE |
| _usb_device_set_status(handle, ARC_USB_STATUS_ADDRESS, new_address); |
| #endif |
| /* ack */ |
| _usb_device_send_data(handle, 0, 0, 0); |
| } |
| else |
| { |
| #ifndef SET_ADDRESS_HARDWARE_ASSISTANCE |
| _usb_device_set_status(handle, ARC_USB_STATUS_ADDRESS, new_address); |
| #endif |
| _usb_device_set_status(handle, ARC_USB_STATUS_DEVICE_STATE, ARC_USB_STATE_ADDRESS); |
| } |
| } |