haiku: Add Haiku support
authorAkshay Jaggi <akshay1994.leo@gmail.com>
Wed, 24 Sep 2014 21:46:17 +0000 (22:46 +0100)
committerPete Batard <pete@akeo.ie>
Thu, 25 Sep 2014 20:42:16 +0000 (21:42 +0100)
15 files changed:
bootstrap.sh
configure.ac
libusb/Makefile.am
libusb/core.c
libusb/libusb.h
libusb/libusbi.h
libusb/os/haiku/Makefile.am [new file with mode: 0644]
libusb/os/haiku/configure.ac [new file with mode: 0644]
libusb/os/haiku/haiku_pollfs.cpp [new file with mode: 0644]
libusb/os/haiku/haiku_usb.h [new file with mode: 0644]
libusb/os/haiku/haiku_usb_backend.cpp [new file with mode: 0644]
libusb/os/haiku/haiku_usb_raw.cpp [new file with mode: 0644]
libusb/os/haiku/haiku_usb_raw.h [new file with mode: 0644]
libusb/strerror.c
libusb/version_nano.h

index 8b2b2c0..506440b 100755 (executable)
@@ -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
index b662c0d..399f397 100644 (file)
@@ -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)
index 80e3705..b3c2f05 100644 (file)
@@ -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
index 4561740..c24ab77 100644 (file)
@@ -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
index a19ab34..79b255f 100644 (file)
@@ -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
 
index 8d1fb9d..98cc4eb 100644 (file)
  */
 #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 (file)
index 0000000..3ab0a09
--- /dev/null
@@ -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 (file)
index 0000000..ae95179
--- /dev/null
@@ -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 (file)
index 0000000..6781de4
--- /dev/null
@@ -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 (file)
index 0000000..0188191
--- /dev/null
@@ -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 (file)
index 0000000..471bda9
--- /dev/null
@@ -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 (file)
index 0000000..2a8f478
--- /dev/null
@@ -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 (file)
index 0000000..54112c2
--- /dev/null
@@ -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_
index 5b71585..a534041 100644 (file)
@@ -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"
 
index 4b584fa..4041786 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 10918
+#define LIBUSB_NANO 10919