Setting up repository
[linux-libre-firmware.git] / ath9k_htc / sboot / magpie_1_1 / sboot / htc / src / htc.c
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted (subject to the limitations in the
7  * disclaimer below) provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the
15  *    distribution.
16  *
17  *  * Neither the name of Qualcomm Atheros nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
22  * GRANTED BY THIS LICENSE.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
23  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
24  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
32  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
33  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 /*
36  * @File: 
37  * 
38  * @Abstract: host target communications
39  * 
40  * @Notes: 
41  */
42 #include <osapi.h>
43 #include <Magpie_api.h> 
44 #include <htc.h>
45 #include <htc_api.h>
46 #include <hif_api.h>
47 #include <adf_os_mem.h> 
48 #include <adf_os_io.h> 
49
50 #include "htc_internal.h" 
51
52 //#define A_ASSERT(m)
53 #define A_UNCACHED_ADDR(addr) addr
54 //#define A_MEMZERO(v, size)
55
56 /*** statics vars ****/ 
57 //HTC_CONTEXT g_htcCtx;
58 //HTC_CONTEXT *g_pHTC = NULL;
59  
60 /* prototypes */
61 LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf, adf_nbuf_t pBuffers, void *arg);
62 LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, void *arg);
63 LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buf, void *context);
64 LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context);
65 LOCAL void HTCFreeMsgBuffer(HTC_CONTEXT *pHTC, adf_nbuf_t pBuffer);
66 LOCAL adf_nbuf_t HTCAllocMsgBuffer(HTC_CONTEXT *pHTC);
67 //LOCAL void HTC_EnqueuePausedRecv(HTC_ENDPOINT *pEndpoint, 
68 //                                 VBUF   *pFirstBuf,
69 //                                 VBUF   *pLastBuf);
70 //LOCAL VBUF* HTC_DequeuePausedRecv(HTC_ENDPOINT *pEndpoint);
71 LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask, HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Id);
72 LOCAL void AdjustCreditThreshold(HTC_ENDPOINT  *pEndpoint);
73 //LOCAL void _HTC_AddBufferResources(int buffers);
74 LOCAL void HTC_AssembleBuffers(HTC_CONTEXT *pHTC, int Count, int Size);
75 LOCAL htc_handle_t _HTC_Init(/*A_UINT32 dataAddr,*/
76         HTC_SETUP_COMPLETE_CB SetupComplete,
77                          HTC_CONFIG *pConfig);
78 LOCAL void _HTC_RegisterService(htc_handle_t handle, HTC_SERVICE *pService);
79 LOCAL void _HTC_Ready(htc_handle_t handle);
80 LOCAL void ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, A_BOOL sendCreditFlag);
81 LOCAL void _HTC_ReturnBuffers(htc_handle_t handle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers);
82 LOCAL void _HTC_ReturnBuffersList(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_queue_t bufHead);
83 LOCAL void _HTC_SendMsg(htc_handle_t handle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers);
84 void _HTC_PauseRecv(HTC_ENDPOINT_ID EndpointID);
85 void _HTC_ResumeRecv(HTC_ENDPOINT_ID EndpointID);
86 LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg);
87 LOCAL void HTCProcessConfigPipeMsg(HTC_CONTEXT *pHTC, HTC_CONFIG_PIPE_MSG *pMsg);
88 LOCAL void RedistributeCredit(adf_nbuf_t buf, int toPipeId);                         
89 LOCAL void _HTC_Shutdown(htc_handle_t htcHandle);
90
91      /* macro to check if the service wants to prevent credit dribbling by using 
92         a dynamic threshold */
93 #define CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint)                                        \
94     if ((pEndpoint)->ConnectionFlags & HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE) { \
95         AdjustCreditThreshold((pEndpoint));                                       \
96     }    
97
98 /***********************************************************************************************/
99 /************************ MODULE API implementation *******************************************/
100 #if 0
101 LOCAL void _HTC_AddBufferResources(int buffers)
102 {
103     (void)buffers;
104     //MboxHW_AddDMAResources(buffers);   
105 }
106 #endif
107
108 LOCAL void HTC_AssembleBuffers(HTC_CONTEXT *pHTC, int Count, int Size)
109 {
110     BUF_Pool_create_pool(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, Count, Size);       
111 }
112
113
114 LOCAL htc_handle_t _HTC_Init(HTC_SETUP_COMPLETE_CB SetupComplete,
115                              HTC_CONFIG *pConfig)
116 {
117     HIF_CALLBACK       hifCBConfig;
118     HTC_CONTEXT        *pHTC;    
119     
120     //if (NULL == g_pHTC) 
121     {
122         pHTC = (HTC_CONTEXT *)adf_os_mem_alloc(sizeof(HTC_CONTEXT));
123         //g_pHTC = &g_htcCtx;
124     } 
125     
126     adf_os_mem_zero(pHTC, sizeof(HTC_CONTEXT));
127
128     pHTC->OSHandle = pConfig->OSHandle;
129     pHTC->PoolHandle = pConfig->PoolHandle;
130     pHTC->hifHandle = pConfig->HIFHandle;
131                         
132     //A_MEMZERO(&hwConfig,sizeof(hwConfig));  
133     hifCBConfig.send_buf_done = A_INDIR(htc._HTC_SendDoneHandler);
134     hifCBConfig.recv_buf = A_INDIR(htc._HTC_MsgRecvHandler);
135     hifCBConfig.context = pHTC;
136     
137     /* initialize hardware layer */
138     HIF_register_callback(pConfig->HIFHandle, &hifCBConfig);
139                              
140         /* see if the host wants us to override the number of ctrl buffers */
141     //g_pHTC->NumBuffersForCreditRpts = (HOST_INTEREST->hi_mbox_io_block_sz >> 16) & 0xF;
142     pHTC->NumBuffersForCreditRpts = 0;
143     
144     if (0 == pHTC->NumBuffersForCreditRpts) {
145         /* nothing to override, simply set default */
146         pHTC->NumBuffersForCreditRpts = HTC_DEFAULT_NUM_CTRL_BUFFERS; 
147     }    
148     
149     //g_pHTC->MaxEpPendingCreditRpts = (HOST_INTEREST->hi_mbox_io_block_sz >> 20) & 0xF;
150     pHTC->MaxEpPendingCreditRpts = 0;
151     
152     if (0 == pHTC->MaxEpPendingCreditRpts) {
153         pHTC->MaxEpPendingCreditRpts = HTC_DEFAULT_MAX_EP_PENDING_CREDIT_REPORTS;    
154     }
155     /* calculate the total allocation size based on the number of credit report buffers */
156     pHTC->CtrlBufferAllocSize = MIN_CREDIT_BUFFER_ALLOC_SIZE * pHTC->NumBuffersForCreditRpts;
157     /* we need at least enough buffer space for 1 ctrl message */
158     pHTC->CtrlBufferAllocSize = A_MAX(pHTC->CtrlBufferAllocSize,MAX_HTC_SETUP_MSG_SIZE);
159     
160     //A_PRINTF("%d, %d, (%d, %d) %s-%s \n",g_pHTC->NumBuffersForCreditRpts,g_pHTC->CtrlBufferAllocSize,
161     //                        MIN_BUF_SIZE_FOR_RPTS, MIN_CREDIT_BUFFER_ALLOC_SIZE,__DATE__, __TIME__);
162                                           
163     /* save the size of each buffer/credit we will receive */
164     pHTC->RecvBufferSize = pConfig->CreditSize; //RecvBufferSize;
165     pHTC->TotalCredits = pConfig->CreditNumber;
166     //g_pHTC->FreeCreditList = pConfig->CreditList;
167     pHTC->TotalCreditsAssigned = 0;
168      
169     /* setup the pseudo service that handles HTC control messages */
170     pHTC->HTCControlService.ProcessRecvMsg = A_INDIR(htc._HTC_ControlSvcProcessMsg);
171     pHTC->HTCControlService.ProcessSendBufferComplete = A_INDIR(htc._HTC_ControlSvcProcessSendComplete);
172     pHTC->HTCControlService.TrailerSpcCheckLimit = HTC_CTRL_BUFFER_CHECK_SIZE;
173     pHTC->HTCControlService.MaxSvcMsgSize = MAX_HTC_SETUP_MSG_SIZE;
174     pHTC->HTCControlService.ServiceCtx = pHTC;
175     
176     /* automatically register this pseudo service to endpoint 1 */
177     pHTC->Endpoints[ENDPOINT0].pService = &pHTC->HTCControlService;
178     HIF_get_default_pipe(pHTC->hifHandle, &pHTC->Endpoints[ENDPOINT0].UpLinkPipeID, 
179                                           &pHTC->Endpoints[ENDPOINT0].DownLinkPipeID);
180     
181     /* Initialize control pipe so we could receive the HTC control packets */
182     // @TODO: msg size!
183     HIF_config_pipe(pHTC->hifHandle, pHTC->Endpoints[ENDPOINT0].UpLinkPipeID, 1);    
184     
185     /* set the first free endpoint */
186     pHTC->CurrentEpIndex = ENDPOINT1;
187     pHTC->SetupCompleteCb = SetupComplete;
188     
189         /* setup buffers for just the setup phase, we only need 1 buffer to handle
190         * setup */
191     HTC_AssembleBuffers(pHTC, 4, MAX_HTC_SETUP_MSG_SIZE);
192    
193     /* start hardware layer so that we can queue buffers */
194     HIF_start(pHTC->hifHandle);
195     
196     return pHTC;
197 }
198
199 LOCAL void _HTC_Shutdown(htc_handle_t htcHandle)
200 {
201     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
202     
203     adf_os_mem_free(pHTC);
204 }
205
206 LOCAL void _HTC_RegisterService(htc_handle_t htcHandle, HTC_SERVICE *pService)
207 {
208     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
209     
210         /* add it to the list */
211     pService->pNext = pHTC->pServiceList;
212     pHTC->pServiceList = pService;
213 }
214
215 LOCAL void _HTC_Ready(htc_handle_t htcHandle)
216 {
217     adf_nbuf_t      pBuffer;
218     HTC_READY_MSG   *pReady;
219     a_uint8_t       *addr;
220     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
221     
222     pBuffer = HTCAllocMsgBuffer(pHTC);
223     //A_ASSERT(pBuffer != NULL);
224        
225     /* an optimization... the header length is chosen to
226      * be aligned on a 16 bit bounday, the fields in the message are designed to
227      * be aligned */
228     addr = adf_nbuf_put_tail(pBuffer, sizeof(HTC_READY_MSG));       
229     pReady = (HTC_READY_MSG *)addr;     
230     A_MEMZERO(pReady,sizeof(HTC_READY_MSG));  
231     pReady->MessageID = adf_os_htons(HTC_MSG_READY_ID);
232     pReady->CreditSize = adf_os_htons((A_UINT16)pHTC->RecvBufferSize);
233     //A_ASSERT(g_pHTC->TotalCredits <= MAX_HTC_CREDITS);
234     pReady->CreditCount = adf_os_htons((A_UINT16)pHTC->TotalCredits);
235     pReady->MaxEndpoints = ENDPOINT_MAX;
236        
237     /* send out the message */
238     //A_DATA_CACHE_FLUSH(pBuffer->buffer, pBuffer->actual_length);    
239     HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);
240     /* now we need to wait for service connection requests */
241 }
242
243 LOCAL void ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, A_BOOL sendCreditFlag)
244 {   
245     int         nbufs = 1;
246     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
247     
248     //A_ASSERT(EndpointID < ENDPOINT_MAX);
249  
250     /* supply some head-room again */
251     adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
252     //A_DATA_CACHE_INVAL(pBuffers->buffer, pBuffers->actual_length + HTC_HDR_SZ);
253               
254     /* enqueue all buffers to the single mailbox */
255     HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers);    
256     //A_ASSERT(nbufs != 0);
257      
258     if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {       
259         A_UINT32    epCreditMask = (1 << EndpointID);
260         /* we are running normally */
261         /* update pending credit counts with the number of buffers that were added */
262         pHTC->Endpoints[EndpointID].CreditsToReturn += (A_INT16)nbufs;
263         pHTC->Endpoints[EndpointID].CreditsConsumed -= (A_INT16)nbufs;  
264         //A_ASSERT(g_pHTC->Endpoints[EndpointID].CreditsConsumed >= 0);          
265         /* update bit map that this endpoint has non-zero credits */
266         pHTC->EpCreditPendingMap |= epCreditMask; 
267
268         if (sendCreditFlag) {
269             HTCCheckAndSendCreditReport(pHTC, epCreditMask,&pHTC->Endpoints[EndpointID],EndpointID);
270         }
271
272     } else {
273         /* we have not started yet so all return operations are simply adding buffers
274          * to the interface at startup, so we can keep track of how many total 
275          * credits we get */
276         /* update global count that will be returned to the host */
277         pHTC->TotalCredits += nbufs;
278     }     
279 }
280
281 LOCAL void _HTC_ReturnBuffersList(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_queue_t bufHead)
282 {
283     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;
284     adf_nbuf_t netbuf, tmpNbuf;
285
286     /* retrieve each nbuf in the queue */
287     netbuf = adf_nbuf_queue_first(&bufHead);
288
289     while (netbuf) {
290
291         tmpNbuf = netbuf;
292         netbuf = adf_nbuf_queue_next(netbuf);
293
294         ReturnBuffers(htcHandle, EndpointID, tmpNbuf, FALSE);
295     }
296
297     HTCCheckAndSendCreditReport(pHTC, (1 << EndpointID),&pHTC->Endpoints[EndpointID],EndpointID);
298 }
299
300 LOCAL void _HTC_ReturnBuffers(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers)
301 {
302     ReturnBuffers(htcHandle, EndpointID, pBuffers, TRUE);
303 }
304  
305 LOCAL void _HTC_SendMsg(htc_handle_t htcHandle, HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers)
306 {
307     HTC_FRAME_HDR       *pHTCHdr;
308     int                 totsz;
309     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;  
310     HTC_BUF_CONTEXT *ctx;
311     
312     ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers);
313     
314     /* init total size (this does not include the space we will put in for the HTC header) */
315     totsz = adf_nbuf_len(pBuffers);
316     
317     /* the first buffer stores the header */
318         /* back up buffer by a header size when we pass it down, by agreed upon convention the caller
319     * points the buffer to it's payload and leaves head room for the HTC header  
320     * Note: in HTCSendDoneHandler(), we undo this so that the caller get's it's buffer
321         *       back untainted */   
322     pHTCHdr = (HTC_FRAME_HDR *)adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
323     
324     /* flag that this is the header buffer that was modified */
325     ctx->htc_flags |= HTC_FLAGS_BUF_HDR;   
326     /* mark where this buffer came from */
327     ctx->end_point = EndpointID;      
328     /* the header start is ALWAYS aligned since we DMA it directly */
329     //pHTCHdr = (HTC_FRAME_HDR *)A_UNCACHED_ADDR(VBUF_GET_DATA_ADDR(pBuffers));
330         /* set some fields, the rest of them will be filled below when we check for
331         * trailer space */
332     pHTCHdr->Flags = 0;
333     pHTCHdr->EndpointID = EndpointID;    
334        
335     //A_ASSERT(totsz <= g_pHTC->Endpoints[EndpointID].pService->MaxSvcMsgSize);  
336     /* check opportunistically if we can return any reports via a trailer */
337     do {
338         int               room,i,totalReportBytes;
339         A_UINT32          creditsPendingMap, compareMask;
340         HTC_CREDIT_REPORT *pCreditRpt;
341         HTC_RECORD_HDR    *pRecHdr;
342         int               pipeMaxLen;
343         A_UINT32          roomForPipeMaxLen;
344                           
345         /* figure out how much room the last buffer can spare */
346         pipeMaxLen = HIF_get_max_msg_len(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID);
347         roomForPipeMaxLen = pipeMaxLen - adf_nbuf_headroom(pBuffers) - adf_nbuf_len(pBuffers);
348         if ( roomForPipeMaxLen < 0 ) {
349             roomForPipeMaxLen = 0;
350         }
351                         
352         room = adf_os_min( adf_nbuf_tailroom(pBuffers), roomForPipeMaxLen);
353         if (room < (int)(sizeof(HTC_CREDIT_REPORT) + sizeof(HTC_RECORD_HDR))) {
354             /* no room for any reports */
355             break;    
356         }   
357             /* note, a record header only has 8 bit fields, so this is safe.
358             * we need an uncached pointer here too */            
359         totalReportBytes = 0;
360         
361         /* get a copy */        
362         creditsPendingMap = pHTC->EpCreditPendingMap;   
363                            
364             /* test pending map to see if we can send a report , if any
365         * credits are available, we might as well send them on the 
366             * unused space in the buffer */
367         if (creditsPendingMap) { 
368             
369             pRecHdr = (HTC_RECORD_HDR *)adf_nbuf_put_tail(pBuffers, sizeof(HTC_RECORD_HDR));            
370             
371                 /* set the ID, the length will be updated with the number of credit reports we
372                 * can fit (see below) */
373             pRecHdr->RecordID = HTC_RECORD_CREDITS;
374             pRecHdr->Length = 0;
375             /* the credit report follows the record header */         
376             totalReportBytes += sizeof(HTC_RECORD_HDR);
377             room -= sizeof(HTC_RECORD_HDR);
378             
379             /* walkthrough pending credits map and build the records */
380             for (i = 0; 
381                  (creditsPendingMap != 0) && (room >= (int)sizeof(HTC_CREDIT_REPORT)); 
382                  i++) {                
383                      compareMask = (1 << i);
384                      if (compareMask & creditsPendingMap) {
385                         
386                          pCreditRpt = (HTC_CREDIT_REPORT *)adf_nbuf_put_tail(pBuffers, sizeof(HTC_CREDIT_REPORT));
387                                     
388                          /* clear pending mask, we are going to return all these credits */
389                          creditsPendingMap &= ~(compareMask);
390                          /* add this record */
391                          pCreditRpt->EndpointID = i;
392                          pCreditRpt->Credits = (A_UINT8)pHTC->Endpoints[i].CreditsToReturn;
393                          /* remove pending credits, we always send deltas */
394                          pHTC->Endpoints[i].CreditsToReturn = 0; 
395                          /* adjust new threshold for this endpoint if needed */
396                          CHECK_AND_ADJUST_CREDIT_THRESHOLD(&pHTC->Endpoints[i]);
397                          /* update this record length */
398                          pRecHdr->Length += sizeof(HTC_CREDIT_REPORT);
399                          room -= sizeof(HTC_CREDIT_REPORT);
400                          totalReportBytes += sizeof(HTC_CREDIT_REPORT);
401
402                          if ( room < sizeof(HTC_CREDIT_REPORT) ) {
403                              break;
404                          }
405                      }
406                  }
407             
408                  /* update new pending credits map */       
409                  pHTC->EpCreditPendingMap = creditsPendingMap;
410         }
411         
412         if (totalReportBytes <= 0) {
413             break;
414         }
415         
416             /* must fit into a byte, this should never actually happen since
417         * the maximum possible number of endpoints is 32. 
418         * The trailer can have at most 1 credit record with up to 32  reports in the record.
419         * The trailer can have at most 1 lookahead record with only 1 lookahead report in the record.
420         * 
421             * */
422         //A_ASSERT(totalReportBytes <= 255);
423         
424         /* set header option bytes */ 
425         pHTCHdr->ControlBytes[0] = totalReportBytes;
426         /* HTC frame contains a trailer */
427         pHTCHdr->Flags |= HTC_FLAGS_RECV_TRAILER;
428         /* increment total size by the reports we added */
429         totsz += totalReportBytes;
430         /* adjust the last buffer we used for adding on the trailer */                                 
431     } while (FALSE);
432           
433     if (totsz == 0) {
434         //A_ASSERT(FALSE);
435     }
436     
437     /* set length for message (this includes any reports that were added above) */
438     pHTCHdr->PayloadLen = adf_os_htons(totsz);  
439     HIF_send_buffer(pHTC->hifHandle, pHTC->Endpoints[EndpointID].DownLinkPipeID, pBuffers);       
440 }
441
442 void _HTC_PauseRecv(HTC_ENDPOINT_ID EndpointID)
443 {
444 #if 0  // Disable first. Ray
445 #ifdef HTC_PAUSE_RESUME_REF_COUNTING    
446     g_pHTC->Endpoints[EndpointID].PauseRefCount++;
447 #endif
448         /* we are now paused */
449     g_pHTC->EpRecvPausedMap |= (1 << EndpointID);
450 #endif    
451 }
452
453 void _HTC_ResumeRecv(HTC_ENDPOINT_ID EndpointID)
454 {
455 #if 0  // Disable first. Ray    
456     HTC_BUFFER      *buffer;
457     HTC_ENDPOINT    *pEndpoint;
458     
459     pEndpoint = &g_pHTC->Endpoints[EndpointID];
460
461 /* TODO: we can't quite use referencing counting yet until we clean up the WLAN
462  * app, there are some un-matched pause/resume cases that need to be fixed */
463 #ifdef HTC_PAUSE_RESUME_REF_COUNTING  
464     pEndpoint->PauseRefCount--;
465     //A_ASSERT(pEndpoint->PauseRefCount >= 0);
466     
467         /* check reference count and unpause if it is zero */
468     if (pEndpoint->PauseRefCount > 0) {
469         return;    
470     }   
471 #endif
472
473     g_pHTC->EpRecvPausedMap &= ~(1 << EndpointID);        
474         /* unload the paused receive queue */
475     while ((buffer = HTC_DequeuePausedRecv(pEndpoint)) != NULL) {          
476         /* note that the paused messages have already been processed at the HTC layer,
477          * we can simply indicate the buffers to the service */
478         pEndpoint->pService->ProcessRecvMsg(EndpointID,buffer);    
479     }
480 #endif    
481 }
482
483 int _HTC_GetReservedHeadroom(htc_handle_t htcHandle)
484 {
485     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle;  
486     
487     return HTC_HDR_LENGTH + HIF_get_reserved_headroom(pHTC->hifHandle);
488 }
489     
490 void htc_module_install(struct htc_apis *pAPIs)
491 {   
492     pAPIs->_HTC_Init = _HTC_Init;
493     pAPIs->_HTC_ReturnBuffers = _HTC_ReturnBuffers;
494     pAPIs->_HTC_ReturnBuffersList = _HTC_ReturnBuffersList;
495     pAPIs->_HTC_Ready = _HTC_Ready;
496     pAPIs->_HTC_RegisterService = _HTC_RegisterService;
497     pAPIs->_HTC_SendMsg = _HTC_SendMsg;   
498     pAPIs->_HTC_Shutdown = _HTC_Shutdown;
499     pAPIs->_HTC_GetReservedHeadroom = _HTC_GetReservedHeadroom;
500     pAPIs->_HTC_MsgRecvHandler = HTCMsgRecvHandler;
501     pAPIs->_HTC_SendDoneHandler = HTCSendDoneHandler;
502     pAPIs->_HTC_ControlSvcProcessMsg = HTCControlSvcProcessMsg;
503     pAPIs->_HTC_ControlSvcProcessSendComplete = HTCControlSvcProcessSendComplete;
504     
505     //pAPIs->_HTC_PauseRecv = _HTC_PauseRecv;
506     //pAPIs->_HTC_ResumeRecv = _HTC_ResumeRecv; 
507     //pAPIs->_HTC_AddBufferResources = _HTC_AddBufferResources;
508         /* save ptr to the ptr to the context for external code to inspect/modify internal module state */
509     //pAPIs->pReserved = &g_pHTC;
510 }
511
512 /*******************************************************************************************/
513 /****************   INTERNAL ROUTINES to this MODULE ***************************************/
514
515 /* free message to the free list */
516 //LOCAL void HTCFreeMsgBuffer(HTC_BUFFER *pBuffer)
517 LOCAL void HTCFreeMsgBuffer(HTC_CONTEXT *pHTC, adf_nbuf_t buf) 
518 {
519     BUF_Pool_free_buf(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, buf);      
520 }
521
522 /* HTC control message allocator (also used for empty frames to send trailer options) */
523 //LOCAL HTC_BUFFER *HTCAllocMsgBuffer(void)
524 LOCAL adf_nbuf_t HTCAllocMsgBuffer(HTC_CONTEXT *pHTC)
525 {
526     return BUF_Pool_alloc_buf(pHTC->PoolHandle, POOL_ID_HTC_CONTROL, HTC_GetReservedHeadroom(pHTC));   
527 }
528
529 LOCAL void HTCCheckAndSendCreditReport(HTC_CONTEXT *pHTC, A_UINT32 EpMask, HTC_ENDPOINT *pEndpoint, HTC_ENDPOINT_ID Eid)
530 {
531     adf_nbuf_t  pCredBuffer;
532     HTC_BUF_CONTEXT *ctx;    
533         
534     do {
535         /* check if host needs credits */
536         if (!(pHTC->EpHostNeedsCreditMap & EpMask)) {
537             /* host does not need any credits for this set */
538             break;    
539         }
540         /* check if any are pending */
541         if (!(pHTC->EpCreditPendingMap & EpMask)) {
542             /* nothing to send up */
543             break;    
544         }  
545         /* was an endpoint specified? */
546         if (pEndpoint != NULL) {
547             /* see if a threshold is in effect for this endpoint */
548             if (pEndpoint->CreditReturnThreshhold != 0) {
549                 if (pEndpoint->CreditsToReturn < pEndpoint->CreditReturnThreshhold) {
550                     /* this endpoint is using a threshold to prevent credits from dribbling
551                      * back to the host */
552                     break;
553                 }
554             }
555          
556             if (pEndpoint->PendingCreditReports >= pHTC->MaxEpPendingCreditRpts) {
557                 /* this endpoint already has some reports outstanding */
558                 /* flag that as soon as a buffer is reaped, we issue a credit update to
559                  * pick up this credit that is being held up because the endpoint has already
560                  * exceeded the max outstanding credit report limit */    
561                pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON;
562                 break;    
563             }                         
564         }
565         
566         /* if we get here we have some credits to send up */
567                         
568         /* allocate a message buffer for the trailer */
569         pCredBuffer = HTCAllocMsgBuffer(pHTC);
570         if (NULL == pCredBuffer) {
571             /* no buffers left to send an empty message with trailers, host will just
572             * have to wait until we get our endpoint 0 messages back.. */
573             /* mark that we need to send an update as soon as we can get a buffer back */
574             pHTC->StateFlags |= HTC_SEND_CREDIT_UPDATE_SOON;
575             break;    
576         }
577         
578         ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pCredBuffer);
579         if (pEndpoint != NULL) {
580             /* keep track of pending reports */
581             pEndpoint->PendingCreditReports++; 
582             /* save the endpoint in order to decrement the count when the send completes */
583             ctx->htc_flags = Eid | HTC_FLAGS_CREDIT_RPT;
584         }   
585             
586         /* this is an empty message, the HTC_SendMsg will tack on a trailer in the remaining
587          * space, NOTE: no need to flush the cache, the header and trailers are assembled
588          * using uncached addresses */
589         HTC_SendMsg(pHTC, ENDPOINT0, pCredBuffer);    
590     
591     } while (FALSE);      
592 }
593         
594 /* called in response to the arrival of a service connection message */
595 LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg)
596 {
597     HTC_SERVICE                         *pService = pHTC->pServiceList;
598     A_UINT8                             connectStatus = HTC_SERVICE_NOT_FOUND;
599     //HTC_BUFFER                          *pBuffer;
600     adf_nbuf_t                          pBuffer;
601     HTC_CONNECT_SERVICE_RESPONSE_MSG    *pRspMsg;
602     int                                 metaDataOutLen = 0;
603     A_UINT16                            serviceId = adf_os_ntohs(pMsg->ServiceID);
604     
605     pBuffer = HTCAllocMsgBuffer(pHTC);
606     //A_ASSERT(pBuffer != NULL);
607     /* note : this will be aligned */
608     pRspMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)
609                 adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG));
610                                  
611     A_MEMZERO(pRspMsg,sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG));
612     pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONNECT_SERVICE_RESPONSE_ID);
613     /* reflect the service ID for this connect attempt */
614     pRspMsg->ServiceID = adf_os_htons(serviceId);
615
616     while (pService) {
617         
618         if (pHTC->CurrentEpIndex >= ENDPOINT_MAX) {
619             /* no more endpoints */
620             connectStatus = HTC_SERVICE_NO_RESOURCES;
621             break;    
622         }
623
624         if (serviceId == pService->ServiceID) {
625             /* we found a match */             
626             A_UINT8     *pMetaDataIN = NULL; 
627             A_UINT8     *pMetaDataOut;
628             
629             /* outgoing meta data resides in the space after the response message */
630             pMetaDataOut = ((A_UINT8 *)pRspMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG);
631             
632             if (pMsg->ServiceMetaLength != 0) {
633                 //A_ASSERT(pMsg->ServiceMetaLength <= HTC_SERVICE_META_DATA_MAX_LENGTH);
634                 /* the meta data follows the connect service message */
635                 pMetaDataIN = ((A_UINT8 *)pMsg) + sizeof(HTC_CONNECT_SERVICE_MSG);
636             }
637
638             //A_ASSERT(pService->ProcessConnect != NULL);
639             /* call the connect callback with the endpoint to use and pointers to meta data */
640             connectStatus = pService->ProcessConnect(pService,
641                     pHTC->CurrentEpIndex,
642                     pMetaDataIN,
643                     pMsg->ServiceMetaLength,
644                     pMetaDataOut,
645                     &metaDataOutLen);
646             
647             /* check if the service accepted this connection request */
648             if (HTC_SERVICE_SUCCESS == connectStatus) {
649                 //A_ASSERT(metaDataOutLen <= HTC_SERVICE_META_DATA_MAX_LENGTH);
650                 /* set the length of the response meta data going back to the host */
651                 pRspMsg->ServiceMetaLength = (A_UINT8)metaDataOutLen;
652                 /* set the endpoint ID the host will now communicate over */
653                 pRspMsg->EndpointID = pHTC->CurrentEpIndex;
654                 /* return the maximum message size for this service */
655                 pRspMsg->MaxMsgSize = adf_os_htons((A_UINT16)pService->MaxSvcMsgSize);
656                 /* assign this endpoint to this service, this will be used in routing messages */
657                 pHTC->Endpoints[pHTC->CurrentEpIndex].pService = pService;
658                 /* set connection flags */
659                 pHTC->Endpoints[pHTC->CurrentEpIndex].ConnectionFlags = pMsg->ConnectionFlags;
660                 
661                 pHTC->Endpoints[pHTC->CurrentEpIndex].DownLinkPipeID = pMsg->DownLinkPipeID;
662                 pHTC->Endpoints[pHTC->CurrentEpIndex].UpLinkPipeID = pMsg->UpLinkPipeID;
663                 
664                 /* mark that we are now connected */
665                 pService->ServiceFlags |= HTC_SERVICE_FLAGS_CONNECTED;
666                 /* bump up our index, this EP is now in use */
667                 pHTC->CurrentEpIndex++;   
668             }
669
670             break;
671         }       
672         
673         pService = pService->pNext;   
674     }
675                    
676     pRspMsg->Status = connectStatus;    
677     
678     /* send out the response message */
679     //A_DATA_CACHE_FLUSH(pBuffer->buffer, pBuffer->actual_length);
680     HTC_SendMsg(pHTC, ENDPOINT0, pBuffer); 
681 }
682
683 LOCAL void HTCProcessConfigPipeMsg(HTC_CONTEXT *pHTC, HTC_CONFIG_PIPE_MSG *pMsg)
684 {
685     //HTC_SERVICE                         *pService = g_pHTC->pServiceList;
686     //A_UINT8                             connectStatus = HTC_SERVICE_NOT_FOUND;
687     adf_nbuf_t                          pBuffer;
688     HTC_CONFIG_PIPE_RESPONSE_MSG        *pRspMsg;
689         
690     pBuffer = HTCAllocMsgBuffer(pHTC);
691        
692     //A_ASSERT(pBuffer != NULL);
693     /* note : this will be aligned */
694     pRspMsg = (HTC_CONFIG_PIPE_RESPONSE_MSG *)
695                 adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONFIG_PIPE_RESPONSE_MSG));    
696               
697     A_MEMZERO(pRspMsg,sizeof(HTC_CONFIG_PIPE_RESPONSE_MSG));
698     
699     pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONFIG_PIPE_RESPONSE_ID);
700     /* reflect the service ID for this connect attempt */
701     pRspMsg->PipeID = pMsg->PipeID;
702
703     if ( HIF_is_pipe_supported(pHTC->hifHandle, pMsg->PipeID) ) {
704         pRspMsg->Status = 0;            
705     } else {
706         pRspMsg->Status = 1; 
707         goto config_done;
708     }
709
710     if ( (pHTC->TotalCreditsAssigned + pMsg->CreditCount) <= pHTC->TotalCredits ) {
711         pHTC->TotalCreditsAssigned += pMsg->CreditCount;
712     } else {
713         pRspMsg->Status = 2;
714         goto config_done;
715     }
716     
717     HIF_config_pipe(pHTC->hifHandle, pMsg->PipeID, pMsg->CreditCount);
718     
719 config_done:      
720     /* send out the response message */
721     //A_DATA_CACHE_FLUSH(pBuffer->buffer, pBuffer->actual_length);    
722     HTC_SendMsg(pHTC, ENDPOINT0, pBuffer);             
723 }
724
725 /* process an incomming control message from the host */
726 LOCAL void HTCControlSvcProcessMsg(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t hdr_buf, adf_nbuf_t pBuffers, void *arg)
727 {  
728     A_BOOL setupComplete = FALSE;
729     a_uint8_t *anbdata;
730     a_uint32_t anblen;
731     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg;
732     HTC_UNKNOWN_MSG  *pMsg;
733         
734     adf_os_assert(hdr_buf == ADF_NBUF_NULL);
735
736     /* we assume buffers are aligned such that we can access the message
737     * parameters directly*/
738     adf_nbuf_peek_header(pBuffers, &anbdata, &anblen);
739     pMsg = (HTC_UNKNOWN_MSG *)anbdata;
740     
741     /* we cannot handle fragmented messages across buffers */
742     //A_ASSERT(pBuffers->next == NULL);
743     
744     switch ( adf_os_ntohs(pMsg->MessageID) ) {        
745         case HTC_MSG_CONNECT_SERVICE_ID:
746             //A_ASSERT(pBuffers->actual_length >= sizeof(HTC_CONNECT_SERVICE_MSG));
747             HTCProcessConnectMsg(pHTC, (HTC_CONNECT_SERVICE_MSG *)pMsg); 
748             break;
749         case HTC_MSG_CONFIG_PIPE_ID:
750             HTCProcessConfigPipeMsg(pHTC, (HTC_CONFIG_PIPE_MSG *)pMsg); 
751             break;            
752         case HTC_MSG_SETUP_COMPLETE_ID:
753                 /* the host has indicated that it has completed all
754             setup tasks and we can now let the services take over to
755             run the rest of the application */
756             setupComplete = TRUE;  
757             /* can't get this more than once */
758             //A_ASSERT(!(g_pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE));            
759             break;
760         default:
761             ;
762             //A_ASSERT(FALSE);
763     }  
764         
765     if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
766         /* recycle buffer only if we are fully running */
767         HTC_ReturnBuffers(pHTC, ENDPOINT0,pBuffers);
768     } else {
769         /* supply some head-room again */
770         //A_DATA_CACHE_INVAL(pBuffers->buffer, pBuffers->actual_length + HTC_HDR_SZ);
771         adf_nbuf_push_head(pBuffers, HTC_HDR_LENGTH);
772             
773         /* otherwise return the packet back to mbox */
774         HIF_return_recv_buf(pHTC->hifHandle, pHTC->Endpoints[EndpointID].UpLinkPipeID, pBuffers);        
775     }
776
777     if (setupComplete) {        
778         /* mark that setup has completed */
779         pHTC->StateFlags |= HTC_STATE_SETUP_COMPLETE; 
780         if (pHTC->SetupCompleteCb != NULL) {
781             pHTC->SetupCompleteCb();
782         }
783     }
784 }
785
786 /* callback when endpoint 0 send buffers are completed */
787 LOCAL void HTCControlSvcProcessSendComplete(HTC_ENDPOINT_ID EndpointID, adf_nbuf_t pBuffers, void *arg)
788 {
789     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)arg;
790     HTC_BUF_CONTEXT *ctx;
791     HTC_ENDPOINT_ID  creditRptEndpoint;
792     
793     ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(pBuffers);       
794     
795     //A_ASSERT(EndpointID == ENDPOINT0);
796     
797     /* put them back into the pool */
798 #if 0    
799     while (pBuffers != NULL) {
800         pNext = pBuffers->next_buf;
801         pBuffers->next_buf = NULL;       
802         /* note: HTC does not send fragmented control messages, so each buffer
803         * represents 1 full HTC control message */  
804         if (pBuffers->desc_list->control & HTC_FLAGS_CREDIT_RPT) {                      
805             /* extract the endpoint number that requested this credit report */     
806             creditRptEndpoint = pBuffers->desc_list->control & HTC_FLAGS_CRPT_EP_MASK;    
807             pBuffers->desc_list->control = 0;
808             g_pHTC->Endpoints[creditRptEndpoint].PendingCreditReports--;  
809             //A_ASSERT(g_pHTC->Endpoints[creditRptEndpoint].PendingCreditReports >= 0);           
810         }
811         /* free this one */
812         HTCFreeMsgBuffer(pBuffers);
813         pBuffers = pNext;
814     }
815 #else
816     if ( ctx->htc_flags & HTC_FLAGS_CREDIT_RPT ) {   
817         /* extract the endpoint number that requested this credit report */ 
818         creditRptEndpoint = ctx->htc_flags & HTC_FLAGS_CRPT_EP_MASK;    
819         pHTC->Endpoints[creditRptEndpoint].PendingCreditReports--;  
820         //A_ASSERT(g_pHTC->Endpoints[creditRptEndpoint].PendingCreditReports >= 0);             
821     }
822     
823     HTCFreeMsgBuffer(pHTC, pBuffers);
824 #endif  
825    
826     if (pHTC->StateFlags & HTC_SEND_CREDIT_UPDATE_SOON) {
827         /* this flag is set when the host could not send a credit report
828          * because we ran out of HTC control buffers */
829         pHTC->StateFlags &= ~HTC_SEND_CREDIT_UPDATE_SOON;
830         /* send out a report if anything is pending */
831         HTCCheckAndSendCreditReport(pHTC, HTC_ANY_ENDPOINT_MASK,NULL,ENDPOINT_MAX);
832     }  
833 }
834
835 LOCAL void HTCSendDoneHandler(adf_nbuf_t buf, void *context)
836 {
837     A_UINT8      current_eid;
838     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context;
839     HTC_BUF_CONTEXT *ctx;
840       
841     ctx = (HTC_BUF_CONTEXT *)adf_nbuf_get_priv(buf);
842     current_eid = ctx->end_point;
843         
844     /* Walk through the buffers and fixup the ones we used for HTC headers.
845      * The buffer list may contain more than one string of HTC buffers comprising of an
846     * HTC message so we need to check every buffer */            
847     adf_nbuf_pull_head(buf, HTC_HDR_LENGTH);
848                    
849     pHTC->Endpoints[current_eid].pService->
850         ProcessSendBufferComplete(current_eid, 
851                                   buf, 
852                                   pHTC->Endpoints[current_eid].pService->ServiceCtx); 
853 }
854
855 #if 0
856 LOCAL void HTC_EnqueuePausedRecv(HTC_ENDPOINT *pEndpoint, 
857                                  HTC_BUFFER *pFirstBuf,
858                                  HTC_BUFFER *pLastBuf)
859 {
860     //A_ASSERT(pLastBuf->next == NULL);
861     
862     if (NULL == pEndpoint->pRcvPausedQueueTail) {
863         pEndpoint->pRcvPausedQueueTail = pLastBuf;
864         pEndpoint->pRcvPausedQueueHead = pFirstBuf;        
865     } else {
866             /* queue to the tail */
867         pEndpoint->pRcvPausedQueueTail->next = pFirstBuf;
868         pEndpoint->pRcvPausedQueueTail = pLastBuf;        
869     }
870     
871 }
872 #endif
873
874 #if 0
875 LOCAL HTC_BUFFER *HTC_DequeuePausedRecv(HTC_ENDPOINT *pEndpoint)
876 {
877     HTC_BUFFER *pHead;
878     HTC_BUFFER *pCur;
879     
880     if (pEndpoint->pRcvPausedQueueHead != NULL) {
881             /* there is a message in the queue */ 
882         pHead = pEndpoint->pRcvPausedQueueHead;   
883         pCur = pHead;
884         
885         while (pCur != NULL) {
886                 /* check for end marker on this buffer */    
887             if (pCur->htc_flags & HTC_FLAGS_RECV_END_MSG) {
888                 pCur->htc_flags &= ~HTC_FLAGS_RECV_END_MSG;
889                     /* advance the head */
890                 pEndpoint->pRcvPausedQueueHead = pCur->next;
891                 
892                 if (NULL == pEndpoint->pRcvPausedQueueHead) {
893                         /* list is now empty */
894                     pEndpoint->pRcvPausedQueueTail = NULL;    
895                 }
896                     /* cut this message out */
897                 pCur->next = NULL;
898                 break;
899             }            
900             pCur = pCur->next;
901         }       
902             /* we should always find complete messages with the marker present */
903         //A_ASSERT(pCur != NULL);
904         return pHead;
905     } else {
906         //A_ASSERT(pEndpoint->pRcvPausedQueueTail == NULL);
907         return NULL;   
908     }
909 }
910 #endif
911     
912 LOCAL void AdjustCreditThreshold(HTC_ENDPOINT  *pEndpoint)
913 {
914
915     A_INT16 creditsOutstanding = pEndpoint->CreditsToReturn + pEndpoint->CreditsConsumed;
916         /* set the new threshold based on the number of credits that have been consumed
917          * and which have not been returned by the app.
918          * Note: it is okay for this threshold to be zero which indicates no threshold 
919          * is in use */    
920     switch (pEndpoint->ConnectionFlags & HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK) {
921         case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH :
922             creditsOutstanding >>= 2;
923             break;                    
924         case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF :
925             creditsOutstanding >>= 1;
926             break;
927         case HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS :  
928             creditsOutstanding = (creditsOutstanding * 3) >> 2;                  
929             break;
930         /* default case is unity */    
931     }
932     
933     pEndpoint->CreditReturnThreshhold = creditsOutstanding;
934     
935 }
936
937 LOCAL void RedistributeCredit(adf_nbuf_t buf, int toPipeId)
938 {
939
940 }
941             
942 /* callback from the mailbox hardware layer when a full message arrives */
943 LOCAL void HTCMsgRecvHandler(adf_nbuf_t hdr_buf, adf_nbuf_t buffer, void *context)
944 {
945     A_UINT16       totsz;
946     HTC_ENDPOINT  *pEndpoint;
947     A_UINT32       eidMask;
948     int            eid;    
949     a_uint8_t      *anbdata;
950     a_uint32_t     anblen;
951     HTC_FRAME_HDR  *pHTCHdr;
952     HTC_CONTEXT *pHTC = (HTC_CONTEXT *)context;
953     adf_nbuf_t tmp_nbuf;
954                 
955     if (hdr_buf == ADF_NBUF_NULL) {
956         /* HTC hdr is not in the hdr_buf */
957         tmp_nbuf = buffer;
958     }
959     else {
960         tmp_nbuf = hdr_buf;
961     }
962                 
963     adf_nbuf_peek_header(tmp_nbuf, &anbdata, &anblen);        
964     pHTCHdr = (HTC_FRAME_HDR *)anbdata; 
965       
966     totsz = adf_os_ntohs(pHTCHdr->PayloadLen); 
967     
968     //A_ASSERT(pHTCHdr->EndpointID < ENDPOINT_MAX);   
969     eid = pHTCHdr->EndpointID; 
970     
971     pEndpoint = &pHTC->Endpoints[eid];
972     eidMask = 1 << eid;
973
974     if (pHTCHdr->Flags & HTC_FLAGS_CREDIT_REDISTRIBUTION) {
975         /* The pipe id where the credit is redistributed to is carried in Control
976         * Byte 0 */
977         RedistributeCredit(tmp_nbuf, pHTCHdr->ControlBytes[0]);
978         return;
979     }
980
981     if (pHTC->StateFlags & HTC_STATE_SETUP_COMPLETE) {
982         /* after setup we keep track of credit consumption to allow us to
983         * adjust thresholds to reduce credit dribbling */  
984         pEndpoint->CreditsConsumed ++;
985     }
986
987     /* from the design document, we put the endpoint into a "host-needs-credit" state
988     * when we receive a frame with the NEED_CREDIT_UPDATE flag set .
989     * if the host received credits through an opportunistic path, then it can
990     * issue a another frame with this bit cleared, this signals the target to clear
991     * the "host-needs-credit" state */    
992     if (pHTCHdr->Flags & HTC_FLAGS_NEED_CREDIT_UPDATE) {
993         /* the host is running low (or is out) of credits on this
994         * endpoint, update mask */
995         pHTC->EpHostNeedsCreditMap |= eidMask; 
996         /* check and set new threshold since host has reached a low credit situation */
997         CHECK_AND_ADJUST_CREDIT_THRESHOLD(pEndpoint);                          
998     } else {
999         /* clear the flag */
1000         pHTC->EpHostNeedsCreditMap &= ~(eidMask);       
1001         pEndpoint->CreditReturnThreshhold = 0; 
1002     }
1003
1004     /* Adjust the first buffer to point to the start of the actual 
1005        payload, the first buffer contains the header */
1006     adf_nbuf_pull_head(tmp_nbuf, HTC_HDR_LENGTH);
1007                     
1008     /* NOTE : This callback could re-queue the recv buffers within this calling context.
1009     *        The callback could also send a response message within the context of this callback
1010     *        as the result of parsing this message.  In either case, if there are
1011     *        pending credits and the host needs them, a credit report will be sent either through 
1012     *        the response message trailer or a NULL message through HTC_ReturnBuffers().
1013     */       
1014         
1015     //A_ASSERT(totsz <= pEndpoint->pService->MaxSvcMsgSize);       
1016
1017 #if 0    
1018     /* is this endpoint paused? */ 
1019     if (g_pHTC->EpRecvPausedMap & eidMask) {
1020         /* note that curr_buf is the last buffer */  
1021         /* mark the last buffer so that it indicates the end of this message */
1022         //curr_buf->htc_flags |= HTC_FLAGS_RECV_END_MSG;
1023         /* enqueue this message to our pause queues */
1024         //HTC_EnqueuePausedRecv(pEndpoint,bufinfo,curr_buf);
1025     } else {           
1026         /* pass the message to the service */
1027         pEndpoint->pService->ProcessRecvMsg(eid, buffer, pEndpoint->pService->ServiceCtx);
1028     }                           
1029 #else
1030     pEndpoint->pService->ProcessRecvMsg(eid, hdr_buf, buffer, pEndpoint->pService->ServiceCtx);
1031 #endif
1032
1033     /* Calls to HTC_ReturnBuffers drives the endpoint credit reporting state machine. 
1034     * We do not want to delay credits for too long in the event that the application is 
1035     * holding onto buffers for excessive periods of time.  This gives us "some" better
1036     * opportunities to send up credits. */
1037     HTCCheckAndSendCreditReport(pHTC, eidMask, pEndpoint, eid); 
1038 }