/**HEADER********************************************************************
* 
* Copyright (c) 2008, 2013 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
*************************************************************************** 
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: usb_host_msd_queue.c$
* $Version : 
* $Date    : 
*
* Comments:
*
*   Implements the queue system for the mass storage class.
*
*END************************************************************************/
#include "usb_host_config.h"
#include "usb.h"
#include "usb_host_stack_interface.h"
#include "usb_host_dev_mng.h"
#include "usb_host_ch9.h"
#include "usb_host_common.h"
#include "usb_host_msd_bo.h"
#include "usb_host.h"

#define MASSQ_NEXT(index)   (uint8_t)( index ==(QUEUE_SIZE - 1)?0:index+1)

/*FUNCTION*----------------------------------------------------------------
*
* Function Name  : usb_class_mass_q_init
* Returned Value : None
* Comments       :
*     This function initializes a mass storage class queue.
*
*END*--------------------------------------------------------------------*/

void usb_class_mass_q_init
   (
      /* [IN] interface structure pointer */
      USB_MASS_CLASS_STRUCT_PTR msd_class_ptr
   )
{ /* Body */
   uint32_t i = 0;
   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_q_init");
   #endif

   msd_class_ptr->QUEUE.FIRST  = 0;
   msd_class_ptr->QUEUE.LAST   = 0;
   msd_class_ptr->QUEUE.COUNT  = 0;
   for(i = 0; i < QUEUE_SIZE; i++)
   {
	   msd_class_ptr->QUEUE.ELEMENTS[i] = NULL;
   }
   //_mem_zero(&msd_class_ptr->QUEUE, sizeof(msd_class_ptr->QUEUE));
   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_q_init, SUCCESSFUL");
   #endif
   
} /* Endbody */


/*FUNCTION*----------------------------------------------------------------
*
* Function Name  : usb_class_mass_q_insert
* Returned Value : Position at which insertion took place in the queue.
* Comments       :
*     This function is called by class driver for inserting a command in the
*     queue.
*END*--------------------------------------------------------------------*/

int32_t usb_class_mass_q_insert
   (
      /* [IN] interface structure pointer */
      USB_MASS_CLASS_STRUCT_PTR  intf_ptr,

      /* [IN] command object to be inserted in the queue*/
      MASS_COMMAND_STRUCT_PTR    pCmd
   )
{ /* Body */
   MASS_QUEUE_STRUCT_PTR   Q =  &intf_ptr->QUEUE;
   int32_t                  tmp = -1;

   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_q_insert");
   #endif

   /*
   ** Insert into queue, update LAST, check if full and return queue position.
   ** If queue is full -1 will be returned
   */
   OS_Lock();
   if (Q->COUNT < QUEUE_SIZE) {
      Q->ELEMENTS[Q->LAST] = pCmd;
      tmp = Q->LAST;
      Q->LAST = MASSQ_NEXT(Q->LAST);
      Q->COUNT++;
   } /* Endif */
   OS_Unlock();

   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_q_insert, SUCCESSFUL");
   #endif

   return tmp;
} /* Endbody */


/*FUNCTION*----------------------------------------------------------------
*
* Function Name  : usb_class_mass_deleteq
* Returned Value : None
* Comments       :
*     This routine deletes the pending request in the queue
*END*--------------------------------------------------------------------*/

void usb_class_mass_deleteq
   (
      /* [IN] interface structure pointer */
      USB_MASS_CLASS_STRUCT_PTR intf_ptr
   )
{ /* Body */
   MASS_QUEUE_STRUCT_PTR   Q =  &intf_ptr->QUEUE;

   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_deleteq");
   #endif

   /* Remove current command and increment FIRST modulo the Q size */
   OS_Lock();
   if (Q->COUNT) {
      Q->ELEMENTS[Q->FIRST] = NULL;
      Q->FIRST = MASSQ_NEXT(Q->FIRST);
   //   Q->AVAILABLE = TRUE;
      Q->COUNT--;
   }
   OS_Unlock();

   //if (Q->COUNT >1) {
   //   printf("\nMASS q size now %d", Q->COUNT );
   //}
   
   
   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_deleteq, SUCCESSFUL");
   #endif
   
} /* Endbody */


/*FUNCTION*----------------------------------------------------------------
*
* Function Name  : usb_class_mass_get_pending_request
* Returned Value : None
* Comments       :
*     This routine fetches the pointer to the first (pending) request in
*     the queue, or NULL if there is no pending requests.
*END*--------------------------------------------------------------------*/

void usb_class_mass_get_pending_request
   (
      /* [IN] interface structure pointer */
      USB_MASS_CLASS_STRUCT_PTR   intf_ptr,

      /* [OUT] pointer to pointer which will hold the pending request */
      MASS_COMMAND_STRUCT_PTR *         cmd_ptr_ptr
   )
{ /* Body */
   MASS_QUEUE_STRUCT_PTR   Q = &intf_ptr->QUEUE;

   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_get_pending_request");
   #endif

   OS_Lock();
   if (Q->COUNT) {
      *cmd_ptr_ptr = (MASS_COMMAND_STRUCT_PTR)Q->ELEMENTS[Q->FIRST];
   } else {
      *cmd_ptr_ptr = NULL;
   } /* Endif */
   OS_Unlock();

   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_get_pending_request, SUCCESSFUL");
   #endif
   
   return;
} /* Endbody */


/*FUNCTION*----------------------------------------------------------------
*
* Function Name  : usb_class_mass_cancelq
* Returned Value : None
* Comments       :
*     This routine cancels the given request in the queue
*END*--------------------------------------------------------------------*/

bool usb_class_mass_cancelq
   (
      /* [IN] interface structure pointer */
      USB_MASS_CLASS_STRUCT_PTR intf_ptr,

      /* [IN] command object to be inserted in the queue*/
      MASS_COMMAND_STRUCT_PTR pCmd
   )
{ /* Body */
   MASS_QUEUE_STRUCT_PTR   Q =  &intf_ptr->QUEUE;
   uint32_t                i,index;
   bool                    result = FALSE;
   
   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE("usb_class_mass_cancelq");
   #endif

   /* Remove given command - leave q size the same*/
   OS_Lock();
   if (Q->COUNT) {
      index = Q->FIRST;
      for (i=0;i<Q->COUNT;i++) {
         if (Q->ELEMENTS[index] == pCmd) {
            Q->ELEMENTS[index] = NULL;
            result = TRUE;
            //printf("\nMASS q entry cancelled!!!" );
            break;
         }   
         index = MASSQ_NEXT(index);
      }
   }
   OS_Unlock();

   #ifdef _HOST_DEBUG_
      DEBUG_LOG_TRACE(result?"usb_class_mass_cancelq, SUCCESSFUL":"usb_class_mass_cancelq, FAILED");
   #endif
   
   return result;
} /* Endbody */

/* EOF */
