Remove the execution flag from non-executables
[platform/core/connectivity/mtp-responder.git] / src / transport / mtp_usb_driver_ffs.c
1 /* -*- mode: C; c-file-style: "linux" -*-
2  *
3  * mtp-responder
4  *
5  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
6  * PROPRIETARY/CONFIDENTIAL
7  *
8  * This software is the confidential and proprietary information of
9  * SAMSUNG ELECTRONICS ("Confidential Information"). You agree and acknowledge
10  * that this software is owned by Samsung and you shall not disclose
11  * such Confidential Information and shall use it only in accordance with
12  * the terms of the license agreement you entered into with SAMSUNG ELECTRONICS.
13  * SAMSUNG make no representations or warranties about the suitability of
14  * the software, either express or implied, including but not limited to
15  * the implied warranties of merchantability, fitness for a particular purpose,
16  * or non-infringement. SAMSUNG shall not be liable for any damages suffered by
17  * licensee arising out of or related to this software.
18  */
19
20 #define _GNU_SOURCE
21 #include <sys/ioctl.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include <glib.h>
26 #include "mtp_usb_driver.h"
27 #include "mtp_device.h"
28 #include "mtp_descs_strings.h"
29 #include "ptp_datacodes.h"
30 #include "mtp_support.h"
31 #include "ptp_container.h"
32 #include "mtp_msgq.h"
33 #include "mtp_thread.h"
34 #include "mtp_transport.h"
35 #include "mtp_event_handler.h"
36 #include "mtp_init.h"
37 #include <sys/prctl.h>
38 #include <systemd/sd-daemon.h>
39
40 /*
41  * GLOBAL AND EXTERN VARIABLES
42  */
43 extern mtp_config_t g_conf;
44
45 /*
46  * STATIC VARIABLES AND FUNCTIONS
47  */
48
49 /*PIMA15740-2000 spec*/
50 #define USB_PTPREQUEST_CANCELIO   0x64    /* Cancel request */
51 #define USB_PTPREQUEST_GETEVENT   0x65    /* Get extened event data */
52 #define USB_PTPREQUEST_RESET      0x66    /* Reset Device */
53 #define USB_PTPREQUEST_GETSTATUS  0x67    /* Get Device Status */
54 #define USB_PTPREQUEST_CANCELIO_SIZE 6
55 #define USB_PTPREQUEST_GETSTATUS_SIZE 12
56
57 static mtp_int32 g_usb_ep0 = -1;       /* read (g_usb_ep0, ...) */
58 static mtp_int32 g_usb_ep_in = -1;     /* write (g_usb_ep_in, ...) */
59 static mtp_int32 g_usb_ep_out = -1;    /* read (g_usb_ep_out, ...) */
60 static mtp_int32 g_usb_ep_status = -1; /* write (g_usb_ep_status, ...) */
61
62 static mtp_max_pkt_size_t pkt_size;
63 static mtp_uint32 rx_mq_sz;
64 static mtp_uint32 tx_mq_sz;
65 static mtp_int32 __handle_usb_read_err(mtp_int32 err,
66                 mtp_uchar *buf, mtp_int32 buf_len);
67 static void __clean_up_msg_queue(void *param);
68 static void __handle_control_request(mtp_int32 request);
69
70 /*
71  * FUNCTIONS
72  */
73
74 /* LCOV_EXCL_START */
75 static mtp_bool __io_init()
76 {
77         int ret;
78
79         if (sd_listen_fds(0) >= 4) {
80                 DBG("socket-activated");
81                 g_usb_ep0 = SD_LISTEN_FDS_START;
82                 g_usb_ep_in = SD_LISTEN_FDS_START + 1;
83                 g_usb_ep_out = SD_LISTEN_FDS_START + 2;
84                 g_usb_ep_status = SD_LISTEN_FDS_START + 3;
85
86                 return TRUE;
87         }
88
89         g_usb_ep0 = open(MTP_EP0_PATH, O_RDWR);
90         if (g_usb_ep0 < 0)
91                 goto out;
92
93         DBG("Writing USB descriptors");
94         ret = write(g_usb_ep0, &descriptors, sizeof(descriptors));
95         if (ret < 0) {
96                 ERR("Error writing descriptors");
97                 goto cleanup;
98         }
99
100         DBG("Writing USB strings");
101         ret = write(g_usb_ep0, &strings, sizeof(strings));
102         if (ret < 0) {
103                 ERR("Error writing strings");
104                 goto cleanup;
105         }
106
107         g_usb_ep_in = open(MTP_EP_IN_PATH, O_RDWR);
108         if (g_usb_ep_in < 0) {
109                 ERR("Error opening bulk-in");
110                 goto cleanup;
111         }
112
113         g_usb_ep_out = open(MTP_EP_OUT_PATH, O_RDWR);
114         if (g_usb_ep_out < 0) {
115                 ERR("Error opening bulk-out");
116                 goto cleanup_in;
117         }
118
119         g_usb_ep_status = open(MTP_EP_STATUS_PATH, O_RDWR);
120         if (g_usb_ep_status < 0) {
121                 ERR("Error opening status");
122                 goto cleanup_out;
123         }
124
125         return TRUE;
126
127 cleanup_out:
128         close(g_usb_ep_out);
129 cleanup_in:
130         close(g_usb_ep_in);
131 cleanup:
132         close(g_usb_ep0);
133 out:
134         return FALSE;
135 }
136
137 static mtp_bool ffs_transport_init_usb_device(void)
138 {
139         mtp_int32 status = 0;
140         int msg_size;
141
142         if (g_usb_ep0 > 0) {
143                 DBG("Device Already open\n");
144                 return TRUE;
145         }
146
147         status = __io_init();
148         if (!status) {
149                 char error[256];
150                 ERR("Device node [%s] open failed, errno [%s]\n",
151                     MTP_EP0_PATH, strerror_r(errno, error, sizeof(error)));
152                 return FALSE;
153         }
154
155         pkt_size.rx = g_conf.read_usb_size;
156         pkt_size.tx = g_conf.write_usb_size;
157
158         DBG("Final : Tx pkt size:[%u], Rx pkt size:[%u]\n", pkt_size.tx, pkt_size.rx);
159
160         msg_size = sizeof(msgq_ptr_t) - sizeof(long);
161         rx_mq_sz = (g_conf.max_io_buf_size / g_conf.max_rx_ipc_size) * msg_size;
162         tx_mq_sz = (g_conf.max_io_buf_size / g_conf.max_tx_ipc_size) * msg_size;
163
164         DBG("RX MQ size :[%u], TX MQ size:[%u]\n", rx_mq_sz, tx_mq_sz);
165
166         return TRUE;
167 }
168
169 static void ffs_transport_deinit_usb_device(void)
170 {
171         if (g_usb_ep0 >= 0)
172                 close(g_usb_ep0);
173         g_usb_ep0 = -1;
174
175         if (g_usb_ep_in >= 0)
176                 close(g_usb_ep_in);
177         g_usb_ep_in = -1;
178
179         if (g_usb_ep_out >= 0)
180                 close(g_usb_ep_out);
181         g_usb_ep_out = -1;
182
183         if (g_usb_ep_status >= 0)
184                 close(g_usb_ep_status);
185         g_usb_ep_status = -1;
186
187         return;
188 }
189
190 static mtp_uint32 ffs_get_tx_pkt_size(void)
191 {
192         return pkt_size.tx;
193 }
194
195 static mtp_uint32 ffs_get_rx_pkt_size(void)
196 {
197         return pkt_size.rx;
198 }
199
200 /*
201  * static mtp_int32 ffs_transport_mq_init()
202  * This function create a message queue for MTP,
203  * A created message queue will be used to help data transfer between
204  * MTP module and usb buffer.
205  * @return      This function returns TRUE on success or
206  *              returns FALSE on failure.
207  */
208 static mtp_int32 ffs_transport_mq_init(msgq_id_t *rx_mqid, msgq_id_t *tx_mqid)
209 {
210         if (_util_msgq_init(rx_mqid, 0) == FALSE) {
211                 ERR("RX MQ init Fail [%d]\n", errno);
212                 return FALSE;
213         }
214
215         if (_util_msgq_set_size(*rx_mqid, rx_mq_sz) == FALSE)
216                 ERR("RX MQ setting size Fail [%d]\n", errno);
217
218         if (_util_msgq_init(tx_mqid, 0) == FALSE) {
219                 ERR("TX MQ init Fail [%d]\n", errno);
220                 _util_msgq_deinit(rx_mqid);
221                 *rx_mqid = -1;
222                 return FALSE;
223         }
224
225         if (_util_msgq_set_size(*tx_mqid, tx_mq_sz) == FALSE)
226                 ERR("TX MQ setting size Fail [%d]\n", errno);
227
228         return TRUE;
229 }
230
231 static void *ffs_transport_thread_usb_write(void *arg)
232 {
233         mtp_int32 status = 0;
234         mtp_uint32 len = 0;
235         unsigned char *mtp_buf = NULL;
236         msg_type_t mtype = MTP_UNDEFINED_PACKET;
237         msgq_id_t *mqid = (msgq_id_t *)arg;
238
239         pthread_cleanup_push(__clean_up_msg_queue, mqid);
240
241         do {
242                 /* original LinuxThreads cancelation didn't work right
243                  * so test for it explicitly.
244                  */
245                 pthread_testcancel();
246
247                 _util_rcv_msg_from_mq(*mqid, &mtp_buf, &len, &mtype);
248
249                 if (mtype == MTP_BULK_PACKET || mtype == MTP_DATA_PACKET) {
250                         status = write(g_usb_ep_in, mtp_buf, len);
251                         if (status < 0) {
252                                 ERR("USB write fail : %d\n", errno);
253                                 if (errno == ENOMEM || errno == ECANCELED) {
254                                         status = 0;
255                                         __clean_up_msg_queue(mqid);
256                                 }
257                         }
258                         g_free(mtp_buf);
259                         mtp_buf = NULL;
260                 } else if (MTP_EVENT_PACKET == mtype) {
261                         /* Handling the MTP Asynchronous Events */
262                         DBG("Send Interrupt data to kernel via g_usb_ep_status\n");
263                         status = write(g_usb_ep_status, mtp_buf, len);
264                         g_free(mtp_buf);
265                         mtp_buf = NULL;
266                 } else if (MTP_ZLP_PACKET == mtype) {
267                         DBG("Send ZLP data to kerne via g_usb_ep_in\n");
268                         status = write(g_usb_ep_in, (void*)0xFEE1DEAD, 0);
269                 } else {
270                         DBG("mtype = %d is not valid\n", mtype);
271                         status = -1;
272                 }
273
274                 if (status < 0) {
275                         ERR("write data to the device node Fail:\
276                                         status = %d\n", status);
277                         break;
278                 }
279         } while (status >= 0);
280
281         DBG("exited Source thread with status %d\n", status);
282         pthread_cleanup_pop(1);
283         g_free(mtp_buf);
284
285         return NULL;
286 }
287
288 static int __setup(int ep0, struct usb_ctrlrequest *ctrl)
289 {
290         const char* requests[] = {
291                 "CANCELIO",     /* 0x64 */
292                 "GETEVENT",     /* 0x65 */
293                 "RESET",        /* 0x66 */
294                 "GETSTATUS",    /* 0x67 */
295         };
296         __u16 wIndex = le16_to_cpu(ctrl->wIndex);
297         __u16 wValue = le16_to_cpu(ctrl->wValue);
298         __u16 wLength = le16_to_cpu(ctrl->wLength);
299         int rc = -EOPNOTSUPP;
300         int status = 0;
301
302         if ((ctrl->bRequestType & 0x7f) != (USB_TYPE_CLASS | USB_RECIP_INTERFACE)) {
303                 DBG(__FILE__ "(%s):%d: Invalid request type: %d",
304                     __func__, __LINE__, ctrl->bRequestType);
305                 goto stall;
306         }
307
308         switch (((ctrl->bRequestType & 0x80) << 8) | ctrl->bRequest) {
309         case ((USB_DIR_OUT << 8) | USB_PTPREQUEST_CANCELIO):
310
311                 DBG(__FILE__ "(%s):%d: USB_PTPREQUEST_%s",
312                     __func__, __LINE__, requests[ctrl->bRequest-0x64]);
313                 if (wValue != 0 || wIndex != 0 || wLength != 6) {
314                         DBG("Invalid request parameters: wValue:%hu wIndex:%hu wLength:%hu\n", wIndex, wValue, wLength);
315                         rc = -EINVAL;
316                         goto stall;
317                 }
318                 __handle_control_request(ctrl->bRequest);
319                 break;
320
321         case ((USB_DIR_IN << 8) | USB_PTPREQUEST_GETSTATUS):
322         case ((USB_DIR_OUT << 8) | USB_PTPREQUEST_RESET):
323
324                 DBG(__FILE__ "(%s):%d: USB_PTPREQUEST_%s",
325                     __func__, __LINE__, requests[ctrl->bRequest-0x64]);
326                 __handle_control_request(ctrl->bRequest);
327                 break;
328
329         case ((USB_DIR_IN << 8) | USB_PTPREQUEST_GETEVENT):
330
331                 /* Optional, may stall */
332                 DBG(__FILE__ "(%s):%d: USB_PTPREQUEST_%s",
333                     __func__, __LINE__, requests[ctrl->bRequest-0x64]);
334                 rc = -EOPNOTSUPP;
335                 goto stall;
336                 break;
337
338         default:
339                 DBG(__FILE__ "(%s):%d: Invalid request: %d", __func__,
340                     __LINE__, ctrl->bRequest);
341                 goto stall;
342         }
343         return 0;
344
345 stall:
346
347         DBG(__FILE__"(%s):%d:stall %0x2x.%02x\n",
348             __func__, __LINE__, ctrl->bRequestType, ctrl->bRequest);
349         if ((ctrl->bRequestType & 0x80) == USB_DIR_IN)
350                 status = read(g_usb_ep0, NULL, 0);
351         else
352                 status = write(g_usb_ep0, NULL, 0);
353
354         if (status != -1 || errno != EL2HLT) {
355                 ERR(__FILE__"(%s):%d:stall error\n",
356                     __func__, __LINE__);
357                 rc = errno;
358         }
359         return rc;
360 }
361
362 static void *ffs_transport_thread_usb_read(void *arg)
363 {
364         mtp_int32 status = 0;
365         msgq_ptr_t pkt = {MTP_DATA_PACKET, 0, 0, NULL};
366         msgq_id_t *mqid = (msgq_id_t *)arg;
367         mtp_uint32 rx_size = _get_rx_pkt_size();
368
369         pthread_cleanup_push(__clean_up_msg_queue, mqid);
370
371         do {
372                 pthread_testcancel();
373
374                 pkt.buffer = (mtp_uchar *)g_malloc(rx_size);
375                 if (NULL == pkt.buffer) {
376                         ERR("Sink thread: memalloc failed.\n");
377                         break;
378                 }
379
380                 status = read(g_usb_ep_out, pkt.buffer, rx_size);
381                 if (status <= 0) {
382                         status = __handle_usb_read_err(status, pkt.buffer, rx_size);
383                         if (status <= 0) {
384                                 ERR("__handle_usb_read_err is failed\n");
385                                 g_free(pkt.buffer);
386                                 break;
387                         }
388                 }
389
390                 pkt.length = status;
391                 if (FALSE == _util_msgq_send(*mqid, (void *)&pkt,
392                                              sizeof(msgq_ptr_t) - sizeof(long), 0)) {
393                         ERR("msgsnd Fail");
394                         g_free(pkt.buffer);
395                 }
396         } while (status > 0);
397
398         DBG("status[%d] errno[%d]\n", status, errno);
399         pthread_cleanup_pop(1);
400
401         return NULL;
402 }
403
404 static void *ffs_transport_thread_usb_control(void *arg)
405 {
406         mtp_int32 status = 0;
407         struct usb_functionfs_event event;
408         msgq_id_t *mqid = (msgq_id_t *)arg;
409
410         pthread_cleanup_push(__clean_up_msg_queue, mqid);
411
412         do {
413                 pthread_testcancel();
414
415                 status = read(g_usb_ep0, &event, sizeof(event));
416                 if (status < 0) {
417                         char error[256];
418                         ERR("read from ep0 failed: %s",
419                             strerror_r(errno, error, sizeof(error)));
420                         continue;
421                 }
422                 DBG("FUNCTIONFS event received: %d", event.type);
423
424                 switch (event.type) {
425                 case FUNCTIONFS_SETUP:
426                         DBG("SETUP: bmRequestType:%d bRequest:%d wValue:%d wIndex:%d wLength:%d\n",
427                             event.u.setup.bRequestType,
428                             event.u.setup.bRequest,
429                             event.u.setup.wValue,
430                             event.u.setup.wIndex,
431                             event.u.setup.wLength);
432                         __setup(g_usb_ep0, &event.u.setup);
433                         break;
434                 case FUNCTIONFS_ENABLE:
435                         DBG("ENABLE");
436                         _util_set_local_usb_status(MTP_PHONE_USB_CONNECTED);
437                         break;
438                 case FUNCTIONFS_DISABLE:
439                         DBG("DISABLE");
440                         _util_set_local_usb_status(MTP_PHONE_USB_DISCONNECTED);
441                         _eh_send_event_req_to_eh_thread(EVENT_USB_REMOVED, 0, 0, NULL);
442                         break;
443                 }
444         } while (status > 0);
445
446         DBG("status[%d] errno[%d]\n", status, errno);
447         pthread_cleanup_pop(1);
448
449         return NULL;
450 }
451
452 static mtp_int32 __handle_usb_read_err(mtp_int32 err,
453                 mtp_uchar *buf, mtp_int32 buf_len)
454 {
455         mtp_int32 retry = 0;
456         mtp_bool ret;
457
458         while (retry++ < MTP_USB_ERROR_MAX_RETRY) {
459                 if (err == 0) {
460                         DBG("ZLP(Zero Length Packet). Skip");
461                 } else if (err < 0 && errno == EINTR) {
462                         DBG("read () is interrupted. Skip");
463                 } else if (err < 0 && errno == EIO) {
464                         DBG("EIO");
465
466                         if (MTP_PHONE_USB_CONNECTED !=
467                             _util_get_local_usb_status()) {
468                                 ERR("USB is disconnected");
469                                 break;
470                         }
471
472                         _transport_deinit_usb_device();
473                         ret = _transport_init_usb_device();
474                         if (ret == FALSE) {
475                                 ERR("_transport_init_usb_device Fail");
476                                 continue;
477                         }
478                 } else if (err < 0 && errno == ESHUTDOWN) {
479                         DBG("ESHUTDOWN");
480                 } else {
481                         ERR("Unknown error : %d, errno [%d] \n", err, errno);
482                         break;
483                 }
484
485                 err = read(g_usb_ep_out, buf, buf_len);
486                 if (err > 0)
487                         break;
488         }
489
490         if (err <= 0)
491                 ERR("USB error handling Fail");
492
493         return err;
494 }
495
496 static void __clean_up_msg_queue(void *mq_id)
497 {
498         mtp_int32 len = 0;
499         msgq_ptr_t pkt = { 0 };
500         msgq_id_t l_mqid;
501
502         ret_if(mq_id == NULL);
503
504         l_mqid = *(msgq_id_t *)mq_id;
505         _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION);
506         while (TRUE == _util_msgq_receive(l_mqid, (void *)&pkt,
507                                           sizeof(msgq_ptr_t) - sizeof(long), 1, &len)) {
508                 g_free(pkt.buffer);
509                 memset(&pkt, 0, sizeof(msgq_ptr_t));
510         }
511
512         return;
513 }
514
515 static void __handle_control_request(mtp_int32 request)
516 {
517         static mtp_bool kernel_reset = FALSE;
518         static mtp_bool host_cancel = FALSE;
519         mtp_int32 status = 0;
520
521         switch (request) {
522         case USB_PTPREQUEST_CANCELIO:
523                 // XXX: Convert cancel request data from little-endian
524                 // before use:  le32_to_cpu(x), le16_to_cpu(x).
525                 DBG("USB_PTPREQUEST_CANCELIO\n");
526                 cancel_req_t cancelreq_data;
527
528                 host_cancel = TRUE;
529                 _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION);
530                 status = read(g_usb_ep0, &cancelreq_data, sizeof(cancelreq_data));
531                 if (status < 0) {
532                         char error[256];
533                         ERR("Failed to read data for CANCELIO request\n: %s",
534                                         strerror_r(errno, error, sizeof(error)));
535                 }
536                 break;
537
538         case USB_PTPREQUEST_RESET:
539
540                 DBG("USB_PTPREQUEST_RESET\n");
541                 _reset_mtp_device();
542                 if (kernel_reset == FALSE) {
543                         kernel_reset = TRUE;
544                 }
545
546                 status = read(g_usb_ep0, NULL, 0);
547                 if (status < 0) {
548                         ERR("IOCTL MTP_SEND_RESET_ACK Failed [%d]\n",
549                                 status);
550                 }
551                 break;
552         case USB_PTPREQUEST_GETSTATUS:
553
554                 DBG("USB_PTPREQUEST_GETSTATUS");
555
556                 /* Send busy status response just once. This flag is also for
557                  * the case that mtp misses the cancel request packet.
558                  */
559                 static mtp_bool sent_busy = FALSE;
560                 usb_status_req_t statusreq_data = { 0 };
561                 mtp_dword num_param = 0;
562
563                 memset(&statusreq_data, 0x00, sizeof(usb_status_req_t));
564                 if (host_cancel == TRUE || (sent_busy == FALSE &&
565                                             kernel_reset == FALSE)) {
566                         DBG("Send busy response, set host_cancel to FALSE");
567                         statusreq_data.len = 0x08;
568                         statusreq_data.code = PTP_RESPONSE_DEVICEBUSY;
569                         host_cancel = FALSE;
570                 } else if (_device_get_phase() == DEVICE_PHASE_NOTREADY) {
571                         statusreq_data.code =
572                                 PTP_RESPONSE_TRANSACTIONCANCELLED;
573                         DBG("PTP_RESPONSE_TRANSACTIONCANCELLED");
574                         statusreq_data.len = (mtp_word)(sizeof(usb_status_req_t) +
575                                                         (num_param - 2) * sizeof(mtp_dword));
576                 } else if (_device_get_status() == DEVICE_STATUSOK) {
577                         DBG("PTP_RESPONSE_OK");
578                         statusreq_data.len = 0x08;
579                         statusreq_data.code = PTP_RESPONSE_OK;
580
581                         if (kernel_reset == TRUE)
582                                 kernel_reset = FALSE;
583                 } else {
584                         DBG("PTP_RESPONSE_GEN_ERROR");
585                         statusreq_data.len = 0x08;
586                         statusreq_data.code = PTP_RESPONSE_GEN_ERROR;
587                 }
588
589                 if (statusreq_data.code == PTP_RESPONSE_DEVICEBUSY) {
590                         sent_busy = TRUE;
591                 } else {
592                         sent_busy = FALSE;
593                 }
594
595                 /* status = ioctl(g_usb_fd, MTP_SET_SETUP_DATA, &statusreq_data);
596                 if (status < 0) {
597                         DBG("IOCTL MTP_SET_SETUP_DATA Fail [%d]\n",
598                                         status);
599                         return;
600                 } */
601
602                 break;
603
604         case USB_PTPREQUEST_GETEVENT:
605                 DBG("USB_PTPREQUEST_GETEVENT");
606                 break;
607
608         default:
609                 DBG("Invalid class specific setup request");
610                 break;
611         }
612         return;
613 }
614
615 /*
616  * mtp_bool ffs_transport_mq_deinit()
617  * This function destroy a message queue for MTP,
618  * @return      This function returns TRUE on success or
619  *              returns FALSE on failure.
620  */
621 static mtp_bool ffs_transport_mq_deinit(msgq_id_t *rx_mqid, msgq_id_t *tx_mqid)
622 {
623         mtp_int32 res = TRUE;
624
625         if (*rx_mqid) {
626                 res = _util_msgq_deinit(rx_mqid);
627                 if (res == FALSE) {
628                         ERR("rx_mqid deinit Fail [%d]\n", errno);
629                 } else {
630                         *rx_mqid = 0;
631                 }
632         }
633
634         if (*tx_mqid) {
635                 res = _util_msgq_deinit(tx_mqid);
636                 if (res == FALSE) {
637                         ERR("tx_mqid deinit fail [%d]\n", errno);
638                 } else {
639                         *tx_mqid = 0;
640                 }
641         }
642
643         return res;
644 }
645
646 static mtp_uint32 ffs_transport_get_usb_packet_len(void)
647 {
648         mtp_int32 status = -1;
649         static mtp_int32 usb_speed = 0;
650
651         if (usb_speed == 0) {
652
653                 //status = ioctl(g_usb_fd, MTP_GET_HIGH_FULL_SPEED, &usb_speed);
654                 if (status < 0) {
655                         ERR("MTP_GET_HIGH_FULL_SPEED Failed [%d]\n", status);
656                         return MTP_MAX_PACKET_SIZE_SEND_FS;
657                 }
658         }
659
660         if (usb_speed % MTP_MAX_PACKET_SIZE_SEND_HS) {
661                 return MTP_MAX_PACKET_SIZE_SEND_FS;
662         }
663
664         return MTP_MAX_PACKET_SIZE_SEND_HS;
665 }
666 /* LCOV_EXCL_STOP */
667
668
669 const mtp_usb_driver_t mtp_usb_driver_ffs = {
670         .transport_init_usb_device = ffs_transport_init_usb_device,
671         .transport_deinit_usb_device = ffs_transport_deinit_usb_device,
672         .transport_thread_usb_write = ffs_transport_thread_usb_write,
673         .transport_thread_usb_read = ffs_transport_thread_usb_read,
674         .transport_thread_usb_control = ffs_transport_thread_usb_control,
675         .transport_mq_init = ffs_transport_mq_init,
676         .transport_mq_deinit = ffs_transport_mq_deinit,
677         .transport_get_usb_packet_len = ffs_transport_get_usb_packet_len,
678         .get_tx_pkt_size = ffs_get_tx_pkt_size,
679         .get_rx_pkt_size = ffs_get_rx_pkt_size,
680 };