1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <unistd.h> 18 #include <stdio.h> 19 #include <string.h> 20 #include <stdlib.h> 21 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 #include <fcntl.h> 25 #include <errno.h> 26 #include <pthread.h> 27 #include <time.h> 28 29 #include <usbhost/usbhost.h> 30 #include <linux/usb/f_accessory.h> 31 32 static struct usb_device *sDevice = NULL; 33 static int sAfterUnplug = 0; 34 static char* sDeviceSerial = NULL; 35 36 static void* message_thread(void* arg) { 37 int *endpoints = (int *)arg; 38 int ret = 0; 39 int num = 0; 40 char message[50]; 41 42 while (sDevice && ret >= 0) { 43 char buffer[16384]; 44 ret = usb_device_bulk_transfer(sDevice, endpoints[0], buffer, sizeof(buffer), 1000); 45 if (ret < 0 && errno == ETIMEDOUT) { 46 ret = 0; 47 } 48 if (ret > 0) { 49 printf("[RECV] "); 50 fwrite(buffer, 1, ret, stdout); 51 printf("\n"); 52 53 // Respond by sending a message back 54 sprintf(message, "Message from Android accessory #%d", num++); 55 printf("[SENT] %s\n", message); 56 fflush(stdout); 57 usb_device_bulk_transfer(sDevice, endpoints[1], message, strlen(message), 1000); 58 } 59 } 60 61 return NULL; 62 } 63 64 static void milli_sleep(int millis) { 65 struct timespec tm; 66 67 tm.tv_sec = 0; 68 tm.tv_nsec = millis * 1000000; 69 nanosleep(&tm, NULL); 70 } 71 72 static int send_string(struct usb_device *device, int index, const char* string) { 73 int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 74 ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 1000); 75 76 // some devices can't handle back-to-back requests, so delay a bit 77 milli_sleep(10); 78 return ret; 79 } 80 81 static int usb_device_added(const char *devname, void* client_data) { 82 struct usb_descriptor_header* desc; 83 struct usb_descriptor_iter iter; 84 uint16_t vendorId, productId; 85 int ret; 86 pthread_t th; 87 88 struct usb_device *device = usb_device_open(devname); 89 if (!device) { 90 fprintf(stderr, "usb_device_open failed\n"); 91 return 0; 92 } 93 94 char* serial = usb_device_get_serial(device); 95 if (sDeviceSerial && (!serial || strcmp(sDeviceSerial, serial))) { 96 free(serial); 97 return 0; 98 } 99 free(serial); 100 101 vendorId = usb_device_get_vendor_id(device); 102 productId = usb_device_get_product_id(device); 103 104 if (!sDevice && (vendorId == 0x18D1 && (productId == 0x2D00 || productId == 0x2D01))) { 105 struct usb_descriptor_header* desc; 106 struct usb_descriptor_iter iter; 107 struct usb_interface_descriptor *intf = NULL; 108 struct usb_endpoint_descriptor *ep1 = NULL; 109 struct usb_endpoint_descriptor *ep2 = NULL; 110 111 printf("Found Android device in accessory mode (%x:%x)...\n", 112 vendorId, productId); 113 sDevice = device; 114 sDeviceSerial = usb_device_get_serial(sDevice); 115 116 usb_descriptor_iter_init(device, &iter); 117 while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) { 118 if (desc->bDescriptorType == USB_DT_INTERFACE) { 119 intf = (struct usb_interface_descriptor *)desc; 120 } else if (desc->bDescriptorType == USB_DT_ENDPOINT) { 121 if (ep1) 122 ep2 = (struct usb_endpoint_descriptor *)desc; 123 else 124 ep1 = (struct usb_endpoint_descriptor *)desc; 125 } 126 } 127 128 if (!intf) { 129 fprintf(stderr, "Interface not found\n"); 130 exit(1); 131 } 132 if (!ep1 || !ep2) { 133 fprintf(stderr, "Endpoints not found\n"); 134 exit(1); 135 } 136 137 if (usb_device_claim_interface(device, intf->bInterfaceNumber)) { 138 fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno); 139 exit(1); 140 } 141 142 int endpoints[2]; 143 if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { 144 endpoints[0] = ep1->bEndpointAddress; 145 endpoints[1] = ep2->bEndpointAddress; 146 } else { 147 endpoints[0] = ep2->bEndpointAddress; 148 endpoints[1] = ep1->bEndpointAddress; 149 } 150 pthread_create(&th, NULL, message_thread, (void *)endpoints); 151 } else { 152 printf("Found possible Android device (%x:%x) " 153 "- attempting to switch to accessory mode...\n", vendorId, productId); 154 155 uint16_t protocol = 0; 156 ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR, 157 ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 1000); 158 if (ret == 2) { 159 printf("Device supports protocol version %d\n", protocol); 160 } else { 161 fprintf(stderr, "Failed to read protocol version\n"); 162 } 163 164 ret = (ret < 0) ? ret : 165 send_string(device, ACCESSORY_STRING_MANUFACTURER, "Android CTS"); 166 ret = (ret < 0) ? ret : 167 send_string(device, ACCESSORY_STRING_MODEL, "CTS USB Accessory"); 168 ret = (ret < 0) ? ret : 169 send_string(device, ACCESSORY_STRING_DESCRIPTION, "CTS USB Accessory"); 170 ret = (ret < 0) ? ret : 171 send_string(device, ACCESSORY_STRING_VERSION, "1.0"); 172 ret = (ret < 0) ? ret : 173 send_string(device, ACCESSORY_STRING_URI, 174 "http://source.android.com/compatibility/cts-intro.html"); 175 ret = (ret < 0) ? ret : 176 send_string(device, ACCESSORY_STRING_SERIAL, "1234567890"); 177 178 ret = (ret < 0) ? ret : 179 usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 180 ACCESSORY_START, 0, 0, 0, 0, 1000); 181 if (ret < 0) { 182 fprintf(stderr, "Failed to start accessory mode\n"); 183 } 184 return 0; 185 } 186 187 if (device != sDevice) 188 usb_device_close(device); 189 190 return 0; 191 } 192 193 static int usb_device_removed(const char *devname, void* client_data) { 194 if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) { 195 usb_device_close(sDevice); 196 sDevice = NULL; 197 if (sAfterUnplug) { 198 // exit when we are disconnected the second time 199 free(sDeviceSerial); 200 return 1; 201 } else { 202 sAfterUnplug = 1; 203 } 204 } 205 return 0; 206 } 207 208 209 int main(int argc, char* argv[]) { 210 printf("CTS USB Accessory Tester\n"); 211 212 struct usb_host_context* context = usb_host_init(); 213 if (!context) { 214 fprintf(stderr, "usb_host_init failed"); 215 return 1; 216 } 217 218 // this will never return so it is safe to pass thiz directly 219 usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL); 220 return 0; 221 } 222