]>
Commit | Line | Data |
---|---|---|
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 | ||
27 | struct 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 */ | |
35 | static 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 | */ | |
47 | int __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 | ||
93 | static 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 | */ | |
120 | int 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 | } |