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