IOMUX: Split out iomux_match_device() helper
[platform/kernel/u-boot.git] / common / iomux.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2008
4  * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
5  */
6
7 #include <common.h>
8 #include <console.h>
9 #include <serial.h>
10 #include <malloc.h>
11
12 #if CONFIG_IS_ENABLED(CONSOLE_MUX)
13 void iomux_printdevs(const int console)
14 {
15         int i;
16         struct stdio_dev *dev;
17
18         for (i = 0; i < cd_count[console]; i++) {
19                 dev = console_devices[console][i];
20                 printf("%s ", dev->name);
21         }
22         printf("\n");
23 }
24
25 int iomux_match_device(struct stdio_dev **set, const int n, struct stdio_dev *sdev)
26 {
27         int i;
28
29         for (i = 0; i < n; i++)
30                 if (sdev == set[i])
31                         return i;
32         return -ENOENT;
33 }
34
35 /* This tries to preserve the old list if an error occurs. */
36 int iomux_doenv(const int console, const char *arg)
37 {
38         char *console_args, *temp, **start;
39         int i, j, io_flag, cs_idx, repeat;
40         struct stdio_dev **cons_set, **old_set;
41         struct stdio_dev *dev;
42
43         console_args = strdup(arg);
44         if (console_args == NULL)
45                 return 1;
46         /*
47          * Check whether a comma separated list of devices was
48          * entered and count how many devices were entered.
49          * The array start[] has pointers to the beginning of
50          * each device name (up to MAX_CONSARGS devices).
51          *
52          * Have to do this twice - once to count the number of
53          * commas and then again to populate start.
54          */
55         i = 0;
56         temp = console_args;
57         for (;;) {
58                 /* There's always one entry more than the number of commas. */
59                 i++;
60
61                 temp = strchr(temp, ',');
62                 if (temp == NULL)
63                         break;
64
65                 temp++;
66         }
67         start = (char **)malloc(i * sizeof(char *));
68         if (start == NULL) {
69                 free(console_args);
70                 return 1;
71         }
72         i = 0;
73         start[0] = console_args;
74         for (;;) {
75                 temp = strchr(start[i++], ',');
76                 if (temp == NULL)
77                         break;
78                 *temp = '\0';
79                 start[i] = temp + 1;
80         }
81         cons_set = (struct stdio_dev **)calloc(i, sizeof(struct stdio_dev *));
82         if (cons_set == NULL) {
83                 free(start);
84                 free(console_args);
85                 return 1;
86         }
87
88         io_flag = stdio_file_to_flags(console);
89         if (io_flag < 0) {
90                 free(start);
91                 free(console_args);
92                 free(cons_set);
93                 return 1;
94         }
95
96         cs_idx = 0;
97         for (j = 0; j < i; j++) {
98                 /*
99                  * Check whether the device exists and is valid.
100                  * console_assign() also calls console_search_dev(),
101                  * but I need the pointer to the device.
102                  */
103                 dev = console_search_dev(io_flag, start[j]);
104                 if (dev == NULL)
105                         continue;
106                 /*
107                  * Prevent multiple entries for a device.
108                  */
109                  repeat = iomux_match_device(cons_set, cs_idx, dev);
110                  if (repeat >= 0)
111                         continue;
112                 /*
113                  * Try assigning the specified device.
114                  * This could screw up the console settings for apps.
115                  */
116                 if (console_assign(console, start[j]) < 0)
117                         continue;
118                 cons_set[cs_idx++] = dev;
119         }
120         free(console_args);
121         free(start);
122         /* failed to set any console */
123         if (cs_idx == 0) {
124                 free(cons_set);
125                 return 1;
126         }
127
128         old_set = console_devices[console];
129         repeat = cd_count[console];
130
131         console_devices[console] = cons_set;
132         cd_count[console] = cs_idx;
133
134         /* Stop dropped consoles */
135         for (i = 0; i < repeat; i++) {
136                 j = iomux_match_device(cons_set, cs_idx, old_set[i]);
137                 if (j == cs_idx)
138                         console_stop(console, old_set[i]);
139         }
140
141         free(old_set);
142         return 0;
143 }
144 #endif /* CONSOLE_MUX */