linux/drivers/staging/westbridge/astoria/api/src/cyasmtp.c
<<
>>
Prefs
   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
  28static void
  29cy_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
  35static cy_as_return_status_t
  36is_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
  53static void
  54my_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
 230static cy_as_return_status_t
 231my_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
 245destroy:
 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
 252static cy_as_return_status_t
 253my_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
 290destroy:
 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
 304cy_as_return_status_t
 305cy_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 becuase 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
 392destroy:
 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
 406static cy_as_return_status_t
 407my_handle_response_mtp_stop(cy_as_device *dev_p,
 408                        cy_as_ll_request_response *req_p,
 409                        cy_as_ll_request_response *reply_p,
 410                        cy_as_return_status_t ret)
 411{
 412        if (ret != CY_AS_ERROR_SUCCESS)
 413                goto destroy;
 414
 415        if (cy_as_ll_request_response__get_code(reply_p) !=
 416                CY_RESP_SUCCESS_FAILURE) {
 417                ret = CY_AS_ERROR_INVALID_RESPONSE;
 418                goto destroy;
 419        }
 420
 421        ret = cy_as_ll_request_response__get_word(reply_p, 0);
 422        if (ret != CY_AS_ERROR_SUCCESS)
 423                goto destroy;
 424
 425        /*
 426        * we sucessfully shutdown the stack, so decrement
 427        * to make the count zero.
 428        */
 429        dev_p->mtp_count--;
 430
 431destroy:
 432        cy_as_ll_destroy_request(dev_p, req_p);
 433        cy_as_ll_destroy_response(dev_p, reply_p);
 434
 435        if (ret != CY_AS_ERROR_SUCCESS)
 436                cy_as_ll_register_request_callback(dev_p,
 437                        CY_RQT_TUR_RQT_CONTEXT, 0);
 438
 439        cy_as_device_clear_m_s_s_pending(dev_p);
 440
 441        return ret;
 442}
 443
 444cy_as_return_status_t
 445cy_as_mtp_stop(cy_as_device_handle handle,
 446                        cy_as_function_callback cb,
 447                        uint32_t client
 448                        )
 449{
 450        cy_as_ll_request_response *req_p = 0, *reply_p = 0;
 451        cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
 452
 453        cy_as_device *dev_p;
 454
 455        cy_as_log_debug_message(6, "cy_as_mtp_stop called");
 456
 457        dev_p = (cy_as_device *)handle;
 458        if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
 459                return CY_AS_ERROR_INVALID_HANDLE;
 460
 461        ret = is_mtp_active(dev_p);
 462        if (ret != CY_AS_ERROR_SUCCESS)
 463                return ret;
 464
 465        if (cy_as_device_is_in_callback(dev_p))
 466                return CY_AS_ERROR_INVALID_IN_CALLBACK;
 467
 468        if (cy_as_device_is_m_s_s_pending(dev_p))
 469                return CY_AS_ERROR_STARTSTOP_PENDING;
 470
 471        cy_as_device_set_m_s_s_pending(dev_p);
 472
 473        if (dev_p->mtp_count == 1) {
 474                /* Create the request to send to the West
 475                 * Bridge device */
 476                req_p = cy_as_ll_create_request(dev_p, CY_RQT_STOP_MTP,
 477                        CY_RQT_TUR_RQT_CONTEXT, 0);
 478                if (req_p == 0) {
 479                        ret = CY_AS_ERROR_OUT_OF_MEMORY;
 480                        goto destroy;
 481                }
 482
 483                /* Reserve space for the reply, the reply data will
 484                 * not exceed one word */
 485                reply_p = cy_as_ll_create_response(dev_p, 1);
 486                if (reply_p == 0) {
 487                        ret = CY_AS_ERROR_OUT_OF_MEMORY;
 488                        goto destroy;
 489                }
 490
 491                if (cb == 0) {
 492                        ret = cy_as_ll_send_request_wait_reply(dev_p,
 493                                req_p, reply_p);
 494                        if (ret != CY_AS_ERROR_SUCCESS)
 495                                goto destroy;
 496
 497                        return my_handle_response_mtp_stop(dev_p, req_p,
 498                                        reply_p, ret);
 499                } else {
 500                        ret = cy_as_misc_send_request(dev_p, cb, client,
 501                                CY_FUNCT_CB_MTP_STOP, 0, dev_p->func_cbs_mtp,
 502                                CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
 503                                cy_as_mtp_func_callback);
 504
 505                        if (ret != CY_AS_ERROR_SUCCESS)
 506                                goto destroy;
 507
 508                        return ret;
 509                }
 510
 511destroy:
 512                cy_as_ll_destroy_request(dev_p, req_p);
 513                cy_as_ll_destroy_response(dev_p, reply_p);
 514        } else if (dev_p->mtp_count > 1) {
 515
 516                dev_p->mtp_count--;
 517
 518                if (cb)
 519                        cb(handle, ret, client, CY_FUNCT_CB_MTP_STOP, 0);
 520        }
 521
 522        cy_as_device_clear_m_s_s_pending(dev_p);
 523
 524        return ret;
 525}
 526
 527static void
 528mtp_write_callback(
 529                cy_as_device *dev_p,
 530                uint8_t context,
 531                cy_as_ll_request_response *rqt,
 532                cy_as_ll_request_response *resp,
 533                cy_as_return_status_t ret)
 534{
 535        cy_as_hal_assert(context == CY_RQT_TUR_RQT_CONTEXT);
 536
 537        if (ret == CY_AS_ERROR_SUCCESS) {
 538                if (cy_as_ll_request_response__get_code(resp) !=
 539                        CY_RESP_SUCCESS_FAILURE)
 540                        ret = CY_AS_ERROR_INVALID_RESPONSE;
 541                else
 542                        ret = cy_as_ll_request_response__get_word(resp, 0);
 543        }
 544
 545        if (ret != CY_AS_ERROR_SUCCESS) {
 546                /* Firmware failed the request. Cancel the DMA transfer. */
 547                cy_as_dma_cancel(dev_p, 0x04, CY_AS_ERROR_CANCELED);
 548                cy_as_device_clear_storage_async_pending(dev_p);
 549        }
 550
 551        cy_as_ll_destroy_response(dev_p, resp);
 552        cy_as_ll_destroy_request(dev_p, rqt);
 553}
 554
 555static void
 556async_write_request_callback(cy_as_device *dev_p,
 557        cy_as_end_point_number_t ep, void *buf_p, uint32_t size,
 558        cy_as_return_status_t err)
 559{
 560        cy_as_device_handle h;
 561        cy_as_function_callback cb;
 562
 563        (void)size;
 564        (void)buf_p;
 565        (void)ep;
 566
 567
 568        cy_as_log_debug_message(6, "async_write_request_callback called");
 569
 570        h = (cy_as_device_handle)dev_p;
 571
 572        cb = dev_p->mtp_cb;
 573        dev_p->mtp_cb = 0;
 574
 575        cy_as_device_clear_storage_async_pending(dev_p);
 576
 577        if (cb)
 578                cb(h, err, dev_p->mtp_client, dev_p->mtp_op, 0);
 579
 580}
 581
 582static void
 583sync_mtp_callback(cy_as_device *dev_p, cy_as_end_point_number_t ep,
 584        void *buf_p, uint32_t size, cy_as_return_status_t err)
 585{
 586        (void)ep;
 587        (void)buf_p;
 588        (void)size;
 589
 590        dev_p->mtp_error = err;
 591}
 592
 593static cy_as_return_status_t
 594cy_as_mtp_operation(cy_as_device *dev_p,
 595                                 cy_as_mtp_block_table *blk_table,
 596                                 uint32_t num_bytes,
 597                                 uint32_t transaction_id,
 598                                 cy_as_function_callback cb,
 599                                 uint32_t client,
 600                                 uint8_t rqttype
 601                                )
 602{
 603        cy_as_ll_request_response *req_p = 0, *reply_p = 0;
 604        cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
 605        uint32_t mask = 0;
 606        cy_as_funct_c_b_type mtp_cb_op = 0;
 607        uint16_t size = 2;
 608
 609        if (dev_p->mtp_count == 0)
 610                return CY_AS_ERROR_NOT_RUNNING;
 611
 612        if (rqttype == CY_RQT_INIT_SEND_OBJECT) {
 613                mtp_cb_op = CY_FUNCT_CB_MTP_INIT_SEND_OBJECT;
 614                dev_p->mtp_turbo_active = cy_true;
 615        } else if (rqttype == CY_RQT_INIT_GET_OBJECT) {
 616                mtp_cb_op = CY_FUNCT_CB_MTP_INIT_GET_OBJECT;
 617                dev_p->mtp_turbo_active = cy_true;
 618        } else
 619                mtp_cb_op = CY_FUNCT_CB_MTP_SEND_BLOCK_TABLE;
 620
 621        ret = is_mtp_active(dev_p);
 622        if (ret != CY_AS_ERROR_SUCCESS)
 623                return ret;
 624
 625        if (CY_RQT_INIT_GET_OBJECT == rqttype)
 626                size = 4;
 627
 628        /* Create the request to send to the West
 629         * Bridge device */
 630        req_p = cy_as_ll_create_request(dev_p, rqttype,
 631                CY_RQT_TUR_RQT_CONTEXT, size);
 632        if (req_p == 0) {
 633                ret = CY_AS_ERROR_OUT_OF_MEMORY;
 634                goto destroy;
 635        }
 636
 637        /* Reserve space for the reply, the reply data will
 638         * not exceed one word */
 639        reply_p = cy_as_ll_create_response(dev_p, 1);
 640        if (reply_p == 0) {
 641                ret = CY_AS_ERROR_OUT_OF_MEMORY;
 642                goto destroy;
 643        }
 644
 645        cy_as_ll_request_response__set_word(req_p, 0,
 646                (uint16_t)(num_bytes & 0xFFFF));
 647        cy_as_ll_request_response__set_word(req_p, 1,
 648                (uint16_t)((num_bytes >> 16) & 0xFFFF));
 649
 650        /* If it is GET_OBJECT, send transaction id as well*/
 651        if (CY_RQT_INIT_GET_OBJECT == rqttype) {
 652                cy_as_ll_request_response__set_word(req_p, 2,
 653                        (uint16_t)(transaction_id & 0xFFFF));
 654                cy_as_ll_request_response__set_word(req_p, 3,
 655                        (uint16_t)((transaction_id >> 16) & 0xFFFF));
 656        }
 657
 658        if (cb == 0) {
 659                /* Queue the DMA request for block table write */
 660                ret = cy_as_dma_queue_request(dev_p, 4, blk_table,
 661                        sizeof(cy_as_mtp_block_table), cy_false,
 662                        cy_false, sync_mtp_callback);
 663
 664                ret = cy_as_ll_send_request_wait_reply(dev_p,
 665                        req_p, reply_p);
 666                if (ret != CY_AS_ERROR_SUCCESS) {
 667                        cy_as_dma_cancel(dev_p, 4, CY_AS_ERROR_CANCELED);
 668                        cy_as_device_clear_storage_async_pending(dev_p);
 669
 670                        goto destroy;
 671                }
 672
 673                ret = cy_as_dma_drain_queue(dev_p, 4, cy_true);
 674                if (ret != CY_AS_ERROR_SUCCESS)
 675                        goto destroy;
 676
 677                ret = dev_p->mtp_error;
 678                goto destroy;
 679        } else {
 680#if 0
 681                ret = cy_as_misc_send_request(dev_p, cb, client,
 682                        CY_FUNCT_CB_MTP_INIT_SEND_OBJECT,
 683                        0, dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX,
 684                        req_p, reply_p, cy_as_mtp_func_callback);
 685
 686                if (ret != CY_AS_ERROR_SUCCESS)
 687                        goto destroy;
 688#endif
 689
 690                /* Protection from interrupt driven code */
 691                /* since we are using storage EP4 check if any
 692                 * storage activity is pending */
 693                mask = cy_as_hal_disable_interrupts();
 694                if ((cy_as_device_is_storage_async_pending(dev_p)) ||
 695                        (dev_p->storage_wait)) {
 696                        cy_as_hal_enable_interrupts(mask);
 697                        return CY_AS_ERROR_ASYNC_PENDING;
 698                }
 699                cy_as_device_set_storage_async_pending(dev_p);
 700                cy_as_hal_enable_interrupts(mask);
 701
 702                dev_p->mtp_cb    = cb;
 703                dev_p->mtp_client = client;
 704                dev_p->mtp_op    = mtp_cb_op;
 705
 706                ret = cy_as_ll_send_request(dev_p, req_p, reply_p,
 707                        cy_false, mtp_write_callback);
 708                if (ret != CY_AS_ERROR_SUCCESS)
 709                        goto destroy;
 710
 711                ret = cy_as_dma_queue_request(dev_p, 4, blk_table,
 712                        sizeof(cy_as_mtp_block_table), cy_false, cy_false,
 713                        async_write_request_callback);
 714                if (ret != CY_AS_ERROR_SUCCESS)
 715                        return ret;
 716
 717                /* Kick start the queue if it is not running */
 718                cy_as_dma_kick_start(dev_p, 4);
 719
 720                return CY_AS_ERROR_SUCCESS;
 721        }
 722
 723destroy:
 724        cy_as_ll_destroy_request(dev_p, req_p);
 725        cy_as_ll_destroy_response(dev_p, reply_p);
 726
 727        return ret;
 728}
 729
 730cy_as_return_status_t
 731cy_as_mtp_init_send_object(cy_as_device_handle handle,
 732                                          cy_as_mtp_block_table *blk_table,
 733                                          uint32_t num_bytes,
 734                                          cy_as_function_callback cb,
 735                                          uint32_t client
 736                                         )
 737{
 738        cy_as_device *dev_p;
 739        dev_p = (cy_as_device *)handle;
 740        if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
 741                return CY_AS_ERROR_INVALID_HANDLE;
 742
 743        return cy_as_mtp_operation(dev_p, blk_table, num_bytes, 0, cb,
 744                client, CY_RQT_INIT_SEND_OBJECT);
 745
 746}
 747
 748cy_as_return_status_t
 749cy_as_mtp_init_get_object(cy_as_device_handle handle,
 750                                         cy_as_mtp_block_table *blk_table,
 751                                         uint32_t num_bytes,
 752                                         uint32_t transaction_id,
 753                                         cy_as_function_callback cb,
 754                                         uint32_t client
 755                                        )
 756{
 757        cy_as_device *dev_p;
 758        dev_p = (cy_as_device *)handle;
 759        if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
 760                return CY_AS_ERROR_INVALID_HANDLE;
 761
 762        return cy_as_mtp_operation(dev_p, blk_table, num_bytes,
 763                transaction_id, cb, client, CY_RQT_INIT_GET_OBJECT);
 764
 765}
 766
 767static cy_as_return_status_t
 768my_handle_response_cancel_send_object(cy_as_device *dev_p,
 769                        cy_as_ll_request_response *req_p,
 770                        cy_as_ll_request_response *reply_p,
 771                        cy_as_return_status_t ret)
 772{
 773        if (ret != CY_AS_ERROR_SUCCESS)
 774                goto destroy;
 775
 776        if (cy_as_ll_request_response__get_code(reply_p) !=
 777                CY_RESP_SUCCESS_FAILURE) {
 778                ret = CY_AS_ERROR_INVALID_RESPONSE;
 779                goto destroy;
 780        }
 781
 782        ret = cy_as_ll_request_response__get_word(reply_p, 0);
 783        if (ret != CY_AS_ERROR_SUCCESS)
 784                goto destroy;
 785
 786
 787destroy:
 788        cy_as_ll_destroy_request(dev_p, req_p);
 789        cy_as_ll_destroy_response(dev_p, reply_p);
 790
 791        return ret;
 792}
 793
 794cy_as_return_status_t
 795cy_as_mtp_cancel_send_object(cy_as_device_handle handle,
 796                                                cy_as_function_callback cb,
 797                                                uint32_t client
 798                                                )
 799{
 800        cy_as_ll_request_response *req_p = 0, *reply_p = 0;
 801        cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
 802        cy_as_device *dev_p;
 803
 804        dev_p = (cy_as_device *)handle;
 805        if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
 806                return CY_AS_ERROR_INVALID_HANDLE;
 807
 808                if (dev_p->mtp_count == 0)
 809                                return CY_AS_ERROR_NOT_RUNNING;
 810
 811        /* Create the request to send to the West Bridge device */
 812        req_p = cy_as_ll_create_request(dev_p,
 813                CY_RQT_CANCEL_SEND_OBJECT, CY_RQT_TUR_RQT_CONTEXT, 0);
 814        if (req_p == 0) {
 815                ret = CY_AS_ERROR_OUT_OF_MEMORY;
 816                goto destroy;
 817        }
 818
 819        /* Reserve space for the reply, the reply data will
 820         * not exceed one word */
 821        reply_p = cy_as_ll_create_response(dev_p, 1);
 822        if (reply_p == 0) {
 823                ret = CY_AS_ERROR_OUT_OF_MEMORY;
 824                goto destroy;
 825        }
 826
 827        if (cb == 0) {
 828                ret = cy_as_ll_send_request_wait_reply(dev_p,
 829                        req_p, reply_p);
 830                if (ret != CY_AS_ERROR_SUCCESS)
 831                        goto destroy;
 832
 833                return my_handle_response_cancel_send_object(dev_p,
 834                        req_p, reply_p, ret);
 835        } else {
 836                ret = cy_as_misc_send_request(dev_p, cb, client,
 837                        CY_FUNCT_CB_MTP_CANCEL_SEND_OBJECT, 0,
 838                        dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX,
 839                        req_p, reply_p, cy_as_mtp_func_callback);
 840
 841                if (ret != CY_AS_ERROR_SUCCESS)
 842                        goto destroy;
 843
 844                return ret;
 845        }
 846
 847destroy:
 848        cy_as_ll_destroy_request(dev_p, req_p);
 849        cy_as_ll_destroy_response(dev_p, reply_p);
 850
 851        return ret;
 852}
 853
 854static cy_as_return_status_t
 855my_handle_response_cancel_get_object(cy_as_device *dev_p,
 856                        cy_as_ll_request_response *req_p,
 857                        cy_as_ll_request_response *reply_p,
 858                        cy_as_return_status_t ret)
 859{
 860        if (ret != CY_AS_ERROR_SUCCESS)
 861                goto destroy;
 862
 863        if (cy_as_ll_request_response__get_code(reply_p) !=
 864                CY_RESP_SUCCESS_FAILURE) {
 865                ret = CY_AS_ERROR_INVALID_RESPONSE;
 866                goto destroy;
 867        }
 868
 869        ret = cy_as_ll_request_response__get_word(reply_p, 0);
 870        if (ret != CY_AS_ERROR_SUCCESS)
 871                goto destroy;
 872
 873
 874destroy:
 875        cy_as_ll_destroy_request(dev_p, req_p);
 876        cy_as_ll_destroy_response(dev_p, reply_p);
 877
 878        return ret;
 879}
 880
 881cy_as_return_status_t
 882cy_as_mtp_cancel_get_object(cy_as_device_handle handle,
 883                                           cy_as_function_callback cb,
 884                                           uint32_t client
 885                                          )
 886{
 887        cy_as_ll_request_response *req_p = 0, *reply_p = 0;
 888        cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
 889        cy_as_device *dev_p;
 890
 891        dev_p = (cy_as_device *)handle;
 892        if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
 893                return CY_AS_ERROR_INVALID_HANDLE;
 894
 895                if (dev_p->mtp_count == 0)
 896                                return CY_AS_ERROR_NOT_RUNNING;
 897
 898        /* Create the request to send to the West Bridge device */
 899        req_p = cy_as_ll_create_request(dev_p, CY_RQT_CANCEL_GET_OBJECT,
 900                CY_RQT_TUR_RQT_CONTEXT, 0);
 901        if (req_p == 0) {
 902                ret = CY_AS_ERROR_OUT_OF_MEMORY;
 903                goto destroy;
 904        }
 905
 906        /* Reserve space for the reply, the reply data will
 907         * not exceed one word */
 908        reply_p = cy_as_ll_create_response(dev_p, 1);
 909        if (reply_p == 0) {
 910                ret = CY_AS_ERROR_OUT_OF_MEMORY;
 911                goto destroy;
 912        }
 913
 914        if (cb == 0) {
 915                ret = cy_as_ll_send_request_wait_reply(dev_p,
 916                        req_p, reply_p);
 917                if (ret != CY_AS_ERROR_SUCCESS)
 918                        goto destroy;
 919
 920                return my_handle_response_cancel_get_object(dev_p,
 921                        req_p, reply_p, ret);
 922        } else {
 923                ret = cy_as_misc_send_request(dev_p, cb, client,
 924                        CY_FUNCT_CB_MTP_CANCEL_GET_OBJECT, 0,
 925                        dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX,
 926                        req_p, reply_p,  cy_as_mtp_func_callback);
 927
 928                if (ret != CY_AS_ERROR_SUCCESS)
 929                        goto destroy;
 930
 931                return ret;
 932        }
 933
 934destroy:
 935        cy_as_ll_destroy_request(dev_p, req_p);
 936        cy_as_ll_destroy_response(dev_p, reply_p);
 937
 938        return ret;
 939}
 940
 941cy_as_return_status_t
 942cy_as_mtp_send_block_table(cy_as_device_handle handle,
 943                        cy_as_mtp_block_table *blk_table,
 944                        cy_as_function_callback cb,
 945                        uint32_t client)
 946{
 947        cy_as_device *dev_p;
 948        dev_p = (cy_as_device *)handle;
 949        if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
 950                return CY_AS_ERROR_INVALID_HANDLE;
 951
 952        return cy_as_mtp_operation(dev_p, blk_table, 0, 0, cb,
 953                client, CY_RQT_SEND_BLOCK_TABLE);
 954}
 955
 956static void
 957cy_as_mtp_func_callback(cy_as_device *dev_p,
 958                                        uint8_t context,
 959                                        cy_as_ll_request_response *rqt,
 960                                        cy_as_ll_request_response *resp,
 961                                        cy_as_return_status_t stat)
 962{
 963        cy_as_func_c_b_node* node = (cy_as_func_c_b_node *)
 964                                        dev_p->func_cbs_mtp->head_p;
 965        cy_as_return_status_t  ret = CY_AS_ERROR_SUCCESS;
 966        uint8_t                  code;
 967        cy_bool delay_callback = cy_false;
 968
 969        cy_as_hal_assert(dev_p->func_cbs_mtp->count != 0);
 970        cy_as_hal_assert(dev_p->func_cbs_mtp->type == CYAS_FUNC_CB);
 971
 972        (void)context;
 973
 974        /* The Handlers are responsible for Deleting the
 975         * rqt and resp when they are finished
 976         */
 977        code = cy_as_ll_request_response__get_code(rqt);
 978        switch (code) {
 979        case CY_RQT_START_MTP:
 980                ret = my_handle_response_mtp_start(dev_p, rqt,
 981                        resp, stat);
 982                break;
 983        case CY_RQT_STOP_MTP:
 984                ret = my_handle_response_mtp_stop(dev_p, rqt,
 985                        resp, stat);
 986                break;
 987#if 0
 988        case CY_RQT_INIT_SEND_OBJECT:
 989                ret = my_handle_response_init_send_object(dev_p,
 990                        rqt, resp, stat, cy_true);
 991                delay_callback = cy_true;
 992                break;
 993#endif
 994        case CY_RQT_CANCEL_SEND_OBJECT:
 995                ret = my_handle_response_cancel_send_object(dev_p,
 996                        rqt, resp, stat);
 997                break;
 998#if 0
 999        case CY_RQT_INIT_GET_OBJECT:
1000                ret = my_handle_response_init_get_object(dev_p,
1001                        rqt, resp, stat, cy_true);
1002                delay_callback = cy_true;
1003                break;
1004#endif
1005        case CY_RQT_CANCEL_GET_OBJECT:
1006                ret = my_handle_response_cancel_get_object(dev_p,
1007                        rqt, resp, stat);
1008                break;
1009#if 0
1010        case CY_RQT_SEND_BLOCK_TABLE:
1011                ret = my_handle_response_send_block_table(dev_p, rqt,
1012                        resp, stat, cy_true);
1013                delay_callback = cy_true;
1014                break;
1015#endif
1016        case CY_RQT_ENABLE_USB_PATH:
1017                ret = my_handle_response_no_data(dev_p, rqt, resp);
1018                if (ret == CY_AS_ERROR_SUCCESS)
1019                        dev_p->is_storage_only_mode = cy_false;
1020                break;
1021        default:
1022                ret = CY_AS_ERROR_INVALID_RESPONSE;
1023                cy_as_hal_assert(cy_false);
1024                break;
1025        }
1026
1027        /*
1028        * if the low level layer returns a direct error, use the
1029        * corresponding error code. if not, use the error code
1030        * based on the response from firmware.
1031        */
1032        if (stat == CY_AS_ERROR_SUCCESS)
1033                stat = ret;
1034
1035        if (!delay_callback) {
1036                node->cb_p((cy_as_device_handle)dev_p, stat, node->client_data,
1037                        node->data_type, node->data);
1038                cy_as_remove_c_b_node(dev_p->func_cbs_mtp);
1039        }
1040}
1041
1042cy_as_return_status_t
1043cy_as_mtp_storage_only_start(cy_as_device_handle handle)
1044{
1045        cy_as_device *dev_p = (cy_as_device *)handle;
1046        if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1047                return CY_AS_ERROR_INVALID_HANDLE;
1048
1049        if (!cy_as_device_is_configured(dev_p))
1050                return CY_AS_ERROR_NOT_CONFIGURED;
1051
1052        if (!cy_as_device_is_firmware_loaded(dev_p))
1053                return CY_AS_ERROR_NO_FIRMWARE;
1054
1055        if (dev_p->storage_count == 0)
1056                return CY_AS_ERROR_NOT_RUNNING;
1057
1058        dev_p->is_storage_only_mode = cy_true;
1059        return CY_AS_ERROR_SUCCESS;
1060}
1061
1062cy_as_return_status_t
1063cy_as_mtp_storage_only_stop(cy_as_device_handle handle,
1064                                                cy_as_function_callback cb,
1065                                                uint32_t client)
1066{
1067        cy_as_device *dev_p = (cy_as_device *)handle;
1068        cy_as_ll_request_response *req_p, *reply_p;
1069        cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1070
1071        if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
1072                return CY_AS_ERROR_INVALID_HANDLE;
1073
1074        if (!cy_as_device_is_configured(dev_p))
1075                return CY_AS_ERROR_NOT_CONFIGURED;
1076
1077        if (!cy_as_device_is_firmware_loaded(dev_p))
1078                return CY_AS_ERROR_NO_FIRMWARE;
1079
1080        if (dev_p->storage_count == 0)
1081                return CY_AS_ERROR_NOT_RUNNING;
1082
1083        if (dev_p->is_storage_only_mode == cy_false)
1084                return CY_AS_ERROR_SUCCESS;
1085
1086        if (cy_as_device_is_in_callback(dev_p))
1087                return CY_AS_ERROR_INVALID_IN_CALLBACK;
1088
1089        req_p = cy_as_ll_create_request(dev_p,
1090                CY_RQT_ENABLE_USB_PATH, CY_RQT_TUR_RQT_CONTEXT, 1);
1091        if (req_p == 0)
1092                return CY_AS_ERROR_OUT_OF_MEMORY;
1093
1094        reply_p = cy_as_ll_create_response(dev_p, 1);
1095        if (reply_p == 0) {
1096                cy_as_ll_destroy_request(dev_p, req_p);
1097                return CY_AS_ERROR_OUT_OF_MEMORY;
1098        }
1099
1100        if (cb == 0) {
1101                ret = cy_as_ll_send_request_wait_reply(dev_p,
1102                        req_p, reply_p);
1103                if (ret != CY_AS_ERROR_SUCCESS)
1104                        goto destroy;
1105
1106                ret = my_handle_response_no_data(dev_p, req_p,
1107                        reply_p);
1108                if (ret == CY_AS_ERROR_SUCCESS)
1109                        dev_p->is_storage_only_mode = cy_false;
1110                return ret;
1111        } else {
1112                ret = cy_as_misc_send_request(dev_p, cb, client,
1113                        CY_FUNCT_CB_MTP_STOP_STORAGE_ONLY, 0,
1114                        dev_p->func_cbs_mtp, CY_AS_REQUEST_RESPONSE_EX,
1115                        req_p, reply_p, cy_as_mtp_func_callback);
1116
1117                if (ret != CY_AS_ERROR_SUCCESS)
1118                        goto destroy;
1119
1120                return ret;
1121        }
1122
1123destroy:
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