libusbhost: The client is now responsible for creating the thread that monitors the bus
This is to allow using a thread that is capable of calling through JNI to Java code to report USB device attached/removed events. Change-Id: Ia58592607a2c1f4357b31072044f5db5617d7f5b Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
parent
4272a7ad70
commit
7a96ba436c
2 changed files with 69 additions and 53 deletions
|
|
@ -23,6 +23,7 @@ extern "C" {
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
struct usb_host_context;
|
||||
struct usb_endpoint_descriptor;
|
||||
|
||||
struct usb_descriptor_iter {
|
||||
|
|
@ -31,18 +32,31 @@ struct usb_descriptor_iter {
|
|||
unsigned char* curr_desc;
|
||||
};
|
||||
|
||||
/* callback for notification when new USB devices are attached */
|
||||
typedef void (* usb_device_added_cb)(const char *dev_name, void *client_data);
|
||||
/* 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 */
|
||||
typedef void (* usb_device_removed_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);
|
||||
|
||||
/* Call this to start monitoring the USB bus.
|
||||
/* 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.
|
||||
*/
|
||||
int usb_host_init(usb_device_added_cb added_cb,
|
||||
void usb_host_run(struct usb_host_context *context,
|
||||
usb_device_added_cb added_cb,
|
||||
usb_device_removed_cb removed_cb,
|
||||
void *client_data);
|
||||
|
||||
|
|
|
|||
|
|
@ -60,9 +60,7 @@
|
|||
|
||||
|
||||
struct usb_host_context {
|
||||
usb_device_added_cb added_cb;
|
||||
usb_device_removed_cb removed_cb;
|
||||
void *client_data;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct usb_device {
|
||||
|
|
@ -88,73 +86,97 @@ static inline int badname(const char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void find_existing_devices(struct usb_host_context *context)
|
||||
/* 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;
|
||||
if(busdir == 0) return 1;
|
||||
|
||||
while((de = readdir(busdir)) != 0) {
|
||||
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))) {
|
||||
while ((de = readdir(devdir)) && !done) {
|
||||
if(badname(de->d_name)) continue;
|
||||
|
||||
snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
|
||||
context->added_cb(devname, context->client_data);
|
||||
done = added_cb(devname, client_data);
|
||||
} // end of devdir while
|
||||
closedir(devdir);
|
||||
} //end of busdir while
|
||||
closedir(busdir);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
static void* device_discovery_thread(void *client_data)
|
||||
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,
|
||||
void *client_data)
|
||||
{
|
||||
struct usb_host_context *context = (struct usb_host_context *)client_data;
|
||||
struct inotify_event* event;
|
||||
char event_buf[512];
|
||||
char path[100];
|
||||
int i, fd, ret;
|
||||
int i, ret, done = 0;
|
||||
int wd, wds[10];
|
||||
int wd_count = sizeof(wds) / sizeof(wds[0]);
|
||||
|
||||
D("Created device discovery thread\n");
|
||||
|
||||
fd = inotify_init();
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "inotify_init failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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(fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
|
||||
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");
|
||||
return NULL;
|
||||
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(fd, path, IN_CREATE | IN_DELETE);
|
||||
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 */
|
||||
find_existing_devices(context);
|
||||
done = find_existing_devices(added_cb, removed_cb, client_data);
|
||||
|
||||
while (1) {
|
||||
ret = read(fd, event_buf, sizeof(event_buf));
|
||||
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;
|
||||
|
|
@ -163,46 +185,26 @@ static void* device_discovery_thread(void *client_data)
|
|||
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(fd, path, IN_CREATE | IN_DELETE);
|
||||
ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
|
||||
if (ret > 0)
|
||||
wds[i] = ret;
|
||||
}
|
||||
} else {
|
||||
for (i = 1; i < wd_count; i++) {
|
||||
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);
|
||||
context->added_cb(path, context->client_data);
|
||||
done = added_cb(path, client_data);
|
||||
} else if (event->mask == IN_DELETE) {
|
||||
D("gone device %s\n", path);
|
||||
context->removed_cb(path, context->client_data);
|
||||
done = removed_cb(path, client_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int usb_host_init(usb_device_added_cb added_cb, usb_device_removed_cb removed_cb, void *client_data)
|
||||
{
|
||||
struct usb_host_context *context;
|
||||
pthread_t tid;
|
||||
pthread_attr_t attr;
|
||||
|
||||
if (!added_cb || !removed_cb)
|
||||
return -EINVAL;
|
||||
|
||||
context = calloc(1, sizeof(struct usb_host_context));
|
||||
context->added_cb = added_cb;
|
||||
context->removed_cb = removed_cb;
|
||||
context->client_data = client_data;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
return pthread_create(&tid, &attr, device_discovery_thread, context);
|
||||
}
|
||||
|
||||
struct usb_device *usb_device_open(const char *dev_name)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue