Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-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         media_mask = 0;
1421         for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
1422                 for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++) {
1423                         if (config_p->devices_to_enumerate[bus][device] ==
1424                         cy_true) {
1425                                 bus_mask   |= (0x01 << bus);
1426                                 media_mask |= dev_p->media_supported[bus];
1427                                 media_mask |= dev_p->media_supported[bus];
1428                         }
1429                 }
1430         }
1431
1432         return my_usb_set_enum_config(dev_p, bus_mask, media_mask,
1433                         config_p->antioch_enumeration,
1434                         config_p->mass_storage_interface,
1435                         config_p->mtp_interface,
1436                         config_p->mass_storage_callbacks,
1437                         cb,
1438                         client
1439                 );
1440 }
1441
1442
1443 static cy_as_return_status_t
1444 my_handle_response_get_enum_config(cy_as_device *dev_p,
1445                         cy_as_ll_request_response *req_p,
1446                         cy_as_ll_request_response *reply_p,
1447                         void *config_p)
1448 {
1449         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1450         uint16_t val;
1451         uint8_t bus_mask;
1452         uint32_t bus;
1453
1454         if (cy_as_ll_request_response__get_code(reply_p) !=
1455         CY_RESP_USB_CONFIG) {
1456                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1457                 goto destroy;
1458         }
1459
1460         /* Marshal the reply */
1461         if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) {
1462                 uint32_t device;
1463                 cy_bool state;
1464                 cy_as_usb_enum_control *ms_config_p =
1465                         (cy_as_usb_enum_control *)config_p;
1466
1467                 bus_mask = (uint8_t)
1468                         (cy_as_ll_request_response__get_word
1469                         (reply_p, 0) & 0xFF);
1470                 for (bus = 0; bus < CY_AS_MAX_BUSES; bus++)  {
1471                         if (bus_mask & (1 << bus))
1472                                 state = cy_true;
1473                         else
1474                                 state = cy_false;
1475
1476                         for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES;
1477                                 device++)
1478                                 ms_config_p->devices_to_enumerate[bus][device]
1479                                         = state;
1480                 }
1481
1482                 ms_config_p->antioch_enumeration =
1483                         (cy_bool)cy_as_ll_request_response__get_word
1484                                 (reply_p, 1);
1485
1486                 val = cy_as_ll_request_response__get_word(reply_p, 2);
1487                 if (dev_p->is_mtp_firmware) {
1488                         ms_config_p->mass_storage_interface = 0;
1489                         ms_config_p->mtp_interface = (uint8_t)(val & 0xFF);
1490                 } else {
1491                         ms_config_p->mass_storage_interface =
1492                                 (uint8_t)(val & 0xFF);
1493                         ms_config_p->mtp_interface = 0;
1494                 }
1495                 ms_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
1496
1497                 /*
1498                 * firmware returns an invalid interface number for mass storage,
1499                 * if mass storage is not enabled. this needs to be converted to
1500                 * zero to match the input configuration.
1501                 */
1502                 if (bus_mask == 0) {
1503                         if (dev_p->is_mtp_firmware)
1504                                 ms_config_p->mtp_interface = 0;
1505                         else
1506                                 ms_config_p->mass_storage_interface = 0;
1507                 }
1508         } else {
1509                 cy_as_usb_enum_control_dep *ex_config_p =
1510                         (cy_as_usb_enum_control_dep *)config_p;
1511
1512                 ex_config_p->enum_mass_storage = (uint8_t)
1513                         ((cy_as_ll_request_response__get_word
1514                                 (reply_p, 0) >> 8) & 0xFF);
1515                 ex_config_p->antioch_enumeration = (cy_bool)
1516                         cy_as_ll_request_response__get_word(reply_p, 1);
1517
1518                 val = cy_as_ll_request_response__get_word(reply_p, 2);
1519                 ex_config_p->mass_storage_interface = (uint8_t)(val & 0xFF);
1520                 ex_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
1521
1522                 /*
1523                 * firmware returns an invalid interface number for mass
1524                 * storage, if mass storage is not enabled. this needs to
1525                 * be converted to zero to match the input configuration.
1526                 */
1527                 if (ex_config_p->enum_mass_storage == 0)
1528                         ex_config_p->mass_storage_interface = 0;
1529         }
1530
1531 destroy:
1532         cy_as_ll_destroy_request(dev_p, req_p);
1533         cy_as_ll_destroy_response(dev_p, reply_p);
1534
1535         return ret;
1536 }
1537
1538 /*
1539 * This sets up the request for the enumerateion configuration
1540 * information, based on if the request is from the old pre-1.2
1541 * functions.
1542 */
1543 static cy_as_return_status_t
1544 my_usb_get_enum_config(cy_as_device_handle handle,
1545                                         uint16_t req_flags,
1546                                         void *config_p,
1547                                         cy_as_function_callback cb,
1548                                         uint32_t client)
1549 {
1550         cy_as_ll_request_response *req_p , *reply_p;
1551         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1552
1553         cy_as_device *dev_p;
1554
1555         cy_as_log_debug_message(6, "cy_as_usb_get_enum_config called");
1556
1557         dev_p = (cy_as_device *)handle;
1558         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1559                 return CY_AS_ERROR_INVALID_HANDLE;
1560
1561         ret = is_usb_active(dev_p);
1562         if (ret != CY_AS_ERROR_SUCCESS)
1563                 return ret;
1564
1565         if (cy_as_device_is_in_callback(dev_p))
1566                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1567
1568         /* Create the request to send to the West Bridge device */
1569         req_p = cy_as_ll_create_request(dev_p,
1570                 CY_RQT_GET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 0);
1571         if (req_p == 0)
1572                 return CY_AS_ERROR_OUT_OF_MEMORY;
1573
1574         /* Reserve space for the reply, the reply data
1575          * will not exceed two bytes */
1576         reply_p = cy_as_ll_create_response(dev_p, 3);
1577         if (reply_p == 0) {
1578                 cy_as_ll_destroy_request(dev_p, req_p);
1579                 return CY_AS_ERROR_OUT_OF_MEMORY;
1580         }
1581
1582         if (cb == 0) {
1583                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1584                 if (ret != CY_AS_ERROR_SUCCESS)
1585                         goto destroy;
1586
1587                 /* we need to know the type of request to
1588                  * know how to manage the data */
1589                 req_p->flags |= req_flags;
1590                 return my_handle_response_get_enum_config(dev_p,
1591                         req_p, reply_p, config_p);
1592         } else {
1593                 ret = cy_as_misc_send_request(dev_p, cb, client,
1594                         CY_FUNCT_CB_USB_GETENUMCONFIG, config_p,
1595                         dev_p->func_cbs_usb, req_flags, req_p, reply_p,
1596                         cy_as_usb_func_callback);
1597
1598                 if (ret != CY_AS_ERROR_SUCCESS)
1599                         goto destroy;
1600
1601                 return ret;
1602         }
1603
1604 destroy:
1605         cy_as_ll_destroy_request(dev_p, req_p);
1606         cy_as_ll_destroy_response(dev_p, reply_p);
1607
1608         return ret;
1609 }
1610
1611 /*
1612  * This method returns the enumerateion configuration information
1613  * from the West Bridge device. Generally this is not used by
1614  * client software but is provided mostly for debug information.
1615  * We want a method to read all state information from the device.
1616  */
1617 cy_as_return_status_t
1618 cy_as_usb_get_enum_config(cy_as_device_handle handle,
1619                                            cy_as_usb_enum_control *config_p,
1620                                            cy_as_function_callback cb,
1621                                            uint32_t client)
1622 {
1623         return my_usb_get_enum_config(handle,
1624                 CY_AS_REQUEST_RESPONSE_MS, config_p, cb, client);
1625 }
1626
1627
1628 /*
1629 * This method sets the USB descriptor for a given entity.
1630 */
1631 cy_as_return_status_t
1632 cy_as_usb_set_descriptor(cy_as_device_handle handle,
1633                                            cy_as_usb_desc_type type,
1634                                            uint8_t index,
1635                                            void *desc_p,
1636                                            uint16_t length,
1637                                            cy_as_function_callback cb,
1638                                            uint32_t client)
1639 {
1640         cy_as_ll_request_response *req_p , *reply_p;
1641         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1642         uint16_t pktlen;
1643
1644         cy_as_device *dev_p;
1645
1646         cy_as_log_debug_message(6, "cy_as_usb_set_descriptor called");
1647
1648         dev_p = (cy_as_device *)handle;
1649         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1650                 return CY_AS_ERROR_INVALID_HANDLE;
1651
1652         ret = is_usb_active(dev_p);
1653         if (ret != CY_AS_ERROR_SUCCESS)
1654                 return ret;
1655
1656         if (cy_as_device_is_in_callback(dev_p))
1657                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1658
1659         if (length > CY_AS_MAX_USB_DESCRIPTOR_SIZE)
1660                 return CY_AS_ERROR_INVALID_DESCRIPTOR;
1661
1662         pktlen = (uint16_t)length / 2;
1663         if (length % 2)
1664                 pktlen++;
1665         pktlen += 2; /* 1 for type, 1 for length */
1666
1667         /* Create the request to send to the West Bridge device */
1668         req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_DESCRIPTOR,
1669                 CY_RQT_USB_RQT_CONTEXT, (uint16_t)pktlen);
1670         if (req_p == 0)
1671                 return CY_AS_ERROR_OUT_OF_MEMORY;
1672
1673         cy_as_ll_request_response__set_word(req_p, 0,
1674                 (uint16_t)((uint8_t)type | (index << 8)));
1675         cy_as_ll_request_response__set_word(req_p, 1,
1676                 (uint16_t)length);
1677         cy_as_ll_request_response__pack(req_p, 2, length, desc_p);
1678
1679         reply_p = cy_as_ll_create_response(dev_p, 1);
1680         if (reply_p == 0) {
1681                 cy_as_ll_destroy_request(dev_p, req_p);
1682                 return CY_AS_ERROR_OUT_OF_MEMORY;
1683         }
1684
1685         if (cb == 0) {
1686                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1687                 if (ret != CY_AS_ERROR_SUCCESS)
1688                         goto destroy;
1689
1690                 return my_handle_response_no_data(dev_p, req_p, reply_p);
1691         } else {
1692                 ret = cy_as_misc_send_request(dev_p, cb, client,
1693                         CY_FUNCT_CB_USB_SETDESCRIPTOR, 0, dev_p->func_cbs_usb,
1694                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1695                         cy_as_usb_func_callback);
1696
1697                 if (ret != CY_AS_ERROR_SUCCESS)
1698                         goto destroy;
1699
1700                 return ret;
1701         }
1702
1703 destroy:
1704         cy_as_ll_destroy_request(dev_p, req_p);
1705         cy_as_ll_destroy_response(dev_p, reply_p);
1706
1707         return ret;
1708 }
1709
1710 /*
1711  * This method clears all descriptors that were previously
1712  * stored on the West Bridge through CyAsUsbSetDescriptor calls.
1713  */
1714 cy_as_return_status_t
1715 cy_as_usb_clear_descriptors(cy_as_device_handle handle,
1716                                            cy_as_function_callback cb,
1717                                            uint32_t client)
1718 {
1719         cy_as_ll_request_response *req_p , *reply_p;
1720         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1721
1722         cy_as_device *dev_p;
1723
1724         cy_as_log_debug_message(6, "cy_as_usb_clear_descriptors called");
1725
1726         dev_p = (cy_as_device *)handle;
1727         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1728                 return CY_AS_ERROR_INVALID_HANDLE;
1729
1730         ret = is_usb_active(dev_p);
1731         if (ret != CY_AS_ERROR_SUCCESS)
1732                 return ret;
1733
1734         if ((cy_as_device_is_in_callback(dev_p)) && (cb == 0))
1735                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1736
1737         /* Create the request to send to the West Bridge device */
1738         req_p = cy_as_ll_create_request(dev_p,
1739                 CY_RQT_CLEAR_DESCRIPTORS, CY_RQT_USB_RQT_CONTEXT, 1);
1740         if (req_p == 0)
1741                 return CY_AS_ERROR_OUT_OF_MEMORY;
1742
1743         reply_p = cy_as_ll_create_response(dev_p, 1);
1744         if (reply_p == 0) {
1745                 cy_as_ll_destroy_request(dev_p, req_p);
1746                 return CY_AS_ERROR_OUT_OF_MEMORY;
1747         }
1748
1749         if (cb == 0) {
1750
1751                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1752                 if (ret != CY_AS_ERROR_SUCCESS)
1753                         goto destroy;
1754
1755                 return my_handle_response_no_data(dev_p, req_p, reply_p);
1756         } else {
1757                 ret = cy_as_misc_send_request(dev_p, cb, client,
1758                         CY_FUNCT_CB_USB_CLEARDESCRIPTORS, 0,
1759                         dev_p->func_cbs_usb,
1760                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1761                         cy_as_usb_func_callback);
1762
1763                 if (ret != CY_AS_ERROR_SUCCESS)
1764                         goto destroy;
1765
1766                 return ret;
1767         }
1768
1769 destroy:
1770         cy_as_ll_destroy_request(dev_p, req_p);
1771         cy_as_ll_destroy_response(dev_p, reply_p);
1772
1773         return ret;
1774 }
1775
1776 static cy_as_return_status_t
1777 my_handle_response_get_descriptor(cy_as_device *dev_p,
1778                                         cy_as_ll_request_response *req_p,
1779                                         cy_as_ll_request_response *reply_p,
1780                                         cy_as_get_descriptor_data *data)
1781 {
1782         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1783          uint32_t retlen;
1784
1785         if (cy_as_ll_request_response__get_code(reply_p) ==
1786         CY_RESP_SUCCESS_FAILURE) {
1787                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1788                 goto destroy;
1789         } else if (cy_as_ll_request_response__get_code(reply_p) !=
1790         CY_RESP_USB_DESCRIPTOR) {
1791                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1792                 goto destroy;
1793         }
1794
1795         retlen = cy_as_ll_request_response__get_word(reply_p, 0);
1796         if (retlen > data->length) {
1797                 ret = CY_AS_ERROR_INVALID_SIZE;
1798                 goto destroy;
1799         }
1800
1801         ret = CY_AS_ERROR_SUCCESS;
1802         cy_as_ll_request_response__unpack(reply_p, 1,
1803                 retlen, data->desc_p);
1804
1805 destroy:
1806                 cy_as_ll_destroy_request(dev_p, req_p);
1807                 cy_as_ll_destroy_response(dev_p, reply_p);
1808
1809                 return ret;
1810 }
1811
1812 /*
1813 * This method retreives the USB descriptor for a given type.
1814 */
1815 cy_as_return_status_t
1816 cy_as_usb_get_descriptor(cy_as_device_handle handle,
1817                                            cy_as_usb_desc_type type,
1818                                            uint8_t index,
1819                                            cy_as_get_descriptor_data *data,
1820                                            cy_as_function_callback cb,
1821                                            uint32_t client)
1822 {
1823         cy_as_return_status_t ret;
1824         cy_as_ll_request_response *req_p , *reply_p;
1825
1826         cy_as_device *dev_p;
1827
1828         cy_as_log_debug_message(6, "cy_as_usb_get_descriptor called");
1829
1830         dev_p = (cy_as_device *)handle;
1831         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1832                 return CY_AS_ERROR_INVALID_HANDLE;
1833
1834         ret = is_usb_active(dev_p);
1835         if (ret != CY_AS_ERROR_SUCCESS)
1836                 return ret;
1837
1838         if (cy_as_device_is_in_callback(dev_p))
1839                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1840
1841         /* Create the request to send to the West Bridge device */
1842         req_p = cy_as_ll_create_request(dev_p,
1843                 CY_RQT_GET_DESCRIPTOR, CY_RQT_USB_RQT_CONTEXT, 1);
1844         if (req_p == 0)
1845                 return CY_AS_ERROR_OUT_OF_MEMORY;
1846
1847         cy_as_ll_request_response__set_word(req_p, 0,
1848                 (uint16_t)((uint8_t)type | (index << 8)));
1849
1850         /* Add one for the length field */
1851         reply_p = cy_as_ll_create_response(dev_p,
1852                 CY_AS_MAX_USB_DESCRIPTOR_SIZE + 1);
1853         if (reply_p == 0) {
1854                 cy_as_ll_destroy_request(dev_p, req_p);
1855                 return CY_AS_ERROR_OUT_OF_MEMORY;
1856         }
1857
1858         if (cb == 0) {
1859                 ret = cy_as_ll_send_request_wait_reply(
1860                                 dev_p, req_p, reply_p);
1861                 if (ret != CY_AS_ERROR_SUCCESS)
1862                         goto destroy;
1863
1864                 return my_handle_response_get_descriptor(dev_p,
1865                         req_p, reply_p, data);
1866         } else {
1867                 ret = cy_as_misc_send_request(dev_p, cb, client,
1868                         CY_FUNCT_CB_USB_GETDESCRIPTOR, data,
1869                         dev_p->func_cbs_usb,
1870                         CY_AS_REQUEST_RESPONSE_EX, req_p,
1871                         reply_p,  cy_as_usb_func_callback);
1872
1873                 if (ret != CY_AS_ERROR_SUCCESS)
1874                         goto destroy;
1875
1876                 return ret;
1877         }
1878
1879 destroy:
1880         cy_as_ll_destroy_request(dev_p, req_p);
1881         cy_as_ll_destroy_response(dev_p, reply_p);
1882
1883         return ret;
1884 }
1885
1886 cy_as_return_status_t
1887 cy_as_usb_set_physical_configuration(cy_as_device_handle handle,
1888         uint8_t config)
1889 {
1890         cy_as_return_status_t ret;
1891         cy_as_device *dev_p;
1892
1893         cy_as_log_debug_message(6,
1894                 "cy_as_usb_set_physical_configuration called");
1895
1896         dev_p = (cy_as_device *)handle;
1897         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1898                 return CY_AS_ERROR_INVALID_HANDLE;
1899
1900         ret = is_usb_active(dev_p);
1901         if (ret != CY_AS_ERROR_SUCCESS)
1902                 return ret;
1903
1904         if (cy_as_device_is_usb_connected(dev_p))
1905                 return CY_AS_ERROR_USB_CONNECTED;
1906
1907         if (config < 1 || config > 12)
1908                 return CY_AS_ERROR_INVALID_CONFIGURATION;
1909
1910         dev_p->usb_phy_config = config;
1911
1912         return CY_AS_ERROR_SUCCESS;
1913 }
1914
1915 static cy_bool
1916 is_physical_valid(uint8_t config, cy_as_end_point_number_t ep)
1917 {
1918         static uint8_t validmask[12] = {
1919                 0x0f,      /* Config  1 - 1, 2, 3, 4 */
1920                 0x07,      /* Config  2 - 1, 2, 3 */
1921                 0x07,      /* Config  3 - 1, 2, 3 */
1922                 0x0d,      /* Config  4 - 1, 3, 4 */
1923                 0x05,      /* Config  5 - 1, 3 */
1924                 0x05,      /* Config  6 - 1, 3 */
1925                 0x0d,      /* Config  7 - 1, 3, 4 */
1926                 0x05,      /* Config  8 - 1, 3 */
1927                 0x05,      /* Config  9 - 1, 3 */
1928                 0x0d,      /* Config 10 - 1, 3, 4 */
1929                 0x09,      /* Config 11 - 1, 4 */
1930                 0x01            /* Config 12 - 1 */
1931         };
1932
1933         return (validmask[config - 1] & (1 << (ep - 1))) ? cy_true : cy_false;
1934 }
1935
1936 /*
1937 * This method sets the configuration for an endpoint
1938 */
1939 cy_as_return_status_t
1940 cy_as_usb_set_end_point_config(cy_as_device_handle handle,
1941         cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
1942 {
1943         cy_as_return_status_t ret;
1944         cy_as_device *dev_p;
1945
1946         cy_as_log_debug_message(6, "cy_as_usb_set_end_point_config called");
1947
1948         dev_p = (cy_as_device *)handle;
1949         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1950                 return CY_AS_ERROR_INVALID_HANDLE;
1951
1952         ret = is_usb_active(dev_p);
1953         if (ret != CY_AS_ERROR_SUCCESS)
1954                 return ret;
1955
1956         if (cy_as_device_is_usb_connected(dev_p))
1957                 return CY_AS_ERROR_USB_CONNECTED;
1958
1959         if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
1960                 return CY_AS_ERROR_INVALID_ENDPOINT;
1961
1962         if (ep == 0) {
1963                 /* Endpoint 0 must be 64 byte, dir IN/OUT,
1964                  * and control type */
1965                 if (config_p->dir != cy_as_usb_in_out ||
1966                         config_p->type != cy_as_usb_control)
1967                         return CY_AS_ERROR_INVALID_CONFIGURATION;
1968         } else if (ep == 1) {
1969                 if ((dev_p->is_mtp_firmware == 1) &&
1970                 (dev_p->usb_config[1].enabled == cy_true)) {
1971                         return CY_AS_ERROR_INVALID_ENDPOINT;
1972                 }
1973
1974                 /*
1975                  * EP1 can only be used either as an OUT ep, or as an IN ep.
1976                  */
1977                 if ((config_p->type == cy_as_usb_control) ||
1978                         (config_p->type == cy_as_usb_iso) ||
1979                         (config_p->dir == cy_as_usb_in_out))
1980                         return CY_AS_ERROR_INVALID_CONFIGURATION;
1981         } else {
1982                 if (config_p->dir == cy_as_usb_in_out ||
1983                         config_p->type == cy_as_usb_control)
1984                         return CY_AS_ERROR_INVALID_CONFIGURATION;
1985
1986                 if (!is_physical_valid(dev_p->usb_phy_config,
1987                         config_p->physical))
1988                         return CY_AS_ERROR_INVALID_PHYSICAL_ENDPOINT;
1989
1990                 /*
1991                 * ISO endpoints must be on E_ps 3, 5, 7 or 9 as
1992                 * they need to align directly with the underlying
1993                 * physical endpoint.
1994                 */
1995                 if (config_p->type == cy_as_usb_iso) {
1996                         if (ep != 3 && ep != 5 && ep != 7 && ep != 9)
1997                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
1998
1999                         if (ep == 3 && config_p->physical != 1)
2000                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2001
2002                         if (ep == 5 && config_p->physical != 2)
2003                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2004
2005                         if (ep == 7 && config_p->physical != 3)
2006                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2007
2008                         if (ep == 9 && config_p->physical != 4)
2009                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2010                 }
2011         }
2012
2013         /* Store the configuration information until a
2014          * CyAsUsbCommitConfig is done */
2015         dev_p->usb_config[ep] = *config_p;
2016
2017         /* If the endpoint is enabled, enable DMA associated
2018          * with the endpoint */
2019         /*
2020         * we make some assumptions that we check here.  we assume
2021         * that the direction fields for the DMA module are the same
2022         * values as the direction values for the USB module.
2023         */
2024         cy_as_hal_assert((int)cy_as_usb_in == (int)cy_as_direction_in);
2025         cy_as_hal_assert((int)cy_as_usb_out == (int)cy_as_direction_out);
2026         cy_as_hal_assert((int)cy_as_usb_in_out == (int)cy_as_direction_in_out);
2027
2028         return cy_as_dma_enable_end_point(dev_p, ep,
2029                 config_p->enabled, (cy_as_dma_direction)config_p->dir);
2030 }
2031
2032 cy_as_return_status_t
2033 cy_as_usb_get_end_point_config(cy_as_device_handle handle,
2034         cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
2035 {
2036         cy_as_return_status_t ret;
2037
2038         cy_as_device *dev_p;
2039
2040         cy_as_log_debug_message(6, "cy_as_usb_get_end_point_config called");
2041
2042         dev_p = (cy_as_device *)handle;
2043         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2044                 return CY_AS_ERROR_INVALID_HANDLE;
2045
2046         ret = is_usb_active(dev_p);
2047         if (ret != CY_AS_ERROR_SUCCESS)
2048                 return ret;
2049
2050         if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
2051                 return CY_AS_ERROR_INVALID_ENDPOINT;
2052
2053         *config_p = dev_p->usb_config[ep];
2054
2055         return CY_AS_ERROR_SUCCESS;
2056 }
2057
2058 /*
2059 * Commit the configuration of the various endpoints to the hardware.
2060 */
2061 cy_as_return_status_t
2062 cy_as_usb_commit_config(cy_as_device_handle handle,
2063                                           cy_as_function_callback cb,
2064                                           uint32_t client)
2065 {
2066         uint32_t i;
2067         cy_as_return_status_t ret;
2068         cy_as_ll_request_response *req_p , *reply_p;
2069         cy_as_device *dev_p;
2070         uint16_t data;
2071
2072         cy_as_log_debug_message(6, "cy_as_usb_commit_config called");
2073
2074         dev_p = (cy_as_device *)handle;
2075         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2076                 return CY_AS_ERROR_INVALID_HANDLE;
2077
2078         ret = is_usb_active(dev_p);
2079         if (ret != CY_AS_ERROR_SUCCESS)
2080                 return ret;
2081
2082         if (cy_as_device_is_usb_connected(dev_p))
2083                 return CY_AS_ERROR_USB_CONNECTED;
2084
2085         if (cy_as_device_is_in_callback(dev_p))
2086                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2087
2088         /*
2089         * this performs the mapping based on informatation that was
2090         * previously stored on the device about the various endpoints
2091         * and how they are configured. the output of this mapping is
2092         * setting the the 14 register values contained in usb_lepcfg
2093         * and usb_pepcfg
2094         */
2095         ret = cy_as_usb_map_logical2_physical(dev_p);
2096         if (ret != CY_AS_ERROR_SUCCESS)
2097                 return ret;
2098
2099         /*
2100         * now, package the information about the various logical and
2101         * physical endpoint configuration registers and send it
2102         * across to the west bridge device.
2103         */
2104         req_p = cy_as_ll_create_request(dev_p,
2105                 CY_RQT_SET_USB_CONFIG_REGISTERS, CY_RQT_USB_RQT_CONTEXT, 8);
2106         if (req_p == 0)
2107                 return CY_AS_ERROR_OUT_OF_MEMORY;
2108
2109         cy_as_hal_print_message("USB configuration: %d\n",
2110                 dev_p->usb_phy_config);
2111         cy_as_hal_print_message("EP1OUT: 0x%02x EP1IN: 0x%02x\n",
2112                 dev_p->usb_ep1cfg[0], dev_p->usb_ep1cfg[1]);
2113         cy_as_hal_print_message("PEP registers: 0x%02x 0x%02x 0x%02x 0x%02x\n",
2114                 dev_p->usb_pepcfg[0], dev_p->usb_pepcfg[1],
2115                 dev_p->usb_pepcfg[2], dev_p->usb_pepcfg[3]);
2116
2117         cy_as_hal_print_message("LEP registers: 0x%02x 0x%02x 0x%02x "
2118                 "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
2119                 dev_p->usb_lepcfg[0], dev_p->usb_lepcfg[1],
2120                 dev_p->usb_lepcfg[2], dev_p->usb_lepcfg[3],
2121                 dev_p->usb_lepcfg[4], dev_p->usb_lepcfg[5],
2122                 dev_p->usb_lepcfg[6], dev_p->usb_lepcfg[7],
2123                 dev_p->usb_lepcfg[8], dev_p->usb_lepcfg[9]);
2124
2125         /* Write the EP1OUTCFG and EP1INCFG data in the first word. */
2126         data = (uint16_t)((dev_p->usb_ep1cfg[0] << 8) |
2127                 dev_p->usb_ep1cfg[1]);
2128         cy_as_ll_request_response__set_word(req_p, 0, data);
2129
2130         /* Write the PEP CFG data in the next 2 words */
2131         for (i = 0; i < 4; i += 2) {
2132                 data = (uint16_t)((dev_p->usb_pepcfg[i] << 8) |
2133                         dev_p->usb_pepcfg[i + 1]);
2134                 cy_as_ll_request_response__set_word(req_p,
2135                         1 + i / 2, data);
2136         }
2137
2138         /* Write the LEP CFG data in the next 5 words */
2139         for (i = 0; i < 10; i += 2) {
2140                 data = (uint16_t)((dev_p->usb_lepcfg[i] << 8) |
2141                         dev_p->usb_lepcfg[i + 1]);
2142                 cy_as_ll_request_response__set_word(req_p,
2143                         3 + i / 2, data);
2144         }
2145
2146         /* A single status word response type */
2147         reply_p = cy_as_ll_create_response(dev_p, 1);
2148         if (reply_p == 0) {
2149                 cy_as_ll_destroy_request(dev_p, req_p);
2150                 return CY_AS_ERROR_OUT_OF_MEMORY;
2151         }
2152
2153         if (cb == 0) {
2154                 ret = cy_as_ll_send_request_wait_reply(dev_p,
2155                         req_p, reply_p);
2156                 if (ret != CY_AS_ERROR_SUCCESS)
2157                         goto destroy;
2158
2159                 ret = my_handle_response_no_data(dev_p,
2160                         req_p, reply_p);
2161
2162                 if (ret == CY_AS_ERROR_SUCCESS)
2163                         ret = cy_as_usb_setup_dma(dev_p);
2164
2165                 return ret;
2166         } else {
2167                 ret = cy_as_misc_send_request(dev_p, cb, client,
2168                         CY_FUNCT_CB_USB_COMMITCONFIG, 0, dev_p->func_cbs_usb,
2169                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
2170                         cy_as_usb_func_callback);
2171
2172                 if (ret != CY_AS_ERROR_SUCCESS)
2173                         goto destroy;
2174
2175                 return ret;
2176         }
2177
2178 destroy:
2179         cy_as_ll_destroy_request(dev_p, req_p);
2180         cy_as_ll_destroy_response(dev_p, reply_p);
2181
2182         return ret;
2183 }
2184
2185 static void
2186 sync_request_callback(cy_as_device *dev_p,
2187         cy_as_end_point_number_t ep, void *buf_p,
2188         uint32_t size, cy_as_return_status_t err)
2189 {
2190         (void)ep;
2191         (void)buf_p;
2192
2193         dev_p->usb_error = err;
2194         dev_p->usb_actual_cnt = size;
2195 }
2196
2197 static void
2198 async_read_request_callback(cy_as_device *dev_p,
2199         cy_as_end_point_number_t ep, void *buf_p,
2200         uint32_t size, cy_as_return_status_t err)
2201 {
2202         cy_as_device_handle h;
2203
2204         cy_as_log_debug_message(6,
2205                 "async_read_request_callback called");
2206
2207         h = (cy_as_device_handle)dev_p;
2208
2209         if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
2210                 dev_p->usb_pending_buffer = buf_p;
2211                 dev_p->usb_pending_size = size;
2212                 dev_p->usb_error = err;
2213                 cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
2214         } else {
2215                 cy_as_usb_io_callback cb;
2216
2217                 cb = dev_p->usb_cb[ep];
2218                 dev_p->usb_cb[ep] = 0;
2219                 cy_as_device_clear_usb_async_pending(dev_p, ep);
2220                 if (cb)
2221                         cb(h, ep, size, buf_p, err);
2222         }
2223 }
2224
2225 static void
2226 async_write_request_callback(cy_as_device *dev_p,
2227         cy_as_end_point_number_t ep, void *buf_p,
2228         uint32_t size, cy_as_return_status_t err)
2229 {
2230         cy_as_device_handle h;
2231
2232         cy_as_log_debug_message(6,
2233                 "async_write_request_callback called");
2234
2235         h = (cy_as_device_handle)dev_p;
2236
2237         if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
2238                 dev_p->usb_pending_buffer = buf_p;
2239                 dev_p->usb_pending_size = size;
2240                 dev_p->usb_error = err;
2241
2242                 /* The west bridge protocol generates ZLPs as required. */
2243                 cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
2244         } else {
2245                 cy_as_usb_io_callback cb;
2246
2247                 cb = dev_p->usb_cb[ep];
2248                 dev_p->usb_cb[ep] = 0;
2249
2250                 cy_as_device_clear_usb_async_pending(dev_p, ep);
2251                 if (cb)
2252                         cb(h, ep, size, buf_p, err);
2253         }
2254 }
2255
2256 static void
2257 my_turbo_rqt_callback(cy_as_device *dev_p,
2258                                         uint8_t context,
2259                                         cy_as_ll_request_response *rqt,
2260                                         cy_as_ll_request_response *resp,
2261                                         cy_as_return_status_t stat)
2262 {
2263         uint8_t code;
2264
2265         (void)context;
2266         (void)stat;
2267
2268         /* The Handlers are responsible for Deleting the rqt and resp when
2269          * they are finished
2270          */
2271         code = cy_as_ll_request_response__get_code(rqt);
2272         switch (code) {
2273         case CY_RQT_TURBO_SWITCH_ENDPOINT:
2274                 cy_as_hal_assert(stat == CY_AS_ERROR_SUCCESS);
2275                 cy_as_ll_destroy_request(dev_p, rqt);
2276                 cy_as_ll_destroy_response(dev_p, resp);
2277                 break;
2278         default:
2279                 cy_as_hal_assert(cy_false);
2280                 break;
2281         }
2282 }
2283
2284 /* Send a mailbox request to prepare the endpoint for switching */
2285 static cy_as_return_status_t
2286 my_send_turbo_switch(cy_as_device *dev_p, uint32_t size, cy_bool pktread)
2287 {
2288         cy_as_return_status_t ret;
2289         cy_as_ll_request_response *req_p , *reply_p;
2290
2291         /* Create the request to send to the West Bridge device */
2292         req_p = cy_as_ll_create_request(dev_p,
2293                 CY_RQT_TURBO_SWITCH_ENDPOINT, CY_RQT_TUR_RQT_CONTEXT, 3);
2294         if (req_p == 0)
2295                 return CY_AS_ERROR_OUT_OF_MEMORY;
2296
2297         /* Reserve space for the reply, the reply data will
2298          * not exceed one word */
2299         reply_p = cy_as_ll_create_response(dev_p, 1);
2300         if (reply_p == 0) {
2301                 cy_as_ll_destroy_request(dev_p, req_p);
2302                 return CY_AS_ERROR_OUT_OF_MEMORY;
2303         }
2304
2305         cy_as_ll_request_response__set_word(req_p, 0,
2306                 (uint16_t)pktread);
2307         cy_as_ll_request_response__set_word(req_p, 1,
2308                 (uint16_t)((size >> 16) & 0xFFFF));
2309         cy_as_ll_request_response__set_word(req_p, 2,
2310                 (uint16_t)(size & 0xFFFF));
2311
2312         ret = cy_as_ll_send_request(dev_p, req_p,
2313                 reply_p, cy_false, my_turbo_rqt_callback);
2314         if (ret != CY_AS_ERROR_SUCCESS) {
2315                 cy_as_ll_destroy_request(dev_p, req_p);
2316                 cy_as_ll_destroy_request(dev_p, reply_p);
2317                 return ret;
2318         }
2319
2320         return CY_AS_ERROR_SUCCESS;
2321 }
2322
2323 cy_as_return_status_t
2324 cy_as_usb_read_data(cy_as_device_handle handle,
2325         cy_as_end_point_number_t ep, cy_bool pktread,
2326         uint32_t dsize, uint32_t *dataread, void *data)
2327 {
2328         cy_as_return_status_t ret;
2329         cy_as_device *dev_p;
2330
2331         cy_as_log_debug_message(6, "cy_as_usb_read_data called");
2332
2333         dev_p = (cy_as_device *)handle;
2334         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2335                 return CY_AS_ERROR_INVALID_HANDLE;
2336
2337         ret = is_usb_active(dev_p);
2338         if (ret != CY_AS_ERROR_SUCCESS)
2339                 return ret;
2340
2341         if (cy_as_device_is_in_callback(dev_p))
2342                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2343
2344         if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
2345                 return CY_AS_ERROR_INVALID_ENDPOINT;
2346
2347         /* EP2 is available for reading when MTP is active */
2348         if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
2349                 return CY_AS_ERROR_INVALID_ENDPOINT;
2350
2351         /* If the endpoint is disabled, we cannot
2352          * write data to the endpoint */
2353         if (!dev_p->usb_config[ep].enabled)
2354                 return CY_AS_ERROR_ENDPOINT_DISABLED;
2355
2356         if (dev_p->usb_config[ep].dir != cy_as_usb_out)
2357                 return CY_AS_ERROR_USB_BAD_DIRECTION;
2358
2359         ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2360                 pktread, cy_true, sync_request_callback);
2361         if (ret != CY_AS_ERROR_SUCCESS)
2362                 return ret;
2363
2364         if (ep == CY_AS_MTP_READ_ENDPOINT)  {
2365                 ret = my_send_turbo_switch(dev_p, dsize, pktread);
2366                 if (ret != CY_AS_ERROR_SUCCESS) {
2367                         cy_as_dma_cancel(dev_p, ep, ret);
2368                         return ret;
2369                 }
2370
2371                 ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
2372                 if (ret != CY_AS_ERROR_SUCCESS)
2373                         return ret;
2374         } else {
2375                 ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
2376                 if (ret != CY_AS_ERROR_SUCCESS)
2377                         return ret;
2378         }
2379
2380         ret = dev_p->usb_error;
2381         *dataread = dev_p->usb_actual_cnt;
2382
2383         return ret;
2384 }
2385
2386 cy_as_return_status_t
2387 cy_as_usb_read_data_async(cy_as_device_handle handle,
2388         cy_as_end_point_number_t ep, cy_bool pktread,
2389         uint32_t dsize, void *data, cy_as_usb_io_callback cb)
2390 {
2391         cy_as_return_status_t ret;
2392         uint32_t mask;
2393         cy_as_device *dev_p;
2394
2395         cy_as_log_debug_message(6, "cy_as_usb_read_data_async called");
2396
2397         dev_p = (cy_as_device *)handle;
2398         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2399                 return CY_AS_ERROR_INVALID_HANDLE;
2400
2401         ret = is_usb_active(dev_p);
2402         if (ret != CY_AS_ERROR_SUCCESS)
2403                 return ret;
2404
2405         if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
2406                 return CY_AS_ERROR_INVALID_ENDPOINT;
2407
2408         /* EP2 is available for reading when MTP is active */
2409         if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
2410                 return CY_AS_ERROR_INVALID_ENDPOINT;
2411
2412         /* If the endpoint is disabled, we cannot
2413          * write data to the endpoint */
2414         if (!dev_p->usb_config[ep].enabled)
2415                 return CY_AS_ERROR_ENDPOINT_DISABLED;
2416
2417         if (dev_p->usb_config[ep].dir != cy_as_usb_out &&
2418                 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2419                 return CY_AS_ERROR_USB_BAD_DIRECTION;
2420
2421         /*
2422         * since async operations can be triggered by interrupt
2423         * code, we must insure that we do not get multiple async
2424         * operations going at one time and protect this test and
2425         * set operation from interrupts.
2426         */
2427         mask = cy_as_hal_disable_interrupts();
2428         if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
2429                 cy_as_hal_enable_interrupts(mask);
2430                 return CY_AS_ERROR_ASYNC_PENDING;
2431         }
2432         cy_as_device_set_usb_async_pending(dev_p, ep);
2433
2434         /*
2435         * if this is for EP0, we set this bit to delay the
2436         * ACK response until after this read has completed.
2437         */
2438         if (ep == 0)
2439                 cy_as_device_set_ack_delayed(dev_p);
2440
2441         cy_as_hal_enable_interrupts(mask);
2442
2443         cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
2444         dev_p->usb_cb[ep] = cb;
2445
2446         ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2447                 pktread, cy_true, async_read_request_callback);
2448         if (ret != CY_AS_ERROR_SUCCESS)
2449                 return ret;
2450
2451         if (ep == CY_AS_MTP_READ_ENDPOINT)  {
2452                 ret = my_send_turbo_switch(dev_p, dsize, pktread);
2453                 if (ret != CY_AS_ERROR_SUCCESS) {
2454                         cy_as_dma_cancel(dev_p, ep, ret);
2455                         return ret;
2456                 }
2457         } else {
2458                 /* Kick start the queue if it is not running */
2459                 cy_as_dma_kick_start(dev_p, ep);
2460         }
2461         return ret;
2462 }
2463
2464 cy_as_return_status_t
2465 cy_as_usb_write_data(cy_as_device_handle handle,
2466         cy_as_end_point_number_t ep, uint32_t dsize, void *data)
2467 {
2468         cy_as_return_status_t ret;
2469         cy_as_device *dev_p;
2470
2471         cy_as_log_debug_message(6, "cy_as_usb_write_data called");
2472
2473         dev_p = (cy_as_device *)handle;
2474         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2475                 return CY_AS_ERROR_INVALID_HANDLE;
2476
2477         ret = is_usb_active(dev_p);
2478         if (ret != CY_AS_ERROR_SUCCESS)
2479                 return ret;
2480
2481         if (cy_as_device_is_in_callback(dev_p))
2482                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2483
2484         if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
2485                 return CY_AS_ERROR_INVALID_ENDPOINT;
2486
2487         /* EP6 is available for writing when MTP is active */
2488         if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
2489                 return CY_AS_ERROR_INVALID_ENDPOINT;
2490
2491         /* If the endpoint is disabled, we cannot
2492          * write data to the endpoint */
2493         if (!dev_p->usb_config[ep].enabled)
2494                 return CY_AS_ERROR_ENDPOINT_DISABLED;
2495
2496         if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
2497                 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2498                 return CY_AS_ERROR_USB_BAD_DIRECTION;
2499
2500         /* Write on Turbo endpoint */
2501         if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
2502                 cy_as_ll_request_response *req_p, *reply_p;
2503
2504                 req_p = cy_as_ll_create_request(dev_p,
2505                         CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
2506                         CY_RQT_TUR_RQT_CONTEXT, 3);
2507                 if (req_p == 0)
2508                         return CY_AS_ERROR_OUT_OF_MEMORY;
2509
2510                 cy_as_ll_request_response__set_word(req_p,
2511                         0, 0x0006); /* EP number to use. */
2512                 cy_as_ll_request_response__set_word(req_p,
2513                         1, (uint16_t)((dsize >> 16) & 0xFFFF));
2514                 cy_as_ll_request_response__set_word(req_p,
2515                         2, (uint16_t)(dsize & 0xFFFF));
2516
2517                 /* Reserve space for the reply, the reply data
2518                  * will not exceed one word */
2519                 reply_p = cy_as_ll_create_response(dev_p, 1);
2520                 if (reply_p == 0) {
2521                         cy_as_ll_destroy_request(dev_p, req_p);
2522                         return CY_AS_ERROR_OUT_OF_MEMORY;
2523                 }
2524
2525                 if (dsize) {
2526                         ret = cy_as_dma_queue_request(dev_p,
2527                                 ep, data, dsize, cy_false,
2528                                 cy_false, sync_request_callback);
2529                         if (ret != CY_AS_ERROR_SUCCESS)
2530                                 return ret;
2531                 }
2532
2533                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
2534                 if (ret == CY_AS_ERROR_SUCCESS) {
2535                         if (cy_as_ll_request_response__get_code(reply_p) !=
2536                         CY_RESP_SUCCESS_FAILURE)
2537                                 ret = CY_AS_ERROR_INVALID_RESPONSE;
2538                         else
2539                                 ret = cy_as_ll_request_response__get_word
2540                                                 (reply_p, 0);
2541                 }
2542
2543                 cy_as_ll_destroy_request(dev_p, req_p);
2544                 cy_as_ll_destroy_response(dev_p, reply_p);
2545
2546                 if (ret != CY_AS_ERROR_SUCCESS) {
2547                         if (dsize)
2548                                 cy_as_dma_cancel(dev_p, ep, ret);
2549                         return ret;
2550                 }
2551
2552                 /* If this is a zero-byte write, firmware will
2553                  * handle it. there is no need to do any work here.
2554                  */
2555                 if (!dsize)
2556                         return CY_AS_ERROR_SUCCESS;
2557         } else {
2558                 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2559                         cy_false, cy_false, sync_request_callback);
2560                 if (ret != CY_AS_ERROR_SUCCESS)
2561                         return ret;
2562         }
2563
2564         if (ep != CY_AS_MTP_WRITE_ENDPOINT)
2565                 ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
2566         else
2567                 ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
2568
2569         if (ret != CY_AS_ERROR_SUCCESS)
2570                 return ret;
2571
2572         ret = dev_p->usb_error;
2573         return ret;
2574 }
2575
2576 static void
2577 mtp_write_callback(
2578                 cy_as_device *dev_p,
2579                 uint8_t context,
2580                 cy_as_ll_request_response *rqt,
2581                 cy_as_ll_request_response *resp,
2582                 cy_as_return_status_t ret)
2583 {
2584         cy_as_usb_io_callback cb;
2585         cy_as_device_handle h = (cy_as_device_handle)dev_p;
2586
2587         cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT);
2588
2589         if (ret == CY_AS_ERROR_SUCCESS) {
2590                 if (cy_as_ll_request_response__get_code(resp) !=
2591                 CY_RESP_SUCCESS_FAILURE)
2592                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2593                 else
2594                         ret = cy_as_ll_request_response__get_word(resp, 0);
2595         }
2596
2597         /* If this was a zero byte transfer request, we can
2598          * call the callback from here. */
2599         if ((cy_as_ll_request_response__get_word(rqt, 1) == 0) &&
2600                         (cy_as_ll_request_response__get_word(rqt, 2) == 0)) {
2601                 cb = dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT];
2602                 dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] = 0;
2603                 cy_as_device_clear_usb_async_pending(dev_p,
2604                         CY_AS_MTP_WRITE_ENDPOINT);
2605                 if (cb)
2606                         cb(h, CY_AS_MTP_WRITE_ENDPOINT, 0, 0, ret);
2607
2608                 goto destroy;
2609         }
2610
2611         if (ret != CY_AS_ERROR_SUCCESS) {
2612                 /* Firmware failed the request. Cancel the DMA transfer. */
2613                 cy_as_dma_cancel(dev_p, 0x06, CY_AS_ERROR_CANCELED);
2614                 dev_p->usb_cb[0x06] = 0;
2615                 cy_as_device_clear_usb_async_pending(dev_p, 0x06);
2616         }
2617
2618 destroy:
2619         cy_as_ll_destroy_response(dev_p, resp);
2620         cy_as_ll_destroy_request(dev_p, rqt);
2621 }
2622
2623 cy_as_return_status_t
2624 cy_as_usb_write_data_async(cy_as_device_handle handle,
2625         cy_as_end_point_number_t ep, uint32_t dsize, void *data,
2626         cy_bool spacket, cy_as_usb_io_callback cb)
2627 {
2628         uint32_t mask;
2629         cy_as_return_status_t ret;
2630         cy_as_device *dev_p;
2631
2632         cy_as_log_debug_message(6, "cy_as_usb_write_data_async called");
2633
2634         dev_p = (cy_as_device *)handle;
2635         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2636                 return CY_AS_ERROR_INVALID_HANDLE;
2637
2638         ret = is_usb_active(dev_p);
2639         if (ret != CY_AS_ERROR_SUCCESS)
2640                 return ret;
2641
2642         if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
2643                 return CY_AS_ERROR_INVALID_ENDPOINT;
2644
2645          /* EP6 is available for writing when MTP is active */
2646         if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
2647                 return CY_AS_ERROR_INVALID_ENDPOINT;
2648
2649         /* If the endpoint is disabled, we cannot
2650          * write data to the endpoint */
2651         if (!dev_p->usb_config[ep].enabled)
2652                 return CY_AS_ERROR_ENDPOINT_DISABLED;
2653
2654         if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
2655                 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2656                 return CY_AS_ERROR_USB_BAD_DIRECTION;
2657
2658         /*
2659         * since async operations can be triggered by interrupt
2660         * code, we must insure that we do not get multiple
2661         * async operations going at one time and
2662         * protect this test and set operation from interrupts.
2663         */
2664         mask = cy_as_hal_disable_interrupts();
2665         if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
2666                 cy_as_hal_enable_interrupts(mask);
2667                 return CY_AS_ERROR_ASYNC_PENDING;
2668         }
2669
2670         cy_as_device_set_usb_async_pending(dev_p, ep);
2671
2672         if (ep == 0)
2673                 cy_as_device_set_ack_delayed(dev_p);
2674
2675         cy_as_hal_enable_interrupts(mask);
2676
2677         cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
2678         dev_p->usb_cb[ep] = cb;
2679         dev_p->usb_spacket[ep] = spacket;
2680
2681         /* Write on Turbo endpoint */
2682         if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
2683                 cy_as_ll_request_response *req_p, *reply_p;
2684
2685                 req_p = cy_as_ll_create_request(dev_p,
2686                         CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
2687                         CY_RQT_TUR_RQT_CONTEXT, 3);
2688
2689                 if (req_p == 0)
2690                         return CY_AS_ERROR_OUT_OF_MEMORY;
2691
2692                 cy_as_ll_request_response__set_word(req_p, 0,
2693                         0x0006); /* EP number to use. */
2694                 cy_as_ll_request_response__set_word(req_p, 1,
2695                         (uint16_t)((dsize >> 16) & 0xFFFF));
2696                 cy_as_ll_request_response__set_word(req_p, 2,
2697                         (uint16_t)(dsize & 0xFFFF));
2698
2699                 /* Reserve space for the reply, the reply data
2700                  * will not exceed one word */
2701                 reply_p = cy_as_ll_create_response(dev_p, 1);
2702                 if (reply_p == 0) {
2703                         cy_as_ll_destroy_request(dev_p, req_p);
2704                         return CY_AS_ERROR_OUT_OF_MEMORY;
2705                 }
2706
2707                 if (dsize) {
2708                         ret = cy_as_dma_queue_request(dev_p, ep, data,
2709                                 dsize, cy_false, cy_false,
2710                                 async_write_request_callback);
2711                         if (ret != CY_AS_ERROR_SUCCESS)
2712                                 return ret;
2713                 }
2714
2715                 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2716                         cy_false, mtp_write_callback);
2717                 if (ret != CY_AS_ERROR_SUCCESS) {
2718                         if (dsize)
2719                                 cy_as_dma_cancel(dev_p, ep, ret);
2720                         return ret;
2721                 }
2722
2723                 /* Firmware will handle a zero byte transfer
2724                  * without any DMA transfers. */
2725                 if (!dsize)
2726                         return CY_AS_ERROR_SUCCESS;
2727         } else {
2728                 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2729                         cy_false, cy_false, async_write_request_callback);
2730                 if (ret != CY_AS_ERROR_SUCCESS)
2731                         return ret;
2732         }
2733
2734         /* Kick start the queue if it is not running */
2735         if (ep != CY_AS_MTP_WRITE_ENDPOINT)
2736                 cy_as_dma_kick_start(dev_p, ep);
2737
2738         return CY_AS_ERROR_SUCCESS;
2739 }
2740
2741 static void
2742 my_usb_cancel_async_callback(
2743                                    cy_as_device *dev_p,
2744                                    uint8_t context,
2745                                    cy_as_ll_request_response *rqt,
2746                                    cy_as_ll_request_response *resp,
2747                                    cy_as_return_status_t ret)
2748 {
2749         uint8_t ep;
2750         (void)context;
2751
2752         ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
2753         if (ret == CY_AS_ERROR_SUCCESS) {
2754                 if (cy_as_ll_request_response__get_code(resp) !=
2755                         CY_RESP_SUCCESS_FAILURE)
2756                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2757                 else
2758                         ret = cy_as_ll_request_response__get_word(resp, 0);
2759         }
2760
2761         cy_as_ll_destroy_request(dev_p, rqt);
2762         cy_as_ll_destroy_response(dev_p, resp);
2763
2764         if (ret == CY_AS_ERROR_SUCCESS) {
2765                 cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
2766                 dev_p->usb_cb[ep] = 0;
2767                 cy_as_device_clear_usb_async_pending(dev_p, ep);
2768         }
2769 }
2770
2771 cy_as_return_status_t
2772 cy_as_usb_cancel_async(cy_as_device_handle handle,
2773         cy_as_end_point_number_t ep)
2774 {
2775         cy_as_return_status_t ret;
2776         cy_as_ll_request_response *req_p, *reply_p;
2777
2778         cy_as_device *dev_p = (cy_as_device *)handle;
2779         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2780                 return CY_AS_ERROR_INVALID_HANDLE;
2781
2782         ep &= 0x7F;              /* Remove the direction bit. */
2783         if (!cy_as_device_is_usb_async_pending(dev_p, ep))
2784                 return CY_AS_ERROR_ASYNC_NOT_PENDING;
2785
2786         ret = is_usb_active(dev_p);
2787         if (ret != CY_AS_ERROR_SUCCESS)
2788                 return ret;
2789
2790         if (cy_as_device_is_in_suspend_mode(dev_p))
2791                 return CY_AS_ERROR_IN_SUSPEND;
2792
2793         if ((ep == CY_AS_MTP_WRITE_ENDPOINT) ||
2794                 (ep == CY_AS_MTP_READ_ENDPOINT)) {
2795                 /* Need firmware support for the cancel operation. */
2796                 req_p = cy_as_ll_create_request(dev_p,
2797                         CY_RQT_CANCEL_ASYNC_TRANSFER,
2798                         CY_RQT_TUR_RQT_CONTEXT, 1);
2799
2800                 if (req_p == 0)
2801                         return CY_AS_ERROR_OUT_OF_MEMORY;
2802
2803                 reply_p = cy_as_ll_create_response(dev_p, 1);
2804                 if (reply_p == 0) {
2805                         cy_as_ll_destroy_request(dev_p, req_p);
2806                         return CY_AS_ERROR_OUT_OF_MEMORY;
2807                 }
2808
2809                 cy_as_ll_request_response__set_word(req_p, 0,
2810                         (uint16_t)ep);
2811
2812                 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2813                         cy_false, my_usb_cancel_async_callback);
2814
2815                 if (ret != CY_AS_ERROR_SUCCESS) {
2816                         cy_as_ll_destroy_request(dev_p, req_p);
2817                         cy_as_ll_destroy_response(dev_p, reply_p);
2818                         return ret;
2819                 }
2820         } else {
2821                 ret = cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
2822                 if (ret != CY_AS_ERROR_SUCCESS)
2823                         return ret;
2824
2825                 dev_p->usb_cb[ep] = 0;
2826                 cy_as_device_clear_usb_async_pending(dev_p, ep);
2827         }
2828
2829         return CY_AS_ERROR_SUCCESS;
2830 }
2831
2832 static void
2833 cy_as_usb_ack_callback(
2834                                    cy_as_device *dev_p,
2835                                    uint8_t context,
2836                                    cy_as_ll_request_response *rqt,
2837                                    cy_as_ll_request_response *resp,
2838                                    cy_as_return_status_t ret)
2839 {
2840         cy_as_func_c_b_node *node  = (cy_as_func_c_b_node *)
2841                 dev_p->func_cbs_usb->head_p;
2842
2843         (void)context;
2844
2845         if (ret == CY_AS_ERROR_SUCCESS) {
2846                 if (cy_as_ll_request_response__get_code(resp) !=
2847                 CY_RESP_SUCCESS_FAILURE)
2848                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2849                 else
2850                         ret = cy_as_ll_request_response__get_word(resp, 0);
2851         }
2852
2853         node->cb_p((cy_as_device_handle)dev_p, ret,
2854                 node->client_data, node->data_type, node->data);
2855         cy_as_remove_c_b_node(dev_p->func_cbs_usb);
2856
2857         cy_as_ll_destroy_request(dev_p, rqt);
2858         cy_as_ll_destroy_response(dev_p, resp);
2859         cy_as_device_clear_ack_delayed(dev_p);
2860 }
2861
2862 static cy_as_return_status_t
2863 cy_as_usb_ack_setup_packet(cy_as_device_handle handle,
2864                                           cy_as_function_callback         cb,
2865                                           uint32_t client)
2866 {
2867         cy_as_return_status_t ret;
2868         cy_as_ll_request_response *req_p;
2869         cy_as_ll_request_response *reply_p;
2870         cy_as_func_c_b_node *cbnode;
2871
2872         cy_as_device *dev_p = (cy_as_device *)handle;
2873         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2874                 return CY_AS_ERROR_INVALID_HANDLE;
2875
2876         ret = is_usb_active(dev_p);
2877         if (ret != CY_AS_ERROR_SUCCESS)
2878                 return ret;
2879
2880         if (cy_as_device_is_in_callback(dev_p) && cb == 0)
2881                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2882
2883         cy_as_hal_assert(cb != 0);
2884
2885         cbnode = cy_as_create_func_c_b_node(cb, client);
2886         if (cbnode == 0)
2887                 return CY_AS_ERROR_OUT_OF_MEMORY;
2888
2889         req_p = cy_as_ll_create_request(dev_p, 0,
2890                 CY_RQT_USB_RQT_CONTEXT, 2);
2891         if (req_p == 0)
2892                 return CY_AS_ERROR_OUT_OF_MEMORY;
2893
2894         reply_p = cy_as_ll_create_response(dev_p, 1);
2895         if (reply_p == 0) {
2896                 cy_as_ll_destroy_request(dev_p, req_p);
2897                 return CY_AS_ERROR_OUT_OF_MEMORY;
2898         }
2899
2900         cy_as_ll_init_request(req_p, CY_RQT_ACK_SETUP_PACKET,
2901                 CY_RQT_USB_RQT_CONTEXT, 1);
2902         cy_as_ll_init_response(reply_p, 1);
2903
2904         req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
2905
2906         cy_as_insert_c_b_node(dev_p->func_cbs_usb, cbnode);
2907
2908         ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2909                 cy_false, cy_as_usb_ack_callback);
2910
2911         return ret;
2912 }
2913
2914 /*
2915  * Flush all data in logical EP that is being NAK-ed or
2916  * Stall-ed, so that this does not continue to block data
2917  * on other LEPs that use the same physical EP.
2918  */
2919 static void
2920 cy_as_usb_flush_logical_e_p(
2921                 cy_as_device *dev_p,
2922                 uint16_t        ep)
2923 {
2924         uint16_t addr, val, count;
2925
2926         addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
2927         val  = cy_as_hal_read_register(dev_p->tag, addr);
2928
2929         while (val) {
2930                 count = ((val & 0xFFF) + 1) / 2;
2931                 while (count--)
2932                         val = cy_as_hal_read_register(dev_p->tag, ep);
2933
2934                 cy_as_hal_write_register(dev_p->tag, addr, 0);
2935                 val = cy_as_hal_read_register(dev_p->tag, addr);
2936         }
2937 }
2938
2939 static cy_as_return_status_t
2940 cy_as_usb_nak_stall_request(cy_as_device_handle handle,
2941                                            cy_as_end_point_number_t ep,
2942                                            uint16_t request,
2943                                            cy_bool state,
2944                                            cy_as_usb_function_callback cb,
2945                                            cy_as_function_callback fcb,
2946                                            uint32_t client)
2947 {
2948         cy_as_return_status_t ret;
2949         cy_as_ll_request_response *req_p , *reply_p;
2950         uint16_t data;
2951
2952         cy_as_device *dev_p = (cy_as_device *)handle;
2953         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2954                 return CY_AS_ERROR_INVALID_HANDLE;
2955
2956         if (cb)
2957                 cy_as_hal_assert(fcb == 0);
2958         if (fcb)
2959                 cy_as_hal_assert(cb == 0);
2960
2961         ret = is_usb_active(dev_p);
2962         if (ret != CY_AS_ERROR_SUCCESS)
2963                 return ret;
2964
2965         if (cy_as_device_is_in_callback(dev_p) && cb == 0 && fcb == 0)
2966                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2967
2968         req_p = cy_as_ll_create_request(dev_p,
2969                 request, CY_RQT_USB_RQT_CONTEXT, 2);
2970         if (req_p == 0)
2971                 return CY_AS_ERROR_OUT_OF_MEMORY;
2972
2973         /* A single status word response type */
2974         reply_p = cy_as_ll_create_response(dev_p, 1);
2975         if (reply_p == 0) {
2976                 cy_as_ll_destroy_request(dev_p, req_p);
2977                 return CY_AS_ERROR_OUT_OF_MEMORY;
2978         }
2979
2980         /* Set the endpoint */
2981         data = (uint8_t)ep;
2982         cy_as_ll_request_response__set_word(req_p, 0, data);
2983
2984         /* Set stall state to stalled */
2985         cy_as_ll_request_response__set_word(req_p, 1, (uint8_t)state);
2986
2987         if (cb || fcb) {
2988                 void *cbnode;
2989                 cy_as_c_b_queue *queue;
2990                 if (cb) {
2991                         cbnode = cy_as_create_usb_func_c_b_node(cb, client);
2992                         queue = dev_p->usb_func_cbs;
2993                 } else {
2994                         cbnode = cy_as_create_func_c_b_node(fcb, client);
2995                         queue = dev_p->func_cbs_usb;
2996                         req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
2997                 }
2998
2999                 if (cbnode == 0) {
3000                         ret = CY_AS_ERROR_OUT_OF_MEMORY;
3001                         goto destroy;
3002                 } else
3003                         cy_as_insert_c_b_node(queue, cbnode);
3004
3005
3006                 if (cy_as_device_is_setup_packet(dev_p)) {
3007                         /* No Ack is needed on a stall request on EP0 */
3008                         if ((state == cy_true) && (ep == 0)) {
3009                                 cy_as_device_set_ep0_stalled(dev_p);
3010                         } else {
3011                                 cy_as_device_set_ack_delayed(dev_p);
3012                                 req_p->flags |=
3013                                         CY_AS_REQUEST_RESPONSE_DELAY_ACK;
3014                         }
3015                 }
3016
3017                 ret = cy_as_ll_send_request(dev_p, req_p,
3018                         reply_p, cy_false, cy_as_usb_func_callback);
3019                 if (ret != CY_AS_ERROR_SUCCESS) {
3020                         if (req_p->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
3021                                 cy_as_device_rem_ack_delayed(dev_p);
3022                         cy_as_remove_c_b_tail_node(queue);
3023
3024                         goto destroy;
3025                 }
3026         } else {
3027                 ret = cy_as_ll_send_request_wait_reply(dev_p,
3028                         req_p, reply_p);
3029                 if (ret != CY_AS_ERROR_SUCCESS)
3030                         goto destroy;
3031
3032                 if (cy_as_ll_request_response__get_code(reply_p) !=
3033                 CY_RESP_SUCCESS_FAILURE) {
3034                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3035                         goto destroy;
3036                 }
3037
3038                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3039
3040                 if ((ret == CY_AS_ERROR_SUCCESS) &&
3041                         (request == CY_RQT_STALL_ENDPOINT)) {
3042                         if ((ep > 1) && (state != 0) &&
3043                                 (dev_p->usb_config[ep].dir == cy_as_usb_out))
3044                                 cy_as_usb_flush_logical_e_p(dev_p, ep);
3045                 }
3046
3047 destroy:
3048                 cy_as_ll_destroy_request(dev_p, req_p);
3049                 cy_as_ll_destroy_response(dev_p, reply_p);
3050         }
3051
3052         return ret;
3053 }
3054
3055 static cy_as_return_status_t
3056 my_handle_response_get_stall(cy_as_device *dev_p,
3057                                 cy_as_ll_request_response *req_p,
3058                                 cy_as_ll_request_response *reply_p,
3059                                 cy_bool *state_p)
3060 {
3061         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3062         uint8_t code = cy_as_ll_request_response__get_code(reply_p);
3063
3064         if (code == CY_RESP_SUCCESS_FAILURE) {
3065                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3066                 goto destroy;
3067         } else if (code != CY_RESP_ENDPOINT_STALL) {
3068                 ret = CY_AS_ERROR_INVALID_RESPONSE;
3069                 goto destroy;
3070         }
3071
3072         *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
3073         ret = CY_AS_ERROR_SUCCESS;
3074
3075
3076 destroy:
3077                 cy_as_ll_destroy_request(dev_p, req_p);
3078                 cy_as_ll_destroy_response(dev_p, reply_p);
3079
3080                 return ret;
3081 }
3082
3083 static cy_as_return_status_t
3084 my_handle_response_get_nak(cy_as_device *dev_p,
3085                                            cy_as_ll_request_response *req_p,
3086                                            cy_as_ll_request_response *reply_p,
3087                                            cy_bool *state_p)
3088 {
3089         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3090         uint8_t code = cy_as_ll_request_response__get_code(reply_p);
3091
3092         if (code == CY_RESP_SUCCESS_FAILURE) {
3093                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3094                 goto destroy;
3095         } else if (code != CY_RESP_ENDPOINT_NAK) {
3096                 ret = CY_AS_ERROR_INVALID_RESPONSE;
3097                 goto destroy;
3098         }
3099
3100         *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
3101         ret = CY_AS_ERROR_SUCCESS;
3102
3103
3104 destroy:
3105                 cy_as_ll_destroy_request(dev_p, req_p);
3106                 cy_as_ll_destroy_response(dev_p, reply_p);
3107
3108                 return ret;
3109 }
3110
3111 static cy_as_return_status_t
3112 cy_as_usb_get_nak_stall(cy_as_device_handle handle,
3113                                    cy_as_end_point_number_t ep,
3114                                    uint16_t request,
3115                                    uint16_t response,
3116                                    cy_bool *state_p,
3117                                    cy_as_function_callback cb,
3118                                    uint32_t client)
3119 {
3120         cy_as_return_status_t ret;
3121         cy_as_ll_request_response *req_p , *reply_p;
3122         uint16_t data;
3123
3124         cy_as_device *dev_p = (cy_as_device *)handle;
3125
3126         (void)response;
3127
3128         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3129                 return CY_AS_ERROR_INVALID_HANDLE;
3130
3131         ret = is_usb_active(dev_p);
3132         if (ret != CY_AS_ERROR_SUCCESS)
3133                 return ret;
3134
3135         if (cy_as_device_is_in_callback(dev_p) && !cb)
3136                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3137
3138         req_p = cy_as_ll_create_request(dev_p, request,
3139                 CY_RQT_USB_RQT_CONTEXT, 1);
3140         if (req_p == 0)
3141                 return CY_AS_ERROR_OUT_OF_MEMORY;
3142
3143         /* Set the endpoint */
3144         data = (uint8_t)ep;
3145         cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)ep);
3146
3147         /* A single status word response type */
3148         reply_p = cy_as_ll_create_response(dev_p, 1);
3149         if (reply_p == 0) {
3150                 cy_as_ll_destroy_request(dev_p, req_p);
3151                 return CY_AS_ERROR_OUT_OF_MEMORY;
3152         }
3153
3154         if (cb == 0) {
3155                 ret = cy_as_ll_send_request_wait_reply(dev_p,
3156                         req_p, reply_p);
3157                 if (ret != CY_AS_ERROR_SUCCESS)
3158                         goto destroy;
3159
3160                 if (request == CY_RQT_GET_STALL)
3161                         return my_handle_response_get_stall(dev_p,
3162                                 req_p, reply_p, state_p);
3163                 else
3164                         return my_handle_response_get_nak(dev_p,
3165                                 req_p, reply_p, state_p);
3166
3167         } else {
3168                 cy_as_funct_c_b_type type;
3169
3170                 if (request == CY_RQT_GET_STALL)
3171                         type = CY_FUNCT_CB_USB_GETSTALL;
3172                 else
3173                         type = CY_FUNCT_CB_USB_GETNAK;
3174
3175                 ret = cy_as_misc_send_request(dev_p, cb, client, type,
3176                         state_p, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
3177                         req_p, reply_p, cy_as_usb_func_callback);
3178
3179                 if (ret != CY_AS_ERROR_SUCCESS)
3180                         goto destroy;
3181
3182                 return ret;
3183         }
3184
3185 destroy:
3186         cy_as_ll_destroy_request(dev_p, req_p);
3187         cy_as_ll_destroy_response(dev_p, reply_p);
3188
3189         return ret;
3190 }
3191
3192 cy_as_return_status_t
3193 cy_as_usb_set_nak(cy_as_device_handle handle,
3194                                 cy_as_end_point_number_t ep,
3195                                 cy_as_function_callback cb,
3196                                 uint32_t client)
3197 {
3198         cy_as_device *dev_p = (cy_as_device *)handle;
3199         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3200                 return CY_AS_ERROR_INVALID_HANDLE;
3201
3202         /*
3203         * we send the firmware the EP# with the appropriate direction
3204         * bit, regardless of what the user gave us.
3205         */
3206         ep &= 0x0f;
3207         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3208                 ep |= 0x80;
3209
3210                 if (dev_p->mtp_count > 0)
3211                                 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3212
3213         return cy_as_usb_nak_stall_request(handle, ep,
3214                 CY_RQT_ENDPOINT_SET_NAK, cy_true, 0, cb, client);
3215 }
3216
3217
3218 cy_as_return_status_t
3219 cy_as_usb_clear_nak(cy_as_device_handle handle,
3220                                   cy_as_end_point_number_t ep,
3221                                   cy_as_function_callback cb,
3222                                   uint32_t client)
3223 {
3224         cy_as_device *dev_p = (cy_as_device *)handle;
3225         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3226                 return CY_AS_ERROR_INVALID_HANDLE;
3227
3228         /*
3229         * we send the firmware the EP# with the appropriate
3230         * direction bit, regardless of what the user gave us.
3231         */
3232         ep &= 0x0f;
3233         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3234                 ep |= 0x80;
3235
3236                 if (dev_p->mtp_count > 0)
3237                                 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3238
3239         return cy_as_usb_nak_stall_request(handle, ep,
3240                 CY_RQT_ENDPOINT_SET_NAK, cy_false, 0, cb, client);
3241 }
3242
3243 cy_as_return_status_t
3244 cy_as_usb_get_nak(cy_as_device_handle handle,
3245                                 cy_as_end_point_number_t ep,
3246                                 cy_bool *nak_p,
3247                                 cy_as_function_callback cb,
3248                                 uint32_t client)
3249 {
3250         cy_as_device *dev_p = (cy_as_device *)handle;
3251         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3252                 return CY_AS_ERROR_INVALID_HANDLE;
3253
3254         /*
3255         * we send the firmware the EP# with the appropriate
3256         * direction bit, regardless of what the user gave us.
3257         */
3258         ep &= 0x0f;
3259         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3260                 ep |= 0x80;
3261
3262                 if (dev_p->mtp_count > 0)
3263                                 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3264
3265         return cy_as_usb_get_nak_stall(handle, ep,
3266                 CY_RQT_GET_ENDPOINT_NAK, CY_RESP_ENDPOINT_NAK,
3267                 nak_p, cb, client);
3268 }
3269
3270
3271 cy_as_return_status_t
3272 cy_as_usb_set_stall(cy_as_device_handle handle,
3273                                   cy_as_end_point_number_t ep,
3274                                   cy_as_function_callback cb,
3275                                   uint32_t client)
3276 {
3277         cy_as_device *dev_p = (cy_as_device *)handle;
3278         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3279                 return CY_AS_ERROR_INVALID_HANDLE;
3280
3281         /*
3282         * we send the firmware the EP# with the appropriate
3283         * direction bit, regardless of what the user gave us.
3284         */
3285         ep &= 0x0f;
3286         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3287                 ep |= 0x80;
3288
3289         if (dev_p->mtp_turbo_active)
3290                 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3291
3292         return cy_as_usb_nak_stall_request(handle, ep,
3293                 CY_RQT_STALL_ENDPOINT, cy_true, 0, cb, client);
3294 }
3295
3296 cy_as_return_status_t
3297 cy_as_usb_clear_stall(cy_as_device_handle handle,
3298                                         cy_as_end_point_number_t ep,
3299                                         cy_as_function_callback cb,
3300                                         uint32_t client)
3301 {
3302         cy_as_device *dev_p = (cy_as_device *)handle;
3303         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3304                 return CY_AS_ERROR_INVALID_HANDLE;
3305
3306         /*
3307         * we send the firmware the EP# with the appropriate
3308         * direction bit, regardless of what the user gave us.
3309         */
3310         ep &= 0x0f;
3311         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3312                 ep |= 0x80;
3313
3314         if (dev_p->mtp_turbo_active)
3315                 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3316
3317         return cy_as_usb_nak_stall_request(handle, ep,
3318                 CY_RQT_STALL_ENDPOINT, cy_false, 0, cb, client);
3319 }
3320
3321 cy_as_return_status_t
3322 cy_as_usb_get_stall(cy_as_device_handle handle,
3323                                   cy_as_end_point_number_t ep,
3324                                   cy_bool *stall_p,
3325                                   cy_as_function_callback cb,
3326                                   uint32_t client)
3327 {
3328         cy_as_device *dev_p = (cy_as_device *)handle;
3329         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3330                 return CY_AS_ERROR_INVALID_HANDLE;
3331
3332         /*
3333         * we send the firmware the EP# with the appropriate
3334         * direction bit, regardless of what the user gave us.
3335         */
3336         ep &= 0x0f;
3337         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3338                 ep |= 0x80;
3339
3340         if (dev_p->mtp_turbo_active)
3341                 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3342
3343         return cy_as_usb_get_nak_stall(handle, ep,
3344                 CY_RQT_GET_STALL, CY_RESP_ENDPOINT_STALL, stall_p, cb, client);
3345 }
3346
3347 cy_as_return_status_t
3348 cy_as_usb_signal_remote_wakeup(cy_as_device_handle handle,
3349                 cy_as_function_callback cb,
3350                 uint32_t client)
3351 {
3352         cy_as_return_status_t ret;
3353         cy_as_ll_request_response *req_p , *reply_p;
3354
3355         cy_as_device *dev_p = (cy_as_device *)handle;
3356         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3357                 return CY_AS_ERROR_INVALID_HANDLE;
3358
3359         ret = is_usb_active(dev_p);
3360         if (ret != CY_AS_ERROR_SUCCESS)
3361                 return ret;
3362
3363         if (cy_as_device_is_in_callback(dev_p))
3364                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3365
3366         if (dev_p->usb_last_event != cy_as_event_usb_suspend)
3367                 return CY_AS_ERROR_NOT_IN_SUSPEND;
3368
3369         req_p = cy_as_ll_create_request(dev_p,
3370                 CY_RQT_USB_REMOTE_WAKEUP, CY_RQT_USB_RQT_CONTEXT, 0);
3371         if (req_p == 0)
3372                 return CY_AS_ERROR_OUT_OF_MEMORY;
3373
3374         /* A single status word response type */
3375         reply_p = cy_as_ll_create_response(dev_p, 1);
3376         if (reply_p == 0) {
3377                 cy_as_ll_destroy_request(dev_p, req_p);
3378                 return CY_AS_ERROR_OUT_OF_MEMORY;
3379         }
3380
3381         if (cb == 0) {
3382                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3383                 if (ret != CY_AS_ERROR_SUCCESS)
3384                         goto destroy;
3385
3386                 if (cy_as_ll_request_response__get_code(reply_p) ==
3387                         CY_RESP_SUCCESS_FAILURE)
3388                         ret = cy_as_ll_request_response__get_word(reply_p, 0);
3389                 else
3390                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3391         } else {
3392                 ret = cy_as_misc_send_request(dev_p, cb, client,
3393                         CY_FUNCT_CB_USB_SIGNALREMOTEWAKEUP, 0,
3394                         dev_p->func_cbs_usb,
3395                         CY_AS_REQUEST_RESPONSE_EX, req_p,
3396                         reply_p, cy_as_usb_func_callback);
3397
3398                 if (ret != CY_AS_ERROR_SUCCESS)
3399                         goto destroy;
3400                 return ret;
3401         }
3402
3403 destroy:
3404         cy_as_ll_destroy_request(dev_p, req_p);
3405         cy_as_ll_destroy_response(dev_p, reply_p);
3406
3407         return ret;
3408 }
3409
3410 cy_as_return_status_t
3411 cy_as_usb_set_m_s_report_threshold(cy_as_device_handle handle,
3412                 uint32_t wr_sectors,
3413                 uint32_t rd_sectors,
3414                 cy_as_function_callback cb,
3415                 uint32_t client)
3416 {
3417         cy_as_return_status_t ret;
3418         cy_as_ll_request_response *req_p , *reply_p;
3419
3420         cy_as_device *dev_p = (cy_as_device *)handle;
3421         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3422                 return CY_AS_ERROR_INVALID_HANDLE;
3423
3424         ret = is_usb_active(dev_p);
3425         if (ret != CY_AS_ERROR_SUCCESS)
3426                 return ret;
3427
3428         if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
3429                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3430
3431         /* Check if the firmware version supports this feature. */
3432         if ((dev_p->media_supported[0]) && (dev_p->media_supported[0] ==
3433                 (1 << cy_as_media_nand)))
3434                 return CY_AS_ERROR_NOT_SUPPORTED;
3435
3436         req_p = cy_as_ll_create_request(dev_p, CY_RQT_USB_STORAGE_MONITOR,
3437                 CY_RQT_USB_RQT_CONTEXT, 4);
3438         if (req_p == 0)
3439                 return CY_AS_ERROR_OUT_OF_MEMORY;
3440
3441         /* A single status word response type */
3442         reply_p = cy_as_ll_create_response(dev_p, 1);
3443         if (reply_p == 0) {
3444                 cy_as_ll_destroy_request(dev_p, req_p);
3445                 return CY_AS_ERROR_OUT_OF_MEMORY;
3446         }
3447
3448         /* Set the read and write count parameters into
3449          * the request structure. */
3450         cy_as_ll_request_response__set_word(req_p, 0,
3451                 (uint16_t)((wr_sectors >> 16) & 0xFFFF));
3452         cy_as_ll_request_response__set_word(req_p, 1,
3453                 (uint16_t)(wr_sectors & 0xFFFF));
3454         cy_as_ll_request_response__set_word(req_p, 2,
3455                 (uint16_t)((rd_sectors >> 16) & 0xFFFF));
3456         cy_as_ll_request_response__set_word(req_p, 3,
3457                 (uint16_t)(rd_sectors & 0xFFFF));
3458
3459         if (cb == 0) {
3460                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3461                 if (ret != CY_AS_ERROR_SUCCESS)
3462                         goto destroy;
3463
3464                 if (cy_as_ll_request_response__get_code(reply_p) ==
3465                 CY_RESP_SUCCESS_FAILURE)
3466                         ret = cy_as_ll_request_response__get_word(reply_p, 0);
3467                 else
3468                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3469         } else {
3470                 ret = cy_as_misc_send_request(dev_p, cb, client,
3471                         CY_FUNCT_CB_USB_SET_MSREPORT_THRESHOLD, 0,
3472                         dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
3473                         req_p, reply_p, cy_as_usb_func_callback);
3474
3475                 if (ret != CY_AS_ERROR_SUCCESS)
3476                         goto destroy;
3477                 return ret;
3478         }
3479
3480 destroy:
3481         cy_as_ll_destroy_request(dev_p, req_p);
3482         cy_as_ll_destroy_response(dev_p, reply_p);
3483
3484         return ret;
3485 }
3486
3487 cy_as_return_status_t
3488 cy_as_usb_select_m_s_partitions(
3489                 cy_as_device_handle             handle,
3490                 cy_as_bus_number_t               bus,
3491                 uint32_t                                device,
3492                 cy_as_usb_m_s_type_t             type,
3493                 cy_as_function_callback cb,
3494                 uint32_t                                client)
3495 {
3496         cy_as_return_status_t ret;
3497         cy_as_ll_request_response *req_p , *reply_p;
3498         uint16_t val;
3499
3500         cy_as_device *dev_p = (cy_as_device *)handle;
3501         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3502                 return CY_AS_ERROR_INVALID_HANDLE;
3503
3504         ret = is_usb_active(dev_p);
3505         if (ret != CY_AS_ERROR_SUCCESS)
3506                 return ret;
3507
3508         /* This API has to be made before SetEnumConfig is called. */
3509         if (dev_p->usb_config[0].enabled)
3510                 return CY_AS_ERROR_INVALID_CALL_SEQUENCE;
3511
3512         if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
3513                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3514
3515         req_p = cy_as_ll_create_request(dev_p, CY_RQT_MS_PARTITION_SELECT,
3516                 CY_RQT_USB_RQT_CONTEXT, 2);
3517         if (req_p == 0)
3518                 return CY_AS_ERROR_OUT_OF_MEMORY;
3519
3520         /* A single status word response type */
3521         reply_p = cy_as_ll_create_response(dev_p, 1);
3522         if (reply_p == 0) {
3523                 cy_as_ll_destroy_request(dev_p, req_p);
3524                 return CY_AS_ERROR_OUT_OF_MEMORY;
3525         }
3526
3527         /* Set the read and write count parameters into
3528          * the request structure. */
3529         cy_as_ll_request_response__set_word(req_p, 0,
3530                 (uint16_t)((bus << 8) | device));
3531
3532         val = 0;
3533         if ((type == cy_as_usb_m_s_unit0) || (type == cy_as_usb_m_s_both))
3534                 val |= 1;
3535         if ((type == cy_as_usb_m_s_unit1) || (type == cy_as_usb_m_s_both))
3536                 val |= (1 << 8);
3537
3538         cy_as_ll_request_response__set_word(req_p, 1, val);
3539
3540         if (cb == 0) {
3541                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3542                 if (ret != CY_AS_ERROR_SUCCESS)
3543                         goto destroy;
3544
3545                 if (cy_as_ll_request_response__get_code(reply_p) ==
3546                 CY_RESP_SUCCESS_FAILURE)
3547                         ret = cy_as_ll_request_response__get_word(reply_p, 0);
3548                 else
3549                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3550         } else {
3551                 ret = cy_as_misc_send_request(dev_p, cb, client,
3552                         CY_FUNCT_CB_NODATA, 0, dev_p->func_cbs_usb,
3553                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
3554                         cy_as_usb_func_callback);
3555
3556                 if (ret != CY_AS_ERROR_SUCCESS)
3557                         goto destroy;
3558                 return ret;
3559         }
3560
3561 destroy:
3562         cy_as_ll_destroy_request(dev_p, req_p);
3563         cy_as_ll_destroy_response(dev_p, reply_p);
3564
3565         return ret;
3566 }
3567
3568 static void
3569 cy_as_usb_func_callback(
3570                                         cy_as_device *dev_p,
3571                                         uint8_t context,
3572                                         cy_as_ll_request_response *rqt,
3573                                         cy_as_ll_request_response *resp,
3574                                         cy_as_return_status_t stat)
3575 {
3576         cy_as_usb_func_c_b_node* node = (cy_as_usb_func_c_b_node *)
3577                 dev_p->usb_func_cbs->head_p;
3578         cy_as_func_c_b_node* fnode = (cy_as_func_c_b_node *)
3579                 dev_p->func_cbs_usb->head_p;
3580         cy_as_return_status_t  ret = CY_AS_ERROR_SUCCESS;
3581
3582         cy_as_device_handle     h = (cy_as_device_handle)dev_p;
3583         cy_bool delayed_ack = (rqt->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
3584                 == CY_AS_REQUEST_RESPONSE_DELAY_ACK;
3585         cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX)
3586                 == CY_AS_REQUEST_RESPONSE_EX;
3587         cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS)
3588                 == CY_AS_REQUEST_RESPONSE_MS;
3589         uint8_t code;
3590         uint8_t ep, state;
3591
3592         if (!ex_request && !ms_request) {
3593                 cy_as_hal_assert(dev_p->usb_func_cbs->count != 0);
3594                 cy_as_hal_assert(dev_p->usb_func_cbs->type ==
3595                         CYAS_USB_FUNC_CB);
3596         } else {
3597                 cy_as_hal_assert(dev_p->func_cbs_usb->count != 0);
3598                 cy_as_hal_assert(dev_p->func_cbs_usb->type == CYAS_FUNC_CB);
3599         }
3600
3601         (void)context;
3602
3603         /* The Handlers are responsible for Deleting the rqt and resp when
3604          * they are finished
3605          */
3606         code = cy_as_ll_request_response__get_code(rqt);
3607         switch (code) {
3608         case CY_RQT_START_USB:
3609                 ret = my_handle_response_usb_start(dev_p, rqt, resp, stat);
3610                 break;
3611         case CY_RQT_STOP_USB:
3612                 ret = my_handle_response_usb_stop(dev_p, rqt, resp, stat);
3613                 break;
3614         case CY_RQT_SET_CONNECT_STATE:
3615                 if (!cy_as_ll_request_response__get_word(rqt, 0))
3616                         ret = my_handle_response_disconnect(
3617                                 dev_p, rqt, resp, stat);
3618                 else
3619                         ret = my_handle_response_connect(
3620                                 dev_p, rqt, resp, stat);
3621                 break;
3622         case CY_RQT_GET_CONNECT_STATE:
3623                 break;
3624         case CY_RQT_SET_USB_CONFIG:
3625                 ret = my_handle_response_set_enum_config(dev_p, rqt, resp);
3626                 break;
3627         case CY_RQT_GET_USB_CONFIG:
3628                 cy_as_hal_assert(fnode->data != 0);
3629                 ret = my_handle_response_get_enum_config(dev_p,
3630                         rqt, resp, fnode->data);
3631                 break;
3632         case CY_RQT_STALL_ENDPOINT:
3633                 ep      = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
3634                 state = (uint8_t)cy_as_ll_request_response__get_word(rqt, 1);
3635                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3636                 if ((ret == CY_AS_ERROR_SUCCESS) && (ep > 1) && (state != 0)
3637                         && (dev_p->usb_config[ep].dir == cy_as_usb_out))
3638                         cy_as_usb_flush_logical_e_p(dev_p, ep);
3639                 break;
3640         case CY_RQT_GET_STALL:
3641                 cy_as_hal_assert(fnode->data != 0);
3642                 ret = my_handle_response_get_stall(dev_p,
3643                         rqt, resp, (cy_bool *)fnode->data);
3644                 break;
3645         case CY_RQT_SET_DESCRIPTOR:
3646                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3647                 break;
3648         case CY_RQT_GET_DESCRIPTOR:
3649                 cy_as_hal_assert(fnode->data != 0);
3650                 ret = my_handle_response_get_descriptor(dev_p,
3651                         rqt, resp, (cy_as_get_descriptor_data *)fnode->data);
3652                 break;
3653         case CY_RQT_SET_USB_CONFIG_REGISTERS:
3654                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3655                 if (ret == CY_AS_ERROR_SUCCESS)
3656                         ret = cy_as_usb_setup_dma(dev_p);
3657                 break;
3658         case CY_RQT_ENDPOINT_SET_NAK:
3659                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3660                 break;
3661         case CY_RQT_GET_ENDPOINT_NAK:
3662                 cy_as_hal_assert(fnode->data != 0);
3663                 ret = my_handle_response_get_nak(dev_p,
3664                         rqt, resp, (cy_bool *)fnode->data);
3665                 break;
3666         case CY_RQT_ACK_SETUP_PACKET:
3667                 break;
3668         case CY_RQT_USB_REMOTE_WAKEUP:
3669                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3670                 break;
3671         case CY_RQT_CLEAR_DESCRIPTORS:
3672                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3673                 break;
3674         case CY_RQT_USB_STORAGE_MONITOR:
3675                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3676                 break;
3677         case CY_RQT_MS_PARTITION_SELECT:
3678                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3679                 break;
3680         default:
3681                 ret = CY_AS_ERROR_INVALID_RESPONSE;
3682                 cy_as_hal_assert(cy_false);
3683                 break;
3684         }
3685
3686         /*
3687          * if the low level layer returns a direct error, use
3688          * the corresponding error code. if not, use the error
3689          * code based on the response from firmware.
3690          */
3691         if (stat == CY_AS_ERROR_SUCCESS)
3692                 stat = ret;
3693
3694         if (ex_request || ms_request) {
3695                 fnode->cb_p((cy_as_device_handle)dev_p, stat,
3696                         fnode->client_data, fnode->data_type, fnode->data);
3697                 cy_as_remove_c_b_node(dev_p->func_cbs_usb);
3698         } else {
3699                 node->cb_p((cy_as_device_handle)dev_p, stat,
3700                         node->client_data);
3701                 cy_as_remove_c_b_node(dev_p->usb_func_cbs);
3702         }
3703
3704         if (delayed_ack) {
3705                 cy_as_hal_assert(cy_as_device_is_ack_delayed(dev_p));
3706                 cy_as_device_rem_ack_delayed(dev_p);
3707
3708                 /*
3709                  * send the ACK if required.
3710                  */
3711                 if (!cy_as_device_is_ack_delayed(dev_p))
3712                         cy_as_usb_ack_setup_packet(h,
3713                                 usb_ack_callback, 0);
3714         }
3715 }
3716
3717
3718 /*[]*/