]> git.ipfire.org Git - thirdparty/linux.git/blame - kernel/printk/conopt.c
Merge tag 'tty-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[thirdparty/linux.git] / kernel / printk / conopt.c
CommitLineData
f03e8c10
TL
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Kernel command line console options for hardware based addressing
4 *
5 * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
6 * Author: Tony Lindgren <tony@atomide.com>
7 */
8
9#include <linux/console.h>
10#include <linux/init.h>
11#include <linux/string.h>
12#include <linux/types.h>
13
14#include <asm/errno.h>
15
16#include "console_cmdline.h"
17
18/*
19 * Allow longer DEVNAME:0.0 style console naming such as abcd0000.serial:0.0
20 * in addition to the legacy ttyS0 style naming.
21 */
22#define CONSOLE_NAME_MAX 32
23
24#define CONSOLE_OPT_MAX 16
25#define CONSOLE_BRL_OPT_MAX 16
26
27struct console_option {
28 char name[CONSOLE_NAME_MAX];
29 char opt[CONSOLE_OPT_MAX];
30 char brl_opt[CONSOLE_BRL_OPT_MAX];
31 u8 has_brl_opt:1;
32};
33
34/* Updated only at console_setup() time, no locking needed */
35static struct console_option conopt[MAX_CMDLINECONSOLES];
36
37/**
38 * console_opt_save - Saves kernel command line console option for driver use
39 * @str: Kernel command line console name and option
40 * @brl_opt: Braille console options
41 *
42 * Saves a kernel command line console option for driver subsystems to use for
43 * adding a preferred console during init. Called from console_setup() only.
44 *
45 * Return: 0 on success, negative error code on failure.
46 */
47int __init console_opt_save(const char *str, const char *brl_opt)
48{
49 struct console_option *con;
50 size_t namelen, optlen;
51 const char *opt;
52 int i;
53
54 namelen = strcspn(str, ",");
55 if (namelen == 0 || namelen >= CONSOLE_NAME_MAX)
56 return -EINVAL;
57
58 opt = str + namelen;
59 if (*opt == ',')
60 opt++;
61
62 optlen = strlen(opt);
63 if (optlen >= CONSOLE_OPT_MAX)
64 return -EINVAL;
65
66 for (i = 0; i < MAX_CMDLINECONSOLES; i++) {
67 con = &conopt[i];
68
69 if (con->name[0]) {
70 if (!strncmp(str, con->name, namelen))
71 return 0;
72 continue;
73 }
74
75 /*
76 * The name isn't terminated, only opt is. Empty opt is fine,
77 * but brl_opt can be either empty or NULL. For more info, see
78 * _braille_console_setup().
79 */
80 strscpy(con->name, str, namelen + 1);
81 strscpy(con->opt, opt, CONSOLE_OPT_MAX);
82 if (brl_opt) {
83 strscpy(con->brl_opt, brl_opt, CONSOLE_BRL_OPT_MAX);
84 con->has_brl_opt = 1;
85 }
86
87 return 0;
88 }
89
90 return -ENOMEM;
91}
92
93static struct console_option *console_opt_find(const char *name)
94{
95 struct console_option *con;
96 int i;
97
98 for (i = 0; i < MAX_CMDLINECONSOLES; i++) {
99 con = &conopt[i];
100 if (!strcmp(name, con->name))
101 return con;
102 }
103
104 return NULL;
105}
106
107/**
108 * add_preferred_console_match - Adds a preferred console if a match is found
109 * @match: Expected console on kernel command line, such as console=DEVNAME:0.0
110 * @name: Name of the console character device to add such as ttyS
111 * @idx: Index for the console
112 *
113 * Allows driver subsystems to add a console after translating the command
114 * line name to the character device name used for the console. Options are
115 * added automatically based on the kernel command line. Duplicate preferred
116 * consoles are ignored by __add_preferred_console().
117 *
118 * Return: 0 on success, negative error code on failure.
119 */
120int add_preferred_console_match(const char *match, const char *name,
121 const short idx)
122{
123 struct console_option *con;
124 char *brl_opt = NULL;
125
126 if (!match || !strlen(match) || !name || !strlen(name) ||
127 idx < 0)
128 return -EINVAL;
129
130 con = console_opt_find(match);
131 if (!con)
132 return -ENOENT;
133
134 /*
135 * See __add_preferred_console(). It checks for NULL brl_options to set
136 * the preferred_console flag. Empty brl_opt instead of NULL leads into
137 * the preferred_console flag not set, and CON_CONSDEV not being set,
138 * and the boot console won't get disabled at the end of console_setup().
139 */
140 if (con->has_brl_opt)
141 brl_opt = con->brl_opt;
142
143 console_opt_add_preferred_console(name, idx, con->opt, brl_opt);
144
145 return 0;
146}