/* returns true if one of the callbacks indicates we are done */ static int find_existing_devices(usb_device_added_cb added_cb, void *client_data) { char busname[32]; DIR *busdir; struct dirent *de; int done = 0; busdir = opendir(USB_FS_DIR); if(busdir == 0) return 0; while ((de = readdir(busdir)) != 0 && !done) { if(badname(de->d_name)) continue; snprintf(busname, sizeof(busname), USB_FS_DIR "/%s", de->d_name); done = find_existing_devices_bus(busname, added_cb, client_data); } //end of busdir while closedir(busdir); return done; }
int usb_host_read_event(struct usb_host_context *context) { struct inotify_event* event; char event_buf[512]; char path[100]; int i, ret, done = 0; int offset = 0; int wd; ret = read(context->fd, event_buf, sizeof(event_buf)); if (ret >= (int)sizeof(struct inotify_event)) { while (offset < ret && !done) { event = (struct inotify_event*)&event_buf[offset]; done = 0; wd = event->wd; if (wd == context->wdd) { if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) { context->wddbus = inotify_add_watch(context->fd, DEV_BUS_DIR, IN_CREATE | IN_DELETE); if (context->wddbus < 0) { done = 1; } else { watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT); done = find_existing_devices(context->cb_added, context->data); } } } else if (wd == context->wddbus) { if ((event->mask & IN_CREATE) && !strcmp(event->name, "usb")) { 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, "usb")) { 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 == context->wds[0]) { i = atoi(event->name); snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name); D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ? "new" : "gone", path, i); if (i > 0 && i < MAX_USBFS_WD_COUNT) { int local_ret = 0; if (event->mask & IN_CREATE) { local_ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE); if (local_ret >= 0) context->wds[i] = local_ret; done = find_existing_devices_bus(path, context->cb_added, context->data); } else if (event->mask & IN_DELETE) { inotify_rm_watch(context->fd, context->wds[i]); context->wds[i] = -1; } } } else { for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) { if (wd == context->wds[i]) { snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name); if (event->mask == IN_CREATE) { D("new device %s\n", path); done = context->cb_added(path, context->data); } else if (event->mask == IN_DELETE) { D("gone device %s\n", path); done = context->cb_removed(path, context->data); } } } } offset += sizeof(struct inotify_event) + event->len; } } 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) { struct inotify_event* event; char event_buf[512]; char path[100]; int i, ret, done = 0; 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 */ for (i = 0; i < wd_count; i++) wds[i] = -1; /* watch the root for new subdirectories */ 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_subdirs(context, wds, wd_count); /* check for existing devices first, after we have inotify set up */ done = find_existing_devices(added_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 == 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) ? "new" : "gone", path, i); if (i > 0 && i < wd_count) { if (event->mask & IN_CREATE) { ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE); if (ret >= 0) wds[i] = ret; done = find_existing_devices_bus(path, added_cb, client_data); } else if (event->mask & IN_DELETE) { inotify_rm_watch(context->fd, wds[i]); wds[i] = -1; } } } 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); } } } } } } }