From 362235e28d24f74ae502c8f8dca9cc9098de15a5 Mon Sep 17 00:00:00 2001
From: nowrap <nowrap@gmx.net>
Date: Sun, 29 Mar 2026 21:50:55 +0200
Subject: [PATCH 1/2] Migrate from libusb-0.1 to libusb-1.0

libusb-0.1 uses the legacy USBDEVFS_CLAIMINTERFACE ioctl which fails
with ENOENT on modern kernels (Linux 6.x / Debian 13). Migrate to
libusb-1.0 which uses the current kernel USB API.

API changes:
- configure.ac: detect libusb-1.0 via pkg-config instead of libusb-0.1
- Replace usb_dev_handle with libusb_device_handle throughout
- Replace struct usb_device with libusb_device throughout
- Device enumeration: libusb_get_device_list + libusb_ref_device
  instead of usb_find_busses/usb_find_devices/usb_busses iteration
- USB control: libusb_control_transfer instead of usb_control_msg
- Device open: libusb_open (returns error code via int, handle via pointer)
- Error reporting: libusb_strerror(ret) instead of usb_strerror()
- Device info: libusb_get_bus_number/libusb_get_device_address
  instead of dev->bus->dirname/dev->filename
- Cleanup: libusb_unref_device + libusb_exit at program exit

get_handle() changes:
- libusb_detach_kernel_driver before claiming the interface
- libusb_set_configuration + libusb_claim_interface +
  libusb_set_interface_alt_setting (no auto-detach)

The Gembird Silver Shield PM (Cypress CY7C63001A) sends a truncated
configuration descriptor on the first USB enumeration, causing the
kernel to register 0 interfaces. A USB reset in main() before the
device scan forces a re-enumeration with the correct descriptor.

Also add missing #include <stdlib.h> in process.c and socket.c
(was transitively included by old usb.h).
Also add missing #include <unistd.h> in main.c.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
 configure.ac    |   2 +-
 src/main.c      | 155 ++++++++++++++++++++++++++++++++----------------
 src/process.c   |  21 +++----
 src/sispm_ctl.c | 135 ++++++++++++++++++++++-------------------
 src/sispm_ctl.h |  26 ++++----
 src/socket.c    |   5 +-
 src/socket.h    |   4 +-
 7 files changed, 208 insertions(+), 140 deletions(-)

diff --git a/configure.ac b/configure.ac
index 381ad88..fb64375 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,7 +47,7 @@ AS_HELP_STRING([--with-bindaddr=IP], [bind listening socket to IP]),
 AC_SUBST(BINDADDR)
 
 dnl check for libusb
-PKG_CHECK_MODULES(LIBUSB, libusb >= 0.1.11)
+PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0.16)
 CFLAGS="$CFLAGS $LIBUSB_CFLAGS"
 LIBS="$LIBS $LIBUSB_LIBS"
 
diff --git a/src/main.c b/src/main.c
index faa46a6..40220ec 100644
--- a/src/main.c
+++ b/src/main.c
@@ -35,7 +35,8 @@
 #include <signal.h>
 #include <syslog.h>
 #include <time.h>
-#include <usb.h>
+#include <unistd.h>
+#include <libusb-1.0/libusb.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -187,7 +188,7 @@ static void print_usage(char *name)
 }
 
 static void parse_command_line(int argc, char *argv[], int count,
-                               struct usb_device *dev[], char *usbdevsn[])
+                               libusb_device *dev[], char *usbdevsn[])
 {
   int numeric = 0;
   int c;
@@ -196,8 +197,8 @@ static void parse_command_line(int argc, char *argv[], int count,
   int from = 1, upto = 4;
   int status;
   int devnum = 0;
-  usb_dev_handle *udev = NULL;
-  usb_dev_handle *sudev; //scan device
+  libusb_device_handle *udev = NULL;
+  libusb_device_handle *sudev; //scan device
   unsigned int id=0; //product id of current device
   char *onoff[] = {"off", "on", "0", "1"};
 #ifndef WEBLESS
@@ -223,7 +224,7 @@ static void parse_command_line(int argc, char *argv[], int count,
       default:
         fprintf(stderr, "No GEMBIRD SiS-PM found. Check USB connections, please!\n");
         if (udev != NULL) {
-          usb_close(udev);
+          libusb_close(udev);
           udev = NULL;
         }
         exit(1);
@@ -251,12 +252,14 @@ static void parse_command_line(int argc, char *argv[], int count,
       if(udev == NULL) {
         udev = get_handle(dev[devnum]);
         if(udev == NULL) {
-          fprintf(stderr, "No access to Gembird #%d USB device %s\n",
-                  devnum, dev[devnum]->filename );
+          fprintf(stderr, "No access to Gembird #%d USB device %03d:%03d\n",
+                  devnum, libusb_get_bus_number(dev[devnum]),
+                  libusb_get_device_address(dev[devnum]));
           exit(1);
         } else if(verbose) {
-          printf("Accessing Gembird #%d USB device %s\n", devnum,
-                 dev[devnum]->filename);
+          printf("Accessing Gembird #%d USB device %03d:%03d\n", devnum,
+                 libusb_get_bus_number(dev[devnum]),
+                 libusb_get_device_address(dev[devnum]));
         }
         id = get_id(dev[devnum]);
       }
@@ -287,11 +290,13 @@ static void parse_command_line(int argc, char *argv[], int count,
       case 's':
         for (status = 0; status < count; ++status) {
           if (numeric == 0)
-            printf("Gembird #%d\nUSB information:  bus %s, device %s\n", status,
-                   dev[status]->bus->dirname, dev[status]->filename);
+            printf("Gembird #%d\nUSB information:  bus %03d, device %03d\n", status,
+                   libusb_get_bus_number(dev[status]),
+                   libusb_get_device_address(dev[status]));
           else
-            printf("%d %s %s\n", status,
-                   dev[status]->bus->dirname, dev[status]->filename);
+            printf("%d %03d %03d\n", status,
+                   libusb_get_bus_number(dev[status]),
+                   libusb_get_device_address(dev[status]));
           id = get_id(dev[status]);
           if ((id == PRODUCT_ID_SISPM) ||
               (id == PRODUCT_ID_SISPM_FLASH_NEW) ||
@@ -307,15 +312,16 @@ static void parse_command_line(int argc, char *argv[], int count,
           sudev = get_handle(dev[status]);
           id = get_id(dev[status]);
           if(sudev == NULL) {
-            fprintf(stderr, "No access to Gembird #%d USB device %s\n",
-                    status, dev[status]->filename );
+            fprintf(stderr, "No access to Gembird #%d USB device %03d:%03d\n",
+                    status, libusb_get_bus_number(dev[status]),
+                    libusb_get_device_address(dev[status]));
             exit(1);
           }
           if (numeric == 0)
             printf("serial number:    %s\n",get_serial(sudev));
           else
             printf("%s\n", get_serial(sudev));
-          usb_close(sudev);
+          libusb_close(sudev);
           printf("\n");
         }
         break;
@@ -323,7 +329,7 @@ static void parse_command_line(int argc, char *argv[], int count,
       // replace previous (first is default) device by selected one
       case 'd': // by id
         if (udev != NULL) {
-          usb_close(udev);
+          libusb_close(udev);
           udev = NULL;
         }
         devnum = atoi(optarg);
@@ -331,7 +337,7 @@ static void parse_command_line(int argc, char *argv[], int count,
           fprintf(stderr, "Invalid number or given device not found.\n"
                   "Terminating\n");
           if (udev != NULL) {
-            usb_close(udev);
+            libusb_close(udev);
             udev = NULL;
           }
           exit(-8);
@@ -343,7 +349,7 @@ static void parse_command_line(int argc, char *argv[], int count,
             fprintf(stderr, "now comparing %s and %s\n", usbdevsn[j], optarg);
           if (strcasecmp(usbdevsn[j], optarg) == 0) {
             if (udev != NULL) {
-              usb_close(udev);
+              libusb_close(udev);
               udev = NULL;
             }
             devnum = j;
@@ -354,7 +360,7 @@ static void parse_command_line(int argc, char *argv[], int count,
           fprintf(stderr, "No device with serial number %s found.\n"
                   "Terminating\n",optarg);
           if (udev != NULL) {
-            usb_close(udev);
+            libusb_close(udev);
             udev = NULL;
           }
           exit(-8);
@@ -362,14 +368,15 @@ static void parse_command_line(int argc, char *argv[], int count,
         break;
       case 'U': // by USB Bus:Device
         for (j=0; j < count; ++j) {
-          char tmp[8194];
-          sprintf(tmp, "%s:%s", dev[j]->bus->dirname, dev[j]->filename);
+          char tmp[16];
+          sprintf(tmp, "%03d:%03d", libusb_get_bus_number(dev[j]),
+                  libusb_get_device_address(dev[j]));
 
           if (debug)
             fprintf(stderr, "now comparing %s and %s\n", tmp, optarg);
           if (strcasecmp(tmp, optarg) == 0) {
             if (udev != NULL) {
-              usb_close(udev);
+              libusb_close(udev);
               udev = NULL;
             }
             devnum = j;
@@ -380,7 +387,7 @@ static void parse_command_line(int argc, char *argv[], int count,
           fprintf(stderr, "No device at USB Bus:Device %s found.\n"
                   "Terminating\n",optarg);
           if (udev != NULL) {
-            usb_close(udev);
+            libusb_close(udev);
             udev = NULL;
           }
           exit(-8);
@@ -595,7 +602,7 @@ static void parse_command_line(int argc, char *argv[], int count,
   } // loop through options
 
   if (udev) {
-    usb_close(udev);
+    libusb_close(udev);
     udev = NULL;
   }
   return;
@@ -604,9 +611,10 @@ static void parse_command_line(int argc, char *argv[], int count,
 
 int main(int argc, char *argv[])
 {
-  struct usb_bus *bus;
-  struct usb_device *dev, *usbdev[MAXGEMBIRD], *usbdevtemp;
+  libusb_device **devlist = NULL;
+  libusb_device *usbdev[MAXGEMBIRD], *usbdevtemp;
   char *usbdevsn[MAXGEMBIRD];
+  ssize_t devcnt;
   int count=0, found = 0, i=1;
 
 #ifndef MSG_NOSIGNAL
@@ -615,9 +623,45 @@ int main(int argc, char *argv[])
 
   memset(usbdev,0,sizeof(usbdev));
 
-  usb_init();
-  usb_find_busses();
-  usb_find_devices();
+  libusb_init(NULL);
+
+  /*
+   * Some Gembird devices (Cypress CY7C63001A) send a truncated
+   * configuration descriptor on the first USB enumeration, causing the
+   * kernel to register 0 interfaces.  A USB reset makes the device send
+   * the full descriptor on re-enumeration.
+   *
+   * We therefore do a first scan just to find and reset these devices,
+   * then re-enumerate so the kernel has correct descriptors.
+   */
+  devcnt = libusb_get_device_list(NULL, &devlist);
+  if (devcnt >= 0) {
+    for (ssize_t j = 0; j < devcnt; ++j) {
+      struct libusb_device_descriptor desc;
+      libusb_device_handle *h;
+      libusb_get_device_descriptor(devlist[j], &desc);
+      if (desc.idVendor == VENDOR_ID
+          && (desc.idProduct == PRODUCT_ID_SISPM ||
+              desc.idProduct == PRODUCT_ID_MSISPM_OLD ||
+              desc.idProduct == PRODUCT_ID_MSISPM_FLASH ||
+              desc.idProduct == PRODUCT_ID_SISPM_FLASH_NEW ||
+              desc.idProduct == PRODUCT_ID_SISPM_EG_PMS2)) {
+        if (libusb_open(devlist[j], &h) == 0) {
+          libusb_reset_device(h);
+          libusb_close(h);
+        }
+      }
+    }
+    libusb_free_device_list(devlist, 1);
+  }
+
+  /* Now re-enumerate — devices have correct descriptors after reset */
+  devcnt = libusb_get_device_list(NULL, &devlist);
+  if (devcnt < 0) {
+    fprintf(stderr, "Failed to get USB device list\n");
+    libusb_exit(NULL);
+    return 1;
+  }
 
   // initialize by setting device pointers to zero
   for (count = 0; count < MAXGEMBIRD; ++count)
@@ -625,32 +669,33 @@ int main(int argc, char *argv[])
   count = 0;
 
   //first search for GEMBIRD (m)SiS-PM devices
-  for (bus = usb_busses; bus; bus = bus->next) {
-    for (dev = bus->devices; dev; dev = dev->next) {
-      if ((dev->descriptor.idVendor == VENDOR_ID)
-          && ((dev->descriptor.idProduct == PRODUCT_ID_SISPM) ||
-              (dev->descriptor.idProduct == PRODUCT_ID_MSISPM_OLD) ||
-              (dev->descriptor.idProduct == PRODUCT_ID_MSISPM_FLASH) ||
-              (dev->descriptor.idProduct == PRODUCT_ID_SISPM_FLASH_NEW) ||
-              (dev->descriptor.idProduct == PRODUCT_ID_SISPM_EG_PMS2))) {
-        usbdev[count] = dev;
-        ++count;
-      }
-      if (count == MAXGEMBIRD) {
-        fprintf(stderr,"%d devices found. Please recompile if you need to "
-                "support more devices!\n",count);
-        goto max_gembird;
-      }
+  for (ssize_t j = 0; j < devcnt; ++j) {
+    struct libusb_device_descriptor desc;
+    libusb_get_device_descriptor(devlist[j], &desc);
+    if ((desc.idVendor == VENDOR_ID)
+        && ((desc.idProduct == PRODUCT_ID_SISPM) ||
+            (desc.idProduct == PRODUCT_ID_MSISPM_OLD) ||
+            (desc.idProduct == PRODUCT_ID_MSISPM_FLASH) ||
+            (desc.idProduct == PRODUCT_ID_SISPM_FLASH_NEW) ||
+            (desc.idProduct == PRODUCT_ID_SISPM_EG_PMS2))) {
+      usbdev[count] = libusb_ref_device(devlist[j]);
+      ++count;
+    }
+    if (count == MAXGEMBIRD) {
+      fprintf(stderr,"%d devices found. Please recompile if you need to "
+              "support more devices!\n",count);
+      goto max_gembird;
     }
   }
 max_gembird:
+  libusb_free_device_list(devlist, 1);
 
   /* bubble sort them first, thnx Ingo Flaschenberger */
   if (count > 1) {
     do {
       found = 0;
       for (i = 1; i < count; ++i) {
-        if (usbdev[i]->devnum < usbdev[i - 1]->devnum) {
+        if (libusb_get_device_address(usbdev[i]) < libusb_get_device_address(usbdev[i - 1])) {
           usbdevtemp = usbdev[i];
           usbdev[i] = usbdev[i - 1];
           usbdev[i - 1] = usbdevtemp;
@@ -662,19 +707,20 @@ max_gembird:
 
   /* get serial number of each device */
   for (i = 0; i < count; ++i) {
-    usb_dev_handle *sudev;
+    libusb_device_handle *sudev;
 
     sudev = get_handle(usbdev[i]);
     if (sudev == NULL) {
-      fprintf(stderr, "No access to Gembird #%d USB device %s\n",
-              i, usbdev[i]->filename );
+      fprintf(stderr, "No access to Gembird #%d USB device %03d:%03d\n",
+              i, libusb_get_bus_number(usbdev[i]),
+              libusb_get_device_address(usbdev[i]));
       usbdevsn[i] = malloc(5);
       usbdevsn[i][0] = '#';
       usbdevsn[i][1] = '0'+i;
       usbdevsn[i][2] = '\0';
     } else {
       usbdevsn[i] = strdup(get_serial(sudev));
-      usb_close(sudev);
+      libusb_close(sudev);
     }
   }
 
@@ -684,5 +730,12 @@ max_gembird:
   else
     parse_command_line(argc, argv, count, usbdev, usbdevsn);
 
+  /* cleanup */
+  for (i = 0; i < count; ++i) {
+    if (usbdev[i])
+      libusb_unref_device(usbdev[i]);
+  }
+  libusb_exit(NULL);
+
   return 0;
 }
diff --git a/src/process.c b/src/process.c
index 03dc739..133ac48 100644
--- a/src/process.c
+++ b/src/process.c
@@ -24,6 +24,7 @@
 */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
 #include <syslog.h>
@@ -31,7 +32,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <unistd.h>
-#include <usb.h>
+#include <libusb-1.0/libusb.h>
 #include "config.h"
 #include "sispm_ctl.h"
 
@@ -117,7 +118,7 @@ char *next_word(char *ptr)
   }
 }
 
-void process(int out,char *request, struct usb_device *dev, int devnum)
+void process(int out,char *request, libusb_device *dev, int devnum)
 {
   char xbuffer[BSIZE+2];
   char filename[1024];
@@ -126,7 +127,7 @@ void process(int out,char *request, struct usb_device *dev, int devnum)
   long length = 0;
   long lastpos = 0;
   long remlen = 0;
-  usb_dev_handle *udev;
+  libusb_device_handle *udev;
   unsigned int id; //product id of current device
   char *retvalue = NULL;
 
@@ -209,16 +210,16 @@ void process(int out,char *request, struct usb_device *dev, int devnum)
   /* get device-handle/-id */
   udev = get_handle(dev);
   if (udev == NULL) {
-    fprintf(stderr, "No access to Gembird #%d USB device %s\n", devnum,
-            dev->filename);
-    syslog(LOG_ERR, "No access to Gembird #%d USB device %s\n", devnum,
-           dev->filename);
+    fprintf(stderr, "No access to Gembird #%d USB device %03d:%03d\n", devnum,
+            libusb_get_bus_number(dev), libusb_get_device_address(dev));
+    syslog(LOG_ERR, "No access to Gembird #%d USB device %03d:%03d\n", devnum,
+           libusb_get_bus_number(dev), libusb_get_device_address(dev));
     service_not_available(out);
     fclose(in);
     return;
   } else if (verbose)
-    fprintf(stderr, "Accessing Gembird #%d USB device %s\n", devnum,
-            dev->filename );
+    fprintf(stderr, "Accessing Gembird #%d USB device %03d:%03d\n", devnum,
+            libusb_get_bus_number(dev), libusb_get_device_address(dev));
   id = get_id(dev);
 
   lastpos = ftell(in);
@@ -364,7 +365,7 @@ void process(int out,char *request, struct usb_device *dev, int devnum)
   }
 
   if (udev != NULL) {
-    usb_close(udev);
+    libusb_close(udev);
     udev = NULL;
   }
   fclose(in);
diff --git a/src/sispm_ctl.c b/src/sispm_ctl.c
index 8da24b8..ac84613 100644
--- a/src/sispm_ctl.c
+++ b/src/sispm_ctl.c
@@ -31,34 +31,37 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <time.h>
-#include <usb.h>
+#include <libusb-1.0/libusb.h>
 #include <assert.h>
 #include "sispm_ctl.h"
 
 char serial_id[15];
 
-int get_id(struct usb_device *dev)
+int get_id(libusb_device *dev)
 {
+  struct libusb_device_descriptor desc;
   assert(dev!=0);
-  return dev->descriptor.idProduct;
+  libusb_get_device_descriptor(dev, &desc);
+  return desc.idProduct;
 }
 
-static int usb_control_msg_tries(usb_dev_handle *dev, int requesttype,
+static int usb_control_msg_tries(libusb_device_handle *dev, int requesttype,
 				 int request, int value, int index,
-				 char *bytes, size_t size, int timeout)
+				 unsigned char *bytes, int size, int timeout)
 {
 	int ret;
-	char buf[64];
+	unsigned char buf[64];
 
-	if (size > sizeof(buf)) {
-		return -1;
+	if (size > (int)sizeof(buf)) {
+		return LIBUSB_ERROR_INVALID_PARAM;
 	}
 
 	for (int i = 0; i < 5; ++i) {
 		usleep(500 * i);
 		memcpy(buf, bytes, size);
-		ret = usb_control_msg(dev, requesttype, request, value, index,
-				      buf, size, timeout);
+		ret = libusb_control_transfer(dev, requesttype, request,
+					      value, index,
+					      buf, size, timeout);
 		if (ret == size) {
 			break;
 		}
@@ -72,23 +75,25 @@ static int usb_control_msg_tries(usb_dev_handle *dev, int requesttype,
 
 
 // for identification: reqtype=a1, request=01, b1=0x01, size=5
-char *get_serial(usb_dev_handle *udev)
+char *get_serial(libusb_device_handle *udev)
 {
   int  reqtype=0xa1; //USB_DIR_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE /* request type */,
   int  req=0x01;
   unsigned char buffer[6] = {0, 0, 0, 0, 0, 0};
+  int ret;
 
-  if (usb_control_msg_tries(udev,               /* handle */
+  ret = usb_control_msg_tries(udev,               /* handle */
                             reqtype,
                             req,
                             (0x03 << 8) | 1,
                             0,                  /* index  */
-                            (char *)buffer,     /* bytes  */
+                            buffer,             /* bytes  */
                             5,                  /* size   */
-                            5000) < 2 ) {
+                            5000);
+  if (ret < 2) {
     fprintf(stderr, "Error performing requested action\n"
-            "Libusb error string: %s\nTerminating\n", usb_strerror());
-    usb_close (udev);
+            "Libusb error: %s\nTerminating\n", libusb_strerror(ret));
+    libusb_close(udev);
     exit(-5);
   }
 
@@ -97,11 +102,12 @@ char *get_serial(usb_dev_handle *udev)
   return serial_id;
 }
 
-int usb_command(usb_dev_handle *udev, int b1, int b2, int return_value_expected)
+int usb_command(libusb_device_handle *udev, int b1, int b2, int return_value_expected)
 {
   int  reqtype=0x21; //USB_DIR_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE /* request type */,
   int  req=0x09;
-  char buffer[5];
+  unsigned char buffer[5];
+  int ret;
 
   buffer[0]=b1;
   buffer[1]=b2;
@@ -109,17 +115,18 @@ int usb_command(usb_dev_handle *udev, int b1, int b2, int return_value_expected)
     reqtype|=USB_DIR_IN;
     req=0x01;
   }
-  if (usb_control_msg_tries(udev,               /* handle */
+  ret = usb_control_msg_tries(udev,               /* handle */
                             reqtype,
                             req,
                             (0x03 << 8) | b1,
                             0,                  /* index  */
                             buffer,             /* bytes  */
                             5,                  /* size   */
-                            5000) < 2 ) {
+                            5000);
+  if (ret < 2) {
     fprintf(stderr, "Error performing requested action\n"
-            "Libusb error string: %s\nTerminating\n", usb_strerror());
-    usb_close (udev);
+            "Libusb error: %s\nTerminating\n", libusb_strerror(ret));
+    libusb_close(udev);
     exit(-5);
   }
 
@@ -127,35 +134,35 @@ int usb_command(usb_dev_handle *udev, int b1, int b2, int return_value_expected)
 }
 
 
-usb_dev_handle *get_handle(struct usb_device*dev)
+libusb_device_handle *get_handle(libusb_device *dev)
 {
-  usb_dev_handle *udev=NULL;
+  libusb_device_handle *udev=NULL;
+  int ret;
   if(!dev)
     return NULL;
-  udev = usb_open(dev);
+
+  ret = libusb_open(dev, &udev);
 
   /* prepare USB access */
-  if (!udev) {
-    fprintf(stderr, "Unable to open USB device %s\n", usb_strerror());
+  if (ret < 0) {
+    fprintf(stderr, "Unable to open USB device: %s\n", libusb_strerror(ret));
     return NULL;
   }
-  if (usb_set_configuration(udev, 1)) {
-    fprintf(stderr, "USB set configuration %s\n", usb_strerror());
-    usb_close (udev);
-    return NULL;
-  }
-  if (usb_claim_interface(udev, 0)) {
-    fprintf(stderr, "USB claim interface %s\nMaybe device already in use?\n",
-            usb_strerror());
-    usb_close(udev);
-    return NULL;
-  }
-  if (usb_set_altinterface(udev, 0)) {
-    fprintf(stderr, "USB set alt interface %s\n", usb_strerror());
-    usb_close (udev);
-    return NULL;;
+
+  /* Try to detach kernel driver — ignore errors (may not be bound) */
+  libusb_detach_kernel_driver(udev, 0);
+
+  libusb_set_configuration(udev, 1);
+  ret = libusb_claim_interface(udev, 0);
+  if (ret == 0) {
+    libusb_set_interface_alt_setting(udev, 0, 0);
+    return udev;
   }
-  return udev;
+
+  fprintf(stderr, "USB claim interface: %s\nMaybe device already in use?\n",
+          libusb_strerror(ret));
+  libusb_close(udev);
+  return NULL;
 }
 
 int check_outlet_number(int id, int outlet)
@@ -190,19 +197,19 @@ int check_outlet_number(int id, int outlet)
   return outlet;
 }
 
-int sispm_switch_on(usb_dev_handle *udev, int id, int outlet)
+int sispm_switch_on(libusb_device_handle *udev, int id, int outlet)
 {
   outlet=check_outlet_number(id, outlet);
   return usb_command(udev, 3 * outlet, 0x03, 0 ) ;
 }
 
-int sispm_switch_off(usb_dev_handle *udev, int id, int outlet)
+int sispm_switch_off(libusb_device_handle *udev, int id, int outlet)
 {
   outlet=check_outlet_number(id, outlet);
   return usb_command(udev, 3 * outlet, 0x00, 0 );
 }
 
-int sispm_switch_toggle(usb_dev_handle *udev, int id, int outlet)
+int sispm_switch_toggle(libusb_device_handle *udev, int id, int outlet)
 {
   if (!sispm_switch_getstatus(udev, id, outlet)) { //on
     sispm_switch_on(udev, id, outlet);
@@ -215,7 +222,7 @@ int sispm_switch_toggle(usb_dev_handle *udev, int id, int outlet)
   return 0;
 }
 
-int sispm_switch_getstatus(usb_dev_handle * udev, int id, int outlet)
+int sispm_switch_getstatus(libusb_device_handle * udev, int id, int outlet)
 {
   int result;
 
@@ -224,7 +231,7 @@ int sispm_switch_getstatus(usb_dev_handle * udev, int id, int outlet)
   return result & 1;
 }
 
-int sispm_get_power_supply_status(usb_dev_handle *udev, int id, int outlet)
+int sispm_get_power_supply_status(libusb_device_handle *udev, int id, int outlet)
 {
   int result;
 
@@ -377,25 +384,27 @@ void plannif_scanf(struct plannif *plan, const unsigned char *buffer)
 }
 
 // queries the device, and fills the schedule structure
-void usb_command_getplannif(usb_dev_handle *udev, int socket,
+void usb_command_getplannif(libusb_device_handle *udev, int socket,
                             struct plannif *plan)
 {
   int reqtype = 0x21 | USB_DIR_IN; /* request type */
   int req = 0x01;
   unsigned char buffer[0x28];
   unsigned int id;
+  int ret;
 
-  if (usb_control_msg_tries(udev,                               /* handle */
+  ret = usb_control_msg_tries(udev,                               /* handle */
                             reqtype,
                             req,
                             ((0x03 << 8) | (3 * socket)) + 1,
                             0,                                  /* index  */
-                            (char *)buffer,                     /* bytes  */
+                            buffer,                             /* bytes  */
                             0x28,                               /* size   */
-                            5000) < 0x27 ) {
+                            5000);
+  if (ret < 0x27) {
     fprintf(stderr, "Error performing requested action\n"
-            "Libusb error string: %s\nTerminating\n", usb_strerror());
-    usb_close(udev);
+            "Libusb error: %s\nTerminating\n", libusb_strerror(ret));
+    libusb_close(udev);
     exit(-5);
   }
 
@@ -406,7 +415,7 @@ void usb_command_getplannif(usb_dev_handle *udev, int socket,
   printf("\n");
   // */
 
-  id = get_id(usb_device(udev));
+  id = get_id(libusb_get_device(udev));
   if (id == PRODUCT_ID_SISPM_EG_PMS2)
     pms2_buffer_to_schedule(buffer, plan);
   else
@@ -475,15 +484,16 @@ void plannif_printf(const struct plannif *plan, unsigned char *buffer)
 }
 
 // prepares the buffer according to plannif and sends it to the device
-void usb_command_setplannif(usb_dev_handle *udev, struct plannif* plan)
+void usb_command_setplannif(libusb_device_handle *udev, struct plannif* plan)
 {
   int reqtype=0x21; //USB_DIR_OUT + USB_TYPE_CLASS + USB_RECIP_INTERFACE /*request type*/,
   int req=0x09;
   unsigned char buffer_size = 0x27;
   unsigned char buffer[0x28];
   unsigned int id;
+  int ret;
 
-  id = get_id(usb_device(udev));
+  id = get_id(libusb_get_device(udev));
   if (id == PRODUCT_ID_SISPM_EG_PMS2) {
     if (pms2_schedule_to_buffer(plan, buffer))
         exit(-2);
@@ -502,17 +512,18 @@ void usb_command_setplannif(usb_dev_handle *udev, struct plannif* plan)
   plannif_display(plan, 0, NULL);
   exit(0);
   //*/
-  if (usb_control_msg_tries(udev,                                  /* handle */
+  ret = usb_control_msg_tries(udev,                                  /* handle */
                             reqtype,
                             req,
                             ((0x03 << 8) | (3 * plan->socket)) + 1,
                             0,                                      /* index */
-                            (char *) buffer,                        /* bytes */
+                            buffer,                                 /* bytes */
                             buffer_size,                            /* size  */
-                            5000) < buffer_size ) {
+                            5000);
+  if (ret < buffer_size) {
     fprintf(stderr, "Error performing requested action\n"
-            "Libusb error string: %s\nTerminating\n", usb_strerror());
-    usb_close (udev);
+            "Libusb error: %s\nTerminating\n", libusb_strerror(ret));
+    libusb_close(udev);
     exit(-5);
   }
 }
diff --git a/src/sispm_ctl.h b/src/sispm_ctl.h
index 30c5090..f56fbf4 100644
--- a/src/sispm_ctl.h
+++ b/src/sispm_ctl.h
@@ -27,7 +27,7 @@
 #ifndef SISPM_CTL_H
 #define SISPM_CTL_H
 
-#include <usb.h>
+#include <libusb-1.0/libusb.h>
 
 #define MAXGEMBIRD                      32
 #define MAXANSWER                       8192
@@ -115,28 +115,28 @@ struct plannif {
 };
 
 void plannif_reset (struct plannif* plan);
-void usb_command_getplannif(usb_dev_handle *udev, int socket,
+void usb_command_getplannif(libusb_device_handle *udev, int socket,
                             struct plannif* plan);
-void usb_command_setplannif(usb_dev_handle *udev, struct plannif* plan);
+void usb_command_setplannif(libusb_device_handle *udev, struct plannif* plan);
 void plannif_display(const struct plannif* plan, int verbose,
                      const char* progname);
-void process(int out,char*v,struct usb_device*dev,int devnum);
+void process(int out,char*v,libusb_device*dev,int devnum);
 
-usb_dev_handle*get_handle(struct usb_device*dev);
-int usb_command(usb_dev_handle *udev, int b1, int b2,
+libusb_device_handle*get_handle(libusb_device*dev);
+int usb_command(libusb_device_handle *udev, int b1, int b2,
                 int return_value_expected);
 
 #define sispm_buzzer_on(udev)           usb_command(udev, 0x02, 0x00, 0)
 #define sispm_buzzer_off(udev)          usb_command(udev, 0x02, 0x04, 0)
 
-int get_id( struct usb_device* dev);
-char* get_serial(usb_dev_handle *udev);
-int sispm_switch_on(usb_dev_handle * udev,int id, int outlet);
-int sispm_switch_off(usb_dev_handle * udev,int id, int outlet);
-int sispm_switch_getstatus(usb_dev_handle * udev,int id, int outlet);
-int sispm_get_power_supply_status(usb_dev_handle * udev,int id, int outlet);
+int get_id(libusb_device* dev);
+char* get_serial(libusb_device_handle *udev);
+int sispm_switch_on(libusb_device_handle * udev,int id, int outlet);
+int sispm_switch_off(libusb_device_handle * udev,int id, int outlet);
+int sispm_switch_getstatus(libusb_device_handle * udev,int id, int outlet);
+int sispm_get_power_supply_status(libusb_device_handle * udev,int id, int outlet);
 int check_outlet_number(int id, int outlet);
-int sispm_switch_toggle(usb_dev_handle * udev,int id, int outlet);
+int sispm_switch_toggle(libusb_device_handle * udev,int id, int outlet);
 
 extern int debug;
 extern int verbose;
diff --git a/src/socket.c b/src/socket.c
index f4c6eec..64be150 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -34,14 +35,14 @@
 #ifdef HAVE_NET_ETHERNET_H
 #include <net/ethernet.h>
 #endif
-#include <usb.h>
+#include <libusb-1.0/libusb.h>
 #include "sispm_ctl.h"
 #include "socket.h"
 
 #ifndef WEBLESS
 int listenport=LISTENPORT;
 
-void l_listen(int*sock, struct usb_device*dev, int devnum)
+void l_listen(int*sock, libusb_device *dev, int devnum)
 {
   int i;
   int s;
diff --git a/src/socket.h b/src/socket.h
index 48093bd..7dc3eae 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -1,9 +1,11 @@
 #ifndef LOCAL_H
 #define LOCAL_H
 
+#include <libusb-1.0/libusb.h>
+
 #define LISTENPORT 2638
 extern int listenport;
 int*socket_init(char*bindaddr);
-void l_listen(int*sock,struct usb_device*,int devnum);
+void l_listen(int*sock,libusb_device*,int devnum);
 
 #endif /* ! LOCAL_H */
-- 
2.53.0.windows.2


From c01c8abcd02ed765d4035835dc94c3768a9cca47 Mon Sep 17 00:00:00 2001
From: nowrap <nowrap@gmx.net>
Date: Sun, 29 Mar 2026 22:33:29 +0200
Subject: [PATCH 2/2] Bump version to 4.13, update snap to libusb-1.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- configure.ac: 4.12 → 4.13
- snap/snapcraft.yaml: 4.12 → 4.13, libusb-dev → libusb-1.0-0-dev,
  libusb-0.1-4 → libusb-1.0-0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
 configure.ac        | 2 +-
 snap/snapcraft.yaml | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index fb64375..b6e88bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.59])
-AC_INIT([sispmctl], [4.12], [xypron.glpk@gmx.de])
+AC_INIT([sispmctl], [4.13], [xypron.glpk@gmx.de])
 AC_CONFIG_AUX_DIR(admin)
 AC_CANONICAL_TARGET
 AM_INIT_AUTOMAKE
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index bf9d762..eae1c2e 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -1,7 +1,7 @@
 name: sispmctl
 icon: artwork/sispmctl.svg
 license: GPL-2.0-or-later
-version: '4.12'
+version: '4.13'
 grade: stable
 summary: Silver Shield PM Control for Linux (sispmctl)
 source-code: https://sourceforge.net/p/sispmctl/git/
@@ -51,7 +51,7 @@ parts:
       - --enable-webless
     build-packages:
       - autotools-dev
-      - libusb-dev
+      - libusb-1.0-0-dev
       - pkg-config
     stage-packages:
-      - libusb-0.1-4
+      - libusb-1.0-0
-- 
2.53.0.windows.2

