diff options
Diffstat (limited to 'libs/usb/tests/accessorytest/usb.c')
| -rw-r--r-- | libs/usb/tests/accessorytest/usb.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/libs/usb/tests/accessorytest/usb.c b/libs/usb/tests/accessorytest/usb.c new file mode 100644 index 0000000..ac72b35 --- /dev/null +++ b/libs/usb/tests/accessorytest/usb.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <signal.h> +#include <pthread.h> +#include <errno.h> +#include <string.h> + +#include <usbhost/usbhost.h> +#include "f_accessory.h" + +#include "accessory.h" + +static struct usb_device *current_device = NULL; +static uint8_t read_ep; +static uint8_t write_ep; + +static pthread_mutex_t device_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t device_cond = PTHREAD_COND_INITIALIZER; + +static void milli_sleep(int millis) { + struct timespec tm; + + tm.tv_sec = 0; + tm.tv_nsec = millis * 1000000; + nanosleep(&tm, NULL); +} + +static void* read_thread(void* arg) { + int ret = 0; + + while (current_device && ret >= 0) { + char buffer[16384]; + + ret = usb_device_bulk_transfer(current_device, read_ep, buffer, sizeof(buffer), 1000); + if (ret < 0 && errno == ETIMEDOUT) + ret = 0; + if (ret > 0) { + fwrite(buffer, 1, ret, stdout); + fprintf(stderr, "\n"); + fflush(stdout); + } + } + + return NULL; +} + +static void* write_thread(void* arg) { + int ret = 0; + + while (ret >= 0) { + char buffer[16384]; + char *line = fgets(buffer, sizeof(buffer), stdin); + if (!line || !current_device) + break; + ret = usb_device_bulk_transfer(current_device, write_ep, line, strlen(line), 1000); + } + + return NULL; +} + +static void send_string(struct usb_device *device, int index, const char* string) { + usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, + ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0); + + // some devices can't handle back-to-back requests, so delay a bit + milli_sleep(10); +} + +static int usb_device_added(const char *devname, void* client_data) { + uint16_t vendorId, productId; + int ret; + int enable_accessory = (int)client_data; + + struct usb_device *device = usb_device_open(devname); + if (!device) { + fprintf(stderr, "usb_device_open failed\n"); + return 0; + } + + vendorId = usb_device_get_vendor_id(device); + productId = usb_device_get_product_id(device); + + if (!current_device && vendorId == 0x18D1 && productId >= 0x2D00 && productId <= 0x2D05) { + + pthread_mutex_lock(&device_mutex); + fprintf(stderr, "Found android device in accessory mode\n"); + current_device = device; + pthread_cond_broadcast(&device_cond); + pthread_mutex_unlock(&device_mutex); + + if (enable_accessory) { + struct usb_descriptor_header* desc; + struct usb_descriptor_iter iter; + struct usb_interface_descriptor *intf = NULL; + struct usb_endpoint_descriptor *ep1 = NULL; + struct usb_endpoint_descriptor *ep2 = NULL; + pthread_t th; + + usb_descriptor_iter_init(device, &iter); + while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) { + if (desc->bDescriptorType == USB_DT_INTERFACE) { + intf = (struct usb_interface_descriptor *)desc; + } else if (desc->bDescriptorType == USB_DT_ENDPOINT) { + if (ep1) + ep2 = (struct usb_endpoint_descriptor *)desc; + else + ep1 = (struct usb_endpoint_descriptor *)desc; + } + } + + if (!intf) { + fprintf(stderr, "interface not found\n"); + exit(1); + } + if (!ep1 || !ep2) { + fprintf(stderr, "endpoints not found\n"); + exit(1); + } + + if (usb_device_claim_interface(device, intf->bInterfaceNumber)) { + fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno); + exit(1); + } + + if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { + read_ep = ep1->bEndpointAddress; + write_ep = ep2->bEndpointAddress; + } else { + read_ep = ep2->bEndpointAddress; + write_ep = ep1->bEndpointAddress; + } + + pthread_create(&th, NULL, read_thread, NULL); + pthread_create(&th, NULL, write_thread, NULL); + } + } else { +// fprintf(stderr, "Found new device - attempting to switch to accessory mode\n"); + + uint16_t protocol = -1; + ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR, + ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 1000); + if (ret < 0) { + // fprintf(stderr, "ACCESSORY_GET_PROTOCOL returned %d errno: %d\n", ret, errno); + } else { + fprintf(stderr, "device supports protocol version %d\n", protocol); + if (protocol >= 2) { + if (enable_accessory) { + send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc."); + send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat"); + send_string(device, ACCESSORY_STRING_DESCRIPTION, "Accessory Chat"); + send_string(device, ACCESSORY_STRING_VERSION, "1.0"); + send_string(device, ACCESSORY_STRING_URI, "http://www.android.com"); + send_string(device, ACCESSORY_STRING_SERIAL, "1234567890"); + } + + fprintf(stderr, "sending ACCESSORY_SET_AUDIO_MODE\n"); + ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, + ACCESSORY_SET_AUDIO_MODE, 1, 0, NULL, 0, 1000); + if (ret < 0) + fprintf(stderr, "ACCESSORY_SET_AUDIO_MODE returned %d errno: %d\n", ret, errno); + + fprintf(stderr, "sending ACCESSORY_START\n"); + ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, + ACCESSORY_START, 0, 0, NULL, 0, 1000); + fprintf(stderr, "did ACCESSORY_START\n"); + if (ret < 0) + fprintf(stderr, "ACCESSORY_START returned %d errno: %d\n", ret, errno); + } + } + + return 0; + } + + if (device != current_device) + usb_device_close(device); + + return 0; +} + +static int usb_device_removed(const char *devname, void* client_data) { + pthread_mutex_lock(&device_mutex); + + if (current_device && !strcmp(usb_device_get_name(current_device), devname)) { + fprintf(stderr, "current device disconnected\n"); + usb_device_close(current_device); + current_device = NULL; + } + + pthread_mutex_unlock(&device_mutex); + return 0; +} + +struct usb_device* usb_wait_for_device() { + struct usb_device* device = NULL; + + pthread_mutex_lock(&device_mutex); + while (!current_device) + pthread_cond_wait(&device_cond, &device_mutex); + device = current_device; + pthread_mutex_unlock(&device_mutex); + + return device; +} + +void usb_run(int enable_accessory) { + struct usb_host_context* context = usb_host_init(); + + usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)enable_accessory); +} + |
