Merge from AOSP staging branch

Change-Id: I28f72f7c361eaa4a0fae671e988b52708cb9e3af
This commit is contained in:
Jean-Baptiste Queru 2012-12-18 15:17:57 -08:00
commit 22e9136661
3 changed files with 128 additions and 65 deletions

View file

@ -72,6 +72,19 @@ struct usb_host_context *usb_host_init(void);
/* Call this to cleanup the USB host library. */ /* Call this to cleanup the USB host library. */
void usb_host_cleanup(struct usb_host_context *context); void usb_host_cleanup(struct usb_host_context *context);
/* Call this to get the inotify file descriptor. */
int usb_host_get_fd(struct usb_host_context *context);
/* Call this to initialize the usb host context. */
int usb_host_load(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);
/* Call this to read and handle occuring usb event. */
int usb_host_read_event(struct usb_host_context *context);
/* Call this to monitor the USB bus for new and removed devices. /* Call this to monitor the USB bus for new and removed devices.
* This is intended to be called from a dedicated thread, * This is intended to be called from a dedicated thread,
* as it will not return until one of the callbacks returns true. * as it will not return until one of the callbacks returns true.

View file

@ -44,3 +44,13 @@ LOCAL_CFLAGS := -g -DUSE_LIBLOG
LOCAL_SHARED_LIBRARIES := libcutils LOCAL_SHARED_LIBRARIES := libcutils
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)
# Static library for target
# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := libusbhost
LOCAL_SRC_FILES := usbhost.c
include $(BUILD_STATIC_LIBRARY)

View file

@ -33,6 +33,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <stddef.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/types.h> #include <sys/types.h>
@ -50,16 +51,23 @@
#include "usbhost/usbhost.h" #include "usbhost/usbhost.h"
#define DEV_DIR "/dev" #define DEV_DIR "/dev"
#define USB_FS_DIR "/dev/bus/usb" #define USB_FS_DIR DEV_DIR "/bus/usb"
#define USB_FS_ID_SCANNER "/dev/bus/usb/%d/%d" #define USB_FS_ID_SCANNER USB_FS_DIR "/%d/%d"
#define USB_FS_ID_FORMAT "/dev/bus/usb/%03d/%03d" #define USB_FS_ID_FORMAT USB_FS_DIR "/%03d/%03d"
// From drivers/usb/core/devio.c // From drivers/usb/core/devio.c
// I don't know why this isn't in a kernel header // I don't know why this isn't in a kernel header
#define MAX_USBFS_BUFFER_SIZE 16384 #define MAX_USBFS_BUFFER_SIZE 16384
#define MAX_USBFS_WD_COUNT 10
struct usb_host_context { struct usb_host_context {
int fd; int fd;
usb_device_added_cb cb_added;
usb_device_removed_cb cb_removed;
void *data;
int wds[MAX_USBFS_WD_COUNT];
int wdd;
}; };
struct usb_device { struct usb_device {
@ -116,10 +124,10 @@ static int find_existing_devices(usb_device_added_cb added_cb,
while ((de = readdir(busdir)) != 0 && !done) { while ((de = readdir(busdir)) != 0 && !done) {
if(badname(de->d_name)) continue; if(badname(de->d_name)) continue;
snprintf(busname, sizeof(busname), "%s/%s", USB_FS_DIR, de->d_name); snprintf(busname, sizeof(busname), USB_FS_DIR "/%s", de->d_name);
done = find_existing_devices_bus(busname, added_cb, done = find_existing_devices_bus(busname, added_cb,
client_data); client_data);
} } //end of busdir while
closedir(busdir); closedir(busdir);
return done; return done;
@ -137,7 +145,7 @@ static void watch_existing_subdirs(struct usb_host_context *context,
/* watch existing subdirectories of USB_FS_DIR */ /* watch existing subdirectories of USB_FS_DIR */
for (i = 1; i < wd_count; i++) { for (i = 1; i < wd_count; i++) {
snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i); snprintf(path, sizeof(path), USB_FS_DIR "/%03d", i);
ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE); ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
if (ret >= 0) if (ret >= 0)
wds[i] = ret; wds[i] = ret;
@ -166,93 +174,126 @@ void usb_host_cleanup(struct usb_host_context *context)
free(context); free(context);
} }
void usb_host_run(struct usb_host_context *context, int usb_host_get_fd(struct usb_host_context *context)
{
return context->fd;
} /* usb_host_get_fd() */
int usb_host_load(struct usb_host_context *context,
usb_device_added_cb added_cb, usb_device_added_cb added_cb,
usb_device_removed_cb removed_cb, usb_device_removed_cb removed_cb,
usb_discovery_done_cb discovery_done_cb, usb_discovery_done_cb discovery_done_cb,
void *client_data) void *client_data)
{ {
struct inotify_event* event; int done = 0;
char event_buf[512]; int i;
char path[100];
int i, ret, done = 0; context->cb_added = added_cb;
int wd, wdd, wds[10]; context->cb_removed = removed_cb;
int wd_count = sizeof(wds) / sizeof(wds[0]); context->data = client_data;
D("Created device discovery thread\n"); D("Created device discovery thread\n");
/* watch for files added and deleted within USB_FS_DIR */ /* watch for files added and deleted within USB_FS_DIR */
for (i = 0; i < wd_count; i++) for (i = 0; i < MAX_USBFS_WD_COUNT; i++)
wds[i] = -1; context->wds[i] = -1;
/* watch the root for new subdirectories */ /* watch the root for new subdirectories */
wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE); context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
if (wdd < 0) { if (context->wdd < 0) {
fprintf(stderr, "inotify_add_watch failed\n"); fprintf(stderr, "inotify_add_watch failed\n");
if (discovery_done_cb) if (discovery_done_cb)
discovery_done_cb(client_data); discovery_done_cb(client_data);
return; return done;
} }
watch_existing_subdirs(context, wds, wd_count); watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
/* check for existing devices first, after we have inotify set up */ /* check for existing devices first, after we have inotify set up */
done = find_existing_devices(added_cb, client_data); done = find_existing_devices(added_cb, client_data);
if (discovery_done_cb) if (discovery_done_cb)
done |= discovery_done_cb(client_data); done |= discovery_done_cb(client_data);
while (!done) { return done;
ret = read(context->fd, event_buf, sizeof(event_buf)); } /* usb_host_load() */
if (ret >= (int)sizeof(struct inotify_event)) {
event = (struct inotify_event *)event_buf; int usb_host_read_event(struct usb_host_context *context)
wd = event->wd; {
if (wd == wdd) { struct inotify_event* event;
if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) { char event_buf[512];
watch_existing_subdirs(context, wds, wd_count); char path[100];
done = find_existing_devices(added_cb, client_data); int i, ret, done = 0;
} else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) { int j, event_size;
for (i = 0; i < wd_count; i++) { int wd;
if (wds[i] >= 0) {
inotify_rm_watch(context->fd, wds[i]); ret = read(context->fd, event_buf, sizeof(event_buf));
wds[i] = -1; if (ret >= (int)sizeof(struct inotify_event)) {
} event = (struct inotify_event *)event_buf;
wd = event->wd;
if (wd == context->wdd) {
if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
done = find_existing_devices(context->cb_added, context->data);
} else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {
if (context->wds[i] >= 0) {
inotify_rm_watch(context->fd, context->wds[i]);
context->wds[i] = -1;
} }
} }
} else if (wd == wds[0]) { }
i = atoi(event->name); } else if (wd == context->wds[0]) {
snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name); i = atoi(event->name);
D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ? snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);
"new" : "gone", path, i); D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
if (i > 0 && i < wd_count) { "new" : "gone", path, i);
if (event->mask & IN_CREATE) { if (i > 0 && i < MAX_USBFS_WD_COUNT) {
ret = inotify_add_watch(context->fd, path, if (event->mask & IN_CREATE) {
IN_CREATE | IN_DELETE); ret = inotify_add_watch(context->fd, path,
if (ret >= 0) IN_CREATE | IN_DELETE);
wds[i] = ret; if (ret >= 0)
done = find_existing_devices_bus(path, added_cb, context->wds[i] = ret;
client_data); done = find_existing_devices_bus(path, context->cb_added,
} else if (event->mask & IN_DELETE) { context->data);
inotify_rm_watch(context->fd, wds[i]); } else if (event->mask & IN_DELETE) {
wds[i] = -1; inotify_rm_watch(context->fd, context->wds[i]);
} context->wds[i] = -1;
} }
} else { }
for (i = 1; i < wd_count && !done; i++) { } else {
if (wd == wds[i]) { for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {
snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name); if (wd == context->wds[i]) {
if (event->mask == IN_CREATE) { snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name);
D("new device %s\n", path); if (event->mask == IN_CREATE) {
done = added_cb(path, client_data); D("new device %s\n", path);
} else if (event->mask == IN_DELETE) { done = context->cb_added(path, context->data);
D("gone device %s\n", path); } else if (event->mask == IN_DELETE) {
done = removed_cb(path, client_data); D("gone device %s\n", path);
} done = context->cb_removed(path, context->data);
} }
} }
} }
} }
} }
}
return done;
} /* usb_host_read_event() */
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)
{
int done;
done = usb_host_load(context, added_cb, removed_cb, discovery_done_cb, client_data);
while (!done) {
done = usb_host_read_event(context);
}
} /* usb_host_run() */
struct usb_device *usb_device_open(const char *dev_name) struct usb_device *usb_device_open(const char *dev_name)
{ {
@ -606,7 +647,6 @@ struct usb_request *usb_request_wait(struct usb_device *dev)
{ {
struct usbdevfs_urb *urb = NULL; struct usbdevfs_urb *urb = NULL;
struct usb_request *req = NULL; struct usb_request *req = NULL;
int res;
while (1) { while (1) {
int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb); int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);