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"
332a656c332b792c84fa6e96d8b40e2c8c0fe94ef9Szymon Starzycki#include "utils.h"
34a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
35a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define   TRACE_TAG  TRACE_USB
36a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
37a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define MAX_PACKET_SIZE_FS     64
38a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define MAX_PACKET_SIZE_HS     512
39a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
40a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define cpu_to_le16(x)  htole16(x)
41a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define cpu_to_le32(x)  htole32(x)
42a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
43a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define FASTBOOT_CLASS         0xff
44a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define FASTBOOT_SUBCLASS      0x42
45a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define FASTBOOT_PROTOCOL      0x3
46a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
47a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_PATH  "/dev/usb-ffs/adb/"
48a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_EP(x) USB_FFS_FASTBOOT_PATH#x
49a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
50a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_EP0   USB_FFS_FASTBOOT_EP(ep0)
51a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_OUT   USB_FFS_FASTBOOT_EP(ep1)
52a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define USB_FFS_FASTBOOT_IN    USB_FFS_FASTBOOT_EP(ep2)
53a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
54a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define container_of(ptr, type, member) \
55a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ((type*)((char*)(ptr) - offsetof(type, member)))
56a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
57a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstruct usb_transport {
58a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport transport;
59a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
60a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_cond_t notify;
61a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_t lock;
62a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
63a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int control;
64a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int bulk_out; /* "out" from the host's perspective => source for fastbootd */
65a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int bulk_in;  /* "in" from the host's perspective => sink for fastbootd */
66a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross};
67a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
68a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstruct usb_handle {
69a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport_handle handle;
70a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross};
71a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
72a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic const struct {
73a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_functionfs_descs_head header;
74a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct {
75a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        struct usb_interface_descriptor intf;
76a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        struct usb_endpoint_descriptor_no_audio source;
77a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        struct usb_endpoint_descriptor_no_audio sink;
78a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    } __attribute__((packed)) fs_descs, hs_descs;
79a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross} __attribute__((packed)) descriptors = {
80a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .header = {
81a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
82a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .length = cpu_to_le32(sizeof(descriptors)),
83a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .fs_count = 3,
84a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .hs_count = 3,
85a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
86a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .fs_descs = {
87a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .intf = {
88a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.fs_descs.intf),
89a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_INTERFACE,
90a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceNumber = 0,
91a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bNumEndpoints = 2,
92a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceClass = FASTBOOT_CLASS,
93a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
94a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
95a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .iInterface = 1, /* first string from the provided table */
96a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
97a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .source = {
98a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.fs_descs.source),
99a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_ENDPOINT,
100a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bEndpointAddress = 1 | USB_DIR_OUT,
101a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bmAttributes = USB_ENDPOINT_XFER_BULK,
102a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
103a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
104a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .sink = {
105a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.fs_descs.sink),
106a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_ENDPOINT,
107a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bEndpointAddress = 2 | USB_DIR_IN,
108a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bmAttributes = USB_ENDPOINT_XFER_BULK,
109a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .wMaxPacketSize = MAX_PACKET_SIZE_FS,
110a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
111a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
112a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .hs_descs = {
113a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .intf = {
114a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.hs_descs.intf),
115a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_INTERFACE,
116a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceNumber = 0,
117a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bNumEndpoints = 2,
118a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceClass = FASTBOOT_CLASS,
119a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceSubClass = FASTBOOT_SUBCLASS,
120a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bInterfaceProtocol = FASTBOOT_PROTOCOL,
121a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .iInterface = 1, /* first string from the provided table */
122a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
123a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .source = {
124a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.hs_descs.source),
125a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_ENDPOINT,
126a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bEndpointAddress = 1 | USB_DIR_OUT,
127a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bmAttributes = USB_ENDPOINT_XFER_BULK,
128a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
129a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
130a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .sink = {
131a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bLength = sizeof(descriptors.hs_descs.sink),
132a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bDescriptorType = USB_DT_ENDPOINT,
133a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bEndpointAddress = 2 | USB_DIR_IN,
134a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .bmAttributes = USB_ENDPOINT_XFER_BULK,
135a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross            .wMaxPacketSize = MAX_PACKET_SIZE_HS,
136a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        },
137a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
138a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross};
139a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
140a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross#define STR_INTERFACE_ "Fastboot Interface"
141a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
142a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic const struct {
143a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_functionfs_strings_head header;
144a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct {
145a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        __le16 code;
146a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        const char str1[sizeof(STR_INTERFACE_)];
147a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    } __attribute__((packed)) lang0;
148a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross} __attribute__((packed)) strings = {
149a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .header = {
150a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
151a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .length = cpu_to_le32(sizeof(strings)),
152a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .str_count = cpu_to_le32(1),
153a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        .lang_count = cpu_to_le32(1),
154a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
155a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    .lang0 = {
156a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        cpu_to_le16(0x0409), /* en-us */
157a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        STR_INTERFACE_,
158a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    },
159a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross};
160a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
161a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic int init_functionfs(struct usb_transport *usb_transport)
162a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
163a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ssize_t ret;
164a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
165a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(VERBOSE, "OPENING %s", USB_FFS_FASTBOOT_EP0);
166a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->control = open(USB_FFS_FASTBOOT_EP0, O_RDWR);
167a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->control < 0) {
168a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: cannot open control endpoint: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
169a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
170a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
171a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
172a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = write(usb_transport->control, &descriptors, sizeof(descriptors));
173a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
174a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: write descriptors failed: errno=%d ]", USB_FFS_FASTBOOT_EP0, errno);
175a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
176a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
177a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
178a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = write(usb_transport->control, &strings, sizeof(strings));
179a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
180a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: writing strings failed: errno=%d]", USB_FFS_FASTBOOT_EP0, errno);
181a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
182a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
183a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
184a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->bulk_out = open(USB_FFS_FASTBOOT_OUT, O_RDWR);
185a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->bulk_out < 0) {
186a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: cannot open bulk-out ep: errno=%d ]", USB_FFS_FASTBOOT_OUT, errno);
187a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
188a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
189a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
190a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->bulk_in = open(USB_FFS_FASTBOOT_IN, O_RDWR);
191a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->bulk_in < 0) {
192a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "[ %s: cannot open bulk-in ep: errno=%d ]", USB_FFS_FASTBOOT_IN, errno);
193a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        goto err;
194a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
195a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
196a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return 0;
197a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
198a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crosserr:
199a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->bulk_in > 0) {
200a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        close(usb_transport->bulk_in);
201a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        usb_transport->bulk_in = -1;
202a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
203a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->bulk_out > 0) {
204a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        close(usb_transport->bulk_out);
205a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        usb_transport->bulk_out = -1;
206a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
207a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (usb_transport->control > 0) {
208a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        close(usb_transport->control);
209a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        usb_transport->control = -1;
210a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
211a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return -1;
212a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
213a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
214a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstatic ssize_t usb_write(struct transport_handle *thandle, const void *data, size_t len)
215a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
216a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ssize_t ret;
217a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport *t = thandle->transport;
218a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
219a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
220ccecf1425412beb2bc3bb38d470293fdc244d6f1Elliott Hughes    D(DEBUG, "about to write (fd=%d, len=%zu)", usb_transport->bulk_in, len);
221a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = bulk_write(usb_transport->bulk_in, data, len);
222a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
223a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_in, ret);
224a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        return -1;
225a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
226a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(DEBUG, "[ usb_write done fd=%d ]", usb_transport->bulk_in);
227a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return ret;
228a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
229a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
230a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossssize_t usb_read(struct transport_handle *thandle, void *data, size_t len)
231a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
232a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ssize_t ret;
233a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport *t = thandle->transport;
234a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
235a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
236ccecf1425412beb2bc3bb38d470293fdc244d6f1Elliott Hughes    D(DEBUG, "about to read (fd=%d, len=%zu)", usb_transport->bulk_out, len);
237a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = bulk_read(usb_transport->bulk_out, data, len);
238a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
239a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_out, ret);
240a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        return -1;
241a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
242a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(DEBUG, "[ usb_read done fd=%d ret=%zd]", usb_transport->bulk_out, ret);
243a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return ret;
244a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
245a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
246a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossvoid usb_close(struct transport_handle *thandle)
247a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
248a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int err;
249a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct transport *t = thandle->transport;
250a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
251a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
252a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    err = ioctl(usb_transport->bulk_in, FUNCTIONFS_CLEAR_HALT);
253a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (err < 0)
254a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(WARN, "[ kick: source (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_in, errno);
255a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
256a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    err = ioctl(usb_transport->bulk_out, FUNCTIONFS_CLEAR_HALT);
257a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (err < 0)
258a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(WARN, "[ kick: sink (fd=%d) clear halt failed (%d) ]", usb_transport->bulk_out, errno);
259a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
260a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_lock(&usb_transport->lock);
261a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    close(usb_transport->control);
262a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    close(usb_transport->bulk_out);
263a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    close(usb_transport->bulk_in);
264a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->control = usb_transport->bulk_out = usb_transport->bulk_in = -1;
265a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
266a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_cond_signal(&usb_transport->notify);
267a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_unlock(&usb_transport->lock);
268a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
269a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
270a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossstruct transport_handle *usb_connect(struct transport *transport)
271a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
272a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    int ret;
273a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_handle *usb_handle = calloc(sizeof(struct usb_handle), 1);
274a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = container_of(transport, struct usb_transport, transport);
275a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
276a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_lock(&usb_transport->lock);
277a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    while (usb_transport->control != -1)
278a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        pthread_cond_wait(&usb_transport->notify, &usb_transport->lock);
279a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_unlock(&usb_transport->lock);
280a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
281a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    ret = init_functionfs(usb_transport);
282a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    if (ret < 0) {
283a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        D(ERR, "usb connect: failed to initialize usb transport");
284a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross        return NULL;
285a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    }
286a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
287a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    D(DEBUG, "[ usb_thread - registering device ]");
288a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    return &usb_handle->handle;
289a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
290a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
291a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Crossvoid usb_init()
292a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross{
293a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    struct usb_transport *usb_transport = calloc(1, sizeof(struct usb_transport));
294a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
295a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->transport.connect = usb_connect;
296a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->transport.close = usb_close;
297a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->transport.read = usb_read;
298a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->transport.write = usb_write;
299a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->control  = -1;
300a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->bulk_out = -1;
301a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    usb_transport->bulk_out = -1;
302a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
303a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_cond_init(&usb_transport->notify, NULL);
304a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    pthread_mutex_init(&usb_transport->lock, NULL);
305a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
306a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross    transport_register(&usb_transport->transport);
307a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross}
308a3d386ea56ef53bb070b87ea7c28e103c5a53e45Colin Cross
309