1a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross/*
2a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * Copyright (C) 2007 The Android Open Source Project
3a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross *
4a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * Licensed under the Apache License, Version 2.0 (the "License");
5a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * you may not use this file except in compliance with the License.
6a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * You may obtain a copy of the License at
7a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross *
8a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross *      http://www.apache.org/licenses/LICENSE-2.0
9a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross *
10a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * Unless required by applicable law or agreed to in writing, software
11a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * distributed under the License is distributed on an "AS IS" BASIS,
12a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * See the License for the specific language governing permissions and
14a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross * limitations under the License.
15a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross */
16a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
17a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <endian.h>
18a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <fcntl.h>
19a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <pthread.h>
20a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <stdio.h>
21a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <stdlib.h>
22a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <string.h>
23a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <unistd.h>
24a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
25a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <sys/ioctl.h>
26a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <sys/types.h>
27a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
28a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <linux/usb/ch9.h>
29a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include <linux/usb/functionfs.h>
30a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
31a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include "debug.h"
32a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#include "transport.h"
33a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
34a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define   TRACE_TAG  TRACE_USB
35a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
36a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define MAX_PACKET_SIZE_FS     64
37a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define MAX_PACKET_SIZE_HS     512
38a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
39a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define cpu_to_le16(x)  htole16(x)
40a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define cpu_to_le32(x)  htole32(x)
41a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
42a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define FASTBOOT_CLASS         0xff
43a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define FASTBOOT_SUBCLASS      0x42
44a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define FASTBOOT_PROTOCOL      0x3
45a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
46a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_PATH  "/dev/usb-ffs/adb/"
47a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_EP(x) USB_FFS_FASTBOOT_PATH#x
48a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
49a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_EP0   USB_FFS_FASTBOOT_EP(ep0)
50a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_OUT   USB_FFS_FASTBOOT_EP(ep1)
51a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_IN    USB_FFS_FASTBOOT_EP(ep2)
52a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
53a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define READ_BUF_SIZE (16*1024)
54a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
55a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define container_of(ptr, type, member) \
56a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ((type*)((char*)(ptr) - offsetof(type, member)))
57a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
58a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstruct usb_transport {
59a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport transport;
60a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
61a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_cond_t notify;
62a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_t lock;
63a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
64a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int control;
65a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int bulk_out; /* "out" from the host's perspective => source for fastbootd */
66a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int bulk_in;  /* "in" from the host's perspective => sink for fastbootd */
67a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross};
68a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
69a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstruct usb_handle {
70a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport_handle handle;
71a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross};
72a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
73a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic const struct {
74a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_functionfs_descs_head header;
75a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct {
76a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        struct usb_interface_descriptor intf;
77a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        struct usb_endpoint_descriptor_no_audio source;
78a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        struct usb_endpoint_descriptor_no_audio sink;
79a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    } __attribute__((packed)) fs_descs, hs_descs;
80a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross} __attribute__((packed)) descriptors = {
81a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .header = {
82a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
83a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .length = cpu_to_le32(sizeof(descriptors)),
84a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .fs_count = 3,
85a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .hs_count = 3,
86a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
87a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .fs_descs = {
88a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .intf = {
89a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.fs_descs.intf),
90a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_INTERFACE,
91a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceNumber = 0,
92a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bNumEndpoints = 2,
93a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceClass = FASTBOOT_CLASS,
94a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
95a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
96a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .iInterface = 1, /* first string from the provided table */
97a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
98a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .source = {
99a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.fs_descs.source),
100a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_ENDPOINT,
101a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bEndpointAddress = 1 | USB_DIR_OUT,
102a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bmAttributes = USB_ENDPOINT_XFER_BULK,
103a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
104a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
105a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .sink = {
106a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.fs_descs.sink),
107a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_ENDPOINT,
108a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bEndpointAddress = 2 | USB_DIR_IN,
109a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bmAttributes = USB_ENDPOINT_XFER_BULK,
110a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
111a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
112a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
113a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .hs_descs = {
114a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .intf = {
115a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.hs_descs.intf),
116a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_INTERFACE,
117a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceNumber = 0,
118a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bNumEndpoints = 2,
119a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceClass = FASTBOOT_CLASS,
120a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
121a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
122a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .iInterface = 1, /* first string from the provided table */
123a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
124a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .source = {
125a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.hs_descs.source),
126a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_ENDPOINT,
127a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bEndpointAddress = 1 | USB_DIR_OUT,
128a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bmAttributes = USB_ENDPOINT_XFER_BULK,
129a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
130a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
131a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .sink = {
132a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.hs_descs.sink),
133a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_ENDPOINT,
134a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bEndpointAddress = 2 | USB_DIR_IN,
135a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bmAttributes = USB_ENDPOINT_XFER_BULK,
136a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
137a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
138a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
139a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross};
140a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
141a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define STR_INTERFACE_ "Fastboot Interface"
142a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
143a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic const struct {
144a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_functionfs_strings_head header;
145a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct {
146a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        __le16 code;
147a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        const char str1[sizeof(STR_INTERFACE_)];
148a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    } __attribute__((packed)) lang0;
149a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross} __attribute__((packed)) strings = {
150a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .header = {
151a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
152a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .length = cpu_to_le32(sizeof(strings)),
153a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .str_count = cpu_to_le32(1),
154a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .lang_count = cpu_to_le32(1),
155a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
156a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .lang0 = {
157a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        cpu_to_le16(0x0409), /* en-us */
158a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        STR_INTERFACE_,
159a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
160a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross};
161a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
162a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic int init_functionfs(struct usb_transport *usb_transport)
163a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
164a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ssize_t ret;
165a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
166a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(VERBOSE, "OPENING %s", USB_FFS_FASTBOOT_EP0);
167a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->control = open(USB_FFS_FASTBOOT_EP0, O_RDWR);
168a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->control < 0) {
169a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: cannot open control endpoint: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
170a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
171a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
172a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
173a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = write(usb_transport->control, &descriptors, sizeof(descriptors));
174a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
175a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno);
176a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
177a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
178a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
179a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = write(usb_transport->control, &strings, sizeof(strings));
180a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
181a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: writing strings failed: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
182a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
183a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
184a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
185a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->bulk_out = open(USB_FFS_FASTBOOT_OUT, O_RDWR);
186a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->bulk_out < 0) {
187a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: cannot open bulk-out ep: errno=%d ]", USB_FFS_FASTBOOT_OUT, errno);
188a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
189a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
190a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
191a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->bulk_in = open(USB_FFS_FASTBOOT_IN, O_RDWR);
192a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->bulk_in < 0) {
193a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: cannot open bulk-in ep: errno=%d ]", USB_FFS_FASTBOOT_IN, errno);
194a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
195a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
196a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
197a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return 0;
198a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
199a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crosserr:
200a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->bulk_in > 0) {
201a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        close(usb_transport->bulk_in);
202a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        usb_transport->bulk_in = -1;
203a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
204a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->bulk_out > 0) {
205a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        close(usb_transport->bulk_out);
206a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        usb_transport->bulk_out = -1;
207a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
208a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->control > 0) {
209a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        close(usb_transport->control);
210a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        usb_transport->control = -1;
211a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
212a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return -1;
213a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
214a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
215a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic ssize_t bulk_write(int bulk_in, const char *buf, size_t length)
216a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
217a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    size_t count = 0;
218a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ssize_t ret;
219a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
220a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    do {
221a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        ret = TEMP_FAILURE_RETRY(write(bulk_in, buf + count, length - count));
222a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        if (ret < 0) {
223a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
224a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross                    bulk_in, length, errno, strerror(errno));
225a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            return -1;
226a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        } else {
227a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            count += ret;
228a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        }
229a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    } while (count < length);
230a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
231a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(VERBOSE, "[ bulk_write done fd=%d ]", bulk_in);
232a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return count;
233a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
234a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
235a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic ssize_t usb_write(struct transport_handle *thandle, const void *data, size_t len)
236a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
237a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ssize_t ret;
238a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport *t = thandle->transport;
239a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
240a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
241a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(DEBUG, "about to write (fd=%d, len=%d)", usb_transport->bulk_in, len);
242a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = bulk_write(usb_transport->bulk_in, data, len);
243a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
244a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_in, ret);
245a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        return -1;
246a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
247a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(DEBUG, "[ usb_write done fd=%d ]", usb_transport->bulk_in);
248a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return ret;
249a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
250a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
251a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic ssize_t bulk_read(int bulk_out, char *buf, size_t length)
252a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
253a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ssize_t ret;
254a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    size_t n = 0;
255a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
256a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    while (n < length) {
257a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        size_t to_read = (length - n > READ_BUF_SIZE) ? READ_BUF_SIZE : length - n;
258a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        ret = TEMP_FAILURE_RETRY(read(bulk_out, buf + n, to_read));
259a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        if (ret < 0) {
260a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
261a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross                    bulk_out, length, errno, strerror(errno));
262a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            return ret;
263a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        }
264a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        n += ret;
265a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        if (ret < (ssize_t)to_read) {
266a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            D(VERBOSE, "bulk_read short read, ret=%zd to_read=%u n=%u length=%u",
267a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross                    ret, to_read, n, length);
268a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            break;
269a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        }
270a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
271a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
272a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return n;
273a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
274a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
275a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossssize_t usb_read(struct transport_handle *thandle, void *data, size_t len)
276a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
277a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ssize_t ret;
278a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport *t = thandle->transport;
279a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
280a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
281a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(DEBUG, "about to read (fd=%d, len=%d)", usb_transport->bulk_out, len);
282a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = bulk_read(usb_transport->bulk_out, data, len);
283a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
284a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_out, ret);
285a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        return -1;
286a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
287a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(DEBUG, "[ usb_read done fd=%d ret=%zd]", usb_transport->bulk_out, ret);
288a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return ret;
289a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
290a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
291a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossvoid usb_close(struct transport_handle *thandle)
292a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
293a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int err;
294a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport *t = thandle->transport;
295a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
296a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
297a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    err = ioctl(usb_transport->bulk_in, FUNCTIONFS_CLEAR_HALT);
298a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (err < 0)
299a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(WARN, "[ kick: source (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_in, errno);
300a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
301a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    err = ioctl(usb_transport->bulk_out, FUNCTIONFS_CLEAR_HALT);
302a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (err < 0)
303a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(WARN, "[ kick: sink (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_out, errno);
304a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
305a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_lock(&usb_transport->lock);
306a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    close(usb_transport->control);
307a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    close(usb_transport->bulk_out);
308a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    close(usb_transport->bulk_in);
309a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->control = usb_transport->bulk_out = usb_transport->bulk_in = -1;
310a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
311a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_cond_signal(&usb_transport->notify);
312a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_unlock(&usb_transport->lock);
313a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
314a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
315a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstruct transport_handle *usb_connect(struct transport *transport)
316a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
317a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int ret;
318a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_handle *usb_handle = calloc(sizeof(struct usb_handle), 1);
319a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = container_of(transport, struct usb_transport, transport);
320a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
321a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_lock(&usb_transport->lock);
322a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    while (usb_transport->control != -1)
323a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        pthread_cond_wait(&usb_transport->notify, &usb_transport->lock);
324a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_unlock(&usb_transport->lock);
325a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
326a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = init_functionfs(usb_transport);
327a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
328a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "usb connect: failed to initialize usb transport");
329a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        return NULL;
330a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
331a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
332a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(DEBUG, "[ usb_thread - registering device ]");
333a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return &usb_handle->handle;
334a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
335a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
336a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossvoid usb_init()
337a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
338a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = calloc(1, sizeof(struct usb_transport));
339a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
340a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->transport.connect = usb_connect;
341a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->transport.close = usb_close;
342a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->transport.read = usb_read;
343a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->transport.write = usb_write;
344a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->control  = -1;
345a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->bulk_out = -1;
346a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->bulk_out = -1;
347a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
348a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_cond_init(&usb_transport->notify, NULL);
349a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_init(&usb_transport->lock, NULL);
350a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
351a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    transport_register(&usb_transport->transport);
352a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
353a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
354