/*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);
   }
}
/****************************************************************************//**
 * @brief      Get Report command
 *
 * @param[in]  _usb_device_handle
 *
 * @return TRUE or FALSE
 *
 *******************************************************************************/
uint32_t HID_GetReport(_usb_device_handle handle)
{
    /* added the handle */
    _usb_device_send_data(handle, 0, ReportDescriptor, sizeof(ReportDescriptor));

    return (TRUE);
}
/*FUNCTION*----------------------------------------------------------------
* 
* Function Name  : ch9SetConfig
* Returned Value : None
* Comments       :
*     Chapter 9 SetConfig 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 configuration number and go to the CONFIG state.
* 
*END*--------------------------------------------------------------------*/
void    mvUsbCh9SetConfig(_usb_device_handle handle,
                        boolean setup, SETUP_STRUCT* setup_ptr)
{ /* Body */
   static uint_8            new_config;

   ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ADDR, "%s: setup=%d, config=%d\n", 
                                    __FUNCTION__, (int)setup, setup_ptr->VALUE);

   if (setup) 
   {
      new_config = 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.
       *******************************************************/
       _usb_device_set_status(handle, ARC_USB_STATUS_CURRENT_CONFIG, new_config);
      /* ack */
      _usb_device_send_data(handle, 0, 0, 0);
   } 
   else 
   {
      _usb_device_set_status(handle, ARC_USB_STATUS_CURRENT_CONFIG, new_config);
      _usb_device_set_status(handle, ARC_USB_STATUS_DEVICE_STATE, ARC_USB_STATE_CONFIG);        
   }
}
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 */
/*FUNCTION*----------------------------------------------------------------
*
* Function Name  : _usb_dci_vusb20_set_test_mode
* Returned Value : None
* Comments       :
*     sets/resets the test mode
*
*END*--------------------------------------------------------------------*/
void _usb_dci_vusb20_set_test_mode(
					  /* [IN] Handle to the USB device */
					  _usb_device_handle handle,
					  /* [IN] Test mode */
					  uint16_t test_mode)
{				/* Body */
	USB_DEV_STATE_STRUCT_PTR usb_dev_ptr;
	VUSB20_REG_STRUCT_PTR dev_ptr;
	uint32_t temp;

#ifdef _DEVICE_DEBUG_
	DEBUG_LOG_TRACE("_usb_dci_vusb20_set_test_mode");
#endif

	usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR) handle;
	dev_ptr = (VUSB20_REG_STRUCT_PTR) usb_dev_ptr->DEV_PTR;

	temp = dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[0];

	dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[0] =
	    (temp | EHCI_EPCTRL_TX_DATA_TOGGLE_RST);

	if (test_mode == USB_TEST_MODE_TEST_PACKET) {
		_usb_device_send_data(handle, 0, test_packet,
				      USB_TEST_MODE_TEST_PACKET_LENGTH);
	}
	/* Endif */
	temp = dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0];
	temp &= ~EHCI_PORTSCX_W1C_BITS;

	dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0] = (temp |
								      ((uint32_t)
								       test_mode
								       << 8));

#ifdef _DEVICE_DEBUG_
	DEBUG_LOG_TRACE("_usb_dci_vusb20_set_test_mode, SUCCESSFUL");
#endif

}				/* EndBody */
/*FUNCTION*----------------------------------------------------------------
* 
* Function Name  : _usb_dci_vusb20_set_test_mode
* Returned Value : None
* Comments       :
*     sets/resets the test mode
* 
*END*--------------------------------------------------------------------*/
void _usb_dci_vusb20_set_test_mode
   (
      /* [IN] Handle to the USB device */
      _usb_device_handle handle,
      
      /* [IN] Test mode */
      uint_16 test_mode
   )
{ /* Body */
   USB_DEV_STATE_STRUCT_PTR                     usb_dev_ptr;
   VUSB20_REG_STRUCT_PTR                        dev_ptr;
   uint_32                                      temp;

   ARC_DEBUG_TRACE(ARC_DEBUG_FLAG_ANY, "set_test_mode\n");
   
   usb_dev_ptr = (USB_DEV_STATE_STRUCT_PTR)handle;
   dev_ptr = (VUSB20_REG_STRUCT_PTR)usb_dev_ptr->DEV_PTR;
   
   temp = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[0]);
   
   dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTCTRLX[0] = 
                                USB_32BIT_LE((temp | EHCI_EPCTRL_TX_DATA_TOGGLE_RST));

   if (test_mode == ARC_USB_TEST_MODE_TEST_PACKET) 
   {
       USB_memcopy(test_packet, usb_dev_ptr->TEST_PKT_PTR, USB_TEST_MODE_TEST_PACKET_LENGTH); 
      _usb_device_send_data(handle, 0, usb_dev_ptr->TEST_PKT_PTR, USB_TEST_MODE_TEST_PACKET_LENGTH);

   } /* Endif */
   
   temp = USB_32BIT_LE(dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0]);
   temp &= ~EHCI_PORTSCX_W1C_BITS;
   
   dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.PORTSCX[0] = 
                                    USB_32BIT_LE(temp | ((uint_32)test_mode << 8));
             
} /* 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 */
}