Linux-libre 3.0.56-gnu1
[librecmc/linux-libre.git] / drivers / staging / westbridge / astoria / api / src / cyasmtp.c
1 /* Cypress West Bridge API header file (cyasmtp.h)
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/cyasmtp.h"
24 #include "../../include/linux/westbridge/cyaserr.h"
25 #include "../../include/linux/westbridge/cyasdma.h"
26 #include "../../include/linux/westbridge/cyaslowlevel.h"
27
28 static void
29 cy_as_mtp_func_callback(cy_as_device *dev_p,
30                                         uint8_t context,
31                                         cy_as_ll_request_response *rqt,
32                                         cy_as_ll_request_response *resp,
33                                         cy_as_return_status_t stat);
34
35 static cy_as_return_status_t
36 is_mtp_active(cy_as_device *dev_p)
37 {
38         if (!cy_as_device_is_configured(dev_p))
39                 return CY_AS_ERROR_NOT_CONFIGURED;
40
41         if (!cy_as_device_is_firmware_loaded(dev_p))
42                 return CY_AS_ERROR_NO_FIRMWARE;
43
44         if (dev_p->mtp_count == 0)
45                 return CY_AS_ERROR_NOT_RUNNING;
46
47         if (cy_as_device_is_in_suspend_mode(dev_p))
48                 return CY_AS_ERROR_IN_SUSPEND;
49
50         return CY_AS_ERROR_SUCCESS;
51 }
52
53 static void
54 my_mtp_request_callback(cy_as_device *dev_p,
55                                          uint8_t context,
56                                          cy_as_ll_request_response *req_p,
57                                          cy_as_ll_request_response *resp_p,
58                                          cy_as_return_status_t ret)
59 {
60         uint16_t val, ev, status;
61         uint16_t mtp_datalen = 0;
62         uint32_t bytecount_l, bytecount_h;
63         cy_as_mtp_send_object_complete_data send_obj_data;
64         cy_as_mtp_get_object_complete_data  get_obj_data;
65         cy_as_dma_end_point *ep_p;
66
67         uint8_t code = cy_as_ll_request_response__get_code(req_p);
68
69         (void)resp_p;
70         (void)context;
71         (void)ret;
72
73         switch (code) {
74         case CY_RQT_MTP_EVENT:
75                 val = cy_as_ll_request_response__get_word(req_p, 0);
76                 /* MSB indicates status of read/write */
77                 status = (val >> 8) & 0xFF;
78                 /* event type */
79                 ev =   val & 0xFF;
80                 switch (ev) {
81                 case 0: /* SendObject Complete */
82                         {
83                                 bytecount_l =
84                                         cy_as_ll_request_response__get_word
85                                         (req_p, 1);
86                                 bytecount_h =
87                                         cy_as_ll_request_response__get_word
88                                         (req_p, 2);
89                                 send_obj_data.byte_count =
90                                         (bytecount_h << 16) | bytecount_l;
91
92                                 send_obj_data.status = status;
93
94                                 /* use the byte count again */
95                                 bytecount_l =
96                                         cy_as_ll_request_response__get_word
97                                         (req_p, 3);
98                                 bytecount_h =
99                                         cy_as_ll_request_response__get_word
100                                         (req_p, 4);
101                                 send_obj_data.transaction_id =
102                                         (bytecount_h << 16) | bytecount_l;
103
104                                 dev_p->mtp_turbo_active = cy_false;
105
106                                 if (dev_p->mtp_event_cb)
107                                         dev_p->mtp_event_cb(
108                                         (cy_as_device_handle) dev_p,
109                                         cy_as_mtp_send_object_complete,
110                                                 &send_obj_data);
111                         }
112                         break;
113
114                 case 1: /* GetObject Complete */
115                         {
116                                 bytecount_l =
117                                         cy_as_ll_request_response__get_word
118                                         (req_p, 1);
119                                 bytecount_h =
120                                         cy_as_ll_request_response__get_word
121                                         (req_p, 2);
122
123                                 get_obj_data.byte_count =
124                                         (bytecount_h << 16) | bytecount_l;
125
126                                 get_obj_data.status = status;
127
128                                 dev_p->mtp_turbo_active = cy_false;
129
130                                 if (dev_p->mtp_event_cb)
131                                         dev_p->mtp_event_cb(
132                                         (cy_as_device_handle) dev_p,
133                                         cy_as_mtp_get_object_complete,
134                                         &get_obj_data);
135                         }
136                         break;
137
138                 case 2: /* BlockTable Needed */
139                         {
140                                 if (dev_p->mtp_event_cb)
141                                         dev_p->mtp_event_cb(
142                                         (cy_as_device_handle) dev_p,
143                                         cy_as_mtp_block_table_needed, 0);
144                         }
145                         break;
146                 default:
147                         cy_as_hal_print_message("invalid event type\n");
148                         cy_as_ll_send_data_response(dev_p,
149                                 CY_RQT_TUR_RQT_CONTEXT,
150                                 CY_RESP_MTP_INVALID_EVENT,
151                                 sizeof(ev), &ev);
152                         break;
153                 }
154                 break;
155
156         case CY_RQT_TURBO_CMD_FROM_HOST:
157                 {
158                         mtp_datalen =
159                                 cy_as_ll_request_response__get_word(req_p, 1);
160
161                         /* Get the endpoint pointer based on
162                          * the endpoint number */
163                         ep_p = CY_AS_NUM_EP(dev_p, CY_AS_MTP_READ_ENDPOINT);
164
165                         /* The event should arrive only after the DMA operation
166                          * has been queued. */
167                         cy_as_hal_assert(ep_p->queue_p != 0);
168
169                         /* Put the len in ep data information in
170                          * dmaqueue and kick start the queue */
171                         cy_as_hal_assert(ep_p->queue_p->size >= mtp_datalen);
172
173                         if (mtp_datalen == 0) {
174                                 cy_as_dma_completed_callback(dev_p->tag,
175                                         CY_AS_MTP_READ_ENDPOINT, 0,
176                                         CY_AS_ERROR_SUCCESS);
177                         } else {
178                                 ep_p->maxhwdata = mtp_datalen;
179
180                                 /*
181                                  * make sure that the DMA status for this
182                                  * EP is not running, so that the call to
183                                  * cy_as_dma_kick_start gets this transfer
184                                  * going. note: in MTP mode, we never leave
185                                  * a DMA transfer of greater than one packet
186                                  * running. so, it is okay to override the
187                                  * status here and start the next packet
188                                  * transfer.
189                                  */
190                                 cy_as_dma_end_point_set_stopped(ep_p);
191
192                                 /* Kick start the queue if it is not running */
193                                 cy_as_dma_kick_start(dev_p,
194                                         CY_AS_MTP_READ_ENDPOINT);
195                         }
196                 }
197                 break;
198
199         case CY_RQT_TURBO_START_WRITE_DMA:
200                 {
201                         /*
202                          * now that the firmware is ready to receive the
203                          * next packet of data, start the corresponding
204                          * DMA transfer.  first, ensure that a DMA
205                          * operation is still pending in the queue for the
206                          * write endpoint.
207                          */
208                         cy_as_ll_send_status_response(dev_p,
209                                 CY_RQT_TUR_RQT_CONTEXT,
210                                 CY_AS_ERROR_SUCCESS, 0);
211
212                         ep_p = CY_AS_NUM_EP(dev_p, CY_AS_MTP_WRITE_ENDPOINT);
213                         cy_as_hal_assert(ep_p->queue_p != 0);
214
215                         cy_as_dma_end_point_set_stopped(ep_p);
216                         cy_as_dma_kick_start(dev_p, CY_AS_MTP_WRITE_ENDPOINT);
217                 }
218                 break;
219
220         default:
221                 cy_as_hal_print_message("invalid request received "
222                                 "on TUR context\n");
223                 val = req_p->box0;
224                 cy_as_ll_send_data_response(dev_p, CY_RQT_TUR_RQT_CONTEXT,
225                         CY_RESP_INVALID_REQUEST, sizeof(val), &val);
226                 break;
227         }
228 }
229
230 static cy_as_return_status_t
231 my_handle_response_no_data(cy_as_device *dev_p,
232                         cy_as_ll_request_response *req_p,
233                         cy_as_ll_request_response *reply_p)
234 {
235         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
236
237         if (cy_as_ll_request_response__get_code(reply_p) !=
238                 CY_RESP_SUCCESS_FAILURE) {
239                 ret = CY_AS_ERROR_INVALID_RESPONSE;
240                 goto destroy;
241         }
242
243         ret = cy_as_ll_request_response__get_word(reply_p, 0);
244
245 destroy:
246         cy_as_ll_destroy_request(dev_p, req_p);
247         cy_as_ll_destroy_response(dev_p, reply_p);
248
249         return ret;
250 }
251
252 static cy_as_return_status_t
253 my_handle_response_mtp_start(cy_as_device *dev_p,
254                         cy_as_ll_request_response *req_p,
255                         cy_as_ll_request_response *reply_p,
256                         cy_as_return_status_t ret)
257 {
258         if (ret != CY_AS_ERROR_SUCCESS)
259                 goto destroy;
260
261         if (cy_as_ll_request_response__get_code(reply_p) !=
262                 CY_RESP_SUCCESS_FAILURE) {
263                 ret = CY_AS_ERROR_INVALID_RESPONSE;
264                 goto destroy;
265         }
266
267         ret = cy_as_ll_request_response__get_word(reply_p, 0);
268         if (ret != CY_AS_ERROR_SUCCESS)
269                 goto destroy;
270
271         dev_p->mtp_count++;
272
273         cy_as_dma_enable_end_point(dev_p, CY_AS_MTP_READ_ENDPOINT,
274                 cy_true, cy_as_direction_out);
275         dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].enabled = cy_true;
276         dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].dir = cy_as_usb_out;
277         dev_p->usb_config[CY_AS_MTP_READ_ENDPOINT].type = cy_as_usb_bulk;
278
279         cy_as_dma_enable_end_point(dev_p, CY_AS_MTP_WRITE_ENDPOINT,
280                 cy_true, cy_as_direction_in);
281         dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].enabled = cy_true;
282         dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].dir = cy_as_usb_in;
283         dev_p->usb_config[CY_AS_MTP_WRITE_ENDPOINT].type = cy_as_usb_bulk;
284
285         /* Packet size is 512 bytes */
286         cy_as_dma_set_max_dma_size(dev_p, 0x02, 0x0200);
287         /* Packet size is 64 bytes until a switch to high speed happens.*/
288         cy_as_dma_set_max_dma_size(dev_p, 0x06, 0x40);
289
290 destroy:
291         cy_as_ll_destroy_request(dev_p, req_p);
292         cy_as_ll_destroy_response(dev_p, reply_p);
293
294         if (ret != CY_AS_ERROR_SUCCESS)
295                 cy_as_ll_register_request_callback(dev_p,
296                         CY_RQT_TUR_RQT_CONTEXT, 0);
297
298         cy_as_device_clear_m_s_s_pending(dev_p);
299
300         return ret;
301 }
302
303
304 cy_as_return_status_t
305 cy_as_mtp_start(cy_as_device_handle handle,
306                          cy_as_mtp_event_callback event_c_b,
307                          cy_as_function_callback cb,
308                          uint32_t client
309                         )
310 {
311         cy_as_ll_request_response *req_p, *reply_p;
312         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
313         cy_as_device *dev_p;
314
315         dev_p = (cy_as_device *)handle;
316         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
317                 return CY_AS_ERROR_INVALID_HANDLE;
318
319         if (!cy_as_device_is_configured(dev_p))
320                 return CY_AS_ERROR_NOT_CONFIGURED;
321
322         if (!cy_as_device_is_firmware_loaded(dev_p))
323                 return CY_AS_ERROR_NO_FIRMWARE;
324
325         if (cy_as_device_is_in_suspend_mode(dev_p))
326                 return CY_AS_ERROR_IN_SUSPEND;
327
328         if (cy_as_device_is_in_callback(dev_p))
329                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
330
331         if (cy_as_device_is_m_s_s_pending(dev_p))
332                 return CY_AS_ERROR_STARTSTOP_PENDING;
333
334         if (dev_p->storage_count == 0)
335                 return CY_AS_ERROR_NOT_RUNNING;
336
337         if (dev_p->usb_count == 0)
338                 return CY_AS_ERROR_NOT_RUNNING;
339
340         if (dev_p->is_mtp_firmware == 0)
341                 return CY_AS_ERROR_NOT_SUPPORTED;
342
343         cy_as_device_set_m_s_s_pending(dev_p);
344
345         if (dev_p->mtp_count == 0) {
346
347                 dev_p->mtp_event_cb = event_c_b;
348                 /*
349                 * we register here because the start request may cause
350                 * events to occur before the response to the start request.
351                 */
352                 cy_as_ll_register_request_callback(dev_p,
353                         CY_RQT_TUR_RQT_CONTEXT, my_mtp_request_callback);
354
355                 /* Create the request to send to the West Bridge device */
356                 req_p = cy_as_ll_create_request(dev_p,
357                         CY_RQT_START_MTP, CY_RQT_TUR_RQT_CONTEXT, 0);
358                 if (req_p == 0) {
359                         cy_as_device_clear_m_s_s_pending(dev_p);
360                         return CY_AS_ERROR_OUT_OF_MEMORY;
361                 }
362
363                 /* Reserve space for the reply, the reply data will
364                  * not exceed one word */
365                 reply_p = cy_as_ll_create_response(dev_p, 1);
366                 if (reply_p == 0) {
367                         cy_as_ll_destroy_request(dev_p, req_p);
368                         cy_as_device_clear_m_s_s_pending(dev_p);
369                         return CY_AS_ERROR_OUT_OF_MEMORY;
370                 }
371
372                 if (cb == 0) {
373                         ret = cy_as_ll_send_request_wait_reply(dev_p,
374                                 req_p, reply_p);
375                         if (ret != CY_AS_ERROR_SUCCESS)
376                                 goto destroy;
377
378                         return my_handle_response_mtp_start(dev_p, req_p,
379                                 reply_p, ret);
380                 } else {
381                         ret = cy_as_misc_send_request(dev_p, cb, client,
382                                 CY_FUNCT_CB_MTP_START, 0, dev_p->func_cbs_mtp,
383                                 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
384                                 cy_as_mtp_func_callback);
385
386                         if (ret != CY_AS_ERROR_SUCCESS)
387                                 goto destroy;
388
389                         return ret;
390                 }
391
392 destroy:
393                 cy_as_ll_destroy_request(dev_p, req_p);
394                 cy_as_ll_destroy_response(dev_p, reply_p);
395         } else {
396                 dev_p->mtp_count++;
397                 if (cb)
398                         cb(handle, ret, client, CY_FUNCT_CB_MTP_START, 0);
399         }
400
401         cy_as_device_clear_m_s_s_pending(dev_p);
402
403         return ret;
404 }
405 EXPORT_SYMBOL(cy_as_mtp_start);
406
407 static cy_as_return_status_t
408 my_handle_response_mtp_stop(cy_as_device *dev_p,
409                         cy_as_ll_request_response *req_p,
410                         cy_as_ll_request_response *reply_p,
411                         cy_as_return_status_t ret)
412 {
413         if (ret != CY_AS_ERROR_SUCCESS)
414                 goto destroy;
415
416         if (cy_as_ll_request_response__get_code(reply_p) !=
417                 CY_RESP_SUCCESS_FAILURE) {
418                 ret = CY_AS_ERROR_INVALID_RESPONSE;
419                 goto destroy;
420         }
421
422         ret = cy_as_ll_request_response__get_word(reply_p, 0);
423         if (ret != CY_AS_ERROR_SUCCESS)
424                 goto destroy;
425
426         /*
427         * we successfully shutdown the stack, so decrement
428         * to make the count zero.
429         */
430         dev_p->mtp_count--;
431
432 destroy:
433         cy_as_ll_destroy_request(dev_p, req_p);
434         cy_as_ll_destroy_response(dev_p, reply_p);
435
436         if (ret != CY_AS_ERROR_SUCCESS)
437                 cy_as_ll_register_request_callback(dev_p,
438                         CY_RQT_TUR_RQT_CONTEXT, 0);
439
440         cy_as_device_clear_m_s_s_pending(dev_p);
441
442         return ret;
443 }
444
445 cy_as_return_status_t
446 cy_as_mtp_stop(cy_as_device_handle handle,
447                         cy_as_function_callback cb,
448                         uint32_t client
449                         )
450 {
451         cy_as_ll_request_response *req_p = 0, *reply_p = 0;
452         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
453
454         cy_as_device *dev_p;
455
456         cy_as_log_debug_message(6, "cy_as_mtp_stop called");
457
458         dev_p = (cy_as_device *)handle;
459         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
460                 return CY_AS_ERROR_INVALID_HANDLE;
461
462         ret = is_mtp_active(dev_p);
463         if (ret != CY_AS_ERROR_SUCCESS)
464                 return ret;
465
466         if (cy_as_device_is_in_callback(dev_p))
467                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
468
469         if (cy_as_device_is_m_s_s_pending(dev_p))
470                 return CY_AS_ERROR_STARTSTOP_PENDING;
471
472         cy_as_device_set_m_s_s_pending(dev_p);
473
474         if (dev_p->mtp_count == 1) {
475                 /* Create the request to send to the West
476                  * Bridge device */
477                 req_p = cy_as_ll_create_request(dev_p, CY_RQT_STOP_MTP,
478                         CY_RQT_TUR_RQT_CONTEXT, 0);
479                 if (req_p == 0) {
480                         ret = CY_AS_ERROR_OUT_OF_MEMORY;
481                         goto destroy;
482                 }
483
484                 /* Reserve space for the reply, the reply data will
485                  * not exceed one word */
486                 reply_p = cy_as_ll_create_response(dev_p, 1);
487                 if (reply_p == 0) {
488                         ret = CY_AS_ERROR_OUT_OF_MEMORY;
489                         goto destroy;
490                 }
491
492                 if (cb == 0) {
493                         ret = cy_as_ll_send_request_wait_reply(dev_p,
494                                 req_p, reply_p);
495                         if (ret != CY_AS_ERROR_SUCCESS)
496                                 goto destroy;
497
498                         return my_handle_response_mtp_stop(dev_p, req_p,
499                                         reply_p, ret);
500                 } else {
501                         ret = cy_as_misc_send_request(dev_p, cb, client,
502                                 CY_FUNCT_CB_MTP_STOP, 0, dev_p->func_cbs_mtp,
503                                 CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
504                                 cy_as_mtp_func_callback);
505
506                         if (ret != CY_AS_ERROR_SUCCESS)
507                                 goto destroy;
508
509                         return ret;
510                 }
511
512 destroy:
513                 cy_as_ll_destroy_request(dev_p, req_p);
514                 cy_as_ll_destroy_response(dev_p, reply_p);
515         } else if (dev_p->mtp_count > 1) {
516
517                 dev_p->mtp_count--;
518
519                 if (cb)
520                         cb(handle, ret, client, CY_FUNCT_CB_MTP_STOP, 0);
521         }
522
523         cy_as_device_clear_m_s_s_pending(dev_p);
524
525         return ret;
526 }
527
528 static void
529 mtp_write_callback(
530                 cy_as_device *dev_p,
531                 uint8_t context,
532                 cy_as_ll_request_response *rqt,
533                 cy_as_ll_request_response *resp,
534                 cy_as_return_status_t ret)
535 {
536         cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT);
537
538         if (ret == CY_AS_ERROR_SUCCESS) {
539                 if (cy_as_ll_request_response__get_code(resp) !=
540                         CY_RESP_SUCCESS_FAILURE)
541                         ret = CY_AS_ERROR_INVALID_RESPONSE;
542                 else
543                         ret = cy_as_ll_request_response__get_word(resp, 0);
544         }
545
546         if (ret != CY_AS_ERROR_SUCCESS) {
547                 /* Firmware failed the request. Cancel the DMA transfer. */
548                 cy_as_dma_cancel(dev_p, 0x04, CY_AS_ERROR_CANCELED);
549                 cy_as_device_clear_storage_async_pending(dev_p);
550         }
551
552         cy_as_ll_destroy_response(dev_p, resp);
553         cy_as_ll_destroy_request(dev_p, rqt);
554 }
555
556 static void
557 async_write_request_callback(cy_as_device *dev_p,
558         cy_as_end_point_number_t ep, void *buf_p, uint32_t size,
559         cy_as_return_status_t err)
560 {
561         cy_as_device_handle h;
562         cy_as_function_callback cb;
563
564         (void)size;
565         (void)buf_p;
566         (void)ep;
567
568
569         cy_as_log_debug_message(6, "async_write_request_callback called");
570
571         h = (cy_as_device_handle)dev_p;
572
573         cb = dev_p->mtp_cb;
574         dev_p->mtp_cb = 0;
575
576         cy_as_device_clear_storage_async_pending(dev_p);
577
578         if (cb)
579                 cb(h, err, dev_p->mtp_client, dev_p->mtp_op, 0);
580
581 }
582
583 static void
584 sync_mtp_callback(cy_as_device *dev_p, cy_as_end_point_number_t ep,
585         void *buf_p, uint32_t size, cy_as_return_status_t err)
586 {
587         (void)ep;
588         (void)buf_p;
589         (void)size;
590
591         dev_p->mtp_error = err;
592 }
593
594 static cy_as_return_status_t
595 cy_as_mtp_operation(cy_as_device *dev_p,
596                                  cy_as_mtp_block_table *blk_table,
597                                  uint32_t num_bytes,
598                                  uint32_t transaction_id,
599                                  cy_as_function_callback cb,
600                                  uint32_t client,
601                                  uint8_t rqttype
602                                 )
603 {
604         cy_as_ll_request_response *req_p = 0, *reply_p = 0;
605         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
606         uint32_t mask = 0;
607         cy_as_funct_c_b_type mtp_cb_op = 0;
608         uint16_t size = 2;
609
610         if (dev_p->mtp_count == 0)
611                 return CY_AS_ERROR_NOT_RUNNING;
612
613         if (rqttype == CY_RQT_INIT_SEND_OBJECT) {
614                 mtp_cb_op = CY_FUNCT_CB_MTP_INIT_SEND_OBJECT;
615                 dev_p->mtp_turbo_active = cy_true;
616         } else if (rqttype == CY_RQT_INIT_GET_OBJECT) {
617                 mtp_cb_op = CY_FUNCT_CB_MTP_INIT_GET_OBJECT;
618                 dev_p->mtp_turbo_active = cy_true;
619         } else
620                 mtp_cb_op = CY_FUNCT_CB_MTP_SEND_BLOCK_TABLE;
621
622         ret = is_mtp_active(dev_p);
623         if (ret != CY_AS_ERROR_SUCCESS)
624                 return ret;
625
626         if (CY_RQT_INIT_GET_OBJECT == rqttype)
627                 size = 4;
628
629         /* Create the request to send to the West
630          * Bridge device */
631         req_p = cy_as_ll_create_request(dev_p, rqttype,
632                 CY_RQT_TUR_RQT_CONTEXT, size);
633         if (req_p == 0) {
634                 ret = CY_AS_ERROR_OUT_OF_MEMORY;
635                 goto destroy;
636         }
637
638         /* Reserve space for the reply, the reply data will
639          * not exceed one word */
640         reply_p = cy_as_ll_create_response(dev_p, 1);
641         if (reply_p == 0) {
642                 ret = CY_AS_ERROR_OUT_OF_MEMORY;
643                 goto destroy;
644         }
645
646         cy_as_ll_request_response__set_word(req_p, 0,
647                 (uint16_t)(num_bytes & 0xFFFF));
648         cy_as_ll_request_response__set_word(req_p, 1,
649                 (uint16_t)((num_bytes >> 16) & 0xFFFF));
650
651         /* If it is GET_OBJECT, send transaction id as well*/
652         if (CY_RQT_INIT_GET_OBJECT == rqttype) {
653                 cy_as_ll_request_response__set_word(req_p, 2,
654                         (uint16_t)(transaction_id & 0xFFFF));
655                 cy_as_ll_request_response__set_word(req_p, 3,
656                         (uint16_t)((transaction_id >> 16) & 0xFFFF));
657         }
658
659         if (cb == 0) {
660                 /* Queue the DMA request for block table write */
661                 ret = cy_as_dma_queue_request(dev_p, 4, blk_table,
662                         sizeof(cy_as_mtp_block_table), cy_false,
663                         cy_false, sync_mtp_callback);
664
665                 ret = cy_as_ll_send_request_wait_reply(dev_p,
666                         req_p, reply_p);
667                 if (ret != CY_AS_ERROR_SUCCESS) {
668                         cy_as_dma_cancel(dev_p, 4, CY_AS_ERROR_CANCELED);
669                         cy_as_device_clear_storage_async_pending(dev_p);
670
671                         goto destroy;
672                 }
673
674                 ret = cy_as_dma_drain_queue(dev_p, 4, cy_true);
675                 if (ret != CY_AS_ERROR_SUCCESS)
676                         goto destroy;
677
678                 ret = dev_p->mtp_error;
679                 goto destroy;
680         } else {
681 #if 0
682                 ret = cy_as_misc_send_request(dev_p, cb, client,
683                         CY_FUNCT_CB_MTP_INIT_SEND_OBJECT,
684                         0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX,
685                         req_p, reply_p, cy_as_mtp_func_callback);
686
687                 if (ret != CY_AS_ERROR_SUCCESS)
688                         goto destroy;
689 #endif
690
691                 /* Protection from interrupt driven code */
692                 /* since we are using storage EP4 check if any
693                  * storage activity is pending */
694                 mask = cy_as_hal_disable_interrupts();
695                 if ((cy_as_device_is_storage_async_pending(dev_p)) ||
696                         (dev_p->storage_wait)) {
697                         cy_as_hal_enable_interrupts(mask);
698                         return CY_AS_ERROR_ASYNC_PENDING;
699                 }
700                 cy_as_device_set_storage_async_pending(dev_p);
701                 cy_as_hal_enable_interrupts(mask);
702
703                 dev_p->mtp_cb    = cb;
704                 dev_p->mtp_client = client;
705                 dev_p->mtp_op    = mtp_cb_op;
706
707                 ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
708                         cy_false, mtp_write_callback);
709                 if (ret != CY_AS_ERROR_SUCCESS)
710                         goto destroy;
711
712                 ret = cy_as_dma_queue_request(dev_p, 4, blk_table,
713                         sizeof(cy_as_mtp_block_table), cy_false, cy_false,
714                         async_write_request_callback);
715                 if (ret != CY_AS_ERROR_SUCCESS)
716                         return ret;
717
718                 /* Kick start the queue if it is not running */
719                 cy_as_dma_kick_start(dev_p, 4);
720
721                 return CY_AS_ERROR_SUCCESS;
722         }
723
724 destroy:
725         cy_as_ll_destroy_request(dev_p, req_p);
726         cy_as_ll_destroy_response(dev_p, reply_p);
727
728         return ret;
729 }
730
731 cy_as_return_status_t
732 cy_as_mtp_init_send_object(cy_as_device_handle handle,
733                                           cy_as_mtp_block_table *blk_table,
734                                           uint32_t num_bytes,
735                                           cy_as_function_callback cb,
736                                           uint32_t client
737                                          )
738 {
739         cy_as_device *dev_p;
740         dev_p = (cy_as_device *)handle;
741         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
742                 return CY_AS_ERROR_INVALID_HANDLE;
743
744         return cy_as_mtp_operation(dev_p, blk_table, num_bytes, 0, cb,
745                 client, CY_RQT_INIT_SEND_OBJECT);
746
747 }
748 EXPORT_SYMBOL(cy_as_mtp_init_send_object);
749
750 cy_as_return_status_t
751 cy_as_mtp_init_get_object(cy_as_device_handle handle,
752                                          cy_as_mtp_block_table *blk_table,
753                                          uint32_t num_bytes,
754                                          uint32_t transaction_id,
755                                          cy_as_function_callback cb,
756                                          uint32_t client
757                                         )
758 {
759         cy_as_device *dev_p;
760         dev_p = (cy_as_device *)handle;
761         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
762                 return CY_AS_ERROR_INVALID_HANDLE;
763
764         return cy_as_mtp_operation(dev_p, blk_table, num_bytes,
765                 transaction_id, cb, client, CY_RQT_INIT_GET_OBJECT);
766
767 }
768 EXPORT_SYMBOL(cy_as_mtp_init_get_object);
769
770 static cy_as_return_status_t
771 my_handle_response_cancel_send_object(cy_as_device *dev_p,
772                         cy_as_ll_request_response *req_p,
773                         cy_as_ll_request_response *reply_p,
774                         cy_as_return_status_t ret)
775 {
776         if (ret != CY_AS_ERROR_SUCCESS)
777                 goto destroy;
778
779         if (cy_as_ll_request_response__get_code(reply_p) !=
780                 CY_RESP_SUCCESS_FAILURE) {
781                 ret = CY_AS_ERROR_INVALID_RESPONSE;
782                 goto destroy;
783         }
784
785         ret = cy_as_ll_request_response__get_word(reply_p, 0);
786         if (ret != CY_AS_ERROR_SUCCESS)
787                 goto destroy;
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
794         return ret;
795 }
796
797 cy_as_return_status_t
798 cy_as_mtp_cancel_send_object(cy_as_device_handle handle,
799                                                 cy_as_function_callback cb,
800                                                 uint32_t client
801                                                 )
802 {
803         cy_as_ll_request_response *req_p = 0, *reply_p = 0;
804         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
805         cy_as_device *dev_p;
806
807         dev_p = (cy_as_device *)handle;
808         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
809                 return CY_AS_ERROR_INVALID_HANDLE;
810
811                 if (dev_p->mtp_count == 0)
812                                 return CY_AS_ERROR_NOT_RUNNING;
813
814         /* Create the request to send to the West Bridge device */
815         req_p = cy_as_ll_create_request(dev_p,
816                 CY_RQT_CANCEL_SEND_OBJECT, CY_RQT_TUR_RQT_CONTEXT, 0);
817         if (req_p == 0) {
818                 ret = CY_AS_ERROR_OUT_OF_MEMORY;
819                 goto destroy;
820         }
821
822         /* Reserve space for the reply, the reply data will
823          * not exceed one word */
824         reply_p = cy_as_ll_create_response(dev_p, 1);
825         if (reply_p == 0) {
826                 ret = CY_AS_ERROR_OUT_OF_MEMORY;
827                 goto destroy;
828         }
829
830         if (cb == 0) {
831                 ret = cy_as_ll_send_request_wait_reply(dev_p,
832                         req_p, reply_p);
833                 if (ret != CY_AS_ERROR_SUCCESS)
834                         goto destroy;
835
836                 return my_handle_response_cancel_send_object(dev_p,
837                         req_p, reply_p, ret);
838         } else {
839                 ret = cy_as_misc_send_request(dev_p, cb, client,
840                         CY_FUNCT_CB_MTP_CANCEL_SEND_OBJECT, 0,
841                         dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX,
842                         req_p, reply_p, cy_as_mtp_func_callback);
843
844                 if (ret != CY_AS_ERROR_SUCCESS)
845                         goto destroy;
846
847                 return ret;
848         }
849
850 destroy:
851         cy_as_ll_destroy_request(dev_p, req_p);
852         cy_as_ll_destroy_response(dev_p, reply_p);
853
854         return ret;
855 }
856 EXPORT_SYMBOL(cy_as_mtp_cancel_send_object);
857
858 static cy_as_return_status_t
859 my_handle_response_cancel_get_object(cy_as_device *dev_p,
860                         cy_as_ll_request_response *req_p,
861                         cy_as_ll_request_response *reply_p,
862                         cy_as_return_status_t ret)
863 {
864         if (ret != CY_AS_ERROR_SUCCESS)
865                 goto destroy;
866
867         if (cy_as_ll_request_response__get_code(reply_p) !=
868                 CY_RESP_SUCCESS_FAILURE) {
869                 ret = CY_AS_ERROR_INVALID_RESPONSE;
870                 goto destroy;
871         }
872
873         ret = cy_as_ll_request_response__get_word(reply_p, 0);
874         if (ret != CY_AS_ERROR_SUCCESS)
875                 goto destroy;
876
877
878 destroy:
879         cy_as_ll_destroy_request(dev_p, req_p);
880         cy_as_ll_destroy_response(dev_p, reply_p);
881
882         return ret;
883 }
884
885 cy_as_return_status_t
886 cy_as_mtp_cancel_get_object(cy_as_device_handle handle,
887                                            cy_as_function_callback cb,
888                                            uint32_t client
889                                           )
890 {
891         cy_as_ll_request_response *req_p = 0, *reply_p = 0;
892         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
893         cy_as_device *dev_p;
894
895         dev_p = (cy_as_device *)handle;
896         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
897                 return CY_AS_ERROR_INVALID_HANDLE;
898
899                 if (dev_p->mtp_count == 0)
900                                 return CY_AS_ERROR_NOT_RUNNING;
901
902         /* Create the request to send to the West Bridge device */
903         req_p = cy_as_ll_create_request(dev_p, CY_RQT_CANCEL_GET_OBJECT,
904                 CY_RQT_TUR_RQT_CONTEXT, 0);
905         if (req_p == 0) {
906                 ret = CY_AS_ERROR_OUT_OF_MEMORY;
907                 goto destroy;
908         }
909
910         /* Reserve space for the reply, the reply data will
911          * not exceed one word */
912         reply_p = cy_as_ll_create_response(dev_p, 1);
913         if (reply_p == 0) {
914                 ret = CY_AS_ERROR_OUT_OF_MEMORY;
915                 goto destroy;
916         }
917
918         if (cb == 0) {
919                 ret = cy_as_ll_send_request_wait_reply(dev_p,
920                         req_p, reply_p);
921                 if (ret != CY_AS_ERROR_SUCCESS)
922                         goto destroy;
923
924                 return my_handle_response_cancel_get_object(dev_p,
925                         req_p, reply_p, ret);
926         } else {
927                 ret = cy_as_misc_send_request(dev_p, cb, client,
928                         CY_FUNCT_CB_MTP_CANCEL_GET_OBJECT, 0,
929                         dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX,
930                         req_p, reply_p,  cy_as_mtp_func_callback);
931
932                 if (ret != CY_AS_ERROR_SUCCESS)
933                         goto destroy;
934
935                 return ret;
936         }
937
938 destroy:
939         cy_as_ll_destroy_request(dev_p, req_p);
940         cy_as_ll_destroy_response(dev_p, reply_p);
941
942         return ret;
943 }
944 EXPORT_SYMBOL(cy_as_mtp_cancel_get_object);
945
946 cy_as_return_status_t
947 cy_as_mtp_send_block_table(cy_as_device_handle handle,
948                         cy_as_mtp_block_table *blk_table,
949                         cy_as_function_callback cb,
950                         uint32_t client)
951 {
952         cy_as_device *dev_p;
953         dev_p = (cy_as_device *)handle;
954         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
955                 return CY_AS_ERROR_INVALID_HANDLE;
956
957         return cy_as_mtp_operation(dev_p, blk_table, 0, 0, cb,
958                 client, CY_RQT_SEND_BLOCK_TABLE);
959 }
960
961 static void
962 cy_as_mtp_func_callback(cy_as_device *dev_p,
963                                         uint8_t context,
964                                         cy_as_ll_request_response *rqt,
965                                         cy_as_ll_request_response *resp,
966                                         cy_as_return_status_t stat)
967 {
968         cy_as_func_c_b_node* node = (cy_as_func_c_b_node *)
969                                         dev_p->func_cbs_mtp->head_p;
970         cy_as_return_status_t  ret = CY_AS_ERROR_SUCCESS;
971         uint8_t                  code;
972         cy_bool delay_callback = cy_false;
973
974         cy_as_hal_assert(dev_p->func_cbs_mtp->count != 0);
975         cy_as_hal_assert(dev_p->func_cbs_mtp->type == CYAS_FUNC_CB);
976
977         (void)context;
978
979         /* The Handlers are responsible for Deleting the
980          * rqt and resp when they are finished
981          */
982         code = cy_as_ll_request_response__get_code(rqt);
983         switch (code) {
984         case CY_RQT_START_MTP:
985                 ret = my_handle_response_mtp_start(dev_p, rqt,
986                         resp, stat);
987                 break;
988         case CY_RQT_STOP_MTP:
989                 ret = my_handle_response_mtp_stop(dev_p, rqt,
990                         resp, stat);
991                 break;
992 #if 0
993         case CY_RQT_INIT_SEND_OBJECT:
994                 ret = my_handle_response_init_send_object(dev_p,
995                         rqt, resp, stat, cy_true);
996                 delay_callback = cy_true;
997                 break;
998 #endif
999         case CY_RQT_CANCEL_SEND_OBJECT:
1000                 ret = my_handle_response_cancel_send_object(dev_p,
1001                         rqt, resp, stat);
1002                 break;
1003 #if 0
1004         case CY_RQT_INIT_GET_OBJECT:
1005                 ret = my_handle_response_init_get_object(dev_p,
1006                         rqt, resp, stat, cy_true);
1007                 delay_callback = cy_true;
1008                 break;
1009 #endif
1010         case CY_RQT_CANCEL_GET_OBJECT:
1011                 ret = my_handle_response_cancel_get_object(dev_p,
1012                         rqt, resp, stat);
1013                 break;
1014 #if 0
1015         case CY_RQT_SEND_BLOCK_TABLE:
1016                 ret = my_handle_response_send_block_table(dev_p, rqt,
1017                         resp, stat, cy_true);
1018                 delay_callback = cy_true;
1019                 break;
1020 #endif
1021         case CY_RQT_ENABLE_USB_PATH:
1022                 ret = my_handle_response_no_data(dev_p, rqt, resp);
1023                 if (ret == CY_AS_ERROR_SUCCESS)
1024                         dev_p->is_storage_only_mode = cy_false;
1025                 break;
1026         default:
1027                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1028                 cy_as_hal_assert(cy_false);
1029                 break;
1030         }
1031
1032         /*
1033         * if the low level layer returns a direct error, use the
1034         * corresponding error code. if not, use the error code
1035         * based on the response from firmware.
1036         */
1037         if (stat == CY_AS_ERROR_SUCCESS)
1038                 stat = ret;
1039
1040         if (!delay_callback) {
1041                 node->cb_p((cy_as_device_handle)dev_p, stat, node->client_data,
1042                         node->data_type, node->data);
1043                 cy_as_remove_c_b_node(dev_p->func_cbs_mtp);
1044         }
1045 }
1046
1047 cy_as_return_status_t
1048 cy_as_mtp_storage_only_start(cy_as_device_handle handle)
1049 {
1050         cy_as_device *dev_p = (cy_as_device *)handle;
1051         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1052                 return CY_AS_ERROR_INVALID_HANDLE;
1053
1054         if (!cy_as_device_is_configured(dev_p))
1055                 return CY_AS_ERROR_NOT_CONFIGURED;
1056
1057         if (!cy_as_device_is_firmware_loaded(dev_p))
1058                 return CY_AS_ERROR_NO_FIRMWARE;
1059
1060         if (dev_p->storage_count == 0)
1061                 return CY_AS_ERROR_NOT_RUNNING;
1062
1063         dev_p->is_storage_only_mode = cy_true;
1064         return CY_AS_ERROR_SUCCESS;
1065 }
1066 EXPORT_SYMBOL(cy_as_mtp_storage_only_start);
1067
1068 cy_as_return_status_t
1069 cy_as_mtp_storage_only_stop(cy_as_device_handle handle,
1070                                                 cy_as_function_callback cb,
1071                                                 uint32_t client)
1072 {
1073         cy_as_device *dev_p = (cy_as_device *)handle;
1074         cy_as_ll_request_response *req_p, *reply_p;
1075         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1076
1077         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1078                 return CY_AS_ERROR_INVALID_HANDLE;
1079
1080         if (!cy_as_device_is_configured(dev_p))
1081                 return CY_AS_ERROR_NOT_CONFIGURED;
1082
1083         if (!cy_as_device_is_firmware_loaded(dev_p))
1084                 return CY_AS_ERROR_NO_FIRMWARE;
1085
1086         if (dev_p->storage_count == 0)
1087                 return CY_AS_ERROR_NOT_RUNNING;
1088
1089         if (dev_p->is_storage_only_mode == cy_false)
1090                 return CY_AS_ERROR_SUCCESS;
1091
1092         if (cy_as_device_is_in_callback(dev_p))
1093                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1094
1095         req_p = cy_as_ll_create_request(dev_p,
1096                 CY_RQT_ENABLE_USB_PATH, CY_RQT_TUR_RQT_CONTEXT, 1);
1097         if (req_p == 0)
1098                 return CY_AS_ERROR_OUT_OF_MEMORY;
1099
1100         reply_p = cy_as_ll_create_response(dev_p, 1);
1101         if (reply_p == 0) {
1102                 cy_as_ll_destroy_request(dev_p, req_p);
1103                 return CY_AS_ERROR_OUT_OF_MEMORY;
1104         }
1105
1106         if (cb == 0) {
1107                 ret = cy_as_ll_send_request_wait_reply(dev_p,
1108                         req_p, reply_p);
1109                 if (ret != CY_AS_ERROR_SUCCESS)
1110                         goto destroy;
1111
1112                 ret = my_handle_response_no_data(dev_p, req_p,
1113                         reply_p);
1114                 if (ret == CY_AS_ERROR_SUCCESS)
1115                         dev_p->is_storage_only_mode = cy_false;
1116                 return ret;
1117         } else {
1118                 ret = cy_as_misc_send_request(dev_p, cb, client,
1119                         CY_FUNCT_CB_MTP_STOP_STORAGE_ONLY, 0,
1120                         dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX,
1121                         req_p, reply_p, cy_as_mtp_func_callback);
1122
1123                 if (ret != CY_AS_ERROR_SUCCESS)
1124                         goto destroy;
1125
1126                 return ret;
1127         }
1128
1129 destroy:
1130         cy_as_ll_destroy_request(dev_p, req_p);
1131         cy_as_ll_destroy_response(dev_p, reply_p);
1132
1133         return ret;
1134 }
1135 EXPORT_SYMBOL(cy_as_mtp_storage_only_stop);
1136