mirror of
https://github.com/RPCS3/libusb.git
synced 2026-07-01 13:13:20 -04:00
haiku: Add Haiku support
This commit is contained in:
committed by
Pete Batard
parent
12e9e35579
commit
dc97425bb4
@@ -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
|
||||
|
||||
+26
-1
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
+14
-1
@@ -48,6 +48,10 @@
|
||||
*/
|
||||
#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DEVICE_DESC_LENGTH 18
|
||||
|
||||
#define USB_MAXENDPOINTS 32
|
||||
@@ -145,8 +149,12 @@ static inline void *usbi_reallocf(void *ptr, size_t size)
|
||||
const typeof( ((type *)0)->member ) *mptr = (ptr); \
|
||||
(type *)( (char *)mptr - offsetof(type,member) );})
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0)
|
||||
|
||||
@@ -454,7 +462,7 @@ void usbi_connect_device (struct libusb_device *dev);
|
||||
void usbi_disconnect_device (struct libusb_device *dev);
|
||||
|
||||
/* Internal abstraction for poll (needs struct usbi_transfer on Windows) */
|
||||
#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD)
|
||||
#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) || defined(OS_HAIKU)
|
||||
#include <unistd.h>
|
||||
#include "os/poll_posix.h"
|
||||
#elif defined(OS_WINDOWS) || defined(OS_WINCE)
|
||||
@@ -1027,8 +1035,13 @@ extern const struct usbi_os_backend openbsd_backend;
|
||||
extern const struct usbi_os_backend netbsd_backend;
|
||||
extern const struct usbi_os_backend windows_backend;
|
||||
extern const struct usbi_os_backend wince_backend;
|
||||
extern const struct usbi_os_backend haiku_usb_raw_backend;
|
||||
|
||||
extern struct list_head active_contexts_list;
|
||||
extern usbi_mutex_static_t active_contexts_lock;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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_
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define LIBUSB_NANO 10918
|
||||
#define LIBUSB_NANO 10919
|
||||
|
||||
Reference in New Issue
Block a user