diff options
Diffstat (limited to 'freebsd/sys/kern/subr_bus.c')
-rw-r--r-- | freebsd/sys/kern/subr_bus.c | 112 |
1 files changed, 85 insertions, 27 deletions
diff --git a/freebsd/sys/kern/subr_bus.c b/freebsd/sys/kern/subr_bus.c index 8076e7e3..0626ec0a 100644 --- a/freebsd/sys/kern/subr_bus.c +++ b/freebsd/sys/kern/subr_bus.c @@ -1863,6 +1863,8 @@ make_device(device_t parent, const char *name, int unit) return (NULL); } } + if (parent != NULL && device_has_quiet_children(parent)) + dev->flags |= DF_QUIET | DF_QUIET_CHILDREN; dev->ivars = NULL; dev->softc = NULL; @@ -2688,6 +2690,15 @@ device_quiet(device_t dev) } /** + * @brief Set the DF_QUIET_CHILDREN flag for the device + */ +void +device_quiet_children(device_t dev) +{ + dev->flags |= DF_QUIET_CHILDREN; +} + +/** * @brief Clear the DF_QUIET flag for the device */ void @@ -2697,6 +2708,15 @@ device_verbose(device_t dev) } /** + * @brief Return non-zero if the DF_QUIET_CHIDLREN flag is set on the device + */ +int +device_has_quiet_children(device_t dev) +{ + return ((dev->flags & DF_QUIET_CHILDREN) != 0); +} + +/** * @brief Return non-zero if the DF_QUIET flag is set on the device */ int @@ -3760,7 +3780,11 @@ bus_generic_detach(device_t dev) if (dev->state != DS_ATTACHED) return (EBUSY); - TAILQ_FOREACH(child, &dev->children, link) { + /* + * Detach children in the reverse order. + * See bus_generic_suspend for details. + */ + TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { if ((error = device_detach(child)) != 0) return (error); } @@ -3780,7 +3804,11 @@ bus_generic_shutdown(device_t dev) { device_t child; - TAILQ_FOREACH(child, &dev->children, link) { + /* + * Shut down children in the reverse order. + * See bus_generic_suspend for details. + */ + TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { device_shutdown(child); } @@ -3833,15 +3861,23 @@ int bus_generic_suspend(device_t dev) { int error; - device_t child, child2; + device_t child; - TAILQ_FOREACH(child, &dev->children, link) { + /* + * Suspend children in the reverse order. + * For most buses all children are equal, so the order does not matter. + * Other buses, such as acpi, carefully order their child devices to + * express implicit dependencies between them. For such buses it is + * safer to bring down devices in the reverse order. + */ + TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { error = BUS_SUSPEND_CHILD(dev, child); - if (error) { - for (child2 = TAILQ_FIRST(&dev->children); - child2 && child2 != child; - child2 = TAILQ_NEXT(child2, link)) - BUS_RESUME_CHILD(dev, child2); + if (error != 0) { + child = TAILQ_NEXT(child, link); + if (child != NULL) { + TAILQ_FOREACH_FROM(child, &dev->children, link) + BUS_RESUME_CHILD(dev, child); + } return (error); } } @@ -5285,8 +5321,9 @@ sysctl_devices(SYSCTL_HANDLER_ARGS) u_int namelen = arg2; int index; device_t dev; - struct u_device udev; /* XXX this is a bit big */ + struct u_device *udev; int error; + char *walker, *ep; if (namelen != 2) return (EINVAL); @@ -5307,24 +5344,45 @@ sysctl_devices(SYSCTL_HANDLER_ARGS) return (ENOENT); /* - * Populate the return array. + * Populate the return item, careful not to overflow the buffer. */ - bzero(&udev, sizeof(udev)); - udev.dv_handle = (uintptr_t)dev; - udev.dv_parent = (uintptr_t)dev->parent; - if (dev->nameunit != NULL) - strlcpy(udev.dv_name, dev->nameunit, sizeof(udev.dv_name)); - if (dev->desc != NULL) - strlcpy(udev.dv_desc, dev->desc, sizeof(udev.dv_desc)); - if (dev->driver != NULL && dev->driver->name != NULL) - strlcpy(udev.dv_drivername, dev->driver->name, - sizeof(udev.dv_drivername)); - bus_child_pnpinfo_str(dev, udev.dv_pnpinfo, sizeof(udev.dv_pnpinfo)); - bus_child_location_str(dev, udev.dv_location, sizeof(udev.dv_location)); - udev.dv_devflags = dev->devflags; - udev.dv_flags = dev->flags; - udev.dv_state = dev->state; - error = SYSCTL_OUT(req, &udev, sizeof(udev)); + udev = malloc(sizeof(*udev), M_BUS, M_WAITOK | M_ZERO); + if (udev == NULL) + return (ENOMEM); + udev->dv_handle = (uintptr_t)dev; + udev->dv_parent = (uintptr_t)dev->parent; + udev->dv_devflags = dev->devflags; + udev->dv_flags = dev->flags; + udev->dv_state = dev->state; + walker = udev->dv_fields; + ep = walker + sizeof(udev->dv_fields); +#define CP(src) \ + if ((src) == NULL) \ + *walker++ = '\0'; \ + else { \ + strlcpy(walker, (src), ep - walker); \ + walker += strlen(walker) + 1; \ + } \ + if (walker >= ep) \ + break; + + do { + CP(dev->nameunit); + CP(dev->desc); + CP(dev->driver != NULL ? dev->driver->name : NULL); + bus_child_pnpinfo_str(dev, walker, ep - walker); + walker += strlen(walker) + 1; + if (walker >= ep) + break; + bus_child_location_str(dev, walker, ep - walker); + walker += strlen(walker) + 1; + if (walker >= ep) + break; + *walker++ = '\0'; + } while (0); +#undef CP + error = SYSCTL_OUT(req, udev, sizeof(*udev)); + free(udev, M_BUS); return (error); } |