|
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 } |