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 struct usb_device *sDevice = NULL; 33 34 static void* message_thread(void* arg) { 35 int *endpoints = (int *)arg; 36 int ret = 0; 37 int num = 0; 38 char message[50]; 39 40 while (sDevice && ret >= 0) { 41 char buffer[16384]; 42 ret = usb_device_bulk_transfer(sDevice, endpoints[0], buffer, sizeof(buffer), 1000); 43 if (ret < 0 && errno == ETIMEDOUT) { 44 ret = 0; 45 } 46 if (ret > 0) { 47 printf("[RECV] "); 48 fwrite(buffer, 1, ret, stdout); 49 printf("\n"); 50 51 // Respond by sending a message back 52 sprintf(message, "Message from Android accessory #%d", num++); 53 printf("[SENT] %s\n", message); 54 fflush(stdout); 55 usb_device_bulk_transfer(sDevice, endpoints[1], message, strlen(message), 1000); 56 } 57 } 58 59 return NULL; 60 } 61 62 static void milli_sleep(int millis) { 63 struct timespec tm; 64 65 tm.tv_sec = 0; 66 tm.tv_nsec = millis * 1000000; 67 nanosleep(&tm, NULL); 68 } 69 70 static void send_string(struct usb_device *device, int index, const char* string) { 71 int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 72 ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0); 73 74 // some devices can't handle back-to-back requests, so delay a bit 75 milli_sleep(10); 76 } 77 78 static int usb_device_added(const char *devname, void* client_data) { 79 struct usb_descriptor_header* desc; 80 struct usb_descriptor_iter iter; 81 uint16_t vendorId, productId; 82 int ret; 83 pthread_t th; 84 85 struct usb_device *device = usb_device_open(devname); 86 if (!device) { 87 fprintf(stderr, "usb_device_open failed\n"); 88 return 0; 89 } 90 91 vendorId = usb_device_get_vendor_id(device); 92 productId = usb_device_get_product_id(device); 93 94 if (!sDevice && (vendorId == 0x18D1 && (productId == 0x2D00 || productId == 0x2D01))) { 95 struct usb_descriptor_header* desc; 96 struct usb_descriptor_iter iter; 97 struct usb_interface_descriptor *intf = NULL; 98 struct usb_endpoint_descriptor *ep1 = NULL; 99 struct usb_endpoint_descriptor *ep2 = NULL; 100 101 printf("Found Android device in accessory mode (%x:%x)...\n", 102 vendorId, productId); 103 sDevice = device; 104 105 usb_descriptor_iter_init(device, &iter); 106 while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) { 107 if (desc->bDescriptorType == USB_DT_INTERFACE) { 108 intf = (struct usb_interface_descriptor *)desc; 109 } else if (desc->bDescriptorType == USB_DT_ENDPOINT) { 110 if (ep1) 111 ep2 = (struct usb_endpoint_descriptor *)desc; 112 else 113 ep1 = (struct usb_endpoint_descriptor *)desc; 114 } 115 } 116 117 if (!intf) { 118 fprintf(stderr, "Interface not found\n"); 119 exit(1); 120 } 121 if (!ep1 || !ep2) { 122 fprintf(stderr, "Endpoints not found\n"); 123 exit(1); 124 } 125 126 if (usb_device_claim_interface(device, intf->bInterfaceNumber)) { 127 fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno); 128 exit(1); 129 } 130 131 int endpoints[2]; 132 if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { 133 endpoints[0] = ep1->bEndpointAddress; 134 endpoints[1] = ep2->bEndpointAddress; 135 } else { 136 endpoints[0] = ep2->bEndpointAddress; 137 endpoints[1] = ep1->bEndpointAddress; 138 } 139 pthread_create(&th, NULL, message_thread, (void *)endpoints); 140 } else { 141 printf("Found possible Android device (%x:%x) " 142 "- attempting to switch to accessory mode...\n", vendorId, productId); 143 144 uint16_t protocol = 0; 145 ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR, 146 ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0); 147 if (ret == 2) 148 printf("Device supports protocol version %d\n", protocol); 149 else 150 fprintf(stderr, "Failed to read protocol version\n"); 151 152 send_string(device, ACCESSORY_STRING_MANUFACTURER, "Android CTS"); 153 send_string(device, ACCESSORY_STRING_MODEL, "CTS USB Accessory"); 154 send_string(device, ACCESSORY_STRING_DESCRIPTION, "CTS USB Accessory"); 155 send_string(device, ACCESSORY_STRING_VERSION, "1.0"); 156 send_string(device, ACCESSORY_STRING_URI, 157 "http://source.android.com/compatibility/cts-intro.html"); 158 send_string(device, ACCESSORY_STRING_SERIAL, "1234567890"); 159 160 ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 161 ACCESSORY_START, 0, 0, 0, 0, 0); 162 return 0; 163 } 164 165 if (device != sDevice) 166 usb_device_close(device); 167 168 return 0; 169 } 170 171 static int usb_device_removed(const char *devname, void* client_data) { 172 if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) { 173 usb_device_close(sDevice); 174 sDevice = NULL; 175 // exit when we are disconnected 176 return 1; 177 } 178 return 0; 179 } 180 181 182 int main(int argc, char* argv[]) { 183 printf("CTS USB Accessory Tester\n"); 184 185 struct usb_host_context* context = usb_host_init(); 186 if (!context) { 187 fprintf(stderr, "usb_host_init failed"); 188 return 1; 189 } 190 191 // this will never return so it is safe to pass thiz directly 192 usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL); 193 return 0; 194 } 195