Fix common misspellings
[linux-flexiantxendom0-3.2.10.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 because 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 EXPORT_SYMBOL(cy_as_usb_start);
804
805 void
806 cy_as_usb_reset(cy_as_device *dev_p)
807 {
808         int i;
809
810         cy_as_device_clear_usb_connected(dev_p);
811
812         for (i = 0; i < sizeof(dev_p->usb_config) /
813                 sizeof(dev_p->usb_config[0]); i++) {
814                 /*
815                  * cancel all pending USB read/write operations, as it is
816                  * possible that the USB stack comes up in a different
817                  * configuration with a different set of endpoints.
818                  */
819                 if (cy_as_device_is_usb_async_pending(dev_p, i))
820                         cy_as_usb_cancel_async(dev_p,
821                                 (cy_as_end_point_number_t)i);
822
823                 dev_p->usb_cb[i] = 0;
824                 dev_p->usb_config[i].enabled = cy_false;
825         }
826
827         dev_p->usb_phy_config = 0;
828 }
829
830 /*
831  * This function does all the API side clean-up associated
832  * with CyAsUsbStop, without any communication with firmware.
833  * This needs to be done when the device is being reset while
834  * the USB stack is active.
835  */
836 void
837 cy_as_usb_cleanup(cy_as_device *dev_p)
838 {
839         if (dev_p->usb_count) {
840                 cy_as_usb_reset_e_p0_state(dev_p);
841                 cy_as_usb_reset(dev_p);
842                 cy_as_hal_mem_set(dev_p->usb_config, 0,
843                         sizeof(dev_p->usb_config));
844                 cy_as_destroy_c_b_queue(dev_p->usb_func_cbs);
845
846                 dev_p->usb_count = 0;
847         }
848 }
849
850 static cy_as_return_status_t
851 my_handle_response_usb_stop(cy_as_device *dev_p,
852                                         cy_as_ll_request_response *req_p,
853                                         cy_as_ll_request_response *reply_p,
854                                         cy_as_return_status_t ret)
855 {
856         if (ret != CY_AS_ERROR_SUCCESS)
857                 goto destroy;
858
859         if (cy_as_ll_request_response__get_code(reply_p) !=
860         CY_RESP_SUCCESS_FAILURE) {
861                 ret = CY_AS_ERROR_INVALID_RESPONSE;
862                 goto destroy;
863         }
864
865         ret = cy_as_ll_request_response__get_word(reply_p, 0);
866         if (ret != CY_AS_ERROR_SUCCESS)
867                 goto destroy;
868
869         /*
870          * we successfully shutdown the stack, so
871          * decrement to make the count zero.
872          */
873         cy_as_usb_cleanup(dev_p);
874
875 destroy:
876         cy_as_ll_destroy_request(dev_p, req_p);
877         cy_as_ll_destroy_response(dev_p, reply_p);
878
879         if (ret != CY_AS_ERROR_SUCCESS)
880                 cy_as_ll_register_request_callback(dev_p,
881                         CY_RQT_USB_RQT_CONTEXT, 0);
882
883         cy_as_device_clear_u_s_s_pending(dev_p);
884
885         return ret;
886 }
887
888 /*
889 * This function stops the USB stack. The USB stack is reference
890 * counted so first is reference count is decremented. If the
891 * reference count is then zero, a request is sent to the West
892 * Bridge device to stop the USB stack on the West Bridge device.
893 */
894 cy_as_return_status_t
895 cy_as_usb_stop(cy_as_device_handle handle,
896                           cy_as_function_callback cb,
897                           uint32_t client)
898 {
899         cy_as_ll_request_response *req_p = 0, *reply_p = 0;
900         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
901
902         cy_as_device *dev_p;
903
904         cy_as_log_debug_message(6, "cy_as_usb_stop called");
905
906         dev_p = (cy_as_device *)handle;
907         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
908                 return CY_AS_ERROR_INVALID_HANDLE;
909
910         ret = is_usb_active(dev_p);
911         if (ret != CY_AS_ERROR_SUCCESS)
912                 return ret;
913
914         if (cy_as_device_is_usb_connected(dev_p))
915                 return CY_AS_ERROR_USB_CONNECTED;
916
917         if (cy_as_device_is_in_callback(dev_p))
918                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
919
920         if (cy_as_device_is_u_s_s_pending(dev_p))
921                 return CY_AS_ERROR_STARTSTOP_PENDING;
922
923         cy_as_device_set_u_s_s_pending(dev_p);
924
925         if (dev_p->usb_count == 1) {
926                 /* Create the request to send to the West Bridge device */
927                 req_p = cy_as_ll_create_request(dev_p, CY_RQT_STOP_USB,
928                         CY_RQT_USB_RQT_CONTEXT, 0);
929                 if (req_p == 0) {
930                         ret = CY_AS_ERROR_OUT_OF_MEMORY;
931                         goto destroy;
932                 }
933
934                 /* Reserve space for the reply, the reply data will not
935                  * exceed one word */
936                 reply_p = cy_as_ll_create_response(dev_p, 1);
937                 if (reply_p == 0) {
938                         ret = CY_AS_ERROR_OUT_OF_MEMORY;
939                         goto destroy;
940                 }
941
942                 if (cb == 0) {
943                         ret = cy_as_ll_send_request_wait_reply(dev_p,
944                                 req_p, reply_p);
945                         if (ret != CY_AS_ERROR_SUCCESS)
946                                 goto destroy;
947
948                         return my_handle_response_usb_stop(dev_p,
949                                 req_p, reply_p, ret);
950                 } else {
951                         ret = cy_as_misc_send_request(dev_p, cb, client,
952                                 CY_FUNCT_CB_USB_STOP, 0, dev_p->func_cbs_usb,
953                                 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
954                                 cy_as_usb_func_callback);
955
956                         if (ret != CY_AS_ERROR_SUCCESS)
957                                 goto destroy;
958
959                         return ret;
960                 }
961
962 destroy:
963                 cy_as_ll_destroy_request(dev_p, req_p);
964                 cy_as_ll_destroy_response(dev_p, reply_p);
965         } else if (dev_p->usb_count > 1) {
966                 /*
967                  * reset all LE_ps to inactive state, after cleaning
968                  * up any pending async read/write calls.
969                  */
970                 cy_as_usb_reset(dev_p);
971                 dev_p->usb_count--;
972
973                 if (cb)
974                         cb(handle, ret, client, CY_FUNCT_CB_USB_STOP, 0);
975         }
976
977         cy_as_device_clear_u_s_s_pending(dev_p);
978
979         return ret;
980 }
981 EXPORT_SYMBOL(cy_as_usb_stop);
982
983 /*
984 * This function registers a callback to be called when
985 * USB events are processed
986 */
987 cy_as_return_status_t
988 cy_as_usb_register_callback(cy_as_device_handle handle,
989         cy_as_usb_event_callback callback)
990 {
991         cy_as_device *dev_p;
992
993         cy_as_log_debug_message(6, "cy_as_usb_register_callback called");
994
995         dev_p = (cy_as_device *)handle;
996         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
997                 return CY_AS_ERROR_INVALID_HANDLE;
998
999         if (!cy_as_device_is_configured(dev_p))
1000                 return CY_AS_ERROR_NOT_CONFIGURED;
1001
1002         if (!cy_as_device_is_firmware_loaded(dev_p))
1003                 return CY_AS_ERROR_NO_FIRMWARE;
1004
1005         dev_p->usb_event_cb = NULL;
1006         dev_p->usb_event_cb_ms = callback;
1007         return CY_AS_ERROR_SUCCESS;
1008 }
1009 EXPORT_SYMBOL(cy_as_usb_register_callback);
1010
1011 static cy_as_return_status_t
1012 my_handle_response_no_data(cy_as_device *dev_p,
1013                                         cy_as_ll_request_response *req_p,
1014                                         cy_as_ll_request_response *reply_p)
1015 {
1016         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1017
1018         if (cy_as_ll_request_response__get_code(reply_p) !=
1019         CY_RESP_SUCCESS_FAILURE)
1020                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1021         else
1022                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1023
1024         cy_as_ll_destroy_request(dev_p, req_p);
1025         cy_as_ll_destroy_response(dev_p, reply_p);
1026
1027         return ret;
1028 }
1029
1030 static cy_as_return_status_t
1031 my_handle_response_connect(cy_as_device *dev_p,
1032                                            cy_as_ll_request_response *req_p,
1033                                            cy_as_ll_request_response *reply_p,
1034                                            cy_as_return_status_t ret)
1035 {
1036         if (ret != CY_AS_ERROR_SUCCESS)
1037                 goto destroy;
1038
1039         if (cy_as_ll_request_response__get_code(reply_p) !=
1040         CY_RESP_SUCCESS_FAILURE) {
1041                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1042                 goto destroy;
1043         }
1044
1045         ret = cy_as_ll_request_response__get_word(reply_p, 0);
1046         if (ret == CY_AS_ERROR_SUCCESS)
1047                 cy_as_device_set_usb_connected(dev_p);
1048
1049 destroy:
1050         cy_as_ll_destroy_request(dev_p, req_p);
1051         cy_as_ll_destroy_response(dev_p, reply_p);
1052
1053         return ret;
1054 }
1055
1056
1057 /*
1058 * This method asks the West Bridge device to connect the
1059 * internal USB D+ and D- signals to the USB pins, thus
1060 * starting the enumeration processes if the external pins
1061 * are connected to a USB host. If the external pins are
1062 * not connected to a USB host, enumeration will begin as soon
1063 * as the USB pins are connected to a host.
1064 */
1065 cy_as_return_status_t
1066 cy_as_usb_connect(cy_as_device_handle handle,
1067                                  cy_as_function_callback cb,
1068                                  uint32_t client)
1069 {
1070         cy_as_ll_request_response *req_p , *reply_p;
1071         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1072
1073         cy_as_device *dev_p;
1074
1075         cy_as_log_debug_message(6, "cy_as_usb_connect called");
1076
1077         dev_p = (cy_as_device *)handle;
1078         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1079                 return CY_AS_ERROR_INVALID_HANDLE;
1080
1081         ret = is_usb_active(dev_p);
1082         if (ret != CY_AS_ERROR_SUCCESS)
1083                 return ret;
1084
1085         if (cy_as_device_is_in_callback(dev_p))
1086                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1087
1088         /* Create the request to send to the West Bridge device */
1089         req_p = cy_as_ll_create_request(dev_p,
1090                 CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1);
1091         if (req_p == 0)
1092                 return CY_AS_ERROR_OUT_OF_MEMORY;
1093
1094         /* 1 = Connect request */
1095         cy_as_ll_request_response__set_word(req_p, 0, 1);
1096
1097         /* Reserve space for the reply, the reply
1098          * data will not exceed one word */
1099         reply_p = cy_as_ll_create_response(dev_p, 1);
1100         if (reply_p == 0) {
1101                 cy_as_ll_destroy_request(dev_p, req_p);
1102                 return CY_AS_ERROR_OUT_OF_MEMORY;
1103         }
1104
1105         if (cb == 0) {
1106                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1107                 if (ret != CY_AS_ERROR_SUCCESS)
1108                         goto destroy;
1109
1110                 return my_handle_response_connect(dev_p, req_p, reply_p, ret);
1111         } else {
1112                 ret = cy_as_misc_send_request(dev_p, cb, client,
1113                         CY_FUNCT_CB_USB_CONNECT, 0, dev_p->func_cbs_usb,
1114                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1115                         cy_as_usb_func_callback);
1116
1117                 if (ret != CY_AS_ERROR_SUCCESS)
1118                         goto destroy;
1119
1120                 return ret;
1121         }
1122
1123 destroy:
1124         cy_as_ll_destroy_request(dev_p, req_p);
1125         cy_as_ll_destroy_response(dev_p, reply_p);
1126
1127         return ret;
1128 }
1129 EXPORT_SYMBOL(cy_as_usb_connect);
1130
1131 static cy_as_return_status_t
1132 my_handle_response_disconnect(cy_as_device *dev_p,
1133                                            cy_as_ll_request_response *req_p,
1134                                            cy_as_ll_request_response *reply_p,
1135                                            cy_as_return_status_t ret)
1136 {
1137         if (ret != CY_AS_ERROR_SUCCESS)
1138                 goto destroy;
1139
1140         if (cy_as_ll_request_response__get_code(reply_p) !=
1141         CY_RESP_SUCCESS_FAILURE) {
1142                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1143                 goto destroy;
1144         }
1145
1146         ret = cy_as_ll_request_response__get_word(reply_p, 0);
1147         if (ret == CY_AS_ERROR_SUCCESS)
1148                 cy_as_device_clear_usb_connected(dev_p);
1149
1150 destroy:
1151         cy_as_ll_destroy_request(dev_p, req_p);
1152         cy_as_ll_destroy_response(dev_p, reply_p);
1153
1154         return ret;
1155 }
1156 /*
1157 * This method forces a disconnect of the D+ and D- pins
1158 * external to the West Bridge device from the D+ and D-
1159 * signals internally, effectively disconnecting the West
1160 * Bridge device from any connected USB host.
1161 */
1162 cy_as_return_status_t
1163 cy_as_usb_disconnect(cy_as_device_handle handle,
1164                                         cy_as_function_callback cb,
1165                                         uint32_t client)
1166 {
1167         cy_as_ll_request_response *req_p , *reply_p;
1168         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1169
1170         cy_as_device *dev_p;
1171
1172         cy_as_log_debug_message(6, "cy_as_usb_disconnect called");
1173
1174         dev_p = (cy_as_device *)handle;
1175         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1176                 return CY_AS_ERROR_INVALID_HANDLE;
1177
1178         ret = is_usb_active(dev_p);
1179         if (ret != CY_AS_ERROR_SUCCESS)
1180                 return ret;
1181
1182         if (cy_as_device_is_in_callback(dev_p))
1183                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1184
1185         if (!cy_as_device_is_usb_connected(dev_p))
1186                 return CY_AS_ERROR_USB_NOT_CONNECTED;
1187
1188         /* Create the request to send to the West Bridge device */
1189         req_p = cy_as_ll_create_request(dev_p,
1190                 CY_RQT_SET_CONNECT_STATE, CY_RQT_USB_RQT_CONTEXT, 1);
1191         if (req_p == 0)
1192                 return CY_AS_ERROR_OUT_OF_MEMORY;
1193
1194         cy_as_ll_request_response__set_word(req_p, 0, 0);
1195
1196         /* Reserve space for the reply, the reply
1197          * data will not exceed two bytes */
1198         reply_p = cy_as_ll_create_response(dev_p, 1);
1199         if (reply_p == 0) {
1200                 cy_as_ll_destroy_request(dev_p, req_p);
1201                 return CY_AS_ERROR_OUT_OF_MEMORY;
1202         }
1203
1204         if (cb == 0) {
1205                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1206                 if (ret != CY_AS_ERROR_SUCCESS)
1207                         goto destroy;
1208
1209                 return my_handle_response_disconnect(dev_p,
1210                         req_p, reply_p, ret);
1211         } else {
1212                 ret = cy_as_misc_send_request(dev_p, cb, client,
1213                         CY_FUNCT_CB_USB_DISCONNECT, 0, dev_p->func_cbs_usb,
1214                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1215                         cy_as_usb_func_callback);
1216
1217                 if (ret != CY_AS_ERROR_SUCCESS)
1218                         goto destroy;
1219
1220                 return ret;
1221         }
1222 destroy:
1223         cy_as_ll_destroy_request(dev_p, req_p);
1224         cy_as_ll_destroy_response(dev_p, reply_p);
1225
1226         return ret;
1227 }
1228 EXPORT_SYMBOL(cy_as_usb_disconnect);
1229
1230 static cy_as_return_status_t
1231 my_handle_response_set_enum_config(cy_as_device *dev_p,
1232                         cy_as_ll_request_response *req_p,
1233                         cy_as_ll_request_response *reply_p)
1234 {
1235         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1236
1237         if (cy_as_ll_request_response__get_code(reply_p) !=
1238         CY_RESP_SUCCESS_FAILURE) {
1239                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1240                 goto destroy;
1241         }
1242
1243         ret = cy_as_ll_request_response__get_word(reply_p, 0);
1244
1245         if (ret == CY_AS_ERROR_SUCCESS) {
1246                 /*
1247                 * we configured the west bridge device and
1248                 * enumeration is going to happen on the P port
1249                 * processor.  now we must enable endpoint zero
1250                 */
1251                 cy_as_usb_end_point_config config;
1252
1253                 config.dir = cy_as_usb_in_out;
1254                 config.type = cy_as_usb_control;
1255                 config.enabled = cy_true;
1256
1257                 ret = cy_as_usb_set_end_point_config((cy_as_device_handle *)
1258                         dev_p, 0, &config);
1259         }
1260
1261 destroy:
1262                 cy_as_ll_destroy_request(dev_p, req_p);
1263                 cy_as_ll_destroy_response(dev_p, reply_p);
1264
1265                 return ret;
1266 }
1267
1268 /*
1269 * This method sets how the USB is enumerated and should
1270 * be called before the CyAsUsbConnect() is called.
1271 */
1272 static cy_as_return_status_t
1273 my_usb_set_enum_config(cy_as_device *dev_p,
1274                                         uint8_t bus_mask,
1275                                         uint8_t media_mask,
1276                                         cy_bool use_antioch_enumeration,
1277                                         uint8_t mass_storage_interface,
1278                                         uint8_t mtp_interface,
1279                                         cy_bool mass_storage_callbacks,
1280                                         cy_as_function_callback cb,
1281                                         uint32_t client)
1282 {
1283         cy_as_ll_request_response *req_p , *reply_p;
1284         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1285
1286         cy_as_log_debug_message(6, "cy_as_usb_set_enum_config called");
1287
1288         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1289                 return CY_AS_ERROR_INVALID_HANDLE;
1290
1291         ret = is_usb_active(dev_p);
1292         if (ret != CY_AS_ERROR_SUCCESS)
1293                 return ret;
1294
1295         if (cy_as_device_is_usb_connected(dev_p))
1296                 return CY_AS_ERROR_USB_CONNECTED;
1297
1298         if (cy_as_device_is_in_callback(dev_p))
1299                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1300
1301         /* if we are using MTP firmware:  */
1302         if (dev_p->is_mtp_firmware == 1) {
1303                 /* we cannot enumerate MSC */
1304                 if (mass_storage_interface != 0)
1305                         return CY_AS_ERROR_INVALID_CONFIGURATION;
1306
1307                 if (bus_mask == 0) {
1308                         if (mtp_interface != 0)
1309                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
1310                 } else if (bus_mask == 2) {
1311                         /* enable EP 1 as it will be used */
1312                         cy_as_dma_enable_end_point(dev_p, 1, cy_true,
1313                                 cy_as_direction_in);
1314                         dev_p->usb_config[1].enabled = cy_true;
1315                         dev_p->usb_config[1].dir = cy_as_usb_in;
1316                         dev_p->usb_config[1].type = cy_as_usb_int;
1317                 } else {
1318                         return CY_AS_ERROR_INVALID_CONFIGURATION;
1319                 }
1320         /* if we are not using MTP firmware, we cannot enumerate MTP */
1321         } else if (mtp_interface != 0)
1322                 return CY_AS_ERROR_INVALID_CONFIGURATION;
1323
1324         /*
1325         * if we are not enumerating mass storage, we should
1326         * not be providing an interface number.
1327         */
1328         if (bus_mask == 0 && mass_storage_interface != 0)
1329                 return CY_AS_ERROR_INVALID_CONFIGURATION;
1330
1331         /*
1332         * if we are going to use mtp_interface, bus mask must be 2.
1333         */
1334         if (mtp_interface != 0 && bus_mask != 2)
1335                 return CY_AS_ERROR_INVALID_CONFIGURATION;
1336
1337
1338         /* Create the request to send to the West Bridge device */
1339         req_p = cy_as_ll_create_request(dev_p,
1340                 CY_RQT_SET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 4);
1341         if (req_p == 0)
1342                 return CY_AS_ERROR_OUT_OF_MEMORY;
1343
1344         /* Marshal the structure */
1345         cy_as_ll_request_response__set_word(req_p, 0,
1346                 (uint16_t)((media_mask << 8) | bus_mask));
1347         cy_as_ll_request_response__set_word(req_p, 1,
1348                 (uint16_t)use_antioch_enumeration);
1349         cy_as_ll_request_response__set_word(req_p, 2,
1350                 dev_p->is_mtp_firmware ? mtp_interface :
1351                         mass_storage_interface);
1352         cy_as_ll_request_response__set_word(req_p, 3,
1353                 (uint16_t)mass_storage_callbacks);
1354
1355         /* Reserve space for the reply, the reply
1356          * data will not exceed one word */
1357         reply_p = cy_as_ll_create_response(dev_p, 1);
1358         if (reply_p == 0) {
1359                 cy_as_ll_destroy_request(dev_p, req_p);
1360                 return CY_AS_ERROR_OUT_OF_MEMORY;
1361         }
1362
1363         if (cb == 0) {
1364
1365                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1366                 if (ret != CY_AS_ERROR_SUCCESS)
1367                         goto destroy;
1368
1369                 return my_handle_response_set_enum_config(dev_p,
1370                                         req_p, reply_p);
1371         } else {
1372                 ret = cy_as_misc_send_request(dev_p, cb, client,
1373                         CY_FUNCT_CB_USB_SETENUMCONFIG,  0, dev_p->func_cbs_usb,
1374                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1375                         cy_as_usb_func_callback);
1376
1377                 if (ret != CY_AS_ERROR_SUCCESS)
1378                         goto destroy;
1379
1380                 return ret;
1381         }
1382
1383 destroy:
1384         cy_as_ll_destroy_request(dev_p, req_p);
1385         cy_as_ll_destroy_response(dev_p, reply_p);
1386
1387         return ret;
1388 }
1389
1390 /*
1391  * This method sets how the USB is enumerated and should
1392  * be called before the CyAsUsbConnect() is called.
1393  */
1394 cy_as_return_status_t
1395 cy_as_usb_set_enum_config(cy_as_device_handle handle,
1396                                            cy_as_usb_enum_control *config_p,
1397                                            cy_as_function_callback cb,
1398                                            uint32_t client)
1399 {
1400         cy_as_device *dev_p = (cy_as_device *)handle;
1401         uint8_t bus_mask, media_mask;
1402         uint32_t bus, device;
1403         cy_as_return_status_t ret;
1404
1405         dev_p = (cy_as_device *)handle;
1406         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1407                 return CY_AS_ERROR_INVALID_HANDLE;
1408
1409         ret = is_usb_active(dev_p);
1410         if (ret != CY_AS_ERROR_SUCCESS)
1411                 return ret;
1412
1413         if ((cy_as_device_is_in_callback(dev_p))  && (cb != 0))
1414                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1415
1416         /* Since we are mapping the media types to bus with NAND to 0
1417          * and the rest to 1, and we are only allowing for enumerating
1418          * all the devices on a bus we just scan the array for any
1419          * positions where there a device is enabled and mark the bus
1420          * to be enumerated.
1421          */
1422         bus_mask   = 0;
1423         media_mask = 0;
1424         for (bus = 0; bus < CY_AS_MAX_BUSES; bus++) {
1425                 for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES; device++) {
1426                         if (config_p->devices_to_enumerate[bus][device] ==
1427                         cy_true) {
1428                                 bus_mask   |= (0x01 << bus);
1429                                 media_mask |= dev_p->media_supported[bus];
1430                                 media_mask |= dev_p->media_supported[bus];
1431                         }
1432                 }
1433         }
1434
1435         return my_usb_set_enum_config(dev_p, bus_mask, media_mask,
1436                         config_p->antioch_enumeration,
1437                         config_p->mass_storage_interface,
1438                         config_p->mtp_interface,
1439                         config_p->mass_storage_callbacks,
1440                         cb,
1441                         client
1442                 );
1443 }
1444 EXPORT_SYMBOL(cy_as_usb_set_enum_config);
1445
1446 static cy_as_return_status_t
1447 my_handle_response_get_enum_config(cy_as_device *dev_p,
1448                         cy_as_ll_request_response *req_p,
1449                         cy_as_ll_request_response *reply_p,
1450                         void *config_p)
1451 {
1452         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1453         uint16_t val;
1454         uint8_t bus_mask;
1455         uint32_t bus;
1456
1457         if (cy_as_ll_request_response__get_code(reply_p) !=
1458         CY_RESP_USB_CONFIG) {
1459                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1460                 goto destroy;
1461         }
1462
1463         /* Marshal the reply */
1464         if (req_p->flags & CY_AS_REQUEST_RESPONSE_MS) {
1465                 uint32_t device;
1466                 cy_bool state;
1467                 cy_as_usb_enum_control *ms_config_p =
1468                         (cy_as_usb_enum_control *)config_p;
1469
1470                 bus_mask = (uint8_t)
1471                         (cy_as_ll_request_response__get_word
1472                         (reply_p, 0) & 0xFF);
1473                 for (bus = 0; bus < CY_AS_MAX_BUSES; bus++)  {
1474                         if (bus_mask & (1 << bus))
1475                                 state = cy_true;
1476                         else
1477                                 state = cy_false;
1478
1479                         for (device = 0; device < CY_AS_MAX_STORAGE_DEVICES;
1480                                 device++)
1481                                 ms_config_p->devices_to_enumerate[bus][device]
1482                                         = state;
1483                 }
1484
1485                 ms_config_p->antioch_enumeration =
1486                         (cy_bool)cy_as_ll_request_response__get_word
1487                                 (reply_p, 1);
1488
1489                 val = cy_as_ll_request_response__get_word(reply_p, 2);
1490                 if (dev_p->is_mtp_firmware) {
1491                         ms_config_p->mass_storage_interface = 0;
1492                         ms_config_p->mtp_interface = (uint8_t)(val & 0xFF);
1493                 } else {
1494                         ms_config_p->mass_storage_interface =
1495                                 (uint8_t)(val & 0xFF);
1496                         ms_config_p->mtp_interface = 0;
1497                 }
1498                 ms_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
1499
1500                 /*
1501                 * firmware returns an invalid interface number for mass storage,
1502                 * if mass storage is not enabled. this needs to be converted to
1503                 * zero to match the input configuration.
1504                 */
1505                 if (bus_mask == 0) {
1506                         if (dev_p->is_mtp_firmware)
1507                                 ms_config_p->mtp_interface = 0;
1508                         else
1509                                 ms_config_p->mass_storage_interface = 0;
1510                 }
1511         } else {
1512                 cy_as_usb_enum_control_dep *ex_config_p =
1513                         (cy_as_usb_enum_control_dep *)config_p;
1514
1515                 ex_config_p->enum_mass_storage = (uint8_t)
1516                         ((cy_as_ll_request_response__get_word
1517                                 (reply_p, 0) >> 8) & 0xFF);
1518                 ex_config_p->antioch_enumeration = (cy_bool)
1519                         cy_as_ll_request_response__get_word(reply_p, 1);
1520
1521                 val = cy_as_ll_request_response__get_word(reply_p, 2);
1522                 ex_config_p->mass_storage_interface = (uint8_t)(val & 0xFF);
1523                 ex_config_p->mass_storage_callbacks = (cy_bool)(val >> 8);
1524
1525                 /*
1526                 * firmware returns an invalid interface number for mass
1527                 * storage, if mass storage is not enabled. this needs to
1528                 * be converted to zero to match the input configuration.
1529                 */
1530                 if (ex_config_p->enum_mass_storage == 0)
1531                         ex_config_p->mass_storage_interface = 0;
1532         }
1533
1534 destroy:
1535         cy_as_ll_destroy_request(dev_p, req_p);
1536         cy_as_ll_destroy_response(dev_p, reply_p);
1537
1538         return ret;
1539 }
1540
1541 /*
1542 * This sets up the request for the enumerateion configuration
1543 * information, based on if the request is from the old pre-1.2
1544 * functions.
1545 */
1546 static cy_as_return_status_t
1547 my_usb_get_enum_config(cy_as_device_handle handle,
1548                                         uint16_t req_flags,
1549                                         void *config_p,
1550                                         cy_as_function_callback cb,
1551                                         uint32_t client)
1552 {
1553         cy_as_ll_request_response *req_p , *reply_p;
1554         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1555
1556         cy_as_device *dev_p;
1557
1558         cy_as_log_debug_message(6, "cy_as_usb_get_enum_config called");
1559
1560         dev_p = (cy_as_device *)handle;
1561         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1562                 return CY_AS_ERROR_INVALID_HANDLE;
1563
1564         ret = is_usb_active(dev_p);
1565         if (ret != CY_AS_ERROR_SUCCESS)
1566                 return ret;
1567
1568         if (cy_as_device_is_in_callback(dev_p))
1569                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1570
1571         /* Create the request to send to the West Bridge device */
1572         req_p = cy_as_ll_create_request(dev_p,
1573                 CY_RQT_GET_USB_CONFIG, CY_RQT_USB_RQT_CONTEXT, 0);
1574         if (req_p == 0)
1575                 return CY_AS_ERROR_OUT_OF_MEMORY;
1576
1577         /* Reserve space for the reply, the reply data
1578          * will not exceed two bytes */
1579         reply_p = cy_as_ll_create_response(dev_p, 3);
1580         if (reply_p == 0) {
1581                 cy_as_ll_destroy_request(dev_p, req_p);
1582                 return CY_AS_ERROR_OUT_OF_MEMORY;
1583         }
1584
1585         if (cb == 0) {
1586                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1587                 if (ret != CY_AS_ERROR_SUCCESS)
1588                         goto destroy;
1589
1590                 /* we need to know the type of request to
1591                  * know how to manage the data */
1592                 req_p->flags |= req_flags;
1593                 return my_handle_response_get_enum_config(dev_p,
1594                         req_p, reply_p, config_p);
1595         } else {
1596                 ret = cy_as_misc_send_request(dev_p, cb, client,
1597                         CY_FUNCT_CB_USB_GETENUMCONFIG, config_p,
1598                         dev_p->func_cbs_usb, req_flags, req_p, reply_p,
1599                         cy_as_usb_func_callback);
1600
1601                 if (ret != CY_AS_ERROR_SUCCESS)
1602                         goto destroy;
1603
1604                 return ret;
1605         }
1606
1607 destroy:
1608         cy_as_ll_destroy_request(dev_p, req_p);
1609         cy_as_ll_destroy_response(dev_p, reply_p);
1610
1611         return ret;
1612 }
1613
1614 /*
1615  * This method returns the enumerateion configuration information
1616  * from the West Bridge device. Generally this is not used by
1617  * client software but is provided mostly for debug information.
1618  * We want a method to read all state information from the device.
1619  */
1620 cy_as_return_status_t
1621 cy_as_usb_get_enum_config(cy_as_device_handle handle,
1622                                            cy_as_usb_enum_control *config_p,
1623                                            cy_as_function_callback cb,
1624                                            uint32_t client)
1625 {
1626         return my_usb_get_enum_config(handle,
1627                 CY_AS_REQUEST_RESPONSE_MS, config_p, cb, client);
1628 }
1629 EXPORT_SYMBOL(cy_as_usb_get_enum_config);
1630
1631 /*
1632 * This method sets the USB descriptor for a given entity.
1633 */
1634 cy_as_return_status_t
1635 cy_as_usb_set_descriptor(cy_as_device_handle handle,
1636                                            cy_as_usb_desc_type type,
1637                                            uint8_t index,
1638                                            void *desc_p,
1639                                            uint16_t length,
1640                                            cy_as_function_callback cb,
1641                                            uint32_t client)
1642 {
1643         cy_as_ll_request_response *req_p , *reply_p;
1644         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1645         uint16_t pktlen;
1646
1647         cy_as_device *dev_p;
1648
1649         cy_as_log_debug_message(6, "cy_as_usb_set_descriptor called");
1650
1651         dev_p = (cy_as_device *)handle;
1652         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1653                 return CY_AS_ERROR_INVALID_HANDLE;
1654
1655         ret = is_usb_active(dev_p);
1656         if (ret != CY_AS_ERROR_SUCCESS)
1657                 return ret;
1658
1659         if (cy_as_device_is_in_callback(dev_p))
1660                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1661
1662         if (length > CY_AS_MAX_USB_DESCRIPTOR_SIZE)
1663                 return CY_AS_ERROR_INVALID_DESCRIPTOR;
1664
1665         pktlen = (uint16_t)length / 2;
1666         if (length % 2)
1667                 pktlen++;
1668         pktlen += 2; /* 1 for type, 1 for length */
1669
1670         /* Create the request to send to the West Bridge device */
1671         req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_DESCRIPTOR,
1672                 CY_RQT_USB_RQT_CONTEXT, (uint16_t)pktlen);
1673         if (req_p == 0)
1674                 return CY_AS_ERROR_OUT_OF_MEMORY;
1675
1676         cy_as_ll_request_response__set_word(req_p, 0,
1677                 (uint16_t)((uint8_t)type | (index << 8)));
1678         cy_as_ll_request_response__set_word(req_p, 1,
1679                 (uint16_t)length);
1680         cy_as_ll_request_response__pack(req_p, 2, length, desc_p);
1681
1682         reply_p = cy_as_ll_create_response(dev_p, 1);
1683         if (reply_p == 0) {
1684                 cy_as_ll_destroy_request(dev_p, req_p);
1685                 return CY_AS_ERROR_OUT_OF_MEMORY;
1686         }
1687
1688         if (cb == 0) {
1689                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1690                 if (ret != CY_AS_ERROR_SUCCESS)
1691                         goto destroy;
1692
1693                 return my_handle_response_no_data(dev_p, req_p, reply_p);
1694         } else {
1695                 ret = cy_as_misc_send_request(dev_p, cb, client,
1696                         CY_FUNCT_CB_USB_SETDESCRIPTOR, 0, dev_p->func_cbs_usb,
1697                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1698                         cy_as_usb_func_callback);
1699
1700                 if (ret != CY_AS_ERROR_SUCCESS)
1701                         goto destroy;
1702
1703                 return ret;
1704         }
1705
1706 destroy:
1707         cy_as_ll_destroy_request(dev_p, req_p);
1708         cy_as_ll_destroy_response(dev_p, reply_p);
1709
1710         return ret;
1711 }
1712 EXPORT_SYMBOL(cy_as_usb_set_descriptor);
1713
1714 /*
1715  * This method clears all descriptors that were previously
1716  * stored on the West Bridge through CyAsUsbSetDescriptor calls.
1717  */
1718 cy_as_return_status_t
1719 cy_as_usb_clear_descriptors(cy_as_device_handle handle,
1720                                            cy_as_function_callback cb,
1721                                            uint32_t client)
1722 {
1723         cy_as_ll_request_response *req_p , *reply_p;
1724         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1725
1726         cy_as_device *dev_p;
1727
1728         cy_as_log_debug_message(6, "cy_as_usb_clear_descriptors called");
1729
1730         dev_p = (cy_as_device *)handle;
1731         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1732                 return CY_AS_ERROR_INVALID_HANDLE;
1733
1734         ret = is_usb_active(dev_p);
1735         if (ret != CY_AS_ERROR_SUCCESS)
1736                 return ret;
1737
1738         if ((cy_as_device_is_in_callback(dev_p)) && (cb == 0))
1739                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1740
1741         /* Create the request to send to the West Bridge device */
1742         req_p = cy_as_ll_create_request(dev_p,
1743                 CY_RQT_CLEAR_DESCRIPTORS, CY_RQT_USB_RQT_CONTEXT, 1);
1744         if (req_p == 0)
1745                 return CY_AS_ERROR_OUT_OF_MEMORY;
1746
1747         reply_p = cy_as_ll_create_response(dev_p, 1);
1748         if (reply_p == 0) {
1749                 cy_as_ll_destroy_request(dev_p, req_p);
1750                 return CY_AS_ERROR_OUT_OF_MEMORY;
1751         }
1752
1753         if (cb == 0) {
1754
1755                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1756                 if (ret != CY_AS_ERROR_SUCCESS)
1757                         goto destroy;
1758
1759                 return my_handle_response_no_data(dev_p, req_p, reply_p);
1760         } else {
1761                 ret = cy_as_misc_send_request(dev_p, cb, client,
1762                         CY_FUNCT_CB_USB_CLEARDESCRIPTORS, 0,
1763                         dev_p->func_cbs_usb,
1764                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1765                         cy_as_usb_func_callback);
1766
1767                 if (ret != CY_AS_ERROR_SUCCESS)
1768                         goto destroy;
1769
1770                 return ret;
1771         }
1772
1773 destroy:
1774         cy_as_ll_destroy_request(dev_p, req_p);
1775         cy_as_ll_destroy_response(dev_p, reply_p);
1776
1777         return ret;
1778 }
1779 EXPORT_SYMBOL(cy_as_usb_clear_descriptors);
1780
1781 static cy_as_return_status_t
1782 my_handle_response_get_descriptor(cy_as_device *dev_p,
1783                                         cy_as_ll_request_response *req_p,
1784                                         cy_as_ll_request_response *reply_p,
1785                                         cy_as_get_descriptor_data *data)
1786 {
1787         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1788          uint32_t retlen;
1789
1790         if (cy_as_ll_request_response__get_code(reply_p) ==
1791         CY_RESP_SUCCESS_FAILURE) {
1792                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1793                 goto destroy;
1794         } else if (cy_as_ll_request_response__get_code(reply_p) !=
1795         CY_RESP_USB_DESCRIPTOR) {
1796                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1797                 goto destroy;
1798         }
1799
1800         retlen = cy_as_ll_request_response__get_word(reply_p, 0);
1801         if (retlen > data->length) {
1802                 ret = CY_AS_ERROR_INVALID_SIZE;
1803                 goto destroy;
1804         }
1805
1806         ret = CY_AS_ERROR_SUCCESS;
1807         cy_as_ll_request_response__unpack(reply_p, 1,
1808                 retlen, data->desc_p);
1809
1810 destroy:
1811                 cy_as_ll_destroy_request(dev_p, req_p);
1812                 cy_as_ll_destroy_response(dev_p, reply_p);
1813
1814                 return ret;
1815 }
1816
1817 /*
1818 * This method retreives the USB descriptor for a given type.
1819 */
1820 cy_as_return_status_t
1821 cy_as_usb_get_descriptor(cy_as_device_handle handle,
1822                                            cy_as_usb_desc_type type,
1823                                            uint8_t index,
1824                                            cy_as_get_descriptor_data *data,
1825                                            cy_as_function_callback cb,
1826                                            uint32_t client)
1827 {
1828         cy_as_return_status_t ret;
1829         cy_as_ll_request_response *req_p , *reply_p;
1830
1831         cy_as_device *dev_p;
1832
1833         cy_as_log_debug_message(6, "cy_as_usb_get_descriptor called");
1834
1835         dev_p = (cy_as_device *)handle;
1836         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1837                 return CY_AS_ERROR_INVALID_HANDLE;
1838
1839         ret = is_usb_active(dev_p);
1840         if (ret != CY_AS_ERROR_SUCCESS)
1841                 return ret;
1842
1843         if (cy_as_device_is_in_callback(dev_p))
1844                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1845
1846         /* Create the request to send to the West Bridge device */
1847         req_p = cy_as_ll_create_request(dev_p,
1848                 CY_RQT_GET_DESCRIPTOR, CY_RQT_USB_RQT_CONTEXT, 1);
1849         if (req_p == 0)
1850                 return CY_AS_ERROR_OUT_OF_MEMORY;
1851
1852         cy_as_ll_request_response__set_word(req_p, 0,
1853                 (uint16_t)((uint8_t)type | (index << 8)));
1854
1855         /* Add one for the length field */
1856         reply_p = cy_as_ll_create_response(dev_p,
1857                 CY_AS_MAX_USB_DESCRIPTOR_SIZE + 1);
1858         if (reply_p == 0) {
1859                 cy_as_ll_destroy_request(dev_p, req_p);
1860                 return CY_AS_ERROR_OUT_OF_MEMORY;
1861         }
1862
1863         if (cb == 0) {
1864                 ret = cy_as_ll_send_request_wait_reply(
1865                                 dev_p, req_p, reply_p);
1866                 if (ret != CY_AS_ERROR_SUCCESS)
1867                         goto destroy;
1868
1869                 return my_handle_response_get_descriptor(dev_p,
1870                         req_p, reply_p, data);
1871         } else {
1872                 ret = cy_as_misc_send_request(dev_p, cb, client,
1873                         CY_FUNCT_CB_USB_GETDESCRIPTOR, data,
1874                         dev_p->func_cbs_usb,
1875                         CY_AS_REQUEST_RESPONSE_EX, req_p,
1876                         reply_p,  cy_as_usb_func_callback);
1877
1878                 if (ret != CY_AS_ERROR_SUCCESS)
1879                         goto destroy;
1880
1881                 return ret;
1882         }
1883
1884 destroy:
1885         cy_as_ll_destroy_request(dev_p, req_p);
1886         cy_as_ll_destroy_response(dev_p, reply_p);
1887
1888         return ret;
1889 }
1890 EXPORT_SYMBOL(cy_as_usb_get_descriptor);
1891
1892 cy_as_return_status_t
1893 cy_as_usb_set_physical_configuration(cy_as_device_handle handle,
1894         uint8_t config)
1895 {
1896         cy_as_return_status_t ret;
1897         cy_as_device *dev_p;
1898
1899         cy_as_log_debug_message(6,
1900                 "cy_as_usb_set_physical_configuration called");
1901
1902         dev_p = (cy_as_device *)handle;
1903         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1904                 return CY_AS_ERROR_INVALID_HANDLE;
1905
1906         ret = is_usb_active(dev_p);
1907         if (ret != CY_AS_ERROR_SUCCESS)
1908                 return ret;
1909
1910         if (cy_as_device_is_usb_connected(dev_p))
1911                 return CY_AS_ERROR_USB_CONNECTED;
1912
1913         if (config < 1 || config > 12)
1914                 return CY_AS_ERROR_INVALID_CONFIGURATION;
1915
1916         dev_p->usb_phy_config = config;
1917
1918         return CY_AS_ERROR_SUCCESS;
1919 }
1920 EXPORT_SYMBOL(cy_as_usb_set_physical_configuration);
1921
1922 static cy_bool
1923 is_physical_valid(uint8_t config, cy_as_end_point_number_t ep)
1924 {
1925         static uint8_t validmask[12] = {
1926                 0x0f,      /* Config  1 - 1, 2, 3, 4 */
1927                 0x07,      /* Config  2 - 1, 2, 3 */
1928                 0x07,      /* Config  3 - 1, 2, 3 */
1929                 0x0d,      /* Config  4 - 1, 3, 4 */
1930                 0x05,      /* Config  5 - 1, 3 */
1931                 0x05,      /* Config  6 - 1, 3 */
1932                 0x0d,      /* Config  7 - 1, 3, 4 */
1933                 0x05,      /* Config  8 - 1, 3 */
1934                 0x05,      /* Config  9 - 1, 3 */
1935                 0x0d,      /* Config 10 - 1, 3, 4 */
1936                 0x09,      /* Config 11 - 1, 4 */
1937                 0x01            /* Config 12 - 1 */
1938         };
1939
1940         return (validmask[config - 1] & (1 << (ep - 1))) ? cy_true : cy_false;
1941 }
1942
1943 /*
1944 * This method sets the configuration for an endpoint
1945 */
1946 cy_as_return_status_t
1947 cy_as_usb_set_end_point_config(cy_as_device_handle handle,
1948         cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
1949 {
1950         cy_as_return_status_t ret;
1951         cy_as_device *dev_p;
1952
1953         cy_as_log_debug_message(6, "cy_as_usb_set_end_point_config called");
1954
1955         dev_p = (cy_as_device *)handle;
1956         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1957                 return CY_AS_ERROR_INVALID_HANDLE;
1958
1959         ret = is_usb_active(dev_p);
1960         if (ret != CY_AS_ERROR_SUCCESS)
1961                 return ret;
1962
1963         if (cy_as_device_is_usb_connected(dev_p))
1964                 return CY_AS_ERROR_USB_CONNECTED;
1965
1966         if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
1967                 return CY_AS_ERROR_INVALID_ENDPOINT;
1968
1969         if (ep == 0) {
1970                 /* Endpoint 0 must be 64 byte, dir IN/OUT,
1971                  * and control type */
1972                 if (config_p->dir != cy_as_usb_in_out ||
1973                         config_p->type != cy_as_usb_control)
1974                         return CY_AS_ERROR_INVALID_CONFIGURATION;
1975         } else if (ep == 1) {
1976                 if ((dev_p->is_mtp_firmware == 1) &&
1977                 (dev_p->usb_config[1].enabled == cy_true)) {
1978                         return CY_AS_ERROR_INVALID_ENDPOINT;
1979                 }
1980
1981                 /*
1982                  * EP1 can only be used either as an OUT ep, or as an IN ep.
1983                  */
1984                 if ((config_p->type == cy_as_usb_control) ||
1985                         (config_p->type == cy_as_usb_iso) ||
1986                         (config_p->dir == cy_as_usb_in_out))
1987                         return CY_AS_ERROR_INVALID_CONFIGURATION;
1988         } else {
1989                 if (config_p->dir == cy_as_usb_in_out ||
1990                         config_p->type == cy_as_usb_control)
1991                         return CY_AS_ERROR_INVALID_CONFIGURATION;
1992
1993                 if (!is_physical_valid(dev_p->usb_phy_config,
1994                         config_p->physical))
1995                         return CY_AS_ERROR_INVALID_PHYSICAL_ENDPOINT;
1996
1997                 /*
1998                 * ISO endpoints must be on E_ps 3, 5, 7 or 9 as
1999                 * they need to align directly with the underlying
2000                 * physical endpoint.
2001                 */
2002                 if (config_p->type == cy_as_usb_iso) {
2003                         if (ep != 3 && ep != 5 && ep != 7 && ep != 9)
2004                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2005
2006                         if (ep == 3 && config_p->physical != 1)
2007                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2008
2009                         if (ep == 5 && config_p->physical != 2)
2010                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2011
2012                         if (ep == 7 && config_p->physical != 3)
2013                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2014
2015                         if (ep == 9 && config_p->physical != 4)
2016                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
2017                 }
2018         }
2019
2020         /* Store the configuration information until a
2021          * CyAsUsbCommitConfig is done */
2022         dev_p->usb_config[ep] = *config_p;
2023
2024         /* If the endpoint is enabled, enable DMA associated
2025          * with the endpoint */
2026         /*
2027         * we make some assumptions that we check here.  we assume
2028         * that the direction fields for the DMA module are the same
2029         * values as the direction values for the USB module.
2030         */
2031         cy_as_hal_assert((int)cy_as_usb_in == (int)cy_as_direction_in);
2032         cy_as_hal_assert((int)cy_as_usb_out == (int)cy_as_direction_out);
2033         cy_as_hal_assert((int)cy_as_usb_in_out == (int)cy_as_direction_in_out);
2034
2035         return cy_as_dma_enable_end_point(dev_p, ep,
2036                 config_p->enabled, (cy_as_dma_direction)config_p->dir);
2037 }
2038 EXPORT_SYMBOL(cy_as_usb_set_end_point_config);
2039
2040 cy_as_return_status_t
2041 cy_as_usb_get_end_point_config(cy_as_device_handle handle,
2042         cy_as_end_point_number_t ep, cy_as_usb_end_point_config *config_p)
2043 {
2044         cy_as_return_status_t ret;
2045
2046         cy_as_device *dev_p;
2047
2048         cy_as_log_debug_message(6, "cy_as_usb_get_end_point_config called");
2049
2050         dev_p = (cy_as_device *)handle;
2051         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2052                 return CY_AS_ERROR_INVALID_HANDLE;
2053
2054         ret = is_usb_active(dev_p);
2055         if (ret != CY_AS_ERROR_SUCCESS)
2056                 return ret;
2057
2058         if (ep >= 16 || ep == 2 || ep == 4 || ep == 6 || ep == 8)
2059                 return CY_AS_ERROR_INVALID_ENDPOINT;
2060
2061         *config_p = dev_p->usb_config[ep];
2062
2063         return CY_AS_ERROR_SUCCESS;
2064 }
2065 EXPORT_SYMBOL(cy_as_usb_get_end_point_config);
2066
2067 /*
2068 * Commit the configuration of the various endpoints to the hardware.
2069 */
2070 cy_as_return_status_t
2071 cy_as_usb_commit_config(cy_as_device_handle handle,
2072                                           cy_as_function_callback cb,
2073                                           uint32_t client)
2074 {
2075         uint32_t i;
2076         cy_as_return_status_t ret;
2077         cy_as_ll_request_response *req_p , *reply_p;
2078         cy_as_device *dev_p;
2079         uint16_t data;
2080
2081         cy_as_log_debug_message(6, "cy_as_usb_commit_config called");
2082
2083         dev_p = (cy_as_device *)handle;
2084         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2085                 return CY_AS_ERROR_INVALID_HANDLE;
2086
2087         ret = is_usb_active(dev_p);
2088         if (ret != CY_AS_ERROR_SUCCESS)
2089                 return ret;
2090
2091         if (cy_as_device_is_usb_connected(dev_p))
2092                 return CY_AS_ERROR_USB_CONNECTED;
2093
2094         if (cy_as_device_is_in_callback(dev_p))
2095                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2096
2097         /*
2098         * this performs the mapping based on informatation that was
2099         * previously stored on the device about the various endpoints
2100         * and how they are configured. the output of this mapping is
2101         * setting the the 14 register values contained in usb_lepcfg
2102         * and usb_pepcfg
2103         */
2104         ret = cy_as_usb_map_logical2_physical(dev_p);
2105         if (ret != CY_AS_ERROR_SUCCESS)
2106                 return ret;
2107
2108         /*
2109         * now, package the information about the various logical and
2110         * physical endpoint configuration registers and send it
2111         * across to the west bridge device.
2112         */
2113         req_p = cy_as_ll_create_request(dev_p,
2114                 CY_RQT_SET_USB_CONFIG_REGISTERS, CY_RQT_USB_RQT_CONTEXT, 8);
2115         if (req_p == 0)
2116                 return CY_AS_ERROR_OUT_OF_MEMORY;
2117
2118         cy_as_hal_print_message("USB configuration: %d\n",
2119                 dev_p->usb_phy_config);
2120         cy_as_hal_print_message("EP1OUT: 0x%02x EP1IN: 0x%02x\n",
2121                 dev_p->usb_ep1cfg[0], dev_p->usb_ep1cfg[1]);
2122         cy_as_hal_print_message("PEP registers: 0x%02x 0x%02x 0x%02x 0x%02x\n",
2123                 dev_p->usb_pepcfg[0], dev_p->usb_pepcfg[1],
2124                 dev_p->usb_pepcfg[2], dev_p->usb_pepcfg[3]);
2125
2126         cy_as_hal_print_message("LEP registers: 0x%02x 0x%02x 0x%02x "
2127                 "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
2128                 dev_p->usb_lepcfg[0], dev_p->usb_lepcfg[1],
2129                 dev_p->usb_lepcfg[2], dev_p->usb_lepcfg[3],
2130                 dev_p->usb_lepcfg[4], dev_p->usb_lepcfg[5],
2131                 dev_p->usb_lepcfg[6], dev_p->usb_lepcfg[7],
2132                 dev_p->usb_lepcfg[8], dev_p->usb_lepcfg[9]);
2133
2134         /* Write the EP1OUTCFG and EP1INCFG data in the first word. */
2135         data = (uint16_t)((dev_p->usb_ep1cfg[0] << 8) |
2136                 dev_p->usb_ep1cfg[1]);
2137         cy_as_ll_request_response__set_word(req_p, 0, data);
2138
2139         /* Write the PEP CFG data in the next 2 words */
2140         for (i = 0; i < 4; i += 2) {
2141                 data = (uint16_t)((dev_p->usb_pepcfg[i] << 8) |
2142                         dev_p->usb_pepcfg[i + 1]);
2143                 cy_as_ll_request_response__set_word(req_p,
2144                         1 + i / 2, data);
2145         }
2146
2147         /* Write the LEP CFG data in the next 5 words */
2148         for (i = 0; i < 10; i += 2) {
2149                 data = (uint16_t)((dev_p->usb_lepcfg[i] << 8) |
2150                         dev_p->usb_lepcfg[i + 1]);
2151                 cy_as_ll_request_response__set_word(req_p,
2152                         3 + i / 2, data);
2153         }
2154
2155         /* A single status word response type */
2156         reply_p = cy_as_ll_create_response(dev_p, 1);
2157         if (reply_p == 0) {
2158                 cy_as_ll_destroy_request(dev_p, req_p);
2159                 return CY_AS_ERROR_OUT_OF_MEMORY;
2160         }
2161
2162         if (cb == 0) {
2163                 ret = cy_as_ll_send_request_wait_reply(dev_p,
2164                         req_p, reply_p);
2165                 if (ret != CY_AS_ERROR_SUCCESS)
2166                         goto destroy;
2167
2168                 ret = my_handle_response_no_data(dev_p,
2169                         req_p, reply_p);
2170
2171                 if (ret == CY_AS_ERROR_SUCCESS)
2172                         ret = cy_as_usb_setup_dma(dev_p);
2173
2174                 return ret;
2175         } else {
2176                 ret = cy_as_misc_send_request(dev_p, cb, client,
2177                         CY_FUNCT_CB_USB_COMMITCONFIG, 0, dev_p->func_cbs_usb,
2178                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
2179                         cy_as_usb_func_callback);
2180
2181                 if (ret != CY_AS_ERROR_SUCCESS)
2182                         goto destroy;
2183
2184                 return ret;
2185         }
2186
2187 destroy:
2188         cy_as_ll_destroy_request(dev_p, req_p);
2189         cy_as_ll_destroy_response(dev_p, reply_p);
2190
2191         return ret;
2192 }
2193 EXPORT_SYMBOL(cy_as_usb_commit_config);
2194
2195 static void
2196 sync_request_callback(cy_as_device *dev_p,
2197         cy_as_end_point_number_t ep, void *buf_p,
2198         uint32_t size, cy_as_return_status_t err)
2199 {
2200         (void)ep;
2201         (void)buf_p;
2202
2203         dev_p->usb_error = err;
2204         dev_p->usb_actual_cnt = size;
2205 }
2206
2207 static void
2208 async_read_request_callback(cy_as_device *dev_p,
2209         cy_as_end_point_number_t ep, void *buf_p,
2210         uint32_t size, cy_as_return_status_t err)
2211 {
2212         cy_as_device_handle h;
2213
2214         cy_as_log_debug_message(6,
2215                 "async_read_request_callback called");
2216
2217         h = (cy_as_device_handle)dev_p;
2218
2219         if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
2220                 dev_p->usb_pending_buffer = buf_p;
2221                 dev_p->usb_pending_size = size;
2222                 dev_p->usb_error = err;
2223                 cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
2224         } else {
2225                 cy_as_usb_io_callback cb;
2226
2227                 cb = dev_p->usb_cb[ep];
2228                 dev_p->usb_cb[ep] = 0;
2229                 cy_as_device_clear_usb_async_pending(dev_p, ep);
2230                 if (cb)
2231                         cb(h, ep, size, buf_p, err);
2232         }
2233 }
2234
2235 static void
2236 async_write_request_callback(cy_as_device *dev_p,
2237         cy_as_end_point_number_t ep, void *buf_p,
2238         uint32_t size, cy_as_return_status_t err)
2239 {
2240         cy_as_device_handle h;
2241
2242         cy_as_log_debug_message(6,
2243                 "async_write_request_callback called");
2244
2245         h = (cy_as_device_handle)dev_p;
2246
2247         if (ep == 0 && cy_as_device_is_ack_delayed(dev_p)) {
2248                 dev_p->usb_pending_buffer = buf_p;
2249                 dev_p->usb_pending_size = size;
2250                 dev_p->usb_error = err;
2251
2252                 /* The west bridge protocol generates ZLPs as required. */
2253                 cy_as_usb_ack_setup_packet(h, usb_ack_callback, 0);
2254         } else {
2255                 cy_as_usb_io_callback cb;
2256
2257                 cb = dev_p->usb_cb[ep];
2258                 dev_p->usb_cb[ep] = 0;
2259
2260                 cy_as_device_clear_usb_async_pending(dev_p, ep);
2261                 if (cb)
2262                         cb(h, ep, size, buf_p, err);
2263         }
2264 }
2265
2266 static void
2267 my_turbo_rqt_callback(cy_as_device *dev_p,
2268                                         uint8_t context,
2269                                         cy_as_ll_request_response *rqt,
2270                                         cy_as_ll_request_response *resp,
2271                                         cy_as_return_status_t stat)
2272 {
2273         uint8_t code;
2274
2275         (void)context;
2276         (void)stat;
2277
2278         /* The Handlers are responsible for Deleting the rqt and resp when
2279          * they are finished
2280          */
2281         code = cy_as_ll_request_response__get_code(rqt);
2282         switch (code) {
2283         case CY_RQT_TURBO_SWITCH_ENDPOINT:
2284                 cy_as_hal_assert(stat == CY_AS_ERROR_SUCCESS);
2285                 cy_as_ll_destroy_request(dev_p, rqt);
2286                 cy_as_ll_destroy_response(dev_p, resp);
2287                 break;
2288         default:
2289                 cy_as_hal_assert(cy_false);
2290                 break;
2291         }
2292 }
2293
2294 /* Send a mailbox request to prepare the endpoint for switching */
2295 static cy_as_return_status_t
2296 my_send_turbo_switch(cy_as_device *dev_p, uint32_t size, cy_bool pktread)
2297 {
2298         cy_as_return_status_t ret;
2299         cy_as_ll_request_response *req_p , *reply_p;
2300
2301         /* Create the request to send to the West Bridge device */
2302         req_p = cy_as_ll_create_request(dev_p,
2303                 CY_RQT_TURBO_SWITCH_ENDPOINT, CY_RQT_TUR_RQT_CONTEXT, 3);
2304         if (req_p == 0)
2305                 return CY_AS_ERROR_OUT_OF_MEMORY;
2306
2307         /* Reserve space for the reply, the reply data will
2308          * not exceed one word */
2309         reply_p = cy_as_ll_create_response(dev_p, 1);
2310         if (reply_p == 0) {
2311                 cy_as_ll_destroy_request(dev_p, req_p);
2312                 return CY_AS_ERROR_OUT_OF_MEMORY;
2313         }
2314
2315         cy_as_ll_request_response__set_word(req_p, 0,
2316                 (uint16_t)pktread);
2317         cy_as_ll_request_response__set_word(req_p, 1,
2318                 (uint16_t)((size >> 16) & 0xFFFF));
2319         cy_as_ll_request_response__set_word(req_p, 2,
2320                 (uint16_t)(size & 0xFFFF));
2321
2322         ret = cy_as_ll_send_request(dev_p, req_p,
2323                 reply_p, cy_false, my_turbo_rqt_callback);
2324         if (ret != CY_AS_ERROR_SUCCESS) {
2325                 cy_as_ll_destroy_request(dev_p, req_p);
2326                 cy_as_ll_destroy_request(dev_p, reply_p);
2327                 return ret;
2328         }
2329
2330         return CY_AS_ERROR_SUCCESS;
2331 }
2332
2333 cy_as_return_status_t
2334 cy_as_usb_read_data(cy_as_device_handle handle,
2335         cy_as_end_point_number_t ep, cy_bool pktread,
2336         uint32_t dsize, uint32_t *dataread, void *data)
2337 {
2338         cy_as_return_status_t ret;
2339         cy_as_device *dev_p;
2340
2341         cy_as_log_debug_message(6, "cy_as_usb_read_data called");
2342
2343         dev_p = (cy_as_device *)handle;
2344         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2345                 return CY_AS_ERROR_INVALID_HANDLE;
2346
2347         ret = is_usb_active(dev_p);
2348         if (ret != CY_AS_ERROR_SUCCESS)
2349                 return ret;
2350
2351         if (cy_as_device_is_in_callback(dev_p))
2352                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2353
2354         if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
2355                 return CY_AS_ERROR_INVALID_ENDPOINT;
2356
2357         /* EP2 is available for reading when MTP is active */
2358         if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
2359                 return CY_AS_ERROR_INVALID_ENDPOINT;
2360
2361         /* If the endpoint is disabled, we cannot
2362          * write data to the endpoint */
2363         if (!dev_p->usb_config[ep].enabled)
2364                 return CY_AS_ERROR_ENDPOINT_DISABLED;
2365
2366         if (dev_p->usb_config[ep].dir != cy_as_usb_out)
2367                 return CY_AS_ERROR_USB_BAD_DIRECTION;
2368
2369         ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2370                 pktread, cy_true, sync_request_callback);
2371         if (ret != CY_AS_ERROR_SUCCESS)
2372                 return ret;
2373
2374         if (ep == CY_AS_MTP_READ_ENDPOINT)  {
2375                 ret = my_send_turbo_switch(dev_p, dsize, pktread);
2376                 if (ret != CY_AS_ERROR_SUCCESS) {
2377                         cy_as_dma_cancel(dev_p, ep, ret);
2378                         return ret;
2379                 }
2380
2381                 ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
2382                 if (ret != CY_AS_ERROR_SUCCESS)
2383                         return ret;
2384         } else {
2385                 ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
2386                 if (ret != CY_AS_ERROR_SUCCESS)
2387                         return ret;
2388         }
2389
2390         ret = dev_p->usb_error;
2391         *dataread = dev_p->usb_actual_cnt;
2392
2393         return ret;
2394 }
2395 EXPORT_SYMBOL(cy_as_usb_read_data);
2396
2397 cy_as_return_status_t
2398 cy_as_usb_read_data_async(cy_as_device_handle handle,
2399         cy_as_end_point_number_t ep, cy_bool pktread,
2400         uint32_t dsize, void *data, cy_as_usb_io_callback cb)
2401 {
2402         cy_as_return_status_t ret;
2403         uint32_t mask;
2404         cy_as_device *dev_p;
2405
2406         cy_as_log_debug_message(6, "cy_as_usb_read_data_async called");
2407
2408         dev_p = (cy_as_device *)handle;
2409         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2410                 return CY_AS_ERROR_INVALID_HANDLE;
2411
2412         ret = is_usb_active(dev_p);
2413         if (ret != CY_AS_ERROR_SUCCESS)
2414                 return ret;
2415
2416         if (ep >= 16 || ep == 4 || ep == 6 || ep == 8)
2417                 return CY_AS_ERROR_INVALID_ENDPOINT;
2418
2419         /* EP2 is available for reading when MTP is active */
2420         if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_READ_ENDPOINT)
2421                 return CY_AS_ERROR_INVALID_ENDPOINT;
2422
2423         /* If the endpoint is disabled, we cannot
2424          * write data to the endpoint */
2425         if (!dev_p->usb_config[ep].enabled)
2426                 return CY_AS_ERROR_ENDPOINT_DISABLED;
2427
2428         if (dev_p->usb_config[ep].dir != cy_as_usb_out &&
2429                 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2430                 return CY_AS_ERROR_USB_BAD_DIRECTION;
2431
2432         /*
2433         * since async operations can be triggered by interrupt
2434         * code, we must insure that we do not get multiple async
2435         * operations going at one time and protect this test and
2436         * set operation from interrupts.
2437         */
2438         mask = cy_as_hal_disable_interrupts();
2439         if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
2440                 cy_as_hal_enable_interrupts(mask);
2441                 return CY_AS_ERROR_ASYNC_PENDING;
2442         }
2443         cy_as_device_set_usb_async_pending(dev_p, ep);
2444
2445         /*
2446         * if this is for EP0, we set this bit to delay the
2447         * ACK response until after this read has completed.
2448         */
2449         if (ep == 0)
2450                 cy_as_device_set_ack_delayed(dev_p);
2451
2452         cy_as_hal_enable_interrupts(mask);
2453
2454         cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
2455         dev_p->usb_cb[ep] = cb;
2456
2457         ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2458                 pktread, cy_true, async_read_request_callback);
2459         if (ret != CY_AS_ERROR_SUCCESS)
2460                 return ret;
2461
2462         if (ep == CY_AS_MTP_READ_ENDPOINT)  {
2463                 ret = my_send_turbo_switch(dev_p, dsize, pktread);
2464                 if (ret != CY_AS_ERROR_SUCCESS) {
2465                         cy_as_dma_cancel(dev_p, ep, ret);
2466                         return ret;
2467                 }
2468         } else {
2469                 /* Kick start the queue if it is not running */
2470                 cy_as_dma_kick_start(dev_p, ep);
2471         }
2472         return ret;
2473 }
2474 EXPORT_SYMBOL(cy_as_usb_read_data_async);
2475
2476 cy_as_return_status_t
2477 cy_as_usb_write_data(cy_as_device_handle handle,
2478         cy_as_end_point_number_t ep, uint32_t dsize, void *data)
2479 {
2480         cy_as_return_status_t ret;
2481         cy_as_device *dev_p;
2482
2483         cy_as_log_debug_message(6, "cy_as_usb_write_data called");
2484
2485         dev_p = (cy_as_device *)handle;
2486         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2487                 return CY_AS_ERROR_INVALID_HANDLE;
2488
2489         ret = is_usb_active(dev_p);
2490         if (ret != CY_AS_ERROR_SUCCESS)
2491                 return ret;
2492
2493         if (cy_as_device_is_in_callback(dev_p))
2494                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2495
2496         if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
2497                 return CY_AS_ERROR_INVALID_ENDPOINT;
2498
2499         /* EP6 is available for writing when MTP is active */
2500         if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
2501                 return CY_AS_ERROR_INVALID_ENDPOINT;
2502
2503         /* If the endpoint is disabled, we cannot
2504          * write data to the endpoint */
2505         if (!dev_p->usb_config[ep].enabled)
2506                 return CY_AS_ERROR_ENDPOINT_DISABLED;
2507
2508         if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
2509                 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2510                 return CY_AS_ERROR_USB_BAD_DIRECTION;
2511
2512         /* Write on Turbo endpoint */
2513         if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
2514                 cy_as_ll_request_response *req_p, *reply_p;
2515
2516                 req_p = cy_as_ll_create_request(dev_p,
2517                         CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
2518                         CY_RQT_TUR_RQT_CONTEXT, 3);
2519                 if (req_p == 0)
2520                         return CY_AS_ERROR_OUT_OF_MEMORY;
2521
2522                 cy_as_ll_request_response__set_word(req_p,
2523                         0, 0x0006); /* EP number to use. */
2524                 cy_as_ll_request_response__set_word(req_p,
2525                         1, (uint16_t)((dsize >> 16) & 0xFFFF));
2526                 cy_as_ll_request_response__set_word(req_p,
2527                         2, (uint16_t)(dsize & 0xFFFF));
2528
2529                 /* Reserve space for the reply, the reply data
2530                  * will not exceed one word */
2531                 reply_p = cy_as_ll_create_response(dev_p, 1);
2532                 if (reply_p == 0) {
2533                         cy_as_ll_destroy_request(dev_p, req_p);
2534                         return CY_AS_ERROR_OUT_OF_MEMORY;
2535                 }
2536
2537                 if (dsize) {
2538                         ret = cy_as_dma_queue_request(dev_p,
2539                                 ep, data, dsize, cy_false,
2540                                 cy_false, sync_request_callback);
2541                         if (ret != CY_AS_ERROR_SUCCESS)
2542                                 return ret;
2543                 }
2544
2545                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
2546                 if (ret == CY_AS_ERROR_SUCCESS) {
2547                         if (cy_as_ll_request_response__get_code(reply_p) !=
2548                         CY_RESP_SUCCESS_FAILURE)
2549                                 ret = CY_AS_ERROR_INVALID_RESPONSE;
2550                         else
2551                                 ret = cy_as_ll_request_response__get_word
2552                                                 (reply_p, 0);
2553                 }
2554
2555                 cy_as_ll_destroy_request(dev_p, req_p);
2556                 cy_as_ll_destroy_response(dev_p, reply_p);
2557
2558                 if (ret != CY_AS_ERROR_SUCCESS) {
2559                         if (dsize)
2560                                 cy_as_dma_cancel(dev_p, ep, ret);
2561                         return ret;
2562                 }
2563
2564                 /* If this is a zero-byte write, firmware will
2565                  * handle it. there is no need to do any work here.
2566                  */
2567                 if (!dsize)
2568                         return CY_AS_ERROR_SUCCESS;
2569         } else {
2570                 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2571                         cy_false, cy_false, sync_request_callback);
2572                 if (ret != CY_AS_ERROR_SUCCESS)
2573                         return ret;
2574         }
2575
2576         if (ep != CY_AS_MTP_WRITE_ENDPOINT)
2577                 ret = cy_as_dma_drain_queue(dev_p, ep, cy_true);
2578         else
2579                 ret = cy_as_dma_drain_queue(dev_p, ep, cy_false);
2580
2581         if (ret != CY_AS_ERROR_SUCCESS)
2582                 return ret;
2583
2584         ret = dev_p->usb_error;
2585         return ret;
2586 }
2587 EXPORT_SYMBOL(cy_as_usb_write_data);
2588
2589 static void
2590 mtp_write_callback(
2591                 cy_as_device *dev_p,
2592                 uint8_t context,
2593                 cy_as_ll_request_response *rqt,
2594                 cy_as_ll_request_response *resp,
2595                 cy_as_return_status_t ret)
2596 {
2597         cy_as_usb_io_callback cb;
2598         cy_as_device_handle h = (cy_as_device_handle)dev_p;
2599
2600         cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT);
2601
2602         if (ret == CY_AS_ERROR_SUCCESS) {
2603                 if (cy_as_ll_request_response__get_code(resp) !=
2604                 CY_RESP_SUCCESS_FAILURE)
2605                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2606                 else
2607                         ret = cy_as_ll_request_response__get_word(resp, 0);
2608         }
2609
2610         /* If this was a zero byte transfer request, we can
2611          * call the callback from here. */
2612         if ((cy_as_ll_request_response__get_word(rqt, 1) == 0) &&
2613                         (cy_as_ll_request_response__get_word(rqt, 2) == 0)) {
2614                 cb = dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT];
2615                 dev_p->usb_cb[CY_AS_MTP_WRITE_ENDPOINT] = 0;
2616                 cy_as_device_clear_usb_async_pending(dev_p,
2617                         CY_AS_MTP_WRITE_ENDPOINT);
2618                 if (cb)
2619                         cb(h, CY_AS_MTP_WRITE_ENDPOINT, 0, 0, ret);
2620
2621                 goto destroy;
2622         }
2623
2624         if (ret != CY_AS_ERROR_SUCCESS) {
2625                 /* Firmware failed the request. Cancel the DMA transfer. */
2626                 cy_as_dma_cancel(dev_p, 0x06, CY_AS_ERROR_CANCELED);
2627                 dev_p->usb_cb[0x06] = 0;
2628                 cy_as_device_clear_usb_async_pending(dev_p, 0x06);
2629         }
2630
2631 destroy:
2632         cy_as_ll_destroy_response(dev_p, resp);
2633         cy_as_ll_destroy_request(dev_p, rqt);
2634 }
2635
2636 cy_as_return_status_t
2637 cy_as_usb_write_data_async(cy_as_device_handle handle,
2638         cy_as_end_point_number_t ep, uint32_t dsize, void *data,
2639         cy_bool spacket, cy_as_usb_io_callback cb)
2640 {
2641         uint32_t mask;
2642         cy_as_return_status_t ret;
2643         cy_as_device *dev_p;
2644
2645         cy_as_log_debug_message(6, "cy_as_usb_write_data_async called");
2646
2647         dev_p = (cy_as_device *)handle;
2648         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2649                 return CY_AS_ERROR_INVALID_HANDLE;
2650
2651         ret = is_usb_active(dev_p);
2652         if (ret != CY_AS_ERROR_SUCCESS)
2653                 return ret;
2654
2655         if (ep >= 16 || ep == 2 || ep == 4 || ep == 8)
2656                 return CY_AS_ERROR_INVALID_ENDPOINT;
2657
2658          /* EP6 is available for writing when MTP is active */
2659         if (dev_p->mtp_count == 0 && ep == CY_AS_MTP_WRITE_ENDPOINT)
2660                 return CY_AS_ERROR_INVALID_ENDPOINT;
2661
2662         /* If the endpoint is disabled, we cannot
2663          * write data to the endpoint */
2664         if (!dev_p->usb_config[ep].enabled)
2665                 return CY_AS_ERROR_ENDPOINT_DISABLED;
2666
2667         if (dev_p->usb_config[ep].dir != cy_as_usb_in &&
2668                 dev_p->usb_config[ep].dir != cy_as_usb_in_out)
2669                 return CY_AS_ERROR_USB_BAD_DIRECTION;
2670
2671         /*
2672         * since async operations can be triggered by interrupt
2673         * code, we must insure that we do not get multiple
2674         * async operations going at one time and
2675         * protect this test and set operation from interrupts.
2676         */
2677         mask = cy_as_hal_disable_interrupts();
2678         if (cy_as_device_is_usb_async_pending(dev_p, ep)) {
2679                 cy_as_hal_enable_interrupts(mask);
2680                 return CY_AS_ERROR_ASYNC_PENDING;
2681         }
2682
2683         cy_as_device_set_usb_async_pending(dev_p, ep);
2684
2685         if (ep == 0)
2686                 cy_as_device_set_ack_delayed(dev_p);
2687
2688         cy_as_hal_enable_interrupts(mask);
2689
2690         cy_as_hal_assert(dev_p->usb_cb[ep] == 0);
2691         dev_p->usb_cb[ep] = cb;
2692         dev_p->usb_spacket[ep] = spacket;
2693
2694         /* Write on Turbo endpoint */
2695         if (ep == CY_AS_MTP_WRITE_ENDPOINT) {
2696                 cy_as_ll_request_response *req_p, *reply_p;
2697
2698                 req_p = cy_as_ll_create_request(dev_p,
2699                         CY_RQT_TURBO_SEND_RESP_DATA_TO_HOST,
2700                         CY_RQT_TUR_RQT_CONTEXT, 3);
2701
2702                 if (req_p == 0)
2703                         return CY_AS_ERROR_OUT_OF_MEMORY;
2704
2705                 cy_as_ll_request_response__set_word(req_p, 0,
2706                         0x0006); /* EP number to use. */
2707                 cy_as_ll_request_response__set_word(req_p, 1,
2708                         (uint16_t)((dsize >> 16) & 0xFFFF));
2709                 cy_as_ll_request_response__set_word(req_p, 2,
2710                         (uint16_t)(dsize & 0xFFFF));
2711
2712                 /* Reserve space for the reply, the reply data
2713                  * will not exceed one word */
2714                 reply_p = cy_as_ll_create_response(dev_p, 1);
2715                 if (reply_p == 0) {
2716                         cy_as_ll_destroy_request(dev_p, req_p);
2717                         return CY_AS_ERROR_OUT_OF_MEMORY;
2718                 }
2719
2720                 if (dsize) {
2721                         ret = cy_as_dma_queue_request(dev_p, ep, data,
2722                                 dsize, cy_false, cy_false,
2723                                 async_write_request_callback);
2724                         if (ret != CY_AS_ERROR_SUCCESS)
2725                                 return ret;
2726                 }
2727
2728                 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2729                         cy_false, mtp_write_callback);
2730                 if (ret != CY_AS_ERROR_SUCCESS) {
2731                         if (dsize)
2732                                 cy_as_dma_cancel(dev_p, ep, ret);
2733                         return ret;
2734                 }
2735
2736                 /* Firmware will handle a zero byte transfer
2737                  * without any DMA transfers. */
2738                 if (!dsize)
2739                         return CY_AS_ERROR_SUCCESS;
2740         } else {
2741                 ret = cy_as_dma_queue_request(dev_p, ep, data, dsize,
2742                         cy_false, cy_false, async_write_request_callback);
2743                 if (ret != CY_AS_ERROR_SUCCESS)
2744                         return ret;
2745         }
2746
2747         /* Kick start the queue if it is not running */
2748         if (ep != CY_AS_MTP_WRITE_ENDPOINT)
2749                 cy_as_dma_kick_start(dev_p, ep);
2750
2751         return CY_AS_ERROR_SUCCESS;
2752 }
2753 EXPORT_SYMBOL(cy_as_usb_write_data_async);
2754
2755 static void
2756 my_usb_cancel_async_callback(
2757                                    cy_as_device *dev_p,
2758                                    uint8_t context,
2759                                    cy_as_ll_request_response *rqt,
2760                                    cy_as_ll_request_response *resp,
2761                                    cy_as_return_status_t ret)
2762 {
2763         uint8_t ep;
2764         (void)context;
2765
2766         ep = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
2767         if (ret == CY_AS_ERROR_SUCCESS) {
2768                 if (cy_as_ll_request_response__get_code(resp) !=
2769                         CY_RESP_SUCCESS_FAILURE)
2770                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2771                 else
2772                         ret = cy_as_ll_request_response__get_word(resp, 0);
2773         }
2774
2775         cy_as_ll_destroy_request(dev_p, rqt);
2776         cy_as_ll_destroy_response(dev_p, resp);
2777
2778         if (ret == CY_AS_ERROR_SUCCESS) {
2779                 cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
2780                 dev_p->usb_cb[ep] = 0;
2781                 cy_as_device_clear_usb_async_pending(dev_p, ep);
2782         }
2783 }
2784
2785 cy_as_return_status_t
2786 cy_as_usb_cancel_async(cy_as_device_handle handle,
2787         cy_as_end_point_number_t ep)
2788 {
2789         cy_as_return_status_t ret;
2790         cy_as_ll_request_response *req_p, *reply_p;
2791
2792         cy_as_device *dev_p = (cy_as_device *)handle;
2793         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2794                 return CY_AS_ERROR_INVALID_HANDLE;
2795
2796         ep &= 0x7F;              /* Remove the direction bit. */
2797         if (!cy_as_device_is_usb_async_pending(dev_p, ep))
2798                 return CY_AS_ERROR_ASYNC_NOT_PENDING;
2799
2800         ret = is_usb_active(dev_p);
2801         if (ret != CY_AS_ERROR_SUCCESS)
2802                 return ret;
2803
2804         if (cy_as_device_is_in_suspend_mode(dev_p))
2805                 return CY_AS_ERROR_IN_SUSPEND;
2806
2807         if ((ep == CY_AS_MTP_WRITE_ENDPOINT) ||
2808                 (ep == CY_AS_MTP_READ_ENDPOINT)) {
2809                 /* Need firmware support for the cancel operation. */
2810                 req_p = cy_as_ll_create_request(dev_p,
2811                         CY_RQT_CANCEL_ASYNC_TRANSFER,
2812                         CY_RQT_TUR_RQT_CONTEXT, 1);
2813
2814                 if (req_p == 0)
2815                         return CY_AS_ERROR_OUT_OF_MEMORY;
2816
2817                 reply_p = cy_as_ll_create_response(dev_p, 1);
2818                 if (reply_p == 0) {
2819                         cy_as_ll_destroy_request(dev_p, req_p);
2820                         return CY_AS_ERROR_OUT_OF_MEMORY;
2821                 }
2822
2823                 cy_as_ll_request_response__set_word(req_p, 0,
2824                         (uint16_t)ep);
2825
2826                 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2827                         cy_false, my_usb_cancel_async_callback);
2828
2829                 if (ret != CY_AS_ERROR_SUCCESS) {
2830                         cy_as_ll_destroy_request(dev_p, req_p);
2831                         cy_as_ll_destroy_response(dev_p, reply_p);
2832                         return ret;
2833                 }
2834         } else {
2835                 ret = cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_CANCELED);
2836                 if (ret != CY_AS_ERROR_SUCCESS)
2837                         return ret;
2838
2839                 dev_p->usb_cb[ep] = 0;
2840                 cy_as_device_clear_usb_async_pending(dev_p, ep);
2841         }
2842
2843         return CY_AS_ERROR_SUCCESS;
2844 }
2845 EXPORT_SYMBOL(cy_as_usb_cancel_async);
2846
2847 static void
2848 cy_as_usb_ack_callback(
2849                                    cy_as_device *dev_p,
2850                                    uint8_t context,
2851                                    cy_as_ll_request_response *rqt,
2852                                    cy_as_ll_request_response *resp,
2853                                    cy_as_return_status_t ret)
2854 {
2855         cy_as_func_c_b_node *node  = (cy_as_func_c_b_node *)
2856                 dev_p->func_cbs_usb->head_p;
2857
2858         (void)context;
2859
2860         if (ret == CY_AS_ERROR_SUCCESS) {
2861                 if (cy_as_ll_request_response__get_code(resp) !=
2862                 CY_RESP_SUCCESS_FAILURE)
2863                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2864                 else
2865                         ret = cy_as_ll_request_response__get_word(resp, 0);
2866         }
2867
2868         node->cb_p((cy_as_device_handle)dev_p, ret,
2869                 node->client_data, node->data_type, node->data);
2870         cy_as_remove_c_b_node(dev_p->func_cbs_usb);
2871
2872         cy_as_ll_destroy_request(dev_p, rqt);
2873         cy_as_ll_destroy_response(dev_p, resp);
2874         cy_as_device_clear_ack_delayed(dev_p);
2875 }
2876
2877 static cy_as_return_status_t
2878 cy_as_usb_ack_setup_packet(cy_as_device_handle handle,
2879                                           cy_as_function_callback         cb,
2880                                           uint32_t client)
2881 {
2882         cy_as_return_status_t ret;
2883         cy_as_ll_request_response *req_p;
2884         cy_as_ll_request_response *reply_p;
2885         cy_as_func_c_b_node *cbnode;
2886
2887         cy_as_device *dev_p = (cy_as_device *)handle;
2888         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2889                 return CY_AS_ERROR_INVALID_HANDLE;
2890
2891         ret = is_usb_active(dev_p);
2892         if (ret != CY_AS_ERROR_SUCCESS)
2893                 return ret;
2894
2895         if (cy_as_device_is_in_callback(dev_p) && cb == 0)
2896                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2897
2898         cy_as_hal_assert(cb != 0);
2899
2900         cbnode = cy_as_create_func_c_b_node(cb, client);
2901         if (cbnode == 0)
2902                 return CY_AS_ERROR_OUT_OF_MEMORY;
2903
2904         req_p = cy_as_ll_create_request(dev_p, 0,
2905                 CY_RQT_USB_RQT_CONTEXT, 2);
2906         if (req_p == 0)
2907                 return CY_AS_ERROR_OUT_OF_MEMORY;
2908
2909         reply_p = cy_as_ll_create_response(dev_p, 1);
2910         if (reply_p == 0) {
2911                 cy_as_ll_destroy_request(dev_p, req_p);
2912                 return CY_AS_ERROR_OUT_OF_MEMORY;
2913         }
2914
2915         cy_as_ll_init_request(req_p, CY_RQT_ACK_SETUP_PACKET,
2916                 CY_RQT_USB_RQT_CONTEXT, 1);
2917         cy_as_ll_init_response(reply_p, 1);
2918
2919         req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
2920
2921         cy_as_insert_c_b_node(dev_p->func_cbs_usb, cbnode);
2922
2923         ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
2924                 cy_false, cy_as_usb_ack_callback);
2925
2926         return ret;
2927 }
2928
2929 /*
2930  * Flush all data in logical EP that is being NAK-ed or
2931  * Stall-ed, so that this does not continue to block data
2932  * on other LEPs that use the same physical EP.
2933  */
2934 static void
2935 cy_as_usb_flush_logical_e_p(
2936                 cy_as_device *dev_p,
2937                 uint16_t        ep)
2938 {
2939         uint16_t addr, val, count;
2940
2941         addr = CY_AS_MEM_P0_EP2_DMA_REG + ep - 2;
2942         val  = cy_as_hal_read_register(dev_p->tag, addr);
2943
2944         while (val) {
2945                 count = ((val & 0xFFF) + 1) / 2;
2946                 while (count--)
2947                         val = cy_as_hal_read_register(dev_p->tag, ep);
2948
2949                 cy_as_hal_write_register(dev_p->tag, addr, 0);
2950                 val = cy_as_hal_read_register(dev_p->tag, addr);
2951         }
2952 }
2953
2954 static cy_as_return_status_t
2955 cy_as_usb_nak_stall_request(cy_as_device_handle handle,
2956                                            cy_as_end_point_number_t ep,
2957                                            uint16_t request,
2958                                            cy_bool state,
2959                                            cy_as_usb_function_callback cb,
2960                                            cy_as_function_callback fcb,
2961                                            uint32_t client)
2962 {
2963         cy_as_return_status_t ret;
2964         cy_as_ll_request_response *req_p , *reply_p;
2965         uint16_t data;
2966
2967         cy_as_device *dev_p = (cy_as_device *)handle;
2968         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2969                 return CY_AS_ERROR_INVALID_HANDLE;
2970
2971         if (cb)
2972                 cy_as_hal_assert(fcb == 0);
2973         if (fcb)
2974                 cy_as_hal_assert(cb == 0);
2975
2976         ret = is_usb_active(dev_p);
2977         if (ret != CY_AS_ERROR_SUCCESS)
2978                 return ret;
2979
2980         if (cy_as_device_is_in_callback(dev_p) && cb == 0 && fcb == 0)
2981                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
2982
2983         req_p = cy_as_ll_create_request(dev_p,
2984                 request, CY_RQT_USB_RQT_CONTEXT, 2);
2985         if (req_p == 0)
2986                 return CY_AS_ERROR_OUT_OF_MEMORY;
2987
2988         /* A single status word response type */
2989         reply_p = cy_as_ll_create_response(dev_p, 1);
2990         if (reply_p == 0) {
2991                 cy_as_ll_destroy_request(dev_p, req_p);
2992                 return CY_AS_ERROR_OUT_OF_MEMORY;
2993         }
2994
2995         /* Set the endpoint */
2996         data = (uint8_t)ep;
2997         cy_as_ll_request_response__set_word(req_p, 0, data);
2998
2999         /* Set stall state to stalled */
3000         cy_as_ll_request_response__set_word(req_p, 1, (uint8_t)state);
3001
3002         if (cb || fcb) {
3003                 void *cbnode;
3004                 cy_as_c_b_queue *queue;
3005                 if (cb) {
3006                         cbnode = cy_as_create_usb_func_c_b_node(cb, client);
3007                         queue = dev_p->usb_func_cbs;
3008                 } else {
3009                         cbnode = cy_as_create_func_c_b_node(fcb, client);
3010                         queue = dev_p->func_cbs_usb;
3011                         req_p->flags |= CY_AS_REQUEST_RESPONSE_EX;
3012                 }
3013
3014                 if (cbnode == 0) {
3015                         ret = CY_AS_ERROR_OUT_OF_MEMORY;
3016                         goto destroy;
3017                 } else
3018                         cy_as_insert_c_b_node(queue, cbnode);
3019
3020
3021                 if (cy_as_device_is_setup_packet(dev_p)) {
3022                         /* No Ack is needed on a stall request on EP0 */
3023                         if ((state == cy_true) && (ep == 0)) {
3024                                 cy_as_device_set_ep0_stalled(dev_p);
3025                         } else {
3026                                 cy_as_device_set_ack_delayed(dev_p);
3027                                 req_p->flags |=
3028                                         CY_AS_REQUEST_RESPONSE_DELAY_ACK;
3029                         }
3030                 }
3031
3032                 ret = cy_as_ll_send_request(dev_p, req_p,
3033                         reply_p, cy_false, cy_as_usb_func_callback);
3034                 if (ret != CY_AS_ERROR_SUCCESS) {
3035                         if (req_p->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
3036                                 cy_as_device_rem_ack_delayed(dev_p);
3037                         cy_as_remove_c_b_tail_node(queue);
3038
3039                         goto destroy;
3040                 }
3041         } else {
3042                 ret = cy_as_ll_send_request_wait_reply(dev_p,
3043                         req_p, reply_p);
3044                 if (ret != CY_AS_ERROR_SUCCESS)
3045                         goto destroy;
3046
3047                 if (cy_as_ll_request_response__get_code(reply_p) !=
3048                 CY_RESP_SUCCESS_FAILURE) {
3049                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3050                         goto destroy;
3051                 }
3052
3053                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3054
3055                 if ((ret == CY_AS_ERROR_SUCCESS) &&
3056                         (request == CY_RQT_STALL_ENDPOINT)) {
3057                         if ((ep > 1) && (state != 0) &&
3058                                 (dev_p->usb_config[ep].dir == cy_as_usb_out))
3059                                 cy_as_usb_flush_logical_e_p(dev_p, ep);
3060                 }
3061
3062 destroy:
3063                 cy_as_ll_destroy_request(dev_p, req_p);
3064                 cy_as_ll_destroy_response(dev_p, reply_p);
3065         }
3066
3067         return ret;
3068 }
3069
3070 static cy_as_return_status_t
3071 my_handle_response_get_stall(cy_as_device *dev_p,
3072                                 cy_as_ll_request_response *req_p,
3073                                 cy_as_ll_request_response *reply_p,
3074                                 cy_bool *state_p)
3075 {
3076         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3077         uint8_t code = cy_as_ll_request_response__get_code(reply_p);
3078
3079         if (code == CY_RESP_SUCCESS_FAILURE) {
3080                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3081                 goto destroy;
3082         } else if (code != CY_RESP_ENDPOINT_STALL) {
3083                 ret = CY_AS_ERROR_INVALID_RESPONSE;
3084                 goto destroy;
3085         }
3086
3087         *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
3088         ret = CY_AS_ERROR_SUCCESS;
3089
3090
3091 destroy:
3092                 cy_as_ll_destroy_request(dev_p, req_p);
3093                 cy_as_ll_destroy_response(dev_p, reply_p);
3094
3095                 return ret;
3096 }
3097
3098 static cy_as_return_status_t
3099 my_handle_response_get_nak(cy_as_device *dev_p,
3100                                            cy_as_ll_request_response *req_p,
3101                                            cy_as_ll_request_response *reply_p,
3102                                            cy_bool *state_p)
3103 {
3104         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
3105         uint8_t code = cy_as_ll_request_response__get_code(reply_p);
3106
3107         if (code == CY_RESP_SUCCESS_FAILURE) {
3108                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
3109                 goto destroy;
3110         } else if (code != CY_RESP_ENDPOINT_NAK) {
3111                 ret = CY_AS_ERROR_INVALID_RESPONSE;
3112                 goto destroy;
3113         }
3114
3115         *state_p = (cy_bool)cy_as_ll_request_response__get_word(reply_p, 0);
3116         ret = CY_AS_ERROR_SUCCESS;
3117
3118
3119 destroy:
3120                 cy_as_ll_destroy_request(dev_p, req_p);
3121                 cy_as_ll_destroy_response(dev_p, reply_p);
3122
3123                 return ret;
3124 }
3125
3126 static cy_as_return_status_t
3127 cy_as_usb_get_nak_stall(cy_as_device_handle handle,
3128                                    cy_as_end_point_number_t ep,
3129                                    uint16_t request,
3130                                    uint16_t response,
3131                                    cy_bool *state_p,
3132                                    cy_as_function_callback cb,
3133                                    uint32_t client)
3134 {
3135         cy_as_return_status_t ret;
3136         cy_as_ll_request_response *req_p , *reply_p;
3137         uint16_t data;
3138
3139         cy_as_device *dev_p = (cy_as_device *)handle;
3140
3141         (void)response;
3142
3143         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3144                 return CY_AS_ERROR_INVALID_HANDLE;
3145
3146         ret = is_usb_active(dev_p);
3147         if (ret != CY_AS_ERROR_SUCCESS)
3148                 return ret;
3149
3150         if (cy_as_device_is_in_callback(dev_p) && !cb)
3151                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3152
3153         req_p = cy_as_ll_create_request(dev_p, request,
3154                 CY_RQT_USB_RQT_CONTEXT, 1);
3155         if (req_p == 0)
3156                 return CY_AS_ERROR_OUT_OF_MEMORY;
3157
3158         /* Set the endpoint */
3159         data = (uint8_t)ep;
3160         cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)ep);
3161
3162         /* A single status word response type */
3163         reply_p = cy_as_ll_create_response(dev_p, 1);
3164         if (reply_p == 0) {
3165                 cy_as_ll_destroy_request(dev_p, req_p);
3166                 return CY_AS_ERROR_OUT_OF_MEMORY;
3167         }
3168
3169         if (cb == 0) {
3170                 ret = cy_as_ll_send_request_wait_reply(dev_p,
3171                         req_p, reply_p);
3172                 if (ret != CY_AS_ERROR_SUCCESS)
3173                         goto destroy;
3174
3175                 if (request == CY_RQT_GET_STALL)
3176                         return my_handle_response_get_stall(dev_p,
3177                                 req_p, reply_p, state_p);
3178                 else
3179                         return my_handle_response_get_nak(dev_p,
3180                                 req_p, reply_p, state_p);
3181
3182         } else {
3183                 cy_as_funct_c_b_type type;
3184
3185                 if (request == CY_RQT_GET_STALL)
3186                         type = CY_FUNCT_CB_USB_GETSTALL;
3187                 else
3188                         type = CY_FUNCT_CB_USB_GETNAK;
3189
3190                 ret = cy_as_misc_send_request(dev_p, cb, client, type,
3191                         state_p, dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
3192                         req_p, reply_p, cy_as_usb_func_callback);
3193
3194                 if (ret != CY_AS_ERROR_SUCCESS)
3195                         goto destroy;
3196
3197                 return ret;
3198         }
3199
3200 destroy:
3201         cy_as_ll_destroy_request(dev_p, req_p);
3202         cy_as_ll_destroy_response(dev_p, reply_p);
3203
3204         return ret;
3205 }
3206
3207 cy_as_return_status_t
3208 cy_as_usb_set_nak(cy_as_device_handle handle,
3209                                 cy_as_end_point_number_t ep,
3210                                 cy_as_function_callback cb,
3211                                 uint32_t client)
3212 {
3213         cy_as_device *dev_p = (cy_as_device *)handle;
3214         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3215                 return CY_AS_ERROR_INVALID_HANDLE;
3216
3217         /*
3218         * we send the firmware the EP# with the appropriate direction
3219         * bit, regardless of what the user gave us.
3220         */
3221         ep &= 0x0f;
3222         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3223                 ep |= 0x80;
3224
3225                 if (dev_p->mtp_count > 0)
3226                                 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3227
3228         return cy_as_usb_nak_stall_request(handle, ep,
3229                 CY_RQT_ENDPOINT_SET_NAK, cy_true, 0, cb, client);
3230 }
3231 EXPORT_SYMBOL(cy_as_usb_set_nak);
3232
3233 cy_as_return_status_t
3234 cy_as_usb_clear_nak(cy_as_device_handle handle,
3235                                   cy_as_end_point_number_t ep,
3236                                   cy_as_function_callback cb,
3237                                   uint32_t client)
3238 {
3239         cy_as_device *dev_p = (cy_as_device *)handle;
3240         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3241                 return CY_AS_ERROR_INVALID_HANDLE;
3242
3243         /*
3244         * we send the firmware the EP# with the appropriate
3245         * direction bit, regardless of what the user gave us.
3246         */
3247         ep &= 0x0f;
3248         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3249                 ep |= 0x80;
3250
3251                 if (dev_p->mtp_count > 0)
3252                                 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3253
3254         return cy_as_usb_nak_stall_request(handle, ep,
3255                 CY_RQT_ENDPOINT_SET_NAK, cy_false, 0, cb, client);
3256 }
3257 EXPORT_SYMBOL(cy_as_usb_clear_nak);
3258
3259 cy_as_return_status_t
3260 cy_as_usb_get_nak(cy_as_device_handle handle,
3261                                 cy_as_end_point_number_t ep,
3262                                 cy_bool *nak_p,
3263                                 cy_as_function_callback cb,
3264                                 uint32_t client)
3265 {
3266         cy_as_device *dev_p = (cy_as_device *)handle;
3267         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3268                 return CY_AS_ERROR_INVALID_HANDLE;
3269
3270         /*
3271         * we send the firmware the EP# with the appropriate
3272         * direction bit, regardless of what the user gave us.
3273         */
3274         ep &= 0x0f;
3275         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3276                 ep |= 0x80;
3277
3278                 if (dev_p->mtp_count > 0)
3279                                 return CY_AS_ERROR_NOT_VALID_IN_MTP;
3280
3281         return cy_as_usb_get_nak_stall(handle, ep,
3282                 CY_RQT_GET_ENDPOINT_NAK, CY_RESP_ENDPOINT_NAK,
3283                 nak_p, cb, client);
3284 }
3285 EXPORT_SYMBOL(cy_as_usb_get_nak);
3286
3287 cy_as_return_status_t
3288 cy_as_usb_set_stall(cy_as_device_handle handle,
3289                                   cy_as_end_point_number_t ep,
3290                                   cy_as_function_callback cb,
3291                                   uint32_t client)
3292 {
3293         cy_as_device *dev_p = (cy_as_device *)handle;
3294         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3295                 return CY_AS_ERROR_INVALID_HANDLE;
3296
3297         /*
3298         * we send the firmware the EP# with the appropriate
3299         * direction bit, regardless of what the user gave us.
3300         */
3301         ep &= 0x0f;
3302         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3303                 ep |= 0x80;
3304
3305         if (dev_p->mtp_turbo_active)
3306                 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3307
3308         return cy_as_usb_nak_stall_request(handle, ep,
3309                 CY_RQT_STALL_ENDPOINT, cy_true, 0, cb, client);
3310 }
3311 EXPORT_SYMBOL(cy_as_usb_set_stall);
3312
3313 cy_as_return_status_t
3314 cy_as_usb_clear_stall(cy_as_device_handle handle,
3315                                         cy_as_end_point_number_t ep,
3316                                         cy_as_function_callback cb,
3317                                         uint32_t client)
3318 {
3319         cy_as_device *dev_p = (cy_as_device *)handle;
3320         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3321                 return CY_AS_ERROR_INVALID_HANDLE;
3322
3323         /*
3324         * we send the firmware the EP# with the appropriate
3325         * direction bit, regardless of what the user gave us.
3326         */
3327         ep &= 0x0f;
3328         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3329                 ep |= 0x80;
3330
3331         if (dev_p->mtp_turbo_active)
3332                 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3333
3334         return cy_as_usb_nak_stall_request(handle, ep,
3335                 CY_RQT_STALL_ENDPOINT, cy_false, 0, cb, client);
3336 }
3337 EXPORT_SYMBOL(cy_as_usb_clear_stall);
3338
3339 cy_as_return_status_t
3340 cy_as_usb_get_stall(cy_as_device_handle handle,
3341                                   cy_as_end_point_number_t ep,
3342                                   cy_bool *stall_p,
3343                                   cy_as_function_callback cb,
3344                                   uint32_t client)
3345 {
3346         cy_as_device *dev_p = (cy_as_device *)handle;
3347         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3348                 return CY_AS_ERROR_INVALID_HANDLE;
3349
3350         /*
3351         * we send the firmware the EP# with the appropriate
3352         * direction bit, regardless of what the user gave us.
3353         */
3354         ep &= 0x0f;
3355         if (dev_p->usb_config[ep].dir == cy_as_usb_in)
3356                 ep |= 0x80;
3357
3358         if (dev_p->mtp_turbo_active)
3359                 return CY_AS_ERROR_NOT_VALID_DURING_MTP;
3360
3361         return cy_as_usb_get_nak_stall(handle, ep,
3362                 CY_RQT_GET_STALL, CY_RESP_ENDPOINT_STALL, stall_p, cb, client);
3363 }
3364 EXPORT_SYMBOL(cy_as_usb_get_stall);
3365
3366 cy_as_return_status_t
3367 cy_as_usb_signal_remote_wakeup(cy_as_device_handle handle,
3368                 cy_as_function_callback cb,
3369                 uint32_t client)
3370 {
3371         cy_as_return_status_t ret;
3372         cy_as_ll_request_response *req_p , *reply_p;
3373
3374         cy_as_device *dev_p = (cy_as_device *)handle;
3375         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3376                 return CY_AS_ERROR_INVALID_HANDLE;
3377
3378         ret = is_usb_active(dev_p);
3379         if (ret != CY_AS_ERROR_SUCCESS)
3380                 return ret;
3381
3382         if (cy_as_device_is_in_callback(dev_p))
3383                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3384
3385         if (dev_p->usb_last_event != cy_as_event_usb_suspend)
3386                 return CY_AS_ERROR_NOT_IN_SUSPEND;
3387
3388         req_p = cy_as_ll_create_request(dev_p,
3389                 CY_RQT_USB_REMOTE_WAKEUP, CY_RQT_USB_RQT_CONTEXT, 0);
3390         if (req_p == 0)
3391                 return CY_AS_ERROR_OUT_OF_MEMORY;
3392
3393         /* A single status word response type */
3394         reply_p = cy_as_ll_create_response(dev_p, 1);
3395         if (reply_p == 0) {
3396                 cy_as_ll_destroy_request(dev_p, req_p);
3397                 return CY_AS_ERROR_OUT_OF_MEMORY;
3398         }
3399
3400         if (cb == 0) {
3401                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3402                 if (ret != CY_AS_ERROR_SUCCESS)
3403                         goto destroy;
3404
3405                 if (cy_as_ll_request_response__get_code(reply_p) ==
3406                         CY_RESP_SUCCESS_FAILURE)
3407                         ret = cy_as_ll_request_response__get_word(reply_p, 0);
3408                 else
3409                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3410         } else {
3411                 ret = cy_as_misc_send_request(dev_p, cb, client,
3412                         CY_FUNCT_CB_USB_SIGNALREMOTEWAKEUP, 0,
3413                         dev_p->func_cbs_usb,
3414                         CY_AS_REQUEST_RESPONSE_EX, req_p,
3415                         reply_p, cy_as_usb_func_callback);
3416
3417                 if (ret != CY_AS_ERROR_SUCCESS)
3418                         goto destroy;
3419                 return ret;
3420         }
3421
3422 destroy:
3423         cy_as_ll_destroy_request(dev_p, req_p);
3424         cy_as_ll_destroy_response(dev_p, reply_p);
3425
3426         return ret;
3427 }
3428 EXPORT_SYMBOL(cy_as_usb_signal_remote_wakeup);
3429
3430 cy_as_return_status_t
3431 cy_as_usb_set_m_s_report_threshold(cy_as_device_handle handle,
3432                 uint32_t wr_sectors,
3433                 uint32_t rd_sectors,
3434                 cy_as_function_callback cb,
3435                 uint32_t client)
3436 {
3437         cy_as_return_status_t ret;
3438         cy_as_ll_request_response *req_p , *reply_p;
3439
3440         cy_as_device *dev_p = (cy_as_device *)handle;
3441         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3442                 return CY_AS_ERROR_INVALID_HANDLE;
3443
3444         ret = is_usb_active(dev_p);
3445         if (ret != CY_AS_ERROR_SUCCESS)
3446                 return ret;
3447
3448         if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
3449                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3450
3451         /* Check if the firmware version supports this feature. */
3452         if ((dev_p->media_supported[0]) && (dev_p->media_supported[0] ==
3453                 (1 << cy_as_media_nand)))
3454                 return CY_AS_ERROR_NOT_SUPPORTED;
3455
3456         req_p = cy_as_ll_create_request(dev_p, CY_RQT_USB_STORAGE_MONITOR,
3457                 CY_RQT_USB_RQT_CONTEXT, 4);
3458         if (req_p == 0)
3459                 return CY_AS_ERROR_OUT_OF_MEMORY;
3460
3461         /* A single status word response type */
3462         reply_p = cy_as_ll_create_response(dev_p, 1);
3463         if (reply_p == 0) {
3464                 cy_as_ll_destroy_request(dev_p, req_p);
3465                 return CY_AS_ERROR_OUT_OF_MEMORY;
3466         }
3467
3468         /* Set the read and write count parameters into
3469          * the request structure. */
3470         cy_as_ll_request_response__set_word(req_p, 0,
3471                 (uint16_t)((wr_sectors >> 16) & 0xFFFF));
3472         cy_as_ll_request_response__set_word(req_p, 1,
3473                 (uint16_t)(wr_sectors & 0xFFFF));
3474         cy_as_ll_request_response__set_word(req_p, 2,
3475                 (uint16_t)((rd_sectors >> 16) & 0xFFFF));
3476         cy_as_ll_request_response__set_word(req_p, 3,
3477                 (uint16_t)(rd_sectors & 0xFFFF));
3478
3479         if (cb == 0) {
3480                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3481                 if (ret != CY_AS_ERROR_SUCCESS)
3482                         goto destroy;
3483
3484                 if (cy_as_ll_request_response__get_code(reply_p) ==
3485                 CY_RESP_SUCCESS_FAILURE)
3486                         ret = cy_as_ll_request_response__get_word(reply_p, 0);
3487                 else
3488                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3489         } else {
3490                 ret = cy_as_misc_send_request(dev_p, cb, client,
3491                         CY_FUNCT_CB_USB_SET_MSREPORT_THRESHOLD, 0,
3492                         dev_p->func_cbs_usb, CY_AS_REQUEST_RESPONSE_EX,
3493                         req_p, reply_p, cy_as_usb_func_callback);
3494
3495                 if (ret != CY_AS_ERROR_SUCCESS)
3496                         goto destroy;
3497                 return ret;
3498         }
3499
3500 destroy:
3501         cy_as_ll_destroy_request(dev_p, req_p);
3502         cy_as_ll_destroy_response(dev_p, reply_p);
3503
3504         return ret;
3505 }
3506 EXPORT_SYMBOL(cy_as_usb_set_m_s_report_threshold);
3507
3508 cy_as_return_status_t
3509 cy_as_usb_select_m_s_partitions(
3510                 cy_as_device_handle             handle,
3511                 cy_as_bus_number_t               bus,
3512                 uint32_t                                device,
3513                 cy_as_usb_m_s_type_t             type,
3514                 cy_as_function_callback cb,
3515                 uint32_t                                client)
3516 {
3517         cy_as_return_status_t ret;
3518         cy_as_ll_request_response *req_p , *reply_p;
3519         uint16_t val;
3520
3521         cy_as_device *dev_p = (cy_as_device *)handle;
3522         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
3523                 return CY_AS_ERROR_INVALID_HANDLE;
3524
3525         ret = is_usb_active(dev_p);
3526         if (ret != CY_AS_ERROR_SUCCESS)
3527                 return ret;
3528
3529         /* This API has to be made before SetEnumConfig is called. */
3530         if (dev_p->usb_config[0].enabled)
3531                 return CY_AS_ERROR_INVALID_CALL_SEQUENCE;
3532
3533         if ((cb == 0) && (cy_as_device_is_in_callback(dev_p)))
3534                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
3535
3536         req_p = cy_as_ll_create_request(dev_p, CY_RQT_MS_PARTITION_SELECT,
3537                 CY_RQT_USB_RQT_CONTEXT, 2);
3538         if (req_p == 0)
3539                 return CY_AS_ERROR_OUT_OF_MEMORY;
3540
3541         /* A single status word response type */
3542         reply_p = cy_as_ll_create_response(dev_p, 1);
3543         if (reply_p == 0) {
3544                 cy_as_ll_destroy_request(dev_p, req_p);
3545                 return CY_AS_ERROR_OUT_OF_MEMORY;
3546         }
3547
3548         /* Set the read and write count parameters into
3549          * the request structure. */
3550         cy_as_ll_request_response__set_word(req_p, 0,
3551                 (uint16_t)((bus << 8) | device));
3552
3553         val = 0;
3554         if ((type == cy_as_usb_m_s_unit0) || (type == cy_as_usb_m_s_both))
3555                 val |= 1;
3556         if ((type == cy_as_usb_m_s_unit1) || (type == cy_as_usb_m_s_both))
3557                 val |= (1 << 8);
3558
3559         cy_as_ll_request_response__set_word(req_p, 1, val);
3560
3561         if (cb == 0) {
3562                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
3563                 if (ret != CY_AS_ERROR_SUCCESS)
3564                         goto destroy;
3565
3566                 if (cy_as_ll_request_response__get_code(reply_p) ==
3567                 CY_RESP_SUCCESS_FAILURE)
3568                         ret = cy_as_ll_request_response__get_word(reply_p, 0);
3569                 else
3570                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3571         } else {
3572                 ret = cy_as_misc_send_request(dev_p, cb, client,
3573                         CY_FUNCT_CB_NODATA, 0, dev_p->func_cbs_usb,
3574                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
3575                         cy_as_usb_func_callback);
3576
3577                 if (ret != CY_AS_ERROR_SUCCESS)
3578                         goto destroy;
3579                 return ret;
3580         }
3581
3582 destroy:
3583         cy_as_ll_destroy_request(dev_p, req_p);
3584         cy_as_ll_destroy_response(dev_p, reply_p);
3585
3586         return ret;
3587 }
3588 EXPORT_SYMBOL(cy_as_usb_select_m_s_partitions);
3589
3590 static void
3591 cy_as_usb_func_callback(
3592                                         cy_as_device *dev_p,
3593                                         uint8_t context,
3594                                         cy_as_ll_request_response *rqt,
3595                                         cy_as_ll_request_response *resp,
3596                                         cy_as_return_status_t stat)
3597 {
3598         cy_as_usb_func_c_b_node* node = (cy_as_usb_func_c_b_node *)
3599                 dev_p->usb_func_cbs->head_p;
3600         cy_as_func_c_b_node* fnode = (cy_as_func_c_b_node *)
3601                 dev_p->func_cbs_usb->head_p;
3602         cy_as_return_status_t  ret = CY_AS_ERROR_SUCCESS;
3603
3604         cy_as_device_handle     h = (cy_as_device_handle)dev_p;
3605         cy_bool delayed_ack = (rqt->flags & CY_AS_REQUEST_RESPONSE_DELAY_ACK)
3606                 == CY_AS_REQUEST_RESPONSE_DELAY_ACK;
3607         cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX)
3608                 == CY_AS_REQUEST_RESPONSE_EX;
3609         cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS)
3610                 == CY_AS_REQUEST_RESPONSE_MS;
3611         uint8_t code;
3612         uint8_t ep, state;
3613
3614         if (!ex_request && !ms_request) {
3615                 cy_as_hal_assert(dev_p->usb_func_cbs->count != 0);
3616                 cy_as_hal_assert(dev_p->usb_func_cbs->type ==
3617                         CYAS_USB_FUNC_CB);
3618         } else {
3619                 cy_as_hal_assert(dev_p->func_cbs_usb->count != 0);
3620                 cy_as_hal_assert(dev_p->func_cbs_usb->type == CYAS_FUNC_CB);
3621         }
3622
3623         (void)context;
3624
3625         /* The Handlers are responsible for Deleting the rqt and resp when
3626          * they are finished
3627          */
3628         code = cy_as_ll_request_response__get_code(rqt);
3629         switch (code) {
3630         case CY_RQT_START_USB:
3631                 ret = my_handle_response_usb_start(dev_p, rqt, resp, stat);
3632                 break;
3633         case CY_RQT_STOP_USB:
3634                 ret = my_handle_response_usb_stop(dev_p, rqt, resp, stat);
3635                 break;
3636         case CY_RQT_SET_CONNECT_STATE:
3637                 if (!cy_as_ll_request_response__get_word(rqt, 0))
3638                         ret = my_handle_response_disconnect(
3639                                 dev_p, rqt, resp, stat);
3640                 else
3641                         ret = my_handle_response_connect(
3642                                 dev_p, rqt, resp, stat);
3643                 break;
3644         case CY_RQT_GET_CONNECT_STATE:
3645                 break;
3646         case CY_RQT_SET_USB_CONFIG:
3647                 ret = my_handle_response_set_enum_config(dev_p, rqt, resp);
3648                 break;
3649         case CY_RQT_GET_USB_CONFIG:
3650                 cy_as_hal_assert(fnode->data != 0);
3651                 ret = my_handle_response_get_enum_config(dev_p,
3652                         rqt, resp, fnode->data);
3653                 break;
3654         case CY_RQT_STALL_ENDPOINT:
3655                 ep      = (uint8_t)cy_as_ll_request_response__get_word(rqt, 0);
3656                 state = (uint8_t)cy_as_ll_request_response__get_word(rqt, 1);
3657                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3658                 if ((ret == CY_AS_ERROR_SUCCESS) && (ep > 1) && (state != 0)
3659                         && (dev_p->usb_config[ep].dir == cy_as_usb_out))
3660                         cy_as_usb_flush_logical_e_p(dev_p, ep);
3661                 break;
3662         case CY_RQT_GET_STALL:
3663                 cy_as_hal_assert(fnode->data != 0);
3664                 ret = my_handle_response_get_stall(dev_p,
3665                         rqt, resp, (cy_bool *)fnode->data);
3666                 break;
3667         case CY_RQT_SET_DESCRIPTOR:
3668                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3669                 break;
3670         case CY_RQT_GET_DESCRIPTOR:
3671                 cy_as_hal_assert(fnode->data != 0);
3672                 ret = my_handle_response_get_descriptor(dev_p,
3673                         rqt, resp, (cy_as_get_descriptor_data *)fnode->data);
3674                 break;
3675         case CY_RQT_SET_USB_CONFIG_REGISTERS:
3676                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3677                 if (ret == CY_AS_ERROR_SUCCESS)
3678                         ret = cy_as_usb_setup_dma(dev_p);
3679                 break;
3680         case CY_RQT_ENDPOINT_SET_NAK:
3681                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3682                 break;
3683         case CY_RQT_GET_ENDPOINT_NAK:
3684                 cy_as_hal_assert(fnode->data != 0);
3685                 ret = my_handle_response_get_nak(dev_p,
3686                         rqt, resp, (cy_bool *)fnode->data);
3687                 break;
3688         case CY_RQT_ACK_SETUP_PACKET:
3689                 break;
3690         case CY_RQT_USB_REMOTE_WAKEUP:
3691                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3692                 break;
3693         case CY_RQT_CLEAR_DESCRIPTORS:
3694                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3695                 break;
3696         case CY_RQT_USB_STORAGE_MONITOR:
3697                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3698                 break;
3699         case CY_RQT_MS_PARTITION_SELECT:
3700                 ret = my_handle_response_no_data(dev_p, rqt, resp);
3701                 break;
3702         default:
3703                 ret = CY_AS_ERROR_INVALID_RESPONSE;
3704                 cy_as_hal_assert(cy_false);
3705                 break;
3706         }
3707
3708         /*
3709          * if the low level layer returns a direct error, use
3710          * the corresponding error code. if not, use the error
3711          * code based on the response from firmware.
3712          */
3713         if (stat == CY_AS_ERROR_SUCCESS)
3714                 stat = ret;
3715
3716         if (ex_request || ms_request) {
3717                 fnode->cb_p((cy_as_device_handle)dev_p, stat,
3718                         fnode->client_data, fnode->data_type, fnode->data);
3719                 cy_as_remove_c_b_node(dev_p->func_cbs_usb);
3720         } else {
3721                 node->cb_p((cy_as_device_handle)dev_p, stat,
3722                         node->client_data);
3723                 cy_as_remove_c_b_node(dev_p->usb_func_cbs);
3724         }
3725
3726         if (delayed_ack) {
3727                 cy_as_hal_assert(cy_as_device_is_ack_delayed(dev_p));
3728                 cy_as_device_rem_ack_delayed(dev_p);
3729
3730                 /*
3731                  * send the ACK if required.
3732                  */
3733                 if (!cy_as_device_is_ack_delayed(dev_p))
3734                         cy_as_usb_ack_setup_packet(h,
3735                                 usb_ack_callback, 0);
3736         }
3737 }
3738
3739
3740 /*[]*/