haiku: Add Haiku support
diff --git a/bootstrap.sh b/bootstrap.sh
index 8b2b2c0..506440b 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -12,6 +12,14 @@
   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 @@
 	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 @@
 	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_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_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 @@
 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 @@
 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 @@
 	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 = &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 @@
 #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 @@
         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_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 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