diff options
Diffstat (limited to 'libs/usb')
-rw-r--r-- | libs/usb/Android.mk | 27 | ||||
-rw-r--r-- | libs/usb/src/com/android/future/usb/UsbAccessory.java (renamed from libs/usb/src/com/google/android/usb/UsbAccessory.java) | 2 | ||||
-rw-r--r-- | libs/usb/src/com/android/future/usb/UsbManager.java (renamed from libs/usb/src/com/google/android/usb/UsbManager.java) | 2 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/Android.mk | 31 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/AndroidManifest.xml | 39 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/README.txt | 10 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/accessorychat/Android.mk | 21 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c | 174 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/accessorychat/usbhost.c | 574 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h | 219 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml | 47 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml | 18 | ||||
-rw-r--r-- | libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java | 153 |
13 files changed, 1315 insertions, 2 deletions
diff --git a/libs/usb/Android.mk b/libs/usb/Android.mk new file mode 100644 index 0000000..129828f --- /dev/null +++ b/libs/usb/Android.mk @@ -0,0 +1,27 @@ +# +# Copyright (C) 2011 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under,src) + +LOCAL_MODULE_TAGS := optional + +LOCAL_MODULE:= com.android.future.usb.accessory + +include $(BUILD_JAVA_LIBRARY) diff --git a/libs/usb/src/com/google/android/usb/UsbAccessory.java b/libs/usb/src/com/android/future/usb/UsbAccessory.java index 931f42e..cdd2b73 100644 --- a/libs/usb/src/com/google/android/usb/UsbAccessory.java +++ b/libs/usb/src/com/android/future/usb/UsbAccessory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.google.android.usb; +package com.android.future.usb; /** * A class representing a USB accessory. diff --git a/libs/usb/src/com/google/android/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java index d7afb95..f74b291 100644 --- a/libs/usb/src/com/google/android/usb/UsbManager.java +++ b/libs/usb/src/com/android/future/usb/UsbManager.java @@ -15,7 +15,7 @@ */ -package com.google.android.usb; +package com.android.future.usb; import android.content.Context; import android.content.Intent; diff --git a/libs/usb/tests/AccessoryChat/Android.mk b/libs/usb/tests/AccessoryChat/Android.mk new file mode 100644 index 0000000..d555961 --- /dev/null +++ b/libs/usb/tests/AccessoryChat/Android.mk @@ -0,0 +1,31 @@ +# +# Copyright (C) 2011 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := AccessoryChatGB + +LOCAL_JAVA_LIBRARIES := com.android.future.usb.accessory + +# Force an old SDK version to make sure we aren't using newer UsbManager APIs +LOCAL_SDK_VERSION := 8 + +include $(BUILD_PACKAGE) diff --git a/libs/usb/tests/AccessoryChat/AndroidManifest.xml b/libs/usb/tests/AccessoryChat/AndroidManifest.xml new file mode 100644 index 0000000..d6093ae --- /dev/null +++ b/libs/usb/tests/AccessoryChat/AndroidManifest.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.accessorychat"> + + <application> + <uses-library android:name="com.android.future.usb.accessory" /> + + <activity android:name="AccessoryChat" android:label="Accessory Chat GB"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + + <intent-filter> + <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> + </intent-filter> + + <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" + android:resource="@xml/accessory_filter" /> + </activity> + </application> + <uses-sdk android:minSdkVersion="10" /> +</manifest> diff --git a/libs/usb/tests/AccessoryChat/README.txt b/libs/usb/tests/AccessoryChat/README.txt new file mode 100644 index 0000000..d2ce11e --- /dev/null +++ b/libs/usb/tests/AccessoryChat/README.txt @@ -0,0 +1,10 @@ +This is a test app for the USB accessory APIs. It consists of two parts: + +AccessoryChat - A Java app with a chat-like UI that sends and receives strings + via the UsbAccessory class. + +accessorychat - A C command-line program that communicates with AccessoryChat. + This program behaves as if it were a USB accessory. + It builds both for the host (Linux PC) and as an android + command line program, which will work if run as root on an + android device with USB host support diff --git a/libs/usb/tests/AccessoryChat/accessorychat/Android.mk b/libs/usb/tests/AccessoryChat/accessorychat/Android.mk new file mode 100644 index 0000000..5a7b30e --- /dev/null +++ b/libs/usb/tests/AccessoryChat/accessorychat/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:= $(call my-dir) + +# Build for Linux (desktop) host +ifeq ($(HOST_OS),linux) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := accessorychat.c usbhost.c + +LOCAL_MODULE := accessorychat + +LOCAL_C_INCLUDES += bionic/libc/kernel/common +LOCAL_STATIC_LIBRARIES := libcutils +LOCAL_LDLIBS += -lpthread +LOCAL_CFLAGS := -g -O0 + +include $(BUILD_HOST_EXECUTABLE) + +endif diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c new file mode 100644 index 0000000..94cc0ce --- /dev/null +++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2011 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 <unistd.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <pthread.h> + +#include <usbhost/usbhost.h> +#include <linux/usb/f_accessory.h> + +struct usb_device *sDevice = NULL; + +static void* read_thread(void* arg) { + int endpoint = (int)arg; + int ret = 0; + + while (sDevice && ret >= 0) { + char buffer[16384]; + + ret = usb_device_bulk_transfer(sDevice, endpoint, buffer, sizeof(buffer), 1000); + if (ret < 0 && errno == ETIMEDOUT) + ret = 0; + if (ret > 0) { + fwrite(buffer, 1, ret, stdout); + printf("\n"); + fflush(stdout); + } + } + + return NULL; +} + +static void* write_thread(void* arg) { + int endpoint = (int)arg; + int ret = 0; + + while (ret >= 0) { + char buffer[16384]; + char *line = fgets(buffer, sizeof(buffer), stdin); + if (!line || !sDevice) + break; + ret = usb_device_bulk_transfer(sDevice, endpoint, line, strlen(line), 1000); + } + + return NULL; +} + +static void send_string(struct usb_device *device, int index, const char* string) { + int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, + ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0); +} + +static int usb_device_added(const char *devname, void* client_data) { + struct usb_descriptor_header* desc; + struct usb_descriptor_iter iter; + uint16_t vendorId, productId; + int ret; + pthread_t th; + + 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 (vendorId == 0x18D1 || vendorId == 0x22B8) { + if (!sDevice && (productId == 0x2D00 || productId == 0x2D01)) { + 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; + + printf("Found android device in accessory mode\n"); + sDevice = device; + + 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) { + pthread_create(&th, NULL, read_thread, (void *)ep1->bEndpointAddress); + pthread_create(&th, NULL, write_thread, (void *)ep2->bEndpointAddress); + } else { + pthread_create(&th, NULL, read_thread, (void *)ep2->bEndpointAddress); + pthread_create(&th, NULL, write_thread, (void *)ep1->bEndpointAddress); + } + } else { + printf("Found possible android device - attempting to switch to accessory mode\n"); + + send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc."); + send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat"); + send_string(device, ACCESSORY_STRING_TYPE, "Sample Program"); + send_string(device, ACCESSORY_STRING_VERSION, "1.0"); + + ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, + ACCESSORY_START, 0, 0, 0, 0, 0); + return 0; + } + } + + if (device != sDevice) + usb_device_close(device); + + return 0; +} + +static int usb_device_removed(const char *devname, void* client_data) { + if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) { + usb_device_close(sDevice); + sDevice = NULL; + // exit when we are disconnected + return 1; + } + return 0; +} + + +int main(int argc, char* argv[]) { + struct usb_host_context* context = usb_host_init(); + if (!context) { + fprintf(stderr, "usb_host_init failed"); + return 1; + } + + // this will never return so it is safe to pass thiz directly + usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL); + return 0; +} diff --git a/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c b/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c new file mode 100644 index 0000000..f5a7c3f --- /dev/null +++ b/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c @@ -0,0 +1,574 @@ +/* + * Copyright (C) 2010 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. + */ + +// #define DEBUG 1 +#if DEBUG + +#ifdef USE_LIBLOG +#define LOG_TAG "usbhost" +#include "utils/Log.h" +#define D LOGD +#else +#define D printf +#endif + +#else +#define D(...) +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/inotify.h> +#include <dirent.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <pthread.h> + +#include <linux/usbdevice_fs.h> +#include <asm/byteorder.h> + +#include "usbhost/usbhost.h" + +#define USB_FS_DIR "/dev/bus/usb" +#define USB_FS_ID_SCANNER "/dev/bus/usb/%d/%d" +#define USB_FS_ID_FORMAT "/dev/bus/usb/%03d/%03d" + + +struct usb_host_context { + int fd; +}; + +struct usb_device { + char dev_name[64]; + unsigned char desc[4096]; + int desc_length; + int fd; + int writeable; +}; + +static inline int badname(const char *name) +{ + while(*name) { + if(!isdigit(*name++)) return 1; + } + return 0; +} + +/* returns true if one of the callbacks indicates we are done */ +static int find_existing_devices(usb_device_added_cb added_cb, + usb_device_removed_cb removed_cb, + void *client_data) +{ + char busname[32], devname[32]; + DIR *busdir , *devdir ; + struct dirent *de; + int done = 0; + + busdir = opendir(USB_FS_DIR); + if(busdir == 0) return 1; + + while ((de = readdir(busdir)) != 0 && !done) { + if(badname(de->d_name)) continue; + + snprintf(busname, sizeof busname, "%s/%s", USB_FS_DIR, de->d_name); + devdir = opendir(busname); + if(devdir == 0) continue; + + while ((de = readdir(devdir)) && !done) { + if(badname(de->d_name)) continue; + + snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name); + done = added_cb(devname, client_data); + } // end of devdir while + closedir(devdir); + } //end of busdir while + closedir(busdir); + + return done; +} + +struct usb_host_context *usb_host_init() +{ + struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context)); + if (!context) { + fprintf(stderr, "out of memory in usb_host_context\n"); + return NULL; + } + context->fd = inotify_init(); + if (context->fd < 0) { + fprintf(stderr, "inotify_init failed\n"); + free(context); + return NULL; + } + return context; +} + +void usb_host_cleanup(struct usb_host_context *context) +{ + close(context->fd); + free(context); +} + +void usb_host_run(struct usb_host_context *context, + usb_device_added_cb added_cb, + usb_device_removed_cb removed_cb, + usb_discovery_done_cb discovery_done_cb, + void *client_data) +{ + struct inotify_event* event; + char event_buf[512]; + char path[100]; + int i, ret, done = 0; + int wd, wds[10]; + int wd_count = sizeof(wds) / sizeof(wds[0]); + + D("Created device discovery thread\n"); + + /* watch for files added and deleted within USB_FS_DIR */ + memset(wds, 0, sizeof(wds)); + /* watch the root for new subdirectories */ + wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE); + if (wds[0] < 0) { + fprintf(stderr, "inotify_add_watch failed\n"); + if (discovery_done_cb) + discovery_done_cb(client_data); + return; + } + + /* watch existing subdirectories of USB_FS_DIR */ + for (i = 1; i < wd_count; i++) { + snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i); + ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE); + if (ret > 0) + wds[i] = ret; + } + + /* check for existing devices first, after we have inotify set up */ + done = find_existing_devices(added_cb, removed_cb, client_data); + if (discovery_done_cb) + done |= discovery_done_cb(client_data); + + while (!done) { + ret = read(context->fd, event_buf, sizeof(event_buf)); + if (ret >= (int)sizeof(struct inotify_event)) { + event = (struct inotify_event *)event_buf; + wd = event->wd; + if (wd == wds[0]) { + i = atoi(event->name); + snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name); + D("new subdirectory %s: index: %d\n", path, i); + if (i > 0 && i < wd_count) { + ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE); + if (ret > 0) + wds[i] = ret; + } + } else { + for (i = 1; i < wd_count && !done; i++) { + if (wd == wds[i]) { + snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name); + if (event->mask == IN_CREATE) { + D("new device %s\n", path); + done = added_cb(path, client_data); + } else if (event->mask == IN_DELETE) { + D("gone device %s\n", path); + done = removed_cb(path, client_data); + } + } + } + } + } + } +} + +struct usb_device *usb_device_open(const char *dev_name) +{ + int fd, did_retry = 0, writeable = 1; + + D("usb_device_open %s\n", dev_name); + +retry: + fd = open(dev_name, O_RDWR); + if (fd < 0) { + /* if we fail, see if have read-only access */ + fd = open(dev_name, O_RDONLY); + D("usb_device_open open returned %d errno %d\n", fd, errno); + if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) { + /* work around race condition between inotify and permissions management */ + sleep(1); + did_retry = 1; + goto retry; + } + + if (fd < 0) + return NULL; + writeable = 0; + D("[ usb open read-only %s fd = %d]\n", dev_name, fd); + } + + struct usb_device* result = usb_device_new(dev_name, fd); + if (result) + result->writeable = writeable; + return result; +} + +void usb_device_close(struct usb_device *device) +{ + close(device->fd); + free(device); +} + +struct usb_device *usb_device_new(const char *dev_name, int fd) +{ + struct usb_device *device = calloc(1, sizeof(struct usb_device)); + int length; + + D("usb_device_new %s fd: %d\n", dev_name, fd); + + if (lseek(fd, 0, SEEK_SET) != 0) + goto failed; + length = read(fd, device->desc, sizeof(device->desc)); + D("usb_device_new read returned %d errno %d\n", length, errno); + if (length < 0) + goto failed; + + strncpy(device->dev_name, dev_name, sizeof(device->dev_name) - 1); + device->fd = fd; + device->desc_length = length; + // assume we are writeable, since usb_device_get_fd will only return writeable fds + device->writeable = 1; + return device; + +failed: + close(fd); + free(device); + return NULL; +} + +static int usb_device_reopen_writeable(struct usb_device *device) +{ + if (device->writeable) + return 1; + + int fd = open(device->dev_name, O_RDWR); + if (fd >= 0) { + close(device->fd); + device->fd = fd; + device->writeable = 1; + return 1; + } + D("usb_device_reopen_writeable failed errno %d\n", errno); + return 0; +} + +int usb_device_get_fd(struct usb_device *device) +{ + if (!usb_device_reopen_writeable(device)) + return -1; + return device->fd; +} + +const char* usb_device_get_name(struct usb_device *device) +{ + return device->dev_name; +} + +int usb_device_get_unique_id(struct usb_device *device) +{ + int bus = 0, dev = 0; + sscanf(device->dev_name, USB_FS_ID_SCANNER, &bus, &dev); + return bus * 1000 + dev; +} + +int usb_device_get_unique_id_from_name(const char* name) +{ + int bus = 0, dev = 0; + sscanf(name, USB_FS_ID_SCANNER, &bus, &dev); + return bus * 1000 + dev; +} + +char* usb_device_get_name_from_unique_id(int id) +{ + int bus = id / 1000; + int dev = id % 1000; + char* result = (char *)calloc(1, strlen(USB_FS_ID_FORMAT)); + snprintf(result, strlen(USB_FS_ID_FORMAT) - 1, USB_FS_ID_FORMAT, bus, dev); + return result; +} + +uint16_t usb_device_get_vendor_id(struct usb_device *device) +{ + struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc; + return __le16_to_cpu(desc->idVendor); +} + +uint16_t usb_device_get_product_id(struct usb_device *device) +{ + struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc; + return __le16_to_cpu(desc->idProduct); +} + +const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device) +{ + return (struct usb_device_descriptor*)device->desc; +} + +char* usb_device_get_string(struct usb_device *device, int id) +{ + char string[256]; + __u16 buffer[128]; + __u16 languages[128]; + int i, result; + int languageCount = 0; + + string[0] = 0; + memset(languages, 0, sizeof(languages)); + + // read list of supported languages + result = usb_device_control_transfer(device, + USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR, + (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0); + if (result > 0) + languageCount = (result - 2) / 2; + + for (i = 1; i <= languageCount; i++) { + memset(buffer, 0, sizeof(buffer)); + + result = usb_device_control_transfer(device, + USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR, + (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0); + if (result > 0) { + int i; + // skip first word, and copy the rest to the string, changing shorts to bytes. + result /= 2; + for (i = 1; i < result; i++) + string[i - 1] = buffer[i]; + string[i - 1] = 0; + return strdup(string); + } + } + + return NULL; +} + +char* usb_device_get_manufacturer_name(struct usb_device *device) +{ + struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; + + if (desc->iManufacturer) + return usb_device_get_string(device, desc->iManufacturer); + else + return NULL; +} + +char* usb_device_get_product_name(struct usb_device *device) +{ + struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; + + if (desc->iProduct) + return usb_device_get_string(device, desc->iProduct); + else + return NULL; +} + +char* usb_device_get_serial(struct usb_device *device) +{ + struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; + + if (desc->iSerialNumber) + return usb_device_get_string(device, desc->iSerialNumber); + else + return NULL; +} + +int usb_device_is_writeable(struct usb_device *device) +{ + return device->writeable; +} + +void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter) +{ + iter->config = device->desc; + iter->config_end = device->desc + device->desc_length; + iter->curr_desc = device->desc; +} + +struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter) +{ + struct usb_descriptor_header* next; + if (iter->curr_desc >= iter->config_end) + return NULL; + next = (struct usb_descriptor_header*)iter->curr_desc; + iter->curr_desc += next->bLength; + return next; +} + +int usb_device_claim_interface(struct usb_device *device, unsigned int interface) +{ + return ioctl(device->fd, USBDEVFS_CLAIMINTERFACE, &interface); +} + +int usb_device_release_interface(struct usb_device *device, unsigned int interface) +{ + return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface); +} + +int usb_device_connect_kernel_driver(struct usb_device *device, + unsigned int interface, int connect) +{ + struct usbdevfs_ioctl ctl; + + ctl.ifno = interface; + ctl.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT); + ctl.data = NULL; + return ioctl(device->fd, USBDEVFS_IOCTL, &ctl); +} + +int usb_device_control_transfer(struct usb_device *device, + int requestType, + int request, + int value, + int index, + void* buffer, + int length, + unsigned int timeout) +{ + struct usbdevfs_ctrltransfer ctrl; + + // this usually requires read/write permission + if (!usb_device_reopen_writeable(device)) + return -1; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.bRequestType = requestType; + ctrl.bRequest = request; + ctrl.wValue = value; + ctrl.wIndex = index; + ctrl.wLength = length; + ctrl.data = buffer; + ctrl.timeout = timeout; + return ioctl(device->fd, USBDEVFS_CONTROL, &ctrl); +} + +int usb_device_bulk_transfer(struct usb_device *device, + int endpoint, + void* buffer, + int length, + unsigned int timeout) +{ + struct usbdevfs_bulktransfer ctrl; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.ep = endpoint; + ctrl.len = length; + ctrl.data = buffer; + ctrl.timeout = timeout; + return ioctl(device->fd, USBDEVFS_BULK, &ctrl); +} + +struct usb_request *usb_request_new(struct usb_device *dev, + const struct usb_endpoint_descriptor *ep_desc) +{ + struct usbdevfs_urb *urb = calloc(1, sizeof(struct usbdevfs_urb)); + if (!urb) + return NULL; + + if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) + urb->type = USBDEVFS_URB_TYPE_BULK; + else if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + urb->type = USBDEVFS_URB_TYPE_INTERRUPT; + else { + D("Unsupported endpoint type %d", ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + free(urb); + return NULL; + } + urb->endpoint = ep_desc->bEndpointAddress; + + struct usb_request *req = calloc(1, sizeof(struct usb_request)); + if (!req) { + free(urb); + return NULL; + } + + req->dev = dev; + req->max_packet_size = __le16_to_cpu(ep_desc->wMaxPacketSize); + req->private_data = urb; + req->endpoint = urb->endpoint; + urb->usercontext = req; + + return req; +} + +void usb_request_free(struct usb_request *req) +{ + free(req->private_data); + free(req); +} + +int usb_request_queue(struct usb_request *req) +{ + struct usbdevfs_urb *urb = (struct usbdevfs_urb*)req->private_data; + int res; + + urb->status = -1; + urb->buffer = req->buffer; + urb->buffer_length = req->buffer_length; + + do { + res = ioctl(req->dev->fd, USBDEVFS_SUBMITURB, urb); + } while((res < 0) && (errno == EINTR)); + + return res; +} + +struct usb_request *usb_request_wait(struct usb_device *dev) +{ + struct usbdevfs_urb *urb = NULL; + struct usb_request *req = NULL; + int res; + + while (1) { + int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb); + D("USBDEVFS_REAPURB returned %d\n", res); + if (res < 0) { + if(errno == EINTR) { + continue; + } + D("[ reap urb - error ]\n"); + return NULL; + } else { + D("[ urb @%p status = %d, actual = %d ]\n", + urb, urb->status, urb->actual_length); + req = (struct usb_request*)urb->usercontext; + req->actual_length = urb->actual_length; + } + break; + } + return req; +} + +int usb_request_cancel(struct usb_request *req) +{ + struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data); + return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, &urb); +} + diff --git a/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h b/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h new file mode 100644 index 0000000..9a6b59c --- /dev/null +++ b/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef __USB_HOST_H +#define __USB_HOST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +#include <linux/version.h> +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) +#include <linux/usb/ch9.h> +#else +#include <linux/usb_ch9.h> +#endif + +struct usb_host_context; +struct usb_endpoint_descriptor; + +struct usb_descriptor_iter { + unsigned char* config; + unsigned char* config_end; + unsigned char* curr_desc; +}; + +struct usb_request +{ + struct usb_device *dev; + void* buffer; + int buffer_length; + int actual_length; + int max_packet_size; + void *private_data; /* struct usbdevfs_urb* */ + int endpoint; + void *client_data; /* free for use by client */ +}; + +/* Callback for notification when new USB devices are attached. + * Return true to exit from usb_host_run. + */ +typedef int (* usb_device_added_cb)(const char *dev_name, void *client_data); + +/* Callback for notification when USB devices are removed. + * Return true to exit from usb_host_run. + */ +typedef int (* usb_device_removed_cb)(const char *dev_name, void *client_data); + +/* Callback indicating that initial device discovery is done. + * Return true to exit from usb_host_run. + */ +typedef int (* usb_discovery_done_cb)(void *client_data); + +/* Call this to initialize the USB host library. */ +struct usb_host_context *usb_host_init(void); + +/* Call this to cleanup the USB host library. */ +void usb_host_cleanup(struct usb_host_context *context); + +/* Call this to monitor the USB bus for new and removed devices. + * This is intended to be called from a dedicated thread, + * as it will not return until one of the callbacks returns true. + * added_cb will be called immediately for each existing USB device, + * and subsequently each time a new device is added. + * removed_cb is called when USB devices are removed from the bus. + * discovery_done_cb is called after the initial discovery of already + * connected devices is complete. + */ +void usb_host_run(struct usb_host_context *context, + usb_device_added_cb added_cb, + usb_device_removed_cb removed_cb, + usb_discovery_done_cb discovery_done_cb, + void *client_data); + +/* Creates a usb_device object for a USB device */ +struct usb_device *usb_device_open(const char *dev_name); + +/* Releases all resources associated with the USB device */ +void usb_device_close(struct usb_device *device); + +/* Creates a usb_device object for already open USB device */ +struct usb_device *usb_device_new(const char *dev_name, int fd); + +/* Returns the file descriptor for the usb_device */ +int usb_device_get_fd(struct usb_device *device); + +/* Returns the name for the USB device, which is the same as + * the dev_name passed to usb_device_open() + */ +const char* usb_device_get_name(struct usb_device *device); + +/* Returns a unique ID for the device. + *Currently this is generated from the dev_name path. + */ +int usb_device_get_unique_id(struct usb_device *device); + +/* Returns a unique ID for the device name. + * Currently this is generated from the device path. + */ +int usb_device_get_unique_id_from_name(const char* name); + +/* Returns the device name for the unique ID. + * Call free() to deallocate the returned string */ +char* usb_device_get_name_from_unique_id(int id); + +/* Returns the USB vendor ID from the device descriptor for the USB device */ +uint16_t usb_device_get_vendor_id(struct usb_device *device); + +/* Returns the USB product ID from the device descriptor for the USB device */ +uint16_t usb_device_get_product_id(struct usb_device *device); + +const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device); + +/* Returns a USB descriptor string for the given string ID. + * Used to implement usb_device_get_manufacturer_name, + * usb_device_get_product_name and usb_device_get_serial. + * Call free() to free the result when you are done with it. + */ +char* usb_device_get_string(struct usb_device *device, int id); + +/* Returns the manufacturer name for the USB device. + * Call free() to free the result when you are done with it. + */ +char* usb_device_get_manufacturer_name(struct usb_device *device); + +/* Returns the product name for the USB device. + * Call free() to free the result when you are done with it. + */ +char* usb_device_get_product_name(struct usb_device *device); + +/* Returns the USB serial number for the USB device. + * Call free() to free the result when you are done with it. + */ +char* usb_device_get_serial(struct usb_device *device); + +/* Returns true if we have write access to the USB device, + * and false if we only have access to the USB device configuration. + */ +int usb_device_is_writeable(struct usb_device *device); + +/* Initializes a usb_descriptor_iter, which can be used to iterate through all + * the USB descriptors for a USB device. + */ +void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter); + +/* Returns the next USB descriptor for a device, or NULL if we have reached the + * end of the list. + */ +struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter); + +/* Claims the specified interface of a USB device */ +int usb_device_claim_interface(struct usb_device *device, unsigned int interface); + +/* Releases the specified interface of a USB device */ +int usb_device_release_interface(struct usb_device *device, unsigned int interface); + +/* Requests the kernel to connect or disconnect its driver for the specified interface. + * This can be used to ask the kernel to disconnect its driver for a device + * so usb_device_claim_interface can claim it instead. + */ +int usb_device_connect_kernel_driver(struct usb_device *device, + unsigned int interface, int connect); + +/* Sends a control message to the specified device on endpoint zero */ +int usb_device_control_transfer(struct usb_device *device, + int requestType, + int request, + int value, + int index, + void* buffer, + int length, + unsigned int timeout); + +/* Reads or writes on a bulk endpoint. + * Returns number of bytes transferred, or negative value for error. + */ +int usb_device_bulk_transfer(struct usb_device *device, + int endpoint, + void* buffer, + int length, + unsigned int timeout); + +/* Creates a new usb_request. */ +struct usb_request *usb_request_new(struct usb_device *dev, + const struct usb_endpoint_descriptor *ep_desc); + +/* Releases all resources associated with the request */ +void usb_request_free(struct usb_request *req); + +/* Submits a read or write request on the specified device */ +int usb_request_queue(struct usb_request *req); + + /* Waits for the results of a previous usb_request_queue operation. + * Returns a usb_request, or NULL for error. + */ +struct usb_request *usb_request_wait(struct usb_device *dev); + +/* Cancels a pending usb_request_queue() operation. */ +int usb_request_cancel(struct usb_request *req); + +#ifdef __cplusplus +} +#endif +#endif /* __USB_HOST_H */ diff --git a/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml b/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml new file mode 100644 index 0000000..596ecbf --- /dev/null +++ b/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + > + + <ScrollView android:id="@+id/scroll" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1" + > + <TextView android:id="@+id/log" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="25dp" + android:textSize="12sp" + android:textColor="#ffffffff" + /> + </ScrollView> + + <EditText android:id="@+id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:capitalize="sentences" + android:autoText="true" + android:singleLine="true" + /> + +</LinearLayout> + + diff --git a/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml b/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml new file mode 100644 index 0000000..588946f --- /dev/null +++ b/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 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. +--> +<resources> + <usb-accessory manufacturer="Google, Inc." model="AccessoryChat" type="Sample Program" version="1.0" /> +</resources> diff --git a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java new file mode 100644 index 0000000..5cf02c7 --- /dev/null +++ b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 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. + */ + +package com.android.accessorychat; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.util.Log; +import android.widget.EditText; +import android.widget.TextView; + +import com.android.future.usb.UsbAccessory; +import com.android.future.usb.UsbManager; + +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener { + + private static final String TAG = "AccessoryChat"; + TextView mLog; + EditText mEditText; + ParcelFileDescriptor mFileDescriptor; + FileInputStream mInputStream; + FileOutputStream mOutputStream; + + private static final int MESSAGE_LOG = 1; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.accessory_chat); + mLog = (TextView)findViewById(R.id.log); + mEditText = (EditText)findViewById(R.id.message); + mEditText.setOnEditorActionListener(this); + } + + @Override + public void onResume() { + super.onResume(); + + Intent intent = getIntent(); + Log.d(TAG, "intent: " + intent); + UsbManager manager = UsbManager.getInstance(); + UsbAccessory[] accessories = manager.getAccessoryList(); + UsbAccessory accessory = (accessories == null ? null : accessories[0]); + if (accessory != null) { + mFileDescriptor = manager.openAccessory(accessory); + if (mFileDescriptor != null) { + FileDescriptor fd = mFileDescriptor.getFileDescriptor(); + mInputStream = new FileInputStream(fd); + mOutputStream = new FileOutputStream(fd); + Thread thread = new Thread(null, this, "AccessoryChat"); + thread.start(); + } else { + Log.d(TAG, "openAccessory fail"); + } + } else { + Log.d(TAG, "mAccessory is null"); + } + } + + @Override + public void onPause() { + super.onPause(); + if (mFileDescriptor != null) { + try { + mFileDescriptor.close(); + } catch (IOException e) { + } finally { + mFileDescriptor = null; + } + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) { + try { + mOutputStream.write(v.getText().toString().getBytes()); + } catch (IOException e) { + Log.e(TAG, "write failed", e); + } + v.setText(""); + return true; + } + Log.d(TAG, "onEditorAction " + actionId + " event: " + event); + return false; + } + + public void run() { + int ret = 0; + byte[] buffer = new byte[16384]; + while (ret >= 0) { + try { + ret = mInputStream.read(buffer); + } catch (IOException e) { + break; + } + + if (ret > 0) { + Message m = Message.obtain(mHandler, MESSAGE_LOG); + String text = new String(buffer, 0, ret); + Log.d(TAG, "chat: " + text); + m.obj = text; + mHandler.sendMessage(m); + } + } + Log.d(TAG, "thread out"); + } + + Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_LOG: + mLog.setText(mLog.getText() + "\n" + (String)msg.obj); + break; + } + } + }; +} + + |