mirror of https://github.com/GOSTSec/sgminer
Noel Maersk
11 years ago
51 changed files with 143 additions and 22840 deletions
@ -1,46 +0,0 @@
@@ -1,46 +0,0 @@
|
||||
Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> |
||||
Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> |
||||
Copyright (C) 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net> |
||||
Copyright (C) 2009-2012 Pete Batard <pete@akeo.ie> |
||||
Copyright (C) 2010 Michael Plante <michael.plante@gmail.com> |
||||
Copyright (C) 2010-2012 Peter Stuge <peter@stuge.se> |
||||
Copyright (C) 2011-2012 Hans de Goede <hdegoede@redhat.com> |
||||
Copyright (C) 2012 Martin Pieuchot <mpi@openbsd.org> |
||||
|
||||
Other contributors: |
||||
Alan Ott |
||||
Alan Stern |
||||
Alex Vatchenko |
||||
Artem Egorkine |
||||
Aurelien Jarno |
||||
Bastien Nocera |
||||
Brian Shirley |
||||
David Engraf |
||||
David Moore |
||||
Felipe Balbi |
||||
Graeme Gill |
||||
Hans de Goede |
||||
Hans Ulrich Niedermann |
||||
Hector Martin |
||||
Hoi-Ho Chan |
||||
James Hanko |
||||
Konrad Rzepecki |
||||
Ludovic Rousseau |
||||
Martin Koegler |
||||
Martin Pieuchot |
||||
Maya Erez |
||||
Mike Frysinger |
||||
Mikhail Gusarov |
||||
Orin Eman |
||||
Pekka Nikander |
||||
Peter Stuge |
||||
Rob Walker |
||||
Sean McBride |
||||
Sebastian Pipping |
||||
Stephan Meyer |
||||
Thomas Röfer |
||||
Toby Peterson |
||||
Trygve Laugstøl |
||||
Vasily Khoruzhick |
||||
Vitali Lovich |
||||
Xiaofan Chen |
@ -1,24 +0,0 @@
@@ -1,24 +0,0 @@
|
||||
AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip |
||||
ACLOCAL_AMFLAGS = -I m4 |
||||
DISTCLEANFILES = libusb-1.0.pc |
||||
MAINTAINERCLEANFILES = ChangeLog |
||||
EXTRA_DIST = TODO PORTING |
||||
SUBDIRS = libusb |
||||
|
||||
pkgconfigdir=$(libdir)/pkgconfig |
||||
pkgconfig_DATA=libusb-1.0.pc |
||||
|
||||
.PHONY: ChangeLog dist-up |
||||
ChangeLog: |
||||
git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog |
||||
|
||||
dist-hook: ChangeLog |
||||
|
||||
reldir = .release/$(distdir) |
||||
dist-up: dist |
||||
rm -rf $(reldir) |
||||
mkdir -p $(reldir) |
||||
cp $(distdir).tar.bz2 $(reldir) |
||||
rsync -rv $(reldir) frs.sourceforge.net:/home/frs/project/l/li/libusb/libusb-1.0/ |
||||
rm -rf $(reldir) |
||||
|
@ -1,65 +0,0 @@
@@ -1,65 +0,0 @@
|
||||
This file lists notable changes in each release. For the full history of all |
||||
changes, see ChangeLog. |
||||
|
||||
2012-04-20: 1.0.9 |
||||
* Numerous bug fixes and improvements |
||||
* Backend for Windows, for devices using the WinUSB.sys driver |
||||
* Backend for OpenBSD and NetBSD, for devices using the ugen driver |
||||
* Add libusb_get_device_speed() |
||||
* Add libusb_has_capability() |
||||
* Add libusb_error_name() |
||||
* Add libusb_get_version() |
||||
|
||||
2010-05-07: v1.0.8 |
||||
* Bug fixes |
||||
|
||||
2010-04-19: v1.0.7 |
||||
* Bug fixes and documentation tweaks |
||||
* Add more interface class definitions |
||||
|
||||
2009-11-22: v1.0.6 |
||||
* Bug fixes |
||||
* Increase libusb_handle_events() timeout to 60s for powersaving |
||||
|
||||
2009-11-15: v1.0.5 |
||||
* Use timerfd when available for timer management |
||||
* Small fixes/updates |
||||
|
||||
2009-11-06: v1.0.4 release |
||||
* Bug fixes including transfer locking to fix some potential threading races |
||||
* More flexibility with clock types on Linux |
||||
* Use new bulk continuation tracking in Linux 2.6.32 for improved handling |
||||
of short/failed transfers |
||||
|
||||
2009-08-27: v1.0.3 release |
||||
* Bug fixes |
||||
* Add libusb_get_max_iso_packet_size() |
||||
|
||||
2009-06-13: v1.0.2 release |
||||
* Bug fixes |
||||
|
||||
2009-05-12: v1.0.1 release |
||||
* Bug fixes |
||||
* Darwin backend |
||||
|
||||
2008-12-13: v1.0.0 release |
||||
* Bug fixes |
||||
|
||||
2008-11-21: v0.9.4 release |
||||
* Bug fixes |
||||
* Add libusb_attach_kernel_driver() |
||||
|
||||
2008-08-23: v0.9.3 release |
||||
* Bug fixes |
||||
|
||||
2008-07-19: v0.9.2 release |
||||
* Bug fixes |
||||
|
||||
2008-06-28: v0.9.1 release |
||||
* Bug fixes |
||||
* Introduce contexts to the API |
||||
* Compatibility with new Linux kernel features |
||||
|
||||
2008-05-25: v0.9.0 release |
||||
* First libusb-1.0 beta release |
||||
|
@ -1,95 +0,0 @@
@@ -1,95 +0,0 @@
|
||||
PORTING LIBUSB TO OTHER PLATFORMS |
||||
|
||||
Introduction |
||||
============ |
||||
|
||||
This document is aimed at developers wishing to port libusb to unsupported |
||||
platforms. I believe the libusb API is OS-independent, so by supporting |
||||
multiple operating systems we pave the way for cross-platform USB device |
||||
drivers. |
||||
|
||||
Implementation-wise, the basic idea is that you provide an interface to |
||||
libusb's internal "backend" API, which performs the appropriate operations on |
||||
your target platform. |
||||
|
||||
In terms of USB I/O, your backend provides functionality to submit |
||||
asynchronous transfers (synchronous transfers are implemented in the higher |
||||
layers, based on the async interface). Your backend must also provide |
||||
functionality to cancel those transfers. |
||||
|
||||
Your backend must also provide an event handling function to "reap" ongoing |
||||
transfers and process their results. |
||||
|
||||
The backend must also provide standard functions for other USB operations, |
||||
e.g. setting configuration, obtaining descriptors, etc. |
||||
|
||||
|
||||
File descriptors for I/O polling |
||||
================================ |
||||
|
||||
For libusb to work, your event handling function obviously needs to be called |
||||
at various points in time. Your backend must provide a set of file descriptors |
||||
which libusb and its users can pass to poll() or select() to determine when |
||||
it is time to call the event handling function. |
||||
|
||||
On Linux, this is easy: the usbfs kernel interface exposes a file descriptor |
||||
which can be passed to poll(). If something similar is not true for your |
||||
platform, you can emulate this using an internal library thread to reap I/O as |
||||
necessary, and a pipe() with the main library to raise events. The file |
||||
descriptor of the pipe can then be provided to libusb as an event source. |
||||
|
||||
|
||||
Interface semantics and documentation |
||||
===================================== |
||||
|
||||
Documentation of the backend interface can be found in libusbi.h inside the |
||||
usbi_os_backend structure definition. |
||||
|
||||
Your implementations of these functions will need to call various internal |
||||
libusb functions, prefixed with "usbi_". Documentation for these functions |
||||
can be found in the .c files where they are implemented. |
||||
|
||||
You probably want to skim over *all* the documentation before starting your |
||||
implementation. For example, you probably need to allocate and store private |
||||
OS-specific data for device handles, but the documentation for the mechanism |
||||
for doing so is probably not the first thing you will see. |
||||
|
||||
The Linux backend acts as a good example - view it as a reference |
||||
implementation which you should try to match the behaviour of. |
||||
|
||||
|
||||
Getting started |
||||
=============== |
||||
|
||||
1. Modify configure.ac to detect your platform appropriately (see the OS_LINUX |
||||
stuff for an example). |
||||
|
||||
2. Implement your backend in the libusb/os/ directory, modifying |
||||
libusb/os/Makefile.am appropriately. |
||||
|
||||
3. Add preprocessor logic to the top of libusb/core.c to statically assign the |
||||
right usbi_backend for your platform. |
||||
|
||||
4. Produce and test your implementation. |
||||
|
||||
5. Send your implementation to libusb-devel mailing list. |
||||
|
||||
|
||||
Implementation difficulties? Questions? |
||||
======================================= |
||||
|
||||
If you encounter difficulties porting libusb to your platform, please raise |
||||
these issues on the libusb-devel mailing list. Where possible and sensible, I |
||||
am interested in solving problems preventing libusb from operating on other |
||||
platforms. |
||||
|
||||
The libusb-devel mailing list is also a good place to ask questions and |
||||
make suggestions about the internal API. Hopefully we can produce some |
||||
better documentation based on your questions and other input. |
||||
|
||||
You are encouraged to get involved in the process; if the library needs |
||||
some infrastructure additions/modifications to better support your platform, |
||||
you are encouraged to make such changes (in cleanly distinct patch |
||||
submissions). Even if you do not make such changes yourself, please do raise |
||||
the issues on the mailing list at the very minimum. |
||||
|
@ -1,22 +0,0 @@
@@ -1,22 +0,0 @@
|
||||
libusb |
||||
====== |
||||
|
||||
libusb is a library for USB device access from Linux, Mac OS X, |
||||
OpenBSD, NetBSD, and Windows userspace. |
||||
It is written in C and licensed under the LGPL-2.1 (see COPYING). |
||||
|
||||
libusb is abstracted internally in such a way that it can hopefully |
||||
be ported to other operating systems. See the PORTING file for some |
||||
information, if you fancy a challenge. :) |
||||
|
||||
libusb homepage: |
||||
http://libusb.org/ |
||||
|
||||
Developers will wish to consult the API documentation: |
||||
http://libusb.sourceforge.net/api-1.0/ |
||||
|
||||
Use the mailing list for questions, comments, etc: |
||||
http://libusb.org/wiki/MailingList |
||||
|
||||
- Peter Stuge <peter@stuge.se> |
||||
(use the mailing list rather than mailing developers directly) |
@ -1,8 +0,0 @@
@@ -1,8 +0,0 @@
|
||||
Development contributors are listed in the AUTHORS file. Other community |
||||
members who have made significant contributions in other areas are listed |
||||
in this file: |
||||
|
||||
Alan Stern |
||||
Ludovic Rousseau |
||||
Tim Roberts |
||||
Xiaofan Chen |
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
for 1.1 or future |
||||
================== |
||||
optional timerfd support (runtime detection) |
||||
notifications of hotplugged/unplugged devices |
||||
offer API to create/destroy handle_events thread |
||||
isochronous sync I/O? |
||||
exposing of parent-child device relationships |
||||
"usb primer" introduction docs |
||||
more examples |
@ -1,229 +0,0 @@
@@ -1,229 +0,0 @@
|
||||
dnl These m4 macros are whitespace sensitive and break if moved around much. |
||||
m4_define([LU_VERSION_H], m4_include([libusb/version.h])) |
||||
m4_define([LU_DEFINE_VERSION_ATOM], |
||||
[m4_define([$1], m4_bregexp(LU_VERSION_H, |
||||
[^#define\s*$1\s*\([0-9]*\).*], [\1]))]) |
||||
m4_define([LU_DEFINE_VERSION_RC_ATOM], |
||||
[m4_define([$1], m4_bregexp(LU_VERSION_H, |
||||
[^#define\s*$1\s*"\(-rc[0-9]*\)".*], [\1]))]) |
||||
dnl The m4_bregexp() returns (only) the numbers following the #define named |
||||
dnl in the first macro parameter. m4_define() then defines the name for use |
||||
dnl in AC_INIT(). |
||||
|
||||
LU_DEFINE_VERSION_ATOM([LIBUSB_MAJOR]) |
||||
LU_DEFINE_VERSION_ATOM([LIBUSB_MINOR]) |
||||
LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO]) |
||||
LU_DEFINE_VERSION_RC_ATOM([LIBUSB_RC]) |
||||
|
||||
AC_INIT([libusb], LIBUSB_MAJOR[.]LIBUSB_MINOR[.]LIBUSB_MICRO[]LIBUSB_RC, [libusb-devel@lists.sourceforge.net], [libusb], [http://www.libusb.org/]) |
||||
|
||||
# Library versioning |
||||
# These numbers should be tweaked on every release. Read carefully: |
||||
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html |
||||
# http://sourceware.org/autobook/autobook/autobook_91.html |
||||
lt_current="2" |
||||
lt_revision="0" |
||||
lt_age="0" |
||||
LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}" |
||||
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects]) |
||||
AM_MAINTAINER_MODE |
||||
|
||||
AC_CONFIG_SRCDIR([libusb/core.c]) |
||||
AC_CONFIG_MACRO_DIR([m4]) |
||||
AC_CONFIG_HEADERS([config.h]) |
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) |
||||
|
||||
AC_PREREQ([2.50]) |
||||
AC_PROG_CC |
||||
AC_PROG_LIBTOOL |
||||
LT_LANG([Windows Resource]) |
||||
AC_C_INLINE |
||||
AM_PROG_CC_C_O |
||||
AC_DEFINE([_GNU_SOURCE], 1, [Use GNU extensions]) |
||||
|
||||
LTLDFLAGS="${LTLDFLAGS} -no-undefined" |
||||
|
||||
AC_MSG_CHECKING([operating system]) |
||||
case $host in |
||||
*-linux*) |
||||
AC_MSG_RESULT([Linux]) |
||||
backend="linux" |
||||
;; |
||||
*-darwin*) |
||||
AC_MSG_RESULT([Darwin/Mac OS X]) |
||||
backend="darwin" |
||||
;; |
||||
*-openbsd*) |
||||
AC_MSG_RESULT([OpenBSD]) |
||||
backend="openbsd" |
||||
;; |
||||
*-netbsd*) |
||||
AC_MSG_RESULT([NetBSD (using OpenBSD backend)]) |
||||
backend="openbsd" |
||||
;; |
||||
*-mingw*) |
||||
AC_MSG_RESULT([Windows]) |
||||
backend="windows" |
||||
;; |
||||
*-cygwin*) |
||||
AC_MSG_RESULT([Cygwin (using Windows backend)]) |
||||
backend="windows" |
||||
threads="posix" |
||||
;; |
||||
*) |
||||
AC_MSG_ERROR([unsupported operating system]) |
||||
esac |
||||
case $backend in |
||||
linux) |
||||
AC_DEFINE(OS_LINUX, 1, [Linux backend]) |
||||
AC_SUBST(OS_LINUX) |
||||
AC_CHECK_LIB(rt, clock_gettime, -pthread) |
||||
AC_ARG_ENABLE([udev], |
||||
[AC_HELP_STRING([--with-udev], [use udev for device enumeration and hotplug support (recommended, default: yes)])], |
||||
[], [enable_udev="yes"]) |
||||
if test "x$enable_udev" = "xyes" ; then |
||||
# system has udev. use it or fail! |
||||
AC_CHECK_HEADERS([libudev.h],[],[AC_ERROR(["udev support requested but libudev not installed"])]) |
||||
AC_CHECK_LIB([udev], [udev_new], [], [AC_ERROR(["udev support requested but libudev not installed"])]) |
||||
AC_DEFINE(USE_UDEV, 1, [Use udev for device enumeration/hotplug]) |
||||
else |
||||
AC_CHECK_HEADERS([linux/netlink.h linux/filter.h], [], [AC_ERROR(["Linux netlink headers not found"])]) |
||||
fi |
||||
AC_SUBST(USE_UDEV) |
||||
threads="posix" |
||||
THREAD_CFLAGS="-pthread" |
||||
LIBS="${LIBS} -pthread" |
||||
AC_CHECK_HEADERS([poll.h]) |
||||
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument]) |
||||
;; |
||||
darwin) |
||||
AC_DEFINE(OS_DARWIN, 1, [Darwin backend]) |
||||
AC_SUBST(OS_DARWIN) |
||||
threads="posix" |
||||
LIBS="-lobjc -Wl,-framework,IOKit -Wl,-framework,CoreFoundation" |
||||
LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind" |
||||
AC_CHECK_HEADERS([poll.h]) |
||||
AC_CHECK_TYPE([nfds_t], |
||||
[AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])], |
||||
[AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])], |
||||
[#include <poll.h>]) |
||||
;; |
||||
openbsd) |
||||
AC_DEFINE(OS_OPENBSD, 1, [OpenBSD backend]) |
||||
AC_SUBST(OS_OPENBSD) |
||||
threads="posix" |
||||
THREAD_CFLAGS="-pthread" |
||||
LIBS="-pthread" |
||||
AC_CHECK_HEADERS([poll.h]) |
||||
AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument]) |
||||
;; |
||||
windows) |
||||
AC_DEFINE(OS_WINDOWS, 1, [Windows backend]) |
||||
AC_SUBST(OS_WINDOWS) |
||||
LIBS="" |
||||
LTLDFLAGS="${LTLDFLAGS} -avoid-version -Wl,--add-stdcall-alias" |
||||
AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument]) |
||||
;; |
||||
esac |
||||
AC_SUBST(LIBS) |
||||
|
||||
AM_CONDITIONAL(OS_LINUX, test "x$backend" = xlinux) |
||||
AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin) |
||||
AM_CONDITIONAL(OS_OPENBSD, test "x$backend" = xopenbsd) |
||||
AM_CONDITIONAL(OS_WINDOWS, test "x$backend" = xwindows) |
||||
AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix) |
||||
AM_CONDITIONAL(USE_UDEV, test "x$enable_udev" = xyes) |
||||
if test "$threads" = posix; then |
||||
AC_DEFINE(THREADS_POSIX, 1, [Use POSIX Threads]) |
||||
fi |
||||
|
||||
# timerfd |
||||
AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=1], [timerfd_h=0]) |
||||
AC_ARG_ENABLE([timerfd], |
||||
[AS_HELP_STRING([--enable-timerfd], |
||||
[use timerfd for timing (default auto)])], |
||||
[use_timerfd=$enableval], [use_timerfd='auto']) |
||||
|
||||
if test "x$use_timerfd" = "xyes" -a "x$timerfd_h" = "x0"; then |
||||
AC_MSG_ERROR([timerfd header not available; glibc 2.9+ required]) |
||||
fi |
||||
|
||||
AC_CHECK_DECL([TFD_NONBLOCK], [tfd_hdr_ok=yes], [tfd_hdr_ok=no], [#include <sys/timerfd.h>]) |
||||
if test "x$use_timerfd" = "xyes" -a "x$tfd_hdr_ok" = "xno"; then |
||||
AC_MSG_ERROR([timerfd header not usable; glibc 2.9+ required]) |
||||
fi |
||||
|
||||
AC_MSG_CHECKING([whether to use timerfd for timing]) |
||||
if test "x$use_timerfd" = "xno"; then |
||||
AC_MSG_RESULT([no (disabled by user)]) |
||||
else |
||||
if test "x$timerfd_h" = "x1" -a "x$tfd_hdr_ok" = "xyes"; then |
||||
AC_MSG_RESULT([yes]) |
||||
AC_DEFINE(USBI_TIMERFD_AVAILABLE, 1, [timerfd headers available]) |
||||
else |
||||
AC_MSG_RESULT([no (header not available)]) |
||||
fi |
||||
fi |
||||
|
||||
AC_CHECK_TYPES(struct timespec) |
||||
|
||||
# Message logging |
||||
AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])], |
||||
[log_enabled=$enableval], |
||||
[log_enabled='yes']) |
||||
if test "x$log_enabled" != "xno"; then |
||||
AC_DEFINE([ENABLE_LOGGING], 1, [Message logging]) |
||||
fi |
||||
|
||||
AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log], |
||||
[enable debug logging (default n)])], |
||||
[debug_log_enabled=$enableval], |
||||
[debug_log_enabled='no']) |
||||
if test "x$debug_log_enabled" != "xno"; then |
||||
AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Debug message logging]) |
||||
fi |
||||
|
||||
# Examples build |
||||
AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build], |
||||
[build example applications (default n)])], |
||||
[build_examples=$enableval], |
||||
[build_examples='no']) |
||||
AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"]) |
||||
|
||||
# check for -fvisibility=hidden compiler support (GCC >= 3.4) |
||||
saved_cflags="$CFLAGS" |
||||
# -Werror required for cygwin |
||||
CFLAGS="$CFLAGS -Werror -fvisibility=hidden" |
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], |
||||
[VISIBILITY_CFLAGS="-fvisibility=hidden" |
||||
AC_DEFINE([DEFAULT_VISIBILITY], [__attribute__((visibility("default")))], [Default visibility]) ], |
||||
[ VISIBILITY_CFLAGS="" |
||||
AC_DEFINE([DEFAULT_VISIBILITY], [], [Default visibility]) ], |
||||
]) |
||||
CFLAGS="$saved_cflags" |
||||
|
||||
# check for -Wno-pointer-sign compiler support (GCC >= 4) |
||||
saved_cflags="$CFLAGS" |
||||
CFLAGS="$CFLAGS -Wno-pointer-sign" |
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], |
||||
nopointersign_cflags="-Wno-pointer-sign", nopointersign_cflags="") |
||||
CFLAGS="$saved_cflags" |
||||
|
||||
# sigaction not available on MinGW |
||||
AC_CHECK_FUNC([sigaction], [have_sigaction=yes], [have_sigaction=no]) |
||||
AM_CONDITIONAL([HAVE_SIGACTION], [test "x$have_sigaction" = "xyes"]) |
||||
|
||||
# headers not available on all platforms but required on others |
||||
AC_CHECK_HEADERS([sys/time.h]) |
||||
AC_CHECK_FUNCS(gettimeofday) |
||||
|
||||
AM_CFLAGS="-std=gnu99 -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow ${THREAD_CFLAGS} ${VISIBILITY_CFLAGS}" |
||||
|
||||
AC_SUBST(AM_CFLAGS) |
||||
AC_SUBST(LTLDFLAGS) |
||||
|
||||
AC_CONFIG_FILES([libusb-1.0.pc]) |
||||
AC_CONFIG_FILES([Makefile]) |
||||
AC_CONFIG_FILES([libusb/Makefile]) |
||||
AC_OUTPUT |
@ -1,12 +0,0 @@
@@ -1,12 +0,0 @@
|
||||
prefix=@prefix@ |
||||
exec_prefix=@exec_prefix@ |
||||
libdir=@libdir@ |
||||
includedir=@includedir@ |
||||
|
||||
Name: libusb-1.0 |
||||
Description: C API for USB device access from Linux, Mac OS X, OpenBSD, NetBSD and Windows userspace |
||||
Version: @VERSION@ |
||||
Libs: -L${libdir} -lusb-1.0 |
||||
Libs.private: @LIBS@ |
||||
Cflags: -I${includedir}/libusb-1.0 |
||||
|
@ -1,55 +0,0 @@
@@ -1,55 +0,0 @@
|
||||
lib_LTLIBRARIES = libusb-1.0.la |
||||
|
||||
LINUX_USBFS_SRC = os/linux_usbfs.c |
||||
DARWIN_USB_SRC = os/darwin_usb.c |
||||
OPENBSD_USB_SRC = os/openbsd_usb.c |
||||
WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc \
|
||||
libusb-1.0.def |
||||
|
||||
EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(OPENBSD_USB_SRC) \
|
||||
$(WINDOWS_USB_SRC) os/threads_posix.c os/threads_windows.c \
|
||||
os/linux_udev.c os/linux_netlink.c |
||||
|
||||
if OS_LINUX |
||||
|
||||
if USE_UDEV |
||||
OS_SRC = $(LINUX_USBFS_SRC) os/linux_udev.c |
||||
else |
||||
OS_SRC = $(LINUX_USBFS_SRC) os/linux_netlink.c |
||||
endif |
||||
|
||||
endif |
||||
|
||||
if OS_DARWIN |
||||
OS_SRC = $(DARWIN_USB_SRC) |
||||
AM_CFLAGS_EXT = -no-cpp-precomp |
||||
endif |
||||
|
||||
if OS_OPENBSD |
||||
OS_SRC = $(OPENBSD_USB_SRC) |
||||
endif |
||||
|
||||
if OS_WINDOWS |
||||
OS_SRC = $(WINDOWS_USB_SRC) |
||||
|
||||
.rc.lo: |
||||
$(AM_V_GEN)$(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ |
||||
|
||||
libusb-1.0.rc: version.h |
||||
endif |
||||
|
||||
if THREADS_POSIX |
||||
THREADS_SRC = os/threads_posix.h os/threads_posix.c |
||||
else |
||||
THREADS_SRC = os/threads_windows.h os/threads_windows.c |
||||
endif |
||||
|
||||
libusb_1_0_la_CFLAGS = $(AM_CFLAGS) \
|
||||
-DLIBUSB_DESCRIBE=\"`git --git-dir "$(top_srcdir)/.git" describe --tags 2>/dev/null`\" |
||||
libusb_1_0_la_LDFLAGS = $(LTLDFLAGS) |
||||
libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \
|
||||
hotplug.h hotplug.c os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \
|
||||
$(THREADS_SRC) os/poll_posix.h os/poll_windows.h |
||||
|
||||
hdrdir = $(includedir)/libusb-1.0 |
||||
hdr_HEADERS = libusb.h |
File diff suppressed because it is too large
Load Diff
@ -1,872 +0,0 @@
@@ -1,872 +0,0 @@
|
||||
/*
|
||||
* USB descriptor handling functions for libusb |
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> |
||||
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> |
||||
* Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@cs.unm.edu> |
||||
* |
||||
* 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 <errno.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <assert.h> |
||||
|
||||
#include "libusbi.h" |
||||
|
||||
#define DESC_HEADER_LENGTH 2 |
||||
#define DEVICE_DESC_LENGTH 18 |
||||
#define CONFIG_DESC_LENGTH 9 |
||||
#define INTERFACE_DESC_LENGTH 9 |
||||
#define ENDPOINT_DESC_LENGTH 7 |
||||
#define ENDPOINT_AUDIO_DESC_LENGTH 9 |
||||
|
||||
/** @defgroup desc USB descriptors
|
||||
* This page details how to examine the various standard USB descriptors |
||||
* for detected devices |
||||
*/ |
||||
|
||||
/* set host_endian if the w values are already in host endian format,
|
||||
* as opposed to bus endian. */ |
||||
int usbi_parse_descriptor(const unsigned char *source, const char *descriptor, |
||||
void *dest, int host_endian) |
||||
{ |
||||
const unsigned char *sp = source; |
||||
unsigned char *dp = dest; |
||||
uint16_t w; |
||||
const char *cp; |
||||
uint32_t d; |
||||
|
||||
for (cp = descriptor; *cp; cp++) { |
||||
switch (*cp) { |
||||
case 'b': /* 8-bit byte */ |
||||
*dp++ = *sp++; |
||||
break; |
||||
case 'w': /* 16-bit word, convert from little endian to CPU */ |
||||
dp += ((uintptr_t)dp & 1); /* Align to word boundary */ |
||||
|
||||
if (host_endian) { |
||||
memcpy(dp, sp, 2); |
||||
} else { |
||||
w = (sp[1] << 8) | sp[0]; |
||||
*((uint16_t *)dp) = w; |
||||
} |
||||
sp += 2; |
||||
dp += 2; |
||||
break; |
||||
/* 32-bit word, convert from little endian to CPU */ |
||||
case 'd': |
||||
/* Align to word boundary */ |
||||
dp += ((unsigned long)dp & 1); |
||||
|
||||
if (host_endian) { |
||||
memcpy(dp, sp, 4); |
||||
} else { |
||||
d = (sp[3] << 24) | (sp[2] << 16) | |
||||
(sp[1] << 8) | sp[0]; |
||||
*((uint32_t *)dp) = d; |
||||
} |
||||
sp += 4; |
||||
dp += 4; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return (int) (sp - source); |
||||
} |
||||
|
||||
static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) |
||||
{ |
||||
if (endpoint->extra) |
||||
free((unsigned char *) endpoint->extra); |
||||
} |
||||
|
||||
static int parse_endpoint(struct libusb_context *ctx, |
||||
struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, |
||||
int size, int host_endian) |
||||
{ |
||||
struct usb_descriptor_header header; |
||||
unsigned char *extra; |
||||
unsigned char *begin; |
||||
int parsed = 0; |
||||
int len; |
||||
|
||||
usbi_parse_descriptor(buffer, "bb", &header, 0); |
||||
|
||||
/* Everything should be fine being passed into here, but we sanity */ |
||||
/* check JIC */ |
||||
if (header.bLength > size) { |
||||
usbi_err(ctx, "ran out of descriptors parsing"); |
||||
return -1; |
||||
} |
||||
|
||||
if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) { |
||||
usbi_err(ctx, "unexpected descriptor %x (expected %x)", |
||||
header.bDescriptorType, LIBUSB_DT_ENDPOINT); |
||||
return parsed; |
||||
} |
||||
|
||||
if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) |
||||
usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian); |
||||
else if (header.bLength >= ENDPOINT_DESC_LENGTH) |
||||
usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian); |
||||
|
||||
buffer += header.bLength; |
||||
size -= header.bLength; |
||||
parsed += header.bLength; |
||||
|
||||
/* Skip over the rest of the Class Specific or Vendor Specific */ |
||||
/* descriptors */ |
||||
begin = buffer; |
||||
while (size >= DESC_HEADER_LENGTH) { |
||||
usbi_parse_descriptor(buffer, "bb", &header, 0); |
||||
|
||||
if (header.bLength < 2) { |
||||
usbi_err(ctx, "invalid descriptor length %d", header.bLength); |
||||
return -1; |
||||
} |
||||
|
||||
/* If we find another "proper" descriptor then we're done */ |
||||
if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || |
||||
(header.bDescriptorType == LIBUSB_DT_INTERFACE) || |
||||
(header.bDescriptorType == LIBUSB_DT_CONFIG) || |
||||
(header.bDescriptorType == LIBUSB_DT_DEVICE)) |
||||
break; |
||||
|
||||
usbi_dbg("skipping descriptor %x", header.bDescriptorType); |
||||
buffer += header.bLength; |
||||
size -= header.bLength; |
||||
parsed += header.bLength; |
||||
} |
||||
|
||||
/* Copy any unknown descriptors into a storage area for drivers */ |
||||
/* to later parse */ |
||||
len = (int)(buffer - begin); |
||||
if (!len) { |
||||
endpoint->extra = NULL; |
||||
endpoint->extra_length = 0; |
||||
return parsed; |
||||
} |
||||
|
||||
extra = malloc(len); |
||||
endpoint->extra = extra; |
||||
if (!extra) { |
||||
endpoint->extra_length = 0; |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
} |
||||
|
||||
memcpy(extra, begin, len); |
||||
endpoint->extra_length = len; |
||||
|
||||
return parsed; |
||||
} |
||||
|
||||
static void clear_interface(struct libusb_interface *usb_interface) |
||||
{ |
||||
int i; |
||||
int j; |
||||
|
||||
if (usb_interface->altsetting) { |
||||
for (i = 0; i < usb_interface->num_altsetting; i++) { |
||||
struct libusb_interface_descriptor *ifp = |
||||
(struct libusb_interface_descriptor *) |
||||
usb_interface->altsetting + i; |
||||
if (ifp->extra) |
||||
free((void *) ifp->extra); |
||||
if (ifp->endpoint) { |
||||
for (j = 0; j < ifp->bNumEndpoints; j++) |
||||
clear_endpoint((struct libusb_endpoint_descriptor *) |
||||
ifp->endpoint + j); |
||||
free((void *) ifp->endpoint); |
||||
} |
||||
} |
||||
free((void *) usb_interface->altsetting); |
||||
usb_interface->altsetting = NULL; |
||||
} |
||||
|
||||
} |
||||
|
||||
static int parse_interface(libusb_context *ctx, |
||||
struct libusb_interface *usb_interface, unsigned char *buffer, int size, |
||||
int host_endian) |
||||
{ |
||||
int i; |
||||
int len; |
||||
int r; |
||||
int parsed = 0; |
||||
size_t tmp; |
||||
struct usb_descriptor_header header; |
||||
struct libusb_interface_descriptor *ifp; |
||||
unsigned char *begin; |
||||
|
||||
usb_interface->num_altsetting = 0; |
||||
|
||||
while (size >= INTERFACE_DESC_LENGTH) { |
||||
struct libusb_interface_descriptor *altsetting = |
||||
(struct libusb_interface_descriptor *) usb_interface->altsetting; |
||||
altsetting = realloc(altsetting, |
||||
sizeof(struct libusb_interface_descriptor) * |
||||
(usb_interface->num_altsetting + 1)); |
||||
if (!altsetting) { |
||||
r = LIBUSB_ERROR_NO_MEM; |
||||
goto err; |
||||
} |
||||
usb_interface->altsetting = altsetting; |
||||
|
||||
ifp = altsetting + usb_interface->num_altsetting; |
||||
usb_interface->num_altsetting++; |
||||
usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0); |
||||
ifp->extra = NULL; |
||||
ifp->extra_length = 0; |
||||
ifp->endpoint = NULL; |
||||
|
||||
/* Skip over the interface */ |
||||
buffer += ifp->bLength; |
||||
parsed += ifp->bLength; |
||||
size -= ifp->bLength; |
||||
|
||||
begin = buffer; |
||||
|
||||
/* Skip over any interface, class or vendor descriptors */ |
||||
while (size >= DESC_HEADER_LENGTH) { |
||||
usbi_parse_descriptor(buffer, "bb", &header, 0); |
||||
if (header.bLength < 2) { |
||||
usbi_err(ctx, "invalid descriptor of length %d", |
||||
header.bLength); |
||||
r = LIBUSB_ERROR_IO; |
||||
goto err; |
||||
} |
||||
|
||||
/* If we find another "proper" descriptor then we're done */ |
||||
if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) || |
||||
(header.bDescriptorType == LIBUSB_DT_ENDPOINT) || |
||||
(header.bDescriptorType == LIBUSB_DT_CONFIG) || |
||||
(header.bDescriptorType == LIBUSB_DT_DEVICE) || |
||||
(header.bDescriptorType == |
||||
LIBUSB_DT_SS_ENDPOINT_COMPANION)) |
||||
break; |
||||
|
||||
buffer += header.bLength; |
||||
parsed += header.bLength; |
||||
size -= header.bLength; |
||||
} |
||||
|
||||
/* Copy any unknown descriptors into a storage area for */ |
||||
/* drivers to later parse */ |
||||
len = (int)(buffer - begin); |
||||
if (len) { |
||||
ifp->extra = malloc(len); |
||||
if (!ifp->extra) { |
||||
r = LIBUSB_ERROR_NO_MEM; |
||||
goto err; |
||||
} |
||||
memcpy((unsigned char *) ifp->extra, begin, len); |
||||
ifp->extra_length = len; |
||||
} |
||||
|
||||
/* Did we hit an unexpected descriptor? */ |
||||
if (size >= DESC_HEADER_LENGTH) { |
||||
usbi_parse_descriptor(buffer, "bb", &header, 0); |
||||
if ((header.bDescriptorType == LIBUSB_DT_CONFIG) || |
||||
(header.bDescriptorType == LIBUSB_DT_DEVICE)) { |
||||
return parsed; |
||||
} |
||||
} |
||||
|
||||
if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { |
||||
usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints); |
||||
r = LIBUSB_ERROR_IO; |
||||
goto err; |
||||
} |
||||
|
||||
if (ifp->bNumEndpoints > 0) { |
||||
struct libusb_endpoint_descriptor *endpoint; |
||||
tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor); |
||||
endpoint = malloc(tmp); |
||||
ifp->endpoint = endpoint; |
||||
if (!endpoint) { |
||||
r = LIBUSB_ERROR_NO_MEM; |
||||
goto err; |
||||
} |
||||
|
||||
memset(endpoint, 0, tmp); |
||||
for (i = 0; i < ifp->bNumEndpoints; i++) { |
||||
usbi_parse_descriptor(buffer, "bb", &header, 0); |
||||
|
||||
if (header.bLength > size) { |
||||
usbi_err(ctx, "ran out of descriptors parsing"); |
||||
r = LIBUSB_ERROR_IO; |
||||
goto err; |
||||
} |
||||
|
||||
r = parse_endpoint(ctx, endpoint + i, buffer, size, |
||||
host_endian); |
||||
if (r < 0) |
||||
goto err; |
||||
|
||||
buffer += r; |
||||
parsed += r; |
||||
size -= r; |
||||
} |
||||
} |
||||
|
||||
/* We check to see if it's an alternate to this one */ |
||||
ifp = (struct libusb_interface_descriptor *) buffer; |
||||
if (size < LIBUSB_DT_INTERFACE_SIZE || |
||||
ifp->bDescriptorType != LIBUSB_DT_INTERFACE || |
||||
!ifp->bAlternateSetting) |
||||
return parsed; |
||||
} |
||||
|
||||
return parsed; |
||||
err: |
||||
clear_interface(usb_interface); |
||||
return r; |
||||
} |
||||
|
||||
static void clear_configuration(struct libusb_config_descriptor *config) |
||||
{ |
||||
if (config->interface) { |
||||
int i; |
||||
for (i = 0; i < config->bNumInterfaces; i++) |
||||
clear_interface((struct libusb_interface *) |
||||
config->interface + i); |
||||
free((void *) config->interface); |
||||
} |
||||
if (config->extra) |
||||
free((void *) config->extra); |
||||
} |
||||
|
||||
static int parse_configuration(struct libusb_context *ctx, |
||||
struct libusb_config_descriptor *config, unsigned char *buffer, |
||||
int host_endian) |
||||
{ |
||||
int i; |
||||
int r; |
||||
int size; |
||||
size_t tmp; |
||||
struct usb_descriptor_header header; |
||||
struct libusb_interface *usb_interface; |
||||
|
||||
usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian); |
||||
size = config->wTotalLength; |
||||
|
||||
if (config->bNumInterfaces > USB_MAXINTERFACES) { |
||||
usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces); |
||||
return LIBUSB_ERROR_IO; |
||||
} |
||||
|
||||
tmp = config->bNumInterfaces * sizeof(struct libusb_interface); |
||||
usb_interface = malloc(tmp); |
||||
config->interface = usb_interface; |
||||
if (!config->interface) |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
|
||||
memset(usb_interface, 0, tmp); |
||||
buffer += config->bLength; |
||||
size -= config->bLength; |
||||
|
||||
config->extra = NULL; |
||||
config->extra_length = 0; |
||||
|
||||
for (i = 0; i < config->bNumInterfaces; i++) { |
||||
int len; |
||||
unsigned char *begin; |
||||
|
||||
/* Skip over the rest of the Class Specific or Vendor */ |
||||
/* Specific descriptors */ |
||||
begin = buffer; |
||||
while (size >= DESC_HEADER_LENGTH) { |
||||
usbi_parse_descriptor(buffer, "bb", &header, 0); |
||||
|
||||
if ((header.bLength > size) || |
||||
(header.bLength < DESC_HEADER_LENGTH)) { |
||||
usbi_err(ctx, "invalid descriptor length of %d", |
||||
header.bLength); |
||||
r = LIBUSB_ERROR_IO; |
||||
goto err; |
||||
} |
||||
|
||||
/* If we find another "proper" descriptor then we're done */ |
||||
if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || |
||||
(header.bDescriptorType == LIBUSB_DT_INTERFACE) || |
||||
(header.bDescriptorType == LIBUSB_DT_CONFIG) || |
||||
(header.bDescriptorType == LIBUSB_DT_DEVICE) || |
||||
(header.bDescriptorType == |
||||
LIBUSB_DT_SS_ENDPOINT_COMPANION)) |
||||
break; |
||||
|
||||
usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType); |
||||
buffer += header.bLength; |
||||
size -= header.bLength; |
||||
} |
||||
|
||||
/* Copy any unknown descriptors into a storage area for */ |
||||
/* drivers to later parse */ |
||||
len = (int)(buffer - begin); |
||||
if (len) { |
||||
/* FIXME: We should realloc and append here */ |
||||
if (!config->extra_length) { |
||||
config->extra = malloc(len); |
||||
if (!config->extra) { |
||||
r = LIBUSB_ERROR_NO_MEM; |
||||
goto err; |
||||
} |
||||
|
||||
memcpy((unsigned char *) config->extra, begin, len); |
||||
config->extra_length = len; |
||||
} |
||||
} |
||||
|
||||
r = parse_interface(ctx, usb_interface + i, buffer, size, host_endian); |
||||
if (r < 0) |
||||
goto err; |
||||
|
||||
buffer += r; |
||||
size -= r; |
||||
} |
||||
|
||||
return size; |
||||
|
||||
err: |
||||
clear_configuration(config); |
||||
return r; |
||||
} |
||||
|
||||
int usbi_device_cache_descriptor(libusb_device *dev) |
||||
{ |
||||
int r, host_endian; |
||||
|
||||
r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor, |
||||
&host_endian); |
||||
if (r < 0) |
||||
return r; |
||||
|
||||
if (!host_endian) { |
||||
dev->device_descriptor.bcdUSB = libusb_le16_to_cpu(dev->device_descriptor.bcdUSB); |
||||
dev->device_descriptor.idVendor = libusb_le16_to_cpu(dev->device_descriptor.idVendor); |
||||
dev->device_descriptor.idProduct = libusb_le16_to_cpu(dev->device_descriptor.idProduct); |
||||
dev->device_descriptor.bcdDevice = libusb_le16_to_cpu(dev->device_descriptor.bcdDevice); |
||||
} |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
/** \ingroup desc
|
||||
* Get the USB device descriptor for a given device. |
||||
* |
||||
* This is a non-blocking function; the device descriptor is cached in memory. |
||||
* |
||||
* \param dev the device |
||||
* \param desc output location for the descriptor data |
||||
* \returns 0 on success or a LIBUSB_ERROR code on failure |
||||
*/ |
||||
int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, |
||||
struct libusb_device_descriptor *desc) |
||||
{ |
||||
usbi_dbg(""); |
||||
memcpy((unsigned char *) desc, (unsigned char *) &dev->device_descriptor, |
||||
sizeof (dev->device_descriptor)); |
||||
return 0; |
||||
} |
||||
|
||||
/** \ingroup desc
|
||||
* Get the USB configuration descriptor for the currently active configuration. |
||||
* This is a non-blocking function which does not involve any requests being |
||||
* sent to the device. |
||||
* |
||||
* \param dev a device |
||||
* \param config output location for the USB configuration descriptor. Only |
||||
* valid if 0 was returned. Must be freed with libusb_free_config_descriptor() |
||||
* after use. |
||||
* \returns 0 on success |
||||
* \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state |
||||
* \returns another LIBUSB_ERROR code on error |
||||
* \see libusb_get_config_descriptor |
||||
*/ |
||||
int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, |
||||
struct libusb_config_descriptor **config) |
||||
{ |
||||
struct libusb_config_descriptor *_config = malloc(sizeof(*_config)); |
||||
unsigned char tmp[8]; |
||||
unsigned char *buf = NULL; |
||||
int host_endian = 0; |
||||
int r; |
||||
|
||||
usbi_dbg(""); |
||||
if (!_config) |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
|
||||
r = usbi_backend->get_active_config_descriptor(dev, tmp, sizeof(tmp), |
||||
&host_endian); |
||||
if (r < 0) |
||||
goto err; |
||||
|
||||
usbi_parse_descriptor(tmp, "bbw", _config, host_endian); |
||||
buf = malloc(_config->wTotalLength); |
||||
if (!buf) { |
||||
r = LIBUSB_ERROR_NO_MEM; |
||||
goto err; |
||||
} |
||||
|
||||
r = usbi_backend->get_active_config_descriptor(dev, buf, |
||||
_config->wTotalLength, &host_endian); |
||||
if (r < 0) |
||||
goto err; |
||||
|
||||
r = parse_configuration(dev->ctx, _config, buf, host_endian); |
||||
if (r < 0) { |
||||
usbi_err(dev->ctx, "parse_configuration failed with error %d", r); |
||||
goto err; |
||||
} else if (r > 0) { |
||||
usbi_warn(dev->ctx, "descriptor data still left"); |
||||
} |
||||
|
||||
free(buf); |
||||
*config = _config; |
||||
return 0; |
||||
|
||||
err: |
||||
free(_config); |
||||
if (buf) |
||||
free(buf); |
||||
return r; |
||||
} |
||||
|
||||
/** \ingroup desc
|
||||
* Get a USB configuration descriptor based on its index. |
||||
* This is a non-blocking function which does not involve any requests being |
||||
* sent to the device. |
||||
* |
||||
* \param dev a device |
||||
* \param config_index the index of the configuration you wish to retrieve |
||||
* \param config output location for the USB configuration descriptor. Only |
||||
* valid if 0 was returned. Must be freed with libusb_free_config_descriptor() |
||||
* after use. |
||||
* \returns 0 on success |
||||
* \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
||||
* \returns another LIBUSB_ERROR code on error |
||||
* \see libusb_get_active_config_descriptor() |
||||
* \see libusb_get_config_descriptor_by_value() |
||||
*/ |
||||
int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, |
||||
uint8_t config_index, struct libusb_config_descriptor **config) |
||||
{ |
||||
struct libusb_config_descriptor *_config; |
||||
unsigned char tmp[8]; |
||||
unsigned char *buf = NULL; |
||||
int host_endian = 0; |
||||
int r; |
||||
|
||||
usbi_dbg("index %d", config_index); |
||||
if (config_index >= dev->num_configurations) |
||||
return LIBUSB_ERROR_NOT_FOUND; |
||||
|
||||
_config = malloc(sizeof(*_config)); |
||||
if (!_config) |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
|
||||
r = usbi_backend->get_config_descriptor(dev, config_index, tmp, |
||||
sizeof(tmp), &host_endian); |
||||
if (r < 0) |
||||
goto err; |
||||
|
||||
usbi_parse_descriptor(tmp, "bbw", _config, host_endian); |
||||
buf = malloc(_config->wTotalLength); |
||||
if (!buf) { |
||||
r = LIBUSB_ERROR_NO_MEM; |
||||
goto err; |
||||
} |
||||
|
||||
host_endian = 0; |
||||
r = usbi_backend->get_config_descriptor(dev, config_index, buf, |
||||
_config->wTotalLength, &host_endian); |
||||
if (r < 0) |
||||
goto err; |
||||
|
||||
r = parse_configuration(dev->ctx, _config, buf, host_endian); |
||||
if (r < 0) { |
||||
usbi_err(dev->ctx, "parse_configuration failed with error %d", r); |
||||
goto err; |
||||
} else if (r > 0) { |
||||
usbi_warn(dev->ctx, "descriptor data still left"); |
||||
} |
||||
|
||||
free(buf); |
||||
*config = _config; |
||||
return 0; |
||||
|
||||
err: |
||||
free(_config); |
||||
if (buf) |
||||
free(buf); |
||||
return r; |
||||
} |
||||
|
||||
/* iterate through all configurations, returning the index of the configuration
|
||||
* matching a specific bConfigurationValue in the idx output parameter, or -1 |
||||
* if the config was not found. |
||||
* returns 0 or a LIBUSB_ERROR code |
||||
*/ |
||||
int usbi_get_config_index_by_value(struct libusb_device *dev, |
||||
uint8_t bConfigurationValue, int *idx) |
||||
{ |
||||
uint8_t i; |
||||
|
||||
usbi_dbg("value %d", bConfigurationValue); |
||||
for (i = 0; i < dev->num_configurations; i++) { |
||||
unsigned char tmp[6]; |
||||
int host_endian; |
||||
int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp), |
||||
&host_endian); |
||||
if (r < 0) |
||||
return r; |
||||
if (tmp[5] == bConfigurationValue) { |
||||
*idx = i; |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
*idx = -1; |
||||
return 0; |
||||
} |
||||
|
||||
/** \ingroup desc
|
||||
* Get a USB configuration descriptor with a specific bConfigurationValue. |
||||
* This is a non-blocking function which does not involve any requests being |
||||
* sent to the device. |
||||
* |
||||
* \param dev a device |
||||
* \param bConfigurationValue the bConfigurationValue of the configuration you |
||||
* wish to retrieve |
||||
* \param config output location for the USB configuration descriptor. Only |
||||
* valid if 0 was returned. Must be freed with libusb_free_config_descriptor() |
||||
* after use. |
||||
* \returns 0 on success |
||||
* \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
||||
* \returns another LIBUSB_ERROR code on error |
||||
* \see libusb_get_active_config_descriptor() |
||||
* \see libusb_get_config_descriptor() |
||||
*/ |
||||
int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, |
||||
uint8_t bConfigurationValue, struct libusb_config_descriptor **config) |
||||
{ |
||||
int idx; |
||||
int r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx); |
||||
if (r < 0) |
||||
return r; |
||||
else if (idx == -1) |
||||
return LIBUSB_ERROR_NOT_FOUND; |
||||
else |
||||
return libusb_get_config_descriptor(dev, (uint8_t) idx, config); |
||||
} |
||||
|
||||
/** \ingroup desc
|
||||
* Free a configuration descriptor obtained from |
||||
* libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). |
||||
* It is safe to call this function with a NULL config parameter, in which |
||||
* case the function simply returns. |
||||
* |
||||
* \param config the configuration descriptor to free |
||||
*/ |
||||
void API_EXPORTED libusb_free_config_descriptor( |
||||
struct libusb_config_descriptor *config) |
||||
{ |
||||
if (!config) |
||||
return; |
||||
|
||||
clear_configuration(config); |
||||
free(config); |
||||
} |
||||
|
||||
/** \ingroup desc
|
||||
* Retrieve a string descriptor in C style ASCII. |
||||
* |
||||
* Wrapper around libusb_get_string_descriptor(). Uses the first language |
||||
* supported by the device. |
||||
* |
||||
* \param dev a device handle |
||||
* \param desc_index the index of the descriptor to retrieve |
||||
* \param data output buffer for ASCII string descriptor |
||||
* \param length size of data buffer |
||||
* \returns number of bytes returned in data, or LIBUSB_ERROR code on failure |
||||
*/ |
||||
int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev, |
||||
uint8_t desc_index, unsigned char *data, int length) |
||||
{ |
||||
unsigned char tbuf[255]; /* Some devices choke on size > 255 */ |
||||
int r, si, di; |
||||
uint16_t langid; |
||||
|
||||
/* Asking for the zero'th index is special - it returns a string
|
||||
* descriptor that contains all the language IDs supported by the |
||||
* device. Typically there aren't many - often only one. Language |
||||
* IDs are 16 bit numbers, and they start at the third byte in the |
||||
* descriptor. There's also no point in trying to read descriptor 0 |
||||
* with this function. See USB 2.0 specification section 9.6.7 for |
||||
* more information. |
||||
*/ |
||||
|
||||
if (desc_index == 0) |
||||
return LIBUSB_ERROR_INVALID_PARAM; |
||||
|
||||
r = libusb_get_string_descriptor(dev, 0, 0, tbuf, sizeof(tbuf)); |
||||
if (r < 0) |
||||
return r; |
||||
|
||||
if (r < 4) |
||||
return LIBUSB_ERROR_IO; |
||||
|
||||
langid = tbuf[2] | (tbuf[3] << 8); |
||||
|
||||
r = libusb_get_string_descriptor(dev, desc_index, langid, tbuf, |
||||
sizeof(tbuf)); |
||||
if (r < 0) |
||||
return r; |
||||
|
||||
if (tbuf[1] != LIBUSB_DT_STRING) |
||||
return LIBUSB_ERROR_IO; |
||||
|
||||
if (tbuf[0] > r) |
||||
return LIBUSB_ERROR_IO; |
||||
|
||||
for (di = 0, si = 2; si < tbuf[0]; si += 2) { |
||||
if (di >= (length - 1)) |
||||
break; |
||||
|
||||
if (tbuf[si + 1]) /* high byte */ |
||||
data[di++] = '?'; |
||||
else |
||||
data[di++] = tbuf[si]; |
||||
} |
||||
|
||||
data[di] = 0; |
||||
return di; |
||||
} |
||||
|
||||
int API_EXPORTED libusb_parse_ss_endpoint_comp(const void *buf, int len, |
||||
struct libusb_ss_endpoint_companion_descriptor **ep_comp) |
||||
{ |
||||
struct libusb_ss_endpoint_companion_descriptor *ep_comp_desc; |
||||
struct usb_descriptor_header header; |
||||
|
||||
usbi_parse_descriptor(buf, "bb", &header, 0); |
||||
|
||||
/* Everything should be fine being passed into here, but we sanity */ |
||||
/* check JIC */ |
||||
if (header.bLength > len) { |
||||
usbi_err(NULL, "ran out of descriptors parsing"); |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
} |
||||
|
||||
if (header.bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) { |
||||
usbi_err(NULL, "unexpected descriptor %x (expected %x)", |
||||
header.bDescriptorType, LIBUSB_DT_SS_ENDPOINT_COMPANION); |
||||
return LIBUSB_ERROR_INVALID_PARAM; |
||||
} |
||||
|
||||
ep_comp_desc = calloc(1, sizeof (*ep_comp_desc)); |
||||
if (!ep_comp_desc) { |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
} |
||||
|
||||
if (header.bLength >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) |
||||
usbi_parse_descriptor(buf, "bbbbw", ep_comp_desc, 0); |
||||
|
||||
*ep_comp = ep_comp_desc; |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
void API_EXPORTED libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp) |
||||
{ |
||||
assert(ep_comp); |
||||
free(ep_comp); |
||||
} |
||||
|
||||
int API_EXPORTED libusb_parse_bos_descriptor(const void *buf, int len, |
||||
struct libusb_bos_descriptor **bos) |
||||
{ |
||||
const unsigned char *buffer = (const unsigned char *) buf; |
||||
struct libusb_bos_descriptor *bos_desc; |
||||
int i; |
||||
|
||||
len = len; |
||||
bos_desc = calloc (1, sizeof (*bos_desc)); |
||||
if (!bos_desc) { |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
} |
||||
|
||||
usbi_parse_descriptor(buffer, "bbwb", bos_desc, 0); |
||||
buffer += LIBUSB_DT_BOS_SIZE; |
||||
|
||||
/* Get the device capability descriptors */ |
||||
for (i = 0; i < bos_desc->bNumDeviceCaps; ++i) { |
||||
if (buffer[2] == LIBUSB_USB_CAP_TYPE_EXT) { |
||||
if (!bos_desc->usb_2_0_ext_cap) { |
||||
bos_desc->usb_2_0_ext_cap = |
||||
(struct libusb_usb_2_0_device_capability_descriptor *) |
||||
malloc(sizeof(*bos_desc->usb_2_0_ext_cap)); |
||||
usbi_parse_descriptor(buffer, "bbbd", |
||||
bos_desc->usb_2_0_ext_cap, 0); |
||||
} else |
||||
usbi_warn(NULL, |
||||
"usb_2_0_ext_cap was already allocated"); |
||||
|
||||
/* move to the next device capability descriptor */ |
||||
buffer += LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE; |
||||
} else if (buffer[2] == LIBUSB_SS_USB_CAP_TYPE) { |
||||
if (!bos_desc->ss_usb_cap) { |
||||
bos_desc->ss_usb_cap = |
||||
(struct libusb_ss_usb_device_capability_descriptor *) |
||||
malloc(sizeof(*bos_desc->ss_usb_cap)); |
||||
usbi_parse_descriptor(buffer, "bbbbwbbw", |
||||
bos_desc->ss_usb_cap, 0); |
||||
} else |
||||
usbi_warn(NULL, |
||||
"ss_usb_cap was already allocated"); |
||||
|
||||
/* move to the next device capability descriptor */ |
||||
buffer += LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE; |
||||
} else { |
||||
usbi_info(NULL, "wireless/container_id capability " |
||||
"descriptor"); |
||||
|
||||
/* move to the next device capability descriptor */ |
||||
buffer += buffer[0]; |
||||
} |
||||
} |
||||
|
||||
*bos = bos_desc; |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) |
||||
{ |
||||
assert(bos); |
||||
|
||||
if (bos->usb_2_0_ext_cap) { |
||||
free(bos->usb_2_0_ext_cap); |
||||
} |
||||
|
||||
if (bos->ss_usb_cap) { |
||||
free(bos->ss_usb_cap); |
||||
} |
||||
|
||||
free(bos); |
||||
} |
@ -1,298 +0,0 @@
@@ -1,298 +0,0 @@
|
||||
/* -*- Mode: C; indent-tabs-mode:nil ; c-basic-offset:8 -*- */ |
||||
/*
|
||||
* Hotplug functions for libusb |
||||
* Copyright (C) 2012-2013 Nathan Hjelm <hjelmn@mac.com> |
||||
* Copyright (C) 2012-2013 Peter Stuge <peter@stuge.se> |
||||
* |
||||
* 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 <config.h> |
||||
|
||||
#include <errno.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
#include <assert.h> |
||||
|
||||
#include "libusbi.h" |
||||
#include "hotplug.h" |
||||
|
||||
/**
|
||||
* @defgroup hotplug Device hotplug event notification |
||||
* This page details how to use the libusb hotplug interface. |
||||
* |
||||
* \page hotplug Device hotplug event notification |
||||
* |
||||
* \section intro Introduction |
||||
* |
||||
* Releases of libusb 1.0 newer than 1.X have added support for hotplug |
||||
* events. This interface allows you to request notification for the |
||||
* arrival and departure of matching USB devices. |
||||
* |
||||
* To receive hotplug notification you register a callback by calling |
||||
* libusb_hotplug_register_callback(). This function will optionally return |
||||
* a handle that can be passed to libusb_hotplug_deregister_callback(). |
||||
* |
||||
* A callback function must return an int (0 or 1) indicating whether the callback is |
||||
* expecting additional events. Returning 0 will rearm the callback and 1 will cause |
||||
* the callback to be deregistered. |
||||
* |
||||
* Callbacks for a particulat context are automatically deregistered by libusb_exit(). |
||||
* |
||||
* As of 1.X there are two supported hotplug events: |
||||
* - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: A device has arrived and is ready to use |
||||
* - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: A device has left and is no longer available |
||||
* |
||||
* A hotplug event can listen for either or both of these events. |
||||
* |
||||
* Note: If you receive notification that a device has left and you have any |
||||
* a libusb_device_handles for the device it is up to you to call libusb_close() |
||||
* on each handle to free up any remaining resources associated with the device. |
||||
* Once a device has left any libusb_device_handle associated with the device |
||||
* are invalid and will remain so even if the device comes back. |
||||
* |
||||
* When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered |
||||
* safe to call any libusb function that takes a libusb_device. On the other hand, |
||||
* when handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function |
||||
* is libusb_get_device_descriptor(). |
||||
* |
||||
* The following code provides an example of the usage of the hotplug interface: |
||||
\code |
||||
static int count = 0; |
||||
|
||||
int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, |
||||
libusb_hotplug_event event, void *user_data) { |
||||
static libusb_device_handle *handle = NULL; |
||||
struct libusb_device_descriptor desc; |
||||
int rc; |
||||
|
||||
(void)libusb_get_device_descriptor(dev, &desc); |
||||
|
||||
if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) { |
||||
rc = libusb_open(dev, &handle); |
||||
if (LIBUSB_SUCCESS != rc) { |
||||
printf("Could not open USB device\n"); |
||||
} |
||||
} else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { |
||||
if (handle) { |
||||
libusb_close(handle); |
||||
handle = NULL; |
||||
} |
||||
} else { |
||||
printf("Unhandled event %d\n", event); |
||||
} |
||||
count++; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int main (void) { |
||||
libusb_hotplug_callback_handle handle; |
||||
int rc; |
||||
|
||||
libusb_init(NULL); |
||||
|
||||
rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | |
||||
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, 0x045a, 0x5005, |
||||
LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL, |
||||
&handle); |
||||
if (LIBUSB_SUCCESS != rc) { |
||||
printf("Error creating a hotplug callback\n"); |
||||
libusb_exit(NULL); |
||||
return EXIT_FAILURE; |
||||
} |
||||
|
||||
while (count < 2) { |
||||
usleep(10000); |
||||
} |
||||
|
||||
libusb_hotplug_deregister_callback(handle); |
||||
libusb_exit(NULL); |
||||
|
||||
return 0; |
||||
} |
||||
\endcode |
||||
*/ |
||||
|
||||
static int usbi_hotplug_match_cb (struct libusb_device *dev, libusb_hotplug_event event, |
||||
struct libusb_hotplug_callback *hotplug_cb) { |
||||
struct libusb_context *ctx = dev->ctx; |
||||
|
||||
/* Handle lazy deregistration of callback */ |
||||
if (hotplug_cb->needs_free) { |
||||
/* Free callback */ |
||||
return 1; |
||||
} |
||||
|
||||
if (!(hotplug_cb->events & event)) { |
||||
return 0; |
||||
} |
||||
|
||||
if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id && |
||||
hotplug_cb->vendor_id != dev->device_descriptor.idVendor) { |
||||
return 0; |
||||
} |
||||
|
||||
if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id && |
||||
hotplug_cb->product_id != dev->device_descriptor.idProduct) { |
||||
return 0; |
||||
} |
||||
|
||||
if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class && |
||||
hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) { |
||||
return 0; |
||||
} |
||||
|
||||
return hotplug_cb->cb (ctx == usbi_default_context ? NULL : ctx, |
||||
dev, event, hotplug_cb->user_data); |
||||
} |
||||
|
||||
void usbi_hotplug_match(struct libusb_device *dev, libusb_hotplug_event event) { |
||||
struct libusb_hotplug_callback *hotplug_cb, *next; |
||||
struct libusb_context *ctx = dev->ctx; |
||||
|
||||
usbi_mutex_lock(&ctx->hotplug_cbs_lock); |
||||
|
||||
list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) { |
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock); |
||||
int ret = usbi_hotplug_match_cb (dev, event, hotplug_cb); |
||||
usbi_mutex_lock(&ctx->hotplug_cbs_lock); |
||||
|
||||
if (ret) { |
||||
list_del(&hotplug_cb->list); |
||||
free(hotplug_cb); |
||||
} |
||||
} |
||||
|
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock); |
||||
|
||||
/* loop through and disconnect all open handles for this device */ |
||||
if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) { |
||||
struct libusb_device_handle *handle; |
||||
|
||||
usbi_mutex_lock(&ctx->open_devs_lock); |
||||
list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { |
||||
if (dev == handle->dev) { |
||||
usbi_handle_disconnect (handle); |
||||
} |
||||
} |
||||
usbi_mutex_unlock(&ctx->open_devs_lock); |
||||
} |
||||
} |
||||
|
||||
int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, |
||||
libusb_hotplug_event events, |
||||
libusb_hotplug_flag flags, |
||||
int vendor_id, int product_id, |
||||
int dev_class, |
||||
libusb_hotplug_callback_fn cb_fn, |
||||
void *user_data, libusb_hotplug_callback_handle *handle) { |
||||
libusb_hotplug_callback *new_callback; |
||||
static int handle_id = 1; |
||||
|
||||
/* check for hotplug support */ |
||||
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { |
||||
return LIBUSB_ERROR_NOT_SUPPORTED; |
||||
} |
||||
|
||||
/* check for sane values */ |
||||
if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) || |
||||
(LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) || |
||||
(LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) || |
||||
!cb_fn) { |
||||
return LIBUSB_ERROR_INVALID_PARAM; |
||||
} |
||||
|
||||
USBI_GET_CONTEXT(ctx); |
||||
|
||||
new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback)); |
||||
if (!new_callback) { |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
} |
||||
|
||||
new_callback->ctx = ctx; |
||||
new_callback->vendor_id = vendor_id; |
||||
new_callback->product_id = product_id; |
||||
new_callback->dev_class = dev_class; |
||||
new_callback->flags = flags; |
||||
new_callback->events = events; |
||||
new_callback->cb = cb_fn; |
||||
new_callback->user_data = user_data; |
||||
new_callback->needs_free = 0; |
||||
|
||||
usbi_mutex_lock(&ctx->hotplug_cbs_lock); |
||||
|
||||
/* protect the handle by the context hotplug lock. it doesn't matter if the same handle is used for different
|
||||
contexts only that the handle is unique for this context */ |
||||
new_callback->handle = handle_id++; |
||||
|
||||
list_add(&new_callback->list, &ctx->hotplug_cbs); |
||||
|
||||
if (flags & LIBUSB_HOTPLUG_ENUMERATE) { |
||||
struct libusb_device *dev; |
||||
|
||||
usbi_mutex_lock(&ctx->usb_devs_lock); |
||||
|
||||
list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) { |
||||
(void) usbi_hotplug_match_cb (dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, new_callback); |
||||
} |
||||
|
||||
usbi_mutex_unlock(&ctx->usb_devs_lock); |
||||
} |
||||
|
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock); |
||||
|
||||
if (handle) { |
||||
*handle = new_callback->handle; |
||||
} |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx, libusb_hotplug_callback_handle handle) { |
||||
struct libusb_hotplug_callback *hotplug_cb; |
||||
|
||||
/* check for hotplug support */ |
||||
if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { |
||||
return; |
||||
} |
||||
|
||||
USBI_GET_CONTEXT(ctx); |
||||
|
||||
usbi_mutex_lock(&ctx->hotplug_cbs_lock); |
||||
list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list, |
||||
struct libusb_hotplug_callback) { |
||||
if (handle == hotplug_cb->handle) { |
||||
/* Mark this callback for deregistration */ |
||||
hotplug_cb->needs_free = 1; |
||||
} |
||||
} |
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock); |
||||
} |
||||
|
||||
void usbi_hotplug_deregister_all(struct libusb_context *ctx) { |
||||
struct libusb_hotplug_callback *hotplug_cb, *next; |
||||
|
||||
usbi_mutex_lock(&ctx->hotplug_cbs_lock); |
||||
list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, |
||||
struct libusb_hotplug_callback) { |
||||
list_del(&hotplug_cb->list); |
||||
free(hotplug_cb); |
||||
} |
||||
|
||||
usbi_mutex_unlock(&ctx->hotplug_cbs_lock); |
||||
} |
@ -1,77 +0,0 @@
@@ -1,77 +0,0 @@
|
||||
/* -*- Mode: C; indent-tabs-mode:nil ; c-basic-offset:8 -*- */ |
||||
/*
|
||||
* Hotplug support for libusb 1.0 |
||||
* Copyright (C) 2012 Nathan Hjelm <hjelmn@users.sourceforge.net> |
||||
* Copyright (C) 2012 Peter Stuge <peter@stuge.se> |
||||
* |
||||
* 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 |
||||
*/ |
||||
|
||||
#if !defined(USBI_HOTPLUG_H) |
||||
#define USBI_HOTPLUG_H |
||||
|
||||
/** \ingroup hotplug
|
||||
* The hotplug callback structure. The user populates this structure with |
||||
* libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback() |
||||
* to receive notification of hotplug events. |
||||
*/ |
||||
struct libusb_hotplug_callback { |
||||
/** Context this callback is associated with */ |
||||
struct libusb_context *ctx; |
||||
|
||||
/** Vendor ID to match or LIBUSB_HOTPLUG_MATCH_ANY */ |
||||
int vendor_id; |
||||
|
||||
/** Product ID to match or LIBUSB_HOTPLUG_MATCH_ANY */ |
||||
int product_id; |
||||
|
||||
/** Device class to match or LIBUSB_HOTPLUG_MATCH_ANY */ |
||||
int dev_class; |
||||
|
||||
/** Hotplug callback flags */ |
||||
libusb_hotplug_flag flags; |
||||
|
||||
/** Event(s) that will trigger this callback */ |
||||
libusb_hotplug_event events; |
||||
|
||||
/** Callback function to invoke for matching event/device */ |
||||
libusb_hotplug_callback_fn cb; |
||||
|
||||
/** Handle for this callback (used to match on deregister) */ |
||||
libusb_hotplug_callback_handle handle; |
||||
|
||||
/** User data that will be passed to the callback function */ |
||||
void *user_data; |
||||
|
||||
/** Callback is marked for deletion */ |
||||
int needs_free; |
||||
|
||||
/** List this callback is registered in (ctx->hotplug_cbs) */ |
||||
struct list_head list; |
||||
}; |
||||
|
||||
typedef struct libusb_hotplug_callback libusb_hotplug_callback; |
||||
|
||||
struct libusb_hotplug_message { |
||||
libusb_hotplug_event event; |
||||
struct libusb_device *device; |
||||
}; |
||||
|
||||
typedef struct libusb_hotplug_message libusb_hotplug_message; |
||||
|
||||
void usbi_hotplug_deregister_all(struct libusb_context *ctx); |
||||
void usbi_hotplug_match(struct libusb_device *dev, libusb_hotplug_event event); |
||||
|
||||
#endif |
@ -1,120 +0,0 @@
@@ -1,120 +0,0 @@
|
||||
LIBRARY |
||||
EXPORTS |
||||
libusb_alloc_transfer |
||||
libusb_alloc_transfer@4 = libusb_alloc_transfer |
||||
libusb_attach_kernel_driver |
||||
libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver |
||||
libusb_bulk_transfer |
||||
libusb_bulk_transfer@24 = libusb_bulk_transfer |
||||
libusb_cancel_transfer |
||||
libusb_cancel_transfer@4 = libusb_cancel_transfer |
||||
libusb_claim_interface |
||||
libusb_claim_interface@8 = libusb_claim_interface |
||||
libusb_clear_halt |
||||
libusb_clear_halt@8 = libusb_clear_halt |
||||
libusb_close |
||||
libusb_close@4 = libusb_close |
||||
libusb_control_transfer |
||||
libusb_control_transfer@32 = libusb_control_transfer |
||||
libusb_detach_kernel_driver |
||||
libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver |
||||
libusb_error_name |
||||
libusb_error_name@4 = libusb_error_name |
||||
libusb_event_handler_active |
||||
libusb_event_handler_active@4 = libusb_event_handler_active |
||||
libusb_event_handling_ok |
||||
libusb_event_handling_ok@4 = libusb_event_handling_ok |
||||
libusb_exit |
||||
libusb_exit@4 = libusb_exit |
||||
libusb_free_config_descriptor |
||||
libusb_free_config_descriptor@4 = libusb_free_config_descriptor |
||||
libusb_free_device_list |
||||
libusb_free_device_list@8 = libusb_free_device_list |
||||
libusb_free_transfer |
||||
libusb_free_transfer@4 = libusb_free_transfer |
||||
libusb_get_active_config_descriptor |
||||
libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor |
||||
libusb_get_bus_number |
||||
libusb_get_bus_number@4 = libusb_get_bus_number |
||||
libusb_get_config_descriptor |
||||
libusb_get_config_descriptor@12 = libusb_get_config_descriptor |
||||
libusb_get_config_descriptor_by_value |
||||
libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value |
||||
libusb_get_configuration |
||||
libusb_get_configuration@8 = libusb_get_configuration |
||||
libusb_get_device |
||||
libusb_get_device@4 = libusb_get_device |
||||
libusb_get_device_address |
||||
libusb_get_device_address@4 = libusb_get_device_address |
||||
libusb_get_device_descriptor |
||||
libusb_get_device_descriptor@8 = libusb_get_device_descriptor |
||||
libusb_get_device_list |
||||
libusb_get_device_list@8 = libusb_get_device_list |
||||
libusb_get_device_speed |
||||
libusb_get_device_speed@4 = libusb_get_device_speed |
||||
libusb_get_max_iso_packet_size |
||||
libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size |
||||
libusb_get_max_packet_size |
||||
libusb_get_max_packet_size@8 = libusb_get_max_packet_size |
||||
libusb_get_next_timeout |
||||
libusb_get_next_timeout@8 = libusb_get_next_timeout |
||||
libusb_get_pollfds |
||||
libusb_get_pollfds@4 = libusb_get_pollfds |
||||
libusb_get_string_descriptor_ascii |
||||
libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii |
||||
libusb_get_version |
||||
libusb_get_version@0 = libusb_get_version |
||||
libusb_handle_events |
||||
libusb_handle_events@4 = libusb_handle_events |
||||
libusb_handle_events_completed |
||||
libusb_handle_events_completed@8 = libusb_handle_events_completed |
||||
libusb_handle_events_locked |
||||
libusb_handle_events_locked@8 = libusb_handle_events_locked |
||||
libusb_handle_events_timeout |
||||
libusb_handle_events_timeout@8 = libusb_handle_events_timeout |
||||
libusb_handle_events_timeout_completed |
||||
libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed |
||||
libusb_has_capability |
||||
libusb_has_capability@4 = libusb_has_capability |
||||
libusb_init |
||||
libusb_init@4 = libusb_init |
||||
libusb_interrupt_transfer |
||||
libusb_interrupt_transfer@24 = libusb_interrupt_transfer |
||||
libusb_kernel_driver_active |
||||
libusb_kernel_driver_active@8 = libusb_kernel_driver_active |
||||
libusb_lock_event_waiters |
||||
libusb_lock_event_waiters@4 = libusb_lock_event_waiters |
||||
libusb_lock_events |
||||
libusb_lock_events@4 = libusb_lock_events |
||||
libusb_open |
||||
libusb_open@8 = libusb_open |
||||
libusb_open_device_with_vid_pid |
||||
libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid |
||||
libusb_pollfds_handle_timeouts |
||||
libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts |
||||
libusb_ref_device |
||||
libusb_ref_device@4 = libusb_ref_device |
||||
libusb_release_interface |
||||
libusb_release_interface@8 = libusb_release_interface |
||||
libusb_reset_device |
||||
libusb_reset_device@4 = libusb_reset_device |
||||
libusb_set_configuration |
||||
libusb_set_configuration@8 = libusb_set_configuration |
||||
libusb_set_debug |
||||
libusb_set_debug@8 = libusb_set_debug |
||||
libusb_set_interface_alt_setting |
||||
libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting |
||||
libusb_set_pollfd_notifiers |
||||
libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers |
||||
libusb_submit_transfer |
||||
libusb_submit_transfer@4 = libusb_submit_transfer |
||||
libusb_try_lock_events |
||||
libusb_try_lock_events@4 = libusb_try_lock_events |
||||
libusb_unlock_event_waiters |
||||
libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters |
||||
libusb_unlock_events |
||||
libusb_unlock_events@4 = libusb_unlock_events |
||||
libusb_unref_device |
||||
libusb_unref_device@4 = libusb_unref_device |
||||
libusb_wait_for_event |
||||
libusb_wait_for_event@8 = libusb_wait_for_event |
@ -1,56 +0,0 @@
@@ -1,56 +0,0 @@
|
||||
/* |
||||
* For Windows: input this file to the Resoure Compiler to produce a binary |
||||
* .res file. This is then embedded in the resultant library (like any other |
||||
* compilation object). |
||||
* The information can then be queried using standard APIs and can also be |
||||
* viewed with utilities such as Windows Explorer. |
||||
*/ |
||||
#include "winresrc.h" |
||||
|
||||
#include "version.h" |
||||
#ifndef LIBUSB_VERSIONSTRING |
||||
#define LU_STR(s) #s |
||||
#define LU_XSTR(s) LU_STR(s) |
||||
#if LIBUSB_NANO > 0 |
||||
#define LIBUSB_VERSIONSTRING LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." LU_XSTR(LIBUSB_MICRO) "." LU_XSTR(LIBUSB_NANO) LIBUSB_RC "\0" |
||||
#else |
||||
#define LIBUSB_VERSIONSTRING LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." LU_XSTR(LIBUSB_MICRO) LIBUSB_RC "\0" |
||||
#endif |
||||
#endif |
||||
|
||||
VS_VERSION_INFO VERSIONINFO |
||||
FILEVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO |
||||
PRODUCTVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO |
||||
FILEFLAGSMASK 0x3fL |
||||
#ifdef _DEBUG |
||||
FILEFLAGS 0x1L |
||||
#else |
||||
FILEFLAGS 0x0L |
||||
#endif |
||||
FILEOS 0x40004L |
||||
FILETYPE 0x2L |
||||
FILESUBTYPE 0x0L |
||||
BEGIN |
||||
BLOCK "StringFileInfo" |
||||
BEGIN |
||||
BLOCK "040904b0" |
||||
BEGIN |
||||
VALUE "Comments", "\0" |
||||
VALUE "CompanyName", "libusb.org\0" |
||||
VALUE "FileDescription", "C library for writing portable USB drivers in userspace\0" |
||||
VALUE "FileVersion", LIBUSB_VERSIONSTRING |
||||
VALUE "InternalName", "libusb\0" |
||||
VALUE "LegalCopyright", "See individual source files, GNU LGPL v2.1 or later.\0" |
||||
VALUE "LegalTrademarks", "http://www.gnu.org/licenses/lgpl-2.1.html\0" |
||||
VALUE "OriginalFilename", "libusb-1.0.dll\0" |
||||
VALUE "PrivateBuild", "\0" |
||||
VALUE "ProductName", "libusb-1.0\0" |
||||
VALUE "ProductVersion", LIBUSB_VERSIONSTRING |
||||
VALUE "SpecialBuild", "\0" |
||||
END |
||||
END |
||||
BLOCK "VarFileInfo" |
||||
BEGIN |
||||
VALUE "Translation", 0x409, 1200 |
||||
END |
||||
END |
File diff suppressed because it is too large
Load Diff
@ -1,974 +0,0 @@
@@ -1,974 +0,0 @@
|
||||
/*
|
||||
* Internal header for libusb |
||||
* Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> |
||||
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.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 |
||||
*/ |
||||
|
||||
#ifndef LIBUSBI_H |
||||
#define LIBUSBI_H |
||||
|
||||
#include <config.h> |
||||
|
||||
#include <stddef.h> |
||||
#include <stdint.h> |
||||
#include <time.h> |
||||
#include <stdarg.h> |
||||
#ifdef HAVE_POLL_H |
||||
#include <poll.h> |
||||
#endif |
||||
|
||||
#include <libusb.h> |
||||
#include <version.h> |
||||
|
||||
/* Inside the libusb code, mark all public functions as follows:
|
||||
* return_type API_EXPORTED function_name(params) { ... } |
||||
* But if the function returns a pointer, mark it as follows: |
||||
* DEFAULT_VISIBILITY return_type * LIBUSB_CALL function_name(params) { ... } |
||||
* In the libusb public header, mark all declarations as: |
||||
* return_type LIBUSB_CALL function_name(params); |
||||
*/ |
||||
#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY |
||||
|
||||
#define DEVICE_DESC_LENGTH 18 |
||||
|
||||
#define USB_MAXENDPOINTS 32 |
||||
#define USB_MAXINTERFACES 32 |
||||
#define USB_MAXCONFIG 8 |
||||
|
||||
struct list_head { |
||||
struct list_head *prev, *next; |
||||
}; |
||||
|
||||
/* Get an entry from the list
|
||||
* ptr - the address of this list_head element in "type" |
||||
* type - the data type that contains "member" |
||||
* member - the list_head element in "type" |
||||
*/ |
||||
#define list_entry(ptr, type, member) \ |
||||
((type *)((uintptr_t)(ptr) - (uintptr_t)(&((type *)0L)->member))) |
||||
|
||||
/* Get each entry from a list
|
||||
* pos - A structure pointer has a "member" element |
||||
* head - list head |
||||
* member - the list_head element in "pos" |
||||
* type - the type of the first parameter |
||||
*/ |
||||
#define list_for_each_entry(pos, head, member, type) \ |
||||
for (pos = list_entry((head)->next, type, member); \ |
||||
&pos->member != (head); \ |
||||
pos = list_entry(pos->member.next, type, member)) |
||||
|
||||
#define list_for_each_entry_safe(pos, n, head, member, type) \ |
||||
for (pos = list_entry((head)->next, type, member), \ |
||||
n = list_entry(pos->member.next, type, member); \ |
||||
&pos->member != (head); \ |
||||
pos = n, n = list_entry(n->member.next, type, member)) |
||||
|
||||
#define list_empty(entry) ((entry)->next == (entry)) |
||||
|
||||
static inline void list_init(struct list_head *entry) |
||||
{ |
||||
entry->prev = entry->next = entry; |
||||
} |
||||
|
||||
static inline void list_add(struct list_head *entry, struct list_head *head) |
||||
{ |
||||
entry->next = head->next; |
||||
entry->prev = head; |
||||
|
||||
head->next->prev = entry; |
||||
head->next = entry; |
||||
} |
||||
|
||||
static inline void list_add_tail(struct list_head *entry, |
||||
struct list_head *head) |
||||
{ |
||||
entry->next = head; |
||||
entry->prev = head->prev; |
||||
|
||||
head->prev->next = entry; |
||||
head->prev = entry; |
||||
} |
||||
|
||||
static inline void list_del(struct list_head *entry) |
||||
{ |
||||
entry->next->prev = entry->prev; |
||||
entry->prev->next = entry->next; |
||||
} |
||||
|
||||
#define container_of(ptr, type, member) ({ \ |
||||
const typeof( ((type *)0)->member ) *mptr = (ptr); \ |
||||
(type *)( (char *)mptr - offsetof(type,member) );}) |
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b)) |
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b)) |
||||
|
||||
#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0) |
||||
|
||||
enum usbi_log_level { |
||||
LOG_LEVEL_DEBUG, |
||||
LOG_LEVEL_INFO, |
||||
LOG_LEVEL_WARNING, |
||||
LOG_LEVEL_ERROR, |
||||
}; |
||||
|
||||
void usbi_log(struct libusb_context *ctx, enum usbi_log_level level, |
||||
const char *function, const char *format, ...); |
||||
|
||||
void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level, |
||||
const char *function, const char *format, va_list args); |
||||
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1400 |
||||
|
||||
#ifdef ENABLE_LOGGING |
||||
#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__) |
||||
#else |
||||
#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0) |
||||
#endif |
||||
|
||||
#ifdef ENABLE_DEBUG_LOGGING |
||||
#define usbi_dbg(...) _usbi_log(NULL, LOG_LEVEL_DEBUG, __VA_ARGS__) |
||||
#else |
||||
#define usbi_dbg(...) do {} while(0) |
||||
#endif |
||||
|
||||
#define usbi_info(ctx, ...) _usbi_log(ctx, LOG_LEVEL_INFO, __VA_ARGS__) |
||||
#define usbi_warn(ctx, ...) _usbi_log(ctx, LOG_LEVEL_WARNING, __VA_ARGS__) |
||||
#define usbi_err(ctx, ...) _usbi_log(ctx, LOG_LEVEL_ERROR, __VA_ARGS__) |
||||
|
||||
#else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ |
||||
|
||||
/* Old MS compilers don't support variadic macros. The code is simple, so we
|
||||
* repeat it for each loglevel. Note that the debug case is special. |
||||
* |
||||
* Support for variadic macros was introduced in Visual C++ 2005. |
||||
* http://msdn.microsoft.com/en-us/library/ms177415%28v=VS.80%29.aspx
|
||||
*/ |
||||
|
||||
static inline void usbi_info(struct libusb_context *ctx, const char *fmt, ...) |
||||
{ |
||||
#ifdef ENABLE_LOGGING |
||||
va_list args; |
||||
va_start(args, fmt); |
||||
usbi_log_v(ctx, LOG_LEVEL_INFO, "", fmt, args); |
||||
va_end(args); |
||||
#else |
||||
(void)ctx; |
||||
#endif |
||||
} |
||||
|
||||
static inline void usbi_warn(struct libusb_context *ctx, const char *fmt, ...) |
||||
{ |
||||
#ifdef ENABLE_LOGGING |
||||
va_list args; |
||||
va_start(args, fmt); |
||||
usbi_log_v(ctx, LOG_LEVEL_WARNING, "", fmt, args); |
||||
va_end(args); |
||||
#else |
||||
(void)ctx; |
||||
#endif |
||||
} |
||||
|
||||
static inline void usbi_err(struct libusb_context *ctx, const char *fmt, ...) |
||||
{ |
||||
#ifdef ENABLE_LOGGING |
||||
va_list args; |
||||
va_start(args, fmt); |
||||
usbi_log_v(ctx, LOG_LEVEL_ERROR, "", fmt, args); |
||||
va_end(args); |
||||
#else |
||||
(void)ctx; |
||||
#endif |
||||
} |
||||
|
||||
static inline void usbi_dbg(const char *fmt, ...) |
||||
{ |
||||
#ifdef ENABLE_DEBUG_LOGGING |
||||
va_list args; |
||||
va_start(args, fmt); |
||||
usbi_log_v(NULL, LOG_LEVEL_DEBUG, "", fmt, args); |
||||
va_end(args); |
||||
#else |
||||
(void)fmt; |
||||
#endif |
||||
} |
||||
|
||||
#endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */ |
||||
|
||||
#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context |
||||
#define DEVICE_CTX(dev) ((dev)->ctx) |
||||
#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) |
||||
#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) |
||||
#define ITRANSFER_CTX(transfer) \ |
||||
(TRANSFER_CTX(USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) |
||||
|
||||
#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN)) |
||||
#define IS_EPOUT(ep) (!IS_EPIN(ep)) |
||||
#define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN)) |
||||
#define IS_XFEROUT(xfer) (!IS_XFERIN(xfer)) |
||||
|
||||
/* Internal abstractions for thread synchronization and poll */ |
||||
#if defined(THREADS_POSIX) |
||||
#include <os/threads_posix.h> |
||||
#elif defined(OS_WINDOWS) |
||||
#include <os/threads_windows.h> |
||||
#endif |
||||
|
||||
#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) |
||||
#include <unistd.h> |
||||
#include <os/poll_posix.h> |
||||
#elif defined(OS_WINDOWS) |
||||
#include <os/poll_windows.h> |
||||
#endif |
||||
|
||||
#if defined(OS_WINDOWS) && !defined(__GCC__) |
||||
#undef HAVE_GETTIMEOFDAY |
||||
int usbi_gettimeofday(struct timeval *tp, void *tzp); |
||||
#define LIBUSB_GETTIMEOFDAY_WIN32 |
||||
#define HAVE_USBI_GETTIMEOFDAY |
||||
#else |
||||
#ifdef HAVE_GETTIMEOFDAY |
||||
#define usbi_gettimeofday(tv, tz) gettimeofday((tv), (tz)) |
||||
#define HAVE_USBI_GETTIMEOFDAY |
||||
#endif |
||||
#endif |
||||
|
||||
extern struct libusb_context *usbi_default_context; |
||||
|
||||
struct libusb_context { |
||||
int debug; |
||||
int debug_fixed; |
||||
|
||||
/* internal control pipe, used for interrupting event handling when
|
||||
* something needs to modify poll fds. */ |
||||
int ctrl_pipe[2]; |
||||
|
||||
struct list_head usb_devs; |
||||
usbi_mutex_t usb_devs_lock; |
||||
|
||||
/* A list of open handles. Backends are free to traverse this if required.
|
||||
*/ |
||||
struct list_head open_devs; |
||||
usbi_mutex_t open_devs_lock; |
||||
|
||||
/* A list of registered hotplug callbacks */ |
||||
struct list_head hotplug_cbs; |
||||
usbi_mutex_t hotplug_cbs_lock; |
||||
int hotplug_pipe[2]; |
||||
|
||||
/* this is a list of in-flight transfer handles, sorted by timeout
|
||||
* expiration. URBs to timeout the soonest are placed at the beginning of |
||||
* the list, URBs that will time out later are placed after, and urbs with |
||||
* infinite timeout are always placed at the very end. */ |
||||
struct list_head flying_transfers; |
||||
usbi_mutex_t flying_transfers_lock; |
||||
|
||||
/* list of poll fds */ |
||||
struct list_head pollfds; |
||||
usbi_mutex_t pollfds_lock; |
||||
|
||||
/* a counter that is set when we want to interrupt event handling, in order
|
||||
* to modify the poll fd set. and a lock to protect it. */ |
||||
unsigned int pollfd_modify; |
||||
usbi_mutex_t pollfd_modify_lock; |
||||
|
||||
/* user callbacks for pollfd changes */ |
||||
libusb_pollfd_added_cb fd_added_cb; |
||||
libusb_pollfd_removed_cb fd_removed_cb; |
||||
void *fd_cb_user_data; |
||||
|
||||
/* ensures that only one thread is handling events at any one time */ |
||||
usbi_mutex_t events_lock; |
||||
|
||||
/* used to see if there is an active thread doing event handling */ |
||||
int event_handler_active; |
||||
|
||||
/* used to wait for event completion in threads other than the one that is
|
||||
* event handling */ |
||||
usbi_mutex_t event_waiters_lock; |
||||
usbi_cond_t event_waiters_cond; |
||||
|
||||
#ifdef USBI_TIMERFD_AVAILABLE |
||||
/* used for timeout handling, if supported by OS.
|
||||
* this timerfd is maintained to trigger on the next pending timeout */ |
||||
int timerfd; |
||||
#endif |
||||
|
||||
struct list_head list; |
||||
}; |
||||
|
||||
#ifdef USBI_TIMERFD_AVAILABLE |
||||
#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0) |
||||
#else |
||||
#define usbi_using_timerfd(ctx) (0) |
||||
#endif |
||||
|
||||
struct libusb_device { |
||||
/* lock protects refcnt, everything else is finalized at initialization
|
||||
* time */ |
||||
usbi_mutex_t lock; |
||||
int refcnt; |
||||
|
||||
struct libusb_context *ctx; |
||||
|
||||
uint8_t bus_number; |
||||
uint8_t device_address; |
||||
uint8_t num_configurations; |
||||
enum libusb_speed speed; |
||||
|
||||
struct list_head list; |
||||
unsigned long session_data; |
||||
|
||||
struct libusb_device_descriptor device_descriptor; |
||||
int attached; |
||||
|
||||
unsigned char os_priv |
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) |
||||
[] /* valid C99 code */ |
||||
#else |
||||
[0] /* non-standard, but usually working code */ |
||||
#endif |
||||
; |
||||
}; |
||||
|
||||
struct libusb_device_handle { |
||||
/* lock protects claimed_interfaces */ |
||||
usbi_mutex_t lock; |
||||
unsigned long claimed_interfaces; |
||||
|
||||
struct list_head list; |
||||
struct libusb_device *dev; |
||||
unsigned char os_priv |
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) |
||||
[] /* valid C99 code */ |
||||
#else |
||||
[0] /* non-standard, but usually working code */ |
||||
#endif |
||||
; |
||||
}; |
||||
|
||||
enum { |
||||
USBI_CLOCK_MONOTONIC, |
||||
USBI_CLOCK_REALTIME |
||||
}; |
||||
|
||||
/* in-memory transfer layout:
|
||||
* |
||||
* 1. struct usbi_transfer |
||||
* 2. struct libusb_transfer (which includes iso packets) [variable size] |
||||
* 3. os private data [variable size] |
||||
* |
||||
* from a libusb_transfer, you can get the usbi_transfer by rewinding the |
||||
* appropriate number of bytes. |
||||
* the usbi_transfer includes the number of allocated packets, so you can |
||||
* determine the size of the transfer and hence the start and length of the |
||||
* OS-private data. |
||||
*/ |
||||
|
||||
struct usbi_transfer { |
||||
int num_iso_packets; |
||||
struct list_head list; |
||||
struct timeval timeout; |
||||
int transferred; |
||||
uint8_t flags; |
||||
|
||||
/* this lock is held during libusb_submit_transfer() and
|
||||
* libusb_cancel_transfer() (allowing the OS backend to prevent duplicate |
||||
* cancellation, submission-during-cancellation, etc). the OS backend |
||||
* should also take this lock in the handle_events path, to prevent the user |
||||
* cancelling the transfer from another thread while you are processing |
||||
* its completion (presumably there would be races within your OS backend |
||||
* if this were possible). */ |
||||
usbi_mutex_t lock; |
||||
}; |
||||
|
||||
enum usbi_transfer_flags { |
||||
/* The transfer has timed out */ |
||||
USBI_TRANSFER_TIMED_OUT = 1 << 0, |
||||
|
||||
/* Set by backend submit_transfer() if the OS handles timeout */ |
||||
USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1, |
||||
|
||||
/* Cancellation was requested via libusb_cancel_transfer() */ |
||||
USBI_TRANSFER_CANCELLING = 1 << 2, |
||||
|
||||
/* Operation on the transfer failed because the device disappeared */ |
||||
USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3, |
||||
|
||||
/* Set by backend submit_transfer() if the fds in use were updated */ |
||||
USBI_TRANSFER_UPDATED_FDS = 1 << 4, |
||||
}; |
||||
|
||||
#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \ |
||||
((struct libusb_transfer *)(((unsigned char *)(transfer)) \ |
||||
+ sizeof(struct usbi_transfer))) |
||||
#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \ |
||||
((struct usbi_transfer *)(((unsigned char *)(transfer)) \ |
||||
- sizeof(struct usbi_transfer))) |
||||
|
||||
static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer) |
||||
{ |
||||
return ((unsigned char *)transfer) + sizeof(struct usbi_transfer) |
||||
+ sizeof(struct libusb_transfer) |
||||
+ (transfer->num_iso_packets |
||||
* sizeof(struct libusb_iso_packet_descriptor)); |
||||
} |
||||
|
||||
/* bus structures */ |
||||
|
||||
/* All standard descriptors have these 2 fields in common */ |
||||
struct usb_descriptor_header { |
||||
uint8_t bLength; |
||||
uint8_t bDescriptorType; |
||||
}; |
||||
|
||||
/* shared data and functions */ |
||||
|
||||
int usbi_io_init(struct libusb_context *ctx); |
||||
void usbi_io_exit(struct libusb_context *ctx); |
||||
|
||||
struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, |
||||
unsigned long session_id); |
||||
struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, |
||||
unsigned long session_id); |
||||
int usbi_sanitize_device(struct libusb_device *dev); |
||||
void usbi_handle_disconnect(struct libusb_device_handle *handle); |
||||
|
||||
int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, |
||||
enum libusb_transfer_status status); |
||||
int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer); |
||||
|
||||
int usbi_parse_descriptor(const unsigned char *source, const char *descriptor, |
||||
void *dest, int host_endian); |
||||
int usbi_device_cache_descriptor(libusb_device *dev); |
||||
int usbi_get_config_index_by_value(struct libusb_device *dev, |
||||
uint8_t bConfigurationValue, int *idx); |
||||
|
||||
void usbi_connect_device (struct libusb_device *dev); |
||||
void usbi_disconnect_device (struct libusb_device *dev); |
||||
|
||||
/* polling */ |
||||
|
||||
struct usbi_pollfd { |
||||
/* must come first */ |
||||
struct libusb_pollfd pollfd; |
||||
|
||||
struct list_head list; |
||||
}; |
||||
|
||||
int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events); |
||||
void usbi_remove_pollfd(struct libusb_context *ctx, int fd); |
||||
void usbi_fd_notification(struct libusb_context *ctx); |
||||
|
||||
/* device discovery */ |
||||
|
||||
/* we traverse usbfs without knowing how many devices we are going to find.
|
||||
* so we create this discovered_devs model which is similar to a linked-list |
||||
* which grows when required. it can be freed once discovery has completed, |
||||
* eliminating the need for a list node in the libusb_device structure |
||||
* itself. */ |
||||
struct discovered_devs { |
||||
size_t len; |
||||
size_t capacity; |
||||
struct libusb_device *devices |
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) |
||||
[] /* valid C99 code */ |
||||
#else |
||||
[0] /* non-standard, but usually working code */ |
||||
#endif |
||||
; |
||||
}; |
||||
|
||||
struct discovered_devs *discovered_devs_append( |
||||
struct discovered_devs *discdevs, struct libusb_device *dev); |
||||
|
||||
/* OS abstraction */ |
||||
|
||||
/* This is the interface that OS backends need to implement.
|
||||
* All fields are mandatory, except ones explicitly noted as optional. */ |
||||
struct usbi_os_backend { |
||||
/* A human-readable name for your backend, e.g. "Linux usbfs" */ |
||||
const char *name; |
||||
|
||||
/* Perform initialization of your backend. You might use this function
|
||||
* to determine specific capabilities of the system, allocate required |
||||
* data structures for later, etc. |
||||
* |
||||
* This function is called when a libusb user initializes the library |
||||
* prior to use. |
||||
* |
||||
* Return 0 on success, or a LIBUSB_ERROR code on failure. |
||||
*/ |
||||
int (*init)(struct libusb_context *ctx); |
||||
|
||||
/* Deinitialization. Optional. This function should destroy anything
|
||||
* that was set up by init. |
||||
* |
||||
* This function is called when the user deinitializes the library. |
||||
*/ |
||||
void (*exit)(void); |
||||
|
||||
/* Enumerate all the USB devices on the system, returning them in a list
|
||||
* of discovered devices. |
||||
* |
||||
* Your implementation should enumerate all devices on the system, |
||||
* regardless of whether they have been seen before or not. |
||||
* |
||||
* When you have found a device, compute a session ID for it. The session |
||||
* ID should uniquely represent that particular device for that particular |
||||
* connection session since boot (i.e. if you disconnect and reconnect a |
||||
* device immediately after, it should be assigned a different session ID). |
||||
* If your OS cannot provide a unique session ID as described above, |
||||
* presenting a session ID of (bus_number << 8 | device_address) should |
||||
* be sufficient. Bus numbers and device addresses wrap and get reused, |
||||
* but that is an unlikely case. |
||||
* |
||||
* After computing a session ID for a device, call |
||||
* usbi_get_device_by_session_id(). This function checks if libusb already |
||||
* knows about the device, and if so, it provides you with a libusb_device |
||||
* structure for it. |
||||
* |
||||
* If usbi_get_device_by_session_id() returns NULL, it is time to allocate |
||||
* a new device structure for the device. Call usbi_alloc_device() to |
||||
* obtain a new libusb_device structure with reference count 1. Populate |
||||
* the bus_number and device_address attributes of the new device, and |
||||
* perform any other internal backend initialization you need to do. At |
||||
* this point, you should be ready to provide device descriptors and so |
||||
* on through the get_*_descriptor functions. Finally, call |
||||
* usbi_sanitize_device() to perform some final sanity checks on the |
||||
* device. Assuming all of the above succeeded, we can now continue. |
||||
* If any of the above failed, remember to unreference the device that |
||||
* was returned by usbi_alloc_device(). |
||||
* |
||||
* At this stage we have a populated libusb_device structure (either one |
||||
* that was found earlier, or one that we have just allocated and |
||||
* populated). This can now be added to the discovered devices list |
||||
* using discovered_devs_append(). Note that discovered_devs_append() |
||||
* may reallocate the list, returning a new location for it, and also |
||||
* note that reallocation can fail. Your backend should handle these |
||||
* error conditions appropriately. |
||||
* |
||||
* This function should not generate any bus I/O and should not block. |
||||
* If I/O is required (e.g. reading the active configuration value), it is |
||||
* OK to ignore these suggestions :) |
||||
* |
||||
* This function is executed when the user wishes to retrieve a list |
||||
* of USB devices connected to the system. |
||||
* |
||||
* Return 0 on success, or a LIBUSB_ERROR code on failure. |
||||
*/ |
||||
int (*get_device_list)(struct libusb_context *ctx, |
||||
struct discovered_devs **discdevs); |
||||
|
||||
/* Open a device for I/O and other USB operations. The device handle
|
||||
* is preallocated for you, you can retrieve the device in question |
||||
* through handle->dev. |
||||
* |
||||
* Your backend should allocate any internal resources required for I/O |
||||
* and other operations so that those operations can happen (hopefully) |
||||
* without hiccup. This is also a good place to inform libusb that it |
||||
* should monitor certain file descriptors related to this device - |
||||
* see the usbi_add_pollfd() function. |
||||
* |
||||
* This function should not generate any bus I/O and should not block. |
||||
* |
||||
* This function is called when the user attempts to obtain a device |
||||
* handle for a device. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_ACCESS if the user has insufficient permissions |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since |
||||
* discovery |
||||
* - another LIBUSB_ERROR code on other failure |
||||
* |
||||
* Do not worry about freeing the handle on failed open, the upper layers |
||||
* do this for you. |
||||
*/ |
||||
int (*open)(struct libusb_device_handle *handle); |
||||
|
||||
/* Close a device such that the handle cannot be used again. Your backend
|
||||
* should destroy any resources that were allocated in the open path. |
||||
* This may also be a good place to call usbi_remove_pollfd() to inform |
||||
* libusb of any file descriptors associated with this device that should |
||||
* no longer be monitored. |
||||
* |
||||
* This function is called when the user closes a device handle. |
||||
*/ |
||||
void (*close)(struct libusb_device_handle *handle); |
||||
|
||||
/* Retrieve the device descriptor from a device.
|
||||
* |
||||
* The descriptor should be retrieved from memory, NOT via bus I/O to the |
||||
* device. This means that you may have to cache it in a private structure |
||||
* during get_device_list enumeration. Alternatively, you may be able |
||||
* to retrieve it from a kernel interface (some Linux setups can do this) |
||||
* still without generating bus I/O. |
||||
* |
||||
* This function is expected to write DEVICE_DESC_LENGTH (18) bytes into |
||||
* buffer, which is guaranteed to be big enough. |
||||
* |
||||
* This function is called when sanity-checking a device before adding |
||||
* it to the list of discovered devices, and also when the user requests |
||||
* to read the device descriptor. |
||||
* |
||||
* This function is expected to return the descriptor in bus-endian format |
||||
* (LE). If it returns the multi-byte values in host-endian format, |
||||
* set the host_endian output parameter to "1". |
||||
* |
||||
* Return 0 on success or a LIBUSB_ERROR code on failure. |
||||
*/ |
||||
int (*get_device_descriptor)(struct libusb_device *device, |
||||
unsigned char *buffer, int *host_endian); |
||||
|
||||
/* Get the ACTIVE configuration descriptor for a device.
|
||||
* |
||||
* The descriptor should be retrieved from memory, NOT via bus I/O to the |
||||
* device. This means that you may have to cache it in a private structure |
||||
* during get_device_list enumeration. You may also have to keep track |
||||
* of which configuration is active when the user changes it. |
||||
* |
||||
* This function is expected to write len bytes of data into buffer, which |
||||
* is guaranteed to be big enough. If you can only do a partial write, |
||||
* return an error code. |
||||
* |
||||
* This function is expected to return the descriptor in bus-endian format |
||||
* (LE). If it returns the multi-byte values in host-endian format, |
||||
* set the host_endian output parameter to "1". |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*get_active_config_descriptor)(struct libusb_device *device, |
||||
unsigned char *buffer, size_t len, int *host_endian); |
||||
|
||||
/* Get a specific configuration descriptor for a device.
|
||||
* |
||||
* The descriptor should be retrieved from memory, NOT via bus I/O to the |
||||
* device. This means that you may have to cache it in a private structure |
||||
* during get_device_list enumeration. |
||||
* |
||||
* The requested descriptor is expressed as a zero-based index (i.e. 0 |
||||
* indicates that we are requesting the first descriptor). The index does |
||||
* not (necessarily) equal the bConfigurationValue of the configuration |
||||
* being requested. |
||||
* |
||||
* This function is expected to write len bytes of data into buffer, which |
||||
* is guaranteed to be big enough. If you can only do a partial write, |
||||
* return an error code. |
||||
* |
||||
* This function is expected to return the descriptor in bus-endian format |
||||
* (LE). If it returns the multi-byte values in host-endian format, |
||||
* set the host_endian output parameter to "1". |
||||
* |
||||
* Return 0 on success or a LIBUSB_ERROR code on failure. |
||||
*/ |
||||
int (*get_config_descriptor)(struct libusb_device *device, |
||||
uint8_t config_index, unsigned char *buffer, size_t len, |
||||
int *host_endian); |
||||
|
||||
/* Get the bConfigurationValue for the active configuration for a device.
|
||||
* Optional. This should only be implemented if you can retrieve it from |
||||
* cache (don't generate I/O). |
||||
* |
||||
* If you cannot retrieve this from cache, either do not implement this |
||||
* function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause |
||||
* libusb to retrieve the information through a standard control transfer. |
||||
* |
||||
* This function must be non-blocking. |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - LIBUSB_ERROR_NOT_SUPPORTED if the value cannot be retrieved without |
||||
* blocking |
||||
* - another LIBUSB_ERROR code on other failure. |
||||
*/ |
||||
int (*get_configuration)(struct libusb_device_handle *handle, int *config); |
||||
|
||||
/* Set the active configuration for a device.
|
||||
* |
||||
* A configuration value of -1 should put the device in unconfigured state. |
||||
* |
||||
* This function can block. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
||||
* - LIBUSB_ERROR_BUSY if interfaces are currently claimed (and hence |
||||
* configuration cannot be changed) |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - another LIBUSB_ERROR code on other failure. |
||||
*/ |
||||
int (*set_configuration)(struct libusb_device_handle *handle, int config); |
||||
|
||||
/* Claim an interface. When claimed, the application can then perform
|
||||
* I/O to an interface's endpoints. |
||||
* |
||||
* This function should not generate any bus I/O and should not block. |
||||
* Interface claiming is a logical operation that simply ensures that |
||||
* no other drivers/applications are using the interface, and after |
||||
* claiming, no other drivers/applicatiosn can use the interface because |
||||
* we now "own" it. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NOT_FOUND if the interface does not exist |
||||
* - LIBUSB_ERROR_BUSY if the interface is in use by another driver/app |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*claim_interface)(struct libusb_device_handle *handle, int interface_number); |
||||
|
||||
/* Release a previously claimed interface.
|
||||
* |
||||
* This function should also generate a SET_INTERFACE control request, |
||||
* resetting the alternate setting of that interface to 0. It's OK for |
||||
* this function to block as a result. |
||||
* |
||||
* You will only ever be asked to release an interface which was |
||||
* successfully claimed earlier. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*release_interface)(struct libusb_device_handle *handle, int interface_number); |
||||
|
||||
/* Set the alternate setting for an interface.
|
||||
* |
||||
* You will only ever be asked to set the alternate setting for an |
||||
* interface which was successfully claimed earlier. |
||||
* |
||||
* It's OK for this function to block. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NOT_FOUND if the alternate setting does not exist |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*set_interface_altsetting)(struct libusb_device_handle *handle, |
||||
int interface_number, int altsetting); |
||||
|
||||
/* Clear a halt/stall condition on an endpoint.
|
||||
* |
||||
* It's OK for this function to block. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*clear_halt)(struct libusb_device_handle *handle, |
||||
unsigned char endpoint); |
||||
|
||||
/* Perform a USB port reset to reinitialize a device.
|
||||
* |
||||
* If possible, the handle should still be usable after the reset |
||||
* completes, assuming that the device descriptors did not change during |
||||
* reset and all previous interface state can be restored. |
||||
* |
||||
* If something changes, or you cannot easily locate/verify the resetted |
||||
* device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application |
||||
* to close the old handle and re-enumerate the device. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the device |
||||
* has been disconnected since it was opened |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*reset_device)(struct libusb_device_handle *handle); |
||||
|
||||
/* Determine if a kernel driver is active on an interface. Optional.
|
||||
* |
||||
* The presence of a kernel driver on an interface indicates that any |
||||
* calls to claim_interface would fail with the LIBUSB_ERROR_BUSY code. |
||||
* |
||||
* Return: |
||||
* - 0 if no driver is active |
||||
* - 1 if a driver is active |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*kernel_driver_active)(struct libusb_device_handle *handle, |
||||
int interface_number); |
||||
|
||||
/* Detach a kernel driver from an interface. Optional.
|
||||
* |
||||
* After detaching a kernel driver, the interface should be available |
||||
* for claim. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active |
||||
* - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*detach_kernel_driver)(struct libusb_device_handle *handle, |
||||
int interface_number); |
||||
|
||||
/* Attach a kernel driver to an interface. Optional.
|
||||
* |
||||
* Reattach a kernel driver to the device. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active |
||||
* - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it |
||||
* was opened |
||||
* - LIBUSB_ERROR_BUSY if a program or driver has claimed the interface, |
||||
* preventing reattachment |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*attach_kernel_driver)(struct libusb_device_handle *handle, |
||||
int interface_number); |
||||
|
||||
/* Destroy a device. Optional.
|
||||
* |
||||
* This function is called when the last reference to a device is |
||||
* destroyed. It should free any resources allocated in the get_device_list |
||||
* path. |
||||
*/ |
||||
void (*destroy_device)(struct libusb_device *dev); |
||||
|
||||
/* Submit a transfer. Your implementation should take the transfer,
|
||||
* morph it into whatever form your platform requires, and submit it |
||||
* asynchronously. |
||||
* |
||||
* This function must not block. |
||||
* |
||||
* Return: |
||||
* - 0 on success |
||||
* - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected |
||||
* - another LIBUSB_ERROR code on other failure |
||||
*/ |
||||
int (*submit_transfer)(struct usbi_transfer *itransfer); |
||||
|
||||
/* Cancel a previously submitted transfer.
|
||||
* |
||||
* This function must not block. The transfer cancellation must complete |
||||
* later, resulting in a call to usbi_handle_transfer_cancellation() |
||||
* from the context of handle_events. |
||||
*/ |
||||
int (*cancel_transfer)(struct usbi_transfer *itransfer); |
||||
|
||||
/* Clear a transfer as if it has completed or cancelled, but do not
|
||||
* report any completion/cancellation to the library. You should free |
||||
* all private data from the transfer as if you were just about to report |
||||
* completion or cancellation. |
||||
* |
||||
* This function might seem a bit out of place. It is used when libusb |
||||
* detects a disconnected device - it calls this function for all pending |
||||
* transfers before reporting completion (with the disconnect code) to |
||||
* the user. Maybe we can improve upon this internal interface in future. |
||||
*/ |
||||
void (*clear_transfer_priv)(struct usbi_transfer *itransfer); |
||||
|
||||
/* Handle any pending events. This involves monitoring any active
|
||||
* transfers and processing their completion or cancellation. |
||||
* |
||||
* The function is passed an array of pollfd structures (size nfds) |
||||
* as a result of the poll() system call. The num_ready parameter |
||||
* indicates the number of file descriptors that have reported events |
||||
* (i.e. the poll() return value). This should be enough information |
||||
* for you to determine which actions need to be taken on the currently |
||||
* active transfers. |
||||
* |
||||
* For any cancelled transfers, call usbi_handle_transfer_cancellation(). |
||||
* For completed transfers, call usbi_handle_transfer_completion(). |
||||
* For control/bulk/interrupt transfers, populate the "transferred" |
||||
* element of the appropriate usbi_transfer structure before calling the |
||||
* above functions. For isochronous transfers, populate the status and |
||||
* transferred fields of the iso packet descriptors of the transfer. |
||||
* |
||||
* This function should also be able to detect disconnection of the |
||||
* device, reporting that situation with usbi_handle_disconnect(). |
||||
* |
||||
* When processing an event related to a transfer, you probably want to |
||||
* take usbi_transfer.lock to prevent races. See the documentation for |
||||
* the usbi_transfer structure. |
||||
* |
||||
* Return 0 on success, or a LIBUSB_ERROR code on failure. |
||||
*/ |
||||
int (*handle_events)(struct libusb_context *ctx, |
||||
struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready); |
||||
|
||||
/* Get time from specified clock. At least two clocks must be implemented
|
||||
by the backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC. |
||||
|
||||
Description of clocks: |
||||
USBI_CLOCK_REALTIME : clock returns time since system epoch. |
||||
USBI_CLOCK_MONOTONIC: clock returns time since unspecified start |
||||
time (usually boot). |
||||
*/ |
||||
int (*clock_gettime)(int clkid, struct timespec *tp); |
||||
|
||||
#ifdef USBI_TIMERFD_AVAILABLE |
||||
/* clock ID of the clock that should be used for timerfd */ |
||||
clockid_t (*get_timerfd_clockid)(void); |
||||
#endif |
||||
|
||||
/* Number of bytes to reserve for per-device private backend data.
|
||||
* This private data area is accessible through the "os_priv" field of |
||||
* struct libusb_device. */ |
||||
size_t device_priv_size; |
||||
|
||||
/* Number of bytes to reserve for per-handle private backend data.
|
||||
* This private data area is accessible through the "os_priv" field of |
||||
* struct libusb_device. */ |
||||
size_t device_handle_priv_size; |
||||
|
||||
/* Number of bytes to reserve for per-transfer private backend data.
|
||||
* This private data area is accessible by calling |
||||
* usbi_transfer_get_os_priv() on the appropriate usbi_transfer instance. |
||||
*/ |
||||
size_t transfer_priv_size; |
||||
|
||||
/* Mumber of additional bytes for os_priv for each iso packet.
|
||||
* Can your backend use this? */ |
||||
/* FIXME: linux can't use this any more. if other OS's cannot either,
|
||||
* then remove this */ |
||||
size_t add_iso_packet_size; |
||||
}; |
||||
|
||||
extern const struct usbi_os_backend * const usbi_backend; |
||||
|
||||
extern const struct usbi_os_backend linux_usbfs_backend; |
||||
extern const struct usbi_os_backend darwin_backend; |
||||
extern const struct usbi_os_backend openbsd_backend; |
||||
extern const struct usbi_os_backend windows_backend; |
||||
|
||||
extern struct list_head active_contexts_list; |
||||
extern usbi_mutex_static_t active_contexts_lock; |
||||
|
||||
#endif |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,175 +0,0 @@
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* darwin backend for libusb 1.0 |
||||
* Copyright (C) 2008-2013 Nathan Hjelm <hjelmn@users.sourceforge.net> |
||||
* |
||||
* 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 |
||||
*/ |
||||
|
||||
#if !defined(LIBUSB_DARWIN_H) |
||||
#define LIBUSB_DARWIN_H |
||||
|
||||
#include "libusbi.h" |
||||
|
||||
#include <IOKit/IOTypes.h> |
||||
#include <IOKit/IOCFBundle.h> |
||||
#include <IOKit/usb/IOUSBLib.h> |
||||
#include <IOKit/IOCFPlugIn.h> |
||||
|
||||
/* IOUSBInterfaceInferface */ |
||||
#if defined (kIOUSBInterfaceInterfaceID300) |
||||
|
||||
#define usb_interface_t IOUSBInterfaceInterface300 |
||||
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300 |
||||
#define InterfaceVersion 300 |
||||
|
||||
#elif defined (kIOUSBInterfaceInterfaceID245) |
||||
|
||||
#define usb_interface_t IOUSBInterfaceInterface245 |
||||
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245 |
||||
#define InterfaceVersion 245 |
||||
|
||||
#elif defined (kIOUSBInterfaceInterfaceID220) |
||||
|
||||
#define usb_interface_t IOUSBInterfaceInterface220 |
||||
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 |
||||
#define InterfaceVersion 220 |
||||
|
||||
#elif defined (kIOUSBInterfaceInterfaceID197) |
||||
|
||||
#define usb_interface_t IOUSBInterfaceInterface197 |
||||
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197 |
||||
#define InterfaceVersion 197 |
||||
|
||||
#elif defined (kIOUSBInterfaceInterfaceID190) |
||||
|
||||
#define usb_interface_t IOUSBInterfaceInterface190 |
||||
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190 |
||||
#define InterfaceVersion 190 |
||||
|
||||
#elif defined (kIOUSBInterfaceInterfaceID182) |
||||
|
||||
#define usb_interface_t IOUSBInterfaceInterface182 |
||||
#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182 |
||||
#define InterfaceVersion 182 |
||||
|
||||
#else |
||||
|
||||
#error "IOUSBFamily is too old. Please upgrade your OS" |
||||
|
||||
#endif |
||||
|
||||
/* IOUSBDeviceInterface */ |
||||
#if defined (kIOUSBDeviceInterfaceID500) |
||||
|
||||
#define usb_device_t IOUSBDeviceInterface500 |
||||
#define DeviceInterfaceID kIOUSBDeviceInterfaceID500 |
||||
#define DeviceVersion 500 |
||||
|
||||
#elif defined (kIOUSBDeviceInterfaceID320) |
||||
|
||||
#define usb_device_t IOUSBDeviceInterface320 |
||||
#define DeviceInterfaceID kIOUSBDeviceInterfaceID320 |
||||
#define DeviceVersion 320 |
||||
|
||||
#elif defined (kIOUSBDeviceInterfaceID300) |
||||
|
||||
#define usb_device_t IOUSBDeviceInterface300 |
||||
#define DeviceInterfaceID kIOUSBDeviceInterfaceID300 |
||||
#define DeviceVersion 300 |
||||
|
||||
#elif defined (kIOUSBDeviceInterfaceID245) |
||||
|
||||
#define usb_device_t IOUSBDeviceInterface245 |
||||
#define DeviceInterfaceID kIOUSBDeviceInterfaceID245 |
||||
#define DeviceVersion 245 |
||||
|
||||
#elif defined (kIOUSBDeviceInterfaceID197) |
||||
|
||||
#define usb_device_t IOUSBDeviceInterface197 |
||||
#define DeviceInterfaceID kIOUSBDeviceInterfaceID197 |
||||
#define DeviceVersion 197 |
||||
|
||||
#elif defined (kIOUSBDeviceInterfaceID187) |
||||
|
||||
#define usb_device_t IOUSBDeviceInterface187 |
||||
#define DeviceInterfaceID kIOUSBDeviceInterfaceID187 |
||||
#define DeviceVersion 187 |
||||
|
||||
#elif defined (kIOUSBDeviceInterfaceID182) |
||||
|
||||
#define usb_device_t IOUSBDeviceInterface182 |
||||
#define DeviceInterfaceID kIOUSBDeviceInterfaceID182 |
||||
#define DeviceVersion 182 |
||||
|
||||
#else |
||||
|
||||
#error "IOUSBFamily is too old. Please upgrade your OS" |
||||
|
||||
#endif |
||||
|
||||
#if !defined(IO_OBJECT_NULL) |
||||
#define IO_OBJECT_NULL ((io_object_t) 0) |
||||
#endif |
||||
|
||||
typedef IOCFPlugInInterface *io_cf_plugin_ref_t; |
||||
typedef IONotificationPortRef io_notification_port_t; |
||||
|
||||
/* private structures */ |
||||
struct darwin_device_priv { |
||||
IOUSBDeviceDescriptor dev_descriptor; |
||||
UInt32 location; |
||||
char sys_path[21]; |
||||
usb_device_t **device; |
||||
int open_count; |
||||
UInt8 first_config, active_config; |
||||
}; |
||||
|
||||
struct darwin_device_handle_priv { |
||||
int is_open; |
||||
CFRunLoopSourceRef cfSource; |
||||
int fds[2]; |
||||
|
||||
struct darwin_interface { |
||||
usb_interface_t **interface; |
||||
uint8_t num_endpoints; |
||||
CFRunLoopSourceRef cfSource; |
||||
uint64_t frames[256]; |
||||
uint8_t endpoint_addrs[USB_MAXENDPOINTS]; |
||||
} interfaces[USB_MAXINTERFACES]; |
||||
}; |
||||
|
||||
struct darwin_transfer_priv { |
||||
/* Isoc */ |
||||
IOUSBIsocFrame *isoc_framelist; |
||||
int num_iso_packets; |
||||
|
||||
/* Control */ |
||||
#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) |
||||
IOUSBDevRequestTO req; |
||||
#else |
||||
IOUSBDevRequest req; |
||||
#endif |
||||
|
||||
/* Bulk */ |
||||
}; |
||||
|
||||
/* structure for signaling io completion */ |
||||
struct darwin_msg_async_io_complete { |
||||
struct usbi_transfer *itransfer; |
||||
IOReturn result; |
||||
UInt32 size; |
||||
}; |
||||
|
||||
#endif |
@ -1,231 +0,0 @@
@@ -1,231 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */ |
||||
/*
|
||||
* Linux usbfs backend for libusb |
||||
* Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> |
||||
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> |
||||
* Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.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 "config.h" |
||||
#include <ctype.h> |
||||
#include <dirent.h> |
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <poll.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <arpa/inet.h> |
||||
|
||||
#include "libusb.h" |
||||
#include "libusbi.h" |
||||
#include "linux_usbfs.h" |
||||
|
||||
#include <linux/netlink.h> |
||||
#include <linux/filter.h> |
||||
|
||||
#define KERNEL 1 |
||||
|
||||
static int linux_netlink_socket = -1; |
||||
static pthread_t libusb_linux_event_thread; |
||||
|
||||
static void *linux_netlink_event_thread_main(void *arg); |
||||
|
||||
struct sockaddr_nl snl = { .nl_family=AF_NETLINK, .nl_groups=KERNEL }; |
||||
|
||||
int linux_netlink_start_event_monitor(void) |
||||
{ |
||||
int ret; |
||||
|
||||
snl.nl_groups = KERNEL; |
||||
|
||||
linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); |
||||
if (-1 == linux_netlink_socket) { |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
ret = bind(linux_netlink_socket, (struct sockaddr *) &snl, sizeof(snl)); |
||||
if (0 != ret) { |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
/* TODO -- add authentication */ |
||||
/* setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); */ |
||||
|
||||
ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL); |
||||
if (0 != ret) { |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
int linux_netlink_stop_event_monitor(void) |
||||
{ |
||||
int r; |
||||
|
||||
if (-1 == linux_netlink_socket) { |
||||
/* already closed. nothing to do */ |
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
r = close(linux_netlink_socket); |
||||
if (0 > r) { |
||||
usbi_err(NULL, "error closing netlink socket. %s", strerror(errno)); |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
pthread_cancel(libusb_linux_event_thread); |
||||
|
||||
linux_netlink_socket = -1; |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
static const char *netlink_message_parse (const char *buffer, size_t len, const char *key) |
||||
{ |
||||
size_t keylen = strlen(key); |
||||
size_t offset; |
||||
|
||||
for (offset = 0 ; offset < len && '\0' != buffer[offset] ; offset += strlen(buffer + offset) + 1) { |
||||
if (0 == strncmp(buffer + offset, key, keylen) && |
||||
'=' == buffer[offset + keylen]) { |
||||
return buffer + offset + keylen + 1; |
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
/* parse parts of netlink message common to both libudev and the kernel */ |
||||
static int linux_netlink_parse(char *buffer, size_t len, int *detached, const char **sys_name, |
||||
uint8_t *busnum, uint8_t *devaddr) { |
||||
const char *tmp; |
||||
int i; |
||||
|
||||
errno = 0; |
||||
|
||||
*sys_name = NULL; |
||||
*detached = 0; |
||||
*busnum = 0; |
||||
*devaddr = 0; |
||||
|
||||
tmp = netlink_message_parse((const char *) buffer, len, "ACTION"); |
||||
if (0 == strcmp(tmp, "remove")) { |
||||
*detached = 1; |
||||
} else if (0 != strcmp(tmp, "add")) { |
||||
usbi_dbg("unknown device action"); |
||||
return -1; |
||||
} |
||||
|
||||
/* check that this is a usb message */ |
||||
tmp = netlink_message_parse(buffer, len, "SUBSYSTEM"); |
||||
if (NULL == tmp || 0 != strcmp(tmp, "usb")) { |
||||
/* not usb. ignore */ |
||||
return -1; |
||||
} |
||||
|
||||
tmp = netlink_message_parse(buffer, len, "BUSNUM"); |
||||
if (NULL == tmp) { |
||||
/* no bus number (likely a usb interface). ignore*/ |
||||
return -1; |
||||
} |
||||
|
||||
*busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff); |
||||
if (errno) { |
||||
errno = 0; |
||||
return -1; |
||||
} |
||||
|
||||
tmp = netlink_message_parse(buffer, len, "DEVNUM"); |
||||
if (NULL == tmp) { |
||||
return -1; |
||||
} |
||||
|
||||
*devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff); |
||||
if (errno) { |
||||
errno = 0; |
||||
return -1; |
||||
} |
||||
|
||||
tmp = netlink_message_parse(buffer, len, "DEVPATH"); |
||||
if (NULL == tmp) { |
||||
return -1; |
||||
} |
||||
|
||||
for (i = strlen(tmp) - 1 ; i ; --i) { |
||||
if ('/' ==tmp[i]) { |
||||
*sys_name = tmp + i + 1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* found a usb device */ |
||||
return 0; |
||||
} |
||||
|
||||
static void *linux_netlink_event_thread_main(void *arg) |
||||
{ |
||||
struct pollfd fds = {.fd = linux_netlink_socket, |
||||
.events = POLLIN}; |
||||
unsigned char buffer[1024]; |
||||
struct iovec iov = {.iov_base = buffer, .iov_len = sizeof(buffer)}; |
||||
struct msghdr meh = { .msg_iov=&iov, .msg_iovlen=1, |
||||
.msg_name=&snl, .msg_namelen=sizeof(snl) }; |
||||
uint8_t busnum, devaddr; |
||||
int detached, r; |
||||
size_t len; |
||||
|
||||
/* silence compiler warning */ |
||||
(void) arg; |
||||
|
||||
while (1 == poll(&fds, 1, -1)) { |
||||
const char *sys_name = NULL; |
||||
|
||||
if (POLLIN != fds.revents) { |
||||
break; |
||||
} |
||||
|
||||
/* read netlink message */ |
||||
memset(buffer, 0, sizeof(buffer)); |
||||
len = recvmsg(linux_netlink_socket, &meh, 0); |
||||
if (len < 32) { |
||||
usbi_dbg("error recieving message from netlink"); |
||||
continue; |
||||
} |
||||
|
||||
/* TODO -- authenticate this message is from the kernel or udevd */ |
||||
|
||||
r = linux_netlink_parse(buffer, len, &detached, &sys_name, |
||||
&busnum, &devaddr); |
||||
if (r) |
||||
continue; |
||||
|
||||
usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s", |
||||
busnum, devaddr, sys_name, detached ? "yes" : "no"); |
||||
|
||||
/* signal device is available (or not) to all contexts */ |
||||
if (detached) |
||||
linux_hotplug_disconnected(busnum, devaddr, sys_name); |
||||
else |
||||
linux_hotplug_enumerate(busnum, devaddr, sys_name); |
||||
} |
||||
|
||||
return NULL; |
||||
} |
@ -1,242 +0,0 @@
@@ -1,242 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */ |
||||
/*
|
||||
* Linux usbfs backend for libusb |
||||
* Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> |
||||
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> |
||||
* Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@mac.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 <config.h> |
||||
#include <ctype.h> |
||||
#include <dirent.h> |
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <poll.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/ioctl.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/types.h> |
||||
#include <sys/utsname.h> |
||||
#include <sys/socket.h> |
||||
#include <unistd.h> |
||||
#include <libudev.h> |
||||
|
||||
#include "libusb.h" |
||||
#include "libusbi.h" |
||||
#include "linux_usbfs.h" |
||||
|
||||
/* udev context */ |
||||
static struct udev *udev_ctx = NULL; |
||||
static int udev_monitor_fd = -1; |
||||
static struct udev_monitor *udev_monitor = NULL; |
||||
static pthread_t linux_event_thread; |
||||
|
||||
static void udev_hotplug_event(void); |
||||
static void *linux_udev_event_thread_main(void *arg); |
||||
|
||||
int linux_udev_start_event_monitor(void) |
||||
{ |
||||
int r; |
||||
|
||||
if (NULL == udev_ctx) { |
||||
udev_ctx = udev_new(); |
||||
if (!udev_ctx) { |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
} |
||||
|
||||
udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev"); |
||||
if (!udev_monitor) { |
||||
usbi_err(NULL, "could not initialize udev monitor"); |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", 0); |
||||
if (r) { |
||||
usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem"); |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
if (udev_monitor_enable_receiving(udev_monitor)) { |
||||
usbi_err(NULL, "failed to enable the udev monitor"); |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
udev_monitor_fd = udev_monitor_get_fd(udev_monitor); |
||||
|
||||
pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL); |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
int linux_udev_stop_event_monitor(void) |
||||
{ |
||||
if (-1 == udev_monitor_fd) { |
||||
/* this should never happen */ |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
/* Cancel the event thread. This is the only way to garauntee the thread
|
||||
exits since closing the monitor fd won't necessarily cause poll |
||||
to return. */ |
||||
pthread_cancel(linux_event_thread); |
||||
|
||||
/* Release the udev monitor */ |
||||
udev_monitor_unref(udev_monitor); |
||||
udev_monitor = NULL; |
||||
udev_monitor_fd = -1; |
||||
|
||||
/* Clean up the udev context */ |
||||
udev_unref(udev_ctx); |
||||
udev_ctx = NULL; |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
||||
static void *linux_udev_event_thread_main(void __attribute__((unused)) *arg) |
||||
{ |
||||
struct pollfd fds = {.fd = udev_monitor_fd, |
||||
.events = POLLIN}; |
||||
|
||||
usbi_dbg("udev event thread entering."); |
||||
|
||||
while (1 == poll(&fds, 1, -1)) { |
||||
if (NULL == udev_monitor || POLLIN != fds.revents) { |
||||
break; |
||||
} |
||||
|
||||
udev_hotplug_event(); |
||||
} |
||||
|
||||
usbi_dbg("udev event thread exiting"); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
static int udev_device_info(struct libusb_context *ctx, int detached, |
||||
struct udev_device *udev_dev, uint8_t *busnum, |
||||
uint8_t *devaddr, const char **sys_name) { |
||||
const char *dev_node; |
||||
|
||||
dev_node = udev_device_get_devnode(udev_dev); |
||||
if (!dev_node) { |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
*sys_name = udev_device_get_sysname(udev_dev); |
||||
if (!*sys_name) { |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
return linux_get_device_address(ctx, detached, busnum, devaddr, |
||||
dev_node, *sys_name); |
||||
} |
||||
|
||||
static void udev_hotplug_event(void) |
||||
{ |
||||
struct udev_device* udev_dev; |
||||
const char* udev_action; |
||||
const char* sys_name = NULL; |
||||
uint8_t busnum = 0, devaddr = 0; |
||||
int detached; |
||||
int r; |
||||
|
||||
if (NULL == udev_monitor) { |
||||
return; |
||||
} |
||||
|
||||
do { |
||||
udev_dev = udev_monitor_receive_device(udev_monitor); |
||||
if (!udev_dev) { |
||||
usbi_err(NULL, "failed to read data from udev monitor socket."); |
||||
return; |
||||
} |
||||
|
||||
udev_action = udev_device_get_action(udev_dev); |
||||
if (!udev_action) { |
||||
break; |
||||
} |
||||
|
||||
detached = !strncmp(udev_action, "remove", 6); |
||||
|
||||
r = udev_device_info(NULL, detached, udev_dev, &busnum, &devaddr, &sys_name); |
||||
if (LIBUSB_SUCCESS != r) { |
||||
break; |
||||
} |
||||
|
||||
usbi_dbg("udev hotplug event. action: %s.", udev_action); |
||||
|
||||
if (strncmp(udev_action, "add", 3) == 0) { |
||||
linux_hotplug_enumerate(busnum, devaddr, sys_name); |
||||
} else if (detached) { |
||||
linux_hotplug_disconnected(busnum, devaddr, sys_name); |
||||
} else { |
||||
usbi_err(NULL, "ignoring udev action %s", udev_action); |
||||
} |
||||
} while (0); |
||||
|
||||
udev_device_unref(udev_dev); |
||||
} |
||||
|
||||
int linux_udev_scan_devices(struct libusb_context *ctx) |
||||
{ |
||||
struct udev_enumerate *enumerator; |
||||
struct udev_list_entry *devices, *entry; |
||||
struct udev_device *udev_dev; |
||||
const char *sys_name; |
||||
int r; |
||||
|
||||
if (NULL == udev_ctx) { |
||||
udev_ctx = udev_new(); |
||||
if (!udev_ctx) { |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
} |
||||
|
||||
enumerator = udev_enumerate_new(udev_ctx); |
||||
if (NULL == enumerator) { |
||||
usbi_err(ctx, "error creating udev enumerator"); |
||||
return LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
udev_enumerate_add_match_subsystem(enumerator, "usb"); |
||||
udev_enumerate_scan_devices(enumerator); |
||||
devices = udev_enumerate_get_list_entry(enumerator); |
||||
|
||||
udev_list_entry_foreach(entry, devices) { |
||||
const char *path = udev_list_entry_get_name(entry); |
||||
uint8_t busnum = 0, devaddr = 0; |
||||
|
||||
udev_dev = udev_device_new_from_syspath(udev_ctx, path); |
||||
|
||||
r = udev_device_info(ctx, 0, udev_dev, &busnum, &devaddr, &sys_name); |
||||
if (r) { |
||||
udev_device_unref(udev_dev); |
||||
continue; |
||||
} |
||||
|
||||
linux_enumerate_device(ctx, busnum, devaddr, sys_name); |
||||
udev_device_unref(udev_dev); |
||||
} |
||||
|
||||
udev_enumerate_unref(enumerator); |
||||
|
||||
return LIBUSB_SUCCESS; |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,168 +0,0 @@
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* usbfs header structures |
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> |
||||
* Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.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 |
||||
*/ |
||||
|
||||
#ifndef LIBUSB_USBFS_H |
||||
#define LIBUSB_USBFS_H |
||||
|
||||
#include <linux/types.h> |
||||
|
||||
#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices" |
||||
|
||||
struct usbfs_ctrltransfer { |
||||
/* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */ |
||||
uint8_t bmRequestType; |
||||
uint8_t bRequest; |
||||
uint16_t wValue; |
||||
uint16_t wIndex; |
||||
uint16_t wLength; |
||||
|
||||
uint32_t timeout; /* in milliseconds */ |
||||
|
||||
/* pointer to data */ |
||||
void *data; |
||||
}; |
||||
|
||||
struct usbfs_bulktransfer { |
||||
/* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */ |
||||
unsigned int ep; |
||||
unsigned int len; |
||||
unsigned int timeout; /* in milliseconds */ |
||||
|
||||
/* pointer to data */ |
||||
void *data; |
||||
}; |
||||
|
||||
struct usbfs_setinterface { |
||||
/* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */ |
||||
unsigned int interface; |
||||
unsigned int altsetting; |
||||
}; |
||||
|
||||
#define USBFS_MAXDRIVERNAME 255 |
||||
|
||||
struct usbfs_getdriver { |
||||
unsigned int interface; |
||||
char driver[USBFS_MAXDRIVERNAME + 1]; |
||||
}; |
||||
|
||||
#define USBFS_URB_SHORT_NOT_OK 0x01 |
||||
#define USBFS_URB_ISO_ASAP 0x02 |
||||
#define USBFS_URB_BULK_CONTINUATION 0x04 |
||||
#define USBFS_URB_QUEUE_BULK 0x10 |
||||
#define USBFS_URB_ZERO_PACKET 0x40 |
||||
|
||||
enum usbfs_urb_type { |
||||
USBFS_URB_TYPE_ISO = 0, |
||||
USBFS_URB_TYPE_INTERRUPT = 1, |
||||
USBFS_URB_TYPE_CONTROL = 2, |
||||
USBFS_URB_TYPE_BULK = 3, |
||||
}; |
||||
|
||||
struct usbfs_iso_packet_desc { |
||||
unsigned int length; |
||||
unsigned int actual_length; |
||||
unsigned int status; |
||||
}; |
||||
|
||||
#define MAX_ISO_BUFFER_LENGTH 32768 |
||||
#define MAX_BULK_BUFFER_LENGTH 16384 |
||||
#define MAX_CTRL_BUFFER_LENGTH 4096 |
||||
|
||||
struct usbfs_urb { |
||||
unsigned char type; |
||||
unsigned char endpoint; |
||||
int status; |
||||
unsigned int flags; |
||||
void *buffer; |
||||
int buffer_length; |
||||
int actual_length; |
||||
int start_frame; |
||||
int number_of_packets; |
||||
int error_count; |
||||
unsigned int signr; |
||||
void *usercontext; |
||||
struct usbfs_iso_packet_desc iso_frame_desc[0]; |
||||
}; |
||||
|
||||
struct usbfs_connectinfo { |
||||
unsigned int devnum; |
||||
unsigned char slow; |
||||
}; |
||||
|
||||
struct usbfs_ioctl { |
||||
int ifno; /* interface 0..N ; negative numbers reserved */ |
||||
int ioctl_code; /* MUST encode size + direction of data so the
|
||||
* macros in <asm/ioctl.h> give correct values */ |
||||
void *data; /* param buffer (in, or out) */ |
||||
}; |
||||
|
||||
struct usbfs_hub_portinfo { |
||||
unsigned char numports; |
||||
unsigned char port[127]; /* port to device num mapping */ |
||||
}; |
||||
|
||||
#define USBFS_CAP_ZERO_PACKET 0x01 |
||||
#define USBFS_CAP_BULK_CONTINUATION 0x02 |
||||
#define USBFS_CAP_NO_PACKET_SIZE_LIM 0x04 |
||||
#define USBFS_CAP_BULK_SCATTER_GATHER 0x08 |
||||
|
||||
#define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer) |
||||
#define IOCTL_USBFS_BULK _IOWR('U', 2, struct usbfs_bulktransfer) |
||||
#define IOCTL_USBFS_RESETEP _IOR('U', 3, unsigned int) |
||||
#define IOCTL_USBFS_SETINTF _IOR('U', 4, struct usbfs_setinterface) |
||||
#define IOCTL_USBFS_SETCONFIG _IOR('U', 5, unsigned int) |
||||
#define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver) |
||||
#define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb) |
||||
#define IOCTL_USBFS_DISCARDURB _IO('U', 11) |
||||
#define IOCTL_USBFS_REAPURB _IOW('U', 12, void *) |
||||
#define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *) |
||||
#define IOCTL_USBFS_CLAIMINTF _IOR('U', 15, unsigned int) |
||||
#define IOCTL_USBFS_RELEASEINTF _IOR('U', 16, unsigned int) |
||||
#define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo) |
||||
#define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl) |
||||
#define IOCTL_USBFS_HUB_PORTINFO _IOR('U', 19, struct usbfs_hub_portinfo) |
||||
#define IOCTL_USBFS_RESET _IO('U', 20) |
||||
#define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int) |
||||
#define IOCTL_USBFS_DISCONNECT _IO('U', 22) |
||||
#define IOCTL_USBFS_CONNECT _IO('U', 23) |
||||
#define IOCTL_USBFS_CLAIM_PORT _IOR('U', 24, unsigned int) |
||||
#define IOCTL_USBFS_RELEASE_PORT _IOR('U', 25, unsigned int) |
||||
#define IOCTL_USBFS_GET_CAPABILITIES _IOR('U', 26, __u32) |
||||
|
||||
#if defined(HAVE_LIBUDEV) |
||||
int linux_udev_start_event_monitor(void); |
||||
int linux_udev_stop_event_monitor(void); |
||||
int linux_udev_scan_devices(struct libusb_context *ctx); |
||||
#else |
||||
int linux_netlink_start_event_monitor(void); |
||||
int linux_netlink_stop_event_monitor(void); |
||||
#endif |
||||
|
||||
void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name); |
||||
void linux_hotplug_disconnected(uint8_t busnum, uint8_t devaddr, const char *sys_name); |
||||
|
||||
int linux_get_device_address (struct libusb_context *ctx, int detached, |
||||
uint8_t *busnum, uint8_t *devaddr, |
||||
const char *dev_node, const char *sys_name); |
||||
int linux_enumerate_device(struct libusb_context *ctx, |
||||
uint8_t busnum, uint8_t devaddr, |
||||
const char *sysfs_dir); |
||||
|
||||
#endif |
@ -1,727 +0,0 @@
@@ -1,727 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Martin Pieuchot <mpi@openbsd.org> |
||||
* |
||||
* 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 <sys/time.h> |
||||
#include <sys/types.h> |
||||
|
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <dev/usb/usb.h> |
||||
|
||||
#include "libusb.h" |
||||
#include "libusbi.h" |
||||
|
||||
struct device_priv { |
||||
char devnode[16]; |
||||
int fd; |
||||
|
||||
unsigned char *cdesc; /* active config descriptor */ |
||||
usb_device_descriptor_t ddesc; /* usb device descriptor */ |
||||
}; |
||||
|
||||
struct handle_priv { |
||||
int pipe[2]; /* for event notification */ |
||||
int endpoints[USB_MAX_ENDPOINTS]; |
||||
}; |
||||
|
||||
/*
|
||||
* Backend functions |
||||
*/ |
||||
static int obsd_get_device_list(struct libusb_context *, |
||||
struct discovered_devs **); |
||||
static int obsd_open(struct libusb_device_handle *); |
||||
static void obsd_close(struct libusb_device_handle *); |
||||
|
||||
static int obsd_get_device_descriptor(struct libusb_device *, unsigned char *, |
||||
int *); |
||||
static int obsd_get_active_config_descriptor(struct libusb_device *, |
||||
unsigned char *, size_t, int *); |
||||
static int obsd_get_config_descriptor(struct libusb_device *, uint8_t, |
||||
unsigned char *, size_t, int *); |
||||
|
||||
static int obsd_get_configuration(struct libusb_device_handle *, int *); |
||||
static int obsd_set_configuration(struct libusb_device_handle *, int); |
||||
|
||||
static int obsd_claim_interface(struct libusb_device_handle *, int); |
||||
static int obsd_release_interface(struct libusb_device_handle *, int); |
||||
|
||||
static int obsd_set_interface_altsetting(struct libusb_device_handle *, int, |
||||
int); |
||||
static int obsd_clear_halt(struct libusb_device_handle *, unsigned char); |
||||
static int obsd_reset_device(struct libusb_device_handle *); |
||||
static void obsd_destroy_device(struct libusb_device *); |
||||
|
||||
static int obsd_submit_transfer(struct usbi_transfer *); |
||||
static int obsd_cancel_transfer(struct usbi_transfer *); |
||||
static void obsd_clear_transfer_priv(struct usbi_transfer *); |
||||
static int obsd_handle_events(struct libusb_context *ctx, struct pollfd *, |
||||
nfds_t, int); |
||||
static int obsd_clock_gettime(int, struct timespec *); |
||||
|
||||
/*
|
||||
* Private functions |
||||
*/ |
||||
static int _errno_to_libusb(int); |
||||
static int _cache_active_config_descriptor(struct libusb_device *, int); |
||||
static int _sync_control_transfer(struct usbi_transfer *); |
||||
static int _sync_gen_transfer(struct usbi_transfer *); |
||||
static int _access_endpoint(struct libusb_transfer *); |
||||
|
||||
const struct usbi_os_backend openbsd_backend = { |
||||
"Synchronous OpenBSD backend", |
||||
NULL, /* init() */ |
||||
NULL, /* exit() */ |
||||
obsd_get_device_list, |
||||
obsd_open, |
||||
obsd_close, |
||||
|
||||
obsd_get_device_descriptor, |
||||
obsd_get_active_config_descriptor, |
||||
obsd_get_config_descriptor, |
||||
|
||||
obsd_get_configuration, |
||||
obsd_set_configuration, |
||||
|
||||
obsd_claim_interface, |
||||
obsd_release_interface, |
||||
|
||||
obsd_set_interface_altsetting, |
||||
obsd_clear_halt, |
||||
obsd_reset_device, |
||||
|
||||
NULL, /* kernel_driver_active() */ |
||||
NULL, /* detach_kernel_driver() */ |
||||
NULL, /* attach_kernel_driver() */ |
||||
|
||||
obsd_destroy_device, |
||||
|
||||
obsd_submit_transfer, |
||||
obsd_cancel_transfer, |
||||
obsd_clear_transfer_priv, |
||||
|
||||
obsd_handle_events, |
||||
|
||||
obsd_clock_gettime, |
||||
sizeof(struct device_priv), |
||||
sizeof(struct handle_priv), |
||||
0, /* transfer_priv_size */ |
||||
0, /* add_iso_packet_size */ |
||||
}; |
||||
|
||||
int |
||||
obsd_get_device_list(struct libusb_context * ctx, |
||||
struct discovered_devs **discdevs) |
||||
{ |
||||
struct libusb_device *dev; |
||||
struct device_priv *dpriv; |
||||
struct usb_device_info di; |
||||
unsigned long session_id; |
||||
char devnode[16]; |
||||
int fd, err, i; |
||||
|
||||
usbi_dbg(""); |
||||
|
||||
/* Only ugen(4) is supported */ |
||||
for (i = 0; i < USB_MAX_DEVICES; i++) { |
||||
/* Control endpoint is always .00 */ |
||||
snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i); |
||||
|
||||
if ((fd = open(devnode, O_RDONLY)) < 0) { |
||||
if (errno != ENOENT && errno != ENXIO) |
||||
usbi_err(ctx, "could not open %s", devnode); |
||||
continue; |
||||
} |
||||
|
||||
if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0) |
||||
continue; |
||||
|
||||
session_id = (di.udi_bus << 8 | di.udi_addr); |
||||
dev = usbi_get_device_by_session_id(ctx, session_id); |
||||
|
||||
if (dev == NULL) { |
||||
dev = usbi_alloc_device(ctx, session_id); |
||||
if (dev == NULL) |
||||
return (LIBUSB_ERROR_NO_MEM); |
||||
|
||||
dev->bus_number = di.udi_bus; |
||||
dev->device_address = di.udi_addr; |
||||
dev->speed = di.udi_speed; |
||||
|
||||
dpriv = (struct device_priv *)dev->os_priv; |
||||
strlcpy(dpriv->devnode, devnode, sizeof(devnode)); |
||||
dpriv->fd = -1; |
||||
|
||||
if (ioctl(fd, USB_GET_DEVICE_DESC, &dpriv->ddesc) < 0) { |
||||
err = errno; |
||||
goto error; |
||||
} |
||||
|
||||
dpriv->cdesc = NULL; |
||||
if (_cache_active_config_descriptor(dev, fd)) { |
||||
err = errno; |
||||
goto error; |
||||
} |
||||
|
||||
if ((err = usbi_sanitize_device(dev))) |
||||
goto error; |
||||
} |
||||
close(fd); |
||||
|
||||
if (discovered_devs_append(*discdevs, dev) == NULL) |
||||
return (LIBUSB_ERROR_NO_MEM); |
||||
} |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
|
||||
error: |
||||
close(fd); |
||||
libusb_unref_device(dev); |
||||
return _errno_to_libusb(err); |
||||
} |
||||
|
||||
int |
||||
obsd_open(struct libusb_device_handle *handle) |
||||
{ |
||||
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; |
||||
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; |
||||
|
||||
dpriv->fd = open(dpriv->devnode, O_RDWR); |
||||
if (dpriv->fd < 0) { |
||||
dpriv->fd = open(dpriv->devnode, O_RDONLY); |
||||
if (dpriv->fd < 0) |
||||
return _errno_to_libusb(errno); |
||||
} |
||||
|
||||
usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd); |
||||
|
||||
if (pipe(hpriv->pipe) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->pipe[0], POLLIN); |
||||
} |
||||
|
||||
void |
||||
obsd_close(struct libusb_device_handle *handle) |
||||
{ |
||||
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; |
||||
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; |
||||
|
||||
usbi_dbg("close: fd %d", dpriv->fd); |
||||
|
||||
close(dpriv->fd); |
||||
dpriv->fd = -1; |
||||
|
||||
usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]); |
||||
|
||||
close(hpriv->pipe[0]); |
||||
close(hpriv->pipe[1]); |
||||
} |
||||
|
||||
int |
||||
obsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf, |
||||
int *host_endian) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; |
||||
|
||||
usbi_dbg(""); |
||||
|
||||
memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH); |
||||
|
||||
*host_endian = 0; |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_get_active_config_descriptor(struct libusb_device *dev, |
||||
unsigned char *buf, size_t len, int *host_endian) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; |
||||
usb_config_descriptor_t *ucd; |
||||
|
||||
ucd = (usb_config_descriptor_t *) dpriv->cdesc; |
||||
len = MIN(len, UGETW(ucd->wTotalLength)); |
||||
|
||||
usbi_dbg("len %d", len); |
||||
|
||||
memcpy(buf, dpriv->cdesc, len); |
||||
|
||||
*host_endian = 0; |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx, |
||||
unsigned char *buf, size_t len, int *host_endian) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; |
||||
struct usb_full_desc ufd; |
||||
int fd, err; |
||||
|
||||
usbi_dbg("index %d, len %d", idx, len); |
||||
|
||||
/* A config descriptor may be requested before opening the device */ |
||||
if (dpriv->fd >= 0) { |
||||
fd = dpriv->fd; |
||||
} else { |
||||
fd = open(dpriv->devnode, O_RDONLY); |
||||
if (fd < 0) |
||||
return _errno_to_libusb(errno); |
||||
} |
||||
|
||||
ufd.ufd_config_index = idx; |
||||
ufd.ufd_size = len; |
||||
ufd.ufd_data = buf; |
||||
|
||||
if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) { |
||||
err = errno; |
||||
if (dpriv->fd < 0) |
||||
close(fd); |
||||
return _errno_to_libusb(err); |
||||
} |
||||
|
||||
if (dpriv->fd < 0) |
||||
close(fd); |
||||
|
||||
*host_endian = 0; |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_get_configuration(struct libusb_device_handle *handle, int *config) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; |
||||
|
||||
usbi_dbg(""); |
||||
|
||||
if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
usbi_dbg("configuration %d", *config); |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_set_configuration(struct libusb_device_handle *handle, int config) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; |
||||
|
||||
usbi_dbg("configuration %d", config); |
||||
|
||||
if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
return _cache_active_config_descriptor(handle->dev, dpriv->fd); |
||||
} |
||||
|
||||
int |
||||
obsd_claim_interface(struct libusb_device_handle *handle, int iface) |
||||
{ |
||||
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; |
||||
int i; |
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++) |
||||
hpriv->endpoints[i] = -1; |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_release_interface(struct libusb_device_handle *handle, int iface) |
||||
{ |
||||
struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv; |
||||
int i; |
||||
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++) |
||||
if (hpriv->endpoints[i] >= 0) |
||||
close(hpriv->endpoints[i]); |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface, |
||||
int altsetting) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; |
||||
struct usb_alt_interface intf; |
||||
|
||||
usbi_dbg("iface %d, setting %d", iface, altsetting); |
||||
|
||||
memset(&intf, 0, sizeof(intf)); |
||||
|
||||
intf.uai_interface_index = iface; |
||||
intf.uai_alt_no = altsetting; |
||||
|
||||
if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv; |
||||
struct usb_ctl_request req; |
||||
|
||||
usbi_dbg(""); |
||||
|
||||
req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT; |
||||
req.ucr_request.bRequest = UR_CLEAR_FEATURE; |
||||
USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT); |
||||
USETW(req.ucr_request.wIndex, endpoint); |
||||
USETW(req.ucr_request.wLength, 0); |
||||
|
||||
if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_reset_device(struct libusb_device_handle *handle) |
||||
{ |
||||
usbi_dbg(""); |
||||
|
||||
return (LIBUSB_ERROR_NOT_SUPPORTED); |
||||
} |
||||
|
||||
void |
||||
obsd_destroy_device(struct libusb_device *dev) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; |
||||
|
||||
usbi_dbg(""); |
||||
|
||||
free(dpriv->cdesc); |
||||
} |
||||
|
||||
int |
||||
obsd_submit_transfer(struct usbi_transfer *itransfer) |
||||
{ |
||||
struct libusb_transfer *transfer; |
||||
struct handle_priv *hpriv; |
||||
int err = 0; |
||||
|
||||
usbi_dbg(""); |
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); |
||||
hpriv = (struct handle_priv *)transfer->dev_handle->os_priv; |
||||
|
||||
switch (transfer->type) { |
||||
case LIBUSB_TRANSFER_TYPE_CONTROL: |
||||
err = _sync_control_transfer(itransfer); |
||||
break; |
||||
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: |
||||
if (IS_XFEROUT(transfer)) { |
||||
/* Isochronous write is not supported */ |
||||
err = LIBUSB_ERROR_NOT_SUPPORTED; |
||||
break; |
||||
} |
||||
err = _sync_gen_transfer(itransfer); |
||||
break; |
||||
case LIBUSB_TRANSFER_TYPE_BULK: |
||||
case LIBUSB_TRANSFER_TYPE_INTERRUPT: |
||||
if (IS_XFEROUT(transfer) && |
||||
transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) { |
||||
err = LIBUSB_ERROR_NOT_SUPPORTED; |
||||
break; |
||||
} |
||||
err = _sync_gen_transfer(itransfer); |
||||
break; |
||||
} |
||||
|
||||
if (err) |
||||
return (err); |
||||
|
||||
if (write(hpriv->pipe[1], &itransfer, sizeof(itransfer)) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_cancel_transfer(struct usbi_transfer *itransfer) |
||||
{ |
||||
usbi_dbg(""); |
||||
|
||||
return (LIBUSB_ERROR_NOT_SUPPORTED); |
||||
} |
||||
|
||||
void |
||||
obsd_clear_transfer_priv(struct usbi_transfer *itransfer) |
||||
{ |
||||
usbi_dbg(""); |
||||
|
||||
/* Nothing to do */ |
||||
} |
||||
|
||||
int |
||||
obsd_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, |
||||
int num_ready) |
||||
{ |
||||
struct libusb_device_handle *handle; |
||||
struct handle_priv *hpriv = NULL; |
||||
struct usbi_transfer *itransfer; |
||||
struct pollfd *pollfd; |
||||
int i, err = 0; |
||||
|
||||
usbi_dbg(""); |
||||
|
||||
pthread_mutex_lock(&ctx->open_devs_lock); |
||||
for (i = 0; i < nfds && num_ready > 0; i++) { |
||||
pollfd = &fds[i]; |
||||
|
||||
if (!pollfd->revents) |
||||
continue; |
||||
|
||||
hpriv = NULL; |
||||
num_ready--; |
||||
list_for_each_entry(handle, &ctx->open_devs, list, |
||||
struct libusb_device_handle) { |
||||
hpriv = (struct handle_priv *)handle->os_priv; |
||||
|
||||
if (hpriv->pipe[0] == pollfd->fd) |
||||
break; |
||||
|
||||
hpriv = NULL; |
||||
} |
||||
|
||||
if (NULL == hpriv) { |
||||
usbi_dbg("fd %d is not an event pipe!", pollfd->fd); |
||||
err = ENOENT; |
||||
break; |
||||
} |
||||
|
||||
if (pollfd->revents & POLLERR) { |
||||
usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->pipe[0]); |
||||
usbi_handle_disconnect(handle); |
||||
continue; |
||||
} |
||||
|
||||
if (read(hpriv->pipe[0], &itransfer, sizeof(itransfer)) < 0) { |
||||
err = errno; |
||||
break; |
||||
} |
||||
|
||||
if ((err = usbi_handle_transfer_completion(itransfer, |
||||
LIBUSB_TRANSFER_COMPLETED))) |
||||
break; |
||||
} |
||||
pthread_mutex_unlock(&ctx->open_devs_lock); |
||||
|
||||
if (err) |
||||
return _errno_to_libusb(err); |
||||
|
||||
return (LIBUSB_SUCCESS); |
||||
} |
||||
|
||||
int |
||||
obsd_clock_gettime(int clkid, struct timespec *tp) |
||||
{ |
||||
usbi_dbg("clock %d", clkid); |
||||
|
||||
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); |
||||
} |
||||
|
||||
int |
||||
_errno_to_libusb(int err) |
||||
{ |
||||
switch (err) { |
||||
case EIO: |
||||
return (LIBUSB_ERROR_IO); |
||||
case EACCES: |
||||
return (LIBUSB_ERROR_ACCESS); |
||||
case ENOENT: |
||||
return (LIBUSB_ERROR_NO_DEVICE); |
||||
case ENOMEM: |
||||
return (LIBUSB_ERROR_NO_MEM); |
||||
} |
||||
|
||||
usbi_dbg("error: %s", strerror(err)); |
||||
|
||||
return (LIBUSB_ERROR_OTHER); |
||||
} |
||||
|
||||
int |
||||
_cache_active_config_descriptor(struct libusb_device *dev, int fd) |
||||
{ |
||||
struct device_priv *dpriv = (struct device_priv *)dev->os_priv; |
||||
struct usb_config_desc ucd; |
||||
struct usb_full_desc ufd; |
||||
unsigned char* buf; |
||||
int len; |
||||
|
||||
usbi_dbg("fd %d", fd); |
||||
|
||||
ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX; |
||||
|
||||
if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
usbi_dbg("active bLength %d", ucd.ucd_desc.bLength); |
||||
|
||||
len = UGETW(ucd.ucd_desc.wTotalLength); |
||||
buf = malloc(len); |
||||
if (buf == NULL) |
||||
return (LIBUSB_ERROR_NO_MEM); |
||||
|
||||
ufd.ufd_config_index = ucd.ucd_config_index; |
||||
ufd.ufd_size = len; |
||||
ufd.ufd_data = buf; |
||||
|
||||
usbi_dbg("index %d, len %d", ufd.ufd_config_index, len); |
||||
|
||||
if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) { |
||||
free(buf); |
||||
return _errno_to_libusb(errno); |
||||
} |
||||
|
||||
if (dpriv->cdesc) |
||||
free(dpriv->cdesc); |
||||
dpriv->cdesc = buf; |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
int |
||||
_sync_control_transfer(struct usbi_transfer *itransfer) |
||||
{ |
||||
struct libusb_transfer *transfer; |
||||
struct libusb_control_setup *setup; |
||||
struct device_priv *dpriv; |
||||
struct usb_ctl_request req; |
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); |
||||
dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; |
||||
setup = (struct libusb_control_setup *)transfer->buffer; |
||||
|
||||
usbi_dbg("type %d request %d value %d index %d length %d timeout %d", |
||||
setup->bmRequestType, setup->bRequest, |
||||
libusb_le16_to_cpu(setup->wValue), |
||||
libusb_le16_to_cpu(setup->wIndex), |
||||
libusb_le16_to_cpu(setup->wLength), transfer->timeout); |
||||
|
||||
req.ucr_request.bmRequestType = setup->bmRequestType; |
||||
req.ucr_request.bRequest = setup->bRequest; |
||||
/* Don't use USETW, libusb already deals with the endianness */ |
||||
(*(uint16_t *)req.ucr_request.wValue) = setup->wValue; |
||||
(*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex; |
||||
(*(uint16_t *)req.ucr_request.wLength) = setup->wLength; |
||||
req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; |
||||
|
||||
if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0) |
||||
req.ucr_flags = USBD_SHORT_XFER_OK; |
||||
|
||||
if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
itransfer->transferred = req.ucr_actlen; |
||||
|
||||
usbi_dbg("transferred %d", itransfer->transferred); |
||||
|
||||
return (0); |
||||
} |
||||
|
||||
int |
||||
_access_endpoint(struct libusb_transfer *transfer) |
||||
{ |
||||
struct handle_priv *hpriv; |
||||
struct device_priv *dpriv; |
||||
char *s, devnode[16]; |
||||
int fd, endpt; |
||||
mode_t mode; |
||||
|
||||
hpriv = (struct handle_priv *)transfer->dev_handle->os_priv; |
||||
dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv; |
||||
|
||||
endpt = UE_GET_ADDR(transfer->endpoint); |
||||
mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY; |
||||
|
||||
usbi_dbg("endpoint %d mode %d", endpt, mode); |
||||
|
||||
if (hpriv->endpoints[endpt] < 0) { |
||||
/* Pick the right node given the control one */ |
||||
strlcpy(devnode, dpriv->devnode, sizeof(devnode)); |
||||
s = strchr(devnode, '.'); |
||||
snprintf(s, 4, ".%02d", endpt); |
||||
|
||||
/* We may need to read/write to the same endpoint later. */ |
||||
if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO)) |
||||
if ((fd = open(devnode, mode)) < 0) |
||||
return (-1); |
||||
|
||||
hpriv->endpoints[endpt] = fd; |
||||
} |
||||
|
||||
return (hpriv->endpoints[endpt]); |
||||
} |
||||
|
||||
int |
||||
_sync_gen_transfer(struct usbi_transfer *itransfer) |
||||
{ |
||||
struct libusb_transfer *transfer; |
||||
int fd, nr = 1; |
||||
|
||||
transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); |
||||
|
||||
/*
|
||||
* Bulk, Interrupt or Isochronous transfer depends on the |
||||
* endpoint and thus the node to open. |
||||
*/ |
||||
if ((fd = _access_endpoint(transfer)) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
if (IS_XFERIN(transfer)) { |
||||
if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0) |
||||
if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
nr = read(fd, transfer->buffer, transfer->length); |
||||
} else { |
||||
nr = write(fd, transfer->buffer, transfer->length); |
||||
} |
||||
|
||||
if (nr < 0) |
||||
return _errno_to_libusb(errno); |
||||
|
||||
itransfer->transferred = nr; |
||||
|
||||
return (0); |
||||
} |
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
#ifndef LIBUSB_POLL_POSIX_H |
||||
#define LIBUSB_POLL_POSIX_H |
||||
|
||||
#define usbi_write write |
||||
#define usbi_read read |
||||
#define usbi_close close |
||||
#define usbi_pipe pipe |
||||
#define usbi_poll poll |
||||
|
||||
#endif /* LIBUSB_POLL_POSIX_H */ |
@ -1,745 +0,0 @@
@@ -1,745 +0,0 @@
|
||||
/*
|
||||
* poll_windows: poll compatibility wrapper for Windows |
||||
* Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> |
||||
* With contributions from Michael Plante, Orin Eman et al. |
||||
* Parts of poll implementation from libusb-win32, by Stephan Meyer et al. |
||||
* |
||||
* 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 |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* poll() and pipe() Windows compatibility layer for libusb 1.0 |
||||
* |
||||
* The way this layer works is by using OVERLAPPED with async I/O transfers, as |
||||
* OVERLAPPED have an associated event which is flagged for I/O completion. |
||||
* |
||||
* For USB pollable async I/O, you would typically: |
||||
* - obtain a Windows HANDLE to a file or device that has been opened in |
||||
* OVERLAPPED mode |
||||
* - call usbi_create_fd with this handle to obtain a custom fd. |
||||
* Note that if you need simultaneous R/W access, you need to call create_fd |
||||
* twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate |
||||
* pollable fds |
||||
* - leave the core functions call the poll routine and flag POLLIN/POLLOUT |
||||
* |
||||
* The pipe pollable synchronous I/O works using the overlapped event associated |
||||
* with a fake pipe. The read/write functions are only meant to be used in that |
||||
* context. |
||||
*/ |
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <io.h> |
||||
|
||||
#include <libusbi.h> |
||||
|
||||
// Uncomment to debug the polling layer
|
||||
//#define DEBUG_POLL_WINDOWS
|
||||
#if defined(DEBUG_POLL_WINDOWS) |
||||
#define poll_dbg usbi_dbg |
||||
#else |
||||
// MSVC++ < 2005 cannot use a variadic argument and non MSVC
|
||||
// compilers produce warnings if parenthesis are omitted.
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1400 |
||||
#define poll_dbg |
||||
#else |
||||
#define poll_dbg(...) |
||||
#endif |
||||
#endif |
||||
|
||||
#if defined(_PREFAST_) |
||||
#pragma warning(disable:28719) |
||||
#endif |
||||
|
||||
#if defined(__CYGWIN__) |
||||
// cygwin produces a warning unless these prototypes are defined
|
||||
extern int _open(char* name, int flags); |
||||
extern int _close(int fd); |
||||
extern int _snprintf(char *buffer, size_t count, const char *format, ...); |
||||
#define NUL_DEVICE "/dev/null" |
||||
#else |
||||
#define NUL_DEVICE "NUL" |
||||
#endif |
||||
|
||||
#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) |
||||
|
||||
// public fd data
|
||||
const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE}; |
||||
struct winfd poll_fd[MAX_FDS]; |
||||
// internal fd data
|
||||
struct { |
||||
CRITICAL_SECTION mutex; // lock for fds
|
||||
// Additional variables for XP CancelIoEx partial emulation
|
||||
HANDLE original_handle; |
||||
DWORD thread_id; |
||||
} _poll_fd[MAX_FDS]; |
||||
|
||||
// globals
|
||||
BOOLEAN is_polling_set = FALSE; |
||||
LONG pipe_number = 0; |
||||
static volatile LONG compat_spinlock = 0; |
||||
|
||||
// CancelIoEx, available on Vista and later only, provides the ability to cancel
|
||||
// a single transfer (OVERLAPPED) when used. As it may not be part of any of the
|
||||
// platform headers, we hook into the Kernel32 system DLL directly to seek it.
|
||||
static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; |
||||
#define CancelIoEx_Available (pCancelIoEx != NULL) |
||||
static __inline BOOL cancel_io(int _index) |
||||
{ |
||||
if ((_index < 0) || (_index >= MAX_FDS)) { |
||||
return FALSE; |
||||
} |
||||
|
||||
if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) |
||||
|| (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) { |
||||
return TRUE; |
||||
} |
||||
if (CancelIoEx_Available) { |
||||
return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped); |
||||
} |
||||
if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { |
||||
return CancelIo(poll_fd[_index].handle); |
||||
} |
||||
usbi_warn(NULL, "Unable to cancel I/O that was started from another thread"); |
||||
return FALSE; |
||||
} |
||||
|
||||
// Init
|
||||
void init_polling(void) |
||||
{ |
||||
int i; |
||||
|
||||
while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { |
||||
SleepEx(0, TRUE); |
||||
} |
||||
if (!is_polling_set) { |
||||
pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) |
||||
GetProcAddress(GetModuleHandleA("KERNEL32"), "CancelIoEx"); |
||||
usbi_dbg("Will use CancelIo%s for I/O cancellation", |
||||
CancelIoEx_Available?"Ex":""); |
||||
for (i=0; i<MAX_FDS; i++) { |
||||
poll_fd[i] = INVALID_WINFD; |
||||
_poll_fd[i].original_handle = INVALID_HANDLE_VALUE; |
||||
_poll_fd[i].thread_id = 0; |
||||
InitializeCriticalSection(&_poll_fd[i].mutex); |
||||
} |
||||
is_polling_set = TRUE; |
||||
} |
||||
compat_spinlock = 0; |
||||
} |
||||
|
||||
// Internal function to retrieve the table index (and lock the fd mutex)
|
||||
int _fd_to_index_and_lock(int fd) |
||||
{ |
||||
int i; |
||||
|
||||
if (fd <= 0) |
||||
return -1; |
||||
|
||||
for (i=0; i<MAX_FDS; i++) { |
||||
if (poll_fd[i].fd == fd) { |
||||
EnterCriticalSection(&_poll_fd[i].mutex); |
||||
// fd might have changed before we got to critical
|
||||
if (poll_fd[i].fd != fd) { |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
continue; |
||||
} |
||||
return i; |
||||
} |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
OVERLAPPED *create_overlapped(void) |
||||
{ |
||||
OVERLAPPED *overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED)); |
||||
if (overlapped == NULL) { |
||||
return NULL; |
||||
} |
||||
overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); |
||||
if(overlapped->hEvent == NULL) { |
||||
free (overlapped); |
||||
return NULL; |
||||
} |
||||
return overlapped; |
||||
} |
||||
|
||||
void free_overlapped(OVERLAPPED *overlapped) |
||||
{ |
||||
if (overlapped == NULL) |
||||
return; |
||||
|
||||
if ( (overlapped->hEvent != 0) |
||||
&& (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { |
||||
CloseHandle(overlapped->hEvent); |
||||
} |
||||
free(overlapped); |
||||
} |
||||
|
||||
void reset_overlapped(OVERLAPPED *overlapped) |
||||
{ |
||||
HANDLE event_handle; |
||||
if (overlapped == NULL) |
||||
return; |
||||
|
||||
event_handle = overlapped->hEvent; |
||||
if (event_handle != NULL) { |
||||
ResetEvent(event_handle); |
||||
} |
||||
memset(overlapped, 0, sizeof(OVERLAPPED)); |
||||
overlapped->hEvent = event_handle; |
||||
} |
||||
|
||||
void exit_polling(void) |
||||
{ |
||||
int i; |
||||
|
||||
while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { |
||||
SleepEx(0, TRUE); |
||||
} |
||||
if (is_polling_set) { |
||||
is_polling_set = FALSE; |
||||
|
||||
for (i=0; i<MAX_FDS; i++) { |
||||
// Cancel any async I/O (handle can be invalid)
|
||||
cancel_io(i); |
||||
// If anything was pending on that I/O, it should be
|
||||
// terminating, and we should be able to access the fd
|
||||
// mutex lock before too long
|
||||
EnterCriticalSection(&_poll_fd[i].mutex); |
||||
if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0) |
||||
&& (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) { |
||||
_close(poll_fd[i].fd); |
||||
} |
||||
free_overlapped(poll_fd[i].overlapped); |
||||
if (!CancelIoEx_Available) { |
||||
// Close duplicate handle
|
||||
if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) { |
||||
CloseHandle(poll_fd[i].handle); |
||||
} |
||||
} |
||||
poll_fd[i] = INVALID_WINFD; |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
DeleteCriticalSection(&_poll_fd[i].mutex); |
||||
} |
||||
} |
||||
compat_spinlock = 0; |
||||
} |
||||
|
||||
/*
|
||||
* Create a fake pipe. |
||||
* As libusb only uses pipes for signaling, all we need from a pipe is an |
||||
* event. To that extent, we create a single wfd and overlapped as a means |
||||
* to access that event. |
||||
*/ |
||||
int usbi_pipe(int filedes[2]) |
||||
{ |
||||
int i; |
||||
OVERLAPPED* overlapped; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
overlapped = (OVERLAPPED*) calloc(1, sizeof(OVERLAPPED)); |
||||
if (overlapped == NULL) { |
||||
return -1; |
||||
} |
||||
// The overlapped must have status pending for signaling to work in poll
|
||||
overlapped->Internal = STATUS_PENDING; |
||||
overlapped->InternalHigh = 0; |
||||
|
||||
// Read end of the "pipe"
|
||||
filedes[0] = _open(NUL_DEVICE, _O_WRONLY); |
||||
if (filedes[0] < 0) { |
||||
usbi_err(NULL, "could not create pipe: errno %d", errno); |
||||
goto out1; |
||||
} |
||||
// We can use the same handle for both ends
|
||||
filedes[1] = filedes[0]; |
||||
poll_dbg("pipe filedes = %d", filedes[0]); |
||||
|
||||
// Note: manual reset must be true (second param) as the reset occurs in read
|
||||
overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); |
||||
if(!overlapped->hEvent) { |
||||
goto out2; |
||||
} |
||||
|
||||
for (i=0; i<MAX_FDS; i++) { |
||||
if (poll_fd[i].fd < 0) { |
||||
EnterCriticalSection(&_poll_fd[i].mutex); |
||||
// fd might have been allocated before we got to critical
|
||||
if (poll_fd[i].fd >= 0) { |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
continue; |
||||
} |
||||
|
||||
poll_fd[i].fd = filedes[0]; |
||||
poll_fd[i].handle = DUMMY_HANDLE; |
||||
poll_fd[i].overlapped = overlapped; |
||||
// There's no polling on the write end, so we just use READ for our needs
|
||||
poll_fd[i].rw = RW_READ; |
||||
_poll_fd[i].original_handle = INVALID_HANDLE_VALUE; |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
CloseHandle(overlapped->hEvent); |
||||
out2: |
||||
_close(filedes[0]); |
||||
out1: |
||||
free(overlapped); |
||||
return -1; |
||||
} |
||||
|
||||
/*
|
||||
* Create both an fd and an OVERLAPPED from an open Windows handle, so that |
||||
* it can be used with our polling function |
||||
* The handle MUST support overlapped transfers (usually requires CreateFile |
||||
* with FILE_FLAG_OVERLAPPED) |
||||
* Return a pollable file descriptor struct, or INVALID_WINFD on error |
||||
* |
||||
* Note that the fd returned by this function is a per-transfer fd, rather |
||||
* than a per-session fd and cannot be used for anything else but our |
||||
* custom functions (the fd itself points to the NUL: device) |
||||
* if you plan to do R/W on the same handle, you MUST create 2 fds: one for |
||||
* read and one for write. Using a single R/W fd is unsupported and will |
||||
* produce unexpected results |
||||
*/ |
||||
struct winfd usbi_create_fd(HANDLE handle, int access_mode) |
||||
{ |
||||
int i, fd; |
||||
struct winfd wfd = INVALID_WINFD; |
||||
OVERLAPPED* overlapped = NULL; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { |
||||
return INVALID_WINFD; |
||||
} |
||||
|
||||
if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) { |
||||
usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n" |
||||
"If you want to poll for R/W simultaneously, create multiple fds from the same handle."); |
||||
return INVALID_WINFD; |
||||
} |
||||
if (access_mode == _O_RDONLY) { |
||||
wfd.rw = RW_READ; |
||||
} else { |
||||
wfd.rw = RW_WRITE; |
||||
} |
||||
|
||||
// Ensure that we get a non system conflicting unique fd, using
|
||||
// the same fd attribution system as the pipe ends
|
||||
fd = _open(NUL_DEVICE, _O_WRONLY); |
||||
if (fd < 0) { |
||||
return INVALID_WINFD; |
||||
} |
||||
|
||||
overlapped = create_overlapped(); |
||||
if(overlapped == NULL) { |
||||
_close(fd); |
||||
return INVALID_WINFD; |
||||
} |
||||
|
||||
for (i=0; i<MAX_FDS; i++) { |
||||
if (poll_fd[i].fd < 0) { |
||||
EnterCriticalSection(&_poll_fd[i].mutex); |
||||
// fd might have been removed before we got to critical
|
||||
if (poll_fd[i].fd >= 0) { |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
continue; |
||||
} |
||||
wfd.fd = fd; |
||||
// Attempt to emulate some of the CancelIoEx behaviour on platforms
|
||||
// that don't have it
|
||||
if (!CancelIoEx_Available) { |
||||
_poll_fd[i].thread_id = GetCurrentThreadId(); |
||||
if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), |
||||
&wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { |
||||
usbi_dbg("could not duplicate handle for CancelIo - using original one"); |
||||
wfd.handle = handle; |
||||
// Make sure we won't close the original handle on fd deletion then
|
||||
_poll_fd[i].original_handle = INVALID_HANDLE_VALUE; |
||||
} else { |
||||
_poll_fd[i].original_handle = handle; |
||||
} |
||||
} else { |
||||
wfd.handle = handle; |
||||
} |
||||
wfd.overlapped = overlapped; |
||||
memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
return wfd; |
||||
} |
||||
} |
||||
free_overlapped(overlapped); |
||||
_close(fd); |
||||
return INVALID_WINFD; |
||||
} |
||||
|
||||
void _free_index(int _index) |
||||
{ |
||||
// Cancel any async IO (Don't care about the validity of our handles for this)
|
||||
cancel_io(_index); |
||||
// close fake handle for devices
|
||||
if ( (poll_fd[_index].handle != INVALID_HANDLE_VALUE) && (poll_fd[_index].handle != 0) |
||||
&& (GetFileType(poll_fd[_index].handle) == FILE_TYPE_UNKNOWN) ) { |
||||
_close(poll_fd[_index].fd); |
||||
} |
||||
// close the duplicate handle (if we have an actual duplicate)
|
||||
if (!CancelIoEx_Available) { |
||||
if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { |
||||
CloseHandle(poll_fd[_index].handle); |
||||
} |
||||
_poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; |
||||
_poll_fd[_index].thread_id = 0; |
||||
} |
||||
free_overlapped(poll_fd[_index].overlapped); |
||||
poll_fd[_index] = INVALID_WINFD; |
||||
} |
||||
|
||||
/*
|
||||
* Release a pollable file descriptor. |
||||
* |
||||
* Note that the associated Windows handle is not closed by this call |
||||
*/ |
||||
void usbi_free_fd(int fd) |
||||
{ |
||||
int _index; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
_index = _fd_to_index_and_lock(fd); |
||||
if (_index < 0) { |
||||
return; |
||||
} |
||||
_free_index(_index); |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
} |
||||
|
||||
/*
|
||||
* The functions below perform various conversions between fd, handle and OVERLAPPED |
||||
*/ |
||||
struct winfd fd_to_winfd(int fd) |
||||
{ |
||||
int i; |
||||
struct winfd wfd; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
if (fd <= 0) |
||||
return INVALID_WINFD; |
||||
|
||||
for (i=0; i<MAX_FDS; i++) { |
||||
if (poll_fd[i].fd == fd) { |
||||
EnterCriticalSection(&_poll_fd[i].mutex); |
||||
// fd might have been deleted before we got to critical
|
||||
if (poll_fd[i].fd != fd) { |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
continue; |
||||
} |
||||
memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
return wfd; |
||||
} |
||||
} |
||||
return INVALID_WINFD; |
||||
} |
||||
|
||||
struct winfd handle_to_winfd(HANDLE handle) |
||||
{ |
||||
int i; |
||||
struct winfd wfd; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) |
||||
return INVALID_WINFD; |
||||
|
||||
for (i=0; i<MAX_FDS; i++) { |
||||
if (poll_fd[i].handle == handle) { |
||||
EnterCriticalSection(&_poll_fd[i].mutex); |
||||
// fd might have been deleted before we got to critical
|
||||
if (poll_fd[i].handle != handle) { |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
continue; |
||||
} |
||||
memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
return wfd; |
||||
} |
||||
} |
||||
return INVALID_WINFD; |
||||
} |
||||
|
||||
struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) |
||||
{ |
||||
int i; |
||||
struct winfd wfd; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
if (overlapped == NULL) |
||||
return INVALID_WINFD; |
||||
|
||||
for (i=0; i<MAX_FDS; i++) { |
||||
if (poll_fd[i].overlapped == overlapped) { |
||||
EnterCriticalSection(&_poll_fd[i].mutex); |
||||
// fd might have been deleted before we got to critical
|
||||
if (poll_fd[i].overlapped != overlapped) { |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
continue; |
||||
} |
||||
memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); |
||||
LeaveCriticalSection(&_poll_fd[i].mutex); |
||||
return wfd; |
||||
} |
||||
} |
||||
return INVALID_WINFD; |
||||
} |
||||
|
||||
/*
|
||||
* POSIX poll equivalent, using Windows OVERLAPPED |
||||
* Currently, this function only accepts one of POLLIN or POLLOUT per fd |
||||
* (but you can create multiple fds from the same handle for read and write) |
||||
*/ |
||||
int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) |
||||
{ |
||||
unsigned i; |
||||
int _index, object_index, triggered; |
||||
HANDLE *handles_to_wait_on; |
||||
int *handle_to_index; |
||||
DWORD nb_handles_to_wait_on = 0; |
||||
DWORD ret; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
triggered = 0; |
||||
handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update
|
||||
handle_to_index = (int*) calloc(nfds, sizeof(int)); |
||||
if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { |
||||
errno = ENOMEM; |
||||
triggered = -1; |
||||
goto poll_exit; |
||||
} |
||||
|
||||
for (i = 0; i < nfds; ++i) { |
||||
fds[i].revents = 0; |
||||
|
||||
// Only one of POLLIN or POLLOUT can be selected with this version of poll (not both)
|
||||
if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { |
||||
fds[i].revents |= POLLERR; |
||||
errno = EACCES; |
||||
usbi_warn(NULL, "unsupported set of events"); |
||||
triggered = -1; |
||||
goto poll_exit; |
||||
} |
||||
|
||||
_index = _fd_to_index_and_lock(fds[i].fd); |
||||
poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events); |
||||
|
||||
if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) |
||||
|| (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) { |
||||
fds[i].revents |= POLLNVAL | POLLERR; |
||||
errno = EBADF; |
||||
if (_index >= 0) { |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
} |
||||
usbi_warn(NULL, "invalid fd"); |
||||
triggered = -1; |
||||
goto poll_exit; |
||||
} |
||||
|
||||
// IN or OUT must match our fd direction
|
||||
if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) { |
||||
fds[i].revents |= POLLNVAL | POLLERR; |
||||
errno = EBADF; |
||||
usbi_warn(NULL, "attempted POLLIN on fd without READ access"); |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
triggered = -1; |
||||
goto poll_exit; |
||||
} |
||||
|
||||
if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) { |
||||
fds[i].revents |= POLLNVAL | POLLERR; |
||||
errno = EBADF; |
||||
usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
triggered = -1; |
||||
goto poll_exit; |
||||
} |
||||
|
||||
// The following macro only works if overlapped I/O was reported pending
|
||||
if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) |
||||
|| (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) { |
||||
poll_dbg(" completed"); |
||||
// checks above should ensure this works:
|
||||
fds[i].revents = fds[i].events; |
||||
triggered++; |
||||
} else { |
||||
handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent; |
||||
handle_to_index[nb_handles_to_wait_on] = i; |
||||
nb_handles_to_wait_on++; |
||||
} |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
} |
||||
|
||||
// If nothing was triggered, wait on all fds that require it
|
||||
if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { |
||||
if (timeout < 0) { |
||||
poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); |
||||
} else { |
||||
poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); |
||||
} |
||||
ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, |
||||
FALSE, (timeout<0)?INFINITE:(DWORD)timeout); |
||||
object_index = ret-WAIT_OBJECT_0; |
||||
if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { |
||||
poll_dbg(" completed after wait"); |
||||
i = handle_to_index[object_index]; |
||||
_index = _fd_to_index_and_lock(fds[i].fd); |
||||
fds[i].revents = fds[i].events; |
||||
triggered++; |
||||
if (_index >= 0) { |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
} |
||||
} else if (ret == WAIT_TIMEOUT) { |
||||
poll_dbg(" timed out"); |
||||
triggered = 0; // 0 = timeout
|
||||
} else { |
||||
errno = EIO; |
||||
triggered = -1; // error
|
||||
} |
||||
} |
||||
|
||||
poll_exit: |
||||
if (handles_to_wait_on != NULL) { |
||||
free(handles_to_wait_on); |
||||
} |
||||
if (handle_to_index != NULL) { |
||||
free(handle_to_index); |
||||
} |
||||
return triggered; |
||||
} |
||||
|
||||
/*
|
||||
* close a fake pipe fd |
||||
*/ |
||||
int usbi_close(int fd) |
||||
{ |
||||
int _index; |
||||
int r = -1; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
_index = _fd_to_index_and_lock(fd); |
||||
|
||||
if (_index < 0) { |
||||
errno = EBADF; |
||||
} else { |
||||
if (poll_fd[_index].overlapped != NULL) { |
||||
// Must be a different event for each end of the pipe
|
||||
CloseHandle(poll_fd[_index].overlapped->hEvent); |
||||
free(poll_fd[_index].overlapped); |
||||
} |
||||
r = _close(poll_fd[_index].fd); |
||||
if (r != 0) { |
||||
errno = EIO; |
||||
} |
||||
poll_fd[_index] = INVALID_WINFD; |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
} |
||||
return r; |
||||
} |
||||
|
||||
/*
|
||||
* synchronous write for fake "pipe" signaling |
||||
*/ |
||||
ssize_t usbi_write(int fd, const void *buf, size_t count) |
||||
{ |
||||
int _index; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
if (count != sizeof(unsigned char)) { |
||||
usbi_err(NULL, "this function should only used for signaling"); |
||||
return -1; |
||||
} |
||||
|
||||
_index = _fd_to_index_and_lock(fd); |
||||
|
||||
if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { |
||||
errno = EBADF; |
||||
if (_index >= 0) { |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); |
||||
SetEvent(poll_fd[_index].overlapped->hEvent); |
||||
poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; |
||||
// If two threads write on the pipe at the same time, we need to
|
||||
// process two separate reads => use the overlapped as a counter
|
||||
poll_fd[_index].overlapped->InternalHigh++; |
||||
|
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
return sizeof(unsigned char); |
||||
} |
||||
|
||||
/*
|
||||
* synchronous read for fake "pipe" signaling |
||||
*/ |
||||
ssize_t usbi_read(int fd, void *buf, size_t count) |
||||
{ |
||||
int _index; |
||||
ssize_t r = -1; |
||||
|
||||
CHECK_INIT_POLLING; |
||||
|
||||
if (count != sizeof(unsigned char)) { |
||||
usbi_err(NULL, "this function should only used for signaling"); |
||||
return -1; |
||||
} |
||||
|
||||
_index = _fd_to_index_and_lock(fd); |
||||
|
||||
if (_index < 0) { |
||||
errno = EBADF; |
||||
return -1; |
||||
} |
||||
|
||||
if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { |
||||
usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); |
||||
errno = EIO; |
||||
goto out; |
||||
} |
||||
|
||||
poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); |
||||
poll_fd[_index].overlapped->InternalHigh--; |
||||
// Don't reset unless we don't have any more events to process
|
||||
if (poll_fd[_index].overlapped->InternalHigh <= 0) { |
||||
ResetEvent(poll_fd[_index].overlapped->hEvent); |
||||
poll_fd[_index].overlapped->Internal = STATUS_PENDING; |
||||
} |
||||
|
||||
r = sizeof(unsigned char); |
||||
|
||||
out: |
||||
LeaveCriticalSection(&_poll_fd[_index].mutex); |
||||
return r; |
||||
} |
@ -1,117 +0,0 @@
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Windows compat: POSIX compatibility wrapper |
||||
* Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> |
||||
* With contributions from Michael Plante, Orin Eman et al. |
||||
* Parts of poll implementation from libusb-win32, by Stephan Meyer et al. |
||||
* |
||||
* 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 |
||||
* |
||||
*/ |
||||
#pragma once |
||||
|
||||
#include <windows.h> |
||||
|
||||
#if defined(_MSC_VER) |
||||
// disable /W4 MSVC warnings that are benign
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif |
||||
|
||||
// Handle synchronous completion through the overlapped structure
|
||||
#if !defined(STATUS_REPARSE) // reuse the REPARSE status code
|
||||
#define STATUS_REPARSE ((LONG)0x00000104L) |
||||
#endif |
||||
#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE |
||||
#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY) |
||||
|
||||
#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2) |
||||
|
||||
enum windows_version { |
||||
WINDOWS_UNSUPPORTED, |
||||
WINDOWS_XP, |
||||
WINDOWS_2003, // also includes XP 64
|
||||
WINDOWS_VISTA_AND_LATER, |
||||
}; |
||||
extern enum windows_version windows_version; |
||||
|
||||
#define MAX_FDS 256 |
||||
|
||||
#define POLLIN 0x0001 /* There is data to read */ |
||||
#define POLLPRI 0x0002 /* There is urgent data to read */ |
||||
#define POLLOUT 0x0004 /* Writing now will not block */ |
||||
#define POLLERR 0x0008 /* Error condition */ |
||||
#define POLLHUP 0x0010 /* Hung up */ |
||||
#define POLLNVAL 0x0020 /* Invalid request: fd not open */ |
||||
|
||||
struct pollfd { |
||||
int fd; /* file descriptor */ |
||||
short events; /* requested events */ |
||||
short revents; /* returned events */ |
||||
}; |
||||
|
||||
// access modes
|
||||
enum rw_type { |
||||
RW_NONE, |
||||
RW_READ, |
||||
RW_WRITE, |
||||
}; |
||||
|
||||
// fd struct that can be used for polling on Windows
|
||||
struct winfd { |
||||
int fd; // what's exposed to libusb core
|
||||
HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it
|
||||
OVERLAPPED* overlapped; // what will report our I/O status
|
||||
enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH)
|
||||
}; |
||||
extern const struct winfd INVALID_WINFD; |
||||
|
||||
int usbi_pipe(int pipefd[2]); |
||||
int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout); |
||||
ssize_t usbi_write(int fd, const void *buf, size_t count); |
||||
ssize_t usbi_read(int fd, void *buf, size_t count); |
||||
int usbi_close(int fd); |
||||
|
||||
void init_polling(void); |
||||
void exit_polling(void); |
||||
struct winfd usbi_create_fd(HANDLE handle, int access_mode); |
||||
void usbi_free_fd(int fd); |
||||
struct winfd fd_to_winfd(int fd); |
||||
struct winfd handle_to_winfd(HANDLE handle); |
||||
struct winfd overlapped_to_winfd(OVERLAPPED* overlapped); |
||||
|
||||
/*
|
||||
* Timeval operations |
||||
*/ |
||||
#if defined(DDKBUILD) |
||||
#include <winsock.h> // defines timeval functions on DDK |
||||
#endif |
||||
|
||||
#if !defined(TIMESPEC_TO_TIMEVAL) |
||||
#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ |
||||
(tv)->tv_sec = (long)(ts)->tv_sec; \ |
||||
(tv)->tv_usec = (long)(ts)->tv_nsec / 1000; \ |
||||
} |
||||
#endif |
||||
#if !defined(timersub) |
||||
#define timersub(a, b, result) \ |
||||
do { \ |
||||
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ |
||||
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ |
||||
if ((result)->tv_usec < 0) { \ |
||||
--(result)->tv_sec; \ |
||||
(result)->tv_usec += 1000000; \ |
||||
} \ |
||||
} while (0) |
||||
#endif |
||||
|
@ -1,55 +0,0 @@
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* libusb synchronization using POSIX Threads |
||||
* |
||||
* Copyright (C) 2011 Vitali Lovich <vlovich@aliph.com> |
||||
* Copyright (C) 2011 Peter Stuge <peter@stuge.se> |
||||
* |
||||
* 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 |
||||
*/ |
||||
|
||||
#ifdef _XOPEN_SOURCE |
||||
# if _XOPEN_SOURCE < 500 |
||||
# undef _XOPEN_SOURCE |
||||
# define _XOPEN_SOURCE 500 |
||||
# endif |
||||
#else |
||||
#define _XOPEN_SOURCE 500 |
||||
#endif /* _XOPEN_SOURCE */ |
||||
|
||||
#include "threads_posix.h" |
||||
|
||||
int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr) |
||||
{ |
||||
int err; |
||||
pthread_mutexattr_t stack_attr; |
||||
if (!attr) { |
||||
attr = &stack_attr; |
||||
err = pthread_mutexattr_init(&stack_attr); |
||||
if (err != 0) |
||||
return err; |
||||
} |
||||
|
||||
err = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE); |
||||
if (err != 0) |
||||
goto finish; |
||||
|
||||
err = pthread_mutex_init(mutex, attr); |
||||
|
||||
finish: |
||||
if (attr == &stack_attr) |
||||
pthread_mutexattr_destroy(&stack_attr); |
||||
|
||||
return err; |
||||
} |
@ -1,48 +0,0 @@
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* libusb synchronization using POSIX Threads |
||||
* |
||||
* Copyright (C) 2010 Peter Stuge <peter@stuge.se> |
||||
* |
||||
* 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 |
||||
*/ |
||||
|
||||
#ifndef LIBUSB_THREADS_POSIX_H |
||||
#define LIBUSB_THREADS_POSIX_H |
||||
|
||||
#include <pthread.h> |
||||
|
||||
#define usbi_mutex_static_t pthread_mutex_t |
||||
#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER |
||||
#define usbi_mutex_static_lock pthread_mutex_lock |
||||
#define usbi_mutex_static_unlock pthread_mutex_unlock |
||||
|
||||
#define usbi_mutex_t pthread_mutex_t |
||||
#define usbi_mutex_init pthread_mutex_init |
||||
#define usbi_mutex_lock pthread_mutex_lock |
||||
#define usbi_mutex_unlock pthread_mutex_unlock |
||||
#define usbi_mutex_trylock pthread_mutex_trylock |
||||
#define usbi_mutex_destroy pthread_mutex_destroy |
||||
|
||||
#define usbi_cond_t pthread_cond_t |
||||
#define usbi_cond_init pthread_cond_init |
||||
#define usbi_cond_wait pthread_cond_wait |
||||
#define usbi_cond_timedwait pthread_cond_timedwait |
||||
#define usbi_cond_broadcast pthread_cond_broadcast |
||||
#define usbi_cond_destroy pthread_cond_destroy |
||||
#define usbi_cond_signal pthread_cond_signal |
||||
|
||||
extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr); |
||||
|
||||
#endif /* LIBUSB_THREADS_POSIX_H */ |
@ -1,208 +0,0 @@
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
* libusb synchronization on Microsoft Windows |
||||
* |
||||
* Copyright (C) 2010 Michael Plante <michael.plante@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 <config.h> |
||||
#include <objbase.h> |
||||
#include <errno.h> |
||||
#include <stdarg.h> |
||||
|
||||
#include "libusbi.h" |
||||
|
||||
|
||||
int usbi_mutex_init(usbi_mutex_t *mutex, |
||||
const usbi_mutexattr_t *attr) { |
||||
if(! mutex) return ((errno=EINVAL)); |
||||
*mutex = CreateMutex(NULL, FALSE, NULL); |
||||
if(!*mutex) return ((errno=ENOMEM)); |
||||
return 0; |
||||
} |
||||
int usbi_mutex_destroy(usbi_mutex_t *mutex) { |
||||
// It is not clear if CloseHandle failure is due to failure to unlock.
|
||||
// If so, this should be errno=EBUSY.
|
||||
if(!mutex || !CloseHandle(*mutex)) return ((errno=EINVAL)); |
||||
*mutex = NULL; |
||||
return 0; |
||||
} |
||||
int usbi_mutex_trylock(usbi_mutex_t *mutex) { |
||||
DWORD result; |
||||
if(!mutex) return ((errno=EINVAL)); |
||||
result = WaitForSingleObject(*mutex, 0); |
||||
if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) |
||||
return 0; // acquired (ToDo: check that abandoned is ok)
|
||||
if(result == WAIT_TIMEOUT) |
||||
return ((errno=EBUSY)); |
||||
return ((errno=EINVAL)); // don't know how this would happen
|
||||
// so don't know proper errno
|
||||
} |
||||
int usbi_mutex_lock(usbi_mutex_t *mutex) { |
||||
DWORD result; |
||||
if(!mutex) return ((errno=EINVAL)); |
||||
result = WaitForSingleObject(*mutex, INFINITE); |
||||
if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) |
||||
return 0; // acquired (ToDo: check that abandoned is ok)
|
||||
return ((errno=EINVAL)); // don't know how this would happen
|
||||
// so don't know proper errno
|
||||
} |
||||
int usbi_mutex_unlock(usbi_mutex_t *mutex) { |
||||
if(!mutex) return ((errno=EINVAL)); |
||||
if(!ReleaseMutex(*mutex)) return ((errno=EPERM )); |
||||
return 0; |
||||
} |
||||
|
||||
int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) { |
||||
if(!mutex) return ((errno=EINVAL)); |
||||
while (InterlockedExchange((LONG *)mutex, 1) == 1) { |
||||
SleepEx(0, TRUE); |
||||
} |
||||
return 0; |
||||
} |
||||
int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) { |
||||
if(!mutex) return ((errno=EINVAL)); |
||||
*mutex = 0; |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
int usbi_cond_init(usbi_cond_t *cond, |
||||
const usbi_condattr_t *attr) { |
||||
if(!cond) return ((errno=EINVAL)); |
||||
list_init(&cond->waiters ); |
||||
list_init(&cond->not_waiting); |
||||
return 0; |
||||
} |
||||
int usbi_cond_destroy(usbi_cond_t *cond) { |
||||
// This assumes no one is using this anymore. The check MAY NOT BE safe.
|
||||
struct usbi_cond_perthread *pos, *prev_pos = NULL; |
||||
if(!cond) return ((errno=EINVAL)); |
||||
if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!)
|
||||
list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { |
||||
free(prev_pos); |
||||
CloseHandle(pos->event); |
||||
list_del(&pos->list); |
||||
prev_pos = pos; |
||||
} |
||||
free(prev_pos); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int usbi_cond_broadcast(usbi_cond_t *cond) { |
||||
// Assumes mutex is locked; this is not in keeping with POSIX spec, but
|
||||
// libusb does this anyway, so we simplify by not adding more sync
|
||||
// primitives to the CV definition!
|
||||
int fail = 0; |
||||
struct usbi_cond_perthread *pos; |
||||
if(!cond) return ((errno=EINVAL)); |
||||
list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) { |
||||
if(!SetEvent(pos->event)) |
||||
fail = 1; |
||||
} |
||||
// The wait function will remove its respective item from the list.
|
||||
return fail ? ((errno=EINVAL)) : 0; |
||||
} |
||||
int usbi_cond_signal(usbi_cond_t *cond) { |
||||
// Assumes mutex is locked; this is not in keeping with POSIX spec, but
|
||||
// libusb does this anyway, so we simplify by not adding more sync
|
||||
// primitives to the CV definition!
|
||||
struct usbi_cond_perthread *pos; |
||||
if(!cond) return ((errno=EINVAL)); |
||||
if(list_empty(&cond->waiters)) return 0; // no one to wakeup.
|
||||
pos = list_entry(&cond->waiters.next, struct usbi_cond_perthread, list); |
||||
// The wait function will remove its respective item from the list.
|
||||
return SetEvent(pos->event) ? 0 : ((errno=EINVAL)); |
||||
} |
||||
static int __inline usbi_cond_intwait(usbi_cond_t *cond, |
||||
usbi_mutex_t *mutex, |
||||
DWORD timeout_ms) { |
||||
struct usbi_cond_perthread *pos; |
||||
int found = 0, r; |
||||
DWORD r2,tid = GetCurrentThreadId(); |
||||
if(!cond || !mutex) return ((errno=EINVAL)); |
||||
list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { |
||||
if(tid == pos->tid) { |
||||
found = 1; |
||||
break; |
||||
} |
||||
} |
||||
if(!found) { |
||||
pos = (struct usbi_cond_perthread*) calloc(1, sizeof(struct usbi_cond_perthread)); |
||||
if(!pos) return ((errno=ENOMEM)); // This errno is not POSIX-allowed.
|
||||
pos->tid = tid; |
||||
pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset.
|
||||
if(!pos->event) { |
||||
free(pos); |
||||
return ((errno=ENOMEM)); |
||||
} |
||||
list_add(&pos->list, &cond->not_waiting); |
||||
} |
||||
|
||||
list_del(&pos->list); // remove from not_waiting list.
|
||||
list_add(&pos->list, &cond->waiters); |
||||
|
||||
r = usbi_mutex_unlock(mutex); |
||||
if(r) return r; |
||||
r2 = WaitForSingleObject(pos->event, timeout_ms); |
||||
r = usbi_mutex_lock(mutex); |
||||
if(r) return r; |
||||
|
||||
list_del(&pos->list); |
||||
list_add(&pos->list, &cond->not_waiting); |
||||
|
||||
if(r2 == WAIT_TIMEOUT) return ((errno=ETIMEDOUT)); |
||||
|
||||
return 0; |
||||
} |
||||
// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot!
|
||||
int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) { |
||||
return usbi_cond_intwait(cond, mutex, INFINITE); |
||||
} |
||||
int usbi_cond_timedwait(usbi_cond_t *cond, |
||||
usbi_mutex_t *mutex, |
||||
const struct timespec *abstime) { |
||||
FILETIME filetime; |
||||
ULARGE_INTEGER rtime; |
||||
struct timeval targ_time, cur_time, delta_time; |
||||
struct timespec cur_time_ns; |
||||
DWORD millis; |
||||
extern const uint64_t epoch_time; |
||||
|
||||
GetSystemTimeAsFileTime(&filetime); |
||||
rtime.LowPart = filetime.dwLowDateTime; |
||||
rtime.HighPart = filetime.dwHighDateTime; |
||||
rtime.QuadPart -= epoch_time; |
||||
cur_time_ns.tv_sec = (long)(rtime.QuadPart / 10000000); |
||||
cur_time_ns.tv_nsec = (long)((rtime.QuadPart % 10000000)*100); |
||||
TIMESPEC_TO_TIMEVAL(&cur_time, &cur_time_ns); |
||||
|
||||
TIMESPEC_TO_TIMEVAL(&targ_time, abstime); |
||||
timersub(&targ_time, &cur_time, &delta_time); |
||||
if(delta_time.tv_sec < 0) // abstime already passed?
|
||||
millis = 0; |
||||
else { |
||||
millis = delta_time.tv_usec/1000; |
||||
millis += delta_time.tv_sec *1000; |
||||
if (delta_time.tv_usec % 1000) // round up to next millisecond
|
||||
millis++; |
||||
} |
||||
|
||||
return usbi_cond_intwait(cond, mutex, millis); |
||||
} |
||||
|
@ -1,88 +0,0 @@
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* libusb synchronization on Microsoft Windows |
||||
* |
||||
* Copyright (C) 2010 Michael Plante <michael.plante@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 |
||||
*/ |
||||
|
||||
#ifndef LIBUSB_THREADS_WINDOWS_H |
||||
#define LIBUSB_THREADS_WINDOWS_H |
||||
|
||||
#include <windows.h> |
||||
|
||||
#define usbi_mutex_static_t volatile LONG |
||||
#define USBI_MUTEX_INITIALIZER 0 |
||||
|
||||
#define usbi_mutex_t HANDLE |
||||
|
||||
struct usbi_cond_perthread { |
||||
struct list_head list; |
||||
DWORD tid; |
||||
HANDLE event; |
||||
}; |
||||
struct usbi_cond_t_ { |
||||
// Every time a thread touches the CV, it winds up in one of these lists.
|
||||
// It stays there until the CV is destroyed, even if the thread
|
||||
// terminates.
|
||||
struct list_head waiters; |
||||
struct list_head not_waiting; |
||||
}; |
||||
typedef struct usbi_cond_t_ usbi_cond_t; |
||||
|
||||
// We *were* getting timespec from pthread.h:
|
||||
#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)) |
||||
#define HAVE_STRUCT_TIMESPEC 1 |
||||
#define _TIMESPEC_DEFINED 1 |
||||
struct timespec { |
||||
long tv_sec; |
||||
long tv_nsec; |
||||
}; |
||||
#endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */ |
||||
|
||||
// We *were* getting ETIMEDOUT from pthread.h:
|
||||
#ifndef ETIMEDOUT |
||||
# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ |
||||
#endif |
||||
|
||||
#define usbi_mutexattr_t void |
||||
#define usbi_condattr_t void |
||||
|
||||
// all Windows mutexes are recursive
|
||||
#define usbi_mutex_init_recursive(mutex, attr) usbi_mutex_init((mutex), (attr)) |
||||
|
||||
int usbi_mutex_static_lock(usbi_mutex_static_t *mutex); |
||||
int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex); |
||||
|
||||
|
||||
int usbi_mutex_init(usbi_mutex_t *mutex, |
||||
const usbi_mutexattr_t *attr); |
||||
int usbi_mutex_lock(usbi_mutex_t *mutex); |
||||
int usbi_mutex_unlock(usbi_mutex_t *mutex); |
||||
int usbi_mutex_trylock(usbi_mutex_t *mutex); |
||||
int usbi_mutex_destroy(usbi_mutex_t *mutex); |
||||
|
||||
int usbi_cond_init(usbi_cond_t *cond, |
||||
const usbi_condattr_t *attr); |
||||
int usbi_cond_destroy(usbi_cond_t *cond); |
||||
int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex); |
||||
int usbi_cond_timedwait(usbi_cond_t *cond, |
||||
usbi_mutex_t *mutex, |
||||
const struct timespec *abstime); |
||||
int usbi_cond_broadcast(usbi_cond_t *cond); |
||||
int usbi_cond_signal(usbi_cond_t *cond); |
||||
|
||||
#endif /* LIBUSB_THREADS_WINDOWS_H */ |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,608 +0,0 @@
@@ -1,608 +0,0 @@
|
||||
/*
|
||||
* Windows backend for libusb 1.0 |
||||
* Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> |
||||
* With contributions from Michael Plante, Orin Eman et al. |
||||
* Parts of this code adapted from libusb-win32-v1 by Stephan Meyer |
||||
* Major code testing contribution by Xiaofan Chen |
||||
* |
||||
* 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 |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#if defined(_MSC_VER) |
||||
// disable /W4 MSVC warnings that are benign
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#pragma warning(disable:4214) // bit field types other than int
|
||||
#pragma warning(disable:4201) // nameless struct/union
|
||||
#endif |
||||
|
||||
// Windows API default is uppercase - ugh!
|
||||
#if !defined(bool) |
||||
#define bool BOOL |
||||
#endif |
||||
#if !defined(true) |
||||
#define true TRUE |
||||
#endif |
||||
#if !defined(false) |
||||
#define false FALSE |
||||
#endif |
||||
|
||||
// Missing from MSVC6 setupapi.h
|
||||
#if !defined(SPDRP_ADDRESS) |
||||
#define SPDRP_ADDRESS 28 |
||||
#endif |
||||
#if !defined(SPDRP_INSTALL_STATE) |
||||
#define SPDRP_INSTALL_STATE 34 |
||||
#endif |
||||
|
||||
#if defined(__CYGWIN__ ) |
||||
// cygwin produces a warning unless these prototypes are defined
|
||||
extern int _snprintf(char *buffer, size_t count, const char *format, ...); |
||||
extern char *_strdup(const char *strSource); |
||||
// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread
|
||||
#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, f) |
||||
#endif |
||||
#define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0) |
||||
#define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) |
||||
#define safe_min(a, b) min((size_t)(a), (size_t)(b)) |
||||
#define safe_strcp(dst, dst_max, src, count) do {memcpy(dst, src, safe_min(count, dst_max)); \ |
||||
((char*)dst)[safe_min(count, dst_max)-1] = 0;} while(0) |
||||
#define safe_strcpy(dst, dst_max, src) safe_strcp(dst, dst_max, src, safe_strlen(src)+1) |
||||
#define safe_strncat(dst, dst_max, src, count) strncat(dst, src, safe_min(count, dst_max - safe_strlen(dst) - 1)) |
||||
#define safe_strcat(dst, dst_max, src) safe_strncat(dst, dst_max, src, safe_strlen(src)+1) |
||||
#define safe_strcmp(str1, str2) strcmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2)) |
||||
#define safe_strncmp(str1, str2, count) strncmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2), count) |
||||
#define safe_strlen(str) ((str==NULL)?0:strlen(str)) |
||||
#define safe_sprintf _snprintf |
||||
#define safe_unref_device(dev) do {if (dev != NULL) {libusb_unref_device(dev); dev = NULL;}} while(0) |
||||
#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL) |
||||
static inline void upperize(char* str) { |
||||
size_t i; |
||||
if (str == NULL) return; |
||||
for (i=0; i<safe_strlen(str); i++) |
||||
str[i] = (char)toupper((int)str[i]); |
||||
} |
||||
|
||||
#define MAX_CTRL_BUFFER_LENGTH 4096 |
||||
#define MAX_USB_DEVICES 256 |
||||
#define MAX_USB_STRING_LENGTH 128 |
||||
#define MAX_GUID_STRING_LENGTH 40 |
||||
#define MAX_PATH_LENGTH 128 |
||||
#define MAX_KEY_LENGTH 256 |
||||
#define MAX_TIMER_SEMAPHORES 128 |
||||
#define TIMER_REQUEST_RETRY_MS 100 |
||||
#define ERR_BUFFER_SIZE 256 |
||||
#define LIST_SEPARATOR ';' |
||||
#define HTAB_SIZE 1021 |
||||
|
||||
// http://msdn.microsoft.com/en-us/library/ff545978.aspx
|
||||
// http://msdn.microsoft.com/en-us/library/ff545972.aspx
|
||||
// http://msdn.microsoft.com/en-us/library/ff545982.aspx
|
||||
#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER) |
||||
const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} }; |
||||
#endif |
||||
#if !defined(GUID_DEVINTERFACE_USB_DEVICE) |
||||
const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} }; |
||||
#endif |
||||
#if !defined(GUID_DEVINTERFACE_USB_HUB) |
||||
const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} }; |
||||
#endif |
||||
const GUID GUID_NULL = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; |
||||
|
||||
|
||||
/*
|
||||
* Multiple USB API backend support |
||||
*/ |
||||
#define USB_API_UNSUPPORTED 0 |
||||
#define USB_API_HUB 1 |
||||
#define USB_API_COMPOSITE 2 |
||||
#define USB_API_WINUSB 3 |
||||
#define USB_API_MAX 4 |
||||
|
||||
#define CLASS_GUID_UNSUPPORTED GUID_NULL |
||||
const GUID CLASS_GUID_LIBUSB_WINUSB = { 0x78A1C341, 0x4539, 0x11D3, {0xB8, 0x8D, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71} }; |
||||
const GUID CLASS_GUID_COMPOSITE = { 0x36FC9E60, 0xC465, 0x11cF, {0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} }; |
||||
|
||||
struct windows_usb_api_backend { |
||||
const uint8_t id; |
||||
const char* designation; |
||||
const GUID *class_guid; // The Class GUID (for fallback in case the driver name cannot be read)
|
||||
const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
|
||||
const uint8_t nb_driver_names; |
||||
int (*init)(struct libusb_context *ctx); |
||||
int (*exit)(void); |
||||
int (*open)(struct libusb_device_handle *dev_handle); |
||||
void (*close)(struct libusb_device_handle *dev_handle); |
||||
int (*claim_interface)(struct libusb_device_handle *dev_handle, int iface); |
||||
int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle, int iface, int altsetting); |
||||
int (*release_interface)(struct libusb_device_handle *dev_handle, int iface); |
||||
int (*clear_halt)(struct libusb_device_handle *dev_handle, unsigned char endpoint); |
||||
int (*reset_device)(struct libusb_device_handle *dev_handle); |
||||
int (*submit_bulk_transfer)(struct usbi_transfer *itransfer); |
||||
int (*submit_iso_transfer)(struct usbi_transfer *itransfer); |
||||
int (*submit_control_transfer)(struct usbi_transfer *itransfer); |
||||
int (*abort_control)(struct usbi_transfer *itransfer); |
||||
int (*abort_transfers)(struct usbi_transfer *itransfer); |
||||
int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size); |
||||
}; |
||||
|
||||
extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX]; |
||||
|
||||
#define PRINT_UNSUPPORTED_API(fname) \ |
||||
usbi_dbg("unsupported API call for '" \ |
||||
#fname "' (unrecognized device driver)"); \ |
||||
return LIBUSB_ERROR_NOT_SUPPORTED; |
||||
|
||||
/*
|
||||
* private structures definition |
||||
* with inline pseudo constructors/destructors |
||||
*/ |
||||
typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR; |
||||
struct windows_device_priv { |
||||
uint8_t depth; // distance to HCD
|
||||
uint8_t port; // port number on the hub
|
||||
struct libusb_device *parent_dev; // access to parent is required for usermode ops
|
||||
char *path; // device interface path
|
||||
struct windows_usb_api_backend const *apib; |
||||
struct { |
||||
char *path; // each interface needs a device interface path,
|
||||
struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support),
|
||||
int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
|
||||
uint8_t *endpoint; |
||||
} usb_interface[USB_MAXINTERFACES]; |
||||
uint8_t composite_api_flags; // composite devices require additional data
|
||||
uint8_t active_config; |
||||
USB_DEVICE_DESCRIPTOR dev_descriptor; |
||||
unsigned char **config_descriptor; // list of pointers to the cached config descriptors
|
||||
}; |
||||
|
||||
static inline struct windows_device_priv *_device_priv(struct libusb_device *dev) { |
||||
return (struct windows_device_priv *)dev->os_priv; |
||||
} |
||||
|
||||
static inline void windows_device_priv_init(libusb_device* dev) { |
||||
struct windows_device_priv* p = _device_priv(dev); |
||||
int i; |
||||
p->depth = 0; |
||||
p->port = 0; |
||||
p->parent_dev = NULL; |
||||
p->path = NULL; |
||||
p->apib = &usb_api_backend[USB_API_UNSUPPORTED]; |
||||
p->composite_api_flags = 0; |
||||
p->active_config = 0; |
||||
p->config_descriptor = NULL; |
||||
memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR)); |
||||
for (i=0; i<USB_MAXINTERFACES; i++) { |
||||
p->usb_interface[i].path = NULL; |
||||
p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED]; |
||||
p->usb_interface[i].nb_endpoints = 0; |
||||
p->usb_interface[i].endpoint = NULL; |
||||
} |
||||
} |
||||
|
||||
static inline void windows_device_priv_release(libusb_device* dev) { |
||||
struct windows_device_priv* p = _device_priv(dev); |
||||
int i; |
||||
safe_free(p->path); |
||||
if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { |
||||
for (i=0; i < dev->num_configurations; i++) |
||||
safe_free(p->config_descriptor[i]); |
||||
} |
||||
safe_free(p->config_descriptor); |
||||
for (i=0; i<USB_MAXINTERFACES; i++) { |
||||
safe_free(p->usb_interface[i].path); |
||||
safe_free(p->usb_interface[i].endpoint); |
||||
} |
||||
} |
||||
|
||||
struct interface_handle_t { |
||||
HANDLE dev_handle; // WinUSB needs an extra handle for the file
|
||||
HANDLE api_handle; // used by the API to communicate with the device
|
||||
}; |
||||
|
||||
struct windows_device_handle_priv { |
||||
int active_interface; |
||||
struct interface_handle_t interface_handle[USB_MAXINTERFACES]; |
||||
int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
|
||||
}; |
||||
|
||||
static inline struct windows_device_handle_priv *_device_handle_priv( |
||||
struct libusb_device_handle *handle) |
||||
{ |
||||
return (struct windows_device_handle_priv *) handle->os_priv; |
||||
} |
||||
|
||||
// used for async polling functions
|
||||
struct windows_transfer_priv { |
||||
struct winfd pollable_fd; |
||||
uint8_t interface_number; |
||||
}; |
||||
|
||||
// used to match a device driver (including filter drivers) against a supported API
|
||||
struct driver_lookup { |
||||
char list[MAX_KEY_LENGTH+1];// REG_MULTI_SZ list of services (driver) names
|
||||
const DWORD reg_prop; // SPDRP registry key to use to retreive list
|
||||
const char* designation; // internal designation (for debug output)
|
||||
}; |
||||
|
||||
/*
|
||||
* API macros - from libusb-win32 1.x |
||||
*/ |
||||
#define DLL_DECLARE_PREFIXNAME(api, ret, prefixname, name, args) \ |
||||
typedef ret (api * __dll_##name##_t)args; \ |
||||
static __dll_##name##_t prefixname = NULL |
||||
|
||||
#define DLL_LOAD_PREFIXNAME(dll, prefixname, name, ret_on_failure) \ |
||||
do { \ |
||||
HMODULE h = GetModuleHandleA(#dll); \ |
||||
if (!h) \ |
||||
h = LoadLibraryA(#dll); \ |
||||
if (!h) { \ |
||||
if (ret_on_failure) { return LIBUSB_ERROR_NOT_FOUND; }\ |
||||
else { break; } \ |
||||
} \ |
||||
prefixname = (__dll_##name##_t)GetProcAddress(h, #name); \ |
||||
if (prefixname) break; \ |
||||
prefixname = (__dll_##name##_t)GetProcAddress(h, #name "A"); \ |
||||
if (prefixname) break; \ |
||||
prefixname = (__dll_##name##_t)GetProcAddress(h, #name "W"); \ |
||||
if (prefixname) break; \ |
||||
if(ret_on_failure) \ |
||||
return LIBUSB_ERROR_NOT_FOUND; \ |
||||
} while(0) |
||||
|
||||
#define DLL_DECLARE(api, ret, name, args) DLL_DECLARE_PREFIXNAME(api, ret, name, name, args) |
||||
#define DLL_LOAD(dll, name, ret_on_failure) DLL_LOAD_PREFIXNAME(dll, name, name, ret_on_failure) |
||||
#define DLL_DECLARE_PREFIXED(api, ret, prefix, name, args) DLL_DECLARE_PREFIXNAME(api, ret, prefix##name, name, args) |
||||
#define DLL_LOAD_PREFIXED(dll, prefix, name, ret_on_failure) DLL_LOAD_PREFIXNAME(dll, prefix##name, name, ret_on_failure) |
||||
|
||||
/* OLE32 dependency */ |
||||
DLL_DECLARE_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID)); |
||||
|
||||
/* SetupAPI dependencies */ |
||||
DLL_DECLARE_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD)); |
||||
DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA)); |
||||
DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA, |
||||
const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA)); |
||||
DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, |
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA)); |
||||
DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO)); |
||||
DLL_DECLARE_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM)); |
||||
DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO, |
||||
PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)); |
||||
DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD)); |
||||
DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY)); |
||||
|
||||
/*
|
||||
* Windows DDK API definitions. Most of it copied from MinGW's includes |
||||
*/ |
||||
typedef DWORD DEVNODE, DEVINST; |
||||
typedef DEVNODE *PDEVNODE, *PDEVINST; |
||||
typedef DWORD RETURN_TYPE; |
||||
typedef RETURN_TYPE CONFIGRET; |
||||
|
||||
#define CR_SUCCESS 0x00000000 |
||||
#define CR_NO_SUCH_DEVNODE 0x0000000D |
||||
|
||||
#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE |
||||
#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG |
||||
#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING |
||||
#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE |
||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT |
||||
|
||||
#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS |
||||
#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE |
||||
#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE |
||||
#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS |
||||
#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR |
||||
#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR |
||||
#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION |
||||
#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION |
||||
#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE |
||||
#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE |
||||
#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME |
||||
|
||||
#define USB_GET_NODE_INFORMATION 258 |
||||
#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 |
||||
#define USB_GET_NODE_CONNECTION_NAME 261 |
||||
#define USB_GET_HUB_CAPABILITIES 271 |
||||
#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX) |
||||
#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 |
||||
#endif |
||||
#if !defined(USB_GET_HUB_CAPABILITIES_EX) |
||||
#define USB_GET_HUB_CAPABILITIES_EX 276 |
||||
#endif |
||||
|
||||
#ifndef METHOD_BUFFERED |
||||
#define METHOD_BUFFERED 0 |
||||
#endif |
||||
#ifndef FILE_ANY_ACCESS |
||||
#define FILE_ANY_ACCESS 0x00000000 |
||||
#endif |
||||
#ifndef FILE_DEVICE_UNKNOWN |
||||
#define FILE_DEVICE_UNKNOWN 0x00000022 |
||||
#endif |
||||
#ifndef FILE_DEVICE_USB |
||||
#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN |
||||
#endif |
||||
|
||||
#ifndef CTL_CODE |
||||
#define CTL_CODE(DeviceType, Function, Method, Access)( \ |
||||
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) |
||||
#endif |
||||
|
||||
typedef enum USB_CONNECTION_STATUS { |
||||
NoDeviceConnected, |
||||
DeviceConnected, |
||||
DeviceFailedEnumeration, |
||||
DeviceGeneralFailure, |
||||
DeviceCausedOvercurrent, |
||||
DeviceNotEnoughPower, |
||||
DeviceNotEnoughBandwidth, |
||||
DeviceHubNestedTooDeeply, |
||||
DeviceInLegacyHub |
||||
} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; |
||||
|
||||
typedef enum USB_HUB_NODE { |
||||
UsbHub, |
||||
UsbMIParent |
||||
} USB_HUB_NODE; |
||||
|
||||
/* Cfgmgr32.dll interface */ |
||||
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); |
||||
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); |
||||
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); |
||||
DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); |
||||
|
||||
#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ |
||||
CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) |
||||
|
||||
#define IOCTL_USB_GET_HUB_CAPABILITIES \ |
||||
CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS) |
||||
|
||||
#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ |
||||
CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS) |
||||
|
||||
#define IOCTL_USB_GET_ROOT_HUB_NAME \ |
||||
CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) |
||||
|
||||
#define IOCTL_USB_GET_NODE_INFORMATION \ |
||||
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) |
||||
|
||||
#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ |
||||
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) |
||||
|
||||
#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \ |
||||
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS) |
||||
|
||||
#define IOCTL_USB_GET_NODE_CONNECTION_NAME \ |
||||
CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) |
||||
|
||||
// Most of the structures below need to be packed
|
||||
#pragma pack(push, 1) |
||||
|
||||
typedef struct USB_INTERFACE_DESCRIPTOR { |
||||
UCHAR bLength; |
||||
UCHAR bDescriptorType; |
||||
UCHAR bInterfaceNumber; |
||||
UCHAR bAlternateSetting; |
||||
UCHAR bNumEndpoints; |
||||
UCHAR bInterfaceClass; |
||||
UCHAR bInterfaceSubClass; |
||||
UCHAR bInterfaceProtocol; |
||||
UCHAR iInterface; |
||||
} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; |
||||
|
||||
typedef struct USB_CONFIGURATION_DESCRIPTOR { |
||||
UCHAR bLength; |
||||
UCHAR bDescriptorType; |
||||
USHORT wTotalLength; |
||||
UCHAR bNumInterfaces; |
||||
UCHAR bConfigurationValue; |
||||
UCHAR iConfiguration; |
||||
UCHAR bmAttributes; |
||||
UCHAR MaxPower; |
||||
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; |
||||
|
||||
typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT { |
||||
struct { |
||||
ULONG ConnectionIndex; |
||||
struct { |
||||
UCHAR bmRequest; |
||||
UCHAR bRequest; |
||||
USHORT wValue; |
||||
USHORT wIndex; |
||||
USHORT wLength; |
||||
} SetupPacket; |
||||
} req; |
||||
USB_CONFIGURATION_DESCRIPTOR data; |
||||
} USB_CONFIGURATION_DESCRIPTOR_SHORT; |
||||
|
||||
typedef struct USB_ENDPOINT_DESCRIPTOR { |
||||
UCHAR bLength; |
||||
UCHAR bDescriptorType; |
||||
UCHAR bEndpointAddress; |
||||
UCHAR bmAttributes; |
||||
USHORT wMaxPacketSize; |
||||
UCHAR bInterval; |
||||
} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; |
||||
|
||||
typedef struct USB_DESCRIPTOR_REQUEST { |
||||
ULONG ConnectionIndex; |
||||
struct { |
||||
UCHAR bmRequest; |
||||
UCHAR bRequest; |
||||
USHORT wValue; |
||||
USHORT wIndex; |
||||
USHORT wLength; |
||||
} SetupPacket; |
||||
// UCHAR Data[0];
|
||||
} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; |
||||
|
||||
typedef struct USB_HUB_DESCRIPTOR { |
||||
UCHAR bDescriptorLength; |
||||
UCHAR bDescriptorType; |
||||
UCHAR bNumberOfPorts; |
||||
USHORT wHubCharacteristics; |
||||
UCHAR bPowerOnToPowerGood; |
||||
UCHAR bHubControlCurrent; |
||||
UCHAR bRemoveAndPowerMask[64]; |
||||
} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; |
||||
|
||||
typedef struct USB_ROOT_HUB_NAME { |
||||
ULONG ActualLength; |
||||
WCHAR RootHubName[1]; |
||||
} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME; |
||||
|
||||
typedef struct USB_ROOT_HUB_NAME_FIXED { |
||||
ULONG ActualLength; |
||||
WCHAR RootHubName[MAX_PATH_LENGTH]; |
||||
} USB_ROOT_HUB_NAME_FIXED; |
||||
|
||||
typedef struct USB_NODE_CONNECTION_NAME { |
||||
ULONG ConnectionIndex; |
||||
ULONG ActualLength; |
||||
WCHAR NodeName[1]; |
||||
} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME; |
||||
|
||||
typedef struct USB_NODE_CONNECTION_NAME_FIXED { |
||||
ULONG ConnectionIndex; |
||||
ULONG ActualLength; |
||||
WCHAR NodeName[MAX_PATH_LENGTH]; |
||||
} USB_NODE_CONNECTION_NAME_FIXED; |
||||
|
||||
typedef struct USB_HUB_NAME_FIXED { |
||||
union { |
||||
USB_ROOT_HUB_NAME_FIXED root; |
||||
USB_NODE_CONNECTION_NAME_FIXED node; |
||||
} u; |
||||
} USB_HUB_NAME_FIXED; |
||||
|
||||
typedef struct USB_HUB_INFORMATION { |
||||
USB_HUB_DESCRIPTOR HubDescriptor; |
||||
BOOLEAN HubIsBusPowered; |
||||
} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; |
||||
|
||||
typedef struct USB_MI_PARENT_INFORMATION { |
||||
ULONG NumberOfInterfaces; |
||||
} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; |
||||
|
||||
typedef struct USB_NODE_INFORMATION { |
||||
USB_HUB_NODE NodeType; |
||||
union { |
||||
USB_HUB_INFORMATION HubInformation; |
||||
USB_MI_PARENT_INFORMATION MiParentInformation; |
||||
} u; |
||||
} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; |
||||
|
||||
typedef struct USB_PIPE_INFO { |
||||
USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; |
||||
ULONG ScheduleOffset; |
||||
} USB_PIPE_INFO, *PUSB_PIPE_INFO; |
||||
|
||||
typedef struct USB_NODE_CONNECTION_INFORMATION_EX { |
||||
ULONG ConnectionIndex; |
||||
USB_DEVICE_DESCRIPTOR DeviceDescriptor; |
||||
UCHAR CurrentConfigurationValue; |
||||
UCHAR Speed; |
||||
BOOLEAN DeviceIsHub; |
||||
USHORT DeviceAddress; |
||||
ULONG NumberOfOpenPipes; |
||||
USB_CONNECTION_STATUS ConnectionStatus; |
||||
// USB_PIPE_INFO PipeList[0];
|
||||
} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; |
||||
|
||||
typedef struct USB_HUB_CAP_FLAGS { |
||||
ULONG HubIsHighSpeedCapable:1; |
||||
ULONG HubIsHighSpeed:1; |
||||
ULONG HubIsMultiTtCapable:1; |
||||
ULONG HubIsMultiTt:1; |
||||
ULONG HubIsRoot:1; |
||||
ULONG HubIsArmedWakeOnConnect:1; |
||||
ULONG ReservedMBZ:26; |
||||
} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; |
||||
|
||||
typedef struct USB_HUB_CAPABILITIES { |
||||
ULONG HubIs2xCapable : 1; |
||||
} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES; |
||||
|
||||
typedef struct USB_HUB_CAPABILITIES_EX { |
||||
USB_HUB_CAP_FLAGS CapabilityFlags; |
||||
} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; |
||||
|
||||
#pragma pack(pop) |
||||
|
||||
/* winusb.dll interface */ |
||||
|
||||
#define SHORT_PACKET_TERMINATE 0x01 |
||||
#define AUTO_CLEAR_STALL 0x02 |
||||
#define PIPE_TRANSFER_TIMEOUT 0x03 |
||||
#define IGNORE_SHORT_PACKETS 0x04 |
||||
#define ALLOW_PARTIAL_READS 0x05 |
||||
#define AUTO_FLUSH 0x06 |
||||
#define RAW_IO 0x07 |
||||
#define MAXIMUM_TRANSFER_SIZE 0x08 |
||||
#define AUTO_SUSPEND 0x81 |
||||
#define SUSPEND_DELAY 0x83 |
||||
#define DEVICE_SPEED 0x01 |
||||
#define LowSpeed 0x01 |
||||
#define FullSpeed 0x02 |
||||
#define HighSpeed 0x03 |
||||
|
||||
typedef enum USBD_PIPE_TYPE { |
||||
UsbdPipeTypeControl, |
||||
UsbdPipeTypeIsochronous, |
||||
UsbdPipeTypeBulk, |
||||
UsbdPipeTypeInterrupt |
||||
} USBD_PIPE_TYPE; |
||||
|
||||
typedef struct { |
||||
USBD_PIPE_TYPE PipeType; |
||||
UCHAR PipeId; |
||||
USHORT MaximumPacketSize; |
||||
UCHAR Interval; |
||||
} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; |
||||
|
||||
#pragma pack(1) |
||||
typedef struct { |
||||
UCHAR request_type; |
||||
UCHAR request; |
||||
USHORT value; |
||||
USHORT index; |
||||
USHORT length; |
||||
} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; |
||||
#pragma pack() |
||||
|
||||
typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; |
||||
|
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); |
||||
DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); |
@ -1,322 +0,0 @@
@@ -1,322 +0,0 @@
|
||||
/*
|
||||
* Synchronous I/O functions for libusb |
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> |
||||
* |
||||
* 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 <config.h> |
||||
#include <errno.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include "libusbi.h" |
||||
|
||||
/**
|
||||
* @defgroup syncio Synchronous device I/O |
||||
* |
||||
* This page documents libusb's synchronous (blocking) API for USB device I/O. |
||||
* This interface is easy to use but has some limitations. More advanced users |
||||
* may wish to consider using the \ref asyncio "asynchronous I/O API" instead. |
||||
*/ |
||||
|
||||
static void LIBUSB_CALL ctrl_transfer_cb(struct libusb_transfer *transfer) |
||||
{ |
||||
int *completed = transfer->user_data; |
||||
*completed = 1; |
||||
usbi_dbg("actual_length=%d", transfer->actual_length); |
||||
/* caller interprets result and frees transfer */ |
||||
} |
||||
|
||||
/** \ingroup syncio
|
||||
* Perform a USB control transfer. |
||||
* |
||||
* The direction of the transfer is inferred from the bmRequestType field of |
||||
* the setup packet. |
||||
* |
||||
* The wValue, wIndex and wLength fields values should be given in host-endian |
||||
* byte order. |
||||
* |
||||
* \param dev_handle a handle for the device to communicate with |
||||
* \param bmRequestType the request type field for the setup packet |
||||
* \param bRequest the request field for the setup packet |
||||
* \param wValue the value field for the setup packet |
||||
* \param wIndex the index field for the setup packet |
||||
* \param data a suitably-sized data buffer for either input or output |
||||
* (depending on direction bits within bmRequestType) |
||||
* \param wLength the length field for the setup packet. The data buffer should |
||||
* be at least this size. |
||||
* \param timeout timeout (in millseconds) that this function should wait |
||||
* before giving up due to no response being received. For an unlimited |
||||
* timeout, use value 0. |
||||
* \returns on success, the number of bytes actually transferred |
||||
* \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out |
||||
* \returns LIBUSB_ERROR_PIPE if the control request was not supported by the |
||||
* device |
||||
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected |
||||
* \returns another LIBUSB_ERROR code on other failures |
||||
*/ |
||||
int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, |
||||
uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, |
||||
unsigned char *data, uint16_t wLength, unsigned int timeout) |
||||
{ |
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0); |
||||
unsigned char *buffer; |
||||
int completed = 0; |
||||
int r; |
||||
|
||||
if (!transfer) |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
|
||||
buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength); |
||||
if (!buffer) { |
||||
libusb_free_transfer(transfer); |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
} |
||||
|
||||
libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, |
||||
wLength); |
||||
if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) |
||||
memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength); |
||||
|
||||
libusb_fill_control_transfer(transfer, dev_handle, buffer, |
||||
ctrl_transfer_cb, &completed, timeout); |
||||
transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER; |
||||
r = libusb_submit_transfer(transfer); |
||||
if (r < 0) { |
||||
libusb_free_transfer(transfer); |
||||
return r; |
||||
} |
||||
|
||||
while (!completed) { |
||||
r = libusb_handle_events_completed(HANDLE_CTX(dev_handle), &completed); |
||||
if (r < 0) { |
||||
if (r == LIBUSB_ERROR_INTERRUPTED) |
||||
continue; |
||||
libusb_cancel_transfer(transfer); |
||||
while (!completed) |
||||
if (libusb_handle_events_completed(HANDLE_CTX(dev_handle), &completed) < 0) |
||||
break; |
||||
libusb_free_transfer(transfer); |
||||
return r; |
||||
} |
||||
} |
||||
|
||||
if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) |
||||
memcpy(data, libusb_control_transfer_get_data(transfer), |
||||
transfer->actual_length); |
||||
|
||||
switch (transfer->status) { |
||||
case LIBUSB_TRANSFER_COMPLETED: |
||||
r = transfer->actual_length; |
||||
break; |
||||
case LIBUSB_TRANSFER_TIMED_OUT: |
||||
r = LIBUSB_ERROR_TIMEOUT; |
||||
break; |
||||
case LIBUSB_TRANSFER_STALL: |
||||
r = LIBUSB_ERROR_PIPE; |
||||
break; |
||||
case LIBUSB_TRANSFER_NO_DEVICE: |
||||
r = LIBUSB_ERROR_NO_DEVICE; |
||||
break; |
||||
case LIBUSB_TRANSFER_OVERFLOW: |
||||
r = LIBUSB_ERROR_OVERFLOW; |
||||
break; |
||||
case LIBUSB_TRANSFER_ERROR: |
||||
case LIBUSB_TRANSFER_CANCELLED: |
||||
r = LIBUSB_ERROR_IO; |
||||
break; |
||||
default: |
||||
usbi_warn(HANDLE_CTX(dev_handle), |
||||
"unrecognised status code %d", transfer->status); |
||||
r = LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
libusb_free_transfer(transfer); |
||||
return r; |
||||
} |
||||
|
||||
static void LIBUSB_CALL bulk_transfer_cb(struct libusb_transfer *transfer) |
||||
{ |
||||
int *completed = transfer->user_data; |
||||
*completed = 1; |
||||
usbi_dbg("actual_length=%d", transfer->actual_length); |
||||
/* caller interprets results and frees transfer */ |
||||
} |
||||
|
||||
static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, |
||||
unsigned char endpoint, unsigned char *buffer, int length, |
||||
int *transferred, unsigned int timeout, unsigned char type) |
||||
{ |
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0); |
||||
int completed = 0; |
||||
int r; |
||||
|
||||
if (!transfer) |
||||
return LIBUSB_ERROR_NO_MEM; |
||||
|
||||
libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length, |
||||
bulk_transfer_cb, &completed, timeout); |
||||
transfer->type = type; |
||||
|
||||
r = libusb_submit_transfer(transfer); |
||||
if (r < 0) { |
||||
libusb_free_transfer(transfer); |
||||
return r; |
||||
} |
||||
|
||||
while (!completed) { |
||||
r = libusb_handle_events_completed(HANDLE_CTX(dev_handle), &completed); |
||||
if (r < 0) { |
||||
if (r == LIBUSB_ERROR_INTERRUPTED) |
||||
continue; |
||||
libusb_cancel_transfer(transfer); |
||||
while (!completed) |
||||
if (libusb_handle_events_completed(HANDLE_CTX(dev_handle), &completed) < 0) |
||||
break; |
||||
libusb_free_transfer(transfer); |
||||
return r; |
||||
} |
||||
} |
||||
|
||||
*transferred = transfer->actual_length; |
||||
switch (transfer->status) { |
||||
case LIBUSB_TRANSFER_COMPLETED: |
||||
r = 0; |
||||
break; |
||||
case LIBUSB_TRANSFER_TIMED_OUT: |
||||
r = LIBUSB_ERROR_TIMEOUT; |
||||
break; |
||||
case LIBUSB_TRANSFER_STALL: |
||||
r = LIBUSB_ERROR_PIPE; |
||||
break; |
||||
case LIBUSB_TRANSFER_OVERFLOW: |
||||
r = LIBUSB_ERROR_OVERFLOW; |
||||
break; |
||||
case LIBUSB_TRANSFER_NO_DEVICE: |
||||
r = LIBUSB_ERROR_NO_DEVICE; |
||||
break; |
||||
case LIBUSB_TRANSFER_ERROR: |
||||
case LIBUSB_TRANSFER_CANCELLED: |
||||
r = LIBUSB_ERROR_IO; |
||||
break; |
||||
default: |
||||
usbi_warn(HANDLE_CTX(dev_handle), |
||||
"unrecognised status code %d", transfer->status); |
||||
r = LIBUSB_ERROR_OTHER; |
||||
} |
||||
|
||||
libusb_free_transfer(transfer); |
||||
return r; |
||||
} |
||||
|
||||
/** \ingroup syncio
|
||||
* Perform a USB bulk transfer. The direction of the transfer is inferred from |
||||
* the direction bits of the endpoint address. |
||||
* |
||||
* For bulk reads, the <tt>length</tt> field indicates the maximum length of |
||||
* data you are expecting to receive. If less data arrives than expected, |
||||
* this function will return that data, so be sure to check the |
||||
* <tt>transferred</tt> output parameter. |
||||
* |
||||
* You should also check the <tt>transferred</tt> parameter for bulk writes. |
||||
* Not all of the data may have been written. |
||||
* |
||||
* Also check <tt>transferred</tt> when dealing with a timeout error code. |
||||
* libusb may have to split your transfer into a number of chunks to satisfy |
||||
* underlying O/S requirements, meaning that the timeout may expire after |
||||
* the first few chunks have completed. libusb is careful not to lose any data |
||||
* that may have been transferred; do not assume that timeout conditions |
||||
* indicate a complete lack of I/O. |
||||
* |
||||
* \param dev_handle a handle for the device to communicate with |
||||
* \param endpoint the address of a valid endpoint to communicate with |
||||
* \param data a suitably-sized data buffer for either input or output |
||||
* (depending on endpoint) |
||||
* \param length for bulk writes, the number of bytes from data to be sent. for |
||||
* bulk reads, the maximum number of bytes to receive into the data buffer. |
||||
* \param transferred output location for the number of bytes actually |
||||
* transferred. |
||||
* \param timeout timeout (in millseconds) that this function should wait |
||||
* before giving up due to no response being received. For an unlimited |
||||
* timeout, use value 0. |
||||
* |
||||
* \returns 0 on success (and populates <tt>transferred</tt>) |
||||
* \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates |
||||
* <tt>transferred</tt>) |
||||
* \returns LIBUSB_ERROR_PIPE if the endpoint halted |
||||
* \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see |
||||
* \ref packetoverflow |
||||
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected |
||||
* \returns another LIBUSB_ERROR code on other failures |
||||
*/ |
||||
int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle, |
||||
unsigned char endpoint, unsigned char *data, int length, int *transferred, |
||||
unsigned int timeout) |
||||
{ |
||||
return do_sync_bulk_transfer(dev_handle, endpoint, data, length, |
||||
transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK); |
||||
} |
||||
|
||||
/** \ingroup syncio
|
||||
* Perform a USB interrupt transfer. The direction of the transfer is inferred |
||||
* from the direction bits of the endpoint address. |
||||
* |
||||
* For interrupt reads, the <tt>length</tt> field indicates the maximum length |
||||
* of data you are expecting to receive. If less data arrives than expected, |
||||
* this function will return that data, so be sure to check the |
||||
* <tt>transferred</tt> output parameter. |
||||
* |
||||
* You should also check the <tt>transferred</tt> parameter for interrupt |
||||
* writes. Not all of the data may have been written. |
||||
* |
||||
* Also check <tt>transferred</tt> when dealing with a timeout error code. |
||||
* libusb may have to split your transfer into a number of chunks to satisfy |
||||
* underlying O/S requirements, meaning that the timeout may expire after |
||||
* the first few chunks have completed. libusb is careful not to lose any data |
||||
* that may have been transferred; do not assume that timeout conditions |
||||
* indicate a complete lack of I/O. |
||||
* |
||||
* The default endpoint bInterval value is used as the polling interval. |
||||
* |
||||
* \param dev_handle a handle for the device to communicate with |
||||
* \param endpoint the address of a valid endpoint to communicate with |
||||
* \param data a suitably-sized data buffer for either input or output |
||||
* (depending on endpoint) |
||||
* \param length for bulk writes, the number of bytes from data to be sent. for |
||||
* bulk reads, the maximum number of bytes to receive into the data buffer. |
||||
* \param transferred output location for the number of bytes actually |
||||
* transferred. |
||||
* \param timeout timeout (in millseconds) that this function should wait |
||||
* before giving up due to no response being received. For an unlimited |
||||
* timeout, use value 0. |
||||
* |
||||
* \returns 0 on success (and populates <tt>transferred</tt>) |
||||
* \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out |
||||
* \returns LIBUSB_ERROR_PIPE if the endpoint halted |
||||
* \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see |
||||
* \ref packetoverflow |
||||
* \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected |
||||
* \returns another LIBUSB_ERROR code on other error |
||||
*/ |
||||
int API_EXPORTED libusb_interrupt_transfer( |
||||
struct libusb_device_handle *dev_handle, unsigned char endpoint, |
||||
unsigned char *data, int length, int *transferred, unsigned int timeout) |
||||
{ |
||||
return do_sync_bulk_transfer(dev_handle, endpoint, data, length, |
||||
transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT); |
||||
} |
||||
|
@ -1,18 +0,0 @@
@@ -1,18 +0,0 @@
|
||||
/* This file is parsed by m4 and windres and RC.EXE so please keep it simple. */ |
||||
#ifndef LIBUSB_MAJOR |
||||
#define LIBUSB_MAJOR 1 |
||||
#endif |
||||
#ifndef LIBUSB_MINOR |
||||
#define LIBUSB_MINOR 0 |
||||
#endif |
||||
#ifndef LIBUSB_MICRO |
||||
#define LIBUSB_MICRO 16 |
||||
#endif |
||||
/* LIBUSB_NANO may be used for Windows internal versioning. 0 means unused. */ |
||||
#ifndef LIBUSB_NANO |
||||
#define LIBUSB_NANO 0 |
||||
#endif |
||||
/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */ |
||||
#ifndef LIBUSB_RC |
||||
#define LIBUSB_RC "-rc10" |
||||
#endif |
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
libtool.m4 |
||||
lt~obsolete.m4 |
||||
ltoptions.m4 |
||||
ltsugar.m4 |
||||
ltversion.m4 |
@ -1,86 +0,0 @@
@@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env python2.7 |
||||
# |
||||
# Original version supplied to me (Kano/kanoi) by xiangfu |
||||
# |
||||
# Modified to allow supplying the data to send |
||||
# |
||||
# Linux usAge: ./ubstest.py /dev/ttyUSB0 0xhexcodes|string|icarus |
||||
# OR python ubstest.py /dev/ttyUSB0 0xhexcodes|string|icarus |
||||
# |
||||
# Windows usAge: ./ubstest.py COM1 0xhexcodes|string|icarus |
||||
# |
||||
# sends the data sepcified to the USB device and waits |
||||
# for a reply then displays it |
||||
# |
||||
# the data can be: |
||||
# 0xhexcodes: e.g. 0x68656c6c6f20776f726c640a |
||||
# would send "hello world\n" |
||||
# |
||||
# string: e.g. sendsometext |
||||
# |
||||
# icarus: sends 2 known block payloads for an icarus device |
||||
# and shows the expected and actual answers if it's |
||||
# a working V3 icarus |
||||
|
||||
import sys |
||||
import serial |
||||
import binascii |
||||
|
||||
if len(sys.argv) < 2: |
||||
sys.stderr.write("usAge: " + sys.argv[0] + " device strings...\n") |
||||
sys.stderr.write(" where device is either like /dev/ttyUSB0 or COM1\n") |
||||
sys.stderr.write(" and strings are either '0xXXXX' or 'text'\n") |
||||
sys.stderr.write(" if the first string is 'icarus' the rest are ignored\n") |
||||
sys.stderr.write(" and 2 valid icarus test payloads are sent with results displayed\n") |
||||
sys.stderr.write("\nAfter any command is sent it waits up to 30 seconds for a reply\n"); |
||||
sys.exit("Aborting") |
||||
|
||||
# Open with a 10 second timeout - just to be sure |
||||
ser = serial.Serial(sys.argv[1], 115200, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 10, False, False, 5, False, None) |
||||
|
||||
if sys.argv[2] == "icarus": |
||||
|
||||
# This show how Icarus use the block and midstate data |
||||
# This will produce nonce 063c5e01 |
||||
block = "0000000120c8222d0497a7ab44a1a2c7bf39de941c9970b1dc7cdc400000079700000000e88aabe1f353238c668d8a4df9318e614c10c474f8cdf8bc5f6397b946c33d7c4e7242c31a098ea500000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000" |
||||
midstate = "33c5bf5751ec7f7e056443b5aee3800331432c83f404d9de38b94ecbf907b92d" |
||||
|
||||
rdata2 = block.decode('hex')[95:63:-1] |
||||
rmid = midstate.decode('hex')[::-1] |
||||
payload = rmid + rdata2 |
||||
|
||||
print("Push payload to icarus: " + binascii.hexlify(payload)) |
||||
ser.write(payload) |
||||
|
||||
b=ser.read(4) |
||||
print("Result:(should be: 063c5e01): " + binascii.hexlify(b)) |
||||
|
||||
# Just another test |
||||
payload2 = "ce92099c5a80bb81c52990d5c0924c625fd25a535640607d5a4bdf8174e2c8d500000000000000000000000080000000000000000b290c1a42313b4f21b5bcb8" |
||||
print("Push payload to icarus: " + payload2) |
||||
ser.write(payload2.decode('hex')) |
||||
|
||||
b=ser.read(4) |
||||
print("Result:(should be: 8e0b31c5): " + binascii.hexlify(b)) |
||||
else: |
||||
data = "" |
||||
for arg in sys.argv[2::]: |
||||
if arg[0:2:] == '0x': |
||||
data += arg[2::].decode('hex') |
||||
else: |
||||
data += arg |
||||
|
||||
print("Sending: 0x" + binascii.hexlify(data)) |
||||
ser.write(data) |
||||
|
||||
# If you're expecting more than one linefeed terminated reply, |
||||
# you'll only see the first one |
||||
# AND with no linefeed, this will wait the 10 seconds before returning |
||||
print("Waiting up to 10 seconds ...") |
||||
b=ser.readline() |
||||
print("Result: hex 0x" + binascii.hexlify(b)) |
||||
|
||||
# This could mess up the display - do it last |
||||
print("Result: asc '" + b + "'") |
||||
|
||||
ser.close() |
Loading…
Reference in new issue