accessorychat.c revision ac36d7c715a9cd793b2dce6de547594810101c3a
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 28#include <usbhost/usbhost.h> 29#include <linux/usb/f_accessory.h> 30 31struct usb_device *sDevice = NULL; 32 33static void* read_thread(void* arg) { 34 int endpoint = (int)arg; 35 int ret = 0; 36 37 while (sDevice && ret >= 0) { 38 char buffer[16384]; 39 40 ret = usb_device_bulk_transfer(sDevice, endpoint, buffer, sizeof(buffer), 1000); 41 if (ret < 0 && errno == ETIMEDOUT) 42 ret = 0; 43 if (ret > 0) { 44 fwrite(buffer, 1, ret, stdout); 45 printf("\n"); 46 fflush(stdout); 47 } 48 } 49 50 return NULL; 51} 52 53static void* write_thread(void* arg) { 54 int endpoint = (int)arg; 55 int ret = 0; 56 57 while (ret >= 0) { 58 char buffer[16384]; 59 char *line = fgets(buffer, sizeof(buffer), stdin); 60 if (!line || !sDevice) 61 break; 62 ret = usb_device_bulk_transfer(sDevice, endpoint, line, strlen(line), 1000); 63 } 64 65 return NULL; 66} 67 68static void send_string(struct usb_device *device, int index, const char* string) { 69 int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 70 ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0); 71} 72 73static int usb_device_added(const char *devname, void* client_data) { 74 struct usb_descriptor_header* desc; 75 struct usb_descriptor_iter iter; 76 uint16_t vendorId, productId; 77 int ret; 78 pthread_t th; 79 80 struct usb_device *device = usb_device_open(devname); 81 if (!device) { 82 fprintf(stderr, "usb_device_open failed\n"); 83 return 0; 84 } 85 86 vendorId = usb_device_get_vendor_id(device); 87 productId = usb_device_get_product_id(device); 88 89 if (vendorId == 0x18D1 || vendorId == 0x22B8) { 90 if (!sDevice && (productId == 0x2D00 || productId == 0x2D01)) { 91 struct usb_descriptor_header* desc; 92 struct usb_descriptor_iter iter; 93 struct usb_interface_descriptor *intf = NULL; 94 struct usb_endpoint_descriptor *ep1 = NULL; 95 struct usb_endpoint_descriptor *ep2 = NULL; 96 97 printf("Found android device in accessory mode\n"); 98 sDevice = device; 99 100 usb_descriptor_iter_init(device, &iter); 101 while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) { 102 if (desc->bDescriptorType == USB_DT_INTERFACE) { 103 intf = (struct usb_interface_descriptor *)desc; 104 } else if (desc->bDescriptorType == USB_DT_ENDPOINT) { 105 if (ep1) 106 ep2 = (struct usb_endpoint_descriptor *)desc; 107 else 108 ep1 = (struct usb_endpoint_descriptor *)desc; 109 } 110 } 111 112 if (!intf) { 113 fprintf(stderr, "interface not found\n"); 114 exit(1); 115 } 116 if (!ep1 || !ep2) { 117 fprintf(stderr, "endpoints not found\n"); 118 exit(1); 119 } 120 121 if (usb_device_claim_interface(device, intf->bInterfaceNumber)) { 122 fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno); 123 exit(1); 124 } 125 126 if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { 127 pthread_create(&th, NULL, read_thread, (void *)ep1->bEndpointAddress); 128 pthread_create(&th, NULL, write_thread, (void *)ep2->bEndpointAddress); 129 } else { 130 pthread_create(&th, NULL, read_thread, (void *)ep2->bEndpointAddress); 131 pthread_create(&th, NULL, write_thread, (void *)ep1->bEndpointAddress); 132 } 133 } else { 134 printf("Found possible android device - attempting to switch to accessory mode\n"); 135 136 uint16_t protocol; 137 ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR, 138 ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0); 139 if (ret == 2) 140 printf("device supports protocol version %d\n", protocol); 141 else 142 fprintf(stderr, "failed to read protocol version\n"); 143 144 send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc."); 145 send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat"); 146 send_string(device, ACCESSORY_STRING_DESCRIPTION, "Sample Program"); 147 send_string(device, ACCESSORY_STRING_VERSION, "1.0"); 148 send_string(device, ACCESSORY_STRING_URI, "http://www.android.com"); 149 150 ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 151 ACCESSORY_START, 0, 0, 0, 0, 0); 152 return 0; 153 } 154 } 155 156 if (device != sDevice) 157 usb_device_close(device); 158 159 return 0; 160} 161 162static int usb_device_removed(const char *devname, void* client_data) { 163 if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) { 164 usb_device_close(sDevice); 165 sDevice = NULL; 166 // exit when we are disconnected 167 return 1; 168 } 169 return 0; 170} 171 172 173int main(int argc, char* argv[]) { 174 struct usb_host_context* context = usb_host_init(); 175 if (!context) { 176 fprintf(stderr, "usb_host_init failed"); 177 return 1; 178 } 179 180 // this will never return so it is safe to pass thiz directly 181 usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL); 182 return 0; 183} 184