aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorPetr Mladek <pmladek@suse.com>2026-10-01 16:07:27 +0200
committerPetr Mladek <pmladek@suse.com>2026-10-02 10:26:42 +0200
commitc83e3d2912432107148cc5e288ddd153a84c0f43 (patch)
tree75c11e65141e5bf0651cd47330a694c5b46217e0 /kernel
parent3f8b8c94a723ab6c0a62005e69a0872717f01709 (diff)
braille: nbcon: Allow to use a serial console with NBCON API as Braille console
The Braille console is not registered in console_list. Instead, it is integrated with the virtual terminal (VT) and shows what is displayed on the terminal. It writes the data using con->write*() callback of the associated serial console driver. braille_write() is called from the VT code under console_lock(). The associated serial console driver can be converted to the NBCON API though. The situation is similar to flushing nbcon consoles in the legacy loop when some boot consoles are still registered, see nbcon_legacy_emit_next_record(). But there is a big difference though. braille_write() is not directly called from the code paths flushing registered consoles. The VT code expects that braille_write() succeeds. It does not replay the message when it can't acquire the ownership. As a result, braille_write(): + must try harder to get the ownership. + has to be synchronized only against non-printk serial console which depend nbcon_device_try_acquire() using NBCON_PRIO_NORMAL. Let's look at it from another side and try to simulate the original locking using the NBCON API: 1. Take con->device_lock(), aka the port->lock in the legacy serial console driver. 2. Acquire nbcon context to provide some synchronization for a panic() context. Use NBCON_PRIO_NORMAL because it contends only with nbcon_device_try_acquire() users. Do it in a busy loop. It should always succeed when con->device_lock() succeeded because all other users do the same. The only exception is when the context get acquired by a CPU handling panic. 3. In panic, disable interrupts and try to acquire the nbcon context. Use NBCON_PRIO_PANIC. And try even an unsafe takeover because otherwise the Braille console won't see the text shown during panic(). It is similar to the oops_in_progress/trylock handling in the legacy serial console driver. Finally, avoid the newline prepending logic in the existing serial console drivers when they are used as a Braille console. As explained above, the Braille console shows the last modified line on the terminal (VT). braille_write() is called when single characters are added. Most messages are not ended by newline. Anyway, the VT code does not have logic to reply partially printed messages. Fixes: 13189fa73afa ("printk: nbcon: Rely on kthreads for normal operation") Reviewed-by: John Ogness <john.ogness@linutronix.de> [pmladek@suse.com: Remove white space changes in braille_register_console(). Typo fix.] Link: https://patch.msgid.link/20261001140727.124398-2-pmladek@suse.com Signed-off-by: Petr Mladek <pmladek@suse.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/printk/nbcon.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index d17704fe93ae..fb1b37741952 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1887,6 +1887,7 @@ bool nbcon_device_try_acquire(struct console *con)
memset(ctxt, 0, sizeof(*ctxt));
ctxt->console = con;
+ /* Keep in sync with nbcon_braille_try_acquire(). */
ctxt->prio = NBCON_PRIO_NORMAL;
if (!nbcon_context_try_acquire(ctxt, false))
@@ -2002,3 +2003,81 @@ void nbcon_kdb_release(struct nbcon_write_context *wctxt)
*/
__nbcon_atomic_flush_pending_con(ctxt->console, prb_next_reserve_seq(prb));
}
+
+/**
+ * nbcon_is_braille - Checks whether the nbcon write context is using Braille console
+ *
+ * @wctxt: checked nbcon write context
+ *
+ * Return: True when the write context is associated with a Braille console.
+ * Otherwise, return false.
+ *
+ * Context: Can be called in any context but only when Braille console is
+ * registered and the struct console could not disappear.
+ */
+bool nbcon_write_context_is_braille(struct nbcon_write_context *wctxt)
+{
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+ struct console *con = ctxt->console;
+
+ return con && con->flags & CON_BRL;
+}
+EXPORT_SYMBOL_GPL(nbcon_write_context_is_braille);
+
+/**
+ * nbcon_braille_try_acquire - Try to acquire nbcon console for braille_write()
+ *
+ * @con: The nbcon console to acquire
+ * @wctxt: The nbcon write context to be used on success
+ *
+ * Context: braille_write() for emitting a single buffer on Braille console.
+ *
+ * Return: True if the console was acquired. False otherwise.
+ *
+ * Braille console is not registered as a proper printk consoles. Instead,
+ * it is integrated with the graphical virtual terminal.
+ *
+ * This function is going to synchronize the Braille write against other
+ * operations on the used serial port. The port can be used also for a user
+ * input but printk() won't emit the messages there directly. It means
+ * the other operations will get synchronized using nbcon_device_try_acquire().
+ */
+bool nbcon_braille_try_acquire(struct console *con,
+ struct nbcon_write_context *wctxt)
+{
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+ bool success;
+
+ memset(ctxt, 0, sizeof(*ctxt));
+ ctxt->console = con;
+ /* Keep in sync with nbcon_device_try_acquire(). */
+ if (panic_on_this_cpu())
+ ctxt->prio = NBCON_PRIO_PANIC;
+ else
+ ctxt->prio = NBCON_PRIO_NORMAL;
+
+ success = nbcon_context_try_acquire(ctxt, false);
+ /*
+ * Try hard in panic, otherwise the Braille console would
+ * miss a text on the related VT.
+ */
+ if (panic_on_this_cpu() && !success) {
+ ctxt->allow_unsafe_takeover = true;
+ success = nbcon_context_try_acquire(ctxt, false);
+ }
+
+ return success;
+}
+
+/**
+ * nbcon_braille_release - Release the nbcon console
+ *
+ * @wctxt: The nbcon write context initialized by a successful
+ * nbcon_braille_try_acquire()
+ */
+void nbcon_braille_release(struct nbcon_write_context *wctxt)
+{
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+
+ nbcon_context_release(ctxt);
+}