]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/staging/westbridge/astoria/api/src/cyasusb.c
Merge branch 'fix/asoc' into for-linus
[mirror_ubuntu-zesty-kernel.git] / drivers / staging / westbridge / astoria / api / src / cyasusb.c
1 /* Cypress West Bridge API source file (cyasusb.c)
2 ## ===========================
3 ## Copyright (C) 2010 Cypress Semiconductor
4 ##
5 ## This program is free software; you can redistribute it and/or
6 ## modify it under the terms of the GNU General Public License
7 ## as published by the Free Software Foundation; either version 2
8 ## of the License, or (at your option) any later version.
9 ##
10 ## This program is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ## GNU General Public License for more details.
14 ##
15 ## You should have received a copy of the GNU General Public License
16 ## along with this program; if not, write to the Free Software
17 ## Foundation, Inc., 51 Franklin Street, Fifth Floor
18 ## Boston, MA 02110-1301, USA.
19 ## ===========================
20 */
21
22 #include "../../include/linux/westbridge/cyashal.h"
23 #include "../../include/linux/westbridge/cyasusb.h"
24 #include "../../include/linux/westbridge/cyaserr.h"
25 #include "../../include/linux/westbridge/cyasdma.h"
26 #include "../../include/linux/westbridge/cyaslowlevel.h"
27 #include "../../include/linux/westbridge/cyaslep2pep.h"
28 #include "../../include/linux/westbridge/cyasregs.h"
29 #include "../../include/linux/westbridge/cyasstorage.h"
30
31 static cy_as_return_status_t
32 cy_as_usb_ack_setup_packet(
33 /* Handle to the West Bridge device */
34 cy_as_device_handle handle,
35 /* The callback if async call */
36 cy_as_function_callback cb,
37 /* Client supplied data */
38 uint32_t client
39 );
40
41 static void
42 cy_as_usb_func_callback(
43 cy_as_device *dev_p,
44 uint8_t context,
45 cy_as_ll_request_response *rqt,
46 cy_as_ll_request_response *resp,
47 cy_as_return_status_t ret);
48 /*
49 * Reset the USB EP0 state
50 */
51 static void
52 cy_as_usb_reset_e_p0_state(cy_as_device *dev_p)
53 {
54 cy_as_log_debug_message(6, "cy_as_usb_reset_e_p0_state called");
55
56 cy_as_device_clear_ack_delayed(dev_p);
57 cy_as_device_clear_setup_packet(dev_p);
58 if (cy_as_device_is_usb_async_pending(dev_p, 0))
59 cy_as_usb_cancel_async((cy_as_device_handle)dev_p, 0);
60
61 dev_p->usb_pending_buffer = 0;
62 }
63
64 /*
65 * External function to map logical endpoints to physical endpoints
66 */
67 static cy_as_return_status_t
68 is_usb_active(cy_as_device *dev_p)
69 {
70 if (!cy_as_device_is_configured(dev_p))
71 return CY_AS_ERROR_NOT_CONFIGURED;
72
73 if (!cy_as_device_is_firmware_loaded(dev_p))
74 return CY_AS_ERROR_NO_FIRMWARE;
75
76 if (dev_p->usb_count == 0)
77 return CY_AS_ERROR_NOT_RUNNING;
78
79 if (cy_as_device_is_in_suspend_mode(dev_p))
80 return CY_AS_ERROR_IN_SUSPEND;
81
82 return CY_AS_ERROR_SUCCESS;
83 }
84
85 static void
86 usb_ack_callback(cy_as_device_handle h,
87 cy_as_return_status_t status,
88 uint32_t client,
89 cy_as_funct_c_b_type type,
90 void *data)
91 {
92 cy_as_device *dev_p = (cy_as_device *)h;
93
94 (void)client;
95 (void)status;
96 (void)data;
97
98 cy_as_hal_assert(type == CY_FUNCT_CB_NODATA);
99
100 if (dev_p->usb_pending_buffer) {
101 cy_as_usb_io_callback cb;
102
103 cb = dev_p->usb_cb[0];
104 dev_p->usb_cb[0] = 0;
105 cy_as_device_clear_usb_async_pending(dev_p, 0);
106 if (cb)
107 cb(h, 0, dev_p->usb_pending_size,
108 dev_p->usb_pending_buffer, dev_p->usb_error);
109
110 dev_p->usb_pending_buffer = 0;
111 }
112
113 cy_as_device_clear_setup_packet(dev_p);
114 }
115
116 static void
117 my_usb_request_callback_usb_event(cy_as_device *dev_p,
118 cy_as_ll_request_response *req_p)
119 {
120 uint16_t ev;
121 uint16_t val;
122 cy_as_device_handle h = (cy_as_device_handle)dev_p;
123
124 ev = cy_as_ll_request_response__get_word(req_p, 0);
125 switch (ev) {
126 case 0: /* Reserved */
127 cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
128 CY_AS_ERROR_INVALID_REQUEST, 0);
129 break;
130
131 case 1: /* Reserved */
132 cy_as_ll_send_status_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
133 CY_AS_ERROR_INVALID_REQUEST, 0);
134 break;
135
136 case 2: /* USB Suspend */
137 dev_p->usb_last_event = cy_as_event_usb_suspend;
138 if (dev_p->usb_event_cb_ms)
139 dev_p->usb_event_cb_ms(h, cy_as_event_usb_suspend, 0);
140 else if (dev_p->usb_event_cb)
141 dev_p->usb_event_cb(h, cy_as_event_usb_suspend, 0);
142 cy_as_ll_send_status_response(dev_p,
143 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
144 break;
145
146 case 3: /* USB Resume */
147 dev_p->usb_last_event = cy_as_event_usb_resume;
148 if (dev_p->usb_event_cb_ms)
149 dev_p->usb_event_cb_ms(h, cy_as_event_usb_resume, 0);
150 else if (dev_p->usb_event_cb)
151 dev_p->usb_event_cb(h, cy_as_event_usb_resume, 0);
152 cy_as_ll_send_status_response(dev_p,
153 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
154 break;
155
156 case 4: /* USB Reset */
157 /*
158 * if we get a USB reset, the USB host did not understand
159 * our response or we timed out for some reason. reset
160 * our internal state to be ready for another set of
161 * enumeration based requests.
162 */
163 if (cy_as_device_is_ack_delayed(dev_p))
164 cy_as_usb_reset_e_p0_state(dev_p);
165
166 dev_p->usb_last_event = cy_as_event_usb_reset;
167 if (dev_p->usb_event_cb_ms)
168 dev_p->usb_event_cb_ms(h, cy_as_event_usb_reset, 0);
169 else if (dev_p->usb_event_cb)
170 dev_p->usb_event_cb(h, cy_as_event_usb_reset, 0);
171
172 cy_as_ll_send_status_response(dev_p,
173 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
174 cy_as_device_clear_usb_high_speed(dev_p);
175 cy_as_usb_set_dma_sizes(dev_p);
176 dev_p->usb_max_tx_size = 0x40;
177 cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x40);
178 break;
179
180 case 5: /* USB Set Configuration */
181 /* The configuration to set */
182 val = cy_as_ll_request_response__get_word(req_p, 1);
183 dev_p->usb_last_event = cy_as_event_usb_set_config;
184 if (dev_p->usb_event_cb_ms)
185 dev_p->usb_event_cb_ms(h,
186 cy_as_event_usb_set_config, &val);
187 else if (dev_p->usb_event_cb)
188 dev_p->usb_event_cb(h,
189 cy_as_event_usb_set_config, &val);
190
191 cy_as_ll_send_status_response(dev_p,
192 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
193 break;
194
195 case 6: /* USB Speed change */
196 /* Connect speed */
197 val = cy_as_ll_request_response__get_word(req_p, 1);
198 dev_p->usb_last_event = cy_as_event_usb_speed_change;
199 if (dev_p->usb_event_cb_ms)
200 dev_p->usb_event_cb_ms(h,
201 cy_as_event_usb_speed_change, &val);
202 else if (dev_p->usb_event_cb)
203 dev_p->usb_event_cb(h,
204 cy_as_event_usb_speed_change, &val);
205
206 cy_as_ll_send_status_response(dev_p,
207 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
208 cy_as_device_set_usb_high_speed(dev_p);
209 cy_as_usb_set_dma_sizes(dev_p);
210 dev_p->usb_max_tx_size = 0x200;
211 cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x200);
212 break;
213
214 case 7: /* USB Clear Feature */
215 /* EP Number */
216 val = cy_as_ll_request_response__get_word(req_p, 1);
217 if (dev_p->usb_event_cb_ms)
218 dev_p->usb_event_cb_ms(h,
219 cy_as_event_usb_clear_feature, &val);
220 if (dev_p->usb_event_cb)
221 dev_p->usb_event_cb(h,
222 cy_as_event_usb_clear_feature, &val);
223
224 cy_as_ll_send_status_response(dev_p,
225 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
226 break;
227
228 default:
229 cy_as_hal_print_message("invalid event type\n");
230 cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
231 CY_RESP_USB_INVALID_EVENT, sizeof(ev), &ev);
232 break;
233 }
234 }
235
236 static void
237 my_usb_request_callback_usb_data(cy_as_device *dev_p,
238 cy_as_ll_request_response *req_p)
239 {
240 cy_as_end_point_number_t ep;
241 uint8_t type;
242 uint16_t len;
243 uint16_t val;
244 cy_as_device_handle h = (cy_as_device_handle)dev_p;
245
246 val = cy_as_ll_request_response__get_word(req_p, 0);
247 ep = (cy_as_end_point_number_t)((val >> 13) & 0x01);
248 len = (val & 0x1ff);
249
250 cy_as_hal_assert(len <= 64);
251 cy_as_ll_request_response__unpack(req_p,
252 1, len, dev_p->usb_ep_data);
253
254 type = (uint8_t)((val >> 14) & 0x03);
255 if (type == 0) {
256 if (cy_as_device_is_ack_delayed(dev_p)) {
257 /*
258 * A setup packet has arrived while we are
259 * processing a previous setup packet. reset
260 * our state with respect to EP0 to be ready
261 * to process the new packet.
262 */
263 cy_as_usb_reset_e_p0_state(dev_p);
264 }
265
266 if (len != 8)
267 cy_as_ll_send_status_response(dev_p,
268 CY_RQT_USB_RQT_CONTEXT,
269 CY_AS_ERROR_INVALID_REQUEST, 0);
270 else {
271 cy_as_device_clear_ep0_stalled(dev_p);
272 cy_as_device_set_setup_packet(dev_p);
273 cy_as_ll_send_status_response(dev_p,
274 CY_RQT_USB_RQT_CONTEXT,
275 CY_AS_ERROR_SUCCESS, 0);
276
277 if (dev_p->usb_event_cb_ms)
278 dev_p->usb_event_cb_ms(h,
279 cy_as_event_usb_setup_packet,
280 dev_p->usb_ep_data);
281 else
282 dev_p->usb_event_cb(h,
283 cy_as_event_usb_setup_packet,
284 dev_p->usb_ep_data);
285
286 if ((!cy_as_device_is_ack_delayed(dev_p)) &&
287 (!cy_as_device_is_ep0_stalled(dev_p)))
288 cy_as_usb_ack_setup_packet(h,
289 usb_ack_callback, 0);
290 }
291 } else if (type == 2) {
292 if (len != 0)
293 cy_as_ll_send_status_response(dev_p,
294 CY_RQT_USB_RQT_CONTEXT,
295 CY_AS_ERROR_INVALID_REQUEST, 0);
296 else {
297 if (dev_p->usb_event_cb_ms)
298 dev_p->usb_event_cb_ms(h,
299 cy_as_event_usb_status_packet, 0);
300 else
301 dev_p->usb_event_cb(h,
302 cy_as_event_usb_status_packet, 0);
303
304 cy_as_ll_send_status_response(dev_p,
305 CY_RQT_USB_RQT_CONTEXT,
306 CY_AS_ERROR_SUCCESS, 0);
307 }
308 } else if (type == 1) {
309 /*
310 * we need to hand the data associated with these
311 * endpoints to the DMA module.
312 */
313 cy_as_dma_received_data(dev_p, ep, len, dev_p->usb_ep_data);
314 cy_as_ll_send_status_response(dev_p,
315 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
316 }
317 }
318
319 static void
320 my_usb_request_callback_inquiry(cy_as_device *dev_p,
321 cy_as_ll_request_response *req_p)
322 {
323 cy_as_usb_inquiry_data_dep cbdata;
324 cy_as_usb_inquiry_data cbdata_ms;
325 void *data;
326 uint16_t val;
327 cy_as_device_handle h = (cy_as_device_handle)dev_p;
328 uint8_t def_inq_data[64];
329 uint8_t evpd;
330 uint8_t codepage;
331 cy_bool updated;
332 uint16_t length;
333
334 cy_as_bus_number_t bus;
335 uint32_t device;
336 cy_as_media_type media;
337
338 val = cy_as_ll_request_response__get_word(req_p, 0);
339 bus = cy_as_storage_get_bus_from_address(val);
340 device = cy_as_storage_get_device_from_address(val);
341 media = cy_as_storage_get_media_from_address(val);
342
343 val = cy_as_ll_request_response__get_word(req_p, 1);
344 evpd = (uint8_t)((val >> 8) & 0x01);
345 codepage = (uint8_t)(val & 0xff);
346
347 length = cy_as_ll_request_response__get_word(req_p, 2);
348 data = (void *)def_inq_data;
349
350 updated = cy_false;
351
352 if (dev_p->usb_event_cb_ms) {
353 cbdata_ms.bus = bus;
354 cbdata_ms.device = device;
355 cbdata_ms.updated = updated;
356 cbdata_ms.evpd = evpd;
357 cbdata_ms.codepage = codepage;
358 cbdata_ms.length = length;
359 cbdata_ms.data = data;
360
361 cy_as_hal_assert(cbdata_ms.length <= sizeof(def_inq_data));
362 cy_as_ll_request_response__unpack(req_p,
363 3, cbdata_ms.length, cbdata_ms.data);
364
365 dev_p->usb_event_cb_ms(h,
366 cy_as_event_usb_inquiry_before, &cbdata_ms);
367
368 updated = cbdata_ms.updated;
369 data = cbdata_ms.data;
370 length = cbdata_ms.length;
371 } else if (dev_p->usb_event_cb) {
372 cbdata.media = media;
373 cbdata.updated = updated;
374 cbdata.evpd = evpd;
375 cbdata.codepage = codepage;
376 cbdata.length = length;
377 cbdata.data = data;
378
379 cy_as_hal_assert(cbdata.length <=
380 sizeof(def_inq_data));
381 cy_as_ll_request_response__unpack(req_p, 3,
382 cbdata.length, cbdata.data);
383
384 dev_p->usb_event_cb(h,
385 cy_as_event_usb_inquiry_before, &cbdata);
386
387 updated = cbdata.updated;
388 data = cbdata.data;
389 length = cbdata.length;
390 }
391
392 if (updated && length > 192)
393 cy_as_hal_print_message("an inquiry result from a "
394 "cy_as_event_usb_inquiry_before event "
395 "was greater than 192 bytes.");
396
397 /* Now send the reply with the data back
398 * to the West Bridge device */
399 if (updated && length <= 192) {
400 /*
401 * the callback function modified the inquiry
402 * data, ship the data back to the west bridge firmware.
403 */
404 cy_as_ll_send_data_response(dev_p,
405 CY_RQT_USB_RQT_CONTEXT,
406 CY_RESP_INQUIRY_DATA, length, data);
407 } else {
408 /*
409 * the callback did not modify the data, just acknowledge
410 * that we processed the request
411 */
412 cy_as_ll_send_status_response(dev_p,
413 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1);
414 }
415
416 if (dev_p->usb_event_cb_ms)
417 dev_p->usb_event_cb_ms(h,
418 cy_as_event_usb_inquiry_after, &cbdata_ms);
419 else if (dev_p->usb_event_cb)
420 dev_p->usb_event_cb(h,
421 cy_as_event_usb_inquiry_after, &cbdata);
422 }
423
424 static void
425 my_usb_request_callback_start_stop(cy_as_device *dev_p,
426 cy_as_ll_request_response *req_p)
427 {
428 cy_as_bus_number_t bus;
429 cy_as_media_type media;
430 uint32_t device;
431 uint16_t val;
432
433 if (dev_p->usb_event_cb_ms || dev_p->usb_event_cb) {
434 cy_bool loej;
435 cy_bool start;
436 cy_as_device_handle h = (cy_as_device_handle)dev_p;
437
438 val = cy_as_ll_request_response__get_word(req_p, 0);
439 bus = cy_as_storage_get_bus_from_address(val);
440 device = cy_as_storage_get_device_from_address(val);
441 media = cy_as_storage_get_media_from_address(val);
442
443 val = cy_as_ll_request_response__get_word(req_p, 1);
444 loej = (val & 0x02) ? cy_true : cy_false;
445 start = (val & 0x01) ? cy_true : cy_false;
446
447 if (dev_p->usb_event_cb_ms) {
448 cy_as_usb_start_stop_data cbdata_ms;
449
450 cbdata_ms.bus = bus;
451 cbdata_ms.device = device;
452 cbdata_ms.loej = loej;
453 cbdata_ms.start = start;
454 dev_p->usb_event_cb_ms(h,
455 cy_as_event_usb_start_stop, &cbdata_ms);
456
457 } else if (dev_p->usb_event_cb) {
458 cy_as_usb_start_stop_data_dep cbdata;
459
460 cbdata.media = media;
461 cbdata.loej = loej;
462 cbdata.start = start;
463 dev_p->usb_event_cb(h,
464 cy_as_event_usb_start_stop, &cbdata);
465 }
466 }
467 cy_as_ll_send_status_response(dev_p,
468 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 1);
469 }
470
471 static void
472 my_usb_request_callback_uknown_c_b_w(cy_as_device *dev_p,
473 cy_as_ll_request_response *req_p)
474 {
475 uint16_t val;
476 cy_as_device_handle h = (cy_as_device_handle)dev_p;
477 uint8_t buf[16];
478
479 uint8_t response[4];
480 uint16_t reqlen;
481 void *request;
482 uint8_t status;
483 uint8_t key;
484 uint8_t asc;
485 uint8_t ascq;
486
487 val = cy_as_ll_request_response__get_word(req_p, 0);
488 /* Failed by default */
489 status = 1;
490 /* Invalid command */
491 key = 0x05;
492 /* Invalid command */
493 asc = 0x20;
494 /* Invalid command */
495 ascq = 0x00;
496 reqlen = cy_as_ll_request_response__get_word(req_p, 1);
497 request = buf;
498
499 cy_as_hal_assert(reqlen <= sizeof(buf));
500 cy_as_ll_request_response__unpack(req_p, 2, reqlen, request);
501
502 if (dev_p->usb_event_cb_ms) {
503 cy_as_usb_unknown_command_data cbdata_ms;
504 cbdata_ms.bus = cy_as_storage_get_bus_from_address(val);
505 cbdata_ms.device =
506 cy_as_storage_get_device_from_address(val);
507 cbdata_ms.reqlen = reqlen;
508 cbdata_ms.request = request;
509 cbdata_ms.status = status;
510 cbdata_ms.key = key;
511 cbdata_ms.asc = asc;
512 cbdata_ms.ascq = ascq;
513
514 dev_p->usb_event_cb_ms(h,
515 cy_as_event_usb_unknown_storage, &cbdata_ms);
516 status = cbdata_ms.status;
517 key = cbdata_ms.key;
518 asc = cbdata_ms.asc;
519 ascq = cbdata_ms.ascq;
520 } else if (dev_p->usb_event_cb) {
521 cy_as_usb_unknown_command_data_dep cbdata;
522 cbdata.media =
523 cy_as_storage_get_media_from_address(val);
524 cbdata.reqlen = reqlen;
525 cbdata.request = request;
526 cbdata.status = status;
527 cbdata.key = key;
528 cbdata.asc = asc;
529 cbdata.ascq = ascq;
530
531 dev_p->usb_event_cb(h,
532 cy_as_event_usb_unknown_storage, &cbdata);
533 status = cbdata.status;
534 key = cbdata.key;
535 asc = cbdata.asc;
536 ascq = cbdata.ascq;
537 }
538
539 response[0] = status;
540 response[1] = key;
541 response[2] = asc;
542 response[3] = ascq;
543 cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
544 CY_RESP_UNKNOWN_SCSI_COMMAND, sizeof(response), response);
545 }
546
547 static void
548 my_usb_request_callback_m_s_c_progress(cy_as_device *dev_p,
549 cy_as_ll_request_response *req_p)
550 {
551 uint16_t val1, val2;
552 cy_as_device_handle h = (cy_as_device_handle)dev_p;
553
554 if ((dev_p->usb_event_cb) || (dev_p->usb_event_cb_ms)) {
555 cy_as_m_s_c_progress_data cbdata;
556
557 val1 = cy_as_ll_request_response__get_word(req_p, 0);
558 val2 = cy_as_ll_request_response__get_word(req_p, 1);
559 cbdata.wr_count = (uint32_t)((val1 << 16) | val2);
560
561 val1 = cy_as_ll_request_response__get_word(req_p, 2);
562 val2 = cy_as_ll_request_response__get_word(req_p, 3);
563 cbdata.rd_count = (uint32_t)((val1 << 16) | val2);
564
565 if (dev_p->usb_event_cb)
566 dev_p->usb_event_cb(h,
567 cy_as_event_usb_m_s_c_progress, &cbdata);
568 else
569 dev_p->usb_event_cb_ms(h,
570 cy_as_event_usb_m_s_c_progress, &cbdata);
571 }
572
573 cy_as_ll_send_status_response(dev_p,
574 CY_RQT_USB_RQT_CONTEXT, CY_AS_ERROR_SUCCESS, 0);
575 }
576
577 /*
578 * This function processes the requests delivered from the
579 * firmware within the West Bridge device that are delivered
580 * in the USB context. These requests generally are EP0 and
581 * EP1 related requests or USB events.
582 */
583 static void
584 my_usb_request_callback(cy_as_device *dev_p, uint8_t context,
585 cy_as_ll_request_response *req_p,
586 cy_as_ll_request_response *resp_p,
587 cy_as_return_status_t ret)
588 {
589 uint16_t val;
590 uint8_t code = cy_as_ll_request_response__get_code(req_p);
591
592 (void)resp_p;
593 (void)context;
594 (void)ret;
595
596 switch (code) {
597 case CY_RQT_USB_EVENT:
598 my_usb_request_callback_usb_event(dev_p, req_p);
599 break;
600
601 case CY_RQT_USB_EP_DATA:
602 dev_p->usb_last_event = cy_as_event_usb_setup_packet;
603 my_usb_request_callback_usb_data(dev_p, req_p);
604 break;
605
606 case CY_RQT_SCSI_INQUIRY_COMMAND:
607 dev_p->usb_last_event = cy_as_event_usb_inquiry_after;
608 my_usb_request_callback_inquiry(dev_p, req_p);
609 break;
610
611 case CY_RQT_SCSI_START_STOP_COMMAND:
612 dev_p->usb_last_event = cy_as_event_usb_start_stop;
613 my_usb_request_callback_start_stop(dev_p, req_p);
614 break;
615
616 case CY_RQT_SCSI_UNKNOWN_COMMAND:
617 dev_p->usb_last_event = cy_as_event_usb_unknown_storage;
618 my_usb_request_callback_uknown_c_b_w(dev_p, req_p);
619 break;
620
621 case CY_RQT_USB_ACTIVITY_UPDATE:
622 dev_p->usb_last_event = cy_as_event_usb_m_s_c_progress;
623 my_usb_request_callback_m_s_c_progress(dev_p, req_p);
624 break;
625
626 default:
627 cy_as_hal_print_message("invalid request "
628 "received on USB context\n");
629 val = req_p->box0;
630 cy_as_ll_send_data_response(dev_p, CY_RQT_USB_RQT_CONTEXT,
631 CY_RESP_INVALID_REQUEST, sizeof(val), &val);
632 break;
633 }
634 }
635
636 static cy_as_return_status_t
637 my_handle_response_usb_start(cy_as_device *dev_p,
638 cy_as_ll_request_response *req_p,
639 cy_as_ll_request_response *reply_p,
640 cy_as_return_status_t ret)
641 {
642 if (ret != CY_AS_ERROR_SUCCESS)
643 goto destroy;
644
645 if (cy_as_ll_request_response__get_code(reply_p) !=
646 CY_RESP_SUCCESS_FAILURE) {
647 ret = CY_AS_ERROR_INVALID_RESPONSE;
648 goto destroy;
649 }
650
651 ret = cy_as_ll_request_response__get_word(reply_p, 0);
652 if (ret != CY_AS_ERROR_SUCCESS)
653 goto destroy;
654
655 /*
656 * mark EP 0 and EP1 as 64 byte endpoints
657 */
658 cy_as_dma_set_max_dma_size(dev_p, 0, 64);
659 cy_as_dma_set_max_dma_size(dev_p, 1, 64);
660
661 dev_p->usb_count++;
662
663 destroy:
664 cy_as_ll_destroy_request(dev_p, req_p);
665 cy_as_ll_destroy_response(dev_p, reply_p);
666
667 if (ret != CY_AS_ERROR_SUCCESS) {
668 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
669 cy_as_ll_register_request_callback(dev_p,
670 CY_RQT_USB_RQT_CONTEXT, 0);
671 }
672
673 cy_as_device_clear_u_s_s_pending(dev_p);
674
675 return ret;
676
677 }
678
679 /*
680 * This function starts the USB stack. The stack is reference
681 * counted so if the stack is already started, this function
682 * just increments the count. If the stack has not been started,
683 * a start request is sent to the West Bridge device.
684 *
685 * Note: Starting the USB stack does not cause the USB signals
686 * to be connected to the USB pins. To do this and therefore
687 * initiate enumeration, CyAsUsbConnect() must be called.
688 */
689 cy_as_return_status_t
690 cy_as_usb_start(cy_as_device_handle handle,
691 cy_as_function_callback cb,
692 uint32_t client)
693 {
694 cy_as_ll_request_response *req_p, *reply_p;
695 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
696
697 cy_as_device *dev_p;
698
699 cy_as_log_debug_message(6, "cy_as_usb_start called");
700
701 dev_p = (cy_as_device *)handle;
702 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
703 return CY_AS_ERROR_INVALID_HANDLE;
704
705 if (!cy_as_device_is_configured(dev_p))
706 return CY_AS_ERROR_NOT_CONFIGURED;
707
708 if (!cy_as_device_is_firmware_loaded(dev_p))
709 return CY_AS_ERROR_NO_FIRMWARE;
710
711 if (cy_as_device_is_in_suspend_mode(dev_p))
712 return CY_AS_ERROR_IN_SUSPEND;
713
714 if (cy_as_device_is_in_callback(dev_p))
715 return CY_AS_ERROR_INVALID_IN_CALLBACK;
716
717 if (cy_as_device_is_u_s_s_pending(dev_p))
718 return CY_AS_ERROR_STARTSTOP_PENDING;
719
720 cy_as_device_set_u_s_s_pending(dev_p);
721
722 if (dev_p->usb_count == 0) {
723 /*
724 * since we are just starting the stack,
725 * mark USB as not connected to the remote host
726 */
727 cy_as_device_clear_usb_connected(dev_p);
728 dev_p->usb_phy_config = 0;
729
730 /* Queue for 1.0 Async Requests, kept for
731 * backwards compatibility */
732 dev_p->usb_func_cbs = cy_as_create_c_b_queue(CYAS_USB_FUNC_CB);
733 if (dev_p->usb_func_cbs == 0) {
734 cy_as_device_clear_u_s_s_pending(dev_p);
735 return CY_AS_ERROR_OUT_OF_MEMORY;
736 }
737
738 /* Reset the EP0 state */
739 cy_as_usb_reset_e_p0_state(dev_p);
740
741 /*
742 * we register here becuase the start request may cause
743 * events to occur before the response to the start request.
744 */
745 cy_as_ll_register_request_callback(dev_p,
746 CY_RQT_USB_RQT_CONTEXT, my_usb_request_callback);
747
748 /* Create the request to send to the West Bridge device */
749 req_p = cy_as_ll_create_request(dev_p,
750 CY_RQT_START_USB, CY_RQT_USB_RQT_CONTEXT, 0);
751 if (req_p == 0) {
752 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
753 dev_p->usb_func_cbs = 0;
754 cy_as_device_clear_u_s_s_pending(dev_p);
755 return CY_AS_ERROR_OUT_OF_MEMORY;
756 }
757
758 /* Reserve space for the reply, the reply data
759 * will not exceed one word */
760 reply_p = cy_as_ll_create_response(dev_p, 1);
761 if (reply_p == 0) {
762 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
763 dev_p->usb_func_cbs = 0;
764 cy_as_ll_destroy_request(dev_p, req_p);
765 cy_as_device_clear_u_s_s_pending(dev_p);
766 return CY_AS_ERROR_OUT_OF_MEMORY;
767 }
768
769 if (cb == 0) {
770 ret = cy_as_ll_send_request_wait_reply(dev_p,
771 req_p, reply_p);
772 if (ret != CY_AS_ERROR_SUCCESS)
773 goto destroy;
774
775 return my_handle_response_usb_start(dev_p,
776 req_p, reply_p, ret);
777 } else {
778 ret = cy_as_misc_send_request(dev_p, cb,
779 client, CY_FUNCT_CB_USB_START, 0,
780 dev_p->func_cbs_usb,
781 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
782 cy_as_usb_func_callback);
783
784 if (ret != CY_AS_ERROR_SUCCESS)
785 goto destroy;
786
787 return ret;
788 }
789
790 destroy:
791 cy_as_ll_destroy_request(dev_p, req_p);
792 cy_as_ll_destroy_response(dev_p, reply_p);
793 } else {
794 dev_p->usb_count++;
795 if (cb)
796 cb(handle, ret, client, CY_FUNCT_CB_USB_START, 0);
797 }
798
799 cy_as_device_clear_u_s_s_pending(dev_p);
800
801 return ret;
802 }
803
804 void
805 cy_as_usb_reset(cy_as_device *dev_p)
806 {
807 int i;
808
809 cy_as_device_clear_usb_connected(dev_p);
810
811 for (i = 0; i < sizeof(dev_p->usb_config) /
812 sizeof(dev_p->usb_config[0]); i++) {
813 /*
814 * cancel all pending USB read/write operations, as it is
815 * possible that the USB stack comes up in a different
816 * configuration with a different set of endpoints.
817 */
818 if (cy_as_device_is_usb_async_pending(dev_p, i))
819 cy_as_usb_cancel_async(dev_p,
820 (cy_as_end_point_number_t)i);
821
822 dev_p->usb_cb[i] = 0;
823 dev_p->usb_config[i].enabled = cy_false;
824 }
825
826 dev_p->usb_phy_config = 0;
827 }
828
829 /*
830 * This function does all the API side clean-up associated
831 * with CyAsUsbStop, without any communication with firmware.
832 * This needs to be done when the device is being reset while
833 * the USB stack is active.
834 */
835 void
836 cy_as_usb_cleanup(cy_as_device *dev_p)
837 {
838 if (dev_p->usb_count) {
839 cy_as_usb_reset_e_p0_state(dev_p);
840 cy_as_usb_reset(dev_p);
841 cy_as_hal_mem_set(dev_p->usb_config, 0,
842 sizeof(dev_p->usb_config));
843 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
844
845 dev_p->usb_count = 0;
846 }
847 }
848
849 static cy_as_return_status_t
850 my_handle_response_usb_stop(cy_as_device *dev_p,
851 cy_as_ll_request_response *req_p,
852 cy_as_ll_request_response *reply_p,
853 cy_as_return_status_t ret)
854 {
855 if (ret != CY_AS_ERROR_SUCCESS)
856 goto destroy;
857
858 if (cy_as_ll_request_response__get_code(reply_p) !=
859 CY_RESP_SUCCESS_FAILURE) {
860 ret = CY_AS_ERROR_INVALID_RESPONSE;
861 goto destroy;
862 }
863
864 ret = cy_as_ll_request_response__get_word(reply_p, 0);
865 if (ret != CY_AS_ERROR_SUCCESS)
866 goto destroy;
867
868 /*
869 * we sucessfully shutdown the stack, so
870 * decrement to make the count zero.
871 */
872 cy_as_usb_cleanup(dev_p);
873
874 destroy:
875 cy_as_ll_destroy_request(dev_p, req_p);
876 cy_as_ll_destroy_response(dev_p, reply_p);
877
878 if (ret != CY_AS_ERROR_SUCCESS)
879 cy_as_ll_register_request_callback(dev_p,
880 CY_RQT_USB_RQT_CONTEXT, 0);
881
882 cy_as_device_clear_u_s_s_pending(dev_p);
883
884 return ret;
885 }
886
887 /*
888 * This function stops the USB stack. The USB stack is reference
889 * counted so first is reference count is decremented. If the
890 * reference count is then zero, a request is sent to the West
891 * Bridge device to stop the USB stack on the West Bridge device.
892 */
893 cy_as_return_status_t
894 cy_as_usb_stop(cy_as_device_handle handle,
895 cy_as_function_callback cb,
896 uint32_t client)
897 {
898 cy_as_ll_request_response *req_p = 0, *reply_p = 0;
899 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
900
901 cy_as_device *dev_p;
902
903 cy_as_log_debug_message(6, "cy_as_usb_stop called");
904
905 dev_p = (cy_as_device *)handle;
906 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
907 return CY_AS_ERROR_INVALID_HANDLE;
908
909 ret = is_usb_active(dev_p);
910 if (ret != CY_AS_ERROR_SUCCESS)
911 return ret;
912
913 if (cy_as_device_is_usb_connected(dev_p))
914 return CY_AS_ERROR_USB_CONNECTED;
915
916 if (cy_as_device_is_in_callback(dev_p))
917 return CY_AS_ERROR_INVALID_IN_CALLBACK;
918
919 if (cy_as_device_is_u_s_s_pending(dev_p))
920 return CY_AS_ERROR_STARTSTOP_PENDING;
921
922 cy_as_device_set_u_s_s_pending(dev_p);
923
924 if (dev_p->usb_count == 1) {
925 /* Create the request to send to the West Bridge device */
926 req_p = cy_as_ll_create_request(dev_p, CY_RQT_STOP_USB,
927 CY_RQT_USB_RQT_CONTEXT, 0);
928 if (req_p == 0) {
929 ret = CY_AS_ERROR_OUT_OF_MEMORY;
930 goto destroy;
931 }
932
933 /* Reserve space for the reply, the reply data will not
934 * exceed one word */
935 reply_p = cy_as_ll_create_response(dev_p, 1);
936 if (reply_p == 0) {
937 ret = CY_AS_ERROR_OUT_OF_MEMORY;
938 goto destroy;
939 }
940
941 if (cb == 0) {
942 ret = cy_as_ll_send_request_wait_reply(dev_p,
943 req_p, reply_p);
944 if (ret != CY_AS_ERROR_SUCCESS)
945 goto destroy;
946
947 return my_handle_response_usb_stop(dev_p,
948 req_p, reply_p, ret);
949 } else {
950 ret = cy_as_misc_send_request(dev_p, cb, client,
951 CY_FUNCT_CB_USB_STOP, 0, dev_p->func_cbs_usb,
952 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
953 cy_as_usb_func_callback);
954
955 if (ret != CY_AS_ERROR_SUCCESS)
956 goto destroy;
957
958 return ret;
959 }
960
961 destroy:
962 cy_as_ll_destroy_request(dev_p, req_p);
963 cy_as_ll_destroy_response(dev_p, reply_p);
964 } else if (dev_p->usb_count > 1) {
965 /*
966 * reset all LE_ps to inactive state, after cleaning
967 * up any pending async read/write calls.
968 */
969 cy_as_usb_reset(dev_p);
970 dev_p->usb_count--;
971
972 if (cb)
973 cb(handle, ret, client, CY_FUNCT_CB_USB_STOP, 0);
974 }
975
976 cy_as_device_clear_u_s_s_pending(dev_p);
977
978 return ret;
979 }
980
981 /*
982 * This function registers a callback to be called when
983 * USB events are processed
984 */
985 cy_as_return_status_t
986 cy_as_usb_register_callback(cy_as_device_handle handle,
987 cy_as_usb_event_callback callback)
988 {
989 cy_as_device *dev_p;
990
991 cy_as_log_debug_message(6, "cy_as_usb_register_callback called");
992
993 dev_p = (cy_as_device *)handle;
994 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
995 return CY_AS_ERROR_INVALID_HANDLE;
996
997 if (!cy_as_device_is_configured(dev_p))
998 return CY_AS_ERROR_NOT_CONFIGURED;
999
1000 if (!cy_as_device_is_firmware_loaded(dev_p))
1001 return CY_AS_ERROR_NO_FIRMWARE;
1002
1003 dev_p->usb_event_cb = NULL;
1004 dev_p->usb_event_cb_ms = callback;
1005 return CY_AS_ERROR_SUCCESS;
1006 }
1007
1008
1009 static cy_as_return_status_t
1010 my_handle_response_no_data(cy_as_device *dev_p,
1011 cy_as_ll_request_response *req_p,
1012 cy_as_ll_request_response *reply_p)
1013 {
1014 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1015
1016 if (cy_as_ll_request_response__get_code(reply_p) !=
1017 CY_RESP_SUCCESS_FAILURE)
1018 ret = CY_AS_ERROR_INVALID_RESPONSE;
1019 else
1020 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1021
1022 cy_as_ll_destroy_request(dev_p, req_p);
1023 cy_as_ll_destroy_response(dev_p, reply_p);
1024
1025 return ret;
1026 }
1027
1028 static cy_as_return_status_t
1029 my_handle_response_connect(cy_as_device *dev_p,
1030 cy_as_ll_request_response *req_p,
1031 cy_as_ll_request_response *reply_p,
1032 cy_as_return_status_t ret)
1033 {
1034 if (ret != CY_AS_ERROR_SUCCESS)
1035 goto destroy;
1036
1037 if (cy_as_ll_request_response__get_code(reply_p) !=
1038 CY_RESP_SUCCESS_FAILURE) {
1039 ret = CY_AS_ERROR_INVALID_RESPONSE;
1040 goto destroy;
1041 }
1042
1043 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1044 if (ret == CY_AS_ERROR_SUCCESS)
1045 cy_as_device_set_usb_connected(dev_p);
1046
1047 destroy:
1048 cy_as_ll_destroy_request(dev_p, req_p);
1049 cy_as_ll_destroy_response(dev_p, reply_p);
1050
1051 return ret;
1052 }
1053
1054
1055 /*
1056 * This method asks the West Bridge device to connect the
1057 * internal USB D+ and D- signals to the USB pins, thus
1058 * starting the enumeration processes if the external pins
1059 * are connnected to a USB host. If the external pins are
1060 * not connect to a USB host, enumeration will begin as soon
1061 * as the USB pins are connected to a host.
1062 */
1063 cy_as_return_status_t
1064 cy_as_usb_connect(cy_as_device_handle handle,
1065 cy_as_function_callback cb,
1066 uint32_t client)
1067 {
1068 cy_as_ll_request_response *req_p , *reply_p;
1069 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1070
1071 cy_as_device *dev_p;
1072
1073 cy_as_log_debug_message(6, "cy_as_usb_connect called");
1074
1075 dev_p = (cy_as_device *)handle;
1076 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1077 return CY_AS_ERROR_INVALID_HANDLE;
1078
1079 ret = is_usb_active(dev_p);
1080 if (ret != CY_AS_ERROR_SUCCESS)
1081 return ret;
1082
1083 if (cy_as_device_is_in_callback(dev_p))
1084 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1085
1086 /* Create the request to send to the West Bridge device */
1087 req_p = cy_as_ll_create_request(dev_p,
1088 CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1);
1089 if (req_p == 0)
1090 return CY_AS_ERROR_OUT_OF_MEMORY;
1091
1092 /* 1 = Connect request */
1093 cy_as_ll_request_response__set_word(req_p, 0, 1);
1094
1095 /* Reserve space for the reply, the reply
1096 * data will not exceed one word */
1097 reply_p = cy_as_ll_create_response(dev_p, 1);
1098 if (reply_p == 0) {
1099 cy_as_ll_destroy_request(dev_p, req_p);
1100 return CY_AS_ERROR_OUT_OF_MEMORY;
1101 }
1102
1103 if (cb == 0) {
1104 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1105 if (ret != CY_AS_ERROR_SUCCESS)
1106 goto destroy;
1107
1108 return my_handle_response_connect(dev_p, req_p, reply_p, ret);
1109 } else {
1110 ret = cy_as_misc_send_request(dev_p, cb, client,
1111 CY_FUNCT_CB_USB_CONNECT, 0, dev_p->func_cbs_usb,
1112 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1113 cy_as_usb_func_callback);
1114
1115 if (ret != CY_AS_ERROR_SUCCESS)
1116 goto destroy;
1117
1118 return ret;
1119 }
1120
1121 destroy:
1122 cy_as_ll_destroy_request(dev_p, req_p);
1123 cy_as_ll_destroy_response(dev_p, reply_p);
1124
1125 return ret;
1126 }
1127
1128 static cy_as_return_status_t
1129 my_handle_response_disconnect(cy_as_device *dev_p,
1130 cy_as_ll_request_response *req_p,
1131 cy_as_ll_request_response *reply_p,
1132 cy_as_return_status_t ret)
1133 {
1134 if (ret != CY_AS_ERROR_SUCCESS)
1135 goto destroy;
1136
1137 if (cy_as_ll_request_response__get_code(reply_p) !=
1138 CY_RESP_SUCCESS_FAILURE) {
1139 ret = CY_AS_ERROR_INVALID_RESPONSE;
1140 goto destroy;
1141 }
1142
1143 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1144 if (ret == CY_AS_ERROR_SUCCESS)
1145 cy_as_device_clear_usb_connected(dev_p);
1146
1147 destroy:
1148 cy_as_ll_destroy_request(dev_p, req_p);
1149 cy_as_ll_destroy_response(dev_p, reply_p);
1150
1151 return ret;
1152 }
1153 /*
1154 * This method forces a disconnect of the D+ and D- pins
1155 * external to the West Bridge device from the D+ and D-
1156 * signals internally, effectively disconnecting the West
1157 * Bridge device from any connected USB host.
1158 */
1159 cy_as_return_status_t
1160 cy_as_usb_disconnect(cy_as_device_handle handle,
1161 cy_as_function_callback cb,
1162 uint32_t client)
1163 {
1164 cy_as_ll_request_response *req_p , *reply_p;
1165 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1166
1167 cy_as_device *dev_p;
1168
1169 cy_as_log_debug_message(6, "cy_as_usb_disconnect called");
1170
1171 dev_p = (cy_as_device *)handle;
1172 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1173 return CY_AS_ERROR_INVALID_HANDLE;
1174
1175 ret = is_usb_active(dev_p);
1176 if (ret != CY_AS_ERROR_SUCCESS)
1177 return ret;
1178
1179 if (cy_as_device_is_in_callback(dev_p))
1180 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1181
1182 if (!cy_as_device_is_usb_connected(dev_p))
1183 return CY_AS_ERROR_USB_NOT_CONNECTED;
1184
1185 /* Create the request to send to the West Bridge device */
1186 req_p = cy_as_ll_create_request(dev_p,
1187 CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1);
1188 if (req_p == 0)
1189 return CY_AS_ERROR_OUT_OF_MEMORY;
1190
1191 cy_as_ll_request_response__set_word(req_p, 0, 0);
1192
1193 /* Reserve space for the reply, the reply
1194 * data will not exceed two bytes */
1195 reply_p = cy_as_ll_create_response(dev_p, 1);
1196 if (reply_p == 0) {
1197 cy_as_ll_destroy_request(dev_p, req_p);
1198 return CY_AS_ERROR_OUT_OF_MEMORY;
1199 }
1200
1201 if (cb == 0) {
1202 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1203 if (ret != CY_AS_ERROR_SUCCESS)
1204 goto destroy;
1205
1206 return my_handle_response_disconnect(dev_p,
1207 req_p, reply_p, ret);
1208 } else {
1209 ret = cy_as_misc_send_request(dev_p, cb, client,
1210 CY_FUNCT_CB_USB_DISCONNECT, 0, dev_p->func_cbs_usb,
1211 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1212 cy_as_usb_func_callback);
1213
1214 if (ret != CY_AS_ERROR_SUCCESS)
1215 goto destroy;
1216
1217 return ret;
1218 }
1219 destroy:
1220 cy_as_ll_destroy_request(dev_p, req_p);
1221 cy_as_ll_destroy_response(dev_p, reply_p);
1222
1223 return ret;
1224 }
1225
1226 static cy_as_return_status_t
1227 my_handle_response_set_enum_config(cy_as_device *dev_p,
1228 cy_as_ll_request_response *req_p,
1229 cy_as_ll_request_response *reply_p)
1230 {
1231 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1232
1233 if (cy_as_ll_request_response__get_code(reply_p) !=
1234 CY_RESP_SUCCESS_FAILURE) {
1235 ret = CY_AS_ERROR_INVALID_RESPONSE;
1236 goto destroy;
1237 }
1238
1239 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1240
1241 if (ret == CY_AS_ERROR_SUCCESS) {
1242 /*
1243 * we configured the west bridge device and
1244 * enumeration is going to happen on the P port
1245 * processor. now we must enable endpoint zero
1246 */
1247 cy_as_usb_end_point_config config;
1248
1249 config.dir = cy_as_usb_in_out;
1250 config.type = cy_as_usb_control;
1251 config.enabled = cy_true;
1252
1253 ret = cy_as_usb_set_end_point_config((cy_as_device_handle *)
1254 dev_p, 0, &config);
1255 }
1256
1257 destroy:
1258 cy_as_ll_destroy_request(dev_p, req_p);
1259 cy_as_ll_destroy_response(dev_p, reply_p);
1260
1261 return ret;
1262 }
1263
1264 /*
1265 * This method sets how the USB is enumerated and should
1266 * be called before the CyAsUsbConnect() is called.
1267 */
1268 static cy_as_return_status_t
1269 my_usb_set_enum_config(cy_as_device *dev_p,
1270 uint8_t bus_mask,
1271 uint8_t media_mask,
1272 cy_bool use_antioch_enumeration,
1273 uint8_t mass_storage_interface,
1274 uint8_t mtp_interface,
1275 cy_bool mass_storage_callbacks,
1276 cy_as_function_callback cb,
1277 uint32_t client)
1278 {
1279 cy_as_ll_request_response *req_p , *reply_p;
1280 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1281
1282 cy_as_log_debug_message(6, "cy_as_usb_set_enum_config called");
1283
1284 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1285 return CY_AS_ERROR_INVALID_HANDLE;
1286
1287 ret = is_usb_active(dev_p);
1288 if (ret != CY_AS_ERROR_SUCCESS)
1289 return ret;
1290
1291 if (cy_as_device_is_usb_connected(dev_p))
1292 return CY_AS_ERROR_USB_CONNECTED;
1293
1294 if (cy_as_device_is_in_callback(dev_p))
1295 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1296
1297 /* if we are using MTP firmware: */
1298 if (dev_p->is_mtp_firmware == 1) {
1299 /* we cannot enumerate MSC */
1300 if (mass_storage_interface != 0)
1301 return CY_AS_ERROR_INVALID_CONFIGURATION;
1302
1303 if (bus_mask == 0) {
1304 if (mtp_interface != 0)
1305 return CY_AS_ERROR_INVALID_CONFIGURATION;
1306 } else if (bus_mask == 2) {
1307 /* enable EP 1 as it will be used */
1308 cy_as_dma_enable_end_point(dev_p, 1, cy_true,
1309 cy_as_direction_in);
1310 dev_p->usb_config[1].enabled = cy_true;
1311 dev_p->usb_config[1].dir = cy_as_usb_in;
1312 dev_p->usb_config[1].type = cy_as_usb_int;
1313 } else {
1314 return CY_AS_ERROR_INVALID_CONFIGURATION;
1315 }
1316 /* if we are not using MTP firmware, we cannot enumerate MTP */
1317 } else if (mtp_interface != 0)
1318 return CY_AS_ERROR_INVALID_CONFIGURATION;
1319
1320 /*
1321 * if we are not enumerating mass storage, we should
1322 * not be providing an interface number.
1323 */
1324 if (bus_mask == 0 && mass_storage_interface != 0)
1325 return CY_AS_ERROR_INVALID_CONFIGURATION;
1326
1327 /*
1328 * if we are going to use mtp_interface, bus mask must be 2.
1329 */
1330 if (mtp_interface != 0 && bus_mask != 2)
1331 return CY_AS_ERROR_INVALID_CONFIGURATION;
1332
1333
1334 /* Create the request to send to the West Bridge device */
1335 req_p = cy_as_ll_create_request(dev_p,
1336 CY_RQT_SET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 4);
1337 if (req_p == 0)
1338 return CY_AS_ERROR_OUT_OF_MEMORY;
1339
1340 /* Marshal the structure */
1341 cy_as_ll_request_response__set_word(req_p, 0,
1342 (uint16_t)((media_mask << 8) | bus_mask));
1343 cy_as_ll_request_response__set_word(req_p, 1,
1344 (uint16_t)use_antioch_enumeration);
1345 cy_as_ll_request_response__set_word(req_p, 2,
1346 dev_p->is_mtp_firmware ? mtp_interface :
1347 mass_storage_interface);
1348 cy_as_ll_request_response__set_word(req_p, 3,
1349 (uint16_t)mass_storage_callbacks);
1350
1351 /* Reserve space for the reply, the reply
1352 * data will not exceed one word */
1353 reply_p = cy_as_ll_create_response(dev_p, 1);
1354 if (reply_p == 0) {
1355 cy_as_ll_destroy_request(dev_p, req_p);
1356 return CY_AS_ERROR_OUT_OF_MEMORY;
1357 }
1358
1359 if (cb == 0) {
1360
1361 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1362 if (ret != CY_AS_ERROR_SUCCESS)
1363 goto destroy;
1364
1365 return my_handle_response_set_enum_config(dev_p,
1366 req_p, reply_p);
1367 } else {
1368 ret = cy_as_misc_send_request(dev_p, cb, client,
1369 CY_FUNCT_CB_USB_SETENUMCONFIG, 0, dev_p->func_cbs_usb,
1370 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1371 cy_as_usb_func_callback);
1372
1373 if (ret != CY_AS_ERROR_SUCCESS)
1374 goto destroy;
1375
1376 return ret;
1377 }
1378
1379 destroy:
1380 cy_as_ll_destroy_request(dev_p, req_p);
1381 cy_as_ll_destroy_response(dev_p, reply_p);
1382
1383 return ret;
1384 }
1385
1386 /*
1387 * This method sets how the USB is enumerated and should
1388 * be called before the CyAsUsbConnect() is called.
1389 */
1390 cy_as_return_status_t
1391 cy_as_usb_set_enum_config(cy_as_device_handle handle,
1392 cy_as_usb_enum_control *config_p,
1393 cy_as_function_callback cb,
1394 uint32_t client)
1395 {
1396 cy_as_device *dev_p = (cy_as_device *)handle;
1397 uint8_t bus_mask, media_mask;
1398 uint32_t bus, device;
1399 cy_as_return_status_t ret;
1400
1401 dev_p = (cy_as_device *)handle;
1402 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1403 return CY_AS_ERROR_INVALID_HANDLE;
1404
1405 ret = is_usb_active(dev_p);
1406 if (ret != CY_AS_ERROR_SUCCESS)
1407 return ret;
1408
1409 if ((cy_as_device_is_in_callback(dev_p)) && (cb != 0))
1410 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1411
1412 /* Since we are mapping the media types to bus with NAND to 0
1413 * and the rest to 1, and we are only allowing for enumerating
1414 * all the devices on a bus we just scan the array for any
1415 * positions where there a device is enabled and mark the bus
1416 * to be enumerated.
1417 */
1418 bus_mask = 0;
1419 media_mask = 0;
1420 for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
1421 for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++) {
1422 if (config_p->devices_to_enumerate[bus][device] ==
1423 cy_true) {
1424 bus_mask |= (0x01 << bus);
1425 media_mask |= dev_p->media_supported[bus];
1426 media_mask |= dev_p->media_supported[bus];
1427 }
1428 }
1429 }
1430
1431 return my_usb_set_enum_config(dev_p, bus_mask, media_mask,
1432 config_p->antioch_enumeration,
1433 config_p->mass_storage_interface,
1434 config_p->mtp_interface,
1435 config_p->mass_storage_callbacks,
1436 cb,
1437 client
1438 );
1439 }
1440
1441
1442 static cy_as_return_status_t
1443 my_handle_response_get_enum_config(cy_as_device *dev_p,
1444 cy_as_ll_request_response *req_p,
1445 cy_as_ll_request_response *reply_p,
1446 void *config_p)
1447 {
1448 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1449 uint16_t val;
1450 uint8_t bus_mask;
1451 uint32_t bus;
1452
1453 if (cy_as_ll_request_response__get_code(reply_p) !=
1454 CY_RESP_USB_CONFIG) {
1455 ret = CY_AS_ERROR_INVALID_RESPONSE;
1456 goto destroy;
1457 }
1458
1459 /* Marshal the reply */
1460 if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) {
1461 uint32_t device;
1462 cy_bool state;
1463 cy_as_usb_enum_control *ms_config_p =
1464 (cy_as_usb_enum_control *)config_p;
1465
1466 bus_mask = (uint8_t)
1467 (cy_as_ll_request_response__get_word
1468 (reply_p, 0) & 0xFF);
1469 for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
1470 if (bus_mask & (1 << bus))
1471 state = cy_true;
1472 else
1473 state = cy_false;
1474
1475 for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES;
1476 device++)
1477 ms_config_p->devices_to_enumerate[bus][device]
1478 = state;
1479 }
1480
1481 ms_config_p->antioch_enumeration =
1482 (cy_bool)cy_as_ll_request_response__get_word
1483 (reply_p, 1);
1484
1485 val = cy_as_ll_request_response__get_word(reply_p, 2);
1486 if (dev_p->is_mtp_firmware) {
1487 ms_config_p->mass_storage_interface = 0;
1488 ms_config_p->mtp_interface = (uint8_t)(val & 0xFF);
1489 } else {
1490 ms_config_p->mass_storage_interface =
1491 (uint8_t)(val & 0xFF);
1492 ms_config_p->mtp_interface = 0;
1493 }
1494 ms_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
1495
1496 /*
1497 * firmware returns an invalid interface number for mass storage,
1498 * if mass storage is not enabled. this needs to be converted to
1499 * zero to match the input configuration.
1500 */
1501 if (bus_mask == 0) {
1502 if (dev_p->is_mtp_firmware)
1503 ms_config_p->mtp_interface = 0;
1504 else
1505 ms_config_p->mass_storage_interface = 0;
1506 }
1507 } else {
1508 cy_as_usb_enum_control_dep *ex_config_p =
1509 (cy_as_usb_enum_control_dep *)config_p;
1510
1511 ex_config_p->enum_mass_storage = (uint8_t)
1512 ((cy_as_ll_request_response__get_word
1513 (reply_p, 0) >> 8) & 0xFF);
1514 ex_config_p->antioch_enumeration = (cy_bool)
1515 cy_as_ll_request_response__get_word(reply_p, 1);
1516
1517 val = cy_as_ll_request_response__get_word(reply_p, 2);
1518 ex_config_p->mass_storage_interface = (uint8_t)(val & 0xFF);
1519 ex_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
1520
1521 /*
1522 * firmware returns an invalid interface number for mass
1523 * storage, if mass storage is not enabled. this needs to
1524 * be converted to zero to match the input configuration.
1525 */
1526 if (ex_config_p->enum_mass_storage == 0)
1527 ex_config_p->mass_storage_interface = 0;
1528 }
1529
1530 destroy:
1531 cy_as_ll_destroy_request(dev_p, req_p);
1532 cy_as_ll_destroy_response(dev_p, reply_p);
1533
1534 return ret;
1535 }
1536
1537 /*
1538 * This sets up the request for the enumerateion configuration
1539 * information, based on if the request is from the old pre-1.2
1540 * functions.
1541 */
1542 static cy_as_return_status_t
1543 my_usb_get_enum_config(cy_as_device_handle handle,
1544 uint16_t req_flags,
1545 void *config_p,
1546 cy_as_function_callback cb,
1547 uint32_t client)
1548 {
1549 cy_as_ll_request_response *req_p , *reply_p;
1550 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1551
1552 cy_as_device *dev_p;
1553
1554 cy_as_log_debug_message(6, "cy_as_usb_get_enum_config called");
1555
1556 dev_p = (cy_as_device *)handle;
1557 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1558 return CY_AS_ERROR_INVALID_HANDLE;
1559
1560 ret = is_usb_active(dev_p);
1561 if (ret != CY_AS_ERROR_SUCCESS)
1562 return ret;
1563
1564 if (cy_as_device_is_in_callback(dev_p))
1565 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1566
1567 /* Create the request to send to the West Bridge device */
1568 req_p = cy_as_ll_create_request(dev_p,
1569 CY_RQT_GET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 0);
1570 if (req_p == 0)
1571 return CY_AS_ERROR_OUT_OF_MEMORY;
1572
1573 /* Reserve space for the reply, the reply data
1574 * will not exceed two bytes */
1575 reply_p = cy_as_ll_create_response(dev_p, 3);
1576 if (reply_p == 0) {
1577 cy_as_ll_destroy_request(dev_p, req_p);
1578 return CY_AS_ERROR_OUT_OF_MEMORY;
1579 }
1580
1581 if (cb == 0) {
1582 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1583 if (ret != CY_AS_ERROR_SUCCESS)
1584 goto destroy;
1585
1586 /* we need to know the type of request to
1587 * know how to manage the data */
1588 req_p->flags |= req_flags;
1589 return my_handle_response_get_enum_config(dev_p,
1590 req_p, reply_p, config_p);
1591 } else {
1592 ret = cy_as_misc_send_request(dev_p, cb, client,
1593 CY_FUNCT_CB_USB_GETENUMCONFIG, config_p,
1594 dev_p->func_cbs_usb, req_flags, req_p, reply_p,
1595 cy_as_usb_func_callback);
1596
1597 if (ret != CY_AS_ERROR_SUCCESS)
1598 goto destroy;
1599
1600 return ret;
1601 }
1602
1603 destroy:
1604 cy_as_ll_destroy_request(dev_p, req_p);
1605 cy_as_ll_destroy_response(dev_p, reply_p);
1606
1607 return ret;
1608 }
1609
1610 /*
1611 * This method returns the enumerateion configuration information
1612 * from the West Bridge device. Generally this is not used by
1613 * client software but is provided mostly for debug information.
1614 * We want a method to read all state information from the device.
1615 */
1616 cy_as_return_status_t
1617 cy_as_usb_get_enum_config(cy_as_device_handle handle,
1618 cy_as_usb_enum_control *config_p,
1619 cy_as_function_callback cb,
1620 uint32_t client)
1621 {
1622 return my_usb_get_enum_config(handle,
1623 CY_AS_REQUEST_RESPONSE_MS, config_p, cb, client);
1624 }
1625
1626
1627 /*
1628 * This method sets the USB descriptor for a given entity.
1629 */
1630 cy_as_return_status_t
1631 cy_as_usb_set_descriptor(cy_as_device_handle handle,
1632 cy_as_usb_desc_type type,
1633 uint8_t index,
1634 void *desc_p,
1635 uint16_t length,
1636 cy_as_function_callback cb,
1637 uint32_t client)
1638 {
1639 cy_as_ll_request_response *req_p , *reply_p;
1640 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1641 uint16_t pktlen;
1642
1643 cy_as_device *dev_p;
1644
1645 cy_as_log_debug_message(6, "cy_as_usb_set_descriptor called");
1646
1647 dev_p = (cy_as_device *)handle;
1648 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1649 return CY_AS_ERROR_INVALID_HANDLE;
1650
1651 ret = is_usb_active(dev_p);
1652 if (ret != CY_AS_ERROR_SUCCESS)
1653 return ret;
1654
1655 if (cy_as_device_is_in_callback(dev_p))
1656 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1657
1658 if (length > CY_AS_MAX_USB_DESCRIPTOR_SIZE)
1659 return CY_AS_ERROR_INVALID_DESCRIPTOR;
1660
1661 pktlen = (uint16_t)length / 2;
1662 if (length % 2)
1663 pktlen++;
1664 pktlen += 2; /* 1 for type, 1 for length */
1665
1666 /* Create the request to send to the West Bridge device */
1667 req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_DESCRIPTOR,
1668 CY_RQT_USB_RQT_CONTEXT, (uint16_t)pktlen);
1669 if (req_p == 0)
1670 return CY_AS_ERROR_OUT_OF_MEMORY;
1671
1672 cy_as_ll_request_response__set_word(req_p, 0,
1673 (uint16_t)((uint8_t)type | (index << 8)));
1674 cy_as_ll_request_response__set_word(req_p, 1,
1675 (uint16_t)length);
1676 cy_as_ll_request_response__pack(req_p, 2, length, desc_p);
1677
1678 reply_p = cy_as_ll_create_response(dev_p, 1);
1679 if (reply_p == 0) {
1680 cy_as_ll_destroy_request(dev_p, req_p);
1681 return CY_AS_ERROR_OUT_OF_MEMORY;
1682 }
1683
1684 if (cb == 0) {
1685 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1686 if (ret != CY_AS_ERROR_SUCCESS)
1687 goto destroy;
1688
1689 return my_handle_response_no_data(dev_p, req_p, reply_p);
1690 } else {
1691 ret = cy_as_misc_send_request(dev_p, cb, client,
1692 CY_FUNCT_CB_USB_SETDESCRIPTOR, 0, dev_p->func_cbs_usb,
1693 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1694 cy_as_usb_func_callback);
1695
1696 if (ret != CY_AS_ERROR_SUCCESS)
1697 goto destroy;
1698
1699 return ret;
1700 }
1701
1702 destroy:
1703 cy_as_ll_destroy_request(dev_p, req_p);
1704 cy_as_ll_destroy_response(dev_p, reply_p);
1705
1706 return ret;
1707 }
1708
1709 /*
1710 * This method clears all descriptors that were previously
1711 * stored on the West Bridge through CyAsUsbSetDescriptor calls.
1712 */
1713 cy_as_return_status_t
1714 cy_as_usb_clear_descriptors(cy_as_device_handle handle,
1715 cy_as_function_callback cb,
1716 uint32_t client)
1717 {
1718 cy_as_ll_request_response *req_p , *reply_p;
1719 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1720
1721 cy_as_device *dev_p;
1722
1723 cy_as_log_debug_message(6, "cy_as_usb_clear_descriptors called");
1724
1725 dev_p = (cy_as_device *)handle;
1726 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1727 return CY_AS_ERROR_INVALID_HANDLE;
1728
1729 ret = is_usb_active(dev_p);
1730 if (ret != CY_AS_ERROR_SUCCESS)
1731 return ret;
1732
1733 if ((cy_as_device_is_in_callback(dev_p)) && (cb == 0))
1734 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1735
1736 /* Create the request to send to the West Bridge device */
1737 req_p = cy_as_ll_create_request(dev_p,
1738 CY_RQT_CLEAR_DESCRIPTORS, CY_RQT_USB_RQT_CONTEXT, 1);
1739 if (req_p == 0)
1740 return CY_AS_ERROR_OUT_OF_MEMORY;
1741
1742 reply_p = cy_as_ll_create_response(dev_p, 1);
1743 if (reply_p == 0) {
1744 cy_as_ll_destroy_request(dev_p, req_p);
1745 return CY_AS_ERROR_OUT_OF_MEMORY;
1746 }
1747
1748 if (cb == 0) {
1749
1750 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1751 if (ret != CY_AS_ERROR_SUCCESS)
1752 goto destroy;
1753
1754 return my_handle_response_no_data(dev_p, req_p, reply_p);
1755 } else {
1756 ret = cy_as_misc_send_request(dev_p, cb, client,
1757 CY_FUNCT_CB_USB_CLEARDESCRIPTORS, 0,
1758 dev_p->func_cbs_usb,
1759 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1760 cy_as_usb_func_callback);
1761
1762 if (ret != CY_AS_ERROR_SUCCESS)
1763 goto destroy;
1764
1765 return ret;
1766 }
1767
1768 destroy:
1769 cy_as_ll_destroy_request(dev_p, req_p);
1770 cy_as_ll_destroy_response(dev_p, reply_p);
1771
1772 return ret;
1773 }
1774
1775 static cy_as_return_status_t
1776 my_handle_response_get_descriptor(cy_as_device *dev_p,
1777 cy_as_ll_request_response *req_p,
1778 cy_as_ll_request_response *reply_p,
1779 cy_as_get_descriptor_data *data)
1780 {
1781 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1782 uint32_t retlen;
1783
1784 if (cy_as_ll_request_response__get_code(reply_p) ==
1785 CY_RESP_SUCCESS_FAILURE) {
1786 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1787 goto destroy;
1788 } else if (cy_as_ll_request_response__get_code(reply_p) !=
1789 CY_RESP_USB_DESCRIPTOR) {
1790 ret = CY_AS_ERROR_INVALID_RESPONSE;
1791 goto destroy;
1792 }
1793
1794 retlen = cy_as_ll_request_response__get_word(reply_p, 0);
1795 if (retlen > data->length) {
1796 ret = CY_AS_ERROR_INVALID_SIZE;
1797 goto destroy;
1798 }
1799
1800 ret = CY_AS_ERROR_SUCCESS;
1801 cy_as_ll_request_response__unpack(reply_p, 1,
1802 retlen, data->desc_p);
1803
1804 destroy:
1805 cy_as_ll_destroy_request(dev_p, req_p);
1806 cy_as_ll_destroy_response(dev_p, reply_p);
1807
1808 return ret;
1809 }
1810
1811 /*
1812 * This method retreives the USB descriptor for a given type.
1813 */
1814 cy_as_return_status_t
1815 cy_as_usb_get_descriptor(cy_as_device_handle handle,
1816 cy_as_usb_desc_type type,
1817 uint8_t index,
1818 cy_as_get_descriptor_data *data,
1819 cy_as_function_callback cb,
1820 uint32_t client)
1821 {
1822 cy_as_return_status_t ret;
1823 cy_as_ll_request_response *req_p , *reply_p;
1824
1825 cy_as_device *dev_p;
1826
1827 cy_as_log_debug_message(6, "cy_as_usb_get_descriptor called");
1828
1829 dev_p = (cy_as_device *)handle;
1830 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1831 return CY_AS_ERROR_INVALID_HANDLE;
1832
1833 ret = is_usb_active(dev_p);
1834 if (ret != CY_AS_ERROR_SUCCESS)
1835 return ret;
1836
1837 if (cy_as_device_is_in_callback(dev_p))
1838 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1839
1840 /* Create the request to send to the West Bridge device */
1841 req_p = cy_as_ll_create_request(dev_p,
1842 CY_RQT_GET_DESCRIPTOR, CY_RQT_USB_RQT_CONTEXT, 1);
1843 if (req_p == 0)
1844 return CY_AS_ERROR_OUT_OF_MEMORY;
1845
1846 cy_as_ll_request_response__set_word(req_p, 0,
1847 (uint16_t)((uint8_t)type | (index << 8)));
1848
1849 /* Add one for the length field */
1850 reply_p = cy_as_ll_create_response(dev_p,
1851 CY_AS_MAX_USB_DESCRIPTOR_SIZE + 1);
1852 if (reply_p == 0) {
1853 cy_as_ll_destroy_request(dev_p, req_p);
1854 return CY_AS_ERROR_OUT_OF_MEMORY;
1855 }
1856
1857 if (cb == 0) {
1858 ret = cy_as_ll_send_request_wait_reply(
1859 dev_p, req_p, reply_p);
1860 if (ret != CY_AS_ERROR_SUCCESS)
1861 goto destroy;
1862
1863 return my_handle_response_get_descriptor(dev_p,
1864 req_p, reply_p, data);
1865 } else {
1866 ret = cy_as_misc_send_request(dev_p, cb, client,
1867 CY_FUNCT_CB_USB_GETDESCRIPTOR, data,
1868 dev_p->func_cbs_usb,
1869 CY_AS_REQUEST_RESPONSE_EX, req_p,
1870 reply_p, cy_as_usb_func_callback);
1871
1872 if (ret != CY_AS_ERROR_SUCCESS)
1873 goto destroy;
1874
1875 return ret;
1876 }
1877
1878 destroy:
1879 cy_as_ll_destroy_request(dev_p, req_p);
1880 cy_as_ll_destroy_response(dev_p, reply_p);
1881
1882 return ret;
1883 }
1884
1885 cy_as_return_status_t
1886 cy_as_usb_set_physical_configuration(cy_as_device_handle handle,
1887 uint8_t config)
1888 {
1889 cy_as_return_status_t ret;
1890 cy_as_device *dev_p;
1891
1892 cy_as_log_debug_message(6,
1893 "cy_as_usb_set_physical_configuration called");
1894
1895 dev_p = (cy_as_device *)handle;
1896 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1897 return CY_AS_ERROR_INVALID_HANDLE;
1898
1899 ret = is_usb_active(dev_p);
1900 if (ret != CY_AS_ERROR_SUCCESS)
1901 return ret;
1902
1903 if (cy_as_device_is_usb_connected(dev_p))
1904 return CY_AS_ERROR_USB_CONNECTED;
1905
1906 if (config < 1 || config > 12)
1907 return CY_AS_ERROR_INVALID_CONFIGURATION;
1908
1909 dev_p->usb_phy_config = config;
1910
1911 return CY_AS_ERROR_SUCCESS;
1912 }
1913
1914 static cy_bool
1915 is_physical_valid(uint8_t config, cy_as_end_point_number_t ep)
1916 {
1917 static uint8_t validmask[12] = {
1918 0x0f, /* Config 1 - 1, 2, 3, 4 */
1919 0x07, /* Config 2 - 1, 2, 3 */
1920 0x07, /* Config 3 - 1, 2, 3 */
1921 0x0d, /* Config 4 - 1, 3, 4 */
1922 0x05, /* Config 5 - 1, 3 */
1923 0x05, /* Config 6 - 1, 3 */
1924 0x0d, /* Config 7 - 1, 3, 4 */
1925 0x05, /* Config 8 - 1, 3 */
1926 0x05, /* Config 9 - 1, 3 */
1927 0x0d, /* Config 10 - 1, 3, 4 */
1928 0x09, /* Config 11 - 1, 4 */
1929 0x01 /* Config 12 - 1 */
1930 };
1931
1932 return (validmask[config - 1] & (1 << (ep - 1))) ? cy_true : cy_false;
1933 }
1934
1935 /*
1936 * This method sets the configuration for an endpoint
1937 */
1938 cy_as_return_status_t
1939 cy_as_usb_set_end_point_config(cy_as_device_handle handle,
1940 cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
1941 {
1942 cy_as_return_status_t ret;
1943 cy_as_device *dev_p;
1944
1945 cy_as_log_debug_message(6, "cy_as_usb_set_end_point_config called");
1946
1947 dev_p = (cy_as_device *)handle;
1948 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1949 return CY_AS_ERROR_INVALID_HANDLE;
1950
1951 ret = is_usb_active(dev_p);
1952 if (ret != CY_AS_ERROR_SUCCESS)
1953 return ret;
1954
1955 if (cy_as_device_is_usb_connected(dev_p))
1956 return CY_AS_ERROR_USB_CONNECTED;
1957
1958 if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
1959 return CY_AS_ERROR_INVALID_ENDPOINT;
1960
1961 if (ep == 0) {
1962 /* Endpoint 0 must be 64 byte, dir IN/OUT,
1963 * and control type */
1964 if (config_p->dir != cy_as_usb_in_out ||
1965 config_p->type != cy_as_usb_control)
1966 return CY_AS_ERROR_INVALID_CONFIGURATION;
1967 } else if (ep == 1) {
1968 if ((dev_p->is_mtp_firmware == 1) &&
1969 (dev_p->usb_config[1].enabled == cy_true)) {
1970 return CY_AS_ERROR_INVALID_ENDPOINT;
1971 }
1972
1973 /*
1974 * EP1 can only be used either as an OUT ep, or as an IN ep.
1975 */
1976 if ((config_p->type == cy_as_usb_control) ||
1977 (config_p->type == cy_as_usb_iso) ||
1978 (config_p->dir == cy_as_usb_in_out))
1979 return CY_AS_ERROR_INVALID_CONFIGURATION;
1980 } else {
1981 if (config_p->dir == cy_as_usb_in_out ||
1982 config_p->type == cy_as_usb_control)
1983 return CY_AS_ERROR_INVALID_CONFIGURATION;
1984
1985 if (!is_physical_valid(dev_p->usb_phy_config,
1986 config_p->physical))
1987 return CY_AS_ERROR_INVALID_PHYSICAL_ENDPOINT;
1988
1989 /*
1990 * ISO endpoints must be on E_ps 3, 5, 7 or 9 as
1991 * they need to align directly with the underlying
1992 * physical endpoint.
1993 */
1994 if (config_p->type == cy_as_usb_iso) {
1995 if (ep != 3 && ep != 5 && ep != 7 && ep != 9)
1996 return CY_AS_ERROR_INVALID_CONFIGURATION;
1997
1998 if (ep == 3 && config_p->physical != 1)
1999 return CY_AS_ERROR_INVALID_CONFIGURATION;
2000
2001 if (ep == 5 && config_p->physical != 2)
2002 return CY_AS_ERROR_INVALID_CONFIGURATION;
2003
2004 if (ep == 7 && config_p->physical != 3)
2005 return CY_AS_ERROR_INVALID_CONFIGURATION;
2006
2007 if (ep == 9 && config_p->physical != 4)
2008 return CY_AS_ERROR_INVALID_CONFIGURATION;
2009 }
2010 }
2011
2012 /* Store the configuration information until a
2013 * CyAsUsbCommitConfig is done */
2014 dev_p->usb_config[ep] = *config_p;
2015
2016 /* If the endpoint is enabled, enable DMA associated
2017 * with the endpoint */
2018 /*
2019 * we make some assumptions that we check here. we assume
2020 * that the direction fields for the DMA module are the same
2021 * values as the direction values for the USB module.
2022 */
2023 cy_as_hal_assert((int)cy_as_usb_in == (int)cy_as_direction_in);
2024 cy_as_hal_assert((int)cy_as_usb_out == (int)cy_as_direction_out);
2025 cy_as_hal_assert((int)cy_as_usb_in_out == (int)cy_as_direction_in_out);
2026
2027 return cy_as_dma_enable_end_point(dev_p, ep,
2028 config_p->enabled, (cy_as_dma_direction)config_p->dir);
2029 }
2030
2031 cy_as_return_status_t
2032 cy_as_usb_get_end_point_config(cy_as_device_handle handle,
2033 cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
2034 {
2035 cy_as_return_status_t ret;
2036
2037 cy_as_device *dev_p;
2038
2039 cy_as_log_debug_message(6, "cy_as_usb_get_end_point_config called");
2040
2041 dev_p = (cy_as_device *)handle;
2042 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2043 return CY_AS_ERROR_INVALID_HANDLE;
2044
2045 ret = is_usb_active(dev_p);
2046 if (ret != CY_AS_ERROR_SUCCESS)
2047 return ret;
2048
2049 if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
2050 return CY_AS_ERROR_INVALID_ENDPOINT;
2051
2052 *config_p = dev_p->usb_config[ep];
2053
2054 return CY_AS_ERROR_SUCCESS;
2055 }
2056
2057 /*
2058 * Commit the configuration of the various endpoints to the hardware.
2059 */
2060 cy_as_return_status_t
2061 cy_as_usb_commit_config(cy_as_device_handle handle,
2062 cy_as_function_callback cb,
2063 uint32_t client)
2064 {
2065 uint32_t i;
2066 cy_as_return_status_t ret;
2067 cy_as_ll_request_response *req_p , *reply_p;
2068 cy_as_device *dev_p;
2069 uint16_t data;
2070
2071 cy_as_log_debug_message(6, "cy_as_usb_commit_config called");
2072
2073 dev_p = (cy_as_device *)handle;
2074 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2075 return CY_AS_ERROR_INVALID_HANDLE;
2076
2077 ret = is_usb_active(dev_p);
2078 if (ret != CY_AS_ERROR_SUCCESS)
2079 return ret;
2080
2081 if (cy_as_device_is_usb_connected(dev_p))
2082 return CY_AS_ERROR_USB_CONNECTED;
2083
2084 if (cy_as_device_is_in_callback(dev_p))
2085 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2086
2087 /*
2088 * this performs the mapping based on informatation that was
2089 * previously stored on the device about the various endpoints
2090 * and how they are configured. the output of this mapping is
2091 * setting the the 14 register values contained in usb_lepcfg
2092 * and usb_pepcfg
2093 */
2094 ret = cy_as_usb_map_logical2_physical(dev_p);
2095 if (ret != CY_AS_ERROR_SUCCESS)
2096 return ret;
2097
2098 /*
2099 * now, package the information about the various logical and
2100 * physical endpoint configuration registers and send it
2101 * across to the west bridge device.
2102 */
2103 req_p = cy_as_ll_create_request(dev_p,
2104 CY_RQT_SET_USB_CONFIG_REGISTERS, CY_RQT_USB_RQT_CONTEXT, 8);
2105 if (req_p == 0)
2106 return CY_AS_ERROR_OUT_OF_MEMORY;
2107
2108 cy_as_hal_print_message("USB configuration: %d\n",
2109 dev_p->usb_phy_config);
2110 cy_as_hal_print_message("EP1OUT: 0x%02x EP1IN: 0x%02x\n",
2111 dev_p->usb_ep1cfg[0], dev_p->usb_ep1cfg[1]);
2112 cy_as_hal_print_message("PEP registers: 0x%02x 0x%02x 0x%02x 0x%02x\n",
2113 dev_p->usb_pepcfg[0], dev_p->usb_pepcfg[1],
2114 dev_p->usb_pepcfg[2], dev_p->usb_pepcfg[3]);
2115
2116 cy_as_hal_print_message("LEP registers: 0x%02x 0x%02x 0x%02x "
2117 "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
2118 dev_p->usb_lepcfg[0], dev_p->usb_lepcfg[1],
2119 dev_p->usb_lepcfg[2], dev_p->usb_lepcfg[3],
2120 dev_p->usb_lepcfg[4], dev_p->usb_lepcfg[5],
2121 dev_p->usb_lepcfg[6], dev_p->usb_lepcfg[7],
2122 dev_p->usb_lepcfg[8], dev_p->usb_lepcfg[9]);
2123
2124 /* Write the EP1OUTCFG and EP1INCFG data in the first word. */
2125 data = (uint16_t)((dev_p->usb_ep1cfg[0] << 8) |
2126 dev_p->usb_ep1cfg[1]);
2127 cy_as_ll_request_response__set_word(req_p, 0, data);
2128
2129 /* Write the PEP CFG data in the next 2 words */
2130 for (i = 0; i < 4; i += 2) {
2131 data = (uint16_t)((dev_p->usb_pepcfg[i] << 8) |
2132 dev_p->usb_pepcfg[i + 1]);
2133 cy_as_ll_request_response__set_word(req_p,
2134 1 + i / 2, data);
2135 }
2136
2137 /* Write the LEP CFG data in the next 5 words */
2138 for (i = 0; i < 10; i += 2) {
2139 data = (uint16_t)((dev_p->usb_lepcfg[i] << 8) |
2140 dev_p->usb_lepcfg[i + 1]);
2141 cy_as_ll_request_response__set_word(req_p,
2142 3 + i / 2, data);
2143 }
2144
2145 /* A single status word response type */
2146 reply_p = cy_as_ll_create_response(dev_p, 1);
2147 if (reply_p == 0) {
2148 cy_as_ll_destroy_request(dev_p, req_p);
2149 return CY_AS_ERROR_OUT_OF_MEMORY;
2150 }
2151
2152 if (cb == 0) {
2153 ret = cy_as_ll_send_request_wait_reply(dev_p,
2154 req_p, reply_p);
2155 if (ret != CY_AS_ERROR_SUCCESS)
2156 goto destroy;
2157
2158 ret = my_handle_response_no_data(dev_p,
2159 req_p, reply_p);
2160
2161 if (ret == CY_AS_ERROR_SUCCESS)
2162 ret = cy_as_usb_setup_dma(dev_p);
2163
2164 return ret;
2165 } else {
2166 ret = cy_as_misc_send_request(dev_p, cb, client,
2167 CY_FUNCT_CB_USB_COMMITCONFIG, 0, dev_p->func_cbs_usb,
2168 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
2169 cy_as_usb_func_callback);
2170
2171 if (ret != CY_AS_ERROR_SUCCESS)
2172 goto destroy;
2173
2174 return ret;
2175 }
2176
2177 destroy:
2178 cy_as_ll_destroy_request(dev_p, req_p);
2179 cy_as_ll_destroy_response(dev_p, reply_p);
2180
2181 return ret;
2182 }
2183
2184 static void
2185 sync_request_callback(cy_as_device *dev_p,
2186 cy_as_end_point_number_t ep, void *buf_p,
2187 uint32_t size, cy_as_return_status_t err)
2188 {
2189 (void)ep;
2190 (void)buf_p;
2191
2192 dev_p->usb_error = err;
2193 dev_p->usb_actual_cnt = size;
2194 }
2195
2196 static void
2197 async_read_request_callback(cy_as_device *dev_p,
2198 cy_as_end_point_number_t ep, void *buf_p,
2199 uint32_t size, cy_as_return_status_t err)
2200 {
2201 cy_as_device_handle h;
2202
2203 cy_as_log_debug_message(6,
2204 "async_read_request_callback called");
2205
2206 h = (cy_as_device_handle)dev_p;
2207
2208 if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
2209 dev_p->usb_pending_buffer = buf_p;
2210 dev_p->usb_pending_size = size;
2211 dev_p->usb_error = err;
2212 cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
2213 } else {
2214 cy_as_usb_io_callback cb;
2215
2216 cb = dev_p->usb_cb[ep];
2217 dev_p->usb_cb[ep] = 0;
2218 cy_as_device_clear_usb_async_pending(dev_p, ep);
2219 if (cb)
2220 cb(h, ep, size, buf_p, err);
2221 }
2222 }
2223
2224 static void
2225 async_write_request_callback(cy_as_device *dev_p,
2226 cy_as_end_point_number_t ep, void *buf_p,
2227 uint32_t size, cy_as_return_status_t err)
2228 {
2229 cy_as_device_handle h;
2230
2231 cy_as_log_debug_message(6,
2232 "async_write_request_callback called");
2233
2234 h = (cy_as_device_handle)dev_p;
2235
2236 if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
2237 dev_p->usb_pending_buffer = buf_p;
2238 dev_p->usb_pending_size = size;
2239 dev_p->usb_error = err;
2240
2241 /* The west bridge protocol generates ZLPs as required. */
2242 cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
2243 } else {
2244 cy_as_usb_io_callback cb;
2245
2246 cb = dev_p->usb_cb[ep];
2247 dev_p->usb_cb[ep] = 0;
2248
2249 cy_as_device_clear_usb_async_pending(dev_p, ep);
2250 if (cb)
2251 cb(h, ep, size, buf_p, err);
2252 }
2253 }
2254
2255 static void
2256 my_turbo_rqt_callback(cy_as_device *dev_p,
2257 uint8_t context,
2258 cy_as_ll_request_response *rqt,
2259 cy_as_ll_request_response *resp,
2260 cy_as_return_status_t stat)
2261 {
2262 uint8_t code;
2263
2264 (void)context;
2265 (void)stat;
2266
2267 /* The Handlers are responsible for Deleting the rqt and resp when
2268 * they are finished
2269 */
2270 code = cy_as_ll_request_response__get_code(rqt);
2271 switch (code) {
2272 case CY_RQT_TURBO_SWITCH_ENDPOINT:
2273 cy_as_hal_assert(stat == CY_AS_ERROR_SUCCESS);
2274 cy_as_ll_destroy_request(dev_p, rqt);
2275 cy_as_ll_destroy_response(dev_p, resp);
2276 break;
2277 default:
2278 cy_as_hal_assert(cy_false);
2279 break;
2280 }
2281 }
2282
2283 /* Send a mailbox request to prepare the endpoint for switching */
2284 static cy_as_return_status_t
2285 my_send_turbo_switch(cy_as_device *dev_p, uint32_t size, cy_bool pktread)
2286 {
2287 cy_as_return_status_t ret;
2288 cy_as_ll_request_response *req_p , *reply_p;
2289
2290 /* Create the request to send to the West Bridge device */
2291 req_p = cy_as_ll_create_request(dev_p,
2292 CY_RQT_TURBO_SWITCH_ENDPOINT, CY_RQT_TUR_RQT_CONTEXT, 3);
2293 if (req_p == 0)
2294 return CY_AS_ERROR_OUT_OF_MEMORY;
2295
2296 /* Reserve space for the reply, the reply data will
2297 * not exceed one word */
2298 reply_p = cy_as_ll_create_response(dev_p, 1);
2299 if (reply_p == 0) {
2300 cy_as_ll_destroy_request(dev_p, req_p);
2301 return CY_AS_ERROR_OUT_OF_MEMORY;
2302 }
2303
2304 cy_as_ll_request_response__set_word(req_p, 0,
2305 (uint16_t)pktread);
2306 cy_as_ll_request_response__set_word(req_p, 1,
2307 (uint16_t)((size >> 16) & 0xFFFF));
2308 cy_as_ll_request_response__set_word(req_p, 2,
2309 (uint16_t)(size & 0xFFFF));
2310
2311 ret = cy_as_ll_send_request(dev_p, req_p,
2312 reply_p, cy_false, my_turbo_rqt_callback);
2313 if (ret != CY_AS_ERROR_SUCCESS) {
2314 cy_as_ll_destroy_request(dev_p, req_p);
2315 cy_as_ll_destroy_request(dev_p, reply_p);
2316 return ret;
2317 }
2318
2319 return CY_AS_ERROR_SUCCESS;
2320 }
2321
2322 cy_as_return_status_t
2323 cy_as_usb_read_data(cy_as_device_handle handle,
2324 cy_as_end_point_number_t ep, cy_bool pktread,
2325 uint32_t dsize, uint32_t *dataread, void *data)
2326 {
2327 cy_as_return_status_t ret;
2328 cy_as_device *dev_p;
2329
2330 cy_as_log_debug_message(6, "cy_as_usb_read_data called");
2331
2332 dev_p = (cy_as_device *)handle;
2333 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2334 return CY_AS_ERROR_INVALID_HANDLE;
2335
2336 ret = is_usb_active(dev_p);
2337 if (ret != CY_AS_ERROR_SUCCESS)
2338 return ret;
2339
2340 if (cy_as_device_is_in_callback(dev_p))
2341 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2342
2343 if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
2344 return CY_AS_ERROR_INVALID_ENDPOINT;
2345
2346 /* EP2 is available for reading when MTP is active */
2347 if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
2348 return CY_AS_ERROR_INVALID_ENDPOINT;
2349
2350 /* If the endpoint is disabled, we cannot
2351 * write data to the endpoint */
2352 if (!dev_p->usb_config[ep].enabled)
2353 return CY_AS_ERROR_ENDPOINT_DISABLED;
2354
2355 if (dev_p->usb_config[ep].dir != cy_as_usb_out)
2356 return CY_AS_ERROR_USB_BAD_DIRECTION;
2357
2358 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2359 pktread, cy_true, sync_request_callback);
2360 if (ret != CY_AS_ERROR_SUCCESS)
2361 return ret;
2362
2363 if (ep == CY_AS_MTP_READ_ENDPOINT) {
2364 ret = my_send_turbo_switch(dev_p, dsize, pktread);
2365 if (ret != CY_AS_ERROR_SUCCESS) {
2366 cy_as_dma_cancel(dev_p, ep, ret);
2367 return ret;
2368 }
2369
2370 ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
2371 if (ret != CY_AS_ERROR_SUCCESS)
2372 return ret;
2373 } else {
2374 ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
2375 if (ret != CY_AS_ERROR_SUCCESS)
2376 return ret;
2377 }
2378
2379 ret = dev_p->usb_error;
2380 *dataread = dev_p->usb_actual_cnt;
2381
2382 return ret;
2383 }
2384
2385 cy_as_return_status_t
2386 cy_as_usb_read_data_async(cy_as_device_handle handle,
2387 cy_as_end_point_number_t ep, cy_bool pktread,
2388 uint32_t dsize, void *data, cy_as_usb_io_callback cb)
2389 {
2390 cy_as_return_status_t ret;
2391 uint32_t mask;
2392 cy_as_device *dev_p;
2393
2394 cy_as_log_debug_message(6, "cy_as_usb_read_data_async called");
2395
2396 dev_p = (cy_as_device *)handle;
2397 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2398 return CY_AS_ERROR_INVALID_HANDLE;
2399
2400 ret = is_usb_active(dev_p);
2401 if (ret != CY_AS_ERROR_SUCCESS)
2402 return ret;
2403
2404 if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
2405 return CY_AS_ERROR_INVALID_ENDPOINT;
2406
2407 /* EP2 is available for reading when MTP is active */
2408 if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
2409 return CY_AS_ERROR_INVALID_ENDPOINT;
2410
2411 /* If the endpoint is disabled, we cannot
2412 * write data to the endpoint */
2413 if (!dev_p->usb_config[ep].enabled)
2414 return CY_AS_ERROR_ENDPOINT_DISABLED;
2415
2416 if (dev_p->usb_config[ep].dir != cy_as_usb_out &&
2417 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2418 return CY_AS_ERROR_USB_BAD_DIRECTION;
2419
2420 /*
2421 * since async operations can be triggered by interrupt
2422 * code, we must insure that we do not get multiple async
2423 * operations going at one time and protect this test and
2424 * set operation from interrupts.
2425 */
2426 mask = cy_as_hal_disable_interrupts();
2427 if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
2428 cy_as_hal_enable_interrupts(mask);
2429 return CY_AS_ERROR_ASYNC_PENDING;
2430 }
2431 cy_as_device_set_usb_async_pending(dev_p, ep);
2432
2433 /*
2434 * if this is for EP0, we set this bit to delay the
2435 * ACK response until after this read has completed.
2436 */
2437 if (ep == 0)
2438 cy_as_device_set_ack_delayed(dev_p);
2439
2440 cy_as_hal_enable_interrupts(mask);
2441
2442 cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
2443 dev_p->usb_cb[ep] = cb;
2444
2445 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2446 pktread, cy_true, async_read_request_callback);
2447 if (ret != CY_AS_ERROR_SUCCESS)
2448 return ret;
2449
2450 if (ep == CY_AS_MTP_READ_ENDPOINT) {
2451 ret = my_send_turbo_switch(dev_p, dsize, pktread);
2452 if (ret != CY_AS_ERROR_SUCCESS) {
2453 cy_as_dma_cancel(dev_p, ep, ret);
2454 return ret;
2455 }
2456 } else {
2457 /* Kick start the queue if it is not running */
2458 cy_as_dma_kick_start(dev_p, ep);
2459 }
2460 return ret;
2461 }
2462
2463 cy_as_return_status_t
2464 cy_as_usb_write_data(cy_as_device_handle handle,
2465 cy_as_end_point_number_t ep, uint32_t dsize, void *data)
2466 {
2467 cy_as_return_status_t ret;
2468 cy_as_device *dev_p;
2469
2470 cy_as_log_debug_message(6, "cy_as_usb_write_data called");
2471
2472 dev_p = (cy_as_device *)handle;
2473 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2474 return CY_AS_ERROR_INVALID_HANDLE;
2475
2476 ret = is_usb_active(dev_p);
2477 if (ret != CY_AS_ERROR_SUCCESS)
2478 return ret;
2479
2480 if (cy_as_device_is_in_callback(dev_p))
2481 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2482
2483 if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
2484 return CY_AS_ERROR_INVALID_ENDPOINT;
2485
2486 /* EP6 is available for writing when MTP is active */
2487 if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
2488 return CY_AS_ERROR_INVALID_ENDPOINT;
2489
2490 /* If the endpoint is disabled, we cannot
2491 * write data to the endpoint */
2492 if (!dev_p->usb_config[ep].enabled)
2493 return CY_AS_ERROR_ENDPOINT_DISABLED;
2494
2495 if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
2496 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2497 return CY_AS_ERROR_USB_BAD_DIRECTION;
2498
2499 /* Write on Turbo endpoint */
2500 if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
2501 cy_as_ll_request_response *req_p, *reply_p;
2502
2503 req_p = cy_as_ll_create_request(dev_p,
2504 CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
2505 CY_RQT_TUR_RQT_CONTEXT, 3);
2506 if (req_p == 0)
2507 return CY_AS_ERROR_OUT_OF_MEMORY;
2508
2509 cy_as_ll_request_response__set_word(req_p,
2510 0, 0x0006); /* EP number to use. */
2511 cy_as_ll_request_response__set_word(req_p,
2512 1, (uint16_t)((dsize >> 16) & 0xFFFF));
2513 cy_as_ll_request_response__set_word(req_p,
2514 2, (uint16_t)(dsize & 0xFFFF));
2515
2516 /* Reserve space for the reply, the reply data
2517 * will not exceed one word */
2518 reply_p = cy_as_ll_create_response(dev_p, 1);
2519 if (reply_p == 0) {
2520 cy_as_ll_destroy_request(dev_p, req_p);
2521 return CY_AS_ERROR_OUT_OF_MEMORY;
2522 }
2523
2524 if (dsize) {
2525 ret = cy_as_dma_queue_request(dev_p,
2526 ep, data, dsize, cy_false,
2527 cy_false, sync_request_callback);
2528 if (ret != CY_AS_ERROR_SUCCESS)
2529 return ret;
2530 }
2531
2532 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
2533 if (ret == CY_AS_ERROR_SUCCESS) {
2534 if (cy_as_ll_request_response__get_code(reply_p) !=
2535 CY_RESP_SUCCESS_FAILURE)
2536 ret = CY_AS_ERROR_INVALID_RESPONSE;
2537 else
2538 ret = cy_as_ll_request_response__get_word
2539 (reply_p, 0);
2540 }
2541
2542 cy_as_ll_destroy_request(dev_p, req_p);
2543 cy_as_ll_destroy_response(dev_p, reply_p);
2544
2545 if (ret != CY_AS_ERROR_SUCCESS) {
2546 if (dsize)
2547 cy_as_dma_cancel(dev_p, ep, ret);
2548 return ret;
2549 }
2550
2551 /* If this is a zero-byte write, firmware will
2552 * handle it. there is no need to do any work here.
2553 */
2554 if (!dsize)
2555 return CY_AS_ERROR_SUCCESS;
2556 } else {
2557 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2558 cy_false, cy_false, sync_request_callback);
2559 if (ret != CY_AS_ERROR_SUCCESS)
2560 return ret;
2561 }
2562
2563 if (ep != CY_AS_MTP_WRITE_ENDPOINT)
2564 ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
2565 else
2566 ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
2567
2568 if (ret != CY_AS_ERROR_SUCCESS)
2569 return ret;
2570
2571 ret = dev_p->usb_error;
2572 return ret;
2573 }
2574
2575 static void
2576 mtp_write_callback(
2577 cy_as_device *dev_p,
2578 uint8_t context,
2579 cy_as_ll_request_response *rqt,
2580 cy_as_ll_request_response *resp,
2581 cy_as_return_status_t ret)
2582 {
2583 cy_as_usb_io_callback cb;
2584 cy_as_device_handle h = (cy_as_device_handle)dev_p;
2585
2586 cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT);
2587
2588 if (ret == CY_AS_ERROR_SUCCESS) {
2589 if (cy_as_ll_request_response__get_code(resp) !=
2590 CY_RESP_SUCCESS_FAILURE)
2591 ret = CY_AS_ERROR_INVALID_RESPONSE;
2592 else
2593 ret = cy_as_ll_request_response__get_word(resp, 0);
2594 }
2595
2596 /* If this was a zero byte transfer request, we can
2597 * call the callback from here. */
2598 if ((cy_as_ll_request_response__get_word(rqt, 1) == 0) &&
2599 (cy_as_ll_request_response__get_word(rqt, 2) == 0)) {
2600 cb = dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT];
2601 dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] = 0;
2602 cy_as_device_clear_usb_async_pending(dev_p,
2603 CY_AS_MTP_WRITE_ENDPOINT);
2604 if (cb)
2605 cb(h, CY_AS_MTP_WRITE_ENDPOINT, 0, 0, ret);
2606
2607 goto destroy;
2608 }
2609
2610 if (ret != CY_AS_ERROR_SUCCESS) {
2611 /* Firmware failed the request. Cancel the DMA transfer. */
2612 cy_as_dma_cancel(dev_p, 0x06, CY_AS_ERROR_CANCELED);
2613 dev_p->usb_cb[0x06] = 0;
2614 cy_as_device_clear_usb_async_pending(dev_p, 0x06);
2615 }
2616
2617 destroy:
2618 cy_as_ll_destroy_response(dev_p, resp);
2619 cy_as_ll_destroy_request(dev_p, rqt);
2620 }
2621
2622 cy_as_return_status_t
2623 cy_as_usb_write_data_async(cy_as_device_handle handle,
2624 cy_as_end_point_number_t ep, uint32_t dsize, void *data,
2625 cy_bool spacket, cy_as_usb_io_callback cb)
2626 {
2627 uint32_t mask;
2628 cy_as_return_status_t ret;
2629 cy_as_device *dev_p;
2630
2631 cy_as_log_debug_message(6, "cy_as_usb_write_data_async called");
2632
2633 dev_p = (cy_as_device *)handle;
2634 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2635 return CY_AS_ERROR_INVALID_HANDLE;
2636
2637 ret = is_usb_active(dev_p);
2638 if (ret != CY_AS_ERROR_SUCCESS)
2639 return ret;
2640
2641 if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
2642 return CY_AS_ERROR_INVALID_ENDPOINT;
2643
2644 /* EP6 is available for writing when MTP is active */
2645 if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
2646 return CY_AS_ERROR_INVALID_ENDPOINT;
2647
2648 /* If the endpoint is disabled, we cannot
2649 * write data to the endpoint */
2650 if (!dev_p->usb_config[ep].enabled)
2651 return CY_AS_ERROR_ENDPOINT_DISABLED;
2652
2653 if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
2654 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2655 return CY_AS_ERROR_USB_BAD_DIRECTION;
2656
2657 /*
2658 * since async operations can be triggered by interrupt
2659 * code, we must insure that we do not get multiple
2660 * async operations going at one time and
2661 * protect this test and set operation from interrupts.
2662 */
2663 mask = cy_as_hal_disable_interrupts();
2664 if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
2665 cy_as_hal_enable_interrupts(mask);
2666 return CY_AS_ERROR_ASYNC_PENDING;
2667 }
2668
2669 cy_as_device_set_usb_async_pending(dev_p, ep);
2670
2671 if (ep == 0)
2672 cy_as_device_set_ack_delayed(dev_p);
2673
2674 cy_as_hal_enable_interrupts(mask);
2675
2676 cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
2677 dev_p->usb_cb[ep] = cb;
2678 dev_p->usb_spacket[ep] = spacket;
2679
2680 /* Write on Turbo endpoint */
2681 if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
2682 cy_as_ll_request_response *req_p, *reply_p;
2683
2684 req_p = cy_as_ll_create_request(dev_p,
2685 CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
2686 CY_RQT_TUR_RQT_CONTEXT, 3);
2687
2688 if (req_p == 0)
2689 return CY_AS_ERROR_OUT_OF_MEMORY;
2690
2691 cy_as_ll_request_response__set_word(req_p, 0,
2692 0x0006); /* EP number to use. */
2693 cy_as_ll_request_response__set_word(req_p, 1,
2694 (uint16_t)((dsize >> 16) & 0xFFFF));
2695 cy_as_ll_request_response__set_word(req_p, 2,
2696 (uint16_t)(dsize & 0xFFFF));
2697
2698 /* Reserve space for the reply, the reply data
2699 * will not exceed one word */
2700 reply_p = cy_as_ll_create_response(dev_p, 1);
2701 if (reply_p == 0) {
2702 cy_as_ll_destroy_request(dev_p, req_p);
2703 return CY_AS_ERROR_OUT_OF_MEMORY;
2704 }
2705
2706 if (dsize) {
2707 ret = cy_as_dma_queue_request(dev_p, ep, data,
2708 dsize, cy_false, cy_false,
2709 async_write_request_callback);
2710 if (ret != CY_AS_ERROR_SUCCESS)
2711 return ret;
2712 }
2713
2714 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2715 cy_false, mtp_write_callback);
2716 if (ret != CY_AS_ERROR_SUCCESS) {
2717 if (dsize)
2718 cy_as_dma_cancel(dev_p, ep, ret);
2719 return ret;
2720 }
2721
2722 /* Firmware will handle a zero byte transfer
2723 * without any DMA transfers. */
2724 if (!dsize)
2725 return CY_AS_ERROR_SUCCESS;
2726 } else {
2727 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2728 cy_false, cy_false, async_write_request_callback);
2729 if (ret != CY_AS_ERROR_SUCCESS)
2730 return ret;
2731 }
2732
2733 /* Kick start the queue if it is not running */
2734 if (ep != CY_AS_MTP_WRITE_ENDPOINT)
2735 cy_as_dma_kick_start(dev_p, ep);
2736
2737 return CY_AS_ERROR_SUCCESS;
2738 }
2739
2740 static void
2741 my_usb_cancel_async_callback(
2742 cy_as_device *dev_p,
2743 uint8_t context,
2744 cy_as_ll_request_response *rqt,
2745 cy_as_ll_request_response *resp,
2746 cy_as_return_status_t ret)
2747 {
2748 uint8_t ep;
2749 (void)context;
2750
2751 ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
2752 if (ret == CY_AS_ERROR_SUCCESS) {
2753 if (cy_as_ll_request_response__get_code(resp) !=
2754 CY_RESP_SUCCESS_FAILURE)
2755 ret = CY_AS_ERROR_INVALID_RESPONSE;
2756 else
2757 ret = cy_as_ll_request_response__get_word(resp, 0);
2758 }
2759
2760 cy_as_ll_destroy_request(dev_p, rqt);
2761 cy_as_ll_destroy_response(dev_p, resp);
2762
2763 if (ret == CY_AS_ERROR_SUCCESS) {
2764 cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
2765 dev_p->usb_cb[ep] = 0;
2766 cy_as_device_clear_usb_async_pending(dev_p, ep);
2767 }
2768 }
2769
2770 cy_as_return_status_t
2771 cy_as_usb_cancel_async(cy_as_device_handle handle,
2772 cy_as_end_point_number_t ep)
2773 {
2774 cy_as_return_status_t ret;
2775 cy_as_ll_request_response *req_p, *reply_p;
2776
2777 cy_as_device *dev_p = (cy_as_device *)handle;
2778 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2779 return CY_AS_ERROR_INVALID_HANDLE;
2780
2781 ep &= 0x7F; /* Remove the direction bit. */
2782 if (!cy_as_device_is_usb_async_pending(dev_p, ep))
2783 return CY_AS_ERROR_ASYNC_NOT_PENDING;
2784
2785 ret = is_usb_active(dev_p);
2786 if (ret != CY_AS_ERROR_SUCCESS)
2787 return ret;
2788
2789 if (cy_as_device_is_in_suspend_mode(dev_p))
2790 return CY_AS_ERROR_IN_SUSPEND;
2791
2792 if ((ep == CY_AS_MTP_WRITE_ENDPOINT) ||
2793 (ep == CY_AS_MTP_READ_ENDPOINT)) {
2794 /* Need firmware support for the cancel operation. */
2795 req_p = cy_as_ll_create_request(dev_p,
2796 CY_RQT_CANCEL_ASYNC_TRANSFER,
2797 CY_RQT_TUR_RQT_CONTEXT, 1);
2798
2799 if (req_p == 0)
2800 return CY_AS_ERROR_OUT_OF_MEMORY;
2801
2802 reply_p = cy_as_ll_create_response(dev_p, 1);
2803 if (reply_p == 0) {
2804 cy_as_ll_destroy_request(dev_p, req_p);
2805 return CY_AS_ERROR_OUT_OF_MEMORY;
2806 }
2807
2808 cy_as_ll_request_response__set_word(req_p, 0,
2809 (uint16_t)ep);
2810
2811 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2812 cy_false, my_usb_cancel_async_callback);
2813
2814 if (ret != CY_AS_ERROR_SUCCESS) {
2815 cy_as_ll_destroy_request(dev_p, req_p);
2816 cy_as_ll_destroy_response(dev_p, reply_p);
2817 return ret;
2818 }
2819 } else {
2820 ret = cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
2821 if (ret != CY_AS_ERROR_SUCCESS)
2822 return ret;
2823
2824 dev_p->usb_cb[ep] = 0;
2825 cy_as_device_clear_usb_async_pending(dev_p, ep);
2826 }
2827
2828 return CY_AS_ERROR_SUCCESS;
2829 }
2830
2831 static void
2832 cy_as_usb_ack_callback(
2833 cy_as_device *dev_p,
2834 uint8_t context,
2835 cy_as_ll_request_response *rqt,
2836 cy_as_ll_request_response *resp,
2837 cy_as_return_status_t ret)
2838 {
2839 cy_as_func_c_b_node *node = (cy_as_func_c_b_node *)
2840 dev_p->func_cbs_usb->head_p;
2841
2842 (void)context;
2843
2844 if (ret == CY_AS_ERROR_SUCCESS) {
2845 if (cy_as_ll_request_response__get_code(resp) !=
2846 CY_RESP_SUCCESS_FAILURE)
2847 ret = CY_AS_ERROR_INVALID_RESPONSE;
2848 else
2849 ret = cy_as_ll_request_response__get_word(resp, 0);
2850 }
2851
2852 node->cb_p((cy_as_device_handle)dev_p, ret,
2853 node->client_data, node->data_type, node->data);
2854 cy_as_remove_c_b_node(dev_p->func_cbs_usb);
2855
2856 cy_as_ll_destroy_request(dev_p, rqt);
2857 cy_as_ll_destroy_response(dev_p, resp);
2858 cy_as_device_clear_ack_delayed(dev_p);
2859 }
2860
2861 static cy_as_return_status_t
2862 cy_as_usb_ack_setup_packet(cy_as_device_handle handle,
2863 cy_as_function_callback cb,
2864 uint32_t client)
2865 {
2866 cy_as_return_status_t ret;
2867 cy_as_ll_request_response *req_p;
2868 cy_as_ll_request_response *reply_p;
2869 cy_as_func_c_b_node *cbnode;
2870
2871 cy_as_device *dev_p = (cy_as_device *)handle;
2872 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2873 return CY_AS_ERROR_INVALID_HANDLE;
2874
2875 ret = is_usb_active(dev_p);
2876 if (ret != CY_AS_ERROR_SUCCESS)
2877 return ret;
2878
2879 if (cy_as_device_is_in_callback(dev_p) && cb == 0)
2880 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2881
2882 cy_as_hal_assert(cb != 0);
2883
2884 cbnode = cy_as_create_func_c_b_node(cb, client);
2885 if (cbnode == 0)
2886 return CY_AS_ERROR_OUT_OF_MEMORY;
2887
2888 req_p = cy_as_ll_create_request(dev_p, 0,
2889 CY_RQT_USB_RQT_CONTEXT, 2);
2890 if (req_p == 0)
2891 return CY_AS_ERROR_OUT_OF_MEMORY;
2892
2893 reply_p = cy_as_ll_create_response(dev_p, 1);
2894 if (reply_p == 0) {
2895 cy_as_ll_destroy_request(dev_p, req_p);
2896 return CY_AS_ERROR_OUT_OF_MEMORY;
2897 }
2898
2899 cy_as_ll_init_request(req_p, CY_RQT_ACK_SETUP_PACKET,
2900 CY_RQT_USB_RQT_CONTEXT, 1);
2901 cy_as_ll_init_response(reply_p, 1);
2902
2903 req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
2904
2905 cy_as_insert_c_b_node(dev_p->func_cbs_usb, cbnode);
2906
2907 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2908 cy_false, cy_as_usb_ack_callback);
2909
2910 return ret;
2911 }
2912
2913 /*
2914 * Flush all data in logical EP that is being NAK-ed or
2915 * Stall-ed, so that this does not continue to block data
2916 * on other LEPs that use the same physical EP.
2917 */
2918 static void
2919 cy_as_usb_flush_logical_e_p(
2920 cy_as_device *dev_p,
2921 uint16_t ep)
2922 {
2923 uint16_t addr, val, count;
2924
2925 addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
2926 val = cy_as_hal_read_register(dev_p->tag, addr);
2927
2928 while (val) {
2929 count = ((val & 0xFFF) + 1) / 2;
2930 while (count--)
2931 val = cy_as_hal_read_register(dev_p->tag, ep);
2932
2933 cy_as_hal_write_register(dev_p->tag, addr, 0);
2934 val = cy_as_hal_read_register(dev_p->tag, addr);
2935 }
2936 }
2937
2938 static cy_as_return_status_t
2939 cy_as_usb_nak_stall_request(cy_as_device_handle handle,
2940 cy_as_end_point_number_t ep,
2941 uint16_t request,
2942 cy_bool state,
2943 cy_as_usb_function_callback cb,
2944 cy_as_function_callback fcb,
2945 uint32_t client)
2946 {
2947 cy_as_return_status_t ret;
2948 cy_as_ll_request_response *req_p , *reply_p;
2949 uint16_t data;
2950
2951 cy_as_device *dev_p = (cy_as_device *)handle;
2952 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2953 return CY_AS_ERROR_INVALID_HANDLE;
2954
2955 if (cb)
2956 cy_as_hal_assert(fcb == 0);
2957 if (fcb)
2958 cy_as_hal_assert(cb == 0);
2959
2960 ret = is_usb_active(dev_p);
2961 if (ret != CY_AS_ERROR_SUCCESS)
2962 return ret;
2963
2964 if (cy_as_device_is_in_callback(dev_p) && cb == 0 && fcb == 0)
2965 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2966
2967 req_p = cy_as_ll_create_request(dev_p,
2968 request, CY_RQT_USB_RQT_CONTEXT, 2);
2969 if (req_p == 0)
2970 return CY_AS_ERROR_OUT_OF_MEMORY;
2971
2972 /* A single status word response type */
2973 reply_p = cy_as_ll_create_response(dev_p, 1);
2974 if (reply_p == 0) {
2975 cy_as_ll_destroy_request(dev_p, req_p);
2976 return CY_AS_ERROR_OUT_OF_MEMORY;
2977 }
2978
2979 /* Set the endpoint */
2980 data = (uint8_t)ep;
2981 cy_as_ll_request_response__set_word(req_p, 0, data);
2982
2983 /* Set stall state to stalled */
2984 cy_as_ll_request_response__set_word(req_p, 1, (uint8_t)state);
2985
2986 if (cb || fcb) {
2987 void *cbnode;
2988 cy_as_c_b_queue *queue;
2989 if (cb) {
2990 cbnode = cy_as_create_usb_func_c_b_node(cb, client);
2991 queue = dev_p->usb_func_cbs;
2992 } else {
2993 cbnode = cy_as_create_func_c_b_node(fcb, client);
2994 queue = dev_p->func_cbs_usb;
2995 req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
2996 }
2997
2998 if (cbnode == 0) {
2999 ret = CY_AS_ERROR_OUT_OF_MEMORY;
3000 goto destroy;
3001 } else
3002 cy_as_insert_c_b_node(queue, cbnode);
3003
3004
3005 if (cy_as_device_is_setup_packet(dev_p)) {
3006 /* No Ack is needed on a stall request on EP0 */
3007 if ((state == cy_true) && (ep == 0)) {
3008 cy_as_device_set_ep0_stalled(dev_p);
3009 } else {
3010 cy_as_device_set_ack_delayed(dev_p);
3011 req_p->flags |=
3012 CY_AS_REQUEST_RESPONSE_DELAY_ACK;
3013 }
3014 }
3015
3016 ret = cy_as_ll_send_request(dev_p, req_p,
3017 reply_p, cy_false, cy_as_usb_func_callback);
3018 if (ret != CY_AS_ERROR_SUCCESS) {
3019 if (req_p->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
3020 cy_as_device_rem_ack_delayed(dev_p);
3021 cy_as_remove_c_b_tail_node(queue);
3022
3023 goto destroy;
3024 }
3025 } else {
3026 ret = cy_as_ll_send_request_wait_reply(dev_p,
3027 req_p, reply_p);
3028 if (ret != CY_AS_ERROR_SUCCESS)
3029 goto destroy;
3030
3031 if (cy_as_ll_request_response__get_code(reply_p) !=
3032 CY_RESP_SUCCESS_FAILURE) {
3033 ret = CY_AS_ERROR_INVALID_RESPONSE;
3034 goto destroy;
3035 }
3036
3037 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3038
3039 if ((ret == CY_AS_ERROR_SUCCESS) &&
3040 (request == CY_RQT_STALL_ENDPOINT)) {
3041 if ((ep > 1) && (state != 0) &&
3042 (dev_p->usb_config[ep].dir == cy_as_usb_out))
3043 cy_as_usb_flush_logical_e_p(dev_p, ep);
3044 }
3045
3046 destroy:
3047 cy_as_ll_destroy_request(dev_p, req_p);
3048 cy_as_ll_destroy_response(dev_p, reply_p);
3049 }
3050
3051 return ret;
3052 }
3053
3054 static cy_as_return_status_t
3055 my_handle_response_get_stall(cy_as_device *dev_p,
3056 cy_as_ll_request_response *req_p,
3057 cy_as_ll_request_response *reply_p,
3058 cy_bool *state_p)
3059 {
3060 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3061 uint8_t code = cy_as_ll_request_response__get_code(reply_p);
3062
3063 if (code == CY_RESP_SUCCESS_FAILURE) {
3064 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3065 goto destroy;
3066 } else if (code != CY_RESP_ENDPOINT_STALL) {
3067 ret = CY_AS_ERROR_INVALID_RESPONSE;
3068 goto destroy;
3069 }
3070
3071 *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
3072 ret = CY_AS_ERROR_SUCCESS;
3073
3074
3075 destroy:
3076 cy_as_ll_destroy_request(dev_p, req_p);
3077 cy_as_ll_destroy_response(dev_p, reply_p);
3078
3079 return ret;
3080 }
3081
3082 static cy_as_return_status_t
3083 my_handle_response_get_nak(cy_as_device *dev_p,
3084 cy_as_ll_request_response *req_p,
3085 cy_as_ll_request_response *reply_p,
3086 cy_bool *state_p)
3087 {
3088 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3089 uint8_t code = cy_as_ll_request_response__get_code(reply_p);
3090
3091 if (code == CY_RESP_SUCCESS_FAILURE) {
3092 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3093 goto destroy;
3094 } else if (code != CY_RESP_ENDPOINT_NAK) {
3095 ret = CY_AS_ERROR_INVALID_RESPONSE;
3096 goto destroy;
3097 }
3098
3099 *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
3100 ret = CY_AS_ERROR_SUCCESS;
3101
3102
3103 destroy:
3104 cy_as_ll_destroy_request(dev_p, req_p);
3105 cy_as_ll_destroy_response(dev_p, reply_p);
3106
3107 return ret;
3108 }
3109
3110 static cy_as_return_status_t
3111 cy_as_usb_get_nak_stall(cy_as_device_handle handle,
3112 cy_as_end_point_number_t ep,
3113 uint16_t request,
3114 uint16_t response,
3115 cy_bool *state_p,
3116 cy_as_function_callback cb,
3117 uint32_t client)
3118 {
3119 cy_as_return_status_t ret;
3120 cy_as_ll_request_response *req_p , *reply_p;
3121 uint16_t data;
3122
3123 cy_as_device *dev_p = (cy_as_device *)handle;
3124
3125 (void)response;
3126
3127 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3128 return CY_AS_ERROR_INVALID_HANDLE;
3129
3130 ret = is_usb_active(dev_p);
3131 if (ret != CY_AS_ERROR_SUCCESS)
3132 return ret;
3133
3134 if (cy_as_device_is_in_callback(dev_p) && !cb)
3135 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3136
3137 req_p = cy_as_ll_create_request(dev_p, request,
3138 CY_RQT_USB_RQT_CONTEXT, 1);
3139 if (req_p == 0)
3140 return CY_AS_ERROR_OUT_OF_MEMORY;
3141
3142 /* Set the endpoint */
3143 data = (uint8_t)ep;
3144 cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)ep);
3145
3146 /* A single status word response type */
3147 reply_p = cy_as_ll_create_response(dev_p, 1);
3148 if (reply_p == 0) {
3149 cy_as_ll_destroy_request(dev_p, req_p);
3150 return CY_AS_ERROR_OUT_OF_MEMORY;
3151 }
3152
3153 if (cb == 0) {
3154 ret = cy_as_ll_send_request_wait_reply(dev_p,
3155 req_p, reply_p);
3156 if (ret != CY_AS_ERROR_SUCCESS)
3157 goto destroy;
3158
3159 if (request == CY_RQT_GET_STALL)
3160 return my_handle_response_get_stall(dev_p,
3161 req_p, reply_p, state_p);
3162 else
3163 return my_handle_response_get_nak(dev_p,
3164 req_p, reply_p, state_p);
3165
3166 } else {
3167 cy_as_funct_c_b_type type;
3168
3169 if (request == CY_RQT_GET_STALL)
3170 type = CY_FUNCT_CB_USB_GETSTALL;
3171 else
3172 type = CY_FUNCT_CB_USB_GETNAK;
3173
3174 ret = cy_as_misc_send_request(dev_p, cb, client, type,
3175 state_p, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
3176 req_p, reply_p, cy_as_usb_func_callback);
3177
3178 if (ret != CY_AS_ERROR_SUCCESS)
3179 goto destroy;
3180
3181 return ret;
3182 }
3183
3184 destroy:
3185 cy_as_ll_destroy_request(dev_p, req_p);
3186 cy_as_ll_destroy_response(dev_p, reply_p);
3187
3188 return ret;
3189 }
3190
3191 cy_as_return_status_t
3192 cy_as_usb_set_nak(cy_as_device_handle handle,
3193 cy_as_end_point_number_t ep,
3194 cy_as_function_callback cb,
3195 uint32_t client)
3196 {
3197 cy_as_device *dev_p = (cy_as_device *)handle;
3198 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3199 return CY_AS_ERROR_INVALID_HANDLE;
3200
3201 /*
3202 * we send the firmware the EP# with the appropriate direction
3203 * bit, regardless of what the user gave us.
3204 */
3205 ep &= 0x0f;
3206 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3207 ep |= 0x80;
3208
3209 if (dev_p->mtp_count > 0)
3210 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3211
3212 return cy_as_usb_nak_stall_request(handle, ep,
3213 CY_RQT_ENDPOINT_SET_NAK, cy_true, 0, cb, client);
3214 }
3215
3216
3217 cy_as_return_status_t
3218 cy_as_usb_clear_nak(cy_as_device_handle handle,
3219 cy_as_end_point_number_t ep,
3220 cy_as_function_callback cb,
3221 uint32_t client)
3222 {
3223 cy_as_device *dev_p = (cy_as_device *)handle;
3224 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3225 return CY_AS_ERROR_INVALID_HANDLE;
3226
3227 /*
3228 * we send the firmware the EP# with the appropriate
3229 * direction bit, regardless of what the user gave us.
3230 */
3231 ep &= 0x0f;
3232 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3233 ep |= 0x80;
3234
3235 if (dev_p->mtp_count > 0)
3236 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3237
3238 return cy_as_usb_nak_stall_request(handle, ep,
3239 CY_RQT_ENDPOINT_SET_NAK, cy_false, 0, cb, client);
3240 }
3241
3242 cy_as_return_status_t
3243 cy_as_usb_get_nak(cy_as_device_handle handle,
3244 cy_as_end_point_number_t ep,
3245 cy_bool *nak_p,
3246 cy_as_function_callback cb,
3247 uint32_t client)
3248 {
3249 cy_as_device *dev_p = (cy_as_device *)handle;
3250 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3251 return CY_AS_ERROR_INVALID_HANDLE;
3252
3253 /*
3254 * we send the firmware the EP# with the appropriate
3255 * direction bit, regardless of what the user gave us.
3256 */
3257 ep &= 0x0f;
3258 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3259 ep |= 0x80;
3260
3261 if (dev_p->mtp_count > 0)
3262 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3263
3264 return cy_as_usb_get_nak_stall(handle, ep,
3265 CY_RQT_GET_ENDPOINT_NAK, CY_RESP_ENDPOINT_NAK,
3266 nak_p, cb, client);
3267 }
3268
3269
3270 cy_as_return_status_t
3271 cy_as_usb_set_stall(cy_as_device_handle handle,
3272 cy_as_end_point_number_t ep,
3273 cy_as_function_callback cb,
3274 uint32_t client)
3275 {
3276 cy_as_device *dev_p = (cy_as_device *)handle;
3277 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3278 return CY_AS_ERROR_INVALID_HANDLE;
3279
3280 /*
3281 * we send the firmware the EP# with the appropriate
3282 * direction bit, regardless of what the user gave us.
3283 */
3284 ep &= 0x0f;
3285 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3286 ep |= 0x80;
3287
3288 if (dev_p->mtp_turbo_active)
3289 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3290
3291 return cy_as_usb_nak_stall_request(handle, ep,
3292 CY_RQT_STALL_ENDPOINT, cy_true, 0, cb, client);
3293 }
3294
3295 cy_as_return_status_t
3296 cy_as_usb_clear_stall(cy_as_device_handle handle,
3297 cy_as_end_point_number_t ep,
3298 cy_as_function_callback cb,
3299 uint32_t client)
3300 {
3301 cy_as_device *dev_p = (cy_as_device *)handle;
3302 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3303 return CY_AS_ERROR_INVALID_HANDLE;
3304
3305 /*
3306 * we send the firmware the EP# with the appropriate
3307 * direction bit, regardless of what the user gave us.
3308 */
3309 ep &= 0x0f;
3310 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3311 ep |= 0x80;
3312
3313 if (dev_p->mtp_turbo_active)
3314 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3315
3316 return cy_as_usb_nak_stall_request(handle, ep,
3317 CY_RQT_STALL_ENDPOINT, cy_false, 0, cb, client);
3318 }
3319
3320 cy_as_return_status_t
3321 cy_as_usb_get_stall(cy_as_device_handle handle,
3322 cy_as_end_point_number_t ep,
3323 cy_bool *stall_p,
3324 cy_as_function_callback cb,
3325 uint32_t client)
3326 {
3327 cy_as_device *dev_p = (cy_as_device *)handle;
3328 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3329 return CY_AS_ERROR_INVALID_HANDLE;
3330
3331 /*
3332 * we send the firmware the EP# with the appropriate
3333 * direction bit, regardless of what the user gave us.
3334 */
3335 ep &= 0x0f;
3336 if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3337 ep |= 0x80;
3338
3339 if (dev_p->mtp_turbo_active)
3340 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3341
3342 return cy_as_usb_get_nak_stall(handle, ep,
3343 CY_RQT_GET_STALL, CY_RESP_ENDPOINT_STALL, stall_p, cb, client);
3344 }
3345
3346 cy_as_return_status_t
3347 cy_as_usb_signal_remote_wakeup(cy_as_device_handle handle,
3348 cy_as_function_callback cb,
3349 uint32_t client)
3350 {
3351 cy_as_return_status_t ret;
3352 cy_as_ll_request_response *req_p , *reply_p;
3353
3354 cy_as_device *dev_p = (cy_as_device *)handle;
3355 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3356 return CY_AS_ERROR_INVALID_HANDLE;
3357
3358 ret = is_usb_active(dev_p);
3359 if (ret != CY_AS_ERROR_SUCCESS)
3360 return ret;
3361
3362 if (cy_as_device_is_in_callback(dev_p))
3363 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3364
3365 if (dev_p->usb_last_event != cy_as_event_usb_suspend)
3366 return CY_AS_ERROR_NOT_IN_SUSPEND;
3367
3368 req_p = cy_as_ll_create_request(dev_p,
3369 CY_RQT_USB_REMOTE_WAKEUP, CY_RQT_USB_RQT_CONTEXT, 0);
3370 if (req_p == 0)
3371 return CY_AS_ERROR_OUT_OF_MEMORY;
3372
3373 /* A single status word response type */
3374 reply_p = cy_as_ll_create_response(dev_p, 1);
3375 if (reply_p == 0) {
3376 cy_as_ll_destroy_request(dev_p, req_p);
3377 return CY_AS_ERROR_OUT_OF_MEMORY;
3378 }
3379
3380 if (cb == 0) {
3381 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3382 if (ret != CY_AS_ERROR_SUCCESS)
3383 goto destroy;
3384
3385 if (cy_as_ll_request_response__get_code(reply_p) ==
3386 CY_RESP_SUCCESS_FAILURE)
3387 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3388 else
3389 ret = CY_AS_ERROR_INVALID_RESPONSE;
3390 } else {
3391 ret = cy_as_misc_send_request(dev_p, cb, client,
3392 CY_FUNCT_CB_USB_SIGNALREMOTEWAKEUP, 0,
3393 dev_p->func_cbs_usb,
3394 CY_AS_REQUEST_RESPONSE_EX, req_p,
3395 reply_p, cy_as_usb_func_callback);
3396
3397 if (ret != CY_AS_ERROR_SUCCESS)
3398 goto destroy;
3399 return ret;
3400 }
3401
3402 destroy:
3403 cy_as_ll_destroy_request(dev_p, req_p);
3404 cy_as_ll_destroy_response(dev_p, reply_p);
3405
3406 return ret;
3407 }
3408
3409 cy_as_return_status_t
3410 cy_as_usb_set_m_s_report_threshold(cy_as_device_handle handle,
3411 uint32_t wr_sectors,
3412 uint32_t rd_sectors,
3413 cy_as_function_callback cb,
3414 uint32_t client)
3415 {
3416 cy_as_return_status_t ret;
3417 cy_as_ll_request_response *req_p , *reply_p;
3418
3419 cy_as_device *dev_p = (cy_as_device *)handle;
3420 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3421 return CY_AS_ERROR_INVALID_HANDLE;
3422
3423 ret = is_usb_active(dev_p);
3424 if (ret != CY_AS_ERROR_SUCCESS)
3425 return ret;
3426
3427 if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
3428 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3429
3430 /* Check if the firmware version supports this feature. */
3431 if ((dev_p->media_supported[0]) && (dev_p->media_supported[0] ==
3432 (1 << cy_as_media_nand)))
3433 return CY_AS_ERROR_NOT_SUPPORTED;
3434
3435 req_p = cy_as_ll_create_request(dev_p, CY_RQT_USB_STORAGE_MONITOR,
3436 CY_RQT_USB_RQT_CONTEXT, 4);
3437 if (req_p == 0)
3438 return CY_AS_ERROR_OUT_OF_MEMORY;
3439
3440 /* A single status word response type */
3441 reply_p = cy_as_ll_create_response(dev_p, 1);
3442 if (reply_p == 0) {
3443 cy_as_ll_destroy_request(dev_p, req_p);
3444 return CY_AS_ERROR_OUT_OF_MEMORY;
3445 }
3446
3447 /* Set the read and write count parameters into
3448 * the request structure. */
3449 cy_as_ll_request_response__set_word(req_p, 0,
3450 (uint16_t)((wr_sectors >> 16) & 0xFFFF));
3451 cy_as_ll_request_response__set_word(req_p, 1,
3452 (uint16_t)(wr_sectors & 0xFFFF));
3453 cy_as_ll_request_response__set_word(req_p, 2,
3454 (uint16_t)((rd_sectors >> 16) & 0xFFFF));
3455 cy_as_ll_request_response__set_word(req_p, 3,
3456 (uint16_t)(rd_sectors & 0xFFFF));
3457
3458 if (cb == 0) {
3459 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3460 if (ret != CY_AS_ERROR_SUCCESS)
3461 goto destroy;
3462
3463 if (cy_as_ll_request_response__get_code(reply_p) ==
3464 CY_RESP_SUCCESS_FAILURE)
3465 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3466 else
3467 ret = CY_AS_ERROR_INVALID_RESPONSE;
3468 } else {
3469 ret = cy_as_misc_send_request(dev_p, cb, client,
3470 CY_FUNCT_CB_USB_SET_MSREPORT_THRESHOLD, 0,
3471 dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
3472 req_p, reply_p, cy_as_usb_func_callback);
3473
3474 if (ret != CY_AS_ERROR_SUCCESS)
3475 goto destroy;
3476 return ret;
3477 }
3478
3479 destroy:
3480 cy_as_ll_destroy_request(dev_p, req_p);
3481 cy_as_ll_destroy_response(dev_p, reply_p);
3482
3483 return ret;
3484 }
3485
3486 cy_as_return_status_t
3487 cy_as_usb_select_m_s_partitions(
3488 cy_as_device_handle handle,
3489 cy_as_bus_number_t bus,
3490 uint32_t device,
3491 cy_as_usb_m_s_type_t type,
3492 cy_as_function_callback cb,
3493 uint32_t client)
3494 {
3495 cy_as_return_status_t ret;
3496 cy_as_ll_request_response *req_p , *reply_p;
3497 uint16_t val;
3498
3499 cy_as_device *dev_p = (cy_as_device *)handle;
3500 if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3501 return CY_AS_ERROR_INVALID_HANDLE;
3502
3503 ret = is_usb_active(dev_p);
3504 if (ret != CY_AS_ERROR_SUCCESS)
3505 return ret;
3506
3507 /* This API has to be made before SetEnumConfig is called. */
3508 if (dev_p->usb_config[0].enabled)
3509 return CY_AS_ERROR_INVALID_CALL_SEQUENCE;
3510
3511 if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
3512 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3513
3514 req_p = cy_as_ll_create_request(dev_p, CY_RQT_MS_PARTITION_SELECT,
3515 CY_RQT_USB_RQT_CONTEXT, 2);
3516 if (req_p == 0)
3517 return CY_AS_ERROR_OUT_OF_MEMORY;
3518
3519 /* A single status word response type */
3520 reply_p = cy_as_ll_create_response(dev_p, 1);
3521 if (reply_p == 0) {
3522 cy_as_ll_destroy_request(dev_p, req_p);
3523 return CY_AS_ERROR_OUT_OF_MEMORY;
3524 }
3525
3526 /* Set the read and write count parameters into
3527 * the request structure. */
3528 cy_as_ll_request_response__set_word(req_p, 0,
3529 (uint16_t)((bus << 8) | device));
3530
3531 val = 0;
3532 if ((type == cy_as_usb_m_s_unit0) || (type == cy_as_usb_m_s_both))
3533 val |= 1;
3534 if ((type == cy_as_usb_m_s_unit1) || (type == cy_as_usb_m_s_both))
3535 val |= (1 << 8);
3536
3537 cy_as_ll_request_response__set_word(req_p, 1, val);
3538
3539 if (cb == 0) {
3540 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3541 if (ret != CY_AS_ERROR_SUCCESS)
3542 goto destroy;
3543
3544 if (cy_as_ll_request_response__get_code(reply_p) ==
3545 CY_RESP_SUCCESS_FAILURE)
3546 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3547 else
3548 ret = CY_AS_ERROR_INVALID_RESPONSE;
3549 } else {
3550 ret = cy_as_misc_send_request(dev_p, cb, client,
3551 CY_FUNCT_CB_NODATA, 0, dev_p->func_cbs_usb,
3552 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
3553 cy_as_usb_func_callback);
3554
3555 if (ret != CY_AS_ERROR_SUCCESS)
3556 goto destroy;
3557 return ret;
3558 }
3559
3560 destroy:
3561 cy_as_ll_destroy_request(dev_p, req_p);
3562 cy_as_ll_destroy_response(dev_p, reply_p);
3563
3564 return ret;
3565 }
3566
3567 static void
3568 cy_as_usb_func_callback(
3569 cy_as_device *dev_p,
3570 uint8_t context,
3571 cy_as_ll_request_response *rqt,
3572 cy_as_ll_request_response *resp,
3573 cy_as_return_status_t stat)
3574 {
3575 cy_as_usb_func_c_b_node* node = (cy_as_usb_func_c_b_node *)
3576 dev_p->usb_func_cbs->head_p;
3577 cy_as_func_c_b_node* fnode = (cy_as_func_c_b_node *)
3578 dev_p->func_cbs_usb->head_p;
3579 cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3580
3581 cy_as_device_handle h = (cy_as_device_handle)dev_p;
3582 cy_bool delayed_ack = (rqt->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
3583 == CY_AS_REQUEST_RESPONSE_DELAY_ACK;
3584 cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX)
3585 == CY_AS_REQUEST_RESPONSE_EX;
3586 cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS)
3587 == CY_AS_REQUEST_RESPONSE_MS;
3588 uint8_t code;
3589 uint8_t ep, state;
3590
3591 if (!ex_request && !ms_request) {
3592 cy_as_hal_assert(dev_p->usb_func_cbs->count != 0);
3593 cy_as_hal_assert(dev_p->usb_func_cbs->type ==
3594 CYAS_USB_FUNC_CB);
3595 } else {
3596 cy_as_hal_assert(dev_p->func_cbs_usb->count != 0);
3597 cy_as_hal_assert(dev_p->func_cbs_usb->type == CYAS_FUNC_CB);
3598 }
3599
3600 (void)context;
3601
3602 /* The Handlers are responsible for Deleting the rqt and resp when
3603 * they are finished
3604 */
3605 code = cy_as_ll_request_response__get_code(rqt);
3606 switch (code) {
3607 case CY_RQT_START_USB:
3608 ret = my_handle_response_usb_start(dev_p, rqt, resp, stat);
3609 break;
3610 case CY_RQT_STOP_USB:
3611 ret = my_handle_response_usb_stop(dev_p, rqt, resp, stat);
3612 break;
3613 case CY_RQT_SET_CONNECT_STATE:
3614 if (!cy_as_ll_request_response__get_word(rqt, 0))
3615 ret = my_handle_response_disconnect(
3616 dev_p, rqt, resp, stat);
3617 else
3618 ret = my_handle_response_connect(
3619 dev_p, rqt, resp, stat);
3620 break;
3621 case CY_RQT_GET_CONNECT_STATE:
3622 break;
3623 case CY_RQT_SET_USB_CONFIG:
3624 ret = my_handle_response_set_enum_config(dev_p, rqt, resp);
3625 break;
3626 case CY_RQT_GET_USB_CONFIG:
3627 cy_as_hal_assert(fnode->data != 0);
3628 ret = my_handle_response_get_enum_config(dev_p,
3629 rqt, resp, fnode->data);
3630 break;
3631 case CY_RQT_STALL_ENDPOINT:
3632 ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
3633 state = (uint8_t)cy_as_ll_request_response__get_word(rqt, 1);
3634 ret = my_handle_response_no_data(dev_p, rqt, resp);
3635 if ((ret == CY_AS_ERROR_SUCCESS) && (ep > 1) && (state != 0)
3636 && (dev_p->usb_config[ep].dir == cy_as_usb_out))
3637 cy_as_usb_flush_logical_e_p(dev_p, ep);
3638 break;
3639 case CY_RQT_GET_STALL:
3640 cy_as_hal_assert(fnode->data != 0);
3641 ret = my_handle_response_get_stall(dev_p,
3642 rqt, resp, (cy_bool *)fnode->data);
3643 break;
3644 case CY_RQT_SET_DESCRIPTOR:
3645 ret = my_handle_response_no_data(dev_p, rqt, resp);
3646 break;
3647 case CY_RQT_GET_DESCRIPTOR:
3648 cy_as_hal_assert(fnode->data != 0);
3649 ret = my_handle_response_get_descriptor(dev_p,
3650 rqt, resp, (cy_as_get_descriptor_data *)fnode->data);
3651 break;
3652 case CY_RQT_SET_USB_CONFIG_REGISTERS:
3653 ret = my_handle_response_no_data(dev_p, rqt, resp);
3654 if (ret == CY_AS_ERROR_SUCCESS)
3655 ret = cy_as_usb_setup_dma(dev_p);
3656 break;
3657 case CY_RQT_ENDPOINT_SET_NAK:
3658 ret = my_handle_response_no_data(dev_p, rqt, resp);
3659 break;
3660 case CY_RQT_GET_ENDPOINT_NAK:
3661 cy_as_hal_assert(fnode->data != 0);
3662 ret = my_handle_response_get_nak(dev_p,
3663 rqt, resp, (cy_bool *)fnode->data);
3664 break;
3665 case CY_RQT_ACK_SETUP_PACKET:
3666 break;
3667 case CY_RQT_USB_REMOTE_WAKEUP:
3668 ret = my_handle_response_no_data(dev_p, rqt, resp);
3669 break;
3670 case CY_RQT_CLEAR_DESCRIPTORS:
3671 ret = my_handle_response_no_data(dev_p, rqt, resp);
3672 break;
3673 case CY_RQT_USB_STORAGE_MONITOR:
3674 ret = my_handle_response_no_data(dev_p, rqt, resp);
3675 break;
3676 case CY_RQT_MS_PARTITION_SELECT:
3677 ret = my_handle_response_no_data(dev_p, rqt, resp);
3678 break;
3679 default:
3680 ret = CY_AS_ERROR_INVALID_RESPONSE;
3681 cy_as_hal_assert(cy_false);
3682 break;
3683 }
3684
3685 /*
3686 * if the low level layer returns a direct error, use
3687 * the corresponding error code. if not, use the error
3688 * code based on the response from firmware.
3689 */
3690 if (stat == CY_AS_ERROR_SUCCESS)
3691 stat = ret;
3692
3693 if (ex_request || ms_request) {
3694 fnode->cb_p((cy_as_device_handle)dev_p, stat,
3695 fnode->client_data, fnode->data_type, fnode->data);
3696 cy_as_remove_c_b_node(dev_p->func_cbs_usb);
3697 } else {
3698 node->cb_p((cy_as_device_handle)dev_p, stat,
3699 node->client_data);
3700 cy_as_remove_c_b_node(dev_p->usb_func_cbs);
3701 }
3702
3703 if (delayed_ack) {
3704 cy_as_hal_assert(cy_as_device_is_ack_delayed(dev_p));
3705 cy_as_device_rem_ack_delayed(dev_p);
3706
3707 /*
3708 * send the ACK if required.
3709 */
3710 if (!cy_as_device_is_ack_delayed(dev_p))
3711 cy_as_usb_ack_setup_packet(h,
3712 usb_ack_callback, 0);
3713 }
3714 }
3715
3716
3717 /*[]*/