jenkins-core-weekly: update to 2.491
[oi-userland.git] / components / library / libusb-1 / patches / 01-illumos.patch
blob8c71e978a69e6cfd3f5460c7942bea1ce3121e0a
1 From 57b0bd0b3624eea8f7a56cb477649f2f35b0bab7 Mon Sep 17 00:00:00 2001
2 From: "Joshua M. Clulow" <josh@sysmgr.org>
3 Date: Mon, 27 Dec 2021 16:08:38 -0800
4 Subject: [PATCH] illumos: split off from Solaris backend
6 ---
7 README | 2 +-
8 configure.ac | 19 +-
9 libusb/Makefile.am | 5 +
10 libusb/os/illumos_usb.c | 1653 +++++++++++++++++++++++++++++++++++++++
11 libusb/os/illumos_usb.h | 80 ++
12 5 files changed, 1752 insertions(+), 7 deletions(-)
13 create mode 100644 libusb/os/illumos_usb.c
14 create mode 100644 libusb/os/illumos_usb.h
16 diff --git a/README b/README
17 index a47b4bd6e..adc408c17 100644
18 --- a/README
19 +++ b/README
20 @@ -5,7 +5,7 @@
21 # libusb
23 libusb is a library for USB device access from Linux, macOS,
24 -Windows, OpenBSD/NetBSD, Haiku, Solaris userspace, and WebAssembly
25 +Windows, OpenBSD/NetBSD, Haiku, Solaris, illumos userspace, and WebAssembly
26 via WebUSB.
27 It is written in C (Haiku backend in C++) and licensed under the GNU
28 Lesser General Public License version 2.1 or, at your option, any later
29 diff --git a/configure.ac b/configure.ac
30 index f6cf2f9f7..fe51f2e8f 100644
31 --- a/configure.ac
32 +++ b/configure.ac
33 @@ -108,9 +108,15 @@ case $host in
34 platform=posix
36 *-solaris*)
37 - AC_MSG_RESULT([SunOS])
38 - backend=sunos
39 - platform=posix
40 + if test "x`uname -o`" = xillumos; then
41 + AC_MSG_RESULT([illumos])
42 + backend=illumos
43 + platform=posix
44 + else
45 + AC_MSG_RESULT([SunOS])
46 + backend=sunos
47 + platform=posix
48 + fi
50 *-cygwin*)
51 AC_MSG_RESULT([Windows (using Cygwin)])
52 @@ -183,7 +189,7 @@ linux)
53 AC_CHECK_HEADER([sys/socket.h], [], [AC_MSG_ERROR([Linux socket header not found])])
56 -sunos)
57 +sunos|illumos)
58 LIBS="${LIBS} -ldevinfo"
60 windows)
61 @@ -235,7 +241,7 @@ if test "x$platform" = xposix; then
64 dnl eventfd support
65 -if test "x$backend" = xlinux || test "x$backend" = xsunos; then
66 +if test "x$backend" = xlinux || test "x$backend" = xsunos || test "x$backend" = xillumos; then
67 AC_ARG_ENABLE([eventfd],
68 [AS_HELP_STRING([--enable-eventfd], [use eventfd for signalling [default=auto]])],
69 [use_eventfd=$enableval],
70 @@ -273,7 +279,7 @@ if test "x$backend" = xlinux || test "x$backend" = xsunos; then
73 dnl timerfd support
74 -if test "x$backend" = xlinux || test "x$backend" = xsunos; then
75 +if test "x$backend" = xlinux || test "x$backend" = xsunos || test "x$backend" = xillumos; then
76 AC_ARG_ENABLE([timerfd],
77 [AS_HELP_STRING([--enable-timerfd], [use timerfd for timing [default=auto]])],
78 [use_timerfd=$enableval],
79 @@ -364,6 +370,7 @@ AM_CONDITIONAL([OS_NETBSD], [test "x$backend" = xnetbsd])
80 AM_CONDITIONAL([OS_NULL], [test "x$backend" = xnull])
81 AM_CONDITIONAL([OS_OPENBSD], [test "x$backend" = xopenbsd])
82 AM_CONDITIONAL([OS_SUNOS], [test "x$backend" = xsunos])
83 +AM_CONDITIONAL([OS_ILLUMOS], [test "x$backend" = xillumos])
84 AM_CONDITIONAL([OS_WINDOWS], [test "x$backend" = xwindows])
85 AM_CONDITIONAL([PLATFORM_POSIX], [test "x$platform" = xposix])
86 AM_CONDITIONAL([PLATFORM_WINDOWS], [test "x$platform" = xwindows])
87 diff --git a/libusb/Makefile.am b/libusb/Makefile.am
88 index baf7b38f6..c6ac86452 100644
89 --- a/libusb/Makefile.am
90 +++ b/libusb/Makefile.am
91 @@ -24,6 +24,7 @@ OS_NETBSD_SRC = os/netbsd_usb.c
92 OS_NULL_SRC = os/null_usb.c
93 OS_OPENBSD_SRC = os/openbsd_usb.c
94 OS_SUNOS_SRC = os/sunos_usb.h os/sunos_usb.c
95 +OS_ILLUMOS_SRC = os/illumos_usb.h os/illumos_usb.c
96 OS_WINDOWS_SRC = libusb-1.0.def libusb-1.0.rc \
97 os/windows_common.h os/windows_common.c \
98 os/windows_usbdk.h os/windows_usbdk.c \
99 @@ -64,6 +65,10 @@ if OS_SUNOS
100 OS_SRC = $(OS_SUNOS_SRC)
101 endif
103 +if OS_ILLUMOS
104 +OS_SRC = $(OS_ILLUMOS_SRC)
105 +endif
107 if OS_WINDOWS
108 OS_SRC = $(OS_WINDOWS_SRC)
110 diff --git a/libusb/os/illumos_usb.c b/libusb/os/illumos_usb.c
111 new file mode 100644
112 index 000000000..db8dcf756
113 --- /dev/null
114 +++ b/libusb/os/illumos_usb.c
115 @@ -0,0 +1,1653 @@
118 + * Copyright (c) 2016, Oracle and/or its affiliates.
119 + * Copyright 2021 Oxide Computer Company
121 + * This library is free software; you can redistribute it and/or
122 + * modify it under the terms of the GNU Lesser General Public
123 + * License as published by the Free Software Foundation; either
124 + * version 2.1 of the License, or (at your option) any later version.
126 + * This library is distributed in the hope that it will be useful,
127 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
128 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
129 + * Lesser General Public License for more details.
131 + * You should have received a copy of the GNU Lesser General Public
132 + * License along with this library; if not, write to the Free Software
133 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
134 + */
136 +#include <config.h>
138 +#include <sys/time.h>
139 +#include <sys/types.h>
140 +#include <sys/stat.h>
141 +#include <strings.h>
142 +#include <errno.h>
143 +#include <fcntl.h>
144 +#include <stdio.h>
145 +#include <stdlib.h>
146 +#include <string.h>
147 +#include <wait.h>
148 +#include <unistd.h>
149 +#include <aio.h>
150 +#include <libdevinfo.h>
151 +#include <sys/nvpair.h>
152 +#include <sys/devctl.h>
153 +#include <sys/usb/clients/ugen/usb_ugen.h>
154 +#include <sys/usb/usba.h>
155 +#include <sys/pci.h>
157 +#include "libusbi.h"
158 +#include "illumos_usb.h"
160 +#define UPDATEDRV_PATH "/usr/sbin/update_drv"
161 +#define UPDATEDRV "update_drv"
163 +#define DEFAULT_LISTSIZE 6
165 +typedef struct {
166 + int nargs;
167 + int listsize;
168 + char **string;
169 +} string_list_t;
172 + * Backend functions
173 + */
174 +static int illumos_get_device_list(struct libusb_context *,
175 + struct discovered_devs **);
176 +static int illumos_open(struct libusb_device_handle *);
177 +static void illumos_close(struct libusb_device_handle *);
178 +static int illumos_get_active_config_descriptor(struct libusb_device *,
179 + void *, size_t);
180 +static int illumos_get_config_descriptor(struct libusb_device *, uint8_t,
181 + void *, size_t);
182 +static int illumos_get_configuration(struct libusb_device_handle *, uint8_t *);
183 +static int illumos_set_configuration(struct libusb_device_handle *, int);
184 +static int illumos_claim_interface(struct libusb_device_handle *, uint8_t);
185 +static int illumos_release_interface(struct libusb_device_handle *, uint8_t);
186 +static int illumos_set_interface_altsetting(struct libusb_device_handle *,
187 + uint8_t, uint8_t);
188 +static int illumos_clear_halt(struct libusb_device_handle *, unsigned char);
189 +static void illumos_destroy_device(struct libusb_device *);
190 +static int illumos_submit_transfer(struct usbi_transfer *);
191 +static int illumos_cancel_transfer(struct usbi_transfer *);
192 +static int illumos_handle_transfer_completion(struct usbi_transfer *);
193 +static int illumos_kernel_driver_active(struct libusb_device_handle *, uint8_t);
194 +static int illumos_detach_kernel_driver(struct libusb_device_handle *, uint8_t);
195 +static int illumos_attach_kernel_driver(struct libusb_device_handle *, uint8_t);
196 +static int illumos_usb_open_ep0(illumos_dev_handle_priv_t *hpriv,
197 + illumos_dev_priv_t *dpriv);
198 +static int illumos_usb_ioctl(struct libusb_device *dev, int cmd);
200 +static int
201 +illumos_get_link(di_devlink_t devlink, void *arg)
203 + walk_link_t *larg = (walk_link_t *)arg;
204 + const char *p;
205 + const char *q;
207 + if (larg->path) {
208 + char *content = (char *)di_devlink_content(devlink);
209 + char *start = strstr(content, "/devices/");
210 + start += strlen("/devices");
211 + usbi_dbg(NULL, "%s", start);
213 + /* line content must have minor node */
214 + if (start == NULL ||
215 + strncmp(start, larg->path, larg->len) != 0 ||
216 + start[larg->len] != ':') {
217 + return (DI_WALK_CONTINUE);
221 + p = di_devlink_path(devlink);
222 + q = strrchr(p, '/');
223 + usbi_dbg(NULL, "%s", q);
225 + *(larg->linkpp) = strndup(p, strlen(p) - strlen(q));
227 + return (DI_WALK_TERMINATE);
231 +static int
232 +illumos_physpath_to_devlink(
233 + const char *node_path, const char *match, char **link_path)
235 + walk_link_t larg;
236 + di_devlink_handle_t hdl;
238 + *link_path = NULL;
239 + larg.linkpp = link_path;
240 + if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
241 + usbi_dbg(NULL, "di_devlink_init failure");
242 + return (-1);
245 + larg.len = strlen(node_path);
246 + larg.path = (char *)node_path;
248 + (void) di_devlink_walk(hdl, match, NULL, DI_PRIMARY_LINK,
249 + (void *)&larg, illumos_get_link);
251 + (void) di_devlink_fini(&hdl);
253 + if (*link_path == NULL) {
254 + usbi_dbg(NULL, "there is no devlink for this path");
255 + return (-1);
258 + return (0);
261 +static int
262 +illumos_usb_ioctl(struct libusb_device *dev, int cmd)
264 + int fd;
265 + nvlist_t *nvlist;
266 + char *end;
267 + char *phypath;
268 + char *hubpath;
269 + char path_arg[PATH_MAX];
270 + illumos_dev_priv_t *dpriv;
271 + devctl_ap_state_t devctl_ap_state;
272 + struct devctl_iocdata iocdata;
274 + dpriv = usbi_get_device_priv(dev);
275 + phypath = dpriv->phypath;
277 + end = strrchr(phypath, '/');
278 + if (end == NULL)
279 + return (-1);
280 + hubpath = strndup(phypath, end - phypath);
281 + if (hubpath == NULL)
282 + return (-1);
284 + end = strrchr(hubpath, '@');
285 + if (end == NULL) {
286 + free(hubpath);
287 + return (-1);
289 + end++;
290 + usbi_dbg(DEVICE_CTX(dev), "unitaddr: %s", end);
292 + nvlist_alloc(&nvlist, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
293 + nvlist_add_int32(nvlist, "port", dev->port_number);
294 + //find the hub path
295 + snprintf(path_arg, sizeof(path_arg), "/devices%s:hubd", hubpath);
296 + usbi_dbg(DEVICE_CTX(dev), "ioctl hub path: %s", path_arg);
298 + fd = open(path_arg, O_RDONLY);
299 + if (fd < 0) {
300 + usbi_err(DEVICE_CTX(dev), "open failed: errno %d (%s)",
301 + errno, strerror(errno));
302 + nvlist_free(nvlist);
303 + free(hubpath);
304 + return (-1);
307 + memset(&iocdata, 0, sizeof(iocdata));
308 + memset(&devctl_ap_state, 0, sizeof(devctl_ap_state));
310 + nvlist_pack(nvlist, (char **)&iocdata.nvl_user, &iocdata.nvl_usersz,
311 + NV_ENCODE_NATIVE, 0);
313 + iocdata.cmd = DEVCTL_AP_GETSTATE;
314 + iocdata.flags = 0;
315 + iocdata.c_nodename = (char *)"hub";
316 + iocdata.c_unitaddr = end;
317 + iocdata.cpyout_buf = &devctl_ap_state;
318 + usbi_dbg(DEVICE_CTX(dev), "%p, %" PRIuPTR, iocdata.nvl_user,
319 + iocdata.nvl_usersz);
321 + errno = 0;
322 + if (ioctl(fd, DEVCTL_AP_GETSTATE, &iocdata) == -1) {
323 + usbi_err(DEVICE_CTX(dev),
324 + "ioctl failed: fd %d, cmd %x, errno %d (%s)",
325 + fd, DEVCTL_AP_GETSTATE, errno, strerror(errno));
326 + } else {
327 + usbi_dbg(DEVICE_CTX(dev), "dev rstate: %d",
328 + devctl_ap_state.ap_rstate);
329 + usbi_dbg(DEVICE_CTX(dev), "dev ostate: %d",
330 + devctl_ap_state.ap_ostate);
333 + errno = 0;
334 + iocdata.cmd = cmd;
335 + if (ioctl(fd, (int)cmd, &iocdata) != 0) {
336 + usbi_err(DEVICE_CTX(dev),
337 + "ioctl failed: fd %d, cmd %x, errno %d (%s)",
338 + fd, cmd, errno, strerror(errno));
339 + sleep(2);
342 + close(fd);
343 + free(iocdata.nvl_user);
344 + nvlist_free(nvlist);
345 + free(hubpath);
347 + return (-errno);
350 +static int
351 +illumos_kernel_driver_active(struct libusb_device_handle *dev_handle,
352 + uint8_t interface)
354 + illumos_dev_priv_t *dpriv = usbi_get_device_priv(dev_handle->dev);
356 + UNUSED(interface);
358 + usbi_dbg(HANDLE_CTX(dev_handle), "%s", dpriv->ugenpath);
360 + return (dpriv->ugenpath == NULL);
364 + * Private functions
365 + */
366 +static int _errno_to_libusb(int);
367 +static int illumos_usb_get_status(struct libusb_context *ctx, int fd);
369 +static string_list_t *
370 +illumos_new_string_list(void)
372 + string_list_t *list;
374 + list = calloc(1, sizeof(string_list_t));
375 + if (list == NULL)
376 + return (NULL);
377 + list->string = calloc(DEFAULT_LISTSIZE, sizeof(char *));
378 + if (list->string == NULL) {
379 + free(list);
380 + return (NULL);
382 + list->nargs = 0;
383 + list->listsize = DEFAULT_LISTSIZE;
385 + return (list);
388 +static int
389 +illumos_append_to_string_list(string_list_t *list, const char *arg)
391 + char *str = strdup(arg);
393 + if (str == NULL)
394 + return (-1);
396 + if ((list->nargs + 1) == list->listsize) { /* +1 is for NULL */
397 + char **tmp = realloc(list->string,
398 + sizeof(char *) * (list->listsize + 1));
399 + if (tmp == NULL) {
400 + free(str);
401 + return (-1);
403 + list->string = tmp;
404 + list->string[list->listsize++] = NULL;
406 + list->string[list->nargs++] = str;
408 + return (0);
411 +static void
412 +illumos_free_string_list(string_list_t *list)
414 + int i;
416 + for (i = 0; i < list->nargs; i++) {
417 + free(list->string[i]);
420 + free(list->string);
421 + free(list);
424 +static char **
425 +illumos_build_argv_list(string_list_t *list)
427 + return (list->string);
431 +static int
432 +illumos_exec_command(struct libusb_context *ctx, const char *path,
433 + string_list_t *list)
435 + pid_t pid;
436 + int status;
437 + int waitstat;
438 + int exit_status;
439 + char **argv_list;
441 + argv_list = illumos_build_argv_list(list);
442 + if (argv_list == NULL)
443 + return (-1);
445 + pid = fork();
446 + if (pid == 0) {
447 + /* child */
448 + execv(path, argv_list);
449 + _exit(127);
450 + } else if (pid > 0) {
451 + /* parent */
452 + do {
453 + waitstat = waitpid(pid, &status, 0);
454 + } while ((waitstat == -1 && errno == EINTR) ||
455 + (waitstat == 0 && !WIFEXITED(status) &&
456 + !WIFSIGNALED(status)));
458 + if (waitstat == 0) {
459 + if (WIFEXITED(status))
460 + exit_status = WEXITSTATUS(status);
461 + else
462 + exit_status = WTERMSIG(status);
463 + } else {
464 + usbi_err(ctx, "waitpid failed: errno %d (%s)", errno,
465 + strerror(errno));
466 + exit_status = -1;
468 + } else {
469 + /* fork failed */
470 + usbi_err(ctx, "fork failed: errno %d (%s)", errno,
471 + strerror(errno));
472 + exit_status = -1;
475 + return (exit_status);
478 +static int
479 +illumos_detach_kernel_driver(struct libusb_device_handle *dev_handle,
480 + uint8_t interface_number)
482 + struct libusb_context *ctx = HANDLE_CTX(dev_handle);
483 + string_list_t *list;
484 + char path_arg[PATH_MAX];
485 + illumos_dev_priv_t *dpriv;
486 + int r;
488 + UNUSED(interface_number);
490 + dpriv = usbi_get_device_priv(dev_handle->dev);
491 + snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
492 + usbi_dbg(HANDLE_CTX(dev_handle), "%s", path_arg);
494 + list = illumos_new_string_list();
495 + if (list == NULL)
496 + return (LIBUSB_ERROR_NO_MEM);
498 + /* attach ugen driver */
499 + r = 0;
500 + r |= illumos_append_to_string_list(list, UPDATEDRV);
501 + r |= illumos_append_to_string_list(list, "-a"); /* add rule */
502 + r |= illumos_append_to_string_list(list, "-i"); /* specific device */
503 + r |= illumos_append_to_string_list(list, path_arg); /* physical path */
504 + r |= illumos_append_to_string_list(list, "ugen");
505 + if (r) {
506 + illumos_free_string_list(list);
507 + return (LIBUSB_ERROR_NO_MEM);
510 + r = illumos_exec_command(ctx, UPDATEDRV_PATH, list);
511 + illumos_free_string_list(list);
512 + if (r < 0)
513 + return (LIBUSB_ERROR_OTHER);
515 + /* reconfigure the driver node */
516 + r = 0;
517 + r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
518 + r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
519 + if (r)
520 + usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
522 + snprintf(path_arg, sizeof(path_arg), "^usb/%x.%x",
523 + dev_handle->dev->device_descriptor.idVendor,
524 + dev_handle->dev->device_descriptor.idProduct);
525 + illumos_physpath_to_devlink(dpriv->phypath, path_arg, &dpriv->ugenpath);
527 + if (access(dpriv->ugenpath, F_OK) == -1) {
528 + usbi_err(HANDLE_CTX(dev_handle),
529 + "fail to detach kernel driver");
530 + return (LIBUSB_ERROR_IO);
533 + return (illumos_usb_open_ep0(usbi_get_device_handle_priv(dev_handle),
534 + dpriv));
537 +static int
538 +illumos_attach_kernel_driver(struct libusb_device_handle *dev_handle,
539 + uint8_t interface_number)
541 + struct libusb_context *ctx = HANDLE_CTX(dev_handle);
542 + string_list_t *list;
543 + char path_arg[PATH_MAX];
544 + illumos_dev_priv_t *dpriv;
545 + int r;
547 + UNUSED(interface_number);
549 + /* we open the dev in detach driver, so we need close it first. */
550 + illumos_close(dev_handle);
552 + dpriv = usbi_get_device_priv(dev_handle->dev);
553 + snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
554 + usbi_dbg(HANDLE_CTX(dev_handle), "%s", path_arg);
556 + list = illumos_new_string_list();
557 + if (list == NULL)
558 + return (LIBUSB_ERROR_NO_MEM);
560 + /* detach ugen driver */
561 + r = 0;
562 + r |= illumos_append_to_string_list(list, UPDATEDRV);
563 + r |= illumos_append_to_string_list(list, "-d"); /* add rule */
564 + r |= illumos_append_to_string_list(list, "-i"); /* specific device */
565 + r |= illumos_append_to_string_list(list, path_arg); /* physical path */
566 + r |= illumos_append_to_string_list(list, "ugen");
567 + if (r) {
568 + illumos_free_string_list(list);
569 + return (LIBUSB_ERROR_NO_MEM);
572 + r = illumos_exec_command(ctx, UPDATEDRV_PATH, list);
573 + illumos_free_string_list(list);
574 + if (r < 0)
575 + return (LIBUSB_ERROR_OTHER);
577 + /* reconfigure the driver node */
578 + r = 0;
579 + r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
580 + r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
581 + r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
582 + if (r)
583 + usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
585 + return (0);
588 +static int
589 +illumos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
591 + int proplen;
592 + int *i, n, *addr, *port_prop;
593 + char *phypath;
594 + uint8_t *rdata;
595 + illumos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
596 + char match_str[PATH_MAX];
598 + /* Device descriptors */
599 + proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
600 + "usb-dev-descriptor", &rdata);
601 + if (proplen <= 0) {
602 + return (LIBUSB_ERROR_IO);
604 + bcopy(rdata, &dev->device_descriptor, LIBUSB_DT_DEVICE_SIZE);
606 + /* Raw configuration descriptors */
607 + proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
608 + "usb-raw-cfg-descriptors", &rdata);
609 + if (proplen <= 0) {
610 + usbi_dbg(DEVICE_CTX(dev), "can't find raw config descriptors");
612 + return (LIBUSB_ERROR_IO);
614 + dpriv->raw_cfgdescr = calloc(1, proplen);
615 + if (dpriv->raw_cfgdescr == NULL) {
616 + return (LIBUSB_ERROR_NO_MEM);
617 + } else {
618 + bcopy(rdata, dpriv->raw_cfgdescr, proplen);
619 + dpriv->cfgvalue = ((struct libusb_config_descriptor *)
620 + rdata)->bConfigurationValue;
623 + n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &port_prop);
625 + if ((n != 1) || (*port_prop <= 0)) {
626 + return (LIBUSB_ERROR_IO);
628 + dev->port_number = *port_prop;
630 + /* device physical path */
631 + phypath = di_devfs_path(node);
632 + if (phypath) {
633 + dpriv->phypath = strdup(phypath);
634 + snprintf(match_str, sizeof(match_str), "^usb/%x.%x",
635 + dev->device_descriptor.idVendor,
636 + dev->device_descriptor.idProduct);
637 + usbi_dbg(DEVICE_CTX(dev), "match is %s", match_str);
638 + illumos_physpath_to_devlink(dpriv->phypath, match_str,
639 + &dpriv->ugenpath);
640 + di_devfs_path_free(phypath);
642 + } else {
643 + free(dpriv->raw_cfgdescr);
645 + return (LIBUSB_ERROR_IO);
648 + /* address */
649 + n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "assigned-address", &addr);
650 + if (n != 1 || *addr == 0) {
651 + usbi_dbg(DEVICE_CTX(dev), "can't get address");
652 + } else {
653 + dev->device_address = *addr;
656 + /* speed */
657 + if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) {
658 + dev->speed = LIBUSB_SPEED_LOW;
659 + } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "high-speed",
660 + &i) >= 0) {
661 + dev->speed = LIBUSB_SPEED_HIGH;
662 + } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "full-speed",
663 + &i) >= 0) {
664 + dev->speed = LIBUSB_SPEED_FULL;
665 + } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "super-speed",
666 + &i) >= 0) {
667 + dev->speed = LIBUSB_SPEED_SUPER;
670 + usbi_dbg(DEVICE_CTX(dev),
671 + "vid=%x pid=%x, path=%s, bus_nmber=0x%x, port_number=%d, speed=%d",
672 + dev->device_descriptor.idVendor, dev->device_descriptor.idProduct,
673 + dpriv->phypath, dev->bus_number, dev->port_number, dev->speed);
675 + return (LIBUSB_SUCCESS);
678 +static int
679 +illumos_add_devices(di_devlink_t link, void *arg)
681 + struct devlink_cbarg *largs = (struct devlink_cbarg *)arg;
682 + struct node_args *nargs;
683 + di_node_t myself, dn;
684 + uint64_t session_id = 0;
685 + uint64_t sid = 0;
686 + uint64_t bdf = 0;
687 + struct libusb_device *dev;
688 + illumos_dev_priv_t *devpriv;
689 + int n, *j;
690 + int i = 0;
691 + int *addr_prop;
692 + uint8_t bus_number = 0;
693 + uint32_t * regbuf = NULL;
694 + uint32_t reg;
696 + UNUSED(link);
698 + nargs = (struct node_args *)largs->nargs;
699 + myself = largs->myself;
701 + /*
702 + * Construct session ID.
703 + * session ID = dev_addr | hub addr |parent hub addr|...|root hub bdf
704 + * 8 bits 8bits 8 bits 16bits
705 + */
706 + if (myself == DI_NODE_NIL)
707 + return (DI_WALK_CONTINUE);
709 + dn = myself;
710 + /* find the root hub */
711 + while (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "root-hub", &j) != 0) {
712 + usbi_dbg(NULL, "find_root_hub:%s", di_devfs_path(dn));
713 + n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
714 + "assigned-address", &addr_prop);
715 + session_id |= ((addr_prop[0] & 0xff) << i++ * 8);
716 + dn = di_parent_node(dn);
719 + /* dn is the root hub node */
720 + n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", (int **)&regbuf);
721 + reg = regbuf[0];
722 + bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) |
723 + PCI_REG_FUNC_G(reg);
724 + /* bdf must larger than i*8 bits */
725 + session_id |= (bdf << i * 8);
726 + bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
728 + usbi_dbg(NULL, "device bus address=%s:%x, name:%s",
729 + di_bus_addr(myself), bus_number, di_node_name(dn));
730 + usbi_dbg(NULL, "session id org:%" PRIx64, session_id);
732 + /* dn is the usb device */
733 + for (dn = di_child_node(myself); dn != DI_NODE_NIL;
734 + dn = di_sibling_node(dn)) {
735 + usbi_dbg(NULL, "device path:%s", di_devfs_path(dn));
736 + /* skip hub devices, because its driver can not been unload */
737 + if (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "usb-port-count",
738 + &addr_prop) != -1) {
739 + continue;
741 + /* usb_addr */
742 + n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
743 + "assigned-address", &addr_prop);
744 + if (n != 1 || addr_prop[0] == 0) {
745 + usbi_dbg(NULL, "cannot get valid usb_addr");
746 + continue;
749 + sid = (session_id << 8) | (addr_prop[0] & 0xff) ;
750 + usbi_dbg(NULL, "session id %" PRIX64, sid);
752 + dev = usbi_get_device_by_session_id(nargs->ctx, sid);
753 + if (dev == NULL) {
754 + dev = usbi_alloc_device(nargs->ctx, sid);
755 + if (dev == NULL) {
756 + usbi_dbg(NULL, "can't alloc device");
757 + continue;
759 + devpriv = usbi_get_device_priv(dev);
760 + dev->bus_number = bus_number;
762 + if (illumos_fill_in_dev_info(dn, dev) !=
763 + LIBUSB_SUCCESS) {
764 + libusb_unref_device(dev);
765 + usbi_dbg(NULL, "get information fail");
766 + continue;
768 + if (usbi_sanitize_device(dev) < 0) {
769 + libusb_unref_device(dev);
770 + usbi_dbg(NULL, "sanatize failed: ");
771 + return (DI_WALK_TERMINATE);
773 + } else {
774 + devpriv = usbi_get_device_priv(dev);
775 + usbi_dbg(NULL, "Dev %s exists", devpriv->ugenpath);
778 + if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
779 + usbi_dbg(NULL, "cannot append device");
782 + /*
783 + * we alloc and hence ref this dev. We don't need to ref it
784 + * hereafter. Front end or app should take care of their ref.
785 + */
786 + libusb_unref_device(dev);
788 + usbi_dbg(NULL, "Device %s %s id=0x%" PRIx64
789 + ", devcount:%" PRIuPTR ", bdf=%" PRIx64,
790 + devpriv->ugenpath, di_devfs_path(dn), (uint64_t)sid,
791 + (*nargs->discdevs)->len, bdf);
794 + return (DI_WALK_CONTINUE);
797 +static int
798 +illumos_walk_minor_node_link(di_node_t node, void *args)
800 + di_minor_t minor = DI_MINOR_NIL;
801 + char *minor_path;
802 + struct devlink_cbarg arg;
803 + struct node_args *nargs = (struct node_args *)args;
804 + di_devlink_handle_t devlink_hdl = nargs->dlink_hdl;
806 + /* walk each minor to find usb devices */
807 + while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
808 + minor_path = di_devfs_minor_path(minor);
809 + arg.nargs = args;
810 + arg.myself = node;
811 + arg.minor = minor;
812 + (void) di_devlink_walk(devlink_hdl,
813 + "^usb/hub[0-9]+", minor_path,
814 + DI_PRIMARY_LINK, (void *)&arg, illumos_add_devices);
815 + di_devfs_path_free(minor_path);
818 + /* switch to a different node */
819 + nargs->last_ugenpath = NULL;
821 + return (DI_WALK_CONTINUE);
824 +int
825 +illumos_get_device_list(struct libusb_context * ctx,
826 + struct discovered_devs **discdevs)
828 + di_node_t root_node;
829 + struct node_args args;
830 + di_devlink_handle_t devlink_hdl;
832 + args.ctx = ctx;
833 + args.discdevs = discdevs;
834 + args.last_ugenpath = NULL;
835 + if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
836 + usbi_dbg(ctx, "di_int() failed: errno %d (%s)", errno,
837 + strerror(errno));
838 + return (LIBUSB_ERROR_IO);
841 + if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
842 + di_fini(root_node);
843 + usbi_dbg(ctx, "di_devlink_init() failed: errno %d (%s)", errno,
844 + strerror(errno));
845 + return (LIBUSB_ERROR_IO);
847 + args.dlink_hdl = devlink_hdl;
849 + /* walk each node to find USB devices */
850 + if (di_walk_node(root_node, DI_WALK_SIBFIRST, &args,
851 + illumos_walk_minor_node_link) == -1) {
852 + usbi_dbg(ctx, "di_walk_node() failed: errno %d (%s)", errno,
853 + strerror(errno));
854 + di_fini(root_node);
855 + return (LIBUSB_ERROR_IO);
858 + di_fini(root_node);
859 + di_devlink_fini(&devlink_hdl);
861 + usbi_dbg(ctx, "%zu devices", (*discdevs)->len);
863 + return ((*discdevs)->len);
866 +static int
867 +illumos_usb_open_ep0(illumos_dev_handle_priv_t *hpriv,
868 + illumos_dev_priv_t *dpriv)
870 + char filename[PATH_MAX + 1];
872 + if (hpriv->eps[0].datafd > 0) {
873 + return (LIBUSB_SUCCESS);
875 + snprintf(filename, PATH_MAX, "%s/cntrl0", dpriv->ugenpath);
877 + usbi_dbg(NULL, "opening %s", filename);
878 + hpriv->eps[0].datafd = open(filename, O_RDWR);
879 + if (hpriv->eps[0].datafd < 0) {
880 + return (_errno_to_libusb(errno));
883 + snprintf(filename, PATH_MAX, "%s/cntrl0stat", dpriv->ugenpath);
884 + hpriv->eps[0].statfd = open(filename, O_RDONLY);
885 + if (hpriv->eps[0].statfd < 0) {
886 + close(hpriv->eps[0].datafd);
887 + hpriv->eps[0].datafd = -1;
888 + return (_errno_to_libusb(errno));
891 + return (LIBUSB_SUCCESS);
894 +static void
895 +illumos_usb_close_all_eps(illumos_dev_handle_priv_t *hdev)
897 + int i;
899 + /* not close ep0 */
900 + for (i = 1; i < USB_MAXENDPOINTS; i++) {
901 + if (hdev->eps[i].datafd != -1) {
902 + (void) close(hdev->eps[i].datafd);
903 + hdev->eps[i].datafd = -1;
905 + if (hdev->eps[i].statfd != -1) {
906 + (void) close(hdev->eps[i].statfd);
907 + hdev->eps[i].statfd = -1;
912 +static void
913 +illumos_usb_close_ep0(illumos_dev_handle_priv_t *hdev)
915 + if (hdev->eps[0].datafd >= 0) {
916 + close(hdev->eps[0].datafd);
917 + close(hdev->eps[0].statfd);
918 + hdev->eps[0].datafd = -1;
919 + hdev->eps[0].statfd = -1;
923 +static uchar_t
924 +illumos_usb_ep_index(uint8_t ep_addr)
926 + return ((ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK) +
927 + ((ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? 16 : 0));
930 +static int
931 +illumos_find_interface(struct libusb_device_handle *hdev,
932 + uint8_t endpoint, uint8_t *interface)
934 + struct libusb_config_descriptor *config;
935 + int r;
936 + int iface_idx;
938 + r = libusb_get_active_config_descriptor(hdev->dev, &config);
939 + if (r < 0) {
940 + return (LIBUSB_ERROR_INVALID_PARAM);
943 + for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) {
944 + const struct libusb_interface *iface =
945 + &config->interface[iface_idx];
946 + int altsetting_idx;
948 + for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting;
949 + altsetting_idx++) {
950 + const struct libusb_interface_descriptor *altsetting =
951 + &iface->altsetting[altsetting_idx];
952 + int ep_idx;
954 + for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints;
955 + ep_idx++) {
956 + const struct libusb_endpoint_descriptor *ep =
957 + &altsetting->endpoint[ep_idx];
958 + if (ep->bEndpointAddress == endpoint) {
959 + *interface = iface_idx;
960 + libusb_free_config_descriptor(config);
962 + return (LIBUSB_SUCCESS);
967 + libusb_free_config_descriptor(config);
969 + return (LIBUSB_ERROR_INVALID_PARAM);
972 +static int
973 +illumos_check_device_and_status_open(struct libusb_device_handle *hdl,
974 + uint8_t ep_addr, int ep_type)
976 + char filename[PATH_MAX + 1], statfilename[PATH_MAX + 1];
977 + char cfg_num[16], alt_num[16];
978 + int fd, fdstat, mode, e;
979 + uint8_t ifc = 0;
980 + uint8_t ep_index;
981 + illumos_dev_handle_priv_t *hpriv;
983 + usbi_dbg(HANDLE_CTX(hdl), "open ep 0x%02x", ep_addr);
984 + hpriv = usbi_get_device_handle_priv(hdl);
985 + ep_index = illumos_usb_ep_index(ep_addr);
986 + /* ep already opened */
987 + if ((hpriv->eps[ep_index].datafd > 0) &&
988 + (hpriv->eps[ep_index].statfd > 0)) {
989 + usbi_dbg(HANDLE_CTX(hdl),
990 + "ep 0x%02x already opened, return success", ep_addr);
992 + return (0);
995 + if (illumos_find_interface(hdl, ep_addr, &ifc) < 0) {
996 + usbi_dbg(HANDLE_CTX(hdl),
997 + "can't find interface for endpoint 0x%02x", ep_addr);
998 + return (EACCES);
1001 + /* create filename */
1002 + if (hpriv->config_index > 0) {
1003 + (void) snprintf(cfg_num, sizeof(cfg_num), "cfg%d",
1004 + hpriv->config_index + 1);
1005 + } else {
1006 + bzero(cfg_num, sizeof(cfg_num));
1009 + if (hpriv->altsetting[ifc] > 0) {
1010 + (void) snprintf(alt_num, sizeof(alt_num), ".%d",
1011 + hpriv->altsetting[ifc]);
1012 + } else {
1013 + bzero(alt_num, sizeof(alt_num));
1016 + if ((e = snprintf(filename, sizeof (filename), "%s/%sif%d%s%s%d",
1017 + hpriv->dpriv->ugenpath, cfg_num, ifc, alt_num,
1018 + (ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? "in" :
1019 + "out", (ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK))) < 0 ||
1020 + e >= (int)sizeof (filename) ||
1021 + (e = snprintf(statfilename, sizeof (statfilename), "%sstat",
1022 + filename)) < 0 || e >= (int)sizeof (statfilename)) {
1023 + usbi_dbg(HANDLE_CTX(hdl),
1024 + "path buffer overflow for endpoint 0x%02x", ep_addr);
1025 + return (EINVAL);
1028 + /*
1029 + * In case configuration has been switched, the xfer endpoint needs
1030 + * to be opened before the status endpoint, due to a ugen issue.
1031 + * However, to enable the one transfer mode for an Interrupt-In pipe,
1032 + * the status endpoint needs to be opened before the xfer endpoint.
1033 + * So, open the xfer mode first and close it immediately
1034 + * as a workaround. This will handle the configuration switch.
1035 + * Then, open the status endpoint. If for an Interrupt-in pipe,
1036 + * write the USB_EP_INTR_ONE_XFER control to the status endpoint
1037 + * to enable the one transfer mode. Then, re-open the xfer mode.
1038 + */
1039 + if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
1040 + mode = O_RDWR;
1041 + } else if (ep_addr & LIBUSB_ENDPOINT_IN) {
1042 + mode = O_RDONLY;
1043 + } else {
1044 + mode = O_WRONLY;
1046 + /* Open the xfer endpoint first */
1047 + if ((fd = open(filename, mode)) == -1) {
1048 + usbi_dbg(HANDLE_CTX(hdl), "can't open %s: errno %d (%s)",
1049 + filename, errno, strerror(errno));
1050 + return (errno);
1052 + /* And immediately close the xfer endpoint */
1053 + (void) close(fd);
1055 + /*
1056 + * Open the status endpoint.
1057 + * If for an Interrupt-IN pipe, need to enable the one transfer mode
1058 + * by writing USB_EP_INTR_ONE_XFER control to the status endpoint
1059 + * before opening the xfer endpoint
1060 + */
1061 + if ((ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) &&
1062 + (ep_addr & LIBUSB_ENDPOINT_IN)) {
1063 + char control = USB_EP_INTR_ONE_XFER;
1064 + ssize_t count;
1066 + /* Open the status endpoint with RDWR */
1067 + if ((fdstat = open(statfilename, O_RDWR)) == -1) {
1068 + usbi_dbg(HANDLE_CTX(hdl),
1069 + "can't open %s RDWR: errno %d (%s)",
1070 + statfilename, errno, strerror(errno));
1071 + return (errno);
1072 + } else {
1073 + count = write(fdstat, &control, sizeof(control));
1074 + if (count != 1) {
1075 + /* this should have worked */
1076 + usbi_dbg(HANDLE_CTX(hdl),
1077 + "can't write to %s: errno %d (%s)",
1078 + statfilename, errno, strerror(errno));
1079 + (void) close(fdstat);
1080 + return (errno);
1083 + } else {
1084 + if ((fdstat = open(statfilename, O_RDONLY)) == -1) {
1085 + usbi_dbg(HANDLE_CTX(hdl),
1086 + "can't open %s: errno %d (%s)", statfilename, errno,
1087 + strerror(errno));
1088 + return (errno);
1092 + /* Re-open the xfer endpoint */
1093 + if ((fd = open(filename, mode)) == -1) {
1094 + usbi_dbg(HANDLE_CTX(hdl), "can't open %s: errno %d (%s)",
1095 + filename, errno, strerror(errno));
1096 + (void) close(fdstat);
1097 + return (errno);
1100 + hpriv->eps[ep_index].datafd = fd;
1101 + hpriv->eps[ep_index].statfd = fdstat;
1102 + usbi_dbg(HANDLE_CTX(hdl), "ep=0x%02x datafd=%d, statfd=%d", ep_addr,
1103 + fd, fdstat);
1104 + return (0);
1107 +int
1108 +illumos_open(struct libusb_device_handle *handle)
1110 + illumos_dev_handle_priv_t *hpriv;
1111 + illumos_dev_priv_t *dpriv;
1112 + int i;
1113 + int ret;
1115 + hpriv = usbi_get_device_handle_priv(handle);
1116 + dpriv = usbi_get_device_priv(handle->dev);
1117 + hpriv->dpriv = dpriv;
1119 + /* set all file descriptors to "closed" */
1120 + for (i = 0; i < USB_MAXENDPOINTS; i++) {
1121 + hpriv->eps[i].datafd = -1;
1122 + hpriv->eps[i].statfd = -1;
1125 + if (illumos_kernel_driver_active(handle, 0)) {
1126 + /* pretend we can open the device */
1127 + return (LIBUSB_SUCCESS);
1130 + if ((ret = illumos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) {
1131 + usbi_dbg(HANDLE_CTX(handle), "fail: %d", ret);
1132 + return (ret);
1135 + return (LIBUSB_SUCCESS);
1138 +void
1139 +illumos_close(struct libusb_device_handle *handle)
1141 + illumos_dev_handle_priv_t *hpriv;
1143 + usbi_dbg(HANDLE_CTX(handle), " ");
1145 + hpriv = usbi_get_device_handle_priv(handle);
1147 + illumos_usb_close_all_eps(hpriv);
1148 + illumos_usb_close_ep0(hpriv);
1151 +int
1152 +illumos_get_active_config_descriptor(struct libusb_device *dev,
1153 + void *buf, size_t len)
1155 + illumos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
1156 + struct libusb_config_descriptor *cfg;
1157 + int proplen;
1158 + di_node_t node;
1159 + uint8_t *rdata;
1161 + /*
1162 + * Keep raw configuration descriptors updated, in case config
1163 + * has ever been changed through setCfg.
1164 + */
1165 + if ((node = di_init(dpriv->phypath, DINFOCPYALL)) == DI_NODE_NIL) {
1166 + usbi_dbg(DEVICE_CTX(dev), "di_int() failed: errno %d (%s)",
1167 + errno, strerror(errno));
1168 + return (LIBUSB_ERROR_IO);
1170 + proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
1171 + "usb-raw-cfg-descriptors", &rdata);
1172 + if (proplen <= 0) {
1173 + usbi_dbg(DEVICE_CTX(dev), "can't find raw config descriptors");
1174 + return (LIBUSB_ERROR_IO);
1176 + dpriv->raw_cfgdescr = realloc(dpriv->raw_cfgdescr, proplen);
1177 + if (dpriv->raw_cfgdescr == NULL) {
1178 + return (LIBUSB_ERROR_NO_MEM);
1179 + } else {
1180 + bcopy(rdata, dpriv->raw_cfgdescr, proplen);
1181 + dpriv->cfgvalue = ((struct libusb_config_descriptor *)
1182 + rdata)->bConfigurationValue;
1184 + di_fini(node);
1186 + cfg = (struct libusb_config_descriptor *)dpriv->raw_cfgdescr;
1187 + len = MIN(len, libusb_le16_to_cpu(cfg->wTotalLength));
1188 + memcpy(buf, dpriv->raw_cfgdescr, len);
1189 + usbi_dbg(DEVICE_CTX(dev), "path:%s len %zu", dpriv->phypath, len);
1191 + return (len);
1194 +int
1195 +illumos_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
1196 + void *buf, size_t len)
1198 + UNUSED(idx);
1199 + /* XXX */
1200 + return (illumos_get_active_config_descriptor(dev, buf, len));
1203 +int
1204 +illumos_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
1206 + illumos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
1208 + *config = dpriv->cfgvalue;
1210 + usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %u", *config);
1212 + return (LIBUSB_SUCCESS);
1215 +int
1216 +illumos_set_configuration(struct libusb_device_handle *handle, int config)
1218 + illumos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
1219 + illumos_dev_handle_priv_t *hpriv;
1221 + usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %d", config);
1222 + hpriv = usbi_get_device_handle_priv(handle);
1224 + if (dpriv->ugenpath == NULL)
1225 + return (LIBUSB_ERROR_NOT_SUPPORTED);
1227 + if (config < 1)
1228 + return (LIBUSB_ERROR_NOT_SUPPORTED);
1230 + dpriv->cfgvalue = config;
1231 + hpriv->config_index = config - 1;
1233 + return (LIBUSB_SUCCESS);
1236 +int
1237 +illumos_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
1239 + UNUSED(handle);
1241 + usbi_dbg(HANDLE_CTX(handle), "iface %u", iface);
1243 + return (LIBUSB_SUCCESS);
1246 +int
1247 +illumos_release_interface(struct libusb_device_handle *handle, uint8_t iface)
1249 + illumos_dev_handle_priv_t *hpriv = usbi_get_device_handle_priv(handle);
1251 + usbi_dbg(HANDLE_CTX(handle), "iface %u", iface);
1253 + /* XXX: can we release it? */
1254 + hpriv->altsetting[iface] = 0;
1256 + return (LIBUSB_SUCCESS);
1259 +int
1260 +illumos_set_interface_altsetting(struct libusb_device_handle *handle,
1261 + uint8_t iface, uint8_t altsetting)
1263 + illumos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
1264 + illumos_dev_handle_priv_t *hpriv = usbi_get_device_handle_priv(handle);
1266 + usbi_dbg(HANDLE_CTX(handle), "iface %u, setting %u", iface, altsetting);
1268 + if (dpriv->ugenpath == NULL)
1269 + return (LIBUSB_ERROR_NOT_FOUND);
1271 + /* XXX: can we switch altsetting? */
1272 + hpriv->altsetting[iface] = altsetting;
1274 + return (LIBUSB_SUCCESS);
1277 +static void
1278 +usb_dump_data(const void *data, size_t size)
1280 + const uint8_t *p = data;
1281 + size_t i;
1283 + if (getenv("LIBUSB_DEBUG") == NULL) {
1284 + return;
1287 + (void) fprintf(stderr, "data dump:");
1288 + for (i = 0; i < size; i++) {
1289 + if (i % 16 == 0) {
1290 + (void) fprintf(stderr, "\n%08zx\t", i);
1292 + (void) fprintf(stderr, "%02x ", p[i]);
1294 + (void) fprintf(stderr, "\n");
1297 +static void
1298 +illumos_async_callback(union sigval arg)
1300 + illumos_xfer_priv_t *tpriv = arg.sival_ptr;
1301 + struct libusb_transfer *xfer = tpriv->transfer;
1302 + struct usbi_transfer *ixfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer);
1303 + struct aiocb *aiocb = &tpriv->aiocb;
1304 + int ret;
1305 + illumos_dev_handle_priv_t *hpriv;
1306 + uint8_t ep;
1307 + libusb_device_handle *dev_handle;
1309 + if ((dev_handle = xfer->dev_handle) == NULL) {
1310 + /* libusb can forcibly interrupt transfer in do_close() */
1311 + return;
1314 + hpriv = usbi_get_device_handle_priv(dev_handle);
1315 + ep = illumos_usb_ep_index(xfer->endpoint);
1317 + ret = aio_error(aiocb);
1318 + if (ret != 0) {
1319 + xfer->status = illumos_usb_get_status(TRANSFER_CTX(xfer),
1320 + hpriv->eps[ep].statfd);
1321 + } else {
1322 + xfer->actual_length = ixfer->transferred = aio_return(aiocb);
1325 + usb_dump_data(xfer->buffer, xfer->actual_length);
1327 + usbi_dbg(TRANSFER_CTX(xfer), "ret=%d, len=%d, actual_len=%d",
1328 + ret, xfer->length, xfer->actual_length);
1330 + /* async notification */
1331 + usbi_signal_transfer_completion(ixfer);
1334 +static int
1335 +illumos_do_async_io(struct libusb_transfer *transfer)
1337 + int ret = -1;
1338 + struct aiocb *aiocb;
1339 + illumos_dev_handle_priv_t *hpriv;
1340 + uint8_t ep;
1341 + illumos_xfer_priv_t *tpriv;
1343 + usbi_dbg(TRANSFER_CTX(transfer), " ");
1345 + tpriv = usbi_get_transfer_priv(
1346 + LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
1347 + hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
1348 + ep = illumos_usb_ep_index(transfer->endpoint);
1350 + tpriv->transfer = transfer;
1351 + aiocb = &tpriv->aiocb;
1352 + bzero(aiocb, sizeof(*aiocb));
1353 + aiocb->aio_fildes = hpriv->eps[ep].datafd;
1354 + aiocb->aio_buf = transfer->buffer;
1355 + aiocb->aio_nbytes = transfer->length;
1356 + aiocb->aio_lio_opcode =
1357 + ((transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) ==
1358 + LIBUSB_ENDPOINT_IN) ? LIO_READ:LIO_WRITE;
1359 + aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
1360 + aiocb->aio_sigevent.sigev_value.sival_ptr = tpriv;
1361 + aiocb->aio_sigevent.sigev_notify_function = illumos_async_callback;
1363 + if (aiocb->aio_lio_opcode == LIO_READ) {
1364 + ret = aio_read(aiocb);
1365 + } else {
1366 + ret = aio_write(aiocb);
1369 + return (ret);
1372 +/* return the number of bytes read/written */
1373 +static ssize_t
1374 +usb_do_io(struct libusb_context *ctx, int fd, int stat_fd, void *data,
1375 + size_t size, int flag, int *status)
1377 + int error;
1378 + ssize_t ret = -1;
1380 + usbi_dbg(ctx, "usb_do_io(): datafd=%d statfd=%d size=0x%zx flag=%s",
1381 + fd, stat_fd, size, flag? "WRITE":"READ");
1383 + switch (flag) {
1384 + case READ:
1385 + errno = 0;
1386 + ret = read(fd, data, size);
1387 + usb_dump_data(data, size);
1388 + break;
1389 + case WRITE:
1390 + usb_dump_data(data, size);
1391 + errno = 0;
1392 + ret = write(fd, data, size);
1393 + break;
1396 + usbi_dbg(ctx, "usb_do_io(): amount=%zd", ret);
1398 + if (ret < 0) {
1399 + int save_errno = errno;
1401 + usbi_dbg(ctx, "TID=%x io %s errno %d (%s)", pthread_self(),
1402 + flag?"WRITE":"READ", errno, strerror(errno));
1404 + /* illumos_usb_get_status will do a read and overwrite errno */
1405 + error = illumos_usb_get_status(ctx, stat_fd);
1406 + usbi_dbg(ctx, "io status=%d errno %d (%s)", error,
1407 + save_errno, strerror(save_errno));
1409 + if (status) {
1410 + *status = save_errno;
1413 + return (save_errno);
1415 + } else if (status) {
1416 + *status = 0;
1419 + return (ret);
1422 +static int
1423 +solaris_submit_ctrl_on_default(struct libusb_transfer *transfer)
1425 + ssize_t ret = -1, setup_ret;
1426 + int status;
1427 + illumos_dev_handle_priv_t *hpriv;
1428 + struct libusb_device_handle *hdl = transfer->dev_handle;
1429 + uint16_t wLength;
1430 + uint8_t *data = transfer->buffer;
1432 + hpriv = usbi_get_device_handle_priv(hdl);
1433 + wLength = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
1435 + if (hpriv->eps[0].datafd == -1) {
1436 + usbi_dbg(TRANSFER_CTX(transfer), "ep0 not opened");
1438 + return (LIBUSB_ERROR_NOT_FOUND);
1441 + if ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) {
1442 + usbi_dbg(TRANSFER_CTX(transfer), "IN request");
1443 + ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd,
1444 + hpriv->eps[0].statfd, data, LIBUSB_CONTROL_SETUP_SIZE,
1445 + WRITE, &status);
1446 + } else {
1447 + usbi_dbg(TRANSFER_CTX(transfer), "OUT request");
1448 + ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd,
1449 + hpriv->eps[0].statfd, transfer->buffer, transfer->length,
1450 + WRITE, (int *)&transfer->status);
1453 + setup_ret = ret;
1454 + if (ret < (ssize_t)LIBUSB_CONTROL_SETUP_SIZE) {
1455 + usbi_dbg(TRANSFER_CTX(transfer),
1456 + "error sending control msg: %zd", ret);
1457 + return (LIBUSB_ERROR_IO);
1460 + ret = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
1462 + /* Read the remaining bytes for IN request */
1463 + if ((wLength) && ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) ==
1464 + LIBUSB_ENDPOINT_IN)) {
1465 + usbi_dbg(TRANSFER_CTX(transfer), "DATA: %d",
1466 + transfer->length - (int)setup_ret);
1467 + ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd,
1468 + hpriv->eps[0].statfd,
1469 + transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
1470 + wLength, READ, (int *)&transfer->status);
1473 + if (ret >= 0) {
1474 + LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->transferred = ret;
1476 + usbi_dbg(TRANSFER_CTX(transfer), "Done: ctrl data bytes %zd", ret);
1478 + /*
1479 + * Sync transfer handling.
1480 + * We should release transfer lock here and later get it back
1481 + * as usbi_handle_transfer_completion() takes its own transfer lock.
1482 + */
1483 + usbi_mutex_unlock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
1484 + ret = usbi_handle_transfer_completion(
1485 + LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer), transfer->status);
1486 + usbi_mutex_lock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
1488 + return (ret);
1491 +int
1492 +illumos_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
1494 + int ret;
1496 + usbi_dbg(HANDLE_CTX(handle), "endpoint=0x%02x", endpoint);
1498 + ret = libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT |
1499 + LIBUSB_RECIPIENT_ENDPOINT | LIBUSB_REQUEST_TYPE_STANDARD,
1500 + LIBUSB_REQUEST_CLEAR_FEATURE, 0, endpoint, NULL, 0, 1000);
1502 + usbi_dbg(HANDLE_CTX(handle), "ret=%d", ret);
1504 + return (ret);
1507 +void
1508 +illumos_destroy_device(struct libusb_device *dev)
1510 + illumos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
1512 + usbi_dbg(DEVICE_CTX(dev), "destroy everything");
1513 + free(dpriv->raw_cfgdescr);
1514 + free(dpriv->ugenpath);
1515 + free(dpriv->phypath);
1518 +int
1519 +illumos_submit_transfer(struct usbi_transfer *itransfer)
1521 + struct libusb_transfer *transfer;
1522 + struct libusb_device_handle *hdl;
1523 + int err = 0;
1525 + transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
1526 + hdl = transfer->dev_handle;
1528 + err = illumos_check_device_and_status_open(hdl,
1529 + transfer->endpoint, transfer->type);
1530 + if (err != 0) {
1531 + return (_errno_to_libusb(err));
1534 + switch (transfer->type) {
1535 + case LIBUSB_TRANSFER_TYPE_CONTROL:
1536 + /* sync transfer */
1537 + usbi_dbg(ITRANSFER_CTX(itransfer),
1538 + "CTRL transfer: %d", transfer->length);
1539 + err = solaris_submit_ctrl_on_default(transfer);
1540 + break;
1542 + case LIBUSB_TRANSFER_TYPE_BULK:
1543 + usbi_dbg(ITRANSFER_CTX(itransfer),
1544 + "BULK transfer: %d", transfer->length);
1545 + err = illumos_do_async_io(transfer);
1546 + break;
1548 + case LIBUSB_TRANSFER_TYPE_INTERRUPT:
1549 + usbi_dbg(ITRANSFER_CTX(itransfer),
1550 + "INTR transfer: %d", transfer->length);
1551 + err = illumos_do_async_io(transfer);
1552 + break;
1554 + /* Isochronous/Stream is not supported */
1555 + case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
1556 + usbi_dbg(ITRANSFER_CTX(itransfer),
1557 + "ISOC transfer: %d", transfer->length);
1558 + err = LIBUSB_ERROR_NOT_SUPPORTED;
1559 + break;
1561 + case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
1562 + usbi_dbg(ITRANSFER_CTX(itransfer),
1563 + "BULK STREAM transfer: %d", transfer->length);
1564 + err = LIBUSB_ERROR_NOT_SUPPORTED;
1565 + break;
1568 + return (err);
1571 +int
1572 +illumos_cancel_transfer(struct usbi_transfer *itransfer)
1574 + illumos_xfer_priv_t *tpriv;
1575 + illumos_dev_handle_priv_t *hpriv;
1576 + struct libusb_transfer *transfer;
1577 + struct aiocb *aiocb;
1578 + uint8_t ep;
1579 + int ret;
1581 + tpriv = usbi_get_transfer_priv(itransfer);
1582 + aiocb = &tpriv->aiocb;
1583 + transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
1584 + hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
1585 + ep = illumos_usb_ep_index(transfer->endpoint);
1587 + ret = aio_cancel(hpriv->eps[ep].datafd, aiocb);
1589 + usbi_dbg(ITRANSFER_CTX(itransfer), "aio->fd=%d fd=%d ret = %d, %s",
1590 + aiocb->aio_fildes, hpriv->eps[ep].datafd, ret,
1591 + (ret == AIO_CANCELED) ? "AIO canceled" : strerror(errno));
1593 + if (ret != AIO_CANCELED) {
1594 + ret = _errno_to_libusb(errno);
1595 + } else {
1596 + /*
1597 + * we don't need to call usbi_handle_transfer_cancellation(),
1598 + * because we'll handle everything in illumos_async_callback.
1599 + */
1600 + ret = LIBUSB_SUCCESS;
1603 + return (ret);
1606 +int
1607 +illumos_handle_transfer_completion(struct usbi_transfer *itransfer)
1609 + return (usbi_handle_transfer_completion(itransfer,
1610 + LIBUSB_TRANSFER_COMPLETED));
1613 +int
1614 +_errno_to_libusb(int err)
1616 + usbi_dbg(NULL, "error: %s (%d)", strerror(err), err);
1618 + switch (err) {
1619 + case EIO:
1620 + return (LIBUSB_ERROR_IO);
1621 + case EACCES:
1622 + return (LIBUSB_ERROR_ACCESS);
1623 + case ENOENT:
1624 + return (LIBUSB_ERROR_NO_DEVICE);
1625 + case ENOMEM:
1626 + return (LIBUSB_ERROR_NO_MEM);
1627 + case ETIMEDOUT:
1628 + return (LIBUSB_ERROR_TIMEOUT);
1631 + return (LIBUSB_ERROR_OTHER);
1635 + * illumos_usb_get_status:
1636 + * gets status of endpoint
1638 + * Returns: ugen's last cmd status
1639 + */
1640 +static int
1641 +illumos_usb_get_status(struct libusb_context *ctx, int fd)
1643 + int status;
1644 + ssize_t ret;
1646 + usbi_dbg(ctx, "illumos_usb_get_status(): fd=%d", fd);
1648 + ret = read(fd, &status, sizeof(status));
1649 + if (ret == sizeof(status)) {
1650 + switch (status) {
1651 + case USB_LC_STAT_NOERROR:
1652 + usbi_dbg(ctx, "No Error");
1653 + break;
1654 + case USB_LC_STAT_CRC:
1655 + usbi_dbg(ctx, "CRC Timeout Detected\n");
1656 + break;
1657 + case USB_LC_STAT_BITSTUFFING:
1658 + usbi_dbg(ctx, "Bit Stuffing Violation\n");
1659 + break;
1660 + case USB_LC_STAT_DATA_TOGGLE_MM:
1661 + usbi_dbg(ctx, "Data Toggle Mismatch\n");
1662 + break;
1663 + case USB_LC_STAT_STALL:
1664 + usbi_dbg(ctx, "End Point Stalled\n");
1665 + break;
1666 + case USB_LC_STAT_DEV_NOT_RESP:
1667 + usbi_dbg(ctx, "Device is Not Responding\n");
1668 + break;
1669 + case USB_LC_STAT_PID_CHECKFAILURE:
1670 + usbi_dbg(ctx, "PID Check Failure\n");
1671 + break;
1672 + case USB_LC_STAT_UNEXP_PID:
1673 + usbi_dbg(ctx, "Unexpected PID\n");
1674 + break;
1675 + case USB_LC_STAT_DATA_OVERRUN:
1676 + usbi_dbg(ctx, "Data Exceeded Size\n");
1677 + break;
1678 + case USB_LC_STAT_DATA_UNDERRUN:
1679 + usbi_dbg(ctx, "Less data received\n");
1680 + break;
1681 + case USB_LC_STAT_BUFFER_OVERRUN:
1682 + usbi_dbg(ctx, "Buffer Size Exceeded\n");
1683 + break;
1684 + case USB_LC_STAT_BUFFER_UNDERRUN:
1685 + usbi_dbg(ctx, "Buffer Underrun\n");
1686 + break;
1687 + case USB_LC_STAT_TIMEOUT:
1688 + usbi_dbg(ctx, "Command Timed Out\n");
1689 + break;
1690 + case USB_LC_STAT_NOT_ACCESSED:
1691 + usbi_dbg(ctx, "Not Accessed by h/w\n");
1692 + break;
1693 + case USB_LC_STAT_UNSPECIFIED_ERR:
1694 + usbi_dbg(ctx, "Unspecified Error\n");
1695 + break;
1696 + case USB_LC_STAT_NO_BANDWIDTH:
1697 + usbi_dbg(ctx, "No Bandwidth\n");
1698 + break;
1699 + case USB_LC_STAT_HW_ERR:
1700 + usbi_dbg(ctx, "Host Controller h/w Error\n");
1701 + break;
1702 + case USB_LC_STAT_SUSPENDED:
1703 + usbi_dbg(ctx, "Device was Suspended\n");
1704 + break;
1705 + case USB_LC_STAT_DISCONNECTED:
1706 + usbi_dbg(ctx, "Device was Disconnected\n");
1707 + break;
1708 + case USB_LC_STAT_INTR_BUF_FULL:
1709 + usbi_dbg(ctx, "Interrupt buffer was full\n");
1710 + break;
1711 + case USB_LC_STAT_INVALID_REQ:
1712 + usbi_dbg(ctx, "Request was Invalid\n");
1713 + break;
1714 + case USB_LC_STAT_INTERRUPTED:
1715 + usbi_dbg(ctx, "Request was Interrupted\n");
1716 + break;
1717 + case USB_LC_STAT_NO_RESOURCES:
1718 + usbi_dbg(ctx, "No resources available for "
1719 + "request\n");
1720 + break;
1721 + case USB_LC_STAT_INTR_POLLING_FAILED:
1722 + usbi_dbg(ctx, "Failed to Restart Poll");
1723 + break;
1724 + default:
1725 + usbi_dbg(ctx, "Error Not Determined %d\n",
1726 + status);
1727 + break;
1729 + } else {
1730 + usbi_dbg(ctx, "read stat error: %s",strerror(errno));
1731 + status = -1;
1734 + return (status);
1737 +const struct usbi_os_backend usbi_backend = {
1738 + .name = "illumos",
1739 + .get_device_list = illumos_get_device_list,
1740 + .open = illumos_open,
1741 + .close = illumos_close,
1743 + .get_active_config_descriptor = illumos_get_active_config_descriptor,
1744 + .get_config_descriptor = illumos_get_config_descriptor,
1746 + .get_configuration = illumos_get_configuration,
1747 + .set_configuration = illumos_set_configuration,
1749 + .claim_interface = illumos_claim_interface,
1750 + .release_interface = illumos_release_interface,
1752 + .set_interface_altsetting = illumos_set_interface_altsetting,
1753 + .clear_halt = illumos_clear_halt,
1754 + .destroy_device = illumos_destroy_device,
1756 + .submit_transfer = illumos_submit_transfer,
1757 + .cancel_transfer = illumos_cancel_transfer,
1759 + .handle_transfer_completion = illumos_handle_transfer_completion,
1761 + .device_priv_size = sizeof(illumos_dev_priv_t),
1762 + .device_handle_priv_size = sizeof(illumos_dev_handle_priv_t),
1764 + .kernel_driver_active = illumos_kernel_driver_active,
1765 + .detach_kernel_driver = illumos_detach_kernel_driver,
1766 + .attach_kernel_driver = illumos_attach_kernel_driver,
1767 + .transfer_priv_size = sizeof(illumos_xfer_priv_t),
1769 diff --git a/libusb/os/illumos_usb.h b/libusb/os/illumos_usb.h
1770 new file mode 100644
1771 index 000000000..f24c37075
1772 --- /dev/null
1773 +++ b/libusb/os/illumos_usb.h
1774 @@ -0,0 +1,80 @@
1777 + * Copyright (c) 2016, Oracle and/or its affiliates.
1778 + * Copyright 2021 Oxide Computer Company
1780 + * This library is free software; you can redistribute it and/or
1781 + * modify it under the terms of the GNU Lesser General Public
1782 + * License as published by the Free Software Foundation; either
1783 + * version 2.1 of the License, or (at your option) any later version.
1785 + * This library is distributed in the hope that it will be useful,
1786 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1787 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1788 + * Lesser General Public License for more details.
1790 + * You should have received a copy of the GNU Lesser General Public
1791 + * License along with this library; if not, write to the Free Software
1792 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1793 + */
1795 +#ifndef LIBUSB_ILLUMOS_H
1796 +#define LIBUSB_ILLUMOS_H
1798 +#include <libdevinfo.h>
1799 +#include <pthread.h>
1800 +#include "libusbi.h"
1802 +#define READ 0
1803 +#define WRITE 1
1805 +typedef struct illumos_device_priv {
1806 + uint8_t cfgvalue; /* active config value */
1807 + uint8_t *raw_cfgdescr; /* active config descriptor */
1808 + char *ugenpath; /* name of the ugen(4) node */
1809 + char *phypath; /* physical path */
1810 +} illumos_dev_priv_t;
1812 +typedef struct endpoint {
1813 + int datafd; /* data file */
1814 + int statfd; /* state file */
1815 +} illumos_ep_priv_t;
1817 +typedef struct illumos_device_handle_priv {
1818 + uint8_t altsetting[USB_MAXINTERFACES]; /* a interface's alt */
1819 + uint8_t config_index;
1820 + illumos_ep_priv_t eps[USB_MAXENDPOINTS];
1821 + illumos_dev_priv_t *dpriv; /* device private */
1822 +} illumos_dev_handle_priv_t;
1824 +typedef struct illumos_transfer_priv {
1825 + struct aiocb aiocb;
1826 + struct libusb_transfer *transfer;
1827 +} illumos_xfer_priv_t;
1829 +struct node_args {
1830 + struct libusb_context *ctx;
1831 + struct discovered_devs **discdevs;
1832 + const char *last_ugenpath;
1833 + di_devlink_handle_t dlink_hdl;
1836 +struct devlink_cbarg {
1837 + struct node_args *nargs; /* di node walk arguments */
1838 + di_node_t myself; /* the di node */
1839 + di_minor_t minor;
1842 +typedef struct walk_link {
1843 + char *path;
1844 + int len;
1845 + char **linkpp;
1846 +} walk_link_t;
1848 +/* AIO callback args */
1849 +struct aio_callback_args{
1850 + struct libusb_transfer *transfer;
1851 + struct aiocb aiocb;
1854 +#endif /* LIBUSB_ILLUMOS_H */