xref: /illumos-gate/usr/src/cmd/xhci/xhci_portsc.c (revision 6b1325cf)
1993e3fafSRobert Mustacchi /*
2993e3fafSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3993e3fafSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4993e3fafSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5993e3fafSRobert Mustacchi  * 1.0 of the CDDL.
6993e3fafSRobert Mustacchi  *
7993e3fafSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8993e3fafSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9993e3fafSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10993e3fafSRobert Mustacchi  */
11993e3fafSRobert Mustacchi 
12993e3fafSRobert Mustacchi /*
13993e3fafSRobert Mustacchi  * Copyright 2016 Joyent, Inc.
14993e3fafSRobert Mustacchi  */
15993e3fafSRobert Mustacchi 
16993e3fafSRobert Mustacchi /*
17993e3fafSRobert Mustacchi  * This is a private utility that combines a number of minor debugging routines
18993e3fafSRobert Mustacchi  * for xhci.
19993e3fafSRobert Mustacchi  */
20993e3fafSRobert Mustacchi 
21993e3fafSRobert Mustacchi #include <stdio.h>
22993e3fafSRobert Mustacchi #include <stdarg.h>
23993e3fafSRobert Mustacchi #include <stdlib.h>
24993e3fafSRobert Mustacchi #include <unistd.h>
25993e3fafSRobert Mustacchi #include <err.h>
26993e3fafSRobert Mustacchi #include <string.h>
27993e3fafSRobert Mustacchi #include <sys/types.h>
28993e3fafSRobert Mustacchi #include <sys/stat.h>
29993e3fafSRobert Mustacchi #include <fcntl.h>
30993e3fafSRobert Mustacchi #include <libdevinfo.h>
31993e3fafSRobert Mustacchi #include <sys/usb/hcd/xhci/xhci_ioctl.h>
32993e3fafSRobert Mustacchi #include <sys/usb/hcd/xhci/xhcireg.h>
33993e3fafSRobert Mustacchi 
34993e3fafSRobert Mustacchi static char *xp_devpath = NULL;
35993e3fafSRobert Mustacchi static int xp_npaths;
36993e3fafSRobert Mustacchi static const char *xp_path;
37993e3fafSRobert Mustacchi static const char *xp_state = NULL;
38993e3fafSRobert Mustacchi static uint32_t xp_port;
39993e3fafSRobert Mustacchi static boolean_t xp_verbose = B_FALSE;
40993e3fafSRobert Mustacchi static boolean_t xp_clear = B_FALSE;
41993e3fafSRobert Mustacchi static boolean_t xp_list = B_FALSE;
42993e3fafSRobert Mustacchi extern const char *__progname;
43993e3fafSRobert Mustacchi 
44993e3fafSRobert Mustacchi static int
xp_usage(const char * format,...)45993e3fafSRobert Mustacchi xp_usage(const char *format, ...)
46993e3fafSRobert Mustacchi {
47993e3fafSRobert Mustacchi 	if (format != NULL) {
48993e3fafSRobert Mustacchi 		va_list alist;
49993e3fafSRobert Mustacchi 
50993e3fafSRobert Mustacchi 		va_start(alist, format);
51993e3fafSRobert Mustacchi 		vwarnx(format, alist);
52993e3fafSRobert Mustacchi 		va_end(alist);
53993e3fafSRobert Mustacchi 	}
54993e3fafSRobert Mustacchi 
55993e3fafSRobert Mustacchi 	(void) fprintf(stderr, "usage:  %s [-l] [-v] [-c] [-d path] [-p port] "
56993e3fafSRobert Mustacchi 	    "[-s state]\n", __progname);
57993e3fafSRobert Mustacchi 	return (2);
58993e3fafSRobert Mustacchi }
59993e3fafSRobert Mustacchi 
60993e3fafSRobert Mustacchi static const char *xp_pls_strings[] = {
61993e3fafSRobert Mustacchi 	"U0",
62993e3fafSRobert Mustacchi 	"U1",
63993e3fafSRobert Mustacchi 	"U2",
64993e3fafSRobert Mustacchi 	"U3 (suspended)",
65993e3fafSRobert Mustacchi 	"Disabled",
66993e3fafSRobert Mustacchi 	"RxDetect",
67993e3fafSRobert Mustacchi 	"Inactive",
68993e3fafSRobert Mustacchi 	"Polling",
69993e3fafSRobert Mustacchi 	"Recovery",
70993e3fafSRobert Mustacchi 	"Hot Reset",
71993e3fafSRobert Mustacchi 	"Compliance Mode",
72993e3fafSRobert Mustacchi 	"Test Mode",
73993e3fafSRobert Mustacchi 	"Reserved",
74993e3fafSRobert Mustacchi 	"Reserved",
75993e3fafSRobert Mustacchi 	"Reserved",
76993e3fafSRobert Mustacchi 	"Resume",
77993e3fafSRobert Mustacchi 	NULL
78993e3fafSRobert Mustacchi };
79993e3fafSRobert Mustacchi 
80993e3fafSRobert Mustacchi static void
xp_dump_verbose(uint32_t portsc)81993e3fafSRobert Mustacchi xp_dump_verbose(uint32_t portsc)
82993e3fafSRobert Mustacchi {
83993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_CCS)
84993e3fafSRobert Mustacchi 		(void) printf("\t\t\tCCS\n");
85993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_PED)
86993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPED\n");
87993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_OCA)
88993e3fafSRobert Mustacchi 		(void) printf("\t\t\tOCA\n");
89993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_PR)
90993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPR\n");
91993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_PP) {
92993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPLS: %s (%d)\n",
93993e3fafSRobert Mustacchi 		    xp_pls_strings[XHCI_PS_PLS_GET(portsc)],
94993e3fafSRobert Mustacchi 		    XHCI_PS_PLS_GET(portsc));
95993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPP\n");
96993e3fafSRobert Mustacchi 	} else {
97993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPLS: undefined (No PP)\n");
98993e3fafSRobert Mustacchi 	}
99993e3fafSRobert Mustacchi 
100993e3fafSRobert Mustacchi 	if (XHCI_PS_SPEED_GET(portsc) != 0) {
101993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPort Speed: ");
102993e3fafSRobert Mustacchi 		switch (XHCI_PS_SPEED_GET(portsc)) {
103993e3fafSRobert Mustacchi 		case 0:
104993e3fafSRobert Mustacchi 			(void) printf("Undefined ");
105993e3fafSRobert Mustacchi 			break;
106993e3fafSRobert Mustacchi 		case XHCI_SPEED_FULL:
107993e3fafSRobert Mustacchi 			(void) printf("Full ");
108993e3fafSRobert Mustacchi 			break;
109993e3fafSRobert Mustacchi 		case XHCI_SPEED_LOW:
110993e3fafSRobert Mustacchi 			(void) printf("Low ");
111993e3fafSRobert Mustacchi 			break;
112993e3fafSRobert Mustacchi 		case XHCI_SPEED_HIGH:
113993e3fafSRobert Mustacchi 			(void) printf("High ");
114993e3fafSRobert Mustacchi 			break;
115993e3fafSRobert Mustacchi 		case XHCI_SPEED_SUPER:
116993e3fafSRobert Mustacchi 			(void) printf("Super ");
117993e3fafSRobert Mustacchi 			break;
118993e3fafSRobert Mustacchi 		default:
119993e3fafSRobert Mustacchi 			(void) printf("Unknown ");
120993e3fafSRobert Mustacchi 			break;
121993e3fafSRobert Mustacchi 		}
122993e3fafSRobert Mustacchi 		(void) printf("(%d)\n", XHCI_PS_SPEED_GET(portsc));
123993e3fafSRobert Mustacchi 	}
124993e3fafSRobert Mustacchi 	if (XHCI_PS_PIC_GET(portsc) != 0)
125993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPIC: %d\n", XHCI_PS_PIC_GET(portsc));
126993e3fafSRobert Mustacchi 
127993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_LWS)
128993e3fafSRobert Mustacchi 		(void) printf("\t\t\tLWS\n");
129993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_CSC)
130993e3fafSRobert Mustacchi 		(void) printf("\t\t\tCSC\n");
131993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_PEC)
132993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPEC\n");
133993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_WRC)
134993e3fafSRobert Mustacchi 		(void) printf("\t\t\tWRC\n");
135993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_OCC)
136993e3fafSRobert Mustacchi 		(void) printf("\t\t\tOCC\n");
137993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_PRC)
138993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPRC\n");
139993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_PLC)
140993e3fafSRobert Mustacchi 		(void) printf("\t\t\tPLC\n");
141993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_CEC)
142993e3fafSRobert Mustacchi 		(void) printf("\t\t\tCEC\n");
143993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_CAS)
144993e3fafSRobert Mustacchi 		(void) printf("\t\t\tCAS\n");
145993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_WCE)
146993e3fafSRobert Mustacchi 		(void) printf("\t\t\tWCE\n");
147993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_WDE)
148993e3fafSRobert Mustacchi 		(void) printf("\t\t\tWDE\n");
149993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_WOE)
150993e3fafSRobert Mustacchi 		(void) printf("\t\t\tWOE\n");
151993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_DR)
152993e3fafSRobert Mustacchi 		(void) printf("\t\t\tDR\n");
153993e3fafSRobert Mustacchi 	if (portsc & XHCI_PS_WPR)
154993e3fafSRobert Mustacchi 		(void) printf("\t\t\tWPR\n");
155993e3fafSRobert Mustacchi }
156993e3fafSRobert Mustacchi 
157993e3fafSRobert Mustacchi static void
xp_dump(const char * path)158993e3fafSRobert Mustacchi xp_dump(const char *path)
159993e3fafSRobert Mustacchi {
160993e3fafSRobert Mustacchi 	int fd, i;
161993e3fafSRobert Mustacchi 	xhci_ioctl_portsc_t xhi = { 0 };
162993e3fafSRobert Mustacchi 
163993e3fafSRobert Mustacchi 	fd = open(path, O_RDWR);
164993e3fafSRobert Mustacchi 	if (fd < 0) {
165993e3fafSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open %s", path);
166993e3fafSRobert Mustacchi 	}
167993e3fafSRobert Mustacchi 
168993e3fafSRobert Mustacchi 	if (ioctl(fd, XHCI_IOCTL_PORTSC, &xhi) != 0)
169993e3fafSRobert Mustacchi 		err(EXIT_FAILURE, "failed to get port status");
170993e3fafSRobert Mustacchi 
171993e3fafSRobert Mustacchi 	(void) close(fd);
172993e3fafSRobert Mustacchi 
173993e3fafSRobert Mustacchi 	for (i = 1; i <= xhi.xhi_nports; i++) {
174993e3fafSRobert Mustacchi 		if (xp_port != 0 && i != xp_port)
175993e3fafSRobert Mustacchi 			continue;
176993e3fafSRobert Mustacchi 
177993e3fafSRobert Mustacchi 		(void) printf("port %2d:\t0x%08x\n", i, xhi.xhi_portsc[i]);
178993e3fafSRobert Mustacchi 		if (xp_verbose == B_TRUE)
179993e3fafSRobert Mustacchi 			xp_dump_verbose(xhi.xhi_portsc[i]);
180993e3fafSRobert Mustacchi 	}
181993e3fafSRobert Mustacchi }
182993e3fafSRobert Mustacchi 
183993e3fafSRobert Mustacchi static void
xp_set_pls(const char * path,uint32_t port,const char * state)184993e3fafSRobert Mustacchi xp_set_pls(const char *path, uint32_t port, const char *state)
185993e3fafSRobert Mustacchi {
186993e3fafSRobert Mustacchi 	int fd, i;
187993e3fafSRobert Mustacchi 	xhci_ioctl_setpls_t xis;
188993e3fafSRobert Mustacchi 
189993e3fafSRobert Mustacchi 	fd = open(path, O_RDWR);
190993e3fafSRobert Mustacchi 	if (fd < 0) {
191993e3fafSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open %s", path);
192993e3fafSRobert Mustacchi 	}
193993e3fafSRobert Mustacchi 
194993e3fafSRobert Mustacchi 	xis.xis_port = port;
195993e3fafSRobert Mustacchi 	for (i = 0; xp_pls_strings[i] != NULL; i++) {
196993e3fafSRobert Mustacchi 		if (strcasecmp(state, xp_pls_strings[i]) == 0)
197993e3fafSRobert Mustacchi 			break;
198993e3fafSRobert Mustacchi 	}
199993e3fafSRobert Mustacchi 
200993e3fafSRobert Mustacchi 	if (xp_pls_strings[i] == NULL) {
201993e3fafSRobert Mustacchi 		errx(EXIT_FAILURE, "unknown state string: %s\n", state);
202993e3fafSRobert Mustacchi 	}
203993e3fafSRobert Mustacchi 
204993e3fafSRobert Mustacchi 	xis.xis_pls = i;
205993e3fafSRobert Mustacchi 	(void) printf("setting port %d with pls %d\n", port, xis.xis_pls);
206993e3fafSRobert Mustacchi 
207993e3fafSRobert Mustacchi 	if (ioctl(fd, XHCI_IOCTL_SETPLS, &xis) != 0)
208993e3fafSRobert Mustacchi 		err(EXIT_FAILURE, "failed to set port status");
209993e3fafSRobert Mustacchi 
210993e3fafSRobert Mustacchi 	(void) close(fd);
211993e3fafSRobert Mustacchi }
212993e3fafSRobert Mustacchi 
213993e3fafSRobert Mustacchi static void
xp_clear_change(const char * path,uint32_t port)214993e3fafSRobert Mustacchi xp_clear_change(const char *path, uint32_t port)
215993e3fafSRobert Mustacchi {
216993e3fafSRobert Mustacchi 	int fd;
217993e3fafSRobert Mustacchi 	xhci_ioctl_clear_t xic;
218993e3fafSRobert Mustacchi 
219993e3fafSRobert Mustacchi 	fd = open(path, O_RDWR);
220993e3fafSRobert Mustacchi 	if (fd < 0) {
221993e3fafSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open %s", path);
222993e3fafSRobert Mustacchi 	}
223993e3fafSRobert Mustacchi 
224993e3fafSRobert Mustacchi 	xic.xic_port = port;
225993e3fafSRobert Mustacchi 	(void) printf("clearing change bits on port %d\n", port);
226993e3fafSRobert Mustacchi 	if (ioctl(fd, XHCI_IOCTL_CLEAR, &xic) != 0)
227993e3fafSRobert Mustacchi 		err(EXIT_FAILURE, "failed to set port status");
228993e3fafSRobert Mustacchi 
229993e3fafSRobert Mustacchi 	(void) close(fd);
230993e3fafSRobert Mustacchi }
231993e3fafSRobert Mustacchi 
232993e3fafSRobert Mustacchi /* ARGSUSED */
233993e3fafSRobert Mustacchi static int
xp_devinfo_cb(di_node_t node,void * arg)234993e3fafSRobert Mustacchi xp_devinfo_cb(di_node_t node, void *arg)
235993e3fafSRobert Mustacchi {
236993e3fafSRobert Mustacchi 	char *drv;
237993e3fafSRobert Mustacchi 	di_minor_t minor;
238993e3fafSRobert Mustacchi 	boolean_t *do_print = arg;
239993e3fafSRobert Mustacchi 
240993e3fafSRobert Mustacchi 	drv = di_driver_name(node);
241993e3fafSRobert Mustacchi 	if (drv == NULL)
242993e3fafSRobert Mustacchi 		return (DI_WALK_CONTINUE);
243993e3fafSRobert Mustacchi 	if (strcmp(drv, "xhci") != 0)
244993e3fafSRobert Mustacchi 		return (DI_WALK_CONTINUE);
245993e3fafSRobert Mustacchi 
246993e3fafSRobert Mustacchi 	/*
247993e3fafSRobert Mustacchi 	 * We have an instance of the xhci driver. We need to find the minor
248993e3fafSRobert Mustacchi 	 * node for the hubd instance. These are all usually greater than
249993e3fafSRobert Mustacchi 	 * HUBD_IS_ROOT_HUB. However, to avoid hardcoding that here, we instead
250993e3fafSRobert Mustacchi 	 * rely on the fact that the minor node for the actual device has a
251993e3fafSRobert Mustacchi 	 * :hubd as the intance.
252993e3fafSRobert Mustacchi 	 */
253993e3fafSRobert Mustacchi 	minor = DI_MINOR_NIL;
254993e3fafSRobert Mustacchi 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
255993e3fafSRobert Mustacchi 		char *mname, *path;
256993e3fafSRobert Mustacchi 
257993e3fafSRobert Mustacchi 		mname = di_minor_name(minor);
258993e3fafSRobert Mustacchi 		if (mname == NULL)
259993e3fafSRobert Mustacchi 			continue;
260993e3fafSRobert Mustacchi 		if (strcmp(mname, "hubd") != 0)
261993e3fafSRobert Mustacchi 			continue;
262993e3fafSRobert Mustacchi 		path = di_devfs_minor_path(minor);
263993e3fafSRobert Mustacchi 		if (*do_print == B_TRUE) {
264993e3fafSRobert Mustacchi 			(void) printf("/devices%s\n", path);
265993e3fafSRobert Mustacchi 			di_devfs_path_free(path);
266993e3fafSRobert Mustacchi 		} else {
267993e3fafSRobert Mustacchi 			xp_npaths++;
268993e3fafSRobert Mustacchi 			if (xp_devpath == NULL)
269993e3fafSRobert Mustacchi 				xp_devpath = path;
270993e3fafSRobert Mustacchi 			else
271993e3fafSRobert Mustacchi 				di_devfs_path_free(path);
272993e3fafSRobert Mustacchi 		}
273993e3fafSRobert Mustacchi 	}
274993e3fafSRobert Mustacchi 
275993e3fafSRobert Mustacchi 	return (DI_WALK_PRUNECHILD);
276993e3fafSRobert Mustacchi }
277993e3fafSRobert Mustacchi 
278993e3fafSRobert Mustacchi /*
279993e3fafSRobert Mustacchi  * We need to find all minor nodes of instances of the xhci driver whose name is
280993e3fafSRobert Mustacchi  * 'hubd'.
281993e3fafSRobert Mustacchi  */
282993e3fafSRobert Mustacchi static void
xp_find_devs(boolean_t print)283993e3fafSRobert Mustacchi xp_find_devs(boolean_t print)
284993e3fafSRobert Mustacchi {
285993e3fafSRobert Mustacchi 	di_node_t root;
286993e3fafSRobert Mustacchi 
287993e3fafSRobert Mustacchi 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
288993e3fafSRobert Mustacchi 		err(EXIT_FAILURE, "failed to initialize devices tree");
289993e3fafSRobert Mustacchi 	}
290993e3fafSRobert Mustacchi 
291993e3fafSRobert Mustacchi 	if (di_walk_node(root, DI_WALK_CLDFIRST, &print, xp_devinfo_cb) != 0)
292993e3fafSRobert Mustacchi 		err(EXIT_FAILURE, "failed to walk devices tree");
293993e3fafSRobert Mustacchi }
294993e3fafSRobert Mustacchi 
295993e3fafSRobert Mustacchi int
main(int argc,char * argv[])296993e3fafSRobert Mustacchi main(int argc, char *argv[])
297993e3fafSRobert Mustacchi {
298993e3fafSRobert Mustacchi 	int c;
299993e3fafSRobert Mustacchi 	char devpath[PATH_MAX];
300993e3fafSRobert Mustacchi 
301993e3fafSRobert Mustacchi 	while ((c = getopt(argc, argv, ":d:vlcp:s:")) != -1) {
302993e3fafSRobert Mustacchi 		switch (c) {
303993e3fafSRobert Mustacchi 		case 'c':
304993e3fafSRobert Mustacchi 			xp_clear = B_TRUE;
305993e3fafSRobert Mustacchi 			break;
306993e3fafSRobert Mustacchi 		case 'd':
307993e3fafSRobert Mustacchi 			xp_path = optarg;
308993e3fafSRobert Mustacchi 			break;
309993e3fafSRobert Mustacchi 		case 'l':
310993e3fafSRobert Mustacchi 			xp_list = B_TRUE;
311993e3fafSRobert Mustacchi 			break;
312993e3fafSRobert Mustacchi 		case 'v':
313993e3fafSRobert Mustacchi 			xp_verbose = B_TRUE;
314993e3fafSRobert Mustacchi 			break;
315993e3fafSRobert Mustacchi 		case 'p':
316993e3fafSRobert Mustacchi 			xp_port = atoi(optarg);
317993e3fafSRobert Mustacchi 			if (xp_port < 1 || xp_port > XHCI_PORTSC_NPORTS)
318993e3fafSRobert Mustacchi 				return (xp_usage("invalid port for -p: %d\n",
319993e3fafSRobert Mustacchi 				    optarg));
320993e3fafSRobert Mustacchi 			break;
321993e3fafSRobert Mustacchi 		case 's':
322993e3fafSRobert Mustacchi 			xp_state = optarg;
323993e3fafSRobert Mustacchi 			break;
324993e3fafSRobert Mustacchi 		case ':':
325993e3fafSRobert Mustacchi 			return (xp_usage("-%c requires an operand\n", optopt));
326993e3fafSRobert Mustacchi 		case '?':
327993e3fafSRobert Mustacchi 			return (xp_usage("unknown option: -%c\n", optopt));
328993e3fafSRobert Mustacchi 		default:
329993e3fafSRobert Mustacchi 			abort();
330993e3fafSRobert Mustacchi 		}
331993e3fafSRobert Mustacchi 	}
332993e3fafSRobert Mustacchi 
333993e3fafSRobert Mustacchi 	if (xp_list == B_TRUE && (xp_path != NULL || xp_clear == B_TRUE ||
334993e3fafSRobert Mustacchi 	    xp_port > 0 || xp_state != NULL)) {
335993e3fafSRobert Mustacchi 		return (xp_usage("-l cannot be used with other options\n"));
336993e3fafSRobert Mustacchi 	}
337993e3fafSRobert Mustacchi 
338993e3fafSRobert Mustacchi 	if (xp_list == B_TRUE) {
339993e3fafSRobert Mustacchi 		xp_find_devs(B_TRUE);
340993e3fafSRobert Mustacchi 		return (0);
341993e3fafSRobert Mustacchi 	}
342993e3fafSRobert Mustacchi 
343993e3fafSRobert Mustacchi 	if (xp_path == NULL) {
344993e3fafSRobert Mustacchi 		xp_find_devs(B_FALSE);
345993e3fafSRobert Mustacchi 		if (xp_npaths == 0) {
346993e3fafSRobert Mustacchi 			errx(EXIT_FAILURE, "no xhci devices found");
347993e3fafSRobert Mustacchi 		} else if (xp_npaths > 1) {
348993e3fafSRobert Mustacchi 			errx(EXIT_FAILURE, "more than one xhci device found, "
349993e3fafSRobert Mustacchi 			    "please specify device with -d, use -l to list");
350993e3fafSRobert Mustacchi 		}
351993e3fafSRobert Mustacchi 		if (snprintf(devpath, sizeof (devpath), "/devices/%s",
352993e3fafSRobert Mustacchi 		    xp_devpath) >= sizeof (devpath))
353993e3fafSRobert Mustacchi 			errx(EXIT_FAILURE, "xhci path found at %s overflows "
354*6b1325cfSRobert Mustacchi 			    "internal device path", xp_devpath);
355993e3fafSRobert Mustacchi 		di_devfs_path_free(xp_devpath);
356993e3fafSRobert Mustacchi 		xp_devpath = NULL;
357993e3fafSRobert Mustacchi 		xp_path = devpath;
358993e3fafSRobert Mustacchi 	}
359993e3fafSRobert Mustacchi 
360993e3fafSRobert Mustacchi 	if (xp_clear == B_TRUE && xp_state != NULL) {
361993e3fafSRobert Mustacchi 		return (xp_usage("-c and -s can't be used together\n"));
362993e3fafSRobert Mustacchi 	}
363993e3fafSRobert Mustacchi 
364993e3fafSRobert Mustacchi 	if (xp_state != NULL) {
365993e3fafSRobert Mustacchi 		xp_set_pls(xp_path, xp_port, xp_state);
366993e3fafSRobert Mustacchi 	} else if (xp_clear == B_TRUE) {
367993e3fafSRobert Mustacchi 		xp_clear_change(xp_path, xp_port);
368993e3fafSRobert Mustacchi 	} else {
369993e3fafSRobert Mustacchi 		xp_dump(xp_path);
370993e3fafSRobert Mustacchi 	}
371993e3fafSRobert Mustacchi 
372993e3fafSRobert Mustacchi 	return (0);
373993e3fafSRobert Mustacchi }
374