1672fc84aSRobert Mustacchi /*
2672fc84aSRobert Mustacchi * This file and its contents are supplied under the terms of the
3672fc84aSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4672fc84aSRobert Mustacchi * You may only use this file in accordance with the terms of version
5672fc84aSRobert Mustacchi * 1.0 of the CDDL.
6672fc84aSRobert Mustacchi *
7672fc84aSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8672fc84aSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
9672fc84aSRobert Mustacchi * http://www.illumos.org/license/CDDL.
10672fc84aSRobert Mustacchi */
11672fc84aSRobert Mustacchi
12672fc84aSRobert Mustacchi /*
13672fc84aSRobert Mustacchi * Copyright (c) 2018, Joyent, Inc.
14672fc84aSRobert Mustacchi */
15672fc84aSRobert Mustacchi
16672fc84aSRobert Mustacchi /*
17672fc84aSRobert Mustacchi * This module parses the private file format used for describing
18672fc84aSRobert Mustacchi * platform-specific USB overrides.
19672fc84aSRobert Mustacchi *
20672fc84aSRobert Mustacchi * FILE FORMAT
21672fc84aSRobert Mustacchi * -----------
22672fc84aSRobert Mustacchi *
23672fc84aSRobert Mustacchi * A USB topology file contains a series of lines which are separated by new
24672fc84aSRobert Mustacchi * lines. Leading and trailing whitespace on a line are ignored and empty lines
25672fc84aSRobert Mustacchi * are ignored as well. The '#' character is used as a comment character. There
26672fc84aSRobert Mustacchi * are a series of keywords that are supported which are used to indicate
27672fc84aSRobert Mustacchi * different control aspects. These keywords are all treated in a
28672fc84aSRobert Mustacchi * case-insensitive fashion. There are both top-level keywords and keywords that
29672fc84aSRobert Mustacchi * are only accepted within the context of a scope.
30672fc84aSRobert Mustacchi *
31672fc84aSRobert Mustacchi * Top-level keywords
32672fc84aSRobert Mustacchi * ------------------
33672fc84aSRobert Mustacchi *
34672fc84aSRobert Mustacchi * The following keywords are accepted, but must not be found inside a nested
35672fc84aSRobert Mustacchi * scope:
36672fc84aSRobert Mustacchi *
37672fc84aSRobert Mustacchi * 'disable-acpi' Disables the use of ACPI for this platform. This
38672fc84aSRobert Mustacchi * includes getting information about the port's
39672fc84aSRobert Mustacchi * type and visibility. This implies
40672fc84aSRobert Mustacchi * 'disable-acpi-match'.
41672fc84aSRobert Mustacchi *
42672fc84aSRobert Mustacchi * 'disable-acpi-match' Disables the act of trying to match ports based
43672fc84aSRobert Mustacchi * on ACPI.
44672fc84aSRobert Mustacchi *
45672fc84aSRobert Mustacchi *
46672fc84aSRobert Mustacchi * 'enable-acpi-match' Explicitly enables ACPI port matching on the
47672fc84aSRobert Mustacchi * platform based on ACPI.
48672fc84aSRobert Mustacchi *
49672fc84aSRobert Mustacchi * 'enable-metadata-match' Enables port matching based on metadata. This is
50672fc84aSRobert Mustacchi * most commonly used on platforms that have ehci
51672fc84aSRobert Mustacchi * and xhci controllers that share ports.
52672fc84aSRobert Mustacchi *
53672fc84aSRobert Mustacchi * 'port' Begins a port stanza that describes a single
54672fc84aSRobert Mustacchi * physical port. This stanza will continue until
55672fc84aSRobert Mustacchi * the 'end-port' keyword is encountered.
56672fc84aSRobert Mustacchi *
57672fc84aSRobert Mustacchi * Port Keywords
58672fc84aSRobert Mustacchi * -------------
59672fc84aSRobert Mustacchi *
60672fc84aSRobert Mustacchi * Some port keywords take arguments and others do not. When an argument exists,
61672fc84aSRobert Mustacchi * will occur on the subsequent line. Ports have a series of directives that
62672fc84aSRobert Mustacchi * describe metadata as well as directives that describe how to determine the
63672fc84aSRobert Mustacchi * port.
64672fc84aSRobert Mustacchi *
65672fc84aSRobert Mustacchi * 'label' Indicates that the next line contains the
66672fc84aSRobert Mustacchi * human-readable label for the port.
67672fc84aSRobert Mustacchi *
68672fc84aSRobert Mustacchi * 'chassis' Indicates that this port is part of the chassis
69672fc84aSRobert Mustacchi * and should not be enumerated elsewhere.
70672fc84aSRobert Mustacchi *
71672fc84aSRobert Mustacchi * 'external' Indicates that this port is externally visible.
72672fc84aSRobert Mustacchi *
73672fc84aSRobert Mustacchi * 'internal' Indicates that this port is internal to the
74672fc84aSRobert Mustacchi * chassis and cannot be accessed without opening
75672fc84aSRobert Mustacchi * the chassis.
76672fc84aSRobert Mustacchi *
77672fc84aSRobert Mustacchi * 'port-type' Indicates that the next line contains a number
78672fc84aSRobert Mustacchi * which corresponds to the type of the port. The
79672fc84aSRobert Mustacchi * port numbers are based on the ACPI table and
80672fc84aSRobert Mustacchi * may be in either base 10 or hexadecimal.
81672fc84aSRobert Mustacchi *
82672fc84aSRobert Mustacchi * 'acpi-path' Indicates that the next line contains an ACPI
83672fc84aSRobert Mustacchi * based name that matches the port.
84672fc84aSRobert Mustacchi *
85672fc84aSRobert Mustacchi * 'end-port' Closes the port-clause.
86672fc84aSRobert Mustacchi */
87672fc84aSRobert Mustacchi
88672fc84aSRobert Mustacchi #include <libnvpair.h>
89672fc84aSRobert Mustacchi #include <sys/types.h>
90672fc84aSRobert Mustacchi #include <sys/stat.h>
91672fc84aSRobert Mustacchi #include <fcntl.h>
92672fc84aSRobert Mustacchi #include <fm/topo_list.h>
93672fc84aSRobert Mustacchi #include <fm/topo_mod.h>
94672fc84aSRobert Mustacchi #include <stdio.h>
95672fc84aSRobert Mustacchi #include <string.h>
96672fc84aSRobert Mustacchi #include <strings.h>
97672fc84aSRobert Mustacchi #include <libnvpair.h>
98672fc84aSRobert Mustacchi #include <sys/debug.h>
99672fc84aSRobert Mustacchi #include <ctype.h>
100672fc84aSRobert Mustacchi #include <unistd.h>
101672fc84aSRobert Mustacchi
102672fc84aSRobert Mustacchi #include "topo_usb.h"
103672fc84aSRobert Mustacchi #include "topo_usb_int.h"
104672fc84aSRobert Mustacchi
105672fc84aSRobert Mustacchi /*
106672fc84aSRobert Mustacchi * Maximum number of characters we expect to encounter in a line.
107672fc84aSRobert Mustacchi */
108672fc84aSRobert Mustacchi #define TOPO_USB_META_LINE_MAX 1000
109672fc84aSRobert Mustacchi
110672fc84aSRobert Mustacchi /*
111672fc84aSRobert Mustacchi * This constant is the default set of flags that we'd like to apply when there
112672fc84aSRobert Mustacchi * is no configuration file present to determine the desired behavior. If one is
113672fc84aSRobert Mustacchi * present, we always defer to what it asks for.
114672fc84aSRobert Mustacchi *
115672fc84aSRobert Mustacchi * It's a difficult decision to enable ACPI by default or not. Unfortunately,
116672fc84aSRobert Mustacchi * we've encountered some systems where the ACPI information is wrong. However,
117672fc84aSRobert Mustacchi * we've encountered a larger number where it is correct. When it's correct,
118672fc84aSRobert Mustacchi * this greatly simplifies some of the work that we have to do. Our default
119672fc84aSRobert Mustacchi * disposition at the moment is to opt to decide its correct as that ends up
120672fc84aSRobert Mustacchi * giving us much better information.
121672fc84aSRobert Mustacchi */
122672fc84aSRobert Mustacchi #define USB_TOPO_META_DEFAULT_FLAGS TOPO_USB_M_ACPI_MATCH
123672fc84aSRobert Mustacchi
124672fc84aSRobert Mustacchi typedef enum {
125672fc84aSRobert Mustacchi TOPO_USB_P_START,
126672fc84aSRobert Mustacchi TOPO_USB_P_PORT,
127672fc84aSRobert Mustacchi TOPO_USB_P_LABEL,
128672fc84aSRobert Mustacchi TOPO_USB_P_PORT_TYPE,
129672fc84aSRobert Mustacchi TOPO_USB_P_ACPI_PATH
130672fc84aSRobert Mustacchi } topo_usb_parse_state_t;
131672fc84aSRobert Mustacchi
132672fc84aSRobert Mustacchi typedef struct topo_usb_parse {
133672fc84aSRobert Mustacchi topo_usb_parse_state_t tp_state;
134672fc84aSRobert Mustacchi topo_list_t *tp_ports;
135672fc84aSRobert Mustacchi topo_usb_meta_port_t *tp_cport;
136672fc84aSRobert Mustacchi topo_usb_meta_flags_t tp_flags;
137672fc84aSRobert Mustacchi } topo_usb_parse_t;
138672fc84aSRobert Mustacchi
139672fc84aSRobert Mustacchi /*
140672fc84aSRobert Mustacchi * Read the next line in the file with content. Trim trailing and leading
141672fc84aSRobert Mustacchi * whitespace and trim comments out. If this results in an empty line, read the
142672fc84aSRobert Mustacchi * next. Returns zero if we hit EOF. Otherwise, returns one if data, or negative
143672fc84aSRobert Mustacchi * one if an error occurred.
144672fc84aSRobert Mustacchi */
145672fc84aSRobert Mustacchi static int
topo_usb_getline(topo_mod_t * mod,char * buf,size_t len,FILE * f,char ** first)146672fc84aSRobert Mustacchi topo_usb_getline(topo_mod_t *mod, char *buf, size_t len, FILE *f, char **first)
147672fc84aSRobert Mustacchi {
148672fc84aSRobert Mustacchi while (fgets(buf, len, f) != NULL) {
149672fc84aSRobert Mustacchi char *c;
150672fc84aSRobert Mustacchi size_t i;
151672fc84aSRobert Mustacchi
152672fc84aSRobert Mustacchi if ((c = strrchr(buf, '\n')) == NULL) {
153672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "failed to find new line in "
154672fc84aSRobert Mustacchi "metadata file");
155672fc84aSRobert Mustacchi return (-1);
156672fc84aSRobert Mustacchi }
157672fc84aSRobert Mustacchi
158672fc84aSRobert Mustacchi while (isspace(*c) != 0 && c >= buf) {
159672fc84aSRobert Mustacchi *c = '\0';
160672fc84aSRobert Mustacchi c--;
161672fc84aSRobert Mustacchi continue;
162672fc84aSRobert Mustacchi }
163672fc84aSRobert Mustacchi
164672fc84aSRobert Mustacchi if ((c = strchr(buf, '#')) != 0) {
165672fc84aSRobert Mustacchi *c = '\0';
166672fc84aSRobert Mustacchi }
167672fc84aSRobert Mustacchi
168672fc84aSRobert Mustacchi for (i = 0; buf[i] != '\0'; i++) {
169672fc84aSRobert Mustacchi if (isspace(buf[i]) == 0)
170672fc84aSRobert Mustacchi break;
171672fc84aSRobert Mustacchi }
172672fc84aSRobert Mustacchi
173672fc84aSRobert Mustacchi if (buf[i] == '\0')
174672fc84aSRobert Mustacchi continue;
175672fc84aSRobert Mustacchi *first = &buf[i];
176672fc84aSRobert Mustacchi return (1);
177672fc84aSRobert Mustacchi }
178672fc84aSRobert Mustacchi
179672fc84aSRobert Mustacchi return (0);
180672fc84aSRobert Mustacchi }
181672fc84aSRobert Mustacchi
182672fc84aSRobert Mustacchi static boolean_t
topo_usb_parse_start(topo_mod_t * mod,topo_usb_parse_t * parse,const char * line)183672fc84aSRobert Mustacchi topo_usb_parse_start(topo_mod_t *mod, topo_usb_parse_t *parse, const char *line)
184672fc84aSRobert Mustacchi {
185672fc84aSRobert Mustacchi topo_usb_meta_port_t *port;
186672fc84aSRobert Mustacchi
187672fc84aSRobert Mustacchi VERIFY3S(parse->tp_state, ==, TOPO_USB_P_START);
188672fc84aSRobert Mustacchi VERIFY3P(parse->tp_cport, ==, NULL);
189672fc84aSRobert Mustacchi
190672fc84aSRobert Mustacchi if (strcasecmp(line, "disable-acpi") == 0) {
191672fc84aSRobert Mustacchi parse->tp_flags |= TOPO_USB_M_NO_ACPI;
192672fc84aSRobert Mustacchi parse->tp_flags &= ~TOPO_USB_M_ACPI_MATCH;
193672fc84aSRobert Mustacchi return (B_TRUE);
194672fc84aSRobert Mustacchi } else if (strcasecmp(line, "disable-acpi-match") == 0) {
195672fc84aSRobert Mustacchi parse->tp_flags &= ~TOPO_USB_M_ACPI_MATCH;
196672fc84aSRobert Mustacchi return (B_TRUE);
197672fc84aSRobert Mustacchi } else if (strcasecmp(line, "enable-acpi-match") == 0) {
198672fc84aSRobert Mustacchi parse->tp_flags |= TOPO_USB_M_ACPI_MATCH;
199672fc84aSRobert Mustacchi return (B_TRUE);
200672fc84aSRobert Mustacchi } else if (strcasecmp(line, "enable-metadata-match") == 0) {
201672fc84aSRobert Mustacchi parse->tp_flags |= TOPO_USB_M_METADATA_MATCH;
202672fc84aSRobert Mustacchi return (B_TRUE);
203672fc84aSRobert Mustacchi } else if (strcasecmp(line, "port") != 0) {
204672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "expected 'port', encountered %s",
205672fc84aSRobert Mustacchi line);
206672fc84aSRobert Mustacchi return (B_FALSE);
207672fc84aSRobert Mustacchi }
208672fc84aSRobert Mustacchi
209672fc84aSRobert Mustacchi if ((port = topo_mod_zalloc(mod, sizeof (topo_usb_meta_port_t))) ==
210672fc84aSRobert Mustacchi NULL) {
211672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "failed to allocate metadata port");
212672fc84aSRobert Mustacchi return (B_FALSE);
213672fc84aSRobert Mustacchi }
214672fc84aSRobert Mustacchi port->tmp_port_type = 0xff;
215672fc84aSRobert Mustacchi
216672fc84aSRobert Mustacchi parse->tp_cport = port;
217672fc84aSRobert Mustacchi parse->tp_state = TOPO_USB_P_PORT;
218672fc84aSRobert Mustacchi return (B_TRUE);
219672fc84aSRobert Mustacchi }
220672fc84aSRobert Mustacchi
221672fc84aSRobert Mustacchi static boolean_t
topo_usb_parse_port(topo_mod_t * mod,topo_usb_parse_t * parse,const char * line)222672fc84aSRobert Mustacchi topo_usb_parse_port(topo_mod_t *mod, topo_usb_parse_t *parse, const char *line)
223672fc84aSRobert Mustacchi {
224672fc84aSRobert Mustacchi VERIFY3S(parse->tp_state, ==, TOPO_USB_P_PORT);
225672fc84aSRobert Mustacchi VERIFY3P(parse->tp_cport, !=, NULL);
226672fc84aSRobert Mustacchi
227672fc84aSRobert Mustacchi if (strcasecmp(line, "label") == 0) {
228672fc84aSRobert Mustacchi parse->tp_state = TOPO_USB_P_LABEL;
229672fc84aSRobert Mustacchi } else if (strcasecmp(line, "chassis") == 0) {
230672fc84aSRobert Mustacchi parse->tp_cport->tmp_flags |= TOPO_USB_F_CHASSIS;
231672fc84aSRobert Mustacchi } else if (strcasecmp(line, "external") == 0) {
232672fc84aSRobert Mustacchi parse->tp_cport->tmp_flags |= TOPO_USB_F_EXTERNAL;
233672fc84aSRobert Mustacchi } else if (strcasecmp(line, "internal") == 0) {
234672fc84aSRobert Mustacchi parse->tp_cport->tmp_flags |= TOPO_USB_F_INTERNAL;
235672fc84aSRobert Mustacchi } else if (strcasecmp(line, "port-type") == 0) {
236672fc84aSRobert Mustacchi parse->tp_state = TOPO_USB_P_PORT_TYPE;
237672fc84aSRobert Mustacchi } else if (strcasecmp(line, "acpi-path") == 0) {
238672fc84aSRobert Mustacchi parse->tp_state = TOPO_USB_P_ACPI_PATH;
239672fc84aSRobert Mustacchi } else if (strcasecmp(line, "end-port") == 0) {
240672fc84aSRobert Mustacchi topo_list_append(parse->tp_ports, parse->tp_cport);
241672fc84aSRobert Mustacchi parse->tp_cport = NULL;
242672fc84aSRobert Mustacchi parse->tp_state = TOPO_USB_P_START;
243672fc84aSRobert Mustacchi } else {
244672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "illegal directive in port block: %s",
245672fc84aSRobert Mustacchi line);
246672fc84aSRobert Mustacchi return (B_FALSE);
247672fc84aSRobert Mustacchi }
248672fc84aSRobert Mustacchi
249672fc84aSRobert Mustacchi return (B_TRUE);
250672fc84aSRobert Mustacchi }
251672fc84aSRobert Mustacchi
252672fc84aSRobert Mustacchi static boolean_t
topo_usb_parse_label(topo_mod_t * mod,topo_usb_parse_t * parse,const char * line)253672fc84aSRobert Mustacchi topo_usb_parse_label(topo_mod_t *mod, topo_usb_parse_t *parse, const char *line)
254672fc84aSRobert Mustacchi {
255672fc84aSRobert Mustacchi size_t i, len;
256672fc84aSRobert Mustacchi
257672fc84aSRobert Mustacchi VERIFY3S(parse->tp_state, ==, TOPO_USB_P_LABEL);
258672fc84aSRobert Mustacchi
259672fc84aSRobert Mustacchi len = strlen(line);
260672fc84aSRobert Mustacchi for (i = 0; i < len; i++) {
261672fc84aSRobert Mustacchi if (isascii(line[i]) == 0 || isprint(line[i]) == 0) {
262*6597d6fcSRobert Mustacchi topo_mod_dprintf(mod, "label character %zu is "
263672fc84aSRobert Mustacchi "invalid: 0x%x", i, line[i]);
264672fc84aSRobert Mustacchi return (B_FALSE);
265672fc84aSRobert Mustacchi }
266672fc84aSRobert Mustacchi }
267672fc84aSRobert Mustacchi
268672fc84aSRobert Mustacchi if (parse->tp_cport->tmp_label != NULL) {
269672fc84aSRobert Mustacchi topo_mod_strfree(mod, parse->tp_cport->tmp_label);
270672fc84aSRobert Mustacchi }
271672fc84aSRobert Mustacchi
272672fc84aSRobert Mustacchi if ((parse->tp_cport->tmp_label = topo_mod_strdup(mod, line)) == NULL) {
273672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "failed to duplicate label for port");
274672fc84aSRobert Mustacchi return (B_FALSE);
275672fc84aSRobert Mustacchi }
276672fc84aSRobert Mustacchi
277672fc84aSRobert Mustacchi parse->tp_state = TOPO_USB_P_PORT;
278672fc84aSRobert Mustacchi
279672fc84aSRobert Mustacchi return (B_TRUE);
280672fc84aSRobert Mustacchi }
281672fc84aSRobert Mustacchi
282672fc84aSRobert Mustacchi static boolean_t
topo_usb_parse_port_type(topo_mod_t * mod,topo_usb_parse_t * parse,const char * line)283672fc84aSRobert Mustacchi topo_usb_parse_port_type(topo_mod_t *mod, topo_usb_parse_t *parse,
284672fc84aSRobert Mustacchi const char *line)
285672fc84aSRobert Mustacchi {
286672fc84aSRobert Mustacchi unsigned long val;
287672fc84aSRobert Mustacchi char *eptr;
288672fc84aSRobert Mustacchi
289672fc84aSRobert Mustacchi VERIFY3S(parse->tp_state, ==, TOPO_USB_P_PORT_TYPE);
290672fc84aSRobert Mustacchi
291672fc84aSRobert Mustacchi errno = 0;
292672fc84aSRobert Mustacchi val = strtoul(line, &eptr, 0);
293022bfefbSJohn Levon if (errno != 0 || *eptr != '\0' || val >= UINT_MAX) {
294672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "encountered bad value for port-type "
295672fc84aSRobert Mustacchi "line: %s", line);
296672fc84aSRobert Mustacchi return (B_FALSE);
297672fc84aSRobert Mustacchi }
298672fc84aSRobert Mustacchi
299672fc84aSRobert Mustacchi parse->tp_cport->tmp_port_type = (uint_t)val;
300672fc84aSRobert Mustacchi
301672fc84aSRobert Mustacchi parse->tp_state = TOPO_USB_P_PORT;
302672fc84aSRobert Mustacchi return (B_TRUE);
303672fc84aSRobert Mustacchi }
304672fc84aSRobert Mustacchi
305672fc84aSRobert Mustacchi static boolean_t
topo_usb_parse_path(topo_mod_t * mod,topo_usb_parse_t * parse,topo_usb_path_type_t ptype,const char * line)306672fc84aSRobert Mustacchi topo_usb_parse_path(topo_mod_t *mod, topo_usb_parse_t *parse,
307672fc84aSRobert Mustacchi topo_usb_path_type_t ptype, const char *line)
308672fc84aSRobert Mustacchi {
309672fc84aSRobert Mustacchi char *fspath;
310672fc84aSRobert Mustacchi topo_usb_meta_port_path_t *path;
311672fc84aSRobert Mustacchi
312672fc84aSRobert Mustacchi VERIFY(parse->tp_state == TOPO_USB_P_ACPI_PATH);
313672fc84aSRobert Mustacchi VERIFY3P(parse->tp_cport, !=, NULL);
314672fc84aSRobert Mustacchi
315672fc84aSRobert Mustacchi if ((fspath = topo_mod_strdup(mod, line)) == NULL) {
316672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "failed to duplicate path");
317672fc84aSRobert Mustacchi return (B_FALSE);
318672fc84aSRobert Mustacchi }
319672fc84aSRobert Mustacchi
320672fc84aSRobert Mustacchi if ((path = topo_mod_zalloc(mod, sizeof (topo_usb_meta_port_path_t))) ==
321672fc84aSRobert Mustacchi NULL) {
322672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "failed to allocate meta port path "
323672fc84aSRobert Mustacchi "structure");
324672fc84aSRobert Mustacchi topo_mod_strfree(mod, fspath);
325672fc84aSRobert Mustacchi return (B_FALSE);
326672fc84aSRobert Mustacchi }
327672fc84aSRobert Mustacchi
328672fc84aSRobert Mustacchi path->tmpp_type = ptype;
329672fc84aSRobert Mustacchi path->tmpp_path = fspath;
330672fc84aSRobert Mustacchi
331672fc84aSRobert Mustacchi topo_list_append(&parse->tp_cport->tmp_paths, path);
332672fc84aSRobert Mustacchi
333672fc84aSRobert Mustacchi parse->tp_state = TOPO_USB_P_PORT;
334672fc84aSRobert Mustacchi return (B_TRUE);
335672fc84aSRobert Mustacchi }
336672fc84aSRobert Mustacchi
337672fc84aSRobert Mustacchi
338672fc84aSRobert Mustacchi void
topo_usb_free_metadata(topo_mod_t * mod,topo_list_t * metadata)339672fc84aSRobert Mustacchi topo_usb_free_metadata(topo_mod_t *mod, topo_list_t *metadata)
340672fc84aSRobert Mustacchi {
341672fc84aSRobert Mustacchi topo_usb_meta_port_t *mp;
342672fc84aSRobert Mustacchi
343672fc84aSRobert Mustacchi while ((mp = topo_list_next(metadata)) != NULL) {
344672fc84aSRobert Mustacchi topo_usb_meta_port_path_t *path;
345672fc84aSRobert Mustacchi
346672fc84aSRobert Mustacchi while ((path = topo_list_next((&mp->tmp_paths))) != NULL) {
347672fc84aSRobert Mustacchi topo_list_delete(&mp->tmp_paths, path);
348672fc84aSRobert Mustacchi topo_mod_strfree(mod, path->tmpp_path);
349672fc84aSRobert Mustacchi topo_mod_free(mod, path,
350672fc84aSRobert Mustacchi sizeof (topo_usb_meta_port_path_t));
351672fc84aSRobert Mustacchi }
352672fc84aSRobert Mustacchi
353672fc84aSRobert Mustacchi topo_list_delete(metadata, mp);
354672fc84aSRobert Mustacchi topo_mod_strfree(mod, mp->tmp_label);
355672fc84aSRobert Mustacchi topo_mod_free(mod, mp, sizeof (topo_usb_meta_port_t));
356672fc84aSRobert Mustacchi }
357672fc84aSRobert Mustacchi }
358672fc84aSRobert Mustacchi
359672fc84aSRobert Mustacchi int
topo_usb_load_metadata(topo_mod_t * mod,tnode_t * pnode,topo_list_t * list,topo_usb_meta_flags_t * flagsp)360672fc84aSRobert Mustacchi topo_usb_load_metadata(topo_mod_t *mod, tnode_t *pnode, topo_list_t *list,
361672fc84aSRobert Mustacchi topo_usb_meta_flags_t *flagsp)
362672fc84aSRobert Mustacchi {
363672fc84aSRobert Mustacchi int fd;
364672fc84aSRobert Mustacchi FILE *f = NULL;
365672fc84aSRobert Mustacchi char buf[TOPO_USB_META_LINE_MAX], *first, *prod;
366672fc84aSRobert Mustacchi int ret;
367672fc84aSRobert Mustacchi topo_usb_parse_t parse;
368672fc84aSRobert Mustacchi char pbuf[PATH_MAX];
369672fc84aSRobert Mustacchi
370672fc84aSRobert Mustacchi *flagsp = USB_TOPO_META_DEFAULT_FLAGS;
371672fc84aSRobert Mustacchi
372672fc84aSRobert Mustacchi /*
373672fc84aSRobert Mustacchi * If no product string, just leave it as is and don't attempt to get
374672fc84aSRobert Mustacchi * metadata.
375672fc84aSRobert Mustacchi */
376672fc84aSRobert Mustacchi if ((topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
377672fc84aSRobert Mustacchi FM_FMRI_AUTH_PRODUCT, &prod, &ret)) != 0) {
378672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "skipping metadata load: failed to get "
379672fc84aSRobert Mustacchi "auth");
380672fc84aSRobert Mustacchi return (0);
381672fc84aSRobert Mustacchi }
382672fc84aSRobert Mustacchi
383672fc84aSRobert Mustacchi if (snprintf(pbuf, sizeof (pbuf), "maps/%s-usb.usbtopo", prod) >=
384672fc84aSRobert Mustacchi sizeof (pbuf)) {
385672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "skipping metadata load: product name "
386672fc84aSRobert Mustacchi "too long");
387672fc84aSRobert Mustacchi topo_mod_strfree(mod, prod);
388672fc84aSRobert Mustacchi return (0);
389672fc84aSRobert Mustacchi }
390672fc84aSRobert Mustacchi topo_mod_strfree(mod, prod);
391672fc84aSRobert Mustacchi
392672fc84aSRobert Mustacchi if ((fd = topo_mod_file_search(mod, pbuf, O_RDONLY)) < 0) {
393672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "skipping metadata load: couldn't find "
394672fc84aSRobert Mustacchi "%s", pbuf);
395672fc84aSRobert Mustacchi return (0);
396672fc84aSRobert Mustacchi }
397672fc84aSRobert Mustacchi
398672fc84aSRobert Mustacchi
399672fc84aSRobert Mustacchi if ((f = fdopen(fd, "r")) == NULL) {
400672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "failed to fdopen metadata file %s: %s",
401672fc84aSRobert Mustacchi pbuf, strerror(errno));
402672fc84aSRobert Mustacchi VERIFY0(close(fd));
403672fc84aSRobert Mustacchi ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
404672fc84aSRobert Mustacchi goto err;
405672fc84aSRobert Mustacchi }
406672fc84aSRobert Mustacchi
407672fc84aSRobert Mustacchi bzero(&parse, sizeof (parse));
408672fc84aSRobert Mustacchi parse.tp_ports = list;
409672fc84aSRobert Mustacchi parse.tp_state = TOPO_USB_P_START;
410672fc84aSRobert Mustacchi
411672fc84aSRobert Mustacchi while ((ret = topo_usb_getline(mod, buf, sizeof (buf), f, &first)) !=
412672fc84aSRobert Mustacchi 0) {
413672fc84aSRobert Mustacchi if (ret == -1) {
414672fc84aSRobert Mustacchi ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
415672fc84aSRobert Mustacchi goto err;
416672fc84aSRobert Mustacchi }
417672fc84aSRobert Mustacchi
418672fc84aSRobert Mustacchi switch (parse.tp_state) {
419672fc84aSRobert Mustacchi case TOPO_USB_P_START:
420672fc84aSRobert Mustacchi if (!topo_usb_parse_start(mod, &parse, first)) {
421672fc84aSRobert Mustacchi ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
422672fc84aSRobert Mustacchi goto err;
423672fc84aSRobert Mustacchi }
424672fc84aSRobert Mustacchi break;
425672fc84aSRobert Mustacchi case TOPO_USB_P_PORT:
426672fc84aSRobert Mustacchi if (!topo_usb_parse_port(mod, &parse, first)) {
427672fc84aSRobert Mustacchi ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
428672fc84aSRobert Mustacchi goto err;
429672fc84aSRobert Mustacchi }
430672fc84aSRobert Mustacchi break;
431672fc84aSRobert Mustacchi case TOPO_USB_P_LABEL:
432672fc84aSRobert Mustacchi if (!topo_usb_parse_label(mod, &parse, first)) {
433672fc84aSRobert Mustacchi ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
434672fc84aSRobert Mustacchi goto err;
435672fc84aSRobert Mustacchi }
436672fc84aSRobert Mustacchi break;
437672fc84aSRobert Mustacchi case TOPO_USB_P_PORT_TYPE:
438672fc84aSRobert Mustacchi if (!topo_usb_parse_port_type(mod, &parse, first)) {
439672fc84aSRobert Mustacchi ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
440672fc84aSRobert Mustacchi goto err;
441672fc84aSRobert Mustacchi }
442672fc84aSRobert Mustacchi break;
443672fc84aSRobert Mustacchi
444672fc84aSRobert Mustacchi case TOPO_USB_P_ACPI_PATH:
445672fc84aSRobert Mustacchi if (!topo_usb_parse_path(mod, &parse, TOPO_USB_T_ACPI,
446672fc84aSRobert Mustacchi first)) {
447672fc84aSRobert Mustacchi ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
448672fc84aSRobert Mustacchi goto err;
449672fc84aSRobert Mustacchi }
450672fc84aSRobert Mustacchi break;
451672fc84aSRobert Mustacchi }
452672fc84aSRobert Mustacchi }
453672fc84aSRobert Mustacchi
454672fc84aSRobert Mustacchi if (parse.tp_state != TOPO_USB_P_START) {
455672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "metadata file didn't end in correct "
456672fc84aSRobert Mustacchi "state, failing");
457672fc84aSRobert Mustacchi ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
458672fc84aSRobert Mustacchi goto err;
459672fc84aSRobert Mustacchi }
460672fc84aSRobert Mustacchi
461672fc84aSRobert Mustacchi topo_mod_dprintf(mod, "successfully loaded metadata %s", pbuf);
462672fc84aSRobert Mustacchi VERIFY0(fclose(f));
463672fc84aSRobert Mustacchi *flagsp = parse.tp_flags;
464672fc84aSRobert Mustacchi return (0);
465672fc84aSRobert Mustacchi
466672fc84aSRobert Mustacchi err:
467672fc84aSRobert Mustacchi if (f != NULL)
468672fc84aSRobert Mustacchi VERIFY0(fclose(f));
469672fc84aSRobert Mustacchi topo_usb_free_metadata(mod, list);
470672fc84aSRobert Mustacchi return (ret);
471672fc84aSRobert Mustacchi }
472