127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood/* 227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * Copyright (C) 2011 The Android Open Source Project 327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * 427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * you may not use this file except in compliance with the License. 627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * You may obtain a copy of the License at 727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * 827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * 1027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * Unless required by applicable law or agreed to in writing, software 1127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 1227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * See the License for the specific language governing permissions and 1427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood * limitations under the License. 1527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood */ 1627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 1727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <unistd.h> 1827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <stdio.h> 1927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <string.h> 2027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <stdlib.h> 2127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 2227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <sys/types.h> 2327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <sys/stat.h> 2427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <fcntl.h> 2527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <errno.h> 2627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <pthread.h> 27015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwood#include <time.h> 2827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 2927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <usbhost/usbhost.h> 3027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood#include <linux/usb/f_accessory.h> 3127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 3227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwoodstruct usb_device *sDevice = NULL; 3327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 3427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwoodstatic void* read_thread(void* arg) { 3527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood int endpoint = (int)arg; 3627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood int ret = 0; 3727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 3827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood while (sDevice && ret >= 0) { 3927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood char buffer[16384]; 4027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 4127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood ret = usb_device_bulk_transfer(sDevice, endpoint, buffer, sizeof(buffer), 1000); 4227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (ret < 0 && errno == ETIMEDOUT) 4327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood ret = 0; 4427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (ret > 0) { 4527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood fwrite(buffer, 1, ret, stdout); 4627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood printf("\n"); 4727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood fflush(stdout); 4827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 4927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 5027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 5127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return NULL; 5227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood} 5327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 5427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwoodstatic void* write_thread(void* arg) { 5527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood int endpoint = (int)arg; 5627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood int ret = 0; 5727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 5827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood while (ret >= 0) { 5927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood char buffer[16384]; 6027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood char *line = fgets(buffer, sizeof(buffer), stdin); 6127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (!line || !sDevice) 6227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood break; 6327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood ret = usb_device_bulk_transfer(sDevice, endpoint, line, strlen(line), 1000); 6427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 6527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 6627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return NULL; 6727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood} 6827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 69015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwoodstatic void milli_sleep(int millis) { 70ad5f83e91b6812a6dee4fea7646fa9061d9f9597Mike Lockwood struct timespec tm; 71015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwood 72ad5f83e91b6812a6dee4fea7646fa9061d9f9597Mike Lockwood tm.tv_sec = 0; 73ad5f83e91b6812a6dee4fea7646fa9061d9f9597Mike Lockwood tm.tv_nsec = millis * 1000000; 74ad5f83e91b6812a6dee4fea7646fa9061d9f9597Mike Lockwood nanosleep(&tm, NULL); 75015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwood} 76015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwood 7727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwoodstatic void send_string(struct usb_device *device, int index, const char* string) { 7827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 7927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0); 80015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwood 81015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwood // some devices can't handle back-to-back requests, so delay a bit 82015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwood milli_sleep(10); 8327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood} 8427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 8527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwoodstatic int usb_device_added(const char *devname, void* client_data) { 8627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_descriptor_header* desc; 8727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_descriptor_iter iter; 8827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood uint16_t vendorId, productId; 8927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood int ret; 9027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood pthread_t th; 9127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 9227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_device *device = usb_device_open(devname); 9327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (!device) { 9427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood fprintf(stderr, "usb_device_open failed\n"); 9527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return 0; 9627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 9727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 9827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood vendorId = usb_device_get_vendor_id(device); 9927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood productId = usb_device_get_product_id(device); 10027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 101c92e6f14f9ac6c86b7784f8a21d7077ea7cae0bbSimon Wilson if (vendorId == 0x18D1 || vendorId == 0x22B8 || vendorId == 0x04e8) { 10227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (!sDevice && (productId == 0x2D00 || productId == 0x2D01)) { 10327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_descriptor_header* desc; 10427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_descriptor_iter iter; 10527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_interface_descriptor *intf = NULL; 10627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_endpoint_descriptor *ep1 = NULL; 10727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_endpoint_descriptor *ep2 = NULL; 10827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 10927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood printf("Found android device in accessory mode\n"); 11027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood sDevice = device; 11127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 11227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood usb_descriptor_iter_init(device, &iter); 11327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) { 11427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (desc->bDescriptorType == USB_DT_INTERFACE) { 11527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood intf = (struct usb_interface_descriptor *)desc; 11627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } else if (desc->bDescriptorType == USB_DT_ENDPOINT) { 11727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (ep1) 11827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood ep2 = (struct usb_endpoint_descriptor *)desc; 11927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood else 12027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood ep1 = (struct usb_endpoint_descriptor *)desc; 12127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 12227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 12327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 12427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (!intf) { 12527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood fprintf(stderr, "interface not found\n"); 12627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood exit(1); 12727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 12827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (!ep1 || !ep2) { 12927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood fprintf(stderr, "endpoints not found\n"); 13027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood exit(1); 13127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 13227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 13327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (usb_device_claim_interface(device, intf->bInterfaceNumber)) { 13427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno); 13527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood exit(1); 13627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 13727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 13827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { 13927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood pthread_create(&th, NULL, read_thread, (void *)ep1->bEndpointAddress); 14027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood pthread_create(&th, NULL, write_thread, (void *)ep2->bEndpointAddress); 14127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } else { 14227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood pthread_create(&th, NULL, read_thread, (void *)ep2->bEndpointAddress); 14327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood pthread_create(&th, NULL, write_thread, (void *)ep1->bEndpointAddress); 14427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 14527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } else { 14627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood printf("Found possible android device - attempting to switch to accessory mode\n"); 14727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 148ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood uint16_t protocol; 149ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR, 150ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0); 151ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood if (ret == 2) 152ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood printf("device supports protocol version %d\n", protocol); 153ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood else 154ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood fprintf(stderr, "failed to read protocol version\n"); 155ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood 15627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc."); 15727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat"); 158ad5f83e91b6812a6dee4fea7646fa9061d9f9597Mike Lockwood send_string(device, ACCESSORY_STRING_DESCRIPTION, "Accessory Chat"); 15927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood send_string(device, ACCESSORY_STRING_VERSION, "1.0"); 160ac36d7c715a9cd793b2dce6de547594810101c3aMike Lockwood send_string(device, ACCESSORY_STRING_URI, "http://www.android.com"); 161015b1ecaec27b7cf5f1a78099d9ae34a0c3169f2Mike Lockwood send_string(device, ACCESSORY_STRING_SERIAL, "1234567890"); 16227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 16327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, 16427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood ACCESSORY_START, 0, 0, 0, 0, 0); 16527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return 0; 16627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 16727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 16827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 16927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (device != sDevice) 17027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood usb_device_close(device); 17127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 17227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return 0; 17327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood} 17427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 17527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwoodstatic int usb_device_removed(const char *devname, void* client_data) { 17627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) { 17727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood usb_device_close(sDevice); 17827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood sDevice = NULL; 17927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood // exit when we are disconnected 18027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return 1; 18127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 18227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return 0; 18327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood} 18427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 18527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 18627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwoodint main(int argc, char* argv[]) { 18727555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood struct usb_host_context* context = usb_host_init(); 18827555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood if (!context) { 18927555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood fprintf(stderr, "usb_host_init failed"); 19027555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return 1; 19127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood } 19227555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood 19327555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood // this will never return so it is safe to pass thiz directly 19427555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL); 19527555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood return 0; 19627555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood} 197