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) {
35f5df700e6ce056ebfa322314d970e52d6facc35aAshok Bhat    int endpoint = (int)(uintptr_t)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) {
55f5df700e6ce056ebfa322314d970e52d6facc35aAshok Bhat    int endpoint = (int)(uintptr_t)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) {
139f5df700e6ce056ebfa322314d970e52d6facc35aAshok Bhat                pthread_create(&th, NULL, read_thread, (void *)(uintptr_t)ep1->bEndpointAddress);
140f5df700e6ce056ebfa322314d970e52d6facc35aAshok Bhat                pthread_create(&th, NULL, write_thread, (void *)(uintptr_t)ep2->bEndpointAddress);
14127555315629ffce59a19bd03ba51a8323cc864b0Mike Lockwood            } else {
142f5df700e6ce056ebfa322314d970e52d6facc35aAshok Bhat                pthread_create(&th, NULL, read_thread, (void *)(uintptr_t)ep2->bEndpointAddress);
143f5df700e6ce056ebfa322314d970e52d6facc35aAshok Bhat                pthread_create(&th, NULL, write_thread, (void *)(uintptr_t)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