diff --git a/src/kernel/core/device_manager/probe.cpp b/src/kernel/core/device_manager/probe.cpp index cd727da7ae..42b0d23939 100644 --- a/src/kernel/core/device_manager/probe.cpp +++ b/src/kernel/core/device_manager/probe.cpp @@ -16,6 +16,13 @@ #include "device_manager_private.h" #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -31,12 +38,14 @@ # define TRACE(x) ; #endif -// ToDo: for now - it won't be necessary to do this later anymore -#define pnp_boot_safe_realpath realpath -#define pnp_boot_safe_lstat lstat -#define pnp_boot_safe_opendir opendir -#define pnp_boot_safe_readdir readdir -#define pnp_boot_safe_closedir closedir + +struct path_entry { + struct list_link link; + char *path; + dev_t device; + ino_t node; +}; + // list of driver registration directories const char *pnp_registration_dirs[2] = { @@ -46,19 +55,164 @@ const char *pnp_registration_dirs[2] = { // list of module directories -static const char *modules_dirs[2] = { +static const char *kModulePaths[] = { COMMON_MODULES_DIR, - SYSTEM_MODULES_DIR + "/boot/beos/system/add-ons/kernel",//SYSTEM_MODULES_DIR, + NULL }; +class DirectoryIterator { + public: + DirectoryIterator(const char *path, const char *subPath = NULL, bool recursive = false); + DirectoryIterator(const char **paths, const char *subPath = NULL, bool recursive = false); + ~DirectoryIterator(); + + void SetTo(const char *path, const char *subPath = NULL, bool recursive = false); + void SetTo(const char **paths, const char *subPath = NULL, bool recursive = false); + + status_t GetNext(KPath &path, struct stat &stat); + + void Unset(); + void AddPath(const char *path, const char *subPath = NULL); + + private: + Stack fPaths; + bool fRecursive; + DIR *fDirectory; + KPath *fBasePath; +}; + + +DirectoryIterator::DirectoryIterator(const char *path, const char *subPath, bool recursive) + : + fDirectory(NULL), + fBasePath(NULL) +{ + SetTo(path, subPath, recursive); +} + + +DirectoryIterator::DirectoryIterator(const char **paths, const char *subPath, bool recursive) + : + fDirectory(NULL), + fBasePath(NULL) +{ + SetTo(paths, subPath, recursive); +} + + +DirectoryIterator::~DirectoryIterator() +{ + Unset(); +} + + +void +DirectoryIterator::SetTo(const char *path, const char *subPath, bool recursive) +{ + Unset(); + fRecursive = recursive; + + AddPath(path, subPath); +} + + +void +DirectoryIterator::SetTo(const char **paths, const char *subPath, bool recursive) +{ + Unset(); + fRecursive = recursive; + + for (int32 i = 0; paths[i] != NULL; i++) { + AddPath(paths[i], subPath); + } +} + + +status_t +DirectoryIterator::GetNext(KPath &path, struct stat &stat) +{ +next_directory: + while (fDirectory == NULL) { + delete fBasePath; + fBasePath = NULL; + + if (!fPaths.Pop(&fBasePath)) + return B_ENTRY_NOT_FOUND; + + fDirectory = opendir(fBasePath->Path()); + } + +next_entry: + struct dirent *dirent = readdir(fDirectory); + if (dirent == NULL) { + // get over to next directory on the stack + closedir(fDirectory); + fDirectory = NULL; + + goto next_directory; + } + + if (!strcmp(dirent->d_name, "..") || !strcmp(dirent->d_name, ".")) + goto next_entry; + + path.SetTo(fBasePath->Path()); + path.Append(dirent->d_name); + + if (::stat(path.Path(), &stat) != 0) + goto next_entry; + + if (S_ISDIR(stat.st_mode) && fRecursive) { + KPath *nextPath = new KPath(path); + if (fPaths.Push(nextPath) != B_OK) + return B_NO_MEMORY; + + goto next_entry; + } + + return B_OK; +} + + +void +DirectoryIterator::Unset() +{ + if (fDirectory != NULL) { + closedir(fDirectory); + fDirectory = NULL; + } + + delete fBasePath; + fBasePath = NULL; + + KPath *path; + while (fPaths.Pop(&path)) + delete path; +} + + +void +DirectoryIterator::AddPath(const char *basePath, const char *subPath) +{ + KPath *path = new KPath(basePath); + if (subPath != NULL) + path->Append(subPath); + + fPaths.Push(path); +} + + +// #pragma mark - + + /** notify a consumer that a device he might handle is added - * consumer_name - file name (!) of consumer + * fileName - file name of consumer * (moved to end of file to avoid inlining) */ static status_t -notify_probe_by_file(device_node_info *node, const char *consumer_name) +notify_probe_by_file(device_node_info *node, const char *fileName) { char *type; char *resolved_path; @@ -67,14 +221,14 @@ notify_probe_by_file(device_node_info *node, const char *consumer_name) bool valid_module_name; status_t res; - TRACE(("notify_probe_by_file(%s)\n", consumer_name)); + TRACE(("notify_probe_by_file(%s)\n", fileName)); res = pnp_get_attr_string(node, PNP_DRIVER_TYPE, &type, false); if (res != B_OK) return res; // resolve link to actual driver file - resolved_path = (char *)malloc(PATH_MAX + 1); + resolved_path = (char *)malloc(B_PATH_NAME_LENGTH + 1); if (resolved_path == NULL) { res = B_NO_MEMORY; goto err; @@ -85,7 +239,7 @@ notify_probe_by_file(device_node_info *node, const char *consumer_name) module_name = NULL; if (module_name == NULL) { // broken link or something - dprintf("Cannot resolve driver file name: %s\n", consumer_name); + dprintf("Cannot resolve driver file name: %s\n", fileName); res = errno; goto err2; } @@ -95,10 +249,10 @@ notify_probe_by_file(device_node_info *node, const char *consumer_name) valid_module_name = false; for (i = 0; i < (disable_useraddons ? 1 : 2); ++i) { - int len = strlen(modules_dirs[i]); + int len = strlen(kModulePaths[i]); - if (!strncmp(consumer_name, modules_dirs[i], len) - && !strncmp(module_name, modules_dirs[i], len)) { + if (!strncmp(fileName, kModulePaths[i], len) + && !strncmp(module_name, kModulePaths[i], len)) { valid_module_name = true; module_name = module_name + len; break; @@ -107,14 +261,14 @@ notify_probe_by_file(device_node_info *node, const char *consumer_name) if (!valid_module_name) { TRACE(("Module file %s of consumer %s is in wrong path\n", - consumer_name, module_name)); + fileName, module_name)); res = B_NAME_NOT_FOUND; goto err2; } // append driver type to get specific module name - strlcat(module_name, "/", PATH_MAX); - strlcat(module_name, type, PATH_MAX); + strlcat(module_name, "/", B_PATH_NAME_LENGTH); + strlcat(module_name, type, B_PATH_NAME_LENGTH); res = pnp_notify_probe_by_module(node, module_name); @@ -148,8 +302,8 @@ compose_driver_names(device_node_info *node, const char *dir, if (term_array == NULL) return B_NO_MEMORY; - strlcpy(path, dir, PATH_MAX); - strlcat(path, "/", PATH_MAX); + strlcpy(path, dir, B_PATH_NAME_LENGTH); + strlcat(path, "/", B_PATH_NAME_LENGTH); TRACE(("compose_drive_names(%s)\n", path)); @@ -181,7 +335,7 @@ err: /** notify all drivers under . If is true, notify all, * if false, stop once a drivers notification function returned B_OK - * buffer - scratch buffer of size PATH_MAX + 1 ; destroyed on exit + * buffer - scratch buffer of size B_PATH_NAME_LENGTH + 1 ; destroyed on exit * return: B_NAME_NOT_FOUND, if tell_all is false and no driver returned B_OK */ @@ -199,37 +353,37 @@ try_drivers(device_node_info *node, char *directory, // first try user drivers, then system drivers for (i = 0; i < (disable_useraddons ? 1 : 2); ++i) { strcpy(buffer, pnp_registration_dirs[i]); - strlcat(buffer, directory, PATH_MAX); + strlcat(buffer, directory, B_PATH_NAME_LENGTH); TRACE(("cur_dir: %s\n", buffer)); dir_len = strlen(buffer); - dir = pnp_boot_safe_opendir(buffer); + dir = opendir(buffer); if (dir == NULL) { //SHOW_ERROR(3, "Directory %s doesn't exists", buffer); // directory doesn't exist return tell_all ? B_OK : B_NAME_NOT_FOUND; } - while ((entry = pnp_boot_safe_readdir(dir)) != NULL) { + while ((entry = readdir(dir)) != NULL) { buffer[dir_len] = 0; - strlcat(buffer, "/", PATH_MAX); - strlcat(buffer, entry->d_name, PATH_MAX); + strlcat(buffer, "/", B_PATH_NAME_LENGTH); + strlcat(buffer, entry->d_name, B_PATH_NAME_LENGTH); // skip default directory entries if (!strcmp( entry->d_name, ".") || !strcmp( entry->d_name, "..")) continue; - if (notify_probe_by_file( node, buffer) == B_OK && !tell_all) { + if (notify_probe_by_file(node, buffer) == B_OK && !tell_all) { // tell_all is false, return on first hit - pnp_boot_safe_closedir(dir); + closedir(dir); return B_OK; } } - pnp_boot_safe_closedir(dir); + closedir(dir); } return tell_all ? B_OK : B_NAME_NOT_FOUND; @@ -238,7 +392,7 @@ try_drivers(device_node_info *node, char *directory, /** find normal consumer of node that are stored under ; first, we * look for a specific driver; if none could be found, find a generic - * one path, buffer - used as scratch buffer (all of size PATH_MAX + 1) + * one path, buffer - used as scratch buffer (all of size B_PATH_NAME_LENGTH + 1) * return: B_NAME_NOT_FOUND if no consumer could be found */ @@ -271,11 +425,11 @@ find_normal_consumer(device_node_info *node, const char *dir, struct stat dummy; strcpy(buffer, pnp_registration_dirs[j]); - strlcat(buffer, path, PATH_MAX); + strlcat(buffer, path, B_PATH_NAME_LENGTH); // do a stat to avoid error message if Specific Driver // isn't provided - if (pnp_boot_safe_lstat(buffer, &dummy) == 0) { + if (lstat(buffer, &dummy) == 0) { res = notify_probe_by_file(node, buffer); if (res == B_OK) // got him! @@ -297,8 +451,8 @@ find_normal_consumer(device_node_info *node, const char *dir, } // no specific consumer - go through generic driver - strlcpy(path, dir, PATH_MAX); - strlcat(path, GENERIC_SUBDIR, PATH_MAX); + strlcpy(path, dir, B_PATH_NAME_LENGTH); + strlcat(path, GENERIC_SUBDIR, B_PATH_NAME_LENGTH); if (try_drivers(node, path, false, buffer) != B_OK) { *found_normal_driver = false; @@ -316,31 +470,29 @@ find_normal_consumer(device_node_info *node, const char *dir, * pattern - pattern of consumer name * buffer - buffer to store results in * (returned strings all point to !) - * dir - directory * filename_pattern - pattern of file name * *num_parts - number of split positions */ static status_t preprocess_consumer_names(const char *pattern, char *buffer, - char **dir, char **filename_pattern, int *const num_parts) + char **filename_pattern, int *const num_parts) { - char *last_slash, *str, *dest; + char *str, *dest; bool parts_began; // make a copy of pattern as we will strip escapes from directory part - strlcpy(buffer, pattern, PATH_MAX); + strlcpy(buffer, pattern, B_PATH_NAME_LENGTH); // find directory part and count splitpoints parts_began = false; - last_slash = NULL; *num_parts = 1; for (str = buffer; *str; ++str) { switch (*str) { - case '^': + case '\\': // honour escaped characters, taking care of trailing escape - if (*(str + 1)) + if (str[1]) ++str; break; @@ -354,8 +506,8 @@ preprocess_consumer_names(const char *pattern, char *buffer, // find end of attribute name, taking care of escape sequences for (; *str != 0; ++str) { - if (*str == '^') { - if (*(str + 1) != 0) + if (*str == '\\') { + if (str[1] != 0) ++str; } else if (*str == '%') break; @@ -366,37 +518,23 @@ preprocess_consumer_names(const char *pattern, char *buffer, return B_BAD_VALUE; } break; - - case '/': - // directory finishes at last "/" before first "|" - if (!parts_began) - last_slash = str; - break; } } - if (last_slash == 0) { - dprintf("missing directory in consumer pattern %s\n", pattern); - return B_BAD_VALUE; - } - - // split into directory and filename pattern in place - *dir = buffer; - *last_slash = 0; - *filename_pattern = last_slash + 1; + *filename_pattern = buffer; // remove escape sequences from directory for (str = buffer, dest = buffer; *str; ++str) { - if (*str == '^' && (str + 1) != 0) + if (str[0] == '\\' && str[1] != 0) ++str; *dest++ = *str; } - *dest = 0; + *dest = '\0'; - TRACE(("dir=%s, filename_pattern=%s, num_parts=%d\n", - *dir, *filename_pattern, *num_parts)); + TRACE(("filename_pattern = %s, num_parts = %d\n", + *filename_pattern, *num_parts)); return B_OK; } @@ -408,32 +546,35 @@ preprocess_consumer_names(const char *pattern, char *buffer, */ static status_t -notify_dynamic_consumer(device_node_info *node, const char *pattern, - bool *has_normal_driver) -{ - status_t res; +notify_dynamic_consumer(device_node_info *node, const char *bus, + const char *pattern, bool *has_normal_driver) +{ + status_t status; char *buffers; - char *dir, *filename_pattern; + char *filename_pattern; int num_parts; - TRACE(("notify_dynamic_consumer(pattern=%s, has_normal_driver=%d)\n", - pattern, *has_normal_driver)); + TRACE(("notify_dynamic_consumer(bus = %s, pattern = %s, has_normal_driver = %d)\n", + bus, pattern, *has_normal_driver)); + + if (pattern == NULL) + return B_OK; // we need three buffers - allocate them at once for simplicity - buffers = (char *)malloc(3 * (PATH_MAX + 1)); + buffers = (char *)malloc(3 * (B_PATH_NAME_LENGTH + 1)); if (buffers == NULL) return B_NO_MEMORY; - res = preprocess_consumer_names(pattern, buffers + 2 * (PATH_MAX + 1), - &dir, &filename_pattern, &num_parts); - if (res < B_OK) + status = preprocess_consumer_names(pattern, buffers + 2 * (B_PATH_NAME_LENGTH + 1), + &filename_pattern, &num_parts); + if (status < B_OK) goto err; if (!*has_normal_driver) { // find specific/generic consumer - res = find_normal_consumer(node, dir, filename_pattern, num_parts, - buffers, buffers + PATH_MAX + 1, has_normal_driver); - if (res != B_OK && res != B_NAME_NOT_FOUND) + status = find_normal_consumer(node, bus, filename_pattern, num_parts, + buffers, buffers + B_PATH_NAME_LENGTH + 1, has_normal_driver); + if (status != B_OK && status != B_NAME_NOT_FOUND) // only abort if there was a "real" problem; // if there is no specific/generic consumer, we don't bother // (having no driver is not funny but happens) @@ -441,11 +582,11 @@ notify_dynamic_consumer(device_node_info *node, const char *pattern, } // tell universal drivers - strlcpy(buffers, dir, PATH_MAX); - strlcat(buffers, UNIVERSAL_SUBDIR, PATH_MAX); + strlcpy(buffers, bus, B_PATH_NAME_LENGTH); + strlcat(buffers, UNIVERSAL_SUBDIR, B_PATH_NAME_LENGTH); - res = try_drivers(node, buffers, true, buffers + PATH_MAX + 1); - if (res != B_OK && res != B_NAME_NOT_FOUND) + status = try_drivers(node, buffers, true, buffers + B_PATH_NAME_LENGTH + 1); + if (status != B_OK && status != B_NAME_NOT_FOUND) // again, only abort on real problems goto err; @@ -456,7 +597,176 @@ notify_dynamic_consumer(device_node_info *node, const char *pattern, err: free(buffers); - return res; + return status; +} + + +static path_entry * +find_node_ref_in_list(struct list *list, dev_t device, ino_t node) +{ + path_entry *entry = NULL; + + while ((entry = (path_entry *)list_get_next_item(list, entry)) != NULL) { + if (entry->device == device + && entry->node == node) + return entry; + } + + return NULL; +} + + +static image_id +load_driver(const char *path) +{ + status_t (*init_hardware)(void); + status_t (*init_driver)(void); + const char **devicePaths; + int32 exported = 0; + status_t status; + + // load the module + image_id image = load_kernel_add_on(path); + if (image < 0) + return image; + + // for prettier debug output + const char *name = strrchr(path, '/'); + if (name == NULL) + name = path; + else + name++; + + // For a valid device driver the following exports are required + + device_hooks *(*find_device)(const char *); + const char **(*publish_devices)(void); + uint32 *api_version; + if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, (void **)&publish_devices) != B_OK + || get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, (void **)&api_version) != B_OK + || get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, (void **)&find_device) != B_OK) { + dprintf("%s: mandatory driver symbol(s) missing!\n", name); + status = B_BAD_VALUE; + goto error1; + } + + // test for init_hardware() and call it + if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT, + (void **)&init_hardware) == B_OK + && (status = init_hardware()) != B_OK) { + dprintf("%s: init_hardware() failed: %s\n", name, strerror(status)); + status = ENXIO; + goto error1; + } + + /* OK, so we now have what appears to be a valid module that has + * completed init_hardware and thus thinks it should be used. + * ToDo: + * - this is bogus! + * - the driver init routines should be called by devfs and + * only when the driver is first needed. However, that level + * level of support is not yet in devfs, so we have a hack + * here that calls the init_driver function at this point. + * As a result we will check to see if we actually manage to + * publish the device, and if we do we will keep the module + * loaded. + * - remove this when devfs is fixed! + */ + if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT, + (void **)&init_driver) == B_OK + && (status = init_driver()) != B_OK) { + dprintf("%s: init_driver() failed: %s\n", name, strerror(status)); + status = ENXIO; + goto error2; + } + + // we keep the driver loaded if it exports at least a single interface + devicePaths = publish_devices(); + if (devicePaths == NULL) { + dprintf("%s: publish_devices() returned NULL.\n", name); + status = ENXIO; + goto error3; + } + + for (; devicePaths[0]; devicePaths++) { + device_hooks *hooks = find_device(devicePaths[0]); + + if (hooks && devfs_publish_device(devicePaths[0], NULL, hooks) == 0) + exported++; + } + + // we're all done, driver will be kept loaded (for now, see above comment) + if (exported > 0) + return image; + + status = B_ERROR; // whatever... + + +error3: + { + status_t (*uninit_driver)(void); + if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT, + (void **)&uninit_driver) == B_OK) + uninit_driver(); + } + +error2: +{ + status_t (*uninit_hardware)(void); + if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT, + (void **)&uninit_hardware) == B_OK) + uninit_hardware(); +} +error1: + /* If we've gotten here then the driver will be unloaded and an + * error code returned. + */ + unload_kernel_add_on(image); + return status; +} + + +/** This is no longer part of the public kernel API, so we just export the symbol */ + +status_t load_driver_symbols(const char *driverName); +status_t +load_driver_symbols(const char *driverName) +{ + // This will be globally done for the whole kernel via the settings file. + // We don't have to do anything here. + + return B_OK; +} + + +static status_t +try_drivers(struct list &list) +{ + path_entry *entry; + while ((entry = (path_entry *)list_remove_head_item(&list)) != NULL) { + image_id image = load_kernel_add_on(entry->path); + if (image >= 0) { + // check if it's a driver module + module_info **modules; + if (load_module(entry->path, &modules) == B_OK) { + // we have a module + dprintf("loaded module %s\n", entry->path); + } else { + // it can still be a standard old-style driver + if (load_driver(entry->path) == B_OK) { + // we have a driver + dprintf("loaded driver %s\n", entry->path); + } + } + + unload_kernel_add_on(image); + } + + free(entry->path); + free(entry); + } + + return B_OK; } @@ -472,59 +782,70 @@ err: status_t pnp_notify_dynamic_consumers(device_node_info *node) { - int i; +#if 0 char *buffer; - status_t res; - bool has_normal_driver = false; + char *bus; + status_t status = B_OK; + int32 i, found = 0; - TRACE(("pnp_notify_dynamic_consumers()\n")); + TRACE(("pnp_notify_dynamic_consumers(node = %p)\n", node)); - buffer = (char *)malloc(PATH_MAX + 1); - if (buffer == NULL) - return B_NO_MEMORY; + if (pnp_get_attr_string(node, PNP_DRIVER_CONSUMER_BUS, &bus, false) != B_OK) + return B_OK; - //pnp_load_boot_links(); + TRACE((" Search bus: \"%s\"\n", bus)); + + buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1); + if (buffer == NULL) { + status = B_NO_MEMORY; + goto err; + } // first, append nothing, then "/0", "/1" etc. for (i = -1; ; ++i) { + bool noSpecificDriver = false; char *consumer; - strcpy(buffer, PNP_DRIVER_DYNAMIC_CONSUMER); + strcpy(buffer, PNP_DRIVER_CONSUMER_MAPPING); if (i >= 0) - sprintf(buffer + strlen( buffer ), "/%d", i); + sprintf(buffer + strlen( buffer ), "/%ld", i); // if no more dynamic consumers, cancel loop silently if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK) { - // starting with .../0 is OK, so ignore error if i=-1 + // starting with .../0 is OK, so ignore error if i = -1 if (i == -1) continue; else break; } - TRACE(("Consumer pattern %d: %s\n", i, consumer)); - - res = notify_dynamic_consumer(node, consumer, &has_normal_driver); + TRACE((" Consumer pattern %ld: %s\n", i, consumer)); + status = notify_dynamic_consumer(node, bus, consumer, &noSpecificDriver); free(consumer); + found++; - if (res != B_OK) { + if (status != B_OK) { // this is only reached if a serious error occured, // see notify_dynamic_consumer() - goto err; + break; } } + if (found == 0) { + // no requirement for a special mapping, so we're just scanning the bus directory + bool noSpecificDriver = false; + status = notify_dynamic_consumer(node, bus, NULL, &noSpecificDriver); + } + + // supposed to go through free(buffer); - //pnp_unload_boot_links(); - - return B_OK; - err: - free(buffer); - //pnp_unload_boot_links(); - - return res; + free(bus); + return status; +#else + return B_OK; +#endif } @@ -539,9 +860,9 @@ pnp_notify_fixed_consumers(device_node_info *node) int i; char *buffer; - TRACE(("pnp_notify_fixed_consumers()\n")); + TRACE(("pnp_notify_fixed_consumers(node = %p)\n", node)); - buffer = (char *)malloc(PATH_MAX + 1); + buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1); if (buffer == NULL) return B_NO_MEMORY; @@ -554,7 +875,7 @@ pnp_notify_fixed_consumers(device_node_info *node) sprintf(buffer + strlen(buffer), "/%d", i); // if no more fixed consumers, cancel loop silently - if (pnp_get_attr_string( node, buffer, &consumer, false) != B_OK) + if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK) break; TRACE(("Consumer %d: %s\n", i, consumer)); @@ -566,7 +887,6 @@ pnp_notify_fixed_consumers(device_node_info *node) // as they are obviously crucial (else they wouldn't be fixed) free(consumer); free(buffer); - return B_NAME_NOT_FOUND; } @@ -577,3 +897,78 @@ pnp_notify_fixed_consumers(device_node_info *node) return B_OK; } + +status_t +probe_for_device_type(const char *type) +{ + // search a node with an open connection of the specified type + // or notify bus managers to get one + + status_t status = B_OK; + + // build list of potential drivers for that type + + struct list drivers; + list_init(&drivers); + + char devType[64]; + snprintf(devType, sizeof(devType), "drivers/dev%s%s", type[0] ? "/" : "", type); + + DirectoryIterator iterator(kModulePaths, devType, false); + struct stat stat; + KPath path; + + while (iterator.GetNext(path, stat) == B_OK) { + path_entry *entry = (path_entry *)malloc(sizeof(path_entry)); + if (entry == NULL) + return B_NO_MEMORY; + + entry->path = strdup(path.Path()); + if (entry->path == NULL) { + free(entry); + return B_NO_MEMORY; + } + + entry->device = stat.st_dev; + entry->node = stat.st_ino; + + dprintf("found potential driver: %s\n", path.Path()); + list_add_item(&drivers, entry); + } + + if (list_is_empty(&drivers)) + return B_OK; + + // Iterate through bus managers to shrink the list (let them publish + // their own devices) + + iterator.SetTo(kModulePaths, "drivers/bus", false); + + while (iterator.GetNext(path, stat) == B_OK) { + DirectoryIterator busIterator(path.Path(), NULL, true); + + struct list driversForBus; + list_init(&driversForBus); + + while (busIterator.GetNext(path, stat) == B_OK) { + path_entry *entry = find_node_ref_in_list(&drivers, stat.st_dev, stat.st_ino); + if (entry == NULL) + continue; + + // we found the driver here, so we should check it + list_remove_link(&entry->link); + list_add_item(&driversForBus, entry); + dprintf("found driver for bus \"%s\": \"%s\"\n", path.Path(), entry->path); + } + + // ToDo: do something with the bus drivers... :) + // ToDo: ask bus manager for driver (via mapping) + // ToDo: find all nodes where this driver could be attached to + try_drivers(driversForBus); + } + + // ToDo: do something with the remaining drivers... :) + try_drivers(drivers); + return B_OK; +} +