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