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