pkgsrc-Changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

CVS commit: pkgsrc/devel/libusb1



Module Name:    pkgsrc
Committed By:   nia
Date:           Fri Feb 16 08:13:13 UTC 2024

Modified Files:
        pkgsrc/devel/libusb1: Makefile distinfo
Added Files:
        pkgsrc/devel/libusb1/patches: patch-configure.ac
            patch-libusb_Makefile.am patch-libusb_os_illumos__usb.c
            patch-libusb_os_illumos__usb.h

Log Message:
libusb1: restore working illumos support; via OmniOS


To generate a diff of this commit:
cvs rdiff -u -r1.32 -r1.33 pkgsrc/devel/libusb1/Makefile
cvs rdiff -u -r1.20 -r1.21 pkgsrc/devel/libusb1/distinfo
cvs rdiff -u -r0 -r1.9 pkgsrc/devel/libusb1/patches/patch-configure.ac
cvs rdiff -u -r0 -r1.3 pkgsrc/devel/libusb1/patches/patch-libusb_Makefile.am
cvs rdiff -u -r0 -r1.1 \
    pkgsrc/devel/libusb1/patches/patch-libusb_os_illumos__usb.c \
    pkgsrc/devel/libusb1/patches/patch-libusb_os_illumos__usb.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: pkgsrc/devel/libusb1/Makefile
diff -u pkgsrc/devel/libusb1/Makefile:1.32 pkgsrc/devel/libusb1/Makefile:1.33
--- pkgsrc/devel/libusb1/Makefile:1.32  Sat Feb 10 16:40:56 2024
+++ pkgsrc/devel/libusb1/Makefile       Fri Feb 16 08:13:13 2024
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.32 2024/02/10 16:40:56 wiz Exp $
+# $NetBSD: Makefile,v 1.33 2024/02/16 08:13:13 nia Exp $
 
 DISTNAME=      libusb-1.0.27
 PKGNAME=       ${DISTNAME:S/libusb/libusb1/}
@@ -21,6 +21,7 @@ USE_CC_FEATURES+=     c11
 
 GNU_CONFIGURE= yes
 USE_LIBTOOL=   yes
+USE_TOOLS+=    autoconf automake autoreconf
 USE_TOOLS+=    pkg-config
 MAKE_JOBS_SAFE=        no
 
@@ -43,6 +44,9 @@ LDFLAGS.SunOS+=               -lcmdutils # list_creat
 
 CONFLICTS=     libusbx-[0-9]*
 
+pre-configure:
+       cd ${WRKSRC} && autoreconf -fi
+
 do-test:
        cd ${WRKSRC}/tests && ./stress
 

Index: pkgsrc/devel/libusb1/distinfo
diff -u pkgsrc/devel/libusb1/distinfo:1.20 pkgsrc/devel/libusb1/distinfo:1.21
--- pkgsrc/devel/libusb1/distinfo:1.20  Sat Feb 10 16:40:56 2024
+++ pkgsrc/devel/libusb1/distinfo       Fri Feb 16 08:13:13 2024
@@ -1,5 +1,9 @@
-$NetBSD: distinfo,v 1.20 2024/02/10 16:40:56 wiz Exp $
+$NetBSD: distinfo,v 1.21 2024/02/16 08:13:13 nia Exp $
 
 BLAKE2s (libusb-1.0.27.tar.bz2) = e0cbc6fd96dd3799dff60940d634179015960b81fac8596986806edee95062a7
 SHA512 (libusb-1.0.27.tar.bz2) = 42abbbcf2564f86cc2f05826aeefa6beb03c9f89dc9fe05bdfa351caa3dbd07713ce193daadecf29557604dd3cbc770c8031a78e1ad0a8df3627c3f551d28ff0
 Size (libusb-1.0.27.tar.bz2) = 643680 bytes
+SHA1 (patch-configure.ac) = 52ef406375ea88ea06b8a0c4b1bace2c43586783
+SHA1 (patch-libusb_Makefile.am) = 4cbaca146dd349aad83e1ed696e8395a60c24780
+SHA1 (patch-libusb_os_illumos__usb.c) = ec9f086e29f8cfecc08842a903d7b6be61664c51
+SHA1 (patch-libusb_os_illumos__usb.h) = 3ea0581946ba4e1d21a718899c041977c1f2e5a4

Added files:

Index: pkgsrc/devel/libusb1/patches/patch-configure.ac
diff -u /dev/null pkgsrc/devel/libusb1/patches/patch-configure.ac:1.9
--- /dev/null   Fri Feb 16 08:13:13 2024
+++ pkgsrc/devel/libusb1/patches/patch-configure.ac     Fri Feb 16 08:13:13 2024
@@ -0,0 +1,65 @@
+$NetBSD: patch-configure.ac,v 1.9 2024/02/16 08:13:13 nia Exp $
+
+illumos support; via OmniOS.
+
+From 57b0bd0b3624eea8f7a56cb477649f2f35b0bab7 Mon Sep 17 00:00:00 2001
+From: "Joshua M. Clulow" <josh%sysmgr.org@localhost>
+Date: Mon, 27 Dec 2021 16:08:38 -0800
+Subject: [PATCH] illumos: split off from Solaris backend
+
+--- configure.ac.orig  2024-01-31 22:07:28.000000000 +0000
++++ configure.ac
+@@ -119,9 +119,15 @@ Please use an explicit --host=$host_cpu-
+       platform=posix
+       ;;
+ *-solaris*)
+-      AC_MSG_RESULT([SunOS])
+-      backend=sunos
+-      platform=posix
++      if test "x`uname -o`" = xillumos; then
++              AC_MSG_RESULT([illumos])
++              backend=illumos
++              platform=posix
++      else
++              AC_MSG_RESULT([SunOS])
++              backend=sunos
++              platform=posix
++      fi
+       ;;
+ *-cygwin*)
+       AC_MSG_RESULT([Windows (using Cygwin)])
+@@ -224,7 +230,7 @@ linux)
+               AC_CHECK_HEADER([sys/socket.h], [], [AC_MSG_ERROR([Linux socket header not found])])
+       fi
+       ;;
+-sunos)
++sunos|illumos)
+       LIBS="${LIBS} -ldevinfo"
+       ;;
+ windows)
+@@ -262,7 +268,7 @@ if test "x$platform" = xposix && test "x
+ fi
+ 
+ dnl eventfd support
+-if test "x$backend" = xlinux || test "x$backend" = xsunos; then
++if test "x$backend" = xlinux || test "x$backend" = xsunos || test "x$backend" = xillumos; then
+       AC_ARG_ENABLE([eventfd],
+               [AS_HELP_STRING([--enable-eventfd], [use eventfd for signalling [default=auto]])],
+               [use_eventfd=$enableval],
+@@ -300,7 +306,7 @@ if test "x$backend" = xlinux || test "x$
+ fi
+ 
+ dnl timerfd support
+-if test "x$backend" = xlinux || test "x$backend" = xsunos; then
++if test "x$backend" = xlinux || test "x$backend" = xsunos || test "x$backend" = xillumos; then
+       AC_ARG_ENABLE([timerfd],
+               [AS_HELP_STRING([--enable-timerfd], [use timerfd for timing [default=auto]])],
+               [use_timerfd=$enableval],
+@@ -392,6 +398,7 @@ AM_CONDITIONAL([OS_NETBSD], [test "x$bac
+ AM_CONDITIONAL([OS_NULL], [test "x$backend" = xnull])
+ AM_CONDITIONAL([OS_OPENBSD], [test "x$backend" = xopenbsd])
+ AM_CONDITIONAL([OS_SUNOS], [test "x$backend" = xsunos])
++AM_CONDITIONAL([OS_ILLUMOS], [test "x$backend" = xillumos])
+ AM_CONDITIONAL([OS_WINDOWS], [test "x$backend" = xwindows])
+ AM_CONDITIONAL([OS_EMSCRIPTEN], [test "x$backend" = xemscripten])
+ AM_CONDITIONAL([PLATFORM_POSIX], [test "x$platform" = xposix])

Index: pkgsrc/devel/libusb1/patches/patch-libusb_Makefile.am
diff -u /dev/null pkgsrc/devel/libusb1/patches/patch-libusb_Makefile.am:1.3
--- /dev/null   Fri Feb 16 08:13:13 2024
+++ pkgsrc/devel/libusb1/patches/patch-libusb_Makefile.am       Fri Feb 16 08:13:13 2024
@@ -0,0 +1,30 @@
+$NetBSD: patch-libusb_Makefile.am,v 1.3 2024/02/16 08:13:13 nia Exp $
+
+illumos support; via OmniOS.
+
+From 57b0bd0b3624eea8f7a56cb477649f2f35b0bab7 Mon Sep 17 00:00:00 2001
+From: "Joshua M. Clulow" <josh%sysmgr.org@localhost>
+Date: Mon, 27 Dec 2021 16:08:38 -0800
+Subject: [PATCH] illumos: split off from Solaris backend
+
+--- libusb/Makefile.am.orig    2024-01-19 17:03:19.000000000 +0000
++++ libusb/Makefile.am
+@@ -25,6 +25,7 @@ OS_NETBSD_SRC = os/netbsd_usb.c
+ OS_NULL_SRC = os/null_usb.c
+ OS_OPENBSD_SRC = os/openbsd_usb.c
+ OS_SUNOS_SRC = os/sunos_usb.h os/sunos_usb.c
++OS_ILLUMOS_SRC = os/illumos_usb.h os/illumos_usb.c
+ OS_WINDOWS_SRC = libusb-1.0.def libusb-1.0.rc \
+                os/windows_common.h os/windows_common.c \
+                os/windows_usbdk.h os/windows_usbdk.c \
+@@ -74,6 +75,10 @@ if OS_SUNOS
+ OS_SRC = $(OS_SUNOS_SRC)
+ endif
+ 
++if OS_ILLUMOS
++OS_SRC = $(OS_ILLUMOS_SRC)
++endif
++
+ if OS_WINDOWS
+ OS_SRC = $(OS_WINDOWS_SRC)
+ 

Index: pkgsrc/devel/libusb1/patches/patch-libusb_os_illumos__usb.c
diff -u /dev/null pkgsrc/devel/libusb1/patches/patch-libusb_os_illumos__usb.c:1.1
--- /dev/null   Fri Feb 16 08:13:13 2024
+++ pkgsrc/devel/libusb1/patches/patch-libusb_os_illumos__usb.c Fri Feb 16 08:13:13 2024
@@ -0,0 +1,1723 @@
+$NetBSD: patch-libusb_os_illumos__usb.c,v 1.1 2024/02/16 08:13:13 nia Exp $
+
+illumos support; via OmniOS.
+
+From 57b0bd0b3624eea8f7a56cb477649f2f35b0bab7 Mon Sep 17 00:00:00 2001
+From: "Joshua M. Clulow" <josh%sysmgr.org@localhost>
+Date: Mon, 27 Dec 2021 16:08:38 -0800
+Subject: [PATCH] illumos: split off from Solaris backend
+
+--- libusb/os/illumos_usb.c.orig       2024-02-16 08:09:37.472034604 +0000
++++ libusb/os/illumos_usb.c
+@@ -0,0 +1,1711 @@
++/*
++ *
++ * Copyright (c) 2016, Oracle and/or its affiliates.
++ * Copyright 2021 Oxide Computer Company
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <config.h>
++
++#include <sys/time.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <strings.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <wait.h>
++#include <unistd.h>
++#include <aio.h>
++#include <libdevinfo.h>
++#include <sys/nvpair.h>
++#include <sys/devctl.h>
++#include <sys/usb/clients/ugen/usb_ugen.h>
++#include <sys/usb/usba.h>
++#include <sys/pci.h>
++
++#include "libusbi.h"
++#include "illumos_usb.h"
++
++#define       UPDATEDRV_PATH  "/usr/sbin/update_drv"
++#define       UPDATEDRV       "update_drv"
++
++#define       DEFAULT_LISTSIZE        6
++
++typedef struct {
++      int     nargs;
++      int     listsize;
++      char    **string;
++} string_list_t;
++
++/*
++ * Backend functions
++ */
++static int illumos_get_device_list(struct libusb_context *,
++    struct discovered_devs **);
++static int illumos_open(struct libusb_device_handle *);
++static void illumos_close(struct libusb_device_handle *);
++static int illumos_get_active_config_descriptor(struct libusb_device *,
++    void *, size_t);
++static int illumos_get_config_descriptor(struct libusb_device *, uint8_t,
++    void *, size_t);
++static int illumos_get_configuration(struct libusb_device_handle *, uint8_t *);
++static int illumos_set_configuration(struct libusb_device_handle *, int);
++static int illumos_claim_interface(struct libusb_device_handle *, uint8_t);
++static int illumos_release_interface(struct libusb_device_handle *, uint8_t);
++static int illumos_set_interface_altsetting(struct libusb_device_handle *,
++    uint8_t, uint8_t);
++static int illumos_clear_halt(struct libusb_device_handle *, unsigned char);
++static void illumos_destroy_device(struct libusb_device *);
++static int illumos_submit_transfer(struct usbi_transfer *);
++static int illumos_cancel_transfer(struct usbi_transfer *);
++static int illumos_handle_transfer_completion(struct usbi_transfer *);
++static int illumos_kernel_driver_active(struct libusb_device_handle *, uint8_t);
++static int illumos_detach_kernel_driver(struct libusb_device_handle *, uint8_t);
++static int illumos_attach_kernel_driver(struct libusb_device_handle *, uint8_t);
++static int illumos_usb_open_ep0(illumos_dev_handle_priv_t *hpriv,
++    illumos_dev_priv_t *dpriv);
++static int illumos_usb_ioctl(struct libusb_device *dev, int cmd);
++
++static int
++illumos_get_link(di_devlink_t devlink, void *arg)
++{
++      walk_link_t *larg = (walk_link_t *)arg;
++      const char *p;
++      const char *q;
++
++      if (larg->path) {
++              char *content = (char *)di_devlink_content(devlink);
++              char *start = strstr(content, "/devices/");
++              start += strlen("/devices");
++              usbi_dbg(NULL, "%s", start);
++
++              /* line content must have minor node */
++              if (start == NULL ||
++                  strncmp(start, larg->path, larg->len) != 0 ||
++                  start[larg->len] != ':') {
++                      return (DI_WALK_CONTINUE);
++              }
++      }
++
++      p = di_devlink_path(devlink);
++      q = strrchr(p, '/');
++      usbi_dbg(NULL, "%s", q);
++
++      *(larg->linkpp) = strndup(p, strlen(p) - strlen(q));
++
++      return (DI_WALK_TERMINATE);
++}
++
++
++static int
++illumos_physpath_to_devlink(
++    const char *node_path, const char *match, char **link_path)
++{
++      walk_link_t larg;
++      di_devlink_handle_t hdl;
++
++      *link_path = NULL;
++      larg.linkpp = link_path;
++      if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
++              usbi_dbg(NULL, "di_devlink_init failure");
++              return (-1);
++      }
++
++      larg.len = strlen(node_path);
++      larg.path = (char *)node_path;
++
++      (void) di_devlink_walk(hdl, match, NULL, DI_PRIMARY_LINK,
++          (void *)&larg, illumos_get_link);
++
++      (void) di_devlink_fini(&hdl);
++
++      if (*link_path == NULL) {
++              usbi_dbg(NULL, "there is no devlink for this path");
++              return (-1);
++      }
++
++      return (0);
++}
++
++static int
++illumos_usb_ioctl(struct libusb_device *dev, int cmd)
++{
++      int fd;
++      nvlist_t *nvlist;
++      char *end;
++      char *phypath;
++      char *hubpath;
++      char path_arg[PATH_MAX];
++      illumos_dev_priv_t *dpriv;
++      devctl_ap_state_t devctl_ap_state;
++      struct devctl_iocdata iocdata;
++
++      dpriv = usbi_get_device_priv(dev);
++      phypath = dpriv->phypath;
++
++      end = strrchr(phypath, '/');
++      if (end == NULL)
++              return (-1);
++      hubpath = strndup(phypath, end - phypath);
++      if (hubpath == NULL)
++              return (-1);
++
++      end = strrchr(hubpath, '@');
++      if (end == NULL) {
++              free(hubpath);
++              return (-1);
++      }
++      end++;
++      usbi_dbg(DEVICE_CTX(dev), "unitaddr: %s", end);
++
++      nvlist_alloc(&nvlist, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP);
++      nvlist_add_int32(nvlist, "port", dev->port_number);
++      //find the hub path
++      snprintf(path_arg, sizeof(path_arg), "/devices%s:hubd", hubpath);
++      usbi_dbg(DEVICE_CTX(dev), "ioctl hub path: %s", path_arg);
++
++      fd = open(path_arg, O_RDONLY);
++      if (fd < 0) {
++              usbi_err(DEVICE_CTX(dev), "open failed: errno %d (%s)",
++                  errno, strerror(errno));
++              nvlist_free(nvlist);
++              free(hubpath);
++              return (-1);
++      }
++
++      memset(&iocdata, 0, sizeof(iocdata));
++      memset(&devctl_ap_state, 0, sizeof(devctl_ap_state));
++
++      nvlist_pack(nvlist, (char **)&iocdata.nvl_user, &iocdata.nvl_usersz,
++          NV_ENCODE_NATIVE, 0);
++
++      iocdata.cmd = DEVCTL_AP_GETSTATE;
++      iocdata.flags = 0;
++      iocdata.c_nodename = (char *)"hub";
++      iocdata.c_unitaddr = end;
++      iocdata.cpyout_buf = &devctl_ap_state;
++      usbi_dbg(DEVICE_CTX(dev), "%p, %" PRIuPTR, iocdata.nvl_user,
++          iocdata.nvl_usersz);
++
++      errno = 0;
++      if (ioctl(fd, DEVCTL_AP_GETSTATE, &iocdata) == -1) {
++              usbi_err(DEVICE_CTX(dev),
++                  "ioctl failed: fd %d, cmd %x, errno %d (%s)",
++                  fd, DEVCTL_AP_GETSTATE, errno, strerror(errno));
++      } else {
++              usbi_dbg(DEVICE_CTX(dev), "dev rstate: %d",
++                  devctl_ap_state.ap_rstate);
++              usbi_dbg(DEVICE_CTX(dev), "dev ostate: %d",
++                  devctl_ap_state.ap_ostate);
++      }
++
++      errno = 0;
++      iocdata.cmd = cmd;
++      if (ioctl(fd, (int)cmd, &iocdata) != 0) {
++              usbi_err(DEVICE_CTX(dev),
++                  "ioctl failed: fd %d, cmd %x, errno %d (%s)",
++                  fd, cmd, errno, strerror(errno));
++              sleep(2);
++      }
++
++      close(fd);
++      free(iocdata.nvl_user);
++      nvlist_free(nvlist);
++      free(hubpath);
++
++      return (-errno);
++}
++
++static int
++illumos_kernel_driver_active(struct libusb_device_handle *dev_handle,
++    uint8_t interface)
++{
++      illumos_dev_priv_t *dpriv = usbi_get_device_priv(dev_handle->dev);
++
++      UNUSED(interface);
++
++      usbi_dbg(HANDLE_CTX(dev_handle), "%s", dpriv->ugenpath);
++
++      return (dpriv->ugenpath == NULL);
++}
++
++/*
++ * Private functions
++ */
++static int _errno_to_libusb(int);
++static int illumos_usb_get_status(struct libusb_context *ctx, int fd);
++
++static string_list_t *
++illumos_new_string_list(void)
++{
++      string_list_t *list;
++
++      list = calloc(1, sizeof(string_list_t));
++      if (list == NULL)
++              return (NULL);
++      list->string = calloc(DEFAULT_LISTSIZE, sizeof(char *));
++      if (list->string == NULL) {
++              free(list);
++              return (NULL);
++      }
++      list->nargs = 0;
++      list->listsize = DEFAULT_LISTSIZE;
++
++      return (list);
++}
++
++static int
++illumos_append_to_string_list(string_list_t *list, const char *arg)
++{
++      char *str = strdup(arg);
++
++      if (str == NULL)
++              return (-1);
++
++      if ((list->nargs + 1) == list->listsize) { /* +1 is for NULL */
++              char **tmp = realloc(list->string,
++                  sizeof(char *) * (list->listsize + 1));
++              if (tmp == NULL) {
++                      free(str);
++                      return (-1);
++              }
++              list->string = tmp;
++              list->string[list->listsize++] = NULL;
++      }
++      list->string[list->nargs++] = str;
++
++      return (0);
++}
++
++static void
++illumos_free_string_list(string_list_t *list)
++{
++      int i;
++
++      for (i = 0; i < list->nargs; i++) {
++              free(list->string[i]);
++      }
++
++      free(list->string);
++      free(list);
++}
++
++static char **
++illumos_build_argv_list(string_list_t *list)
++{
++      return (list->string);
++}
++
++
++static int
++illumos_exec_command(struct libusb_context *ctx, const char *path,
++    string_list_t *list)
++{
++      pid_t pid;
++      int status;
++      int waitstat;
++      int exit_status;
++      char **argv_list;
++
++      argv_list = illumos_build_argv_list(list);
++      if (argv_list == NULL)
++              return (-1);
++
++      pid = fork();
++      if (pid == 0) {
++              /* child */
++              execv(path, argv_list);
++              _exit(127);
++      } else if (pid > 0) {
++              /* parent */
++              do {
++                      waitstat = waitpid(pid, &status, 0);
++              } while ((waitstat == -1 && errno == EINTR) ||
++                  (waitstat == 0 && !WIFEXITED(status) &&
++                  !WIFSIGNALED(status)));
++
++              if (waitstat == 0) {
++                      if (WIFEXITED(status))
++                              exit_status = WEXITSTATUS(status);
++                      else
++                              exit_status = WTERMSIG(status);
++              } else {
++                      usbi_err(ctx, "waitpid failed: errno %d (%s)", errno,
++                          strerror(errno));
++                      exit_status = -1;
++              }
++      } else {
++              /* fork failed */
++              usbi_err(ctx, "fork failed: errno %d (%s)", errno,
++                  strerror(errno));
++              exit_status = -1;
++      }
++
++      return (exit_status);
++}
++
++static int
++illumos_detach_kernel_driver(struct libusb_device_handle *dev_handle,
++    uint8_t interface_number)
++{
++      struct libusb_context *ctx = HANDLE_CTX(dev_handle);
++      string_list_t *list;
++      char path_arg[PATH_MAX];
++      illumos_dev_priv_t *dpriv;
++      int r;
++
++      UNUSED(interface_number);
++
++      dpriv = usbi_get_device_priv(dev_handle->dev);
++      snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
++      usbi_dbg(HANDLE_CTX(dev_handle), "%s", path_arg);
++
++      list = illumos_new_string_list();
++      if (list == NULL)
++              return (LIBUSB_ERROR_NO_MEM);
++
++      /* attach ugen driver */
++      r = 0;
++      r |= illumos_append_to_string_list(list, UPDATEDRV);
++      r |= illumos_append_to_string_list(list, "-a"); /* add rule */
++      r |= illumos_append_to_string_list(list, "-i"); /* specific device */
++      r |= illumos_append_to_string_list(list, path_arg); /* physical path */
++      r |= illumos_append_to_string_list(list, "ugen");
++      if (r) {
++              illumos_free_string_list(list);
++              return (LIBUSB_ERROR_NO_MEM);
++      }
++
++      r = illumos_exec_command(ctx, UPDATEDRV_PATH, list);
++      illumos_free_string_list(list);
++      if (r < 0)
++              return (LIBUSB_ERROR_OTHER);
++
++      /* reconfigure the driver node */
++      r = 0;
++      r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
++      r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
++      if (r)
++              usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
++
++      snprintf(path_arg, sizeof(path_arg), "^usb/%x.%x",
++          dev_handle->dev->device_descriptor.idVendor,
++          dev_handle->dev->device_descriptor.idProduct);
++      illumos_physpath_to_devlink(dpriv->phypath, path_arg, &dpriv->ugenpath);
++
++      if (access(dpriv->ugenpath, F_OK) == -1) {
++              usbi_err(HANDLE_CTX(dev_handle),
++                  "fail to detach kernel driver");
++              return (LIBUSB_ERROR_IO);
++      }
++
++      return (illumos_usb_open_ep0(usbi_get_device_handle_priv(dev_handle),
++          dpriv));
++}
++
++static int
++illumos_attach_kernel_driver(struct libusb_device_handle *dev_handle,
++    uint8_t interface_number)
++{
++      struct libusb_context *ctx = HANDLE_CTX(dev_handle);
++      string_list_t *list;
++      char path_arg[PATH_MAX];
++      illumos_dev_priv_t *dpriv;
++      int r;
++
++      UNUSED(interface_number);
++
++      /* we open the dev in detach driver, so we need close it first. */
++      illumos_close(dev_handle);
++
++      dpriv = usbi_get_device_priv(dev_handle->dev);
++      snprintf(path_arg, sizeof(path_arg), "\'\"%s\"\'", dpriv->phypath);
++      usbi_dbg(HANDLE_CTX(dev_handle), "%s", path_arg);
++
++      list = illumos_new_string_list();
++      if (list == NULL)
++              return (LIBUSB_ERROR_NO_MEM);
++
++      /* detach ugen driver */
++      r = 0;
++      r |= illumos_append_to_string_list(list, UPDATEDRV);
++      r |= illumos_append_to_string_list(list, "-d"); /* add rule */
++      r |= illumos_append_to_string_list(list, "-i"); /* specific device */
++      r |= illumos_append_to_string_list(list, path_arg); /* physical path */
++      r |= illumos_append_to_string_list(list, "ugen");
++      if (r) {
++              illumos_free_string_list(list);
++              return (LIBUSB_ERROR_NO_MEM);
++      }
++
++      r = illumos_exec_command(ctx, UPDATEDRV_PATH, list);
++      illumos_free_string_list(list);
++      if (r < 0)
++              return (LIBUSB_ERROR_OTHER);
++
++      /* reconfigure the driver node */
++      r = 0;
++      r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
++      r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_DISCONNECT);
++      r |= illumos_usb_ioctl(dev_handle->dev, DEVCTL_AP_CONFIGURE);
++      if (r)
++              usbi_warn(HANDLE_CTX(dev_handle), "one or more ioctls failed");
++
++      return (0);
++}
++
++static int
++illumos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
++{
++      int proplen;
++      int *i, n, *addr, *port_prop;
++      char *phypath;
++      uint8_t *rdata;
++      illumos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
++      char match_str[PATH_MAX];
++
++      /* Device descriptors */
++      proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
++          "usb-dev-descriptor", &rdata);
++      if (proplen <= 0) {
++              return (LIBUSB_ERROR_IO);
++      }
++      bcopy(rdata, &dev->device_descriptor, LIBUSB_DT_DEVICE_SIZE);
++
++      /* Raw configuration descriptors */
++      proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
++          "usb-raw-cfg-descriptors", &rdata);
++      if (proplen <= 0) {
++              usbi_dbg(DEVICE_CTX(dev), "can't find raw config descriptors");
++
++              return (LIBUSB_ERROR_IO);
++      }
++      dpriv->raw_cfgdescr = calloc(1, proplen);
++      if (dpriv->raw_cfgdescr == NULL) {
++              return (LIBUSB_ERROR_NO_MEM);
++      } else {
++              bcopy(rdata, dpriv->raw_cfgdescr, proplen);
++              dpriv->cfgvalue = ((struct libusb_config_descriptor *)
++                  rdata)->bConfigurationValue;
++      }
++
++      n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &port_prop);
++
++      if ((n != 1) || (*port_prop <= 0)) {
++              return (LIBUSB_ERROR_IO);
++      }
++      dev->port_number = *port_prop;
++
++      /* device physical path */
++      phypath = di_devfs_path(node);
++      if (phypath) {
++              dpriv->phypath = strdup(phypath);
++              snprintf(match_str, sizeof(match_str), "^usb/%x.%x",
++                  dev->device_descriptor.idVendor,
++                  dev->device_descriptor.idProduct);
++              usbi_dbg(DEVICE_CTX(dev), "match is %s", match_str);
++              illumos_physpath_to_devlink(dpriv->phypath, match_str,
++                  &dpriv->ugenpath);
++              di_devfs_path_free(phypath);
++
++      } else {
++              free(dpriv->raw_cfgdescr);
++
++              return (LIBUSB_ERROR_IO);
++      }
++
++      /* address */
++      n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "assigned-address", &addr);
++      if (n != 1 || *addr == 0) {
++              usbi_dbg(DEVICE_CTX(dev), "can't get address");
++      } else {
++              dev->device_address = *addr;
++      }
++
++      /* speed */
++      if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) {
++              dev->speed = LIBUSB_SPEED_LOW;
++      } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "high-speed",
++          &i) >= 0) {
++              dev->speed = LIBUSB_SPEED_HIGH;
++      } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "full-speed",
++          &i) >= 0) {
++              dev->speed = LIBUSB_SPEED_FULL;
++      } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "super-speed",
++          &i) >= 0) {
++              dev->speed = LIBUSB_SPEED_SUPER;
++      }
++
++      usbi_dbg(DEVICE_CTX(dev),
++          "vid=%x pid=%x, path=%s, bus_nmber=0x%x, port_number=%d, speed=%d",
++          dev->device_descriptor.idVendor, dev->device_descriptor.idProduct,
++          dpriv->phypath, dev->bus_number, dev->port_number, dev->speed);
++
++      return (LIBUSB_SUCCESS);
++}
++
++static int
++illumos_add_devices(di_devlink_t link, void *arg)
++{
++      struct devlink_cbarg *largs = (struct devlink_cbarg *)arg;
++      struct node_args *nargs;
++      di_node_t myself, dn;
++      uint64_t session_id = 0;
++      uint64_t sid = 0;
++      uint64_t bdf = 0;
++      struct libusb_device *dev;
++      illumos_dev_priv_t *devpriv;
++      int n, *j;
++      int i = 0;
++      int *addr_prop;
++      uint8_t bus_number = 0;
++      uint32_t * regbuf = NULL;
++      uint32_t reg;
++
++      UNUSED(link);
++
++      nargs = (struct node_args *)largs->nargs;
++      myself = largs->myself;
++
++      /*
++       * Construct session ID.
++       * session ID = dev_addr | hub addr |parent hub addr|...|root hub bdf
++       *              8 bits       8bits          8 bits               16bits
++       */
++      if (myself == DI_NODE_NIL)
++              return (DI_WALK_CONTINUE);
++
++      dn = myself;
++      /* find the root hub */
++      while (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "root-hub", &j) != 0) {
++              usbi_dbg(NULL, "find_root_hub:%s", di_devfs_path(dn));
++              n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
++                              "assigned-address", &addr_prop);
++              session_id |= ((addr_prop[0] & 0xff) << i++ * 8);
++              dn = di_parent_node(dn);
++      }
++
++      /* dn is the root hub node */
++      n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "reg", (int **)&regbuf);
++      reg = regbuf[0];
++      bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) |
++          PCI_REG_FUNC_G(reg);
++      /* bdf must larger than i*8 bits */
++      session_id |= (bdf << i * 8);
++      bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
++
++      usbi_dbg(NULL, "device bus address=%s:%x, name:%s",
++          di_bus_addr(myself), bus_number, di_node_name(dn));
++      usbi_dbg(NULL, "session id org:%" PRIx64, session_id);
++
++      /* dn is the usb device */
++      for (dn = di_child_node(myself); dn != DI_NODE_NIL;
++          dn = di_sibling_node(dn)) {
++              usbi_dbg(NULL, "device path:%s", di_devfs_path(dn));
++              /* skip hub devices, because its driver can not been unload */
++              if (di_prop_lookup_ints(DDI_DEV_T_ANY, dn, "usb-port-count",
++                  &addr_prop) != -1) {
++                      continue;
++              }
++              /* usb_addr */
++              n = di_prop_lookup_ints(DDI_DEV_T_ANY, dn,
++                  "assigned-address", &addr_prop);
++              if (n != 1 || addr_prop[0] == 0) {
++                      usbi_dbg(NULL, "cannot get valid usb_addr");
++                      continue;
++              }
++
++              sid = (session_id << 8) | (addr_prop[0] & 0xff) ;
++              usbi_dbg(NULL, "session id %" PRIX64, sid);
++
++              dev = usbi_get_device_by_session_id(nargs->ctx, sid);
++              if (dev == NULL) {
++                      dev = usbi_alloc_device(nargs->ctx, sid);
++                      if (dev == NULL) {
++                              usbi_dbg(NULL, "can't alloc device");
++                              continue;
++                      }
++                      devpriv = usbi_get_device_priv(dev);
++                      dev->bus_number = bus_number;
++
++                      if (illumos_fill_in_dev_info(dn, dev) !=
++                          LIBUSB_SUCCESS) {
++                              libusb_unref_device(dev);
++                              usbi_dbg(NULL, "get information fail");
++                              continue;
++                      }
++                      if (usbi_sanitize_device(dev) < 0) {
++                              libusb_unref_device(dev);
++                              usbi_dbg(NULL, "sanatize failed: ");
++                              return (DI_WALK_TERMINATE);
++                      }
++              } else {
++                      devpriv = usbi_get_device_priv(dev);
++                      usbi_dbg(NULL, "Dev %s exists", devpriv->ugenpath);
++              }
++
++              if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
++                      usbi_dbg(NULL, "cannot append device");
++              }
++
++              /*
++               * we alloc and hence ref this dev. We don't need to ref it
++               * hereafter. Front end or app should take care of their ref.
++               */
++              libusb_unref_device(dev);
++
++              usbi_dbg(NULL, "Device %s %s id=0x%" PRIx64
++                  ", devcount:%" PRIuPTR ", bdf=%" PRIx64,
++                  devpriv->ugenpath, di_devfs_path(dn), (uint64_t)sid,
++                  (*nargs->discdevs)->len, bdf);
++      }
++
++      return (DI_WALK_CONTINUE);
++}
++
++static int
++illumos_walk_minor_node_link(di_node_t node, void *args)
++{
++      di_minor_t minor = DI_MINOR_NIL;
++      char *minor_path;
++      struct devlink_cbarg arg;
++      struct node_args *nargs = (struct node_args *)args;
++      di_devlink_handle_t devlink_hdl = nargs->dlink_hdl;
++
++      /* walk each minor to find usb devices */
++      while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
++              minor_path = di_devfs_minor_path(minor);
++              arg.nargs = args;
++              arg.myself = node;
++              arg.minor = minor;
++              (void) di_devlink_walk(devlink_hdl,
++                  "^usb/hub[0-9]+", minor_path,
++                  DI_PRIMARY_LINK, (void *)&arg, illumos_add_devices);
++              di_devfs_path_free(minor_path);
++      }
++
++      /* switch to a different node */
++      nargs->last_ugenpath = NULL;
++
++      return (DI_WALK_CONTINUE);
++}
++
++int
++illumos_get_device_list(struct libusb_context * ctx,
++      struct discovered_devs **discdevs)
++{
++      di_node_t root_node;
++      struct node_args args;
++      di_devlink_handle_t devlink_hdl;
++
++      args.ctx = ctx;
++      args.discdevs = discdevs;
++      args.last_ugenpath = NULL;
++      if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
++              usbi_dbg(ctx, "di_int() failed: errno %d (%s)", errno,
++                  strerror(errno));
++              return (LIBUSB_ERROR_IO);
++      }
++
++      if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
++              di_fini(root_node);
++              usbi_dbg(ctx, "di_devlink_init() failed: errno %d (%s)", errno,
++                  strerror(errno));
++              return (LIBUSB_ERROR_IO);
++      }
++      args.dlink_hdl = devlink_hdl;
++
++      /* walk each node to find USB devices */
++      if (di_walk_node(root_node, DI_WALK_SIBFIRST, &args,
++          illumos_walk_minor_node_link) == -1) {
++              usbi_dbg(ctx, "di_walk_node() failed: errno %d (%s)", errno,
++                  strerror(errno));
++              di_fini(root_node);
++              return (LIBUSB_ERROR_IO);
++      }
++
++      di_fini(root_node);
++      di_devlink_fini(&devlink_hdl);
++
++      usbi_dbg(ctx, "%zu devices", (*discdevs)->len);
++
++      return ((*discdevs)->len);
++}
++
++static int
++illumos_usb_open_ep0(illumos_dev_handle_priv_t *hpriv,
++    illumos_dev_priv_t *dpriv)
++{
++      char filename[PATH_MAX + 1];
++
++      if (hpriv->eps[0].datafd > 0) {
++              return (LIBUSB_SUCCESS);
++      }
++      snprintf(filename, PATH_MAX, "%s/cntrl0", dpriv->ugenpath);
++
++      usbi_dbg(NULL, "opening %s", filename);
++      hpriv->eps[0].datafd = open(filename, O_RDWR);
++      if (hpriv->eps[0].datafd < 0) {
++              return (_errno_to_libusb(errno));
++      }
++
++      snprintf(filename, PATH_MAX, "%s/cntrl0stat", dpriv->ugenpath);
++      hpriv->eps[0].statfd = open(filename, O_RDONLY);
++      if (hpriv->eps[0].statfd < 0) {
++              close(hpriv->eps[0].datafd);
++              hpriv->eps[0].datafd = -1;
++              return (_errno_to_libusb(errno));
++      }
++
++      return (LIBUSB_SUCCESS);
++}
++
++static void
++illumos_usb_close_all_eps(illumos_dev_handle_priv_t *hdev)
++{
++      int i;
++
++      /* not close ep0 */
++      for (i = 1; i < USB_MAXENDPOINTS; i++) {
++              if (hdev->eps[i].datafd != -1) {
++                      (void) close(hdev->eps[i].datafd);
++                      hdev->eps[i].datafd = -1;
++              }
++              if (hdev->eps[i].statfd != -1) {
++                      (void) close(hdev->eps[i].statfd);
++                      hdev->eps[i].statfd = -1;
++              }
++      }
++}
++
++static void
++illumos_usb_close_ep0(illumos_dev_handle_priv_t *hdev)
++{
++      if (hdev->eps[0].datafd >= 0) {
++              close(hdev->eps[0].datafd);
++              close(hdev->eps[0].statfd);
++              hdev->eps[0].datafd = -1;
++              hdev->eps[0].statfd = -1;
++      }
++}
++
++static uchar_t
++illumos_usb_ep_index(uint8_t ep_addr)
++{
++      return ((ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK) +
++          ((ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? 16 : 0));
++}
++
++static int
++illumos_find_interface(struct libusb_device_handle *hdev,
++    uint8_t endpoint, uint8_t *interface)
++{
++      struct libusb_config_descriptor *config;
++      int r;
++      int iface_idx;
++
++      r = libusb_get_active_config_descriptor(hdev->dev, &config);
++      if (r < 0) {
++              return (LIBUSB_ERROR_INVALID_PARAM);
++      }
++
++      for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) {
++              const struct libusb_interface *iface =
++                  &config->interface[iface_idx];
++              int altsetting_idx;
++
++              for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting;
++                  altsetting_idx++) {
++                      const struct libusb_interface_descriptor *altsetting =
++                          &iface->altsetting[altsetting_idx];
++                      int ep_idx;
++
++                      for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints;
++                          ep_idx++) {
++                              const struct libusb_endpoint_descriptor *ep =
++                                      &altsetting->endpoint[ep_idx];
++                              if (ep->bEndpointAddress == endpoint) {
++                                      *interface = iface_idx;
++                                      libusb_free_config_descriptor(config);
++
++                                      return (LIBUSB_SUCCESS);
++                              }
++                      }
++              }
++      }
++      libusb_free_config_descriptor(config);
++
++      return (LIBUSB_ERROR_INVALID_PARAM);
++}
++
++static int
++illumos_check_device_and_status_open(struct libusb_device_handle *hdl,
++    uint8_t ep_addr, int ep_type)
++{
++      char filename[PATH_MAX + 1], statfilename[PATH_MAX + 1];
++      char cfg_num[16], alt_num[16];
++      int fd, fdstat, mode, e;
++      uint8_t ifc = 0;
++      uint8_t ep_index;
++      illumos_dev_handle_priv_t *hpriv;
++
++      usbi_dbg(HANDLE_CTX(hdl), "open ep 0x%02x", ep_addr);
++      hpriv = usbi_get_device_handle_priv(hdl);
++      ep_index = illumos_usb_ep_index(ep_addr);
++      /* ep already opened */
++      if ((hpriv->eps[ep_index].datafd > 0) &&
++          (hpriv->eps[ep_index].statfd > 0)) {
++              usbi_dbg(HANDLE_CTX(hdl),
++                  "ep 0x%02x already opened, return success", ep_addr);
++
++              return (0);
++      }
++
++      if (illumos_find_interface(hdl, ep_addr, &ifc) < 0) {
++              usbi_dbg(HANDLE_CTX(hdl),
++                  "can't find interface for endpoint 0x%02x", ep_addr);
++              return (EACCES);
++      }
++
++      /* create filename */
++      if (hpriv->config_index > 0) {
++              (void) snprintf(cfg_num, sizeof(cfg_num), "cfg%d",
++                  hpriv->config_index + 1);
++      } else {
++              bzero(cfg_num, sizeof(cfg_num));
++      }
++
++      if (hpriv->altsetting[ifc] > 0) {
++              (void) snprintf(alt_num, sizeof(alt_num), ".%d",
++                  hpriv->altsetting[ifc]);
++      } else {
++              bzero(alt_num, sizeof(alt_num));
++      }
++
++      if ((e = snprintf(filename, sizeof (filename), "%s/%sif%d%s%s%d",
++          hpriv->dpriv->ugenpath, cfg_num, ifc, alt_num,
++          (ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? "in" :
++          "out", (ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK))) < 0 ||
++          e >= (int)sizeof (filename) ||
++          (e = snprintf(statfilename, sizeof (statfilename), "%sstat",
++          filename)) < 0 || e >= (int)sizeof (statfilename)) {
++              usbi_dbg(HANDLE_CTX(hdl),
++                  "path buffer overflow for endpoint 0x%02x", ep_addr);
++              return (EINVAL);
++      }
++
++      /*
++       * In case configuration has been switched, the xfer endpoint needs
++       * to be opened before the status endpoint, due to a ugen issue.
++       * However, to enable the one transfer mode for an Interrupt-In pipe,
++       * the status endpoint needs to be opened before the xfer endpoint.
++       * So, open the xfer mode first and close it immediately
++       * as a workaround. This will handle the configuration switch.
++       * Then, open the status endpoint.  If for an Interrupt-in pipe,
++       * write the USB_EP_INTR_ONE_XFER control to the status endpoint
++       * to enable the one transfer mode.  Then, re-open the xfer mode.
++       */
++      if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
++              mode = O_RDWR;
++      } else if (ep_addr & LIBUSB_ENDPOINT_IN) {
++              mode = O_RDONLY;
++      } else {
++              mode = O_WRONLY;
++      }
++      /* Open the xfer endpoint first */
++      if ((fd = open(filename, mode)) == -1) {
++              usbi_dbg(HANDLE_CTX(hdl), "can't open %s: errno %d (%s)",
++                  filename, errno, strerror(errno));
++              return (errno);
++      }
++      /* And immediately close the xfer endpoint */
++      (void) close(fd);
++
++      /*
++       * Open the status endpoint.
++       * If for an Interrupt-IN pipe, need to enable the one transfer mode
++       * by writing USB_EP_INTR_ONE_XFER control to the status endpoint
++       * before opening the xfer endpoint
++       */
++      if ((ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) &&
++          (ep_addr & LIBUSB_ENDPOINT_IN)) {
++              char control = USB_EP_INTR_ONE_XFER;
++              ssize_t count;
++
++              /* Open the status endpoint with RDWR */
++              if ((fdstat = open(statfilename, O_RDWR)) == -1) {
++                      usbi_dbg(HANDLE_CTX(hdl),
++                          "can't open %s RDWR: errno %d (%s)",
++                          statfilename, errno, strerror(errno));
++                      return (errno);
++              } else {
++                      count = write(fdstat, &control, sizeof(control));
++                      if (count != 1) {
++                              /* this should have worked */
++                              usbi_dbg(HANDLE_CTX(hdl),
++                                  "can't write to %s: errno %d (%s)",
++                                  statfilename, errno, strerror(errno));
++                              (void) close(fdstat);
++                              return (errno);
++                      }
++              }
++      } else {
++              if ((fdstat = open(statfilename, O_RDONLY)) == -1) {
++                      usbi_dbg(HANDLE_CTX(hdl),
++                          "can't open %s: errno %d (%s)", statfilename, errno,
++                          strerror(errno));
++                      return (errno);
++              }
++      }
++
++      /* Re-open the xfer endpoint */
++      if ((fd = open(filename, mode)) == -1) {
++              usbi_dbg(HANDLE_CTX(hdl), "can't open %s: errno %d (%s)",
++                  filename, errno, strerror(errno));
++              (void) close(fdstat);
++              return (errno);
++      }
++
++      hpriv->eps[ep_index].datafd = fd;
++      hpriv->eps[ep_index].statfd = fdstat;
++      usbi_dbg(HANDLE_CTX(hdl), "ep=0x%02x datafd=%d, statfd=%d", ep_addr,
++          fd, fdstat);
++      return (0);
++}
++
++int
++illumos_open(struct libusb_device_handle *handle)
++{
++      illumos_dev_handle_priv_t *hpriv;
++      illumos_dev_priv_t *dpriv;
++      int i;
++      int ret;
++
++      hpriv = usbi_get_device_handle_priv(handle);
++      dpriv = usbi_get_device_priv(handle->dev);
++      hpriv->dpriv = dpriv;
++
++      /* set all file descriptors to "closed" */
++      for (i = 0; i < USB_MAXENDPOINTS; i++) {
++              hpriv->eps[i].datafd = -1;
++              hpriv->eps[i].statfd = -1;
++      }
++
++      if (illumos_kernel_driver_active(handle, 0)) {
++              /* pretend we can open the device */
++              return (LIBUSB_SUCCESS);
++      }
++
++      if ((ret = illumos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) {
++              usbi_dbg(HANDLE_CTX(handle), "fail: %d", ret);
++              return (ret);
++      }
++
++      return (LIBUSB_SUCCESS);
++}
++
++void
++illumos_close(struct libusb_device_handle *handle)
++{
++      illumos_dev_handle_priv_t *hpriv;
++
++      usbi_dbg(HANDLE_CTX(handle), " ");
++
++      hpriv = usbi_get_device_handle_priv(handle);
++
++      illumos_usb_close_all_eps(hpriv);
++      illumos_usb_close_ep0(hpriv);
++}
++
++int
++illumos_get_active_config_descriptor(struct libusb_device *dev,
++    void *buf, size_t len)
++{
++      illumos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
++      struct libusb_config_descriptor *cfg;
++      int proplen;
++      di_node_t node;
++      uint8_t *rdata;
++
++      /*
++       * Keep raw configuration descriptors updated, in case config
++       * has ever been changed through setCfg.
++       */
++      if ((node = di_init(dpriv->phypath, DINFOCPYALL)) == DI_NODE_NIL) {
++              usbi_dbg(DEVICE_CTX(dev), "di_int() failed: errno %d (%s)",
++                  errno, strerror(errno));
++              return (LIBUSB_ERROR_IO);
++      }
++      proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
++          "usb-raw-cfg-descriptors", &rdata);
++      if (proplen <= 0) {
++              usbi_dbg(DEVICE_CTX(dev), "can't find raw config descriptors");
++              return (LIBUSB_ERROR_IO);
++      }
++      dpriv->raw_cfgdescr = realloc(dpriv->raw_cfgdescr, proplen);
++      if (dpriv->raw_cfgdescr == NULL) {
++              return (LIBUSB_ERROR_NO_MEM);
++      } else {
++              bcopy(rdata, dpriv->raw_cfgdescr, proplen);
++              dpriv->cfgvalue = ((struct libusb_config_descriptor *)
++                  rdata)->bConfigurationValue;
++      }
++      di_fini(node);
++
++      cfg = (struct libusb_config_descriptor *)dpriv->raw_cfgdescr;
++      len = MIN(len, libusb_le16_to_cpu(cfg->wTotalLength));
++      memcpy(buf, dpriv->raw_cfgdescr, len);
++      usbi_dbg(DEVICE_CTX(dev), "path:%s len %zu", dpriv->phypath, len);
++
++      return (len);
++}
++
++int
++illumos_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
++    void *buf, size_t len)
++{
++      UNUSED(idx);
++      /* XXX */
++      return (illumos_get_active_config_descriptor(dev, buf, len));
++}
++
++int
++illumos_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
++{
++      illumos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
++
++      *config = dpriv->cfgvalue;
++
++      usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %u", *config);
++
++      return (LIBUSB_SUCCESS);
++}
++
++int
++illumos_set_configuration(struct libusb_device_handle *handle, int config)
++{
++      illumos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
++      illumos_dev_handle_priv_t *hpriv;
++
++      usbi_dbg(HANDLE_CTX(handle), "bConfigurationValue %d", config);
++      hpriv = usbi_get_device_handle_priv(handle);
++
++      if (dpriv->ugenpath == NULL)
++              return (LIBUSB_ERROR_NOT_SUPPORTED);
++
++      if (config < 1)
++              return (LIBUSB_ERROR_NOT_SUPPORTED);
++
++      dpriv->cfgvalue = config;
++      hpriv->config_index = config - 1;
++
++      return (LIBUSB_SUCCESS);
++}
++
++int
++illumos_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
++{
++      UNUSED(handle);
++
++      usbi_dbg(HANDLE_CTX(handle), "iface %u", iface);
++
++      return (LIBUSB_SUCCESS);
++}
++
++int
++illumos_release_interface(struct libusb_device_handle *handle, uint8_t iface)
++{
++      illumos_dev_handle_priv_t *hpriv = usbi_get_device_handle_priv(handle);
++
++      usbi_dbg(HANDLE_CTX(handle), "iface %u", iface);
++
++      /* XXX: can we release it? */
++      hpriv->altsetting[iface] = 0;
++
++      return (LIBUSB_SUCCESS);
++}
++
++int
++illumos_set_interface_altsetting(struct libusb_device_handle *handle,
++    uint8_t iface, uint8_t altsetting)
++{
++      illumos_dev_priv_t *dpriv = usbi_get_device_priv(handle->dev);
++      illumos_dev_handle_priv_t *hpriv = usbi_get_device_handle_priv(handle);
++
++      usbi_dbg(HANDLE_CTX(handle), "iface %u, setting %u", iface, altsetting);
++
++      if (dpriv->ugenpath == NULL)
++              return (LIBUSB_ERROR_NOT_FOUND);
++
++      /* XXX: can we switch altsetting? */
++      hpriv->altsetting[iface] = altsetting;
++
++      return (LIBUSB_SUCCESS);
++}
++
++static void
++usb_dump_data(const void *data, size_t size)
++{
++      const uint8_t *p = data;
++      size_t i;
++
++      if (getenv("LIBUSB_DEBUG") == NULL) {
++              return;
++      }
++
++      (void) fprintf(stderr, "data dump:");
++      for (i = 0; i < size; i++) {
++              if (i % 16 == 0) {
++                      (void) fprintf(stderr, "\n%08zx\t", i);
++              }
++              (void) fprintf(stderr, "%02x ", p[i]);
++      }
++      (void) fprintf(stderr, "\n");
++}
++
++static void
++illumos_async_callback(union sigval arg)
++{
++      illumos_xfer_priv_t *tpriv = arg.sival_ptr;
++      struct libusb_transfer *xfer = tpriv->transfer;
++      struct usbi_transfer *ixfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer);
++      struct aiocb *aiocb = &tpriv->aiocb;
++      illumos_dev_handle_priv_t *hpriv;
++      uint8_t ep;
++      libusb_device_handle *dev_handle;
++
++      if ((dev_handle = xfer->dev_handle) == NULL) {
++              /* libusb can forcibly interrupt transfer in do_close() */
++              return;
++      }
++
++      if (aio_error(aiocb) != ECANCELED) {
++              hpriv = usbi_get_device_handle_priv(dev_handle);
++              ep = illumos_usb_ep_index(xfer->endpoint);
++
++              /*
++               * Fetch the status for the last command on this endpoint from
++               * ugen(7D) so that we can translate and report it later.
++               */
++              tpriv->ugen_status = illumos_usb_get_status(TRANSFER_CTX(xfer),
++                  hpriv->eps[ep].statfd);
++      } else {
++              tpriv->ugen_status = USB_LC_STAT_NOERROR;
++      }
++
++      usbi_signal_transfer_completion(ixfer);
++}
++
++static int
++illumos_do_async_io(struct libusb_transfer *transfer)
++{
++      int ret = -1;
++      struct aiocb *aiocb;
++      illumos_dev_handle_priv_t *hpriv;
++      uint8_t ep;
++      illumos_xfer_priv_t *tpriv;
++
++      usbi_dbg(TRANSFER_CTX(transfer), " ");
++
++      tpriv = usbi_get_transfer_priv(
++          LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
++      hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
++      ep = illumos_usb_ep_index(transfer->endpoint);
++
++      tpriv->transfer = transfer;
++      aiocb = &tpriv->aiocb;
++      bzero(aiocb, sizeof(*aiocb));
++      aiocb->aio_fildes = hpriv->eps[ep].datafd;
++      aiocb->aio_buf = transfer->buffer;
++      aiocb->aio_nbytes = transfer->length;
++      aiocb->aio_lio_opcode =
++          ((transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) ==
++          LIBUSB_ENDPOINT_IN) ? LIO_READ:LIO_WRITE;
++      aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
++      aiocb->aio_sigevent.sigev_value.sival_ptr = tpriv;
++      aiocb->aio_sigevent.sigev_notify_function = illumos_async_callback;
++
++      if (aiocb->aio_lio_opcode == LIO_READ) {
++              ret = aio_read(aiocb);
++      } else {
++              ret = aio_write(aiocb);
++      }
++
++      return (ret);
++}
++
++/* return the number of bytes read/written */
++static ssize_t
++usb_do_io(struct libusb_context *ctx, int fd, int stat_fd, void *data,
++    size_t size, int flag, int *status)
++{
++      int error;
++      ssize_t ret = -1;
++
++      usbi_dbg(ctx, "usb_do_io(): datafd=%d statfd=%d size=0x%zx flag=%s",
++          fd, stat_fd, size, flag? "WRITE":"READ");
++
++      switch (flag) {
++      case READ:
++              errno = 0;
++              ret = read(fd, data, size);
++              usb_dump_data(data, size);
++              break;
++      case WRITE:
++              usb_dump_data(data, size);
++              errno = 0;
++              ret = write(fd, data, size);
++              break;
++      }
++
++      usbi_dbg(ctx, "usb_do_io(): amount=%zd", ret);
++
++      if (ret < 0) {
++              int save_errno = errno;
++
++              usbi_dbg(ctx, "TID=%x io %s errno %d (%s)", pthread_self(),
++                  flag?"WRITE":"READ", errno, strerror(errno));
++
++              /* illumos_usb_get_status will do a read and overwrite errno */
++              error = illumos_usb_get_status(ctx, stat_fd);
++              usbi_dbg(ctx, "io status=%d errno %d (%s)", error,
++                      save_errno, strerror(save_errno));
++
++              if (status) {
++                      *status = save_errno;
++              }
++
++              return (save_errno);
++
++      } else if (status) {
++              *status = 0;
++      }
++
++      return (ret);
++}
++
++static int
++solaris_submit_ctrl_on_default(struct libusb_transfer *transfer)
++{
++      ssize_t ret = -1, setup_ret;
++      int status;
++      illumos_dev_handle_priv_t *hpriv;
++      struct libusb_device_handle *hdl = transfer->dev_handle;
++      uint16_t wLength;
++      uint8_t *data = transfer->buffer;
++
++      hpriv = usbi_get_device_handle_priv(hdl);
++      wLength = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
++
++      if (hpriv->eps[0].datafd == -1) {
++              usbi_dbg(TRANSFER_CTX(transfer), "ep0 not opened");
++
++              return (LIBUSB_ERROR_NOT_FOUND);
++      }
++
++      if ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) {
++              usbi_dbg(TRANSFER_CTX(transfer), "IN request");
++              ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd,
++                  hpriv->eps[0].statfd, data, LIBUSB_CONTROL_SETUP_SIZE,
++                  WRITE, &status);
++      } else {
++              usbi_dbg(TRANSFER_CTX(transfer), "OUT request");
++              ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd,
++                  hpriv->eps[0].statfd, transfer->buffer, transfer->length,
++                  WRITE, (int *)&transfer->status);
++      }
++
++      setup_ret = ret;
++      if (ret < (ssize_t)LIBUSB_CONTROL_SETUP_SIZE) {
++              usbi_dbg(TRANSFER_CTX(transfer),
++                  "error sending control msg: %zd", ret);
++              return (LIBUSB_ERROR_IO);
++      }
++
++      ret = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
++
++      /* Read the remaining bytes for IN request */
++      if ((wLength) && ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) ==
++          LIBUSB_ENDPOINT_IN)) {
++              usbi_dbg(TRANSFER_CTX(transfer), "DATA: %d",
++                  transfer->length - (int)setup_ret);
++              ret = usb_do_io(TRANSFER_CTX(transfer), hpriv->eps[0].datafd,
++                  hpriv->eps[0].statfd,
++                  transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
++                  wLength, READ, (int *)&transfer->status);
++      }
++
++      if (ret >= 0) {
++              LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->transferred = ret;
++      }
++      usbi_dbg(TRANSFER_CTX(transfer), "Done: ctrl data bytes %zd", ret);
++
++      /*
++       * Sync transfer handling.
++       * We should release transfer lock here and later get it back
++       * as usbi_handle_transfer_completion() takes its own transfer lock.
++       */
++      usbi_mutex_unlock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
++      ret = usbi_handle_transfer_completion(
++          LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer), transfer->status);
++      usbi_mutex_lock(&LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->lock);
++
++      return (ret);
++}
++
++int
++illumos_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
++{
++      int ret;
++
++      usbi_dbg(HANDLE_CTX(handle), "endpoint=0x%02x", endpoint);
++
++      ret = libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT |
++          LIBUSB_RECIPIENT_ENDPOINT | LIBUSB_REQUEST_TYPE_STANDARD,
++          LIBUSB_REQUEST_CLEAR_FEATURE, 0, endpoint, NULL, 0, 1000);
++
++      usbi_dbg(HANDLE_CTX(handle), "ret=%d", ret);
++
++      return (ret);
++}
++
++void
++illumos_destroy_device(struct libusb_device *dev)
++{
++      illumos_dev_priv_t *dpriv = usbi_get_device_priv(dev);
++
++      usbi_dbg(DEVICE_CTX(dev), "destroy everything");
++      free(dpriv->raw_cfgdescr);
++      free(dpriv->ugenpath);
++      free(dpriv->phypath);
++}
++
++int
++illumos_submit_transfer(struct usbi_transfer *itransfer)
++{
++      struct libusb_transfer *transfer;
++      struct libusb_device_handle *hdl;
++      int err = 0;
++
++      transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
++      hdl = transfer->dev_handle;
++
++      err = illumos_check_device_and_status_open(hdl,
++          transfer->endpoint, transfer->type);
++      if (err != 0) {
++              return (_errno_to_libusb(err));
++      }
++
++      switch (transfer->type) {
++      case LIBUSB_TRANSFER_TYPE_CONTROL:
++              /* sync transfer */
++              usbi_dbg(ITRANSFER_CTX(itransfer),
++                  "CTRL transfer: %d", transfer->length);
++              err = solaris_submit_ctrl_on_default(transfer);
++              break;
++
++      case LIBUSB_TRANSFER_TYPE_BULK:
++              usbi_dbg(ITRANSFER_CTX(itransfer),
++                  "BULK transfer: %d", transfer->length);
++              err = illumos_do_async_io(transfer);
++              break;
++
++      case LIBUSB_TRANSFER_TYPE_INTERRUPT:
++              usbi_dbg(ITRANSFER_CTX(itransfer),
++                  "INTR transfer: %d", transfer->length);
++              err = illumos_do_async_io(transfer);
++              break;
++
++      /* Isochronous/Stream is not supported */
++      case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
++              usbi_dbg(ITRANSFER_CTX(itransfer),
++                  "ISOC transfer: %d", transfer->length);
++              err = LIBUSB_ERROR_NOT_SUPPORTED;
++              break;
++
++      case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
++              usbi_dbg(ITRANSFER_CTX(itransfer),
++                  "BULK STREAM transfer: %d", transfer->length);
++              err = LIBUSB_ERROR_NOT_SUPPORTED;
++              break;
++      }
++
++      return (err);
++}
++
++int
++illumos_cancel_transfer(struct usbi_transfer *itransfer)
++{
++      illumos_xfer_priv_t *tpriv;
++      illumos_dev_handle_priv_t *hpriv;
++      struct libusb_transfer *transfer;
++      struct aiocb *aiocb;
++      uint8_t ep;
++      int ret;
++
++      tpriv = usbi_get_transfer_priv(itransfer);
++      aiocb = &tpriv->aiocb;
++      transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
++      hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
++      ep = illumos_usb_ep_index(transfer->endpoint);
++
++      ret = aio_cancel(hpriv->eps[ep].datafd, aiocb);
++
++      usbi_dbg(ITRANSFER_CTX(itransfer), "aio->fd=%d fd=%d ret = %d, %s",
++          aiocb->aio_fildes, hpriv->eps[ep].datafd, ret,
++          (ret == AIO_CANCELED) ? "AIO canceled" : strerror(errno));
++
++      if (ret != AIO_CANCELED) {
++              ret = _errno_to_libusb(errno);
++      } else {
++              ret = LIBUSB_SUCCESS;
++      }
++
++      return (ret);
++}
++
++int
++illumos_handle_transfer_completion(struct usbi_transfer *ixfer)
++{
++      illumos_xfer_priv_t *tpriv = usbi_get_transfer_priv(ixfer);
++      struct libusb_transfer *xfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(ixfer);
++      struct aiocb *aiocb = &tpriv->aiocb;
++      int ret;
++      enum libusb_transfer_status status;
++
++      if ((ret = aio_error(aiocb)) == 0) {
++              /*
++               * The command completed.  Update the transferred length:
++               */
++              xfer->actual_length = ixfer->transferred = aio_return(aiocb);
++
++              usbi_dbg(TRANSFER_CTX(xfer), "ret=%d, len=%d, actual_len=%d",
++                  ret, xfer->length, xfer->actual_length);
++              usb_dump_data(xfer->buffer, xfer->actual_length);
++
++              status = LIBUSB_TRANSFER_COMPLETED;
++
++      } else if (ret == ECANCELED) {
++              /*
++               * We used aio_cancel() to cancel this; report cancellation to
++               * libusb so that timeouts can be handled correctly.
++               */
++              usbi_dbg(TRANSFER_CTX(xfer),
++                  "aio cancelled, len=%d, actual_len=%d",
++                  xfer->length, xfer->actual_length);
++
++              status = LIBUSB_TRANSFER_CANCELLED;
++
++      } else {
++              /*
++               * Convert the ugen(7D)-level status to a libusb-level status:
++               */
++              switch (tpriv->ugen_status) {
++              case USB_LC_STAT_TIMEOUT:
++                      status = LIBUSB_TRANSFER_TIMED_OUT;
++                      break;
++              case USB_LC_STAT_STALL:
++                      status = LIBUSB_TRANSFER_STALL;
++                      break;
++              case USB_LC_STAT_DISCONNECTED:
++                      status = LIBUSB_TRANSFER_NO_DEVICE;
++                      break;
++              case USB_LC_STAT_INTERRUPTED:
++                      status = LIBUSB_TRANSFER_CANCELLED;
++                      break;
++              case USB_LC_STAT_BUFFER_OVERRUN:
++                      /*
++                       * XXX Is this right? (*_DATA_OVERRUN?)
++                       */
++                      status = LIBUSB_TRANSFER_OVERFLOW;
++                      break;
++              default:
++                      /*
++                       * Not every ugen(7D) status maps to a specific
++                       * libusb-level failure case.  Nonetheless, we must
++                       * report all failures as failures:
++                       */
++                      status = LIBUSB_TRANSFER_ERROR;
++                      break;
++              }
++      }
++
++      if (status == LIBUSB_TRANSFER_CANCELLED) {
++              return (usbi_handle_transfer_cancellation(ixfer));
++      } else {
++              return (usbi_handle_transfer_completion(ixfer, status));
++      }
++}
++
++int
++_errno_to_libusb(int err)
++{
++      usbi_dbg(NULL, "error: %s (%d)", strerror(err), err);
++
++      switch (err) {
++      case EIO:
++              return (LIBUSB_ERROR_IO);
++      case EACCES:
++              return (LIBUSB_ERROR_ACCESS);
++      case ENOENT:
++              return (LIBUSB_ERROR_NO_DEVICE);
++      case ENOMEM:
++              return (LIBUSB_ERROR_NO_MEM);
++      case ETIMEDOUT:
++              return (LIBUSB_ERROR_TIMEOUT);
++      }
++
++      return (LIBUSB_ERROR_OTHER);
++}
++
++/*
++ * illumos_usb_get_status:
++ *    gets status of endpoint
++ *
++ * Returns: ugen's last cmd status
++ */
++static int
++illumos_usb_get_status(struct libusb_context *ctx, int fd)
++{
++      int status;
++      ssize_t ret;
++
++      usbi_dbg(ctx, "illumos_usb_get_status(): fd=%d", fd);
++
++      ret = read(fd, &status, sizeof(status));
++      if (ret == sizeof(status)) {
++              switch (status) {
++              case USB_LC_STAT_NOERROR:
++                      usbi_dbg(ctx, "No Error");
++                      break;
++              case USB_LC_STAT_CRC:
++                      usbi_dbg(ctx, "CRC Timeout Detected\n");
++                      break;
++              case USB_LC_STAT_BITSTUFFING:
++                      usbi_dbg(ctx, "Bit Stuffing Violation\n");
++                      break;
++              case USB_LC_STAT_DATA_TOGGLE_MM:
++                      usbi_dbg(ctx, "Data Toggle Mismatch\n");
++                      break;
++              case USB_LC_STAT_STALL:
++                      usbi_dbg(ctx, "End Point Stalled\n");
++                      break;
++              case USB_LC_STAT_DEV_NOT_RESP:
++                      usbi_dbg(ctx, "Device is Not Responding\n");
++                      break;
++              case USB_LC_STAT_PID_CHECKFAILURE:
++                      usbi_dbg(ctx, "PID Check Failure\n");
++                      break;
++              case USB_LC_STAT_UNEXP_PID:
++                      usbi_dbg(ctx, "Unexpected PID\n");
++                      break;
++              case USB_LC_STAT_DATA_OVERRUN:
++                      usbi_dbg(ctx, "Data Exceeded Size\n");
++                      break;
++              case USB_LC_STAT_DATA_UNDERRUN:
++                      usbi_dbg(ctx, "Less data received\n");
++                      break;
++              case USB_LC_STAT_BUFFER_OVERRUN:
++                      usbi_dbg(ctx, "Buffer Size Exceeded\n");
++                      break;
++              case USB_LC_STAT_BUFFER_UNDERRUN:
++                      usbi_dbg(ctx, "Buffer Underrun\n");
++                      break;
++              case USB_LC_STAT_TIMEOUT:
++                      usbi_dbg(ctx, "Command Timed Out\n");
++                      break;
++              case USB_LC_STAT_NOT_ACCESSED:
++                      usbi_dbg(ctx, "Not Accessed by h/w\n");
++                      break;
++              case USB_LC_STAT_UNSPECIFIED_ERR:
++                      usbi_dbg(ctx, "Unspecified Error\n");
++                      break;
++              case USB_LC_STAT_NO_BANDWIDTH:
++                      usbi_dbg(ctx, "No Bandwidth\n");
++                      break;
++              case USB_LC_STAT_HW_ERR:
++                      usbi_dbg(ctx, "Host Controller h/w Error\n");
++                      break;
++              case USB_LC_STAT_SUSPENDED:
++                      usbi_dbg(ctx, "Device was Suspended\n");
++                      break;
++              case USB_LC_STAT_DISCONNECTED:
++                      usbi_dbg(ctx, "Device was Disconnected\n");
++                      break;
++              case USB_LC_STAT_INTR_BUF_FULL:
++                      usbi_dbg(ctx, "Interrupt buffer was full\n");
++                      break;
++              case USB_LC_STAT_INVALID_REQ:
++                      usbi_dbg(ctx, "Request was Invalid\n");
++                      break;
++              case USB_LC_STAT_INTERRUPTED:
++                      usbi_dbg(ctx, "Request was Interrupted\n");
++                      break;
++              case USB_LC_STAT_NO_RESOURCES:
++                      usbi_dbg(ctx, "No resources available for "
++                          "request\n");
++                      break;
++              case USB_LC_STAT_INTR_POLLING_FAILED:
++                      usbi_dbg(ctx, "Failed to Restart Poll");
++                      break;
++              default:
++                      usbi_dbg(ctx, "Error Not Determined %d\n",
++                          status);
++                      break;
++              }
++      } else {
++              usbi_dbg(ctx, "read stat error: %s",strerror(errno));
++              status = -1;
++      }
++
++      return (status);
++}
++
++const struct usbi_os_backend usbi_backend = {
++      .name = "illumos",
++      .get_device_list = illumos_get_device_list,
++      .open = illumos_open,
++      .close = illumos_close,
++
++      .get_active_config_descriptor = illumos_get_active_config_descriptor,
++      .get_config_descriptor = illumos_get_config_descriptor,
++
++      .get_configuration = illumos_get_configuration,
++      .set_configuration = illumos_set_configuration,
++
++      .claim_interface = illumos_claim_interface,
++      .release_interface = illumos_release_interface,
++
++      .set_interface_altsetting = illumos_set_interface_altsetting,
++      .clear_halt = illumos_clear_halt,
++      .destroy_device = illumos_destroy_device,
++
++      .submit_transfer = illumos_submit_transfer,
++      .cancel_transfer = illumos_cancel_transfer,
++
++      .handle_transfer_completion = illumos_handle_transfer_completion,
++
++      .device_priv_size = sizeof(illumos_dev_priv_t),
++      .device_handle_priv_size = sizeof(illumos_dev_handle_priv_t),
++
++      .kernel_driver_active = illumos_kernel_driver_active,
++      .detach_kernel_driver = illumos_detach_kernel_driver,
++      .attach_kernel_driver = illumos_attach_kernel_driver,
++      .transfer_priv_size = sizeof(illumos_xfer_priv_t),
++};
Index: pkgsrc/devel/libusb1/patches/patch-libusb_os_illumos__usb.h
diff -u /dev/null pkgsrc/devel/libusb1/patches/patch-libusb_os_illumos__usb.h:1.1
--- /dev/null   Fri Feb 16 08:13:13 2024
+++ pkgsrc/devel/libusb1/patches/patch-libusb_os_illumos__usb.h Fri Feb 16 08:13:13 2024
@@ -0,0 +1,93 @@
+$NetBSD: patch-libusb_os_illumos__usb.h,v 1.1 2024/02/16 08:13:13 nia Exp $
+
+illumos support; via OmniOS.
+
+From 57b0bd0b3624eea8f7a56cb477649f2f35b0bab7 Mon Sep 17 00:00:00 2001
+From: "Joshua M. Clulow" <josh%sysmgr.org@localhost>
+Date: Mon, 27 Dec 2021 16:08:38 -0800
+Subject: [PATCH] illumos: split off from Solaris backend
+
+--- libusb/os/illumos_usb.h.orig       2024-02-16 08:09:37.474490330 +0000
++++ libusb/os/illumos_usb.h
+@@ -0,0 +1,81 @@
++/*
++ *
++ * Copyright (c) 2016, Oracle and/or its affiliates.
++ * Copyright 2021 Oxide Computer Company
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef       LIBUSB_ILLUMOS_H
++#define       LIBUSB_ILLUMOS_H
++
++#include <libdevinfo.h>
++#include <pthread.h>
++#include "libusbi.h"
++
++#define       READ    0
++#define       WRITE   1
++
++typedef struct illumos_device_priv {
++      uint8_t cfgvalue;               /* active config value */
++      uint8_t *raw_cfgdescr;          /* active config descriptor */
++      char    *ugenpath;              /* name of the ugen(4) node */
++      char    *phypath;               /* physical path */
++} illumos_dev_priv_t;
++
++typedef       struct endpoint {
++      int datafd;     /* data file */
++      int statfd;     /* state file */
++} illumos_ep_priv_t;
++
++typedef struct illumos_device_handle_priv {
++      uint8_t                 altsetting[USB_MAXINTERFACES];  /* a interface's alt */
++      uint8_t                 config_index;
++      illumos_ep_priv_t               eps[USB_MAXENDPOINTS];
++      illumos_dev_priv_t      *dpriv; /* device private */
++} illumos_dev_handle_priv_t;
++
++typedef       struct illumos_transfer_priv {
++      struct aiocb            aiocb;
++      struct libusb_transfer  *transfer;
++      int                     ugen_status;
++} illumos_xfer_priv_t;
++
++struct node_args {
++      struct libusb_context   *ctx;
++      struct discovered_devs  **discdevs;
++      const char              *last_ugenpath;
++      di_devlink_handle_t     dlink_hdl;
++};
++
++struct devlink_cbarg {
++      struct node_args        *nargs; /* di node walk arguments */
++      di_node_t               myself; /* the di node */
++      di_minor_t              minor;
++};
++
++typedef struct walk_link {
++      char *path;
++      int len;
++      char **linkpp;
++} walk_link_t;
++
++/* AIO callback args */
++struct aio_callback_args{
++      struct libusb_transfer *transfer;
++      struct aiocb aiocb;
++};
++
++#endif /* LIBUSB_ILLUMOS_H */



Home | Main Index | Thread Index | Old Index