omap3530/beagle_drivers/wb/api/src/cyaslowlevel.c
changeset 27 117faf51deac
equal deleted inserted replaced
26:b7e488c49d0d 27:117faf51deac
       
     1 /* Cypress West Bridge API source file (cyaslowlevel.c)
       
     2 ## ===========================
       
     3 ##
       
     4 ##  Copyright Cypress Semiconductor Corporation, 2006-2009,
       
     5 ##  All Rights Reserved
       
     6 ##  UNPUBLISHED, LICENSED SOFTWARE.
       
     7 ##
       
     8 ##  CONFIDENTIAL AND PROPRIETARY INFORMATION
       
     9 ##  WHICH IS THE PROPERTY OF CYPRESS.
       
    10 ##
       
    11 ##  Use of this file is governed
       
    12 ##  by the license agreement included in the file
       
    13 ##
       
    14 ##     <install>/license/license.txt
       
    15 ##
       
    16 ##  where <install> is the Cypress software
       
    17 ##  installation root directory path.
       
    18 ##
       
    19 ## ===========================
       
    20 */
       
    21 
       
    22 #include "cyashal.h"
       
    23 #include "cyascast.h"
       
    24 #include "cyasdevice.h"
       
    25 #include "cyaslowlevel.h"
       
    26 #include "cyasintr.h"
       
    27 #include "cyaserr.h"
       
    28 #include "cyasregs.h"
       
    29 
       
    30 static const uint32_t CyAsLowLevelTimeoutCount = 65536 * 4 ;
       
    31 
       
    32 /* Forward declaration */
       
    33 static CyAsReturnStatus_t CyAsSendOne(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p) ;
       
    34 
       
    35 /*
       
    36 * This array holds the size of the largest request we will ever recevie from
       
    37 * the West Bridge device per context.  The size is in 16 bit words.  Note a size of
       
    38 * 0xffff indicates that there will be no requests on this context from West Bridge.
       
    39 */
       
    40 static uint16_t MaxRequestLength[CY_RQT_CONTEXT_COUNT] =
       
    41 {
       
    42     8,                          /* CY_RQT_GENERAL_RQT_CONTEXT - CY_RQT_INITIALIZATION_COMPLETE */
       
    43     8,                          /* CY_RQT_RESOURCE_RQT_CONTEXT - none */
       
    44     8,                          /* CY_RQT_STORAGE_RQT_CONTEXT - CY_RQT_MEDIA_CHANGED */
       
    45     128,                        /* CY_RQT_USB_RQT_CONTEXT - CY_RQT_USB_EVENT */
       
    46     8                           /* CY_RQT_TUR_RQT_CONTEXT - CY_RQT_TURBO_CMD_FROM_HOST */
       
    47 } ;
       
    48 
       
    49 /*
       
    50 * For the given context, this function removes the request node at the head of the
       
    51 * queue from the context.  This is called after all processing has occurred on
       
    52 * the given request and response and we are ready to remove this entry from the
       
    53 * queue.
       
    54 */
       
    55 static void
       
    56 CyAsLLRemoveRequestQueueHead(CyAsDevice *dev_p, CyAsContext *ctxt_p)
       
    57 {
       
    58     uint32_t mask, state ;
       
    59     CyAsLLRequestListNode *node_p ;
       
    60 
       
    61     (void)dev_p ;
       
    62     CyAsHalAssert(ctxt_p->request_queue_p != 0) ;
       
    63 
       
    64     mask = CyAsHalDisableInterrupts() ;
       
    65     node_p = ctxt_p->request_queue_p ;
       
    66     ctxt_p->request_queue_p = node_p->next ;
       
    67     CyAsHalEnableInterrupts(mask) ;
       
    68 
       
    69     node_p->callback = 0 ;
       
    70     node_p->rqt = 0 ;
       
    71     node_p->resp = 0 ;
       
    72 
       
    73     /*
       
    74     * Note that the caller allocates and destroys the request and response.  Generally the
       
    75     * destroy happens in the callback for async requests and after the wait returns for
       
    76     * sync.  The request and response may not actually be destroyed but may be managed in other
       
    77     * ways as well.  It is the responsibilty of the caller to deal with these in any case.  The
       
    78     * caller can do this in the request/response callback function.
       
    79     */
       
    80     state = CyAsHalDisableInterrupts() ;
       
    81     CyAsHalCBFree(node_p) ;
       
    82     CyAsHalEnableInterrupts(state) ;
       
    83 }
       
    84 
       
    85 /*
       
    86 * For the context given, this function sends the next request to
       
    87 * West Bridge via the mailbox register, if the next request is ready to
       
    88 * be sent and has not already been sent.
       
    89 */
       
    90 static void
       
    91 CyAsLLSendNextRequest(CyAsDevice *dev_p, CyAsContext *ctxt_p)
       
    92 {
       
    93     CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
       
    94 
       
    95     /*
       
    96     * ret == ret is equivalent to while (1) but eliminates compiler warnings for
       
    97     * some compilers.
       
    98     */
       
    99     while (ret == ret)
       
   100     {
       
   101         CyAsLLRequestListNode *node_p = ctxt_p->request_queue_p ;
       
   102         if (node_p == 0)
       
   103             break ;
       
   104 
       
   105         if (CyAsRequestGetNodeState(node_p) != CY_AS_REQUEST_LIST_STATE_QUEUED)
       
   106             break ;
       
   107 
       
   108         CyAsRequestSetNodeState(node_p, CY_AS_REQUEST_LIST_STATE_WAITING) ;
       
   109         ret = CyAsSendOne(dev_p, node_p->rqt) ;
       
   110         if (ret == CY_AS_ERROR_SUCCESS)
       
   111         {
       
   112             break ;
       
   113         }
       
   114 
       
   115         /*
       
   116         * If an error occurs in sending the request, tell the requester
       
   117         * about the error and remove the request from the queue.
       
   118         */
       
   119         CyAsRequestSetNodeState(node_p, CY_AS_REQUEST_LIST_STATE_RECEIVED) ;
       
   120         node_p->callback(dev_p, ctxt_p->number, node_p->rqt, node_p->resp, ret) ;
       
   121         CyAsLLRemoveRequestQueueHead(dev_p, ctxt_p) ;
       
   122 
       
   123         /*
       
   124         * This falls through to the while loop to send the next request since
       
   125         * the previous request did not get sent.
       
   126         */
       
   127     }
       
   128 }
       
   129 
       
   130 /*
       
   131 * This method removes an entry from the request queue of a given context.  The entry
       
   132 * is removed only if it is not in transit.
       
   133 */
       
   134 CyAsRemoveRequestResult_t
       
   135 CyAsLLRemoveRequest(CyAsDevice *dev_p, CyAsContext *ctxt_p, CyAsLLRequestResponse *req_p, CyBool force)
       
   136 {
       
   137     uint32_t imask ;
       
   138     CyAsLLRequestListNode *node_p ;
       
   139     CyAsLLRequestListNode *tmp_p ;
       
   140     uint32_t state ;
       
   141 
       
   142     imask = CyAsHalDisableInterrupts() ;
       
   143     if (ctxt_p->request_queue_p != 0 && ctxt_p->request_queue_p->rqt == req_p)
       
   144     {
       
   145         node_p = ctxt_p->request_queue_p ;
       
   146         if ((CyAsRequestGetNodeState(node_p) == CY_AS_REQUEST_LIST_STATE_WAITING) && (!force))
       
   147         {
       
   148             CyAsHalEnableInterrupts(imask) ;
       
   149             return CyAsRemoveRequestInTransit ;
       
   150         }
       
   151 
       
   152         ctxt_p->request_queue_p = node_p->next ;
       
   153     }
       
   154     else
       
   155     {
       
   156         tmp_p = ctxt_p->request_queue_p ;
       
   157         while (tmp_p != 0 && tmp_p->next != 0 && tmp_p->next->rqt != req_p)
       
   158             tmp_p = tmp_p->next ;
       
   159 
       
   160         if (tmp_p == 0 || tmp_p->next == 0)
       
   161         {
       
   162             CyAsHalEnableInterrupts(imask) ;
       
   163             return CyAsRemoveRequestNotFound ;
       
   164         }
       
   165 
       
   166         node_p = tmp_p->next ;
       
   167         tmp_p->next = node_p->next ;
       
   168     }
       
   169 
       
   170     if (node_p->callback)
       
   171         node_p->callback(dev_p, ctxt_p->number, node_p->rqt, node_p->resp, CY_AS_ERROR_CANCELED) ;
       
   172 
       
   173     state = CyAsHalDisableInterrupts() ;
       
   174     CyAsHalCBFree(node_p) ;
       
   175     CyAsHalEnableInterrupts(state) ;
       
   176 
       
   177     CyAsHalEnableInterrupts(imask) ;
       
   178     return CyAsRemoveRequestSucessful ;
       
   179 }
       
   180 
       
   181 void
       
   182 CyAsLLRemoveAllRequests(CyAsDevice *dev_p, CyAsContext *ctxt_p)
       
   183 {
       
   184     CyAsLLRequestListNode *node = ctxt_p->request_queue_p ;
       
   185 
       
   186     while(node)
       
   187     {
       
   188         if(CyAsRequestGetNodeState(ctxt_p->request_queue_p) != CY_AS_REQUEST_LIST_STATE_RECEIVED)
       
   189             CyAsLLRemoveRequest(dev_p, ctxt_p, node->rqt, CyTrue) ;
       
   190         node = node->next ;
       
   191     }
       
   192 }
       
   193 
       
   194 static CyBool
       
   195 CyAsLLIsInQueue(CyAsContext *ctxt_p, CyAsLLRequestResponse *req_p)
       
   196 {
       
   197     uint32_t mask ;
       
   198     CyAsLLRequestListNode *node_p ;
       
   199 
       
   200     mask = CyAsHalDisableInterrupts() ;
       
   201     node_p = ctxt_p->request_queue_p ;
       
   202     while (node_p)
       
   203     {
       
   204         if (node_p->rqt == req_p)
       
   205         {
       
   206             CyAsHalEnableInterrupts(mask) ;
       
   207             return CyTrue ;
       
   208         }
       
   209         node_p = node_p->next ;
       
   210     }
       
   211     CyAsHalEnableInterrupts(mask) ;
       
   212     return CyFalse ;
       
   213 }
       
   214 
       
   215 /*
       
   216 * This is the handler for mailbox data when we are trying to send data to the West Bridge firmware.  The
       
   217 * firmware may be trying to send us data and we need to queue this data to allow the firmware to move
       
   218 * forward and be in a state to receive our request.  Here we just queue the data and it is processed
       
   219 * at a later time by the mailbox interrupt handler.
       
   220 */
       
   221 void
       
   222 CyAsLLQueueMailboxData(CyAsDevice *dev_p)
       
   223 {
       
   224     CyAsContext *ctxt_p ;
       
   225     uint8_t context ;
       
   226     uint16_t data[4] ;
       
   227     int32_t i ;
       
   228 
       
   229     /* Read the data from mailbox 0 to determine what to do with the data */
       
   230     for(i = 3 ; i >= 0 ; i--)
       
   231         data[i] = CyAsHalReadRegister(dev_p->tag, CyCastInt2UInt16(CY_AS_MEM_P0_MAILBOX0 + i)) ;
       
   232 
       
   233     context = CyAsMboxGetContext(data[0]) ;
       
   234     if (context >= CY_RQT_CONTEXT_COUNT)
       
   235     {
       
   236         CyAsHalPrintMessage("Mailbox request/response received with invalid context value (%d)\n", context) ;
       
   237         return ;
       
   238     }
       
   239 
       
   240     ctxt_p = dev_p->context[context] ;
       
   241 
       
   242     /*
       
   243     * If we have queued too much data, drop future data.
       
   244     */
       
   245     CyAsHalAssert(ctxt_p->queue_index * sizeof(uint16_t) + sizeof(data) <= sizeof(ctxt_p->data_queue)) ;
       
   246 
       
   247     for(i = 0 ; i < 4 ; i++)
       
   248         ctxt_p->data_queue[ctxt_p->queue_index++] = data[i] ;
       
   249 
       
   250     CyAsHalAssert((ctxt_p->queue_index % 4) == 0) ;
       
   251     dev_p->ll_queued_data = CyTrue ;
       
   252 }
       
   253 
       
   254 void
       
   255 CyAsMailBoxProcessData(CyAsDevice *dev_p, uint16_t *data)
       
   256 {
       
   257     CyAsContext *ctxt_p ;
       
   258     uint8_t context ;
       
   259     uint16_t *len_p ;
       
   260     CyAsLLRequestResponse *rec_p ;
       
   261     uint8_t st ;
       
   262     uint16_t src, dest ;
       
   263 
       
   264     context = CyAsMboxGetContext(data[0]) ;
       
   265     if (context >= CY_RQT_CONTEXT_COUNT)
       
   266     {
       
   267         CyAsHalPrintMessage("Mailbox request/response received with invalid context value (%d)\n", context) ;
       
   268         return ;
       
   269     }
       
   270 
       
   271     ctxt_p = dev_p->context[context] ;
       
   272 
       
   273     if (CyAsMboxIsRequest(data[0]))
       
   274     {
       
   275         CyAsHalAssert(ctxt_p->req_p != 0) ;
       
   276         rec_p = ctxt_p->req_p ;
       
   277         len_p = &ctxt_p->request_length ;
       
   278 
       
   279     }
       
   280     else
       
   281     {
       
   282         if (ctxt_p->request_queue_p == 0 || CyAsRequestGetNodeState(ctxt_p->request_queue_p) != CY_AS_REQUEST_LIST_STATE_WAITING)
       
   283         {
       
   284             CyAsHalPrintMessage("Mailbox response received on context that was not expecting a response\n") ;
       
   285             CyAsHalPrintMessage("    Context: %d\n", context) ;
       
   286             CyAsHalPrintMessage("    Contents: 0x%04x 0x%04x 0x%04x 0x%04x\n", data[0], data[1], data[2], data[3]) ;
       
   287             if (ctxt_p->request_queue_p != 0)
       
   288                 CyAsHalPrintMessage("    State: 0x%02x\n", ctxt_p->request_queue_p->state) ;
       
   289             return ;
       
   290         }
       
   291 
       
   292         /* Make sure the request has an associated response */
       
   293         CyAsHalAssert(ctxt_p->request_queue_p->resp != 0) ;
       
   294 
       
   295         rec_p = ctxt_p->request_queue_p->resp ;
       
   296         len_p = &ctxt_p->request_queue_p->length ;
       
   297     }
       
   298 
       
   299     if (rec_p->stored == 0)
       
   300     {
       
   301         /*
       
   302         * This is the first cycle of the response
       
   303         */
       
   304         CyAsLLRequestResponse_SetCode(rec_p, CyAsMboxGetCode(data[0])) ;
       
   305         CyAsLLRequestResponse_SetContext(rec_p, context) ;
       
   306 
       
   307         if (CyAsMboxIsLast(data[0]))
       
   308         {
       
   309             /* This is a single cycle response */
       
   310             *len_p = rec_p->length ;
       
   311             st = 1 ;
       
   312         }
       
   313         else
       
   314         {
       
   315             /* Ensure that enough memory has been reserved for the response. */
       
   316             CyAsHalAssert(rec_p->length >= data[1]) ;
       
   317             *len_p = (data[1] < rec_p->length) ? data[1] : rec_p->length ;
       
   318             st = 2 ;
       
   319         }
       
   320     }
       
   321     else
       
   322         st = 1 ;
       
   323 
       
   324     /* Trasnfer the data from the mailboxes to the response */
       
   325     while (rec_p->stored < *len_p && st < 4)
       
   326         rec_p->data[rec_p->stored++] = data[st++] ;
       
   327 
       
   328     if (CyAsMboxIsLast(data[0]))
       
   329     {
       
   330         /* NB: The call-back that is made below can cause the addition of more data
       
   331         in this queue, thus causing a recursive overflow of the queue. This is prevented
       
   332         by removing the request entry that is currently being passed up from the data
       
   333         queue. If this is done, the queue only needs to be as long as two request
       
   334         entries from West Bridge.
       
   335         */
       
   336         if ((ctxt_p->rqt_index > 0) && (ctxt_p->rqt_index <= ctxt_p->queue_index))
       
   337         {
       
   338             dest = 0 ;
       
   339             src  = ctxt_p->rqt_index ;
       
   340 
       
   341             while (src < ctxt_p->queue_index)
       
   342                 ctxt_p->data_queue[dest++] = ctxt_p->data_queue[src++] ;
       
   343 
       
   344             ctxt_p->rqt_index = 0 ;
       
   345             ctxt_p->queue_index = dest ;
       
   346             CyAsHalAssert((ctxt_p->queue_index % 4) == 0) ;
       
   347         }
       
   348 
       
   349         if (ctxt_p->request_queue_p != 0 && rec_p == ctxt_p->request_queue_p->resp)
       
   350         {
       
   351             /*
       
   352             * If this is the last cycle of the response, call the callback and
       
   353             * reset for the next response.
       
   354             */
       
   355             CyAsLLRequestResponse *resp_p = ctxt_p->request_queue_p->resp ;
       
   356             resp_p->length = ctxt_p->request_queue_p->length ;
       
   357             CyAsRequestSetNodeState(ctxt_p->request_queue_p, CY_AS_REQUEST_LIST_STATE_RECEIVED) ;
       
   358 
       
   359             CyAsDeviceSetInCallback(dev_p) ;
       
   360             ctxt_p->request_queue_p->callback(dev_p, context, ctxt_p->request_queue_p->rqt, resp_p, CY_AS_ERROR_SUCCESS) ;
       
   361             CyAsDeviceClearInCallback(dev_p) ;
       
   362 
       
   363             CyAsLLRemoveRequestQueueHead(dev_p, ctxt_p) ;
       
   364             CyAsLLSendNextRequest(dev_p, ctxt_p) ;
       
   365         }
       
   366         else
       
   367         {
       
   368             /* Send the request to the appropriate module to handle */
       
   369             CyAsLLRequestResponse *request_p = ctxt_p->req_p ;
       
   370             ctxt_p->req_p = 0 ;
       
   371             if (ctxt_p->request_callback)
       
   372             {
       
   373                 CyAsDeviceSetInCallback(dev_p) ;
       
   374                 ctxt_p->request_callback(dev_p, context, request_p, 0, CY_AS_ERROR_SUCCESS) ;
       
   375                 CyAsDeviceClearInCallback(dev_p) ;
       
   376             }
       
   377             CyAsLLInitRequest(request_p, 0, context, request_p->length) ;
       
   378             ctxt_p->req_p = request_p ;
       
   379         }
       
   380     }
       
   381 }
       
   382 
       
   383 /*
       
   384 * This is the handler for processing queued mailbox data
       
   385 */
       
   386 void
       
   387 CyAsMailBoxQueuedDataHandler(CyAsDevice *dev_p)
       
   388 {
       
   389     uint16_t i ;
       
   390 
       
   391     /*
       
   392      * If more data gets queued in between our entering this call and the
       
   393      * end of the iteration on all contexts; we should continue processing the
       
   394      * queued data.
       
   395      */
       
   396     while (dev_p->ll_queued_data)
       
   397     {
       
   398         dev_p->ll_queued_data = CyFalse ;
       
   399         for(i = 0 ; i < CY_RQT_CONTEXT_COUNT ; i++)
       
   400         {
       
   401             uint16_t offset ;
       
   402             CyAsContext *ctxt_p = dev_p->context[i] ;
       
   403             CyAsHalAssert((ctxt_p->queue_index % 4) == 0) ;
       
   404 
       
   405             offset = 0 ;
       
   406             while (offset < ctxt_p->queue_index)
       
   407             {
       
   408                 ctxt_p->rqt_index = offset + 4 ;
       
   409                 CyAsMailBoxProcessData(dev_p, ctxt_p->data_queue + offset) ;
       
   410                 offset = ctxt_p->rqt_index ;
       
   411             }
       
   412             ctxt_p->queue_index = 0 ;
       
   413         }
       
   414     }
       
   415 }
       
   416 
       
   417 /*
       
   418 * This is the handler for the mailbox interrupt.  This function reads data from the mailbox registers
       
   419 * until a complete request or response is received.  When a complete request is received, the callback
       
   420 * associated with requests on that context is called.  When a complete response is recevied, the callback
       
   421 * associated with the request that generated the reponse is called.
       
   422 */
       
   423 void
       
   424 CyAsMailBoxInterruptHandler(CyAsDevice *dev_p)
       
   425 {
       
   426     CyAsHalAssert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE) ;
       
   427 
       
   428     /*
       
   429     * Queue the mailbox data to preserve order for later processing.
       
   430     */
       
   431     CyAsLLQueueMailboxData(dev_p) ;
       
   432 
       
   433     /*
       
   434     * Process what was queued and anything that may be pending
       
   435     */
       
   436     CyAsMailBoxQueuedDataHandler(dev_p) ;
       
   437 }
       
   438 
       
   439 CyAsReturnStatus_t
       
   440 CyAsLLStart(CyAsDevice *dev_p)
       
   441 {
       
   442     uint16_t i ;
       
   443 
       
   444     if (CyAsDeviceIsLowLevelRunning(dev_p))
       
   445         return CY_AS_ERROR_ALREADY_RUNNING ;
       
   446 
       
   447     dev_p->ll_sending_rqt = CyFalse ;
       
   448     dev_p->ll_abort_curr_rqt = CyFalse ;
       
   449 
       
   450     for(i = 0 ; i < CY_RQT_CONTEXT_COUNT ; i++)
       
   451     {
       
   452         dev_p->context[i] = (CyAsContext *)CyAsHalAlloc(sizeof(CyAsContext)) ;
       
   453         if (dev_p->context[i] == 0)
       
   454             return CY_AS_ERROR_OUT_OF_MEMORY ;
       
   455 
       
   456         dev_p->context[i]->number = (uint8_t)i ;
       
   457         dev_p->context[i]->request_callback = 0 ;
       
   458         dev_p->context[i]->request_queue_p = 0 ;
       
   459         dev_p->context[i]->last_node_p = 0 ;
       
   460         dev_p->context[i]->req_p = CyAsLLCreateRequest(dev_p, 0, (uint8_t)i, MaxRequestLength[i]) ;
       
   461         dev_p->context[i]->queue_index = 0 ;
       
   462 
       
   463         if (!CyAsHalCreateSleepChannel(&dev_p->context[i]->channel))
       
   464             return CY_AS_ERROR_CREATE_SLEEP_CHANNEL_FAILED ;
       
   465     }
       
   466 
       
   467     CyAsDeviceSetLowLevelRunning(dev_p) ;
       
   468     return CY_AS_ERROR_SUCCESS ;
       
   469 }
       
   470 
       
   471 /*
       
   472 * Shutdown the low level communications module.  This operation will also cancel any
       
   473 * queued low level requests.
       
   474 */
       
   475 CyAsReturnStatus_t
       
   476 CyAsLLStop(CyAsDevice *dev_p)
       
   477 {
       
   478     uint8_t i ;
       
   479     CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
       
   480     CyAsContext *ctxt_p ;
       
   481     uint32_t mask ;
       
   482 
       
   483     for(i = 0 ; i < CY_RQT_CONTEXT_COUNT ; i++)
       
   484     {
       
   485         ctxt_p = dev_p->context[i] ;
       
   486         if (!CyAsHalDestroySleepChannel(&ctxt_p->channel))
       
   487             return CY_AS_ERROR_DESTROY_SLEEP_CHANNEL_FAILED ;
       
   488 
       
   489         /*
       
   490         * Now, free any queued requests and assocaited responses
       
   491         */
       
   492         while (ctxt_p->request_queue_p)
       
   493         {
       
   494             uint32_t state ;
       
   495             CyAsLLRequestListNode *node_p = ctxt_p->request_queue_p ;
       
   496 
       
   497             /* Mark this pair as in a cancel operation */
       
   498             CyAsRequestSetNodeState(node_p, CY_AS_REQUEST_LIST_STATE_CANCELING) ;
       
   499 
       
   500             /* Tell the caller that we are canceling this request */
       
   501             /* NB: The callback is responsible for destroying the request and the
       
   502             response.  We cannot count on the contents of these two after
       
   503             calling the callback.
       
   504             */
       
   505             node_p->callback(dev_p, i, node_p->rqt, node_p->resp, CY_AS_ERROR_CANCELED) ;
       
   506 
       
   507             /* Remove the pair from the queue */
       
   508             mask = CyAsHalDisableInterrupts() ;
       
   509             ctxt_p->request_queue_p = node_p->next ;
       
   510             CyAsHalEnableInterrupts(mask) ;
       
   511 
       
   512             /* Free the list node */
       
   513             state = CyAsHalDisableInterrupts() ;
       
   514             CyAsHalCBFree(node_p) ;
       
   515             CyAsHalEnableInterrupts(state) ;
       
   516         }
       
   517 
       
   518         CyAsLLDestroyRequest(dev_p, dev_p->context[i]->req_p) ;
       
   519         CyAsHalFree(dev_p->context[i]) ;
       
   520         dev_p->context[i] = 0 ;
       
   521 
       
   522     }
       
   523     CyAsDeviceSetLowLevelStopped(dev_p) ;
       
   524 
       
   525     return ret ;
       
   526 }
       
   527 
       
   528 void
       
   529 CyAsLLInitRequest(CyAsLLRequestResponse *req_p, uint16_t code, uint16_t context, uint16_t length)
       
   530 {
       
   531     uint16_t totallen = sizeof(CyAsLLRequestResponse) + (length - 1) * sizeof(uint16_t) ;
       
   532 
       
   533     CyAsHalMemSet(req_p, 0, totallen) ;
       
   534     req_p->length = length ;
       
   535     CyAsLLRequestResponse_SetCode(req_p, code) ;
       
   536     CyAsLLRequestResponse_SetContext(req_p, context) ;
       
   537     CyAsLLRequestResponse_SetRequest(req_p) ;
       
   538 }
       
   539 
       
   540 /*
       
   541 * Create a new request.
       
   542 */
       
   543 CyAsLLRequestResponse *
       
   544 CyAsLLCreateRequest(CyAsDevice *dev_p, uint16_t code, uint8_t context, uint16_t length)
       
   545 {
       
   546     CyAsLLRequestResponse *req_p ;
       
   547     uint32_t state ;
       
   548     uint16_t totallen = sizeof(CyAsLLRequestResponse) + (length - 1) * sizeof(uint16_t) ;
       
   549 
       
   550     (void)dev_p ;
       
   551 
       
   552     state = CyAsHalDisableInterrupts() ;
       
   553     req_p = (CyAsLLRequestResponse *)CyAsHalCBAlloc(totallen) ;
       
   554     CyAsHalEnableInterrupts(state) ;
       
   555     if(req_p)
       
   556         CyAsLLInitRequest(req_p, code, context, length) ;
       
   557 
       
   558     return req_p ;
       
   559 }
       
   560 
       
   561 /*
       
   562 * Destroy a request.
       
   563 */
       
   564 void
       
   565 CyAsLLDestroyRequest(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p)
       
   566 {
       
   567     uint32_t state ;
       
   568     (void)dev_p ;
       
   569     (void)req_p ;
       
   570 
       
   571     state = CyAsHalDisableInterrupts() ;
       
   572     CyAsHalCBFree(req_p) ;
       
   573     CyAsHalEnableInterrupts(state) ;
       
   574 
       
   575 }
       
   576 
       
   577 void
       
   578 CyAsLLInitResponse(CyAsLLRequestResponse *req_p, uint16_t length)
       
   579 {
       
   580     uint16_t totallen = sizeof(CyAsLLRequestResponse) + (length - 1) * sizeof(uint16_t) ;
       
   581 
       
   582     CyAsHalMemSet(req_p, 0, totallen) ;
       
   583     req_p->length = length ;
       
   584     CyAsLLRequestResponse_SetResponse(req_p) ;
       
   585 }
       
   586 
       
   587 /*
       
   588 * Create a new response
       
   589 */
       
   590 CyAsLLRequestResponse *
       
   591 CyAsLLCreateResponse(CyAsDevice *dev_p, uint16_t length)
       
   592 {
       
   593     CyAsLLRequestResponse *req_p ;
       
   594     uint32_t state ;
       
   595     uint16_t totallen = sizeof(CyAsLLRequestResponse) + (length - 1) * sizeof(uint16_t) ;
       
   596 
       
   597     (void)dev_p ;
       
   598 
       
   599     state = CyAsHalDisableInterrupts() ;
       
   600     req_p = (CyAsLLRequestResponse *)CyAsHalCBAlloc(totallen) ;
       
   601     CyAsHalEnableInterrupts(state) ;
       
   602     if(req_p)
       
   603         CyAsLLInitResponse(req_p, length) ;
       
   604 
       
   605     return req_p ;
       
   606 }
       
   607 
       
   608 /*
       
   609 * Destroy the new response
       
   610 */
       
   611 void
       
   612 CyAsLLDestroyResponse(CyAsDevice *dev_p, CyAsLLRequestResponse *req_p)
       
   613 {
       
   614     uint32_t state ;
       
   615     (void)dev_p ;
       
   616     (void)req_p ;
       
   617 
       
   618     state = CyAsHalDisableInterrupts() ;
       
   619     CyAsHalCBFree(req_p) ;
       
   620     CyAsHalEnableInterrupts(state) ;
       
   621 }
       
   622 
       
   623 static uint16_t
       
   624 CyAsReadIntrStatus(
       
   625                    CyAsDevice *dev_p)
       
   626 {
       
   627     uint32_t mask ;
       
   628     CyBool bloop = CyTrue ;
       
   629     uint16_t v = 0, last = 0xffff;
       
   630 
       
   631     /*
       
   632     * Before determining if the mailboxes are ready for more data, we first check the
       
   633     * mailbox interrupt to see if we need to receive data.  This prevents a dead-lock
       
   634     * condition that can occur when both sides are trying to receive data.
       
   635     */
       
   636     while (last == last)
       
   637     {
       
   638         /*
       
   639         * Disable interrupts to be sure we don't process the mailbox here and have the
       
   640         * interrupt routine try to read this data as well.
       
   641         */
       
   642         mask = CyAsHalDisableInterrupts() ;
       
   643 
       
   644         /*
       
   645         * See if there is data to be read.
       
   646         */
       
   647         v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_P0_INTR_REG) ;
       
   648         if ((v & CY_AS_MEM_P0_INTR_REG_MBINT) == 0)
       
   649         {
       
   650             CyAsHalEnableInterrupts(mask) ;
       
   651             break ;
       
   652         }
       
   653 
       
   654         /*
       
   655         * Queue the mailbox data for later processing.  This allows the firmware to move
       
   656         * forward and service the requst from the P port.
       
   657         */
       
   658         CyAsLLQueueMailboxData(dev_p) ;
       
   659 
       
   660         /*
       
   661         * Enable interrupts again to service mailbox interrupts appropriately
       
   662         */
       
   663         CyAsHalEnableInterrupts(mask) ;
       
   664     }
       
   665 
       
   666     /*
       
   667     * Now, all data is received
       
   668     */
       
   669     last = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MB_STAT) & CY_AS_MEM_P0_MCU_MBNOTRD ;
       
   670     while (bloop)
       
   671     {
       
   672         v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MB_STAT) & CY_AS_MEM_P0_MCU_MBNOTRD ;
       
   673         if (v == last)
       
   674             break ;
       
   675 
       
   676         last = v ;
       
   677     }
       
   678 
       
   679     return v ;
       
   680 }
       
   681 
       
   682 /*
       
   683 * Send a single request or response using the mail box register.  This function does not deal
       
   684 * with the internal queues at all, but only sends the request or response across to the firmware
       
   685 */
       
   686 static CyAsReturnStatus_t
       
   687 CyAsSendOne(
       
   688             CyAsDevice *dev_p,
       
   689             CyAsLLRequestResponse *req_p)
       
   690 {
       
   691     int i ;
       
   692     uint16_t mb0, v ;
       
   693     int32_t loopcount ;
       
   694     uint32_t intStat ;
       
   695 
       
   696 #ifdef _DEBUG
       
   697     if (CyAsLLRequestResponse_IsRequest(req_p))
       
   698     {
       
   699         switch(CyAsLLRequestResponse_GetContext(req_p))
       
   700         {
       
   701         case CY_RQT_GENERAL_RQT_CONTEXT:
       
   702             CyAsHalAssert(req_p->length * 2 + 2 < CY_CTX_GEN_MAX_DATA_SIZE) ;
       
   703             break ;
       
   704 
       
   705         case CY_RQT_RESOURCE_RQT_CONTEXT:
       
   706             CyAsHalAssert(req_p->length * 2 + 2 < CY_CTX_RES_MAX_DATA_SIZE) ;
       
   707             break ;
       
   708 
       
   709         case CY_RQT_STORAGE_RQT_CONTEXT:
       
   710             CyAsHalAssert(req_p->length * 2 + 2 < CY_CTX_STR_MAX_DATA_SIZE) ;
       
   711             break ;
       
   712 
       
   713         case CY_RQT_USB_RQT_CONTEXT:
       
   714             CyAsHalAssert(req_p->length * 2 + 2 < CY_CTX_USB_MAX_DATA_SIZE) ;
       
   715             break ;
       
   716         }
       
   717     }
       
   718 #endif
       
   719 
       
   720     /* Write the request to the mail box registers */
       
   721     if (req_p->length > 3)
       
   722     {
       
   723         uint16_t length = req_p->length ;
       
   724         int which = 0 ;
       
   725         int st = 1 ;
       
   726 
       
   727         dev_p->ll_sending_rqt = CyTrue ;
       
   728         while (which < length)
       
   729         {
       
   730             loopcount = CyAsLowLevelTimeoutCount ;
       
   731             do
       
   732             {
       
   733                 v = CyAsReadIntrStatus(dev_p) ;
       
   734 
       
   735             } while (v && loopcount-- > 0) ;
       
   736 
       
   737             if (v)
       
   738             {
       
   739                 CyAsHalPrintMessage(">>>>>> LOW LEVEL TIMEOUT %x %x %x %x\n",
       
   740                     CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX0),
       
   741                     CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX1),
       
   742                     CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX2),
       
   743                     CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX3)) ;
       
   744                 return CY_AS_ERROR_TIMEOUT ;
       
   745             }
       
   746 
       
   747             if (dev_p->ll_abort_curr_rqt)
       
   748             {
       
   749                 dev_p->ll_sending_rqt = CyFalse ;
       
   750                 dev_p->ll_abort_curr_rqt = CyFalse ;
       
   751                 return CY_AS_ERROR_CANCELED ;
       
   752             }
       
   753 
       
   754             intStat = CyAsHalDisableInterrupts () ;
       
   755 
       
   756             /*
       
   757              * Check again whether the mailbox is free. It is possible that an ISR came in
       
   758              * and wrote into the mailboxes since we last checked the status.
       
   759              */
       
   760             v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MB_STAT) & CY_AS_MEM_P0_MCU_MBNOTRD ;
       
   761             if (v)
       
   762             {
       
   763                 /* Go back to the original check since the mailbox is not free. */
       
   764                 CyAsHalEnableInterrupts(intStat) ;
       
   765                 continue ;
       
   766             }
       
   767 
       
   768             if (which == 0)
       
   769             {
       
   770                 CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX1, length) ;
       
   771                 st = 2 ;
       
   772             }
       
   773             else
       
   774             {
       
   775                 st = 1;
       
   776             }
       
   777 
       
   778             while ((which < length) && (st < 4))
       
   779             {
       
   780                 CyAsHalWriteRegister(dev_p->tag, CyCastInt2UInt16(CY_AS_MEM_MCU_MAILBOX0 + st), req_p->data[which++]) ;
       
   781                 st++ ;
       
   782             }
       
   783 
       
   784             mb0 = req_p->box0 ;
       
   785             if (which == length)
       
   786             {
       
   787                 dev_p->ll_sending_rqt = CyFalse ;
       
   788                 mb0 |= CY_AS_REQUEST_RESPONSE_LAST_MASK ;
       
   789             }
       
   790 
       
   791             if (dev_p->ll_abort_curr_rqt)
       
   792             {
       
   793                 dev_p->ll_sending_rqt = CyFalse ;
       
   794                 dev_p->ll_abort_curr_rqt = CyFalse ;
       
   795                 CyAsHalEnableInterrupts (intStat) ;
       
   796                 return CY_AS_ERROR_CANCELED ;
       
   797             }
       
   798 
       
   799             CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX0, mb0) ;
       
   800 
       
   801             /* Wait for the MBOX interrupt to be high */
       
   802             CyAsHalSleep150() ;
       
   803             CyAsHalEnableInterrupts (intStat) ;
       
   804         }
       
   805     }
       
   806     else
       
   807     {
       
   808 CheckMailboxAvailability:
       
   809         /*
       
   810         * Wait for the mailbox registers to become available.  This should be a very quick
       
   811         * wait as the firmware is designed to accept requests at interrupt time and queue
       
   812         * them for future processing.
       
   813         */
       
   814         loopcount = CyAsLowLevelTimeoutCount ;
       
   815         do
       
   816         {
       
   817             v = CyAsReadIntrStatus(dev_p) ;
       
   818 
       
   819         } while (v && loopcount-- > 0) ;
       
   820 
       
   821         if (v)
       
   822         {
       
   823             CyAsHalPrintMessage(">>>>>> LOW LEVEL TIMEOUT %x %x %x %x\n",
       
   824                 CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX0),
       
   825                 CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX1),
       
   826                 CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX2),
       
   827                 CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX3)) ;
       
   828             return CY_AS_ERROR_TIMEOUT ;
       
   829         }
       
   830 
       
   831         intStat = CyAsHalDisableInterrupts ();
       
   832 
       
   833         /*
       
   834          * Check again whether the mailbox is free. It is possible that an ISR came in
       
   835          * and wrote into the mailboxes since we last checked the status.
       
   836          */
       
   837         v = CyAsHalReadRegister(dev_p->tag, CY_AS_MEM_MCU_MB_STAT) & CY_AS_MEM_P0_MCU_MBNOTRD ;
       
   838         if (v)
       
   839         {
       
   840             /* Go back to the original check since the mailbox is not free. */
       
   841             CyAsHalEnableInterrupts(intStat) ;
       
   842             goto CheckMailboxAvailability ;
       
   843         }
       
   844 
       
   845         /* Write the data associated with the request into the mbox registers 1 - 3 */
       
   846         v = 0 ;
       
   847         for(i = req_p->length - 1 ; i >= 0 ; i--)
       
   848             CyAsHalWriteRegister(dev_p->tag, CyCastInt2UInt16(CY_AS_MEM_MCU_MAILBOX1 + i), req_p->data[i]) ;
       
   849 
       
   850         /* Write the mbox register 0 to trigger the interrupt */
       
   851         CyAsHalWriteRegister(dev_p->tag, CY_AS_MEM_MCU_MAILBOX0, req_p->box0 | CY_AS_REQUEST_RESPONSE_LAST_MASK) ;
       
   852 
       
   853         CyAsHalSleep150() ;
       
   854         CyAsHalEnableInterrupts (intStat);
       
   855     }
       
   856 
       
   857     return CY_AS_ERROR_SUCCESS ;
       
   858 }
       
   859 
       
   860 /*
       
   861 * This function queues a single request to be sent to the firmware.
       
   862 */
       
   863 extern CyAsReturnStatus_t
       
   864 CyAsLLSendRequest(
       
   865                   CyAsDevice *dev_p,
       
   866                   CyAsLLRequestResponse *req,   /* The request to send */
       
   867                   CyAsLLRequestResponse *resp,  /* Storage for a reply, must be sure it is of sufficient size */
       
   868                   CyBool sync,                  /* If true, this is a synchronous request */
       
   869                   CyAsResponseCallback cb       /* Callback to call when reply is received */
       
   870                   )
       
   871 {
       
   872     CyAsContext *ctxt_p ;
       
   873     uint16_t box0 = req->box0 ;
       
   874     uint8_t context ;
       
   875     CyAsReturnStatus_t ret = CY_AS_ERROR_SUCCESS ;
       
   876     CyAsLLRequestListNode *node_p ;
       
   877     uint32_t mask, state ;
       
   878 
       
   879     CyAsHalAssert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE);
       
   880 
       
   881     context = CyAsMboxGetContext(box0) ;
       
   882     CyAsHalAssert(context < CY_RQT_CONTEXT_COUNT) ;
       
   883     ctxt_p = dev_p->context[context] ;
       
   884 
       
   885     /* Allocate the list node */
       
   886     state = CyAsHalDisableInterrupts() ;
       
   887     node_p = (CyAsLLRequestListNode *)CyAsHalCBAlloc(sizeof(CyAsLLRequestListNode)) ;
       
   888     CyAsHalEnableInterrupts(state) ;
       
   889 
       
   890     if (node_p == 0)
       
   891         return CY_AS_ERROR_OUT_OF_MEMORY ;
       
   892 
       
   893     /* Initialize the list node */
       
   894     node_p->callback = cb ;
       
   895     node_p->length = 0 ;
       
   896     node_p->next = 0 ;
       
   897     node_p->resp = resp ;
       
   898     node_p->rqt = req ;
       
   899     node_p->state = CY_AS_REQUEST_LIST_STATE_QUEUED ;
       
   900     if (sync)
       
   901         CyAsRequestNodeSetSync(node_p) ;
       
   902 
       
   903     /* Put the request into the queue */
       
   904     mask = CyAsHalDisableInterrupts() ;
       
   905     if (ctxt_p->request_queue_p == 0)
       
   906     {
       
   907         /* Empty queue */
       
   908         ctxt_p->request_queue_p = node_p ;
       
   909         ctxt_p->last_node_p = node_p ;
       
   910     }
       
   911     else
       
   912     {
       
   913         ctxt_p->last_node_p->next = node_p ;
       
   914         ctxt_p->last_node_p = node_p ;
       
   915     }
       
   916     CyAsHalEnableInterrupts(mask) ;
       
   917     CyAsLLSendNextRequest(dev_p, ctxt_p) ;
       
   918 
       
   919     if (!CyAsDeviceIsInCallback(dev_p))
       
   920     {
       
   921         mask = CyAsHalDisableInterrupts() ;
       
   922         CyAsMailBoxQueuedDataHandler(dev_p) ;
       
   923         CyAsHalEnableInterrupts(mask) ;
       
   924     }
       
   925 
       
   926     return ret ;
       
   927 }
       
   928 
       
   929 static void
       
   930 CyAsLLSendCallback(
       
   931                    CyAsDevice *dev_p,
       
   932                    uint8_t context,
       
   933                    CyAsLLRequestResponse *rqt,
       
   934                    CyAsLLRequestResponse *resp,
       
   935                    CyAsReturnStatus_t ret)
       
   936 {
       
   937     (void)rqt ;
       
   938     (void)resp ;
       
   939     (void)ret ;
       
   940 
       
   941 
       
   942     CyAsHalAssert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE) ;
       
   943 
       
   944     /*
       
   945     * Storage the state to return to the caller
       
   946     */
       
   947     dev_p->ll_error = ret ;
       
   948 
       
   949     /*
       
   950     * Now wake the caller
       
   951     */
       
   952     CyAsHalWake(&dev_p->context[context]->channel) ;
       
   953 }
       
   954 
       
   955 CyAsReturnStatus_t
       
   956 CyAsLLSendRequestWaitReply(
       
   957                            CyAsDevice *dev_p,
       
   958                            CyAsLLRequestResponse *req,                          /* The request to send */
       
   959                            CyAsLLRequestResponse *resp                          /* Storage for a reply, must be sure it is of sufficient size */
       
   960                            )
       
   961 {
       
   962     CyAsReturnStatus_t ret ;
       
   963     uint8_t context ;
       
   964     uint32_t loopcount = 800 ;  /* Larger 8 sec time-out to handle the init delay for slower storage devices in USB FS. */
       
   965     CyAsContext *ctxt_p ;
       
   966 
       
   967     /* Get the context for the request */
       
   968     context = CyAsLLRequestResponse_GetContext(req) ;
       
   969     CyAsHalAssert(context < CY_RQT_CONTEXT_COUNT) ;
       
   970     ctxt_p = dev_p->context[context] ;
       
   971 
       
   972     ret = CyAsLLSendRequest(dev_p, req, resp, CyTrue, CyAsLLSendCallback) ;
       
   973     if (ret != CY_AS_ERROR_SUCCESS)
       
   974         return ret ;
       
   975 
       
   976     while (loopcount-- > 0)
       
   977     {
       
   978         /*
       
   979         * Sleep while we wait on the response.  Receiving the reply will
       
   980         * wake this thread.  We will wait, at most 2 seconds (10 ms * 200
       
   981         * tries) before we timeout.  Note if the reply arrives, we will not
       
   982         * sleep the entire 10 ms, just til the reply arrives.
       
   983         */
       
   984         CyAsHalSleepOn(&ctxt_p->channel, 10) ;
       
   985 
       
   986         /*
       
   987         * If the request has left the queue, it means the request has been sent
       
   988         * and the reply has been received.  This means we can return to the caller
       
   989         * and be sure the reply has been received.
       
   990         */
       
   991         if (!CyAsLLIsInQueue(ctxt_p, req))
       
   992             return dev_p->ll_error ;
       
   993     }
       
   994 
       
   995     /* Remove the QueueListNode for this request. */
       
   996     CyAsLLRemoveRequest(dev_p, ctxt_p, req, CyTrue) ;
       
   997 
       
   998     return CY_AS_ERROR_TIMEOUT ;
       
   999 }
       
  1000 
       
  1001 CyAsReturnStatus_t
       
  1002 CyAsLLRegisterRequestCallback(
       
  1003                               CyAsDevice *dev_p,
       
  1004                               uint8_t context,
       
  1005                               CyAsResponseCallback cb)
       
  1006 {
       
  1007     CyAsContext *ctxt_p ;
       
  1008     CyAsHalAssert(context < CY_RQT_CONTEXT_COUNT) ;
       
  1009     ctxt_p = dev_p->context[context] ;
       
  1010 
       
  1011     ctxt_p->request_callback = cb ;
       
  1012     return CY_AS_ERROR_SUCCESS ;
       
  1013 }
       
  1014 
       
  1015 void
       
  1016 CyAsLLRequestResponse_Pack(
       
  1017                            CyAsLLRequestResponse *req_p,
       
  1018                            uint32_t offset,
       
  1019                            uint32_t length,
       
  1020                            void *data_p)
       
  1021 {
       
  1022     uint16_t dt ;
       
  1023     uint8_t *dp = (uint8_t *)data_p ;
       
  1024 
       
  1025     while (length > 1)
       
  1026     {
       
  1027         dt = ((*dp++) << 8) ;
       
  1028         dt |= (*dp++) ;
       
  1029         CyAsLLRequestResponse_SetWord(req_p, offset, dt) ;
       
  1030         offset++ ;
       
  1031         length -= 2 ;
       
  1032     }
       
  1033 
       
  1034     if (length == 1)
       
  1035     {
       
  1036         dt = (*dp << 8) ;
       
  1037         CyAsLLRequestResponse_SetWord(req_p, offset, dt) ;
       
  1038     }
       
  1039 }
       
  1040 
       
  1041 void
       
  1042 CyAsLLRequestResponse_Unpack(
       
  1043                              CyAsLLRequestResponse *req_p,
       
  1044                              uint32_t offset,
       
  1045                              uint32_t length,
       
  1046                              void *data_p)
       
  1047 {
       
  1048     uint8_t *dp = (uint8_t *)data_p ;
       
  1049 
       
  1050     while (length-- > 0)
       
  1051     {
       
  1052         uint16_t val = CyAsLLRequestResponse_GetWord(req_p, offset++) ;
       
  1053         *dp++ = (uint8_t)((val >> 8) & 0xff) ;
       
  1054 
       
  1055         if (length)
       
  1056         {
       
  1057             length-- ;
       
  1058             *dp++ = (uint8_t)(val & 0xff) ;
       
  1059         }
       
  1060     }
       
  1061 }
       
  1062 
       
  1063 extern CyAsReturnStatus_t
       
  1064 CyAsLLSendStatusResponse(
       
  1065                          CyAsDevice *dev_p,
       
  1066                          uint8_t context,
       
  1067                          uint16_t code,
       
  1068                          uint8_t clear_storage)
       
  1069 {
       
  1070     CyAsReturnStatus_t ret ;
       
  1071     CyAsLLRequestResponse resp ;
       
  1072     CyAsLLRequestResponse *resp_p = &resp ;
       
  1073 
       
  1074     CyAsHalMemSet(resp_p, 0, sizeof(resp)) ;
       
  1075     resp_p->length = 1 ;
       
  1076     CyAsLLRequestResponse_SetResponse(resp_p) ;
       
  1077     CyAsLLRequestResponse_SetContext(resp_p, context) ;
       
  1078 
       
  1079     if (clear_storage)
       
  1080         CyAsLLRequestResponse_SetClearStorageFlag(resp_p) ;
       
  1081 
       
  1082     CyAsLLRequestResponse_SetCode(resp_p, CY_RESP_SUCCESS_FAILURE) ;
       
  1083     CyAsLLRequestResponse_SetWord(resp_p, 0, code) ;
       
  1084 
       
  1085     ret = CyAsSendOne(dev_p, resp_p) ;
       
  1086 
       
  1087     return ret ;
       
  1088 }
       
  1089 
       
  1090 extern CyAsReturnStatus_t
       
  1091 CyAsLLSendDataResponse(
       
  1092                        CyAsDevice *dev_p,
       
  1093                        uint8_t context,
       
  1094                        uint16_t code,
       
  1095                        uint16_t length,
       
  1096                        void *data)
       
  1097 {
       
  1098     CyAsLLRequestResponse *resp_p ;
       
  1099     uint16_t wlen ;
       
  1100     uint8_t respbuf[256] ;
       
  1101 
       
  1102     if (length > 192)
       
  1103         return CY_AS_ERROR_INVALID_SIZE ;
       
  1104 
       
  1105     wlen = length / 2 ;                                 /* Word length for bytes */
       
  1106     if (length % 2)                                     /* If byte length odd, add one more */
       
  1107         wlen++ ;
       
  1108     wlen++ ;                                            /* One for the length of field */
       
  1109 
       
  1110     resp_p = (CyAsLLRequestResponse *)respbuf ;
       
  1111     CyAsHalMemSet(resp_p, 0, sizeof(respbuf)) ;
       
  1112     resp_p->length = wlen ;
       
  1113     CyAsLLRequestResponse_SetContext(resp_p, context) ;
       
  1114     CyAsLLRequestResponse_SetCode(resp_p, code) ;
       
  1115 
       
  1116     CyAsLLRequestResponse_SetWord(resp_p, 0, length) ;
       
  1117     CyAsLLRequestResponse_Pack(resp_p, 1, length, data) ;
       
  1118 
       
  1119     return CyAsSendOne(dev_p, resp_p) ;
       
  1120 }
       
  1121 
       
  1122 static CyBool
       
  1123 CyAsLLIsEPTransferRelatedRequest(CyAsLLRequestResponse *rqt_p, CyAsEndPointNumber_t ep)
       
  1124 {
       
  1125     uint16_t v ;
       
  1126     uint8_t  type = CyAsLLRequestResponse_GetCode(rqt_p) ;
       
  1127 
       
  1128     if (CyAsLLRequestResponse_GetContext(rqt_p) != CY_RQT_USB_RQT_CONTEXT)
       
  1129         return CyFalse ;
       
  1130 
       
  1131     /*
       
  1132      * When cancelling outstanding EP0 data transfers, any pending
       
  1133      * Setup ACK requests also need to be cancelled.
       
  1134      */
       
  1135     if ((ep == 0) && (type == CY_RQT_ACK_SETUP_PACKET))
       
  1136         return CyTrue ;
       
  1137 
       
  1138     if (type != CY_RQT_USB_EP_DATA)
       
  1139         return CyFalse ;
       
  1140 
       
  1141     v = CyAsLLRequestResponse_GetWord(rqt_p, 0) ;
       
  1142     if ((CyAsEndPointNumber_t)((v >> 13) & 1) != ep)
       
  1143         return CyFalse ;
       
  1144 
       
  1145     return CyTrue ;
       
  1146 }
       
  1147 
       
  1148 CyAsReturnStatus_t
       
  1149 CyAsLLRemoveEpDataRequests(CyAsDevice *dev_p, CyAsEndPointNumber_t ep)
       
  1150 {
       
  1151     CyAsContext *ctxt_p ;
       
  1152     CyAsLLRequestListNode *node_p ;
       
  1153     uint32_t imask ;
       
  1154 
       
  1155     /*
       
  1156     * First, remove any queued requests
       
  1157     */
       
  1158     ctxt_p = dev_p->context[CY_RQT_USB_RQT_CONTEXT] ;
       
  1159     if (ctxt_p)
       
  1160     {
       
  1161         for(node_p = ctxt_p->request_queue_p ; node_p ; node_p = node_p->next)
       
  1162         {
       
  1163             if (CyAsLLIsEPTransferRelatedRequest(node_p->rqt, ep))
       
  1164             {
       
  1165                 CyAsLLRemoveRequest(dev_p, ctxt_p, node_p->rqt, CyFalse) ;
       
  1166                 break ;
       
  1167             }
       
  1168         }
       
  1169 
       
  1170         /*
       
  1171         * Now, deal with any request that may be in transit
       
  1172         */
       
  1173         imask = CyAsHalDisableInterrupts() ;
       
  1174 
       
  1175         if (ctxt_p->request_queue_p != 0 &&
       
  1176             CyAsLLIsEPTransferRelatedRequest(ctxt_p->request_queue_p->rqt, ep) &&
       
  1177             CyAsRequestGetNodeState(ctxt_p->request_queue_p) == CY_AS_REQUEST_LIST_STATE_WAITING)
       
  1178         {
       
  1179             CyAsHalPrintMessage("Need to remove an in-transit request to Antioch\n") ;
       
  1180 
       
  1181             /*
       
  1182             * If the request has not been fully sent to West Bridge yet, abort sending.
       
  1183             * Otherwise, terminate the request with a CANCELED status. Firmware will
       
  1184             * already have terminated this transfer.
       
  1185             */
       
  1186             if (dev_p->ll_sending_rqt)
       
  1187                 dev_p->ll_abort_curr_rqt = CyTrue ;
       
  1188             else
       
  1189             {
       
  1190                 uint32_t state ;
       
  1191 
       
  1192                 node_p = ctxt_p->request_queue_p ;
       
  1193                 if (node_p->callback)
       
  1194                     node_p->callback(dev_p, ctxt_p->number, node_p->rqt, node_p->resp, CY_AS_ERROR_CANCELED) ;
       
  1195 
       
  1196                 ctxt_p->request_queue_p = node_p->next ;
       
  1197                 state = CyAsHalDisableInterrupts() ;
       
  1198                 CyAsHalCBFree(node_p) ;
       
  1199                 CyAsHalEnableInterrupts(state) ;
       
  1200             }
       
  1201         }
       
  1202 
       
  1203         CyAsHalEnableInterrupts(imask) ;
       
  1204     }
       
  1205 
       
  1206     return CY_AS_ERROR_SUCCESS ;
       
  1207 }