Index: sys/dev/uart/uart_tty.c =================================================================== --- sys/dev/uart/uart_tty.c +++ sys/dev/uart/uart_tty.c @@ -424,6 +424,14 @@ tty_makedev(tp, NULL, "u%r", unit); + /* Try to determine this was registered via cn_init. */ + if (uart_console.cookie) { + struct consdev *cp; + cp = uart_console.cookie; + MPASS(cp->cn_pri > CN_DEAD); + device_set_console(sc->sc_dev); + } + return (0); } Index: sys/kern/subr_bus.c =================================================================== --- sys/kern/subr_bus.c +++ sys/kern/subr_bus.c @@ -2467,6 +2467,15 @@ bus_data_generation_update(); } +/** + * @brief Set a device as having a console + */ +void +device_set_console(device_t dev) +{ + dev->flags |= DF_CONSOLE; +} + /** * @brief Set the device's description * @@ -2720,6 +2729,15 @@ return (dev->state >= DS_ATTACHED); } +/** + * @brief Return non-zero if the device is a console device + */ +int +device_is_console(device_t dev) +{ + return ((dev->flags & DF_CONSOLE) != 0); +} + /** * @brief Return non-zero if the device is currently suspended. */ @@ -3796,6 +3814,10 @@ return (0); } +static bool cons_on_suspend = 0; +SYSCTL_BOOL(_debug, OID_AUTO, cons_on_suspend, CTLFLAG_RWTUN, &cons_on_suspend, + false, + "Try to preserve console during suspend and resume cycles"); /** * @brief Helper function for implementing DEVICE_SUSPEND() * @@ -3810,7 +3832,9 @@ { int error; device_t child; + bool found; + found = false; /* * Suspend children in the reverse order. * For most buses all children are equal, so the order does not matter. @@ -3819,6 +3843,11 @@ * safer to bring down devices in the reverse order. */ TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { + /* children also shouldn't be suspended */ + if (cons_on_suspend && device_is_console(child)) { + found = true; + continue; + } error = BUS_SUSPEND_CHILD(dev, child); if (error != 0) { child = TAILQ_NEXT(child, link); @@ -3829,6 +3858,36 @@ return (error); } } + + /* + * HACK: The VT subsystem entangles the console concept is such a way + * that it isn't easy to determine whether or not it is *the* console we + * want to preserve at suspend. As a result, the easiest thing to do is + * restore the device right now if no other console was found. The + * better way to do this would be to actually figure out at attach time + * that the VGA/EFI device is the kernel console, and set the flag + * appropriately. + * + * Note that all the children need to be restored since we do not know + * if the graphics device can operate without its children. + */ + if (cons_on_suspend && !found) { + device_t *devs; + int devcount, err; + + err = devclass_get_devices(devclass_find("vgapci"), &devs, &devcount); + if (!err && devcount) { + do { + --devcount; + dev = devs[devcount]; + TAILQ_FOREACH_FROM(child, &dev->children, link) + BUS_RESUME_CHILD(dev, child); + DEVICE_RESUME(dev); + device_printf(dev, "Resumed console device\n"); + } while (devcount); + } + } + return (0); } Index: sys/sys/bus.h =================================================================== --- sys/sys/bus.h +++ sys/sys/bus.h @@ -95,6 +95,7 @@ #define DF_QUIET_CHILDREN 0x200 /* Default to quiet for all my children */ #define DF_ATTACHED_ONCE 0x400 /* Has been attached at least once */ #define DF_NEEDNOMATCH 0x800 /* Has a pending NOMATCH event */ +#define DF_CONSOLE 0x1000 /* This device is used as a console */ /** * @brief Device request structure used for ioctl's. @@ -596,6 +597,7 @@ int device_has_quiet_children(device_t dev); int device_is_alive(device_t dev); /* did probe succeed? */ int device_is_attached(device_t dev); /* did attach succeed? */ +int device_is_console(device_t dev); int device_is_enabled(device_t dev); int device_is_suspended(device_t dev); int device_is_quiet(device_t dev); @@ -608,6 +610,7 @@ int device_quiesce(device_t dev); void device_quiet(device_t dev); void device_quiet_children(device_t dev); +void device_set_console(device_t dev); void device_set_desc(device_t dev, const char* desc); void device_set_desc_copy(device_t dev, const char* desc); int device_set_devclass(device_t dev, const char *classname);