libusbhost: Fix USB device discovery on boot

On some devices, /dev/bus/usb does not exist on boot, it is only created
when the otg port is in host mode. Use inotify to detect when /dev/bus/usb
is created and then start watching subdirectories.

Change-Id: Ic1472a5ea7a7118cdbb560cc7071ade9bcee753a
This commit is contained in:
Benoit Goby 2012-08-01 18:54:02 -07:00
parent 6cc883ca09
commit f4de078388

View file

@ -49,7 +49,8 @@
#include "usbhost/usbhost.h"
#define USB_FS_DIR "/dev/bus/usb"
#define DEV_DIR "/dev"
#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"
@ -110,7 +111,7 @@ static int find_existing_devices(usb_device_added_cb added_cb,
int done = 0;
busdir = opendir(USB_FS_DIR);
if(busdir == 0) return 1;
if(busdir == 0) return 0;
while ((de = readdir(busdir)) != 0 && !done) {
if(badname(de->d_name)) continue;
@ -124,6 +125,25 @@ static int find_existing_devices(usb_device_added_cb added_cb,
return done;
}
static void watch_existing_subdirs(struct usb_host_context *context,
int *wds, int wd_count)
{
char path[100];
int i, ret;
wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
if (wds[0] < 0)
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;
}
}
struct usb_host_context *usb_host_init()
{
struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context));
@ -156,29 +176,25 @@ void usb_host_run(struct usb_host_context *context,
char event_buf[512];
char path[100];
int i, ret, done = 0;
int wd, wds[10];
int wd, wdd, 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));
for (i = 0; i < wd_count; i++)
wds[i] = -1;
/* watch the root for new subdirectories */
wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
if (wds[0] < 0) {
wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);
if (wdd < 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;
}
watch_existing_subdirs(context, wds, wd_count);
/* check for existing devices first, after we have inotify set up */
done = find_existing_devices(added_cb, client_data);
@ -190,7 +206,19 @@ void usb_host_run(struct usb_host_context *context,
if (ret >= (int)sizeof(struct inotify_event)) {
event = (struct inotify_event *)event_buf;
wd = event->wd;
if (wd == wds[0]) {
if (wd == wdd) {
if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
watch_existing_subdirs(context, wds, wd_count);
done = find_existing_devices(added_cb, client_data);
} else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
for (i = 0; i < wd_count; i++) {
if (wds[i] >= 0) {
inotify_rm_watch(context->fd, wds[i]);
wds[i] = -1;
}
}
}
} else if (wd == wds[0]) {
i = atoi(event->name);
snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name);
D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
@ -199,7 +227,7 @@ void usb_host_run(struct usb_host_context *context,
if (event->mask & IN_CREATE) {
ret = inotify_add_watch(context->fd, path,
IN_CREATE | IN_DELETE);
if (ret > 0)
if (ret >= 0)
wds[i] = ret;
done = find_existing_devices_bus(path, added_cb,
client_data);