summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay Jaggi <akshay1994.leo@gmail.com>2014-09-24 22:46:17 +0100
committerPete Batard <pete@akeo.ie>2014-09-25 21:42:16 +0100
commitdc97425bb415422423b8876af0e34111e566d56d (patch)
treecf4c2f1e7788948af4551ab38e8f51e8eafe52aa
parent12e9e3557979af218ddb40f1e221d7fc56596fe9 (diff)
downloadlibusb-dc97425bb415422423b8876af0e34111e566d56d.tar.gz
haiku: Add Haiku support
-rwxr-xr-xbootstrap.sh8
-rw-r--r--configure.ac27
-rw-r--r--libusb/Makefile.am12
-rw-r--r--libusb/core.c2
-rw-r--r--libusb/libusb.h2
-rw-r--r--libusb/libusbi.h15
-rw-r--r--libusb/os/haiku/Makefile.am5
-rw-r--r--libusb/os/haiku/configure.ac8
-rw-r--r--libusb/os/haiku/haiku_pollfs.cpp378
-rw-r--r--libusb/os/haiku/haiku_usb.h114
-rw-r--r--libusb/os/haiku/haiku_usb_backend.cpp562
-rw-r--r--libusb/os/haiku/haiku_usb_raw.cpp268
-rw-r--r--libusb/os/haiku/haiku_usb_raw.h180
-rw-r--r--libusb/strerror.c3
-rw-r--r--libusb/version_nano.h2
15 files changed, 1582 insertions, 4 deletions
diff --git a/bootstrap.sh b/bootstrap.sh
index 8b2b2c0..506440b 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -12,6 +12,14 @@ else
exit 1
fi
+# run autotools on haiku package
+cd libusb/os/haiku || exit 1
+$LIBTOOLIZE --copy --force || exit 1
+aclocal || exit 1
+autoconf || exit 1
+automake -a -c || exit 1
+cd ../../..
+
$LIBTOOLIZE --copy --force || exit 1
aclocal || exit 1
autoheader || exit 1
diff --git a/configure.ac b/configure.ac
index b662c0d..399f397 100644
--- a/configure.ac
+++ b/configure.ac
@@ -89,6 +89,12 @@ case $host in
backend="windows"
threads="posix"
;;
+*-haiku*)
+ AC_MSG_RESULT([Haiku])
+ AC_CONFIG_SUBDIRS([libusb/os/haiku])
+ backend="haiku"
+ threads="posix"
+ ;;
*)
AC_MSG_ERROR([unsupported operating system])
esac
@@ -170,6 +176,13 @@ windows)
AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])
AC_DEFINE([WINVER], 0x0501, [Oldest Windows version supported])
;;
+haiku)
+ AC_DEFINE(OS_HAIKU, 1, [Haiku backend])
+ AC_SUBST(OS_HAIKU)
+ LIBS="${LIBS} -lbe"
+ AC_CHECK_HEADERS([poll.h])
+ AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])
+ ;;
esac
AC_SUBST(LIBS)
@@ -179,6 +192,7 @@ AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin)
AM_CONDITIONAL(OS_OPENBSD, test "x$backend" = xopenbsd)
AM_CONDITIONAL(OS_NETBSD, test "x$backend" = xnetbsd)
AM_CONDITIONAL(OS_WINDOWS, test "x$backend" = xwindows)
+AM_CONDITIONAL(OS_HAIKU, test "x$backend" = xhaiku)
AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix)
AM_CONDITIONAL(CREATE_IMPORT_LIB, test "x$create_import_lib" = "xyes")
AM_CONDITIONAL(USE_UDEV, test "x$enable_udev" = xyes)
@@ -289,7 +303,18 @@ AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_FUNCS(gettimeofday)
AC_CHECK_HEADERS([signal.h])
-AM_CFLAGS="${AM_CFLAGS} -std=gnu99 -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow ${THREAD_CFLAGS} ${VISIBILITY_CFLAGS}"
+# check for -std=gnu99 compiler support
+saved_cflags="$CFLAGS"
+CFLAGS="-std=gnu99"
+AC_MSG_CHECKING([whether CC supports -std=gnu99])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+ [AC_MSG_RESULT([yes])]
+ [AM_CFLAGS="${AM_CFLAGS} -std=gnu99"],
+ [AC_MSG_RESULT([no])]
+)
+CFLAGS="$saved_cflags"
+
+AM_CFLAGS="${AM_CFLAGS} -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow ${THREAD_CFLAGS} ${VISIBILITY_CFLAGS}"
AC_SUBST(AM_CFLAGS)
AC_SUBST(LTLDFLAGS)
diff --git a/libusb/Makefile.am b/libusb/Makefile.am
index 80e3705..b3c2f05 100644
--- a/libusb/Makefile.am
+++ b/libusb/Makefile.am
@@ -12,6 +12,9 @@ NETBSD_USB_SRC = os/netbsd_usb.c
WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc libusb-1.0.def
WINCE_USB_SRC = os/wince_usb.c os/wince_usb.h
+dist_data_DATA = os/haiku
+DIST_SUBDIRS =
+
EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_USB_SRC) \
$(NETBSD_USB_SRC) $(WINDOWS_USB_SRC) $(WINCE_USB_SRC) \
$(POSIX_POLL_SRC) \
@@ -43,6 +46,11 @@ if OS_NETBSD
OS_SRC = $(NETBSD_USB_SRC) $(POSIX_POLL_SRC)
endif
+if OS_HAIKU
+OS_SRC = $(POSIX_POLL_SRC)
+SUBDIRS = os/haiku
+endif
+
if OS_WINDOWS
OS_SRC = $(WINDOWS_USB_SRC)
@@ -71,5 +79,9 @@ libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c strerror.c sync.c \
hotplug.h hotplug.c $(THREADS_SRC) $(OS_SRC) \
os/poll_posix.h os/poll_windows.h
+if OS_HAIKU
+libusb_1_0_la_LIBADD = os/haiku/libhaikuusb.la
+endif
+
hdrdir = $(includedir)/libusb-1.0
hdr_HEADERS = libusb.h
diff --git a/libusb/core.c b/libusb/core.c
index 4561740..c24ab77 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -56,6 +56,8 @@ const struct usbi_os_backend * const usbi_backend = &netbsd_backend;
const struct usbi_os_backend * const usbi_backend = &windows_backend;
#elif defined(OS_WINCE)
const struct usbi_os_backend * const usbi_backend = &wince_backend;
+#elif defined(OS_HAIKU)
+const struct usbi_os_backend * const usbi_backend = &haiku_usb_raw_backend;
#else
#error "Unsupported OS"
#endif
diff --git a/libusb/libusb.h b/libusb/libusb.h
index a19ab34..79b255f 100644
--- a/libusb/libusb.h
+++ b/libusb/libusb.h
@@ -54,7 +54,7 @@ typedef unsigned __int32 uint32_t;
#include <sys/types.h>
#endif
-#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__)
+#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
#include <sys/time.h>
#endif
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 8d1fb9d..98cc4eb 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -48,6 +48,10 @@
*/
#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define DEVICE_DESC_LENGTH 18
#define USB_MAXENDPOINTS 32
@@ -145,8 +149,12 @@ static inline void *usbi_reallocf(void *ptr, size_t size)
const typeof( ((type *)0)->member ) *mptr = (ptr); \
(type *)( (char *)mptr - offsetof(type,member) );})
+#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0)
@@ -454,7 +462,7 @@ void usbi_connect_device (struct libusb_device *dev);
void usbi_disconnect_device (struct libusb_device *dev);
/* Internal abstraction for poll (needs struct usbi_transfer on Windows) */
-#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD)
+#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) || defined(OS_HAIKU)
#include <unistd.h>
#include "os/poll_posix.h"
#elif defined(OS_WINDOWS) || defined(OS_WINCE)
@@ -1027,8 +1035,13 @@ extern const struct usbi_os_backend openbsd_backend;
extern const struct usbi_os_backend netbsd_backend;
extern const struct usbi_os_backend windows_backend;
extern const struct usbi_os_backend wince_backend;
+extern const struct usbi_os_backend haiku_usb_raw_backend;
extern struct list_head active_contexts_list;
extern usbi_mutex_static_t active_contexts_lock;
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/libusb/os/haiku/Makefile.am b/libusb/os/haiku/Makefile.am
new file mode 100644
index 0000000..3ab0a09
--- /dev/null
+++ b/libusb/os/haiku/Makefile.am
@@ -0,0 +1,5 @@
+ACLOCAL_AMFLAGS = -I m4
+AUTOMAKE_OPTIONS = subdir-objects
+noinst_LTLIBRARIES = libhaikuusb.la
+libhaikuusb_la_CPPFLAGS = $(AM_CPPFLAGS) -I../.. -I../../..
+libhaikuusb_la_SOURCES = haiku_usb_raw.cpp haiku_usb_backend.cpp haiku_pollfs.cpp
diff --git a/libusb/os/haiku/configure.ac b/libusb/os/haiku/configure.ac
new file mode 100644
index 0000000..ae95179
--- /dev/null
+++ b/libusb/os/haiku/configure.ac
@@ -0,0 +1,8 @@
+AC_INIT([haikuusb], [1.0])
+AM_INIT_AUTOMAKE([no-define foreign])
+AM_MAINTAINER_MODE
+AC_CONFIG_MACRO_DIR([m4])
+LT_INIT
+AC_PROG_CXX
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/libusb/os/haiku/haiku_pollfs.cpp b/libusb/os/haiku/haiku_pollfs.cpp
new file mode 100644
index 0000000..6781de4
--- /dev/null
+++ b/libusb/os/haiku/haiku_pollfs.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2007-2008, Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Michael Lotz <mmlr@mlotz.ch>
+ */
+
+#include "haiku_usb.h"
+#include <cstdio>
+#include <Directory.h>
+#include <Entry.h>
+#include <Looper.h>
+#include <Messenger.h>
+#include <Node.h>
+#include <NodeMonitor.h>
+#include <Path.h>
+#include <cstring>
+
+class WatchedEntry {
+public:
+ WatchedEntry(BMessenger*, entry_ref*);
+ ~WatchedEntry();
+ bool EntryCreated(entry_ref* ref);
+ bool EntryRemoved(ino_t node);
+ bool InitCheck();
+
+private:
+ BMessenger* fMessenger;
+ node_ref fNode;
+ bool fIsDirectory;
+ USBDevice* fDevice;
+ WatchedEntry* fEntries;
+ WatchedEntry* fLink;
+ bool fInitCheck;
+};
+
+
+class RosterLooper : public BLooper {
+public:
+ RosterLooper(USBRoster*);
+ void Stop();
+ virtual void MessageReceived(BMessage*);
+ bool InitCheck();
+
+private:
+ USBRoster* fRoster;
+ WatchedEntry* fRoot;
+ BMessenger* fMessenger;
+ bool fInitCheck;
+};
+
+
+WatchedEntry::WatchedEntry(BMessenger* messenger, entry_ref* ref)
+ : fMessenger(messenger),
+ fIsDirectory(false),
+ fDevice(NULL),
+ fEntries(NULL),
+ fLink(NULL),
+ fInitCheck(false)
+{
+ BEntry entry(ref);
+ entry.GetNodeRef(&fNode);
+
+ BDirectory directory;
+ if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
+
+ fIsDirectory = true;
+
+ while (directory.GetNextEntry(&entry) >= B_OK) {
+ if (entry.GetRef(ref) < B_OK)
+ continue;
+
+ WatchedEntry* child = new(std::nothrow) WatchedEntry(fMessenger, ref);
+ if (child == NULL)
+ continue;
+ if (child->InitCheck() == false)
+ {
+ delete child;
+ continue;
+ }
+
+
+ child->fLink = fEntries;
+ fEntries = child;
+ }
+
+ watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
+
+ } else {
+ if (strncmp(ref->name, "raw", 3) == 0)
+ return;
+
+ BPath path, parent_path;
+ entry.GetPath(&path);
+ fDevice = new(std::nothrow) USBDevice(path.Path());
+ if (fDevice != NULL && fDevice->InitCheck() == true) {
+ // Add this new device to each active context's device list
+ struct libusb_context *ctx;
+ unsigned long session_id = (unsigned long)&fDevice;
+
+ usbi_mutex_lock(&active_contexts_lock);
+ list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+
+ struct libusb_device* dev = usbi_get_device_by_session_id(ctx, session_id);
+ if (dev) {
+ usbi_dbg("using previously allocated device with location %lu", session_id);
+ libusb_unref_device(dev);
+ continue;
+ }
+ usbi_dbg("allocating new device with location %lu" ,session_id);
+ dev = usbi_alloc_device(ctx, session_id);
+ if (!dev) {
+ usbi_dbg("device allocation failed");
+ continue;
+ }
+ *((USBDevice**)dev->os_priv) = fDevice;
+
+ // Calculate pseudo-device-address
+ int addr,tmp;
+ if (strcmp(path.Leaf(), "hub") == 0)
+ {
+ tmp=100; //Random Number
+ }
+ else
+ {
+ sscanf(path.Leaf(), "%d", &tmp);
+ }
+ addr = tmp + 1;
+ path.GetParent(&parent_path);
+ while(strcmp(parent_path.Leaf(),"usb") != 0)
+ {
+ sscanf(parent_path.Leaf(), "%d", &tmp);
+ addr += tmp + 1;
+ parent_path.GetParent(&parent_path);
+ }
+ sscanf(path.Path(), "/dev/bus/usb/%d", &dev->bus_number);
+ (dev->device_address) = addr - (dev->bus_number + 1);
+
+ if(usbi_sanitize_device(dev) < 0)
+ {
+ usbi_dbg("device sanitization failed");
+ libusb_unref_device(dev);
+ continue;
+ }
+ usbi_connect_device(dev);
+ }
+ usbi_mutex_unlock(&active_contexts_lock);
+ } else if (fDevice) {
+ delete fDevice;
+ fDevice = NULL;
+ return;
+ }
+ }
+ fInitCheck = true;
+}
+
+
+WatchedEntry::~WatchedEntry()
+{
+ if (fIsDirectory) {
+ watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
+
+ WatchedEntry* child = fEntries;
+ while (child) {
+ WatchedEntry *next = child->fLink;
+ delete child;
+ child = next;
+ }
+ }
+
+ if (fDevice) {
+ // Remove this device from each active context's device list
+ struct libusb_context *ctx;
+ struct libusb_device *dev;
+ unsigned long session_id = (unsigned long)&fDevice;
+
+ usbi_mutex_lock(&active_contexts_lock);
+ list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
+ dev = usbi_get_device_by_session_id (ctx, session_id);
+ if (dev != NULL) {
+ usbi_disconnect_device (dev);
+ libusb_unref_device(dev);
+ } else {
+ usbi_dbg("device with location %lu not found", session_id);
+ }
+ }
+ usbi_mutex_static_unlock(&active_contexts_lock);
+ delete fDevice;
+ }
+}
+
+
+bool
+WatchedEntry::EntryCreated(entry_ref *ref)
+{
+ if (!fIsDirectory)
+ return false;
+
+ if (ref->directory != fNode.node) {
+ WatchedEntry* child = fEntries;
+ while (child) {
+ if (child->EntryCreated(ref))
+ return true;
+ child = child->fLink;
+ }
+ return false;
+ }
+
+ WatchedEntry* child = new(std::nothrow) WatchedEntry(fMessenger, ref);
+ if (child == NULL)
+ return false;
+ child->fLink = fEntries;
+ fEntries = child;
+ return true;
+}
+
+
+bool
+WatchedEntry::EntryRemoved(ino_t node)
+{
+ if (!fIsDirectory)
+ return false;
+
+ WatchedEntry* child = fEntries;
+ WatchedEntry* lastChild = NULL;
+ while (child) {
+ if (child->fNode.node == node) {
+ if (lastChild)
+ lastChild->fLink = child->fLink;
+ else
+ fEntries = child->fLink;
+ delete child;
+ return true;
+ }
+
+ if (child->EntryRemoved(node))
+ return true;
+
+ lastChild = child;
+ child = child->fLink;
+ }
+ return false;
+}
+
+
+bool
+WatchedEntry::InitCheck()
+{
+ return fInitCheck;
+}
+
+
+RosterLooper::RosterLooper(USBRoster* roster)
+ : BLooper("LibusbRoster Looper"),
+ fRoster(roster),
+ fRoot(NULL),
+ fMessenger(NULL),
+ fInitCheck(false)
+{
+ BEntry entry("/dev/bus/usb");
+ if (!entry.Exists()) {
+ usbi_err(NULL,"usb_raw not published");
+ return;
+ }
+
+ Run();
+ fMessenger = new(std::nothrow) BMessenger(this);
+ if (fMessenger == NULL)
+ {
+ usbi_err(NULL,"error creating BMessenger object");
+ return;
+ }
+
+ if(Lock()) {
+ entry_ref ref;
+ entry.GetRef(&ref);
+ fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref);
+ Unlock();
+ if (fRoot == NULL)
+ {
+ return;
+ }
+ if (fRoot->InitCheck() == false)
+ {
+ delete fRoot;
+ return;
+ }
+ }
+ fInitCheck = true;
+}
+
+
+void
+RosterLooper::Stop()
+{
+ Lock();
+ delete fRoot;
+ delete fMessenger;
+ Quit();
+}
+
+
+void
+RosterLooper::MessageReceived(BMessage *message)
+{
+ int32 opcode;
+ if (message->FindInt32("opcode", &opcode) < B_OK)
+ return;
+
+ switch (opcode) {
+ case B_ENTRY_CREATED: {
+ dev_t device;
+ ino_t directory;
+ const char* name;
+ if (message->FindInt32("device", &device) < B_OK
+ || message->FindInt64("directory", &directory) < B_OK
+ || message->FindString("name", &name) < B_OK)
+ break;
+
+ entry_ref ref(device, directory, name);
+ fRoot->EntryCreated(&ref);
+ break;
+ }
+ case B_ENTRY_REMOVED: {
+ ino_t node;
+ if (message->FindInt64("node", &node) < B_OK)
+ break;
+ fRoot->EntryRemoved(node);
+ break;
+ }
+ }
+}
+
+
+bool
+RosterLooper::InitCheck()
+{
+ return fInitCheck;
+}
+
+
+USBRoster::USBRoster()
+ : fLooper(NULL)
+{
+}
+
+
+USBRoster::~USBRoster()
+{
+ Stop();
+}
+
+
+int
+USBRoster::Start()
+{
+ if(fLooper)
+ return LIBUSB_SUCCESS;
+
+ fLooper = new(std::nothrow) RosterLooper(this);
+ if (fLooper == NULL || ((RosterLooper*)fLooper)->InitCheck() == false)
+ return LIBUSB_ERROR_OTHER;
+ return LIBUSB_SUCCESS;
+}
+
+
+void
+USBRoster::Stop()
+{
+ if(!fLooper)
+ return;
+
+ ((RosterLooper *)fLooper)->Stop();
+ fLooper = NULL;
+}
+
+
diff --git a/libusb/os/haiku/haiku_usb.h b/libusb/os/haiku/haiku_usb.h
new file mode 100644
index 0000000..0188191
--- /dev/null
+++ b/libusb/os/haiku/haiku_usb.h
@@ -0,0 +1,114 @@
+/*
+ * Haiku Backend for libusb
+ * Copyright © 2014 Akshay Jaggi <akshay1994.leo@gmail.com>
+ *
+ * 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 <List.h>
+#include <Locker.h>
+#include <Autolock.h>
+#include <USBKit.h>
+#include <map>
+#include "libusbi.h"
+#include "haiku_usb_raw.h"
+
+using namespace std;
+
+class USBDevice;
+class USBDeviceHandle;
+class USBTransfer;
+
+class USBDevice {
+public:
+ USBDevice(const char *);
+ virtual ~USBDevice();
+ const char* Location() const;
+ uint8 CountConfigurations() const;
+ const usb_device_descriptor* Descriptor() const;
+ const usb_configuration_descriptor* ConfigurationDescriptor(uint32) const;
+ const usb_configuration_descriptor* ActiveConfiguration() const;
+ uint8 EndpointToIndex(uint8) const;
+ uint8 EndpointToInterface(uint8) const;
+ int ClaimInterface(int);
+ int ReleaseInterface(int);
+ int CheckInterfacesFree(int);
+ int SetActiveConfiguration(int);
+ int ActiveConfigurationIndex() const;
+ bool InitCheck();
+private:
+ int Initialise();
+ unsigned int fClaimedInterfaces; // Max Interfaces can be 32. Using a bitmask
+ usb_device_descriptor fDeviceDescriptor;
+ unsigned char** fConfigurationDescriptors;
+ int fActiveConfiguration;
+ char* fPath;
+ map<uint8,uint8> fConfigToIndex;
+ map<uint8,uint8>* fEndpointToIndex;
+ map<uint8,uint8>* fEndpointToInterface;
+ bool fInitCheck;
+};
+
+class USBDeviceHandle {
+public:
+ USBDeviceHandle(USBDevice* dev);
+ virtual ~USBDeviceHandle();
+ int EventPipe(int) const;
+ int ClaimInterface(int);
+ int ReleaseInterface(int);
+ int SetConfiguration(int);
+ int SetAltSetting(int,int);
+ status_t SubmitTransfer(struct usbi_transfer*);
+ status_t CancelTransfer(USBTransfer*);
+ bool InitCheck();
+private:
+ int fRawFD;
+ static status_t TransfersThread(void *);
+ void TransfersWorker();
+ USBDevice* fUSBDevice;
+ unsigned int fClaimedInterfaces;
+ int fEventPipes[2];
+ BList fTransfers;
+ BLocker fTransfersLock;
+ sem_id fTransfersSem;
+ thread_id fTransfersThread;
+ bool fInitCheck;
+};
+
+class USBTransfer {
+public:
+ USBTransfer(struct usbi_transfer*,USBDevice*);
+ virtual ~USBTransfer();
+ void Do(int);
+ struct usbi_transfer* UsbiTransfer();
+ void SetCancelled();
+ bool IsCancelled();
+private:
+ struct usbi_transfer* fUsbiTransfer;
+ struct libusb_transfer* fLibusbTransfer;
+ USBDevice* fUSBDevice;
+ BLocker fStatusLock;
+ bool fCancelled;
+};
+
+class USBRoster {
+public:
+ USBRoster();
+ virtual ~USBRoster();
+ int Start();
+ void Stop();
+private:
+ void* fLooper;
+};
diff --git a/libusb/os/haiku/haiku_usb_backend.cpp b/libusb/os/haiku/haiku_usb_backend.cpp
new file mode 100644
index 0000000..471bda9
--- /dev/null
+++ b/libusb/os/haiku/haiku_usb_backend.cpp
@@ -0,0 +1,562 @@
+/*
+ * Haiku Backend for libusb
+ * Copyright © 2014 Akshay Jaggi <akshay1994.leo@gmail.com>
+ *
+ * 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 <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <new>
+#include <vector>
+
+#include "haiku_usb.h"
+
+int _errno_to_libusb(int status)
+{
+ return status;
+}
+
+USBTransfer::USBTransfer(struct usbi_transfer* itransfer, USBDevice* device)
+{
+ fUsbiTransfer=itransfer;
+ fLibusbTransfer=USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ fUSBDevice=device;
+ fCancelled=false;
+}
+
+USBTransfer::~USBTransfer()
+{
+}
+
+struct usbi_transfer*
+USBTransfer::UsbiTransfer()
+{
+ return fUsbiTransfer;
+}
+
+void
+USBTransfer::SetCancelled()
+{
+ fCancelled=true;
+}
+
+bool
+USBTransfer::IsCancelled()
+{
+ return fCancelled;
+}
+
+void
+USBTransfer::Do(int fRawFD)
+{
+ switch(fLibusbTransfer->type)
+ {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ {
+ struct libusb_control_setup* setup=(struct libusb_control_setup*)fLibusbTransfer->buffer;
+ usb_raw_command command;
+ command.control.request_type=setup->bmRequestType;
+ command.control.request=setup->bRequest;
+ command.control.value=setup->wValue;
+ command.control.index=setup->wIndex;
+ command.control.length=setup->wLength;
+ command.control.data=fLibusbTransfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
+ if(fCancelled)
+ {
+ break;
+ }
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_CONTROL_TRANSFER,&command,
+ sizeof(command)) || command.control.status!=B_USB_RAW_STATUS_SUCCESS) {
+ fUsbiTransfer->transferred=-1;
+ usbi_err(TRANSFER_CTX(fLibusbTransfer),"failed control transfer");
+ break;
+ }
+ fUsbiTransfer->transferred=command.control.length;
+ }
+ break;
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+ {
+ usb_raw_command command;
+ command.transfer.interface=fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
+ command.transfer.endpoint=fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
+ command.transfer.data=fLibusbTransfer->buffer;
+ command.transfer.length=fLibusbTransfer->length;
+ if(fCancelled)
+ {
+ break;
+ }
+ if(fLibusbTransfer->type==LIBUSB_TRANSFER_TYPE_BULK)
+ {
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_BULK_TRANSFER,&command,
+ sizeof(command)) || command.transfer.status!=B_USB_RAW_STATUS_SUCCESS) {
+ fUsbiTransfer->transferred=-1;
+ usbi_err(TRANSFER_CTX(fLibusbTransfer),"failed bulk transfer");
+ break;
+ }
+ }
+ else
+ {
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_INTERRUPT_TRANSFER,&command,
+ sizeof(command)) || command.transfer.status!=B_USB_RAW_STATUS_SUCCESS) {
+ fUsbiTransfer->transferred=-1;
+ usbi_err(TRANSFER_CTX(fLibusbTransfer),"failed interrupt transfer");
+ break;
+ }
+ }
+ fUsbiTransfer->transferred=command.transfer.length;
+ }
+ break;
+ // IsochronousTransfers not tested
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ {
+ usb_raw_command command;
+ command.isochronous.interface=fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
+ command.isochronous.endpoint=fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
+ command.isochronous.data=fLibusbTransfer->buffer;
+ command.isochronous.length=fLibusbTransfer->length;
+ command.isochronous.packet_count=fLibusbTransfer->num_iso_packets;
+ int i=0;
+ usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets];
+ for (i=0; i<fLibusbTransfer->num_iso_packets; i++)
+ {
+ if((int16)(fLibusbTransfer->iso_packet_desc[i]).length!=(fLibusbTransfer->iso_packet_desc[i]).length)
+ {
+ fUsbiTransfer->transferred=-1;
+ usbi_err(TRANSFER_CTX(fLibusbTransfer),"failed isochronous transfer");
+ break;
+ }
+ packetDescriptors[i].request_length=(int16)(fLibusbTransfer->iso_packet_desc[i]).length;
+ }
+ if(i<fLibusbTransfer->num_iso_packets)
+ {
+ break; // TODO Handle this error
+ }
+ command.isochronous.packet_descriptors=packetDescriptors;
+ if(fCancelled)
+ {
+ break;
+ }
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER,&command,
+ sizeof(command)) || command.isochronous.status!=B_USB_RAW_STATUS_SUCCESS) {
+ fUsbiTransfer->transferred=-1;
+ usbi_err(TRANSFER_CTX(fLibusbTransfer),"failed isochronous transfer");
+ break;
+ }
+ for (i=0; i<fLibusbTransfer->num_iso_packets; i++)
+ {
+ (fLibusbTransfer->iso_packet_desc[i]).actual_length=packetDescriptors[i].actual_length;
+ switch(packetDescriptors[i].status)
+ {
+ case B_OK: (fLibusbTransfer->iso_packet_desc[i]).status=LIBUSB_TRANSFER_COMPLETED;
+ break;
+ default: (fLibusbTransfer->iso_packet_desc[i]).status=LIBUSB_TRANSFER_ERROR;
+ break;
+ }
+ }
+ delete[] packetDescriptors;
+ // Do we put the length of transfer here, for isochronous transfers?
+ fUsbiTransfer->transferred=command.transfer.length;
+ }
+ break;
+ default:
+ usbi_err(TRANSFER_CTX(fLibusbTransfer),"Unknown type of transfer");
+ }
+}
+
+bool
+USBDeviceHandle::InitCheck()
+{
+ return fInitCheck;
+}
+
+status_t
+USBDeviceHandle::TransfersThread(void* self)
+{
+ USBDeviceHandle* handle = (USBDeviceHandle*)self;
+ handle->TransfersWorker();
+ return B_OK;
+}
+
+void
+USBDeviceHandle::TransfersWorker()
+{
+ while(true)
+ {
+ status_t status = acquire_sem(fTransfersSem);
+ if(status== B_BAD_SEM_ID)
+ break;
+ if(status == B_INTERRUPTED)
+ continue;
+ fTransfersLock.Lock();
+ USBTransfer* fPendingTransfer= (USBTransfer*) fTransfers.RemoveItem((int32)0);
+ fTransfersLock.Unlock();
+ fPendingTransfer->Do(fRawFD);
+ write(fEventPipes[1],&fPendingTransfer,sizeof(fPendingTransfer));
+ }
+}
+
+status_t
+USBDeviceHandle::SubmitTransfer(struct usbi_transfer* itransfer)
+{
+ USBTransfer* transfer = new USBTransfer(itransfer,fUSBDevice);
+ *((USBTransfer**)usbi_transfer_get_os_priv(itransfer))=transfer;
+ BAutolock locker(fTransfersLock);
+ fTransfers.AddItem(transfer);
+ release_sem(fTransfersSem);
+ return LIBUSB_SUCCESS;
+}
+
+status_t
+USBDeviceHandle::CancelTransfer(USBTransfer* transfer)
+{
+ transfer->SetCancelled();
+ fTransfersLock.Lock();
+ bool removed = fTransfers.RemoveItem(transfer);
+ fTransfersLock.Unlock();
+ if(removed)
+ {
+ write(fEventPipes[1],&transfer,sizeof(transfer));
+ }
+ return LIBUSB_SUCCESS;
+}
+
+USBDeviceHandle::USBDeviceHandle(USBDevice* dev)
+ :
+ fTransfersThread(-1),
+ fUSBDevice(dev),
+ fClaimedInterfaces(0),
+ fInitCheck(false)
+{
+ fRawFD=open(dev->Location(), O_RDWR | O_CLOEXEC);
+ if(fRawFD < 0)
+ {
+ usbi_err(NULL,"failed to open device");
+ return;
+ }
+ pipe(fEventPipes);
+ fcntl(fEventPipes[1], F_SETFD, O_NONBLOCK);
+ fTransfersSem = create_sem(0, "Transfers Queue Sem");
+ fTransfersThread = spawn_thread(TransfersThread,"Transfer Worker",B_NORMAL_PRIORITY, this);
+ resume_thread(fTransfersThread);
+ fInitCheck = true;
+}
+
+USBDeviceHandle::~USBDeviceHandle()
+{
+ if(fRawFD>0)
+ close(fRawFD);
+ for(int i=0; i<32; i++)
+ {
+ if(fClaimedInterfaces&(1<<i))
+ ReleaseInterface(i);
+ }
+ if(fEventPipes[1]>0)
+ close(fEventPipes[1]);
+ if(fEventPipes[0]>0)
+ close(fEventPipes[0]);
+ delete_sem(fTransfersSem);
+ if(fTransfersThread>0)
+ wait_for_thread(fTransfersThread, NULL);
+}
+
+int
+USBDeviceHandle::EventPipe(int index) const
+{
+ return fEventPipes[index];
+}
+
+int
+USBDeviceHandle::ClaimInterface(int inumber)
+{
+ int status=fUSBDevice->ClaimInterface(inumber);
+ if(status==LIBUSB_SUCCESS)
+ {
+ fClaimedInterfaces|=(1<<inumber);
+ }
+ return status;
+}
+
+int
+USBDeviceHandle::ReleaseInterface(int inumber)
+{
+ fUSBDevice->ReleaseInterface(inumber);
+ fClaimedInterfaces&=(!(1<<inumber));
+ return LIBUSB_SUCCESS;
+}
+
+int
+USBDeviceHandle::SetConfiguration(int config)
+{
+ int config_index=fUSBDevice->CheckInterfacesFree(config);
+ if(config_index==LIBUSB_ERROR_BUSY || config_index==LIBUSB_ERROR_NOT_FOUND)
+ return config_index;
+
+ usb_raw_command command;
+ command.config.config_index=config_index;
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_SET_CONFIGURATION,&command,
+ sizeof(command)) || command.config.status != B_USB_RAW_STATUS_SUCCESS) {
+ return _errno_to_libusb(command.config.status);
+ }
+ fUSBDevice->SetActiveConfiguration(config_index);
+ return LIBUSB_SUCCESS;
+}
+
+int
+USBDeviceHandle::SetAltSetting(int inumber, int alt)
+{
+ usb_raw_command command;
+ command.alternate.config_index=fUSBDevice->ActiveConfigurationIndex();
+ command.alternate.interface_index=inumber;
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX,&command,
+ sizeof(command)) || command.alternate.status!=B_USB_RAW_STATUS_SUCCESS) {
+ usbi_err(NULL,"Error retrieving active alternate interface");
+ return _errno_to_libusb(command.alternate.status);
+ }
+ if(command.alternate.alternate_info == alt)
+ {
+ usbi_dbg("Setting alternate interface successful");
+ return LIBUSB_SUCCESS;
+ }
+ command.alternate.alternate_info = alt;
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_SET_ALT_INTERFACE,&command, //IF IOCTL FAILS DEVICE DISONNECTED PROBABLY
+ sizeof(command)) || command.alternate.status!=B_USB_RAW_STATUS_SUCCESS) {
+ usbi_err(NULL,"Error setting alternate interface");
+ return _errno_to_libusb(command.alternate.status);
+ }
+ usbi_dbg("Setting alternate interface successful");
+ return LIBUSB_SUCCESS;
+}
+
+
+USBDevice::USBDevice(const char * path)
+ :
+ fPath(NULL),
+ fActiveConfiguration(0), //0?
+ fConfigurationDescriptors(NULL),
+ fClaimedInterfaces(0),
+ fEndpointToIndex(NULL),
+ fEndpointToInterface(NULL),
+ fInitCheck(false)
+{
+ fPath=strdup(path);
+ Initialise();
+}
+
+USBDevice::~USBDevice()
+{
+ free(fPath);
+ if (fConfigurationDescriptors)
+ {
+ for(int i=0;i<fDeviceDescriptor.num_configurations;i++)
+ {
+ if (fConfigurationDescriptors[i])
+ delete fConfigurationDescriptors[i];
+ }
+ delete[] fConfigurationDescriptors;
+ }
+ if (fEndpointToIndex)
+ delete[] fEndpointToIndex;
+ if (fEndpointToInterface)
+ delete[] fEndpointToInterface;
+}
+
+bool
+USBDevice::InitCheck()
+{
+ return fInitCheck;
+}
+
+const char*
+USBDevice::Location() const
+{
+ return fPath;
+}
+
+uint8
+USBDevice::CountConfigurations() const
+{
+ return fDeviceDescriptor.num_configurations;
+}
+
+const usb_device_descriptor*
+USBDevice::Descriptor() const
+{
+ return &fDeviceDescriptor;
+}
+
+const usb_configuration_descriptor*
+USBDevice::ConfigurationDescriptor(uint32 index) const
+{
+ if(index>CountConfigurations())
+ return NULL;
+ return (usb_configuration_descriptor*) fConfigurationDescriptors[index];
+}
+
+const usb_configuration_descriptor*
+USBDevice::ActiveConfiguration() const
+{
+ return (usb_configuration_descriptor*) fConfigurationDescriptors[fActiveConfiguration];
+}
+
+int
+USBDevice::ActiveConfigurationIndex() const
+{
+ return fActiveConfiguration;
+}
+
+int USBDevice::ClaimInterface(int interface)
+{
+ if(interface>ActiveConfiguration()->number_interfaces)
+ {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+ if((fClaimedInterfaces & (1<<interface)) !=0 )
+ return LIBUSB_ERROR_BUSY;
+ fClaimedInterfaces|=(1<<interface);
+ return LIBUSB_SUCCESS;
+}
+
+int USBDevice::ReleaseInterface(int interface)
+{
+ fClaimedInterfaces&=(!(1<<interface));
+ return LIBUSB_SUCCESS;
+}
+
+int
+USBDevice::CheckInterfacesFree(int config)
+{
+ if(fConfigToIndex.count(config)==0)
+ return LIBUSB_ERROR_NOT_FOUND;
+ if(fClaimedInterfaces==0)
+ return fConfigToIndex[(uint8)config];
+ return LIBUSB_ERROR_BUSY;
+}
+
+int
+USBDevice::SetActiveConfiguration(int config_index)
+{
+ fActiveConfiguration=config_index;
+ return LIBUSB_SUCCESS;
+}
+
+uint8
+USBDevice::EndpointToIndex(uint8 address) const
+{
+ return fEndpointToIndex[fActiveConfiguration][address];
+}
+
+uint8
+USBDevice::EndpointToInterface(uint8 address) const
+{
+ return fEndpointToInterface[fActiveConfiguration][address];
+}
+
+int
+USBDevice::Initialise() //Do we need more error checking, etc? How to report?
+{
+ int fRawFD=open(fPath, O_RDWR | O_CLOEXEC);
+ if(fRawFD < 0)
+ return B_ERROR;
+
+ usb_raw_command command;
+ command.device.descriptor = &fDeviceDescriptor;
+ if(ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command,
+ sizeof(command)) || command.device.status != B_USB_RAW_STATUS_SUCCESS) {
+ close(fRawFD);
+ return B_ERROR;
+ }
+
+ size_t size;
+ fConfigurationDescriptors = new(std::nothrow) unsigned char*[fDeviceDescriptor.num_configurations];
+ fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
+ fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
+ for( int i=0; i<fDeviceDescriptor.num_configurations; i++)
+ {
+ size=0;
+ usb_configuration_descriptor tmp_config;
+ command.config.descriptor = &tmp_config;
+ command.config.config_index = i;
+ if(ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command,
+ sizeof(command)) || command.config.status != B_USB_RAW_STATUS_SUCCESS) {
+ usbi_err(NULL,"failed retrieving configuration descriptor");
+ close(fRawFD);
+ return B_ERROR;
+ }
+ fConfigToIndex[tmp_config.configuration_value]=i;
+ fConfigurationDescriptors[i]=new(std::nothrow) unsigned char[tmp_config.total_length];
+ command.control.request_type=128;
+ command.control.request=6;
+ command.control.value=(2<<8)|i;
+ command.control.index=0;
+ command.control.length=tmp_config.total_length;
+ command.control.data=fConfigurationDescriptors[i];
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_CONTROL_TRANSFER,&command,
+ sizeof(command)) || command.control.status!=B_USB_RAW_STATUS_SUCCESS) {
+ usbi_err(NULL,"failed retrieving full configuration descriptor");
+ close(fRawFD);
+ return B_ERROR;
+ }
+ for( int j=0;j<tmp_config.number_interfaces;j++)
+ {
+ command.alternate.config_index=i;
+ command.alternate.interface_index=j;
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command,
+ sizeof(command)) || command.config.status != B_USB_RAW_STATUS_SUCCESS) {
+ usbi_err(NULL,"failed retrieving number of alternate interfaces");
+ close(fRawFD);
+ return B_ERROR;
+ }
+ int num_alternate=command.alternate.alternate_info;
+ for( int k=0;k<num_alternate;k++)
+ {
+ usb_interface_descriptor tmp_interface;
+ command.interface_etc.config_index=i;
+ command.interface_etc.interface_index=j;
+ command.interface_etc.alternate_index=k;
+ command.interface_etc.descriptor=&tmp_interface;
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command,
+ sizeof(command)) || command.config.status != B_USB_RAW_STATUS_SUCCESS) {
+ usbi_err(NULL,"failed retrieving interface descriptor");
+ close(fRawFD);
+ return B_ERROR;
+ }
+ for( int l=0;l<tmp_interface.num_endpoints;l++)
+ {
+ usb_endpoint_descriptor tmp_endpoint;
+ command.endpoint_etc.config_index=i;
+ command.endpoint_etc.interface_index=j;
+ command.endpoint_etc.alternate_index=k;
+ command.endpoint_etc.endpoint_index=l;
+ command.endpoint_etc.descriptor=&tmp_endpoint;
+ if(ioctl(fRawFD,B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command,
+ sizeof(command)) || command.config.status != B_USB_RAW_STATUS_SUCCESS) {
+ usbi_err(NULL,"failed retrieving endpoint descriptor");
+ close(fRawFD);
+ return B_ERROR;
+ }
+ fEndpointToIndex[i][tmp_endpoint.endpoint_address]=l;
+ fEndpointToInterface[i][tmp_endpoint.endpoint_address]=j;
+ }
+ }
+ }
+ }
+ close(fRawFD);
+ fInitCheck = true;
+ return B_OK;
+}
diff --git a/libusb/os/haiku/haiku_usb_raw.cpp b/libusb/os/haiku/haiku_usb_raw.cpp
new file mode 100644
index 0000000..2a8f478
--- /dev/null
+++ b/libusb/os/haiku/haiku_usb_raw.cpp
@@ -0,0 +1,268 @@
+/*
+ * Haiku Backend for libusb
+ * Copyright © 2014 Akshay Jaggi <akshay1994.leo@gmail.com>
+ *
+ * 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 <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <new>
+#include <vector>
+
+#include "haiku_usb.h"
+
+USBRoster gUsbRoster;
+int32 gInitCount = 0;
+
+static int
+haiku_init(struct libusb_context* ctx)
+{
+ if (atomic_add(&gInitCount, 1) == 0)
+ {
+ return gUsbRoster.Start();
+ }
+ return LIBUSB_SUCCESS;
+}
+
+static void
+haiku_exit(void)
+{
+ if (atomic_add(&gInitCount, -1) == 1)
+ gUsbRoster.Stop();
+}
+
+static int
+haiku_open(struct libusb_device_handle *dev_handle)
+{
+ USBDevice* dev=*((USBDevice**)dev_handle->dev->os_priv);
+ USBDeviceHandle *handle=new(std::nothrow) USBDeviceHandle(dev);
+ if (handle == NULL)
+ return LIBUSB_ERROR_NO_MEM;
+ if (handle->InitCheck() == false)
+ {
+ delete handle;
+ return LIBUSB_ERROR_NO_DEVICE;
+ }
+ *((USBDeviceHandle**)dev_handle->os_priv)=handle;
+ return usbi_add_pollfd(HANDLE_CTX(dev_handle),handle->EventPipe(0), POLLIN);
+}
+
+static void
+haiku_close(struct libusb_device_handle *dev_handle)
+{
+ USBDeviceHandle * handle=*((USBDeviceHandle**)dev_handle->os_priv);
+ if(handle==NULL)
+ return;
+ usbi_remove_pollfd(HANDLE_CTX(dev_handle),handle->EventPipe(0));
+ delete handle;
+ *((USBDeviceHandle**)dev_handle->os_priv)=NULL;
+}
+
+static int
+haiku_get_device_descriptor(struct libusb_device *device, unsigned char* buffer, int *host_endian)
+{
+ USBDevice *dev = *((USBDevice**)(device->os_priv));
+ memcpy(buffer,dev->Descriptor(),DEVICE_DESC_LENGTH);
+ *host_endian=0;
+ return LIBUSB_SUCCESS;
+}
+
+static int
+haiku_get_active_config_descriptor(struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian)
+{
+ USBDevice *dev = *((USBDevice**)(device->os_priv));
+ const usb_configuration_descriptor* act_config = dev->ActiveConfiguration();
+ if(len>act_config->total_length)
+ {
+ return LIBUSB_ERROR_OVERFLOW;
+ }
+ memcpy(buffer,act_config,len);
+ *host_endian=0;
+ return LIBUSB_SUCCESS;
+}
+
+static int
+haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
+{
+ USBDevice *dev = *((USBDevice**)(device->os_priv));
+ const usb_configuration_descriptor* config = dev->ConfigurationDescriptor(config_index);
+ if(config==NULL)
+ {
+ usbi_err(DEVICE_CTX(device),"failed getting configuration descriptor");
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+ if(len>config->total_length)
+ len=config->total_length;
+ memcpy(buffer,(unsigned char*)config,len);
+ *host_endian=0;
+ return len;
+}
+
+static int
+haiku_set_configuration(struct libusb_device_handle *dev_handle, int config)
+{
+ USBDeviceHandle * handle= *((USBDeviceHandle**)dev_handle->os_priv);
+ return handle->SetConfiguration(config);
+}
+
+static int
+haiku_claim_interface(struct libusb_device_handle *dev_handle, int interface_number)
+{
+ USBDeviceHandle * handle=*((USBDeviceHandle**)dev_handle->os_priv);
+ return handle->ClaimInterface(interface_number);
+}
+
+static int
+haiku_set_altsetting(struct libusb_device_handle* dev_handle, int interface_number, int altsetting)
+{
+ USBDeviceHandle* handle = *((USBDeviceHandle**)dev_handle->os_priv);
+ return handle->SetAltSetting(interface_number, altsetting);
+}
+
+static int
+haiku_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
+{
+ USBDeviceHandle * handle=*((USBDeviceHandle**)dev_handle->os_priv);
+ haiku_set_altsetting(dev_handle,interface_number,0);
+ return handle->ReleaseInterface(interface_number);
+}
+
+static int
+haiku_submit_transfer(struct usbi_transfer * itransfer)
+{
+ struct libusb_transfer* fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ USBDeviceHandle * fDeviceHandle = *((USBDeviceHandle**)fLibusbTransfer->dev_handle->os_priv);
+ return fDeviceHandle->SubmitTransfer(itransfer);
+}
+
+static int
+haiku_cancel_transfer(struct usbi_transfer * itransfer)
+{
+ struct libusb_transfer* fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ USBDeviceHandle * fDeviceHandle = *((USBDeviceHandle**)fLibusbTransfer->dev_handle->os_priv);
+ return fDeviceHandle->CancelTransfer(*((USBTransfer**)usbi_transfer_get_os_priv(itransfer)));
+}
+
+static void
+haiku_clear_transfer_priv(struct usbi_transfer * itransfer)
+{
+ USBTransfer* transfer=*((USBTransfer**)usbi_transfer_get_os_priv(itransfer));
+ delete transfer;
+ *((USBTransfer**)usbi_transfer_get_os_priv(itransfer))=NULL;
+}
+
+static int
+haiku_handle_events(struct libusb_context* ctx, struct pollfd* fds, nfds_t nfds, int num_ready)
+{
+ USBTransfer *transfer;
+ for(int i=0;i<nfds && num_ready>0;i++)
+ {
+ struct pollfd *pollfd = &fds[i];
+ if(!pollfd->revents)
+ continue;
+
+ num_ready--;
+ read(pollfd->fd, &transfer, sizeof(transfer));
+ struct usbi_transfer* itransfer=transfer->UsbiTransfer();
+ usbi_mutex_lock(&itransfer->lock);
+ if(transfer->IsCancelled())
+ {
+ delete transfer;
+ *((USBTransfer**)usbi_transfer_get_os_priv(itransfer))=NULL;
+ usbi_mutex_unlock(&itransfer->lock);
+ if (itransfer->transferred < 0)
+ itransfer->transferred = 0;
+ usbi_handle_transfer_cancellation(transfer->UsbiTransfer());
+ continue;
+ }
+ libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
+ if(itransfer->transferred < 0)
+ {
+ usbi_err(ITRANSFER_CTX(itransfer),"error in transfer");
+ status = LIBUSB_TRANSFER_ERROR;
+ itransfer->transferred=0;
+ }
+ delete transfer;
+ *((USBTransfer**)usbi_transfer_get_os_priv(itransfer))=NULL;
+ usbi_mutex_unlock(&itransfer->lock);
+ usbi_handle_transfer_completion(itransfer,status);
+ }
+ return LIBUSB_SUCCESS;
+}
+
+
+static int
+haiku_clock_gettime(int clkid, struct timespec *tp)
+{
+ if(clkid == USBI_CLOCK_REALTIME)
+ return clock_gettime(CLOCK_REALTIME, tp);
+ if(clkid == USBI_CLOCK_MONOTONIC)
+ return clock_gettime(CLOCK_MONOTONIC, tp);
+ return LIBUSB_ERROR_INVALID_PARAM;
+}
+
+const struct usbi_os_backend haiku_usb_raw_backend = {
+ /*.name =*/ "Haiku usbfs",
+ /*.caps =*/ 0,
+ /*.init =*/ haiku_init,
+ /*.exit =*/ haiku_exit,
+ /*.get_device_list =*/ NULL,
+ /*.hotplug_poll =*/ NULL,
+ /*.open =*/ haiku_open,
+ /*.close =*/ haiku_close,
+ /*.get_device_descriptor =*/ haiku_get_device_descriptor,
+ /*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
+ /*.get_config_descriptor =*/ haiku_get_config_descriptor,
+ /*.get_config_descriptor_by_value =*/ NULL,
+
+
+ /*.get_configuration =*/ NULL,
+ /*.set_configuration =*/ haiku_set_configuration,
+ /*.claim_interface =*/ haiku_claim_interface,
+ /*.release_interface =*/ haiku_release_interface,
+
+ /*.set_interface_altsetting =*/ haiku_set_altsetting,
+ /*.clear_halt =*/ NULL,
+ /*.reset_device =*/ NULL,
+
+ /*.alloc_streams =*/ NULL,
+ /*.free_streams =*/ NULL,
+
+ /*.kernel_driver_active =*/ NULL,
+ /*.detach_kernel_driver =*/ NULL,
+ /*.attach_kernel_driver =*/ NULL,
+
+ /*.destroy_device =*/ NULL,
+
+ /*.submit_transfer =*/ haiku_submit_transfer,
+ /*.cancel_transfer =*/ haiku_cancel_transfer,
+ /*.clear_transfer_priv =*/ haiku_clear_transfer_priv,
+
+ /*.handle_events =*/ haiku_handle_events,
+
+ /*.clock_gettime =*/ haiku_clock_gettime,
+
+#ifdef USBI_TIMERFD_AVAILABLE
+ /*.get_timerfd_clockid =*/ NULL,
+#endif
+
+ /*.device_priv_size =*/ sizeof(USBDevice*),
+ /*.device_handle_priv_size =*/ sizeof(USBDeviceHandle*),
+ /*.transfer_priv_size =*/ sizeof(USBTransfer*),
+ /*.add_iso_packet_size =*/ 0,
+};
diff --git a/libusb/os/haiku/haiku_usb_raw.h b/libusb/os/haiku/haiku_usb_raw.h
new file mode 100644
index 0000000..54112c2
--- /dev/null
+++ b/libusb/os/haiku/haiku_usb_raw.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2006-2008, Haiku Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+#ifndef _USB_RAW_H_
+#define _USB_RAW_H_
+
+#include <USB3.h>
+
+#define B_USB_RAW_PROTOCOL_VERSION 0x0015
+#define B_USB_RAW_ACTIVE_ALTERNATE 0xffffffff
+
+typedef enum {
+ B_USB_RAW_COMMAND_GET_VERSION = 0x1000,
+
+ B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR = 0x2000,
+ B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR,
+ B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR,
+ B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR,
+ B_USB_RAW_COMMAND_GET_STRING_DESCRIPTOR,
+ B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR,
+ B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT,
+ B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX,
+ B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC,
+ B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC,
+ B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR_ETC,
+
+ B_USB_RAW_COMMAND_SET_CONFIGURATION = 0x3000,
+ B_USB_RAW_COMMAND_SET_FEATURE,
+ B_USB_RAW_COMMAND_CLEAR_FEATURE,
+ B_USB_RAW_COMMAND_GET_STATUS,
+ B_USB_RAW_COMMAND_GET_DESCRIPTOR,
+ B_USB_RAW_COMMAND_SET_ALT_INTERFACE,
+
+ B_USB_RAW_COMMAND_CONTROL_TRANSFER = 0x4000,
+ B_USB_RAW_COMMAND_INTERRUPT_TRANSFER,
+ B_USB_RAW_COMMAND_BULK_TRANSFER,
+ B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER
+} usb_raw_command_id;
+
+
+typedef enum {
+ B_USB_RAW_STATUS_SUCCESS = 0,
+
+ B_USB_RAW_STATUS_FAILED,
+ B_USB_RAW_STATUS_ABORTED,
+ B_USB_RAW_STATUS_STALLED,
+ B_USB_RAW_STATUS_CRC_ERROR,
+ B_USB_RAW_STATUS_TIMEOUT,
+
+ B_USB_RAW_STATUS_INVALID_CONFIGURATION,
+ B_USB_RAW_STATUS_INVALID_INTERFACE,
+ B_USB_RAW_STATUS_INVALID_ENDPOINT,
+ B_USB_RAW_STATUS_INVALID_STRING,
+
+ B_USB_RAW_STATUS_NO_MEMORY
+} usb_raw_command_status;
+
+
+typedef union {
+ struct {
+ status_t status;
+ } version;
+
+ struct {
+ status_t status;
+ usb_device_descriptor *descriptor;
+ } device;
+
+ struct {
+ status_t status;
+ usb_configuration_descriptor *descriptor;
+ uint32 config_index;
+ } config;
+
+ struct {
+ status_t status;
+ uint32 alternate_info;
+ uint32 config_index;
+ uint32 interface_index;
+ } alternate;
+
+ struct {
+ status_t status;
+ usb_interface_descriptor *descriptor;
+ uint32 config_index;
+ uint32 interface_index;
+ } interface;
+
+ struct {
+ status_t status;
+ usb_interface_descriptor *descriptor;
+ uint32 config_index;
+ uint32 interface_index;
+ uint32 alternate_index;
+ } interface_etc;
+
+ struct {
+ status_t status;
+ usb_endpoint_descriptor *descriptor;
+ uint32 config_index;
+ uint32 interface_index;
+ uint32 endpoint_index;
+ } endpoint;
+
+ struct {
+ status_t status;
+ usb_endpoint_descriptor *descriptor;
+ uint32 config_index;
+ uint32 interface_index;
+ uint32 alternate_index;
+ uint32 endpoint_index;
+ } endpoint_etc;
+
+ struct {
+ status_t status;
+ usb_descriptor *descriptor;
+ uint32 config_index;
+ uint32 interface_index;
+ uint32 generic_index;
+ size_t length;
+ } generic;
+
+ struct {
+ status_t status;
+ usb_descriptor *descriptor;
+ uint32 config_index;
+ uint32 interface_index;
+ uint32 alternate_index;
+ uint32 generic_index;
+ size_t length;
+ } generic_etc;
+
+ struct {
+ status_t status;
+ usb_string_descriptor *descriptor;
+ uint32 string_index;
+ size_t length;
+ } string;
+
+ struct {
+ status_t status;
+ uint8 type;
+ uint8 index;
+ uint16 language_id;
+ void *data;
+ size_t length;
+ } descriptor;
+
+ struct {
+ status_t status;
+ uint8 request_type;
+ uint8 request;
+ uint16 value;
+ uint16 index;
+ uint16 length;
+ void *data;
+ } control;
+
+ struct {
+ status_t status;
+ uint32 interface;
+ uint32 endpoint;
+ void *data;
+ size_t length;
+ } transfer;
+
+ struct {
+ status_t status;
+ uint32 interface;
+ uint32 endpoint;
+ void *data;
+ size_t length;
+ usb_iso_packet_descriptor *packet_descriptors;
+ uint32 packet_count;
+ } isochronous;
+} usb_raw_command;
+
+#endif // _USB_RAW_H_
diff --git a/libusb/strerror.c b/libusb/strerror.c
index 5b71585..a534041 100644
--- a/libusb/strerror.c
+++ b/libusb/strerror.c
@@ -22,6 +22,9 @@
#include <locale.h>
#include <stdlib.h>
#include <string.h>
+#if defined(HAVE_STRINGS_H)
+#include <strings.h>
+#endif
#include "libusbi.h"
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 4b584fa..4041786 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10918
+#define LIBUSB_NANO 10919