Initial revision
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 0000000..ef13344
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,21 @@
+*.tar.gz
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+build-stamp
+config.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+configure-stamp
+hotplug.sh
+libmtp-*
+libmtp.pc
+libtool
+libmtp.sh
+stamp-h1
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..f4e4888
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,7 @@
+libmtp was created by:
+
+Richard Low <richard@wentnet.com>
+Linus Walleij <triad@df.lth.se>
+
+We both came to do libmtp after working on the libnjb
+project.
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f89b4fa
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..68fb379
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,13 @@
+AUTHORS
+autogen.sh
+COPYING
+Makefile.am
+ChangeLog
+configure.ac
+libmtp.pc.in
+
+
+2006-01-30 Linus Walleij <triad@df.lth.se>
+
+ * Created the initial GNU source directory structure.
+ * Added the most basic files.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..c69d766
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,9 @@
+SUBDIRS=src examples doc
+
+pkgconfigdir=$(libdir)/pkgconfig
+pkgconfig_DATA=libmtp.pc
+EXTRA_DIST=libmtp.pc \
+libmtp.usermap \
+libmtp.rules \
+libmtp.sh \
+COPYING
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..509f3a3
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+set -e
+
+# Refresh GNU autotools toolchain.
+libtoolize --copy --force
+aclocal
+autoheader
+automake --add-missing
+autoconf
+
+# Autoupdate config.sub and config.guess
+# from GNU CVS
+WGET=`which wget`
+if [ "x$WGET" != "x" ]; then
+ echo "Autoupdate config.sub and config.guess (y/n)?"
+ read IN
+ if [ "$IN" = "y" ] || [ "$IN" = "Y" ]; then
+ wget -O tmpfile http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+ mv tmpfile config.guess
+ wget -O tmpfile http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+ mv tmpfile config.sub
+ fi
+else
+ echo "Could not autoupdate config.sub and config.guess"
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..e269cbb
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,93 @@
+# Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.52)
+AC_INIT([libmtp], [0.0.1], [libmtp-users@lists.sourceforge.net])
+AM_INIT_AUTOMAKE([foreign])
+AC_CONFIG_SRCDIR([src/libmtp.c])
+AC_CONFIG_HEADER([config.h])
+
+# This can be overridden by the command line switch
+if test "$program_prefix" = NONE; then
+ program_prefix=mtp-
+ program_transform_name="s,^,$program_prefix,;$program_transform_name"
+fi
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_LIBTOOL_WIN32_DLL
+AC_PROG_LIBTOOL
+# Check for doxygen
+AC_CHECK_PROG(HAVE_DOXYGEN, doxygen, true, false)
+AM_CONDITIONAL(HAVE_DOXYGEN,$HAVE_DOXYGEN)
+if test $HAVE_DOXYGEN = "false"; then
+ AC_MSG_WARN([*** doxygen not found, docs will not be built])
+fi
+
+# Check for Darwin
+AC_MSG_CHECKING([if the host operating system is Darwin])
+case "$host" in
+ *-darwin*)
+ AC_MSG_RESULT([yes])
+ CFLAGS="$CFLAGS -DUSE_DARWIN"
+ OSFLAGS="-framework IOKit"
+ ;;
+ *) AC_MSG_RESULT([no]) ;;
+esac
+AC_SUBST(OSFLAGS)
+
+# Check for mingw compiler platform
+AC_MSG_CHECKING([For MinGW32])
+case "$host" in
+ *-*-mingw*)
+ AC_MSG_RESULT([yes])
+ mingw_compiler=yes
+ ;;
+ *) AC_MSG_RESULT([no]) ;;
+esac
+AM_CONDITIONAL(COMPILE_MINGW32, [test "$mingw_compiler" = "yes"])
+
+
+# Checks for libraries.
+AC_CHECK_LIB([curses], [initscr], AC_SUBST([CURSESPLAY], cursesplay))
+AC_CHECK_LIB([usb], [usb_control_msg],,
+ AC_MSG_ERROR([I can't find the libusb libraries on your system. You
+ may need to set the LDFLAGS environment variable to include the
+ search path where you have libusb installed before running
+ configure (e.g. setenv LDFLAGS=-L/usr/local/lib)]), "$OSFLAGS")
+AC_CHECK_LIB([z], [uncompress], AC_SUBST([SAMPLE_LDADD], [-lz]))
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_TIME
+# zlib.h the day we need to decompress firmware
+AC_CHECK_HEADERS([ctype.h errno.h fcntl.h getopt.h libgen.h \
+ limits.h stdio.h string.h sys/stat.h sys/time.h unistd.h])
+AC_CHECK_HEADER([usb.h],,
+ AC_MSG_ERROR([I can't find the libusb header file on your system.
+ You may need to set the CPPFLAGS environment variable to include
+ the search path where you have libusb installed before running
+ configure (e.g. setenv CPPFLAGS=-I/usr/local/include)]))
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_SIGNAL
+AC_TYPE_SIZE_T
+AC_STRUCT_ST_BLKSIZE
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_MEMCMP
+AC_FUNC_STAT
+AC_CHECK_FUNCS(basename memset select strdup strerror strrchr strtoul usleep)
+
+# Switches.
+# Stick in "-Werror" if you want to be more aggressive.
+# (No need to use AC_SUBST on this default substituted environment variable.)
+CFLAGS="$CFLAGS -Wall -Wmissing-prototypes"
+
+# Output files
+AC_CONFIG_FILES([src/libmtp.h doc/Doxyfile Makefile doc/Makefile src/Makefile
+ examples/Makefile libmtp.sh hotplug.sh libmtp.pc])
+AC_OUTPUT
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000..ebca8b1
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,1169 @@
+# Doxyfile 1.3.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "libmtp"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+# Do this with autoconf eventually
+
+PROJECT_NUMBER = @VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+#OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of source
+# files, where putting all generated files in the same directory would otherwise
+# cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is used
+# as the annotated text. Otherwise, the brief description is used as-is. If left
+# blank, the following values are used ("$name" is automatically replaced with the
+# name of the entity): "The $name class" "The $name widget" "The $name file"
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation.
+
+SHOW_DIRECTORIES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# Set to YES by Linus Walleij on 2005-07-30.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+# Set to NO by Linus Walleij on 2005-07-30.
+
+WARNINGS = NO
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+# Set to NO by Linus Walleij on 2005-07-30.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+# Set to NO by Linus Walleij on 2005-07-30.
+
+WARN_IF_DOC_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @top_srcdir@/src \
+ @top_srcdir@/doc/mainpage.h \
+ @top_srcdir@/doc/examples.h
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS = *.c *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = @top_srcdir@/examples
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *.c
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+# doc/libnjb_header.html
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = NO
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes that
+# lay further from the root node will be omitted. Note that setting this option to
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that a graph may be further truncated if the graph's image dimensions are
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..2a0250b
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,20 @@
+EXTRA_DIST=Doxyfile.in examples.h mainpage.h
+
+if HAVE_DOXYGEN
+pkgdocdir=$(datadir)/doc/$(PACKAGE)-$(VERSION)
+htmldocdir=$(pkgdocdir)/html
+
+all-local:
+ doxygen
+
+install-data-local:
+ $(INSTALL) -d $(DESTDIR)$(htmldocdir)
+ $(INSTALL_DATA) html/* $(DESTDIR)$(htmldocdir)
+
+uninstall-local:
+ $(RM) -r $(DESTDIR)$(htmldocdir)
+ $(RM) -r $(DESTDIR)$(pkgdocdir)
+
+clean-local:
+ $(RM) -r html latex man
+endif
diff --git a/doc/examples.h b/doc/examples.h
new file mode 100644
index 0000000..57c6fc2
--- /dev/null
+++ b/doc/examples.h
@@ -0,0 +1,3 @@
+/*
+ * List examples here...
+ */
diff --git a/doc/mainpage.h b/doc/mainpage.h
new file mode 100644
index 0000000..60f8bd8
--- /dev/null
+++ b/doc/mainpage.h
@@ -0,0 +1,16 @@
+/**
+ * \mainpage The official libmtp documentation
+ *
+ * \section Introduction
+ *
+ * libmtp is a library for the Media Transfer Protocol (MTP)
+ * under various POSIX operating systems.
+ *
+ * \section License
+ *
+ * libmtp is available under the GNU General Public License,
+ * version 2. You can use libmtp in Free (speech) software as
+ * long as its license is GPL-compatible. If you do not follow
+ * the GPL you will be in deep, deep trouble.
+ *
+ */
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..448c44c
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,6 @@
+bin_PROGRAMS=detect
+
+detect_SOURCES=detect.c common.h
+
+AM_CFLAGS=-I$(top_builddir)/src
+LDADD=../src/libmtp.la
diff --git a/examples/common.h b/examples/common.h
new file mode 100644
index 0000000..7d33388
--- /dev/null
+++ b/examples/common.h
@@ -0,0 +1,16 @@
+/**
+ * \file common.h
+ * These headers are used by absolutely all sample programs.
+ * Special quirks that apply to all samples go here.
+ */
+#include <libmtp.h>
+#ifndef _MSC_VER
+#include "config.h"
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
+#else
+#include "..\windows\getopt.h"
+#endif
diff --git a/examples/detect.c b/examples/detect.c
new file mode 100644
index 0000000..22da6c2
--- /dev/null
+++ b/examples/detect.c
@@ -0,0 +1,17 @@
+#include "common.h"
+
+int main (int argc, char **argv)
+{
+ mtpdevice_t *device;
+
+ LIBMTP_Init();
+ device = LIBMTP_Get_First_Device();
+ if (device == NULL) {
+ printf("No devices.\n");
+ exit (0);
+ }
+ LIBMTP_Release_Device(device);
+ printf("OK.\n");
+ exit (0);
+}
+
diff --git a/hotplug.sh.in b/hotplug.sh.in
new file mode 100755
index 0000000..df3a24b
--- /dev/null
+++ b/hotplug.sh.in
@@ -0,0 +1,164 @@
+#!/bin/sh
+
+INSTALL="@INSTALL@"
+HOTPLUGPATH=/etc/hotplug
+SCRIPTNAME=libmtp.sh
+USERMAP=libmtp.usermap
+UDEVPATH=/etc/udev/rules.d
+UDEVRULES=libmtp.rules
+
+# See if the parameter script ($2), device ($3) and productid ($4)
+# are already defined in the usermap ($1)
+function inmap {
+ while read LINE; do
+ if [ "x${LINE}" != "x" ]; then
+ firstword=`echo ${LINE} | awk '{ print $1 }'`
+ if [ ${firstword} != "#" ]; then
+ # This is a device line entry
+ script=${firstword}
+ manid=`echo ${LINE} | awk '{ print $3 }'`
+ productid=`echo ${LINE} | awk '{ print $4 }'`
+ # Skip blank products...
+ if [ "x${script}" = "x$2" ]; then
+ if [ "x${manid}" = "x$3" ]; then
+ if [ "x${productid}" = "x$4" ]; then
+ echo "yes"
+ return 0
+ fi
+ fi
+ fi
+ fi
+ fi
+ done < $1
+ echo "no"
+ return 0
+}
+
+# Scan the usermap $2 for all devices in $1 to see if they are already
+# there, else patch the usermap.
+function patchusermap {
+ # Nullify comment
+ comment=""
+ while read LINE; do
+ if [ "x$LINE" != "x" ]; then
+ firstword=`echo ${LINE} | awk '{ print $1 }'`
+ if [ ${firstword} = "#" ]; then
+ # This is a comment line, save it.
+ comment=${LINE}
+ else
+ # This is a device line entry
+ script=${firstword}
+ manid=`echo ${LINE} | awk '{ print $3 }'`
+ productid=`echo ${LINE} | awk '{ print $4 }'`
+ # Skip blank products...
+ if [ "x${manid}" != "x" ]; then
+ # See if this product is already in the usermap
+ echo "Checking for product ${productid} in $2..."
+ if [ `inmap $2 ${script} ${manid} ${productid}` = "no" ]; then
+ echo "Not present, adding to hotplug map."
+ echo ${comment} >> $2
+ echo ${LINE} >> $2
+ comment=""
+ else
+ echo "Already installed."
+ fi
+ fi
+ fi
+ fi
+ done < $1
+}
+
+# Check for udev first
+if test -d ${UDEVPATH} ; then
+ echo "You seem to have udev on your system. Installing udev rules..."
+ ${INSTALL} ${UDEVRULES} ${UDEVPATH}
+ echo "You may need additional setup to get correct permissions on your device."
+ echo "See the INSTALL file for information."
+ echo "Do you also want to install the old hotplug support (y/n)?"
+ read IN
+ if [ "$IN" = "y" ] || [ "$IN" = "Y" ]; then
+ echo "Continuing..."
+ else
+ exit 0
+ fi
+fi
+
+
+# Check prerequisites
+COMMAND=`which grep 2> /dev/null`
+if [ "x${COMMAND}" = "x" ];
+then
+ echo "Missing grep program. Fatal error."
+ exit 1
+fi
+COMMAND=`which awk 2> /dev/null`
+if [ "x${COMMAND}" = "x" ];
+then
+ echo "Missing awk program. Fatal error."
+ exit 1
+fi
+
+# This script locates the hotplug distribution on a certain host
+# and sets up userland hotplugging scripts according to rules.
+# The in-parameters are the hotplug directory and the name of a
+# file of hotplug device entries and a script to be executed for
+# these deviced.
+
+if test -d ${HOTPLUGPATH}
+then
+ echo "Hotplug in ${HOTPLUGPATH}"
+else
+ echo "Hotplug missing on this system. Cannot install."
+ exit 1
+fi
+
+if test -d ${HOTPLUGPATH}/usb
+then
+ echo "Has usb subdirectory."
+else
+ mkdir ${HOTPLUGPATH}/usb
+fi
+
+echo "Installing script."
+${INSTALL} nomadjukebox ${HOTPLUGPATH}/usb
+echo "Installing usermap."
+${INSTALL} -m 644 ${USERMAP} ${HOTPLUGPATH}/usb
+# If we find a usb.usermap file, and we see that this distribution
+# of hotplug does not support private usermaps, then we need to
+# patch the usb.usermap file.
+#
+# Create a merged file, diff the files to each other, and if there
+# were mismatches, then patch the installed file.
+echo "Checking hotplugging CVS version..."
+echo "/etc/hotplug/usb/*.usermap support was added in august 2002"
+EDITMAP="yes"
+CVSTAG=`grep '\$Id:' /etc/hotplug/usb.agent`
+if [ "x${CVSTAG}" != "x" ]; then
+ DATE=`echo ${CVSTAG} | awk '{ print $5 }'`
+ echo "Hotplug version seems to be from ${DATE}"
+ YEAR=`echo ${DATE} | awk 'BEGIN { FS="/"} {print $1; }'`
+ MONTH=`echo ${DATE} | awk 'BEGIN { FS="/"} {print $2; }'`
+ DAY=`echo ${DATE} | awk 'BEGIN { FS="/"} {print $3; }'`
+ if [ "${YEAR}" -gt "2002" ]; then
+ EDITMAP="no"
+ else
+ if [ "${YEAR}" -eq "2002" ]; then
+ if [ "${MONTH}" -ge "08" ]; then
+ EDITMAP="no"
+ fi
+ fi
+ fi
+fi
+if [ "x${EDITMAP}" == "xyes" ]; then
+ echo "We need to edit the ${HOTPLUGPATH}/usb.usermap if it exists..."
+ if test -f ${HOTPLUGPATH}/usb.usermap
+ then
+ echo "We have a usb.usermap..."
+ patchusermap ${USERMAP} /etc/hotplug/usb.usermap
+ fi
+fi
+
+echo "Hotplugging successfully installed."
+
+exit 0
+
diff --git a/libmtp.pc.in b/libmtp.pc.in
new file mode 100644
index 0000000..47b20f9
--- /dev/null
+++ b/libmtp.pc.in
@@ -0,0 +1,14 @@
+# libmtp pkg-config source file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libmtp
+Description: libmtp is a library for accessing Media Transfer Protocol devices
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -lmtp @LIBS@
+Cflags: -I${includedir} @OSFLAGS@
diff --git a/libmtp.rules b/libmtp.rules
new file mode 100644
index 0000000..f19e3ea
--- /dev/null
+++ b/libmtp.rules
@@ -0,0 +1,68 @@
+# nomad.rules a udev rules file for NOMAD jukeboxes.
+# Put this file in /etc/udev/rules.d
+#
+# This script sets the mode of the libnjb accessible devices
+# to "666" meaning "read and write for everyone", really a security
+# risk. Therefore think about it before applying this to your system.
+# However since there are so many ways of managing permissions for
+# devices we have no better idea.
+#
+# If you have a desktop user group, set MODE to "660" and tag
+# on GROUP="jukebox" after the MODE rule. Subsitute GROUP
+# "jukebox" for a good value for your system, this group should
+# include desktop users (see your /etc/group).
+#
+# You can add a RUN="..." attribute to run some arbitrary script
+# when the device is plugged in.
+
+# This rule, if enabled, creates a device node in the hierarchy
+# /dev/bus/usb. This is already part of Fedora Core but I
+# don't know about other distributions. Notice that this will
+# require libusb to be patched too, or use libusb-0.1.12 or
+# higher, or it just won't work.
+#
+# /dev/bus/usb identical to that of /proc/bus/usb. Most distributions
+# using udev already has a rule like this.
+
+# ACTION=="add", SUBSYSTEM=="usb_device", \
+ PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; \
+ printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", \
+ NAME="%c", MODE="0644"
+
+# Old erroneous rule used for debug purposes.
+# ACTION=="add", SUBSYSTEM=="usb_device", PROGRAM="/bin/sh -c 'X=%k X=$${X#usbdev} B=$${X%%%%.*} D=$${X#*.}; echo bus/usb/$$B/$$D'", SYMLINK+="%c", RUN="/home/linus/bin/boxplugin %c"
+
+SUBSYSTEM!="usb_device", ACTION!="add", GOTO="nomad_rules_end"
+
+# Creative Nomad Jukebox
+SYSFS{idVendor}=="0471", SYSFS{idProduct}=="0222", MODE="666"
+# Creative Nomad Jukebox 2
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4100", MODE="666"
+# Creative Nomad Jukebox 3
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4101", MODE="666"
+# Creative Nomad Jukebox Zen
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4108", MODE="666"
+# Creative Nomad Jukebox Zen USB 2.0
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="410b", MODE="666"
+# Creative Nomad Jukebox Zen NX
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4109", MODE="666"
+# Creative Nomad Jukebox Zen Xtra
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4110", MODE="666"
+# Dell Digital Jukebox
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4111", MODE="666"
+# Creative Nomad Jukebox Zen Touch
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="411b", MODE="666"
+# Creative Zen (Zen Micro variant)
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="411d", MODE="666"
+# Creative Nomad Jukebox Zen Micro
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="411e", MODE="666"
+# Second Generation Dell Digital Jukebox
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4126", MODE="666"
+# Dell Pocket DJ
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4127", MODE="666"
+# Creative Zen Sleek
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="4136", MODE="666"
+# Third Generation Dell Digital Jukebox
+SYSFS{idVendor}=="041e", SYSFS{idProduct}=="412f", MODE="666"
+
+LABEL="nomad_rules_end"
diff --git a/libmtp.sh.in b/libmtp.sh.in
new file mode 100644
index 0000000..b149413
--- /dev/null
+++ b/libmtp.sh.in
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Lifts a plugged in MTP device to user space and
+# optionally runs a client program.
+# Written by Linus Walleij 2006, based on the "usbcam"
+# script by Nalin Dahyabhai.
+DEVICEOWNER=root
+DEVICEPERMS=666
+
+# Special quirk for SuSE systems using "resmgr"
+# (see http://rechner.lst.de/~okir/resmgr/)
+if [ -f /sbin/resmgr ]
+then
+ /sbin/resmgr "${ACTION}" "${DEVICE}" desktop usb
+ exit 0
+fi
+
+# This is for most other distributions
+if [ "${ACTION}" = "add" ] && [ -f "${DEVICE}" ]
+then
+ # New code, using lock files instead of copying /dev/console permissions
+ # This also works with non-gdm logins (e.g. on a virtual terminal)
+ # Idea and code from Nalin Dahyabhai <nalin@redhat.com>
+ if [ "x$DEVICEOWNER" = "xCONSOLE" ]
+ then
+ if [ -f /var/run/console/console.lock ]
+ then
+ DEVICEOWNER=`cat /var/run/console/console.lock`
+ elif [ -f /var/run/console.lock ]
+ then
+ DEVICEOWNER=`cat /var/run/console.lock`
+ elif [ -f /var/lock/console.lock ]
+ then
+ DEVICEOWNER=`cat /var/lock/console.lock`
+ else
+ DEVICEOWNER="nobody"
+ DEVICEPERMS="666"
+ fi
+ fi
+ if [ -n "$DEVICEOWNER" ]
+ then
+ chmod 0000 "${DEVICE}"
+ chown "${DEVICEOWNER}" "${DEVICE}"
+ chmod "${DEVICEPERMS}" "${DEVICE}"
+ fi
+fi
diff --git a/libmtp.usermap b/libmtp.usermap
new file mode 100644
index 0000000..c7dde38
--- /dev/null
+++ b/libmtp.usermap
@@ -0,0 +1,30 @@
+# Creative Nomad Jukebox
+nomadjukebox 0x0003 0x0471 0x0222 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Nomad Jukebox 2
+nomadjukebox 0x0003 0x041e 0x4100 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Nomad Jukebox 3
+nomadjukebox 0x0003 0x041e 0x4101 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Nomad Jukebox Zen
+nomadjukebox 0x0003 0x041e 0x4108 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Nomad Jukebox Zen USB 2.0
+nomadjukebox 0x0003 0x041e 0x410b 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Nomad Jukebox Zen NX
+nomadjukebox 0x0003 0x041e 0x4109 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Nomad Jukebox Zen Xtra
+nomadjukebox 0x0003 0x041e 0x4110 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Dell Digital Jukebox
+nomadjukebox 0x0003 0x041e 0x4111 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Nomad Jukebox Zen Touch
+nomadjukebox 0x0003 0x041e 0x411b 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Zen (Zen Micro variant)
+nomadjukebox 0x0003 0x041e 0x411d 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Nomad Jukebox Zen Micro
+nomadjukebox 0x0003 0x041e 0x411e 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Second Generation Dell Digital Jukebox
+nomadjukebox 0x0003 0x041e 0x4126 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Dell Pocket DJ
+nomadjukebox 0x0003 0x041e 0x4127 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Creative Zen Sleek
+nomadjukebox 0x0003 0x041e 0x4136 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+# Third Generation Dell Digital Jukebox
+nomadjukebox 0x0003 0x041e 0x412f 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..9eeac7c
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,33 @@
+lib_LTLIBRARIES=libmtp.la
+libmtp_la_SOURCES=libmtp.c \
+ mtp-utils.c mtp-utils.h mtp-pack.c mtp-pack.h mtp.c mtp.h \
+ libptp-endian.h libptp-stdint.h ptp-pack.c ptp-pack.h ptp.c ptp.h
+include_HEADERS=libmtp.h
+EXTRA_DIST=libmtp.h.in libmtp.sym
+
+# This is the version of the *library interface*, not the revision
+# of libmtp itself. Do not change this unless you're absolutely
+# certain of what the difference is. (See the libtool manual,
+# section 6.3 (http://www.gnu.org/software/libtool/manual.html)
+CURRENT=0
+REVISION=0
+AGE=0
+SOVERSION=$(CURRENT):$(REVISION):$(AGE)
+libmtp_la_LDFLAGS=@LDFLAGS@ -version-info $(SOVERSION)
+
+if COMPILE_MINGW32
+noinst_DATA=libmtp.lib
+libmtp_la_LDFLAGS += -export-dynamic -no-undefined -export-symbols libmtp.sym
+libmtp.def: libmtp.sym
+ echo "LIBRARY \"@PACKAGE@\"" > libmtp.def
+ echo "DESCRIPTION \"Media Transfer Protocol (MTP) library\"" >> libmtp.def
+ echo "VERSION @VERSION@" >> libmtp.def
+ echo >> libmtp.def
+ echo "EXPORTS" >> libmtp.def
+ cat libmtp.sym >> libmtp.def
+libmtp.lib: libmtp.la libmtp.def
+ lib -name:libmtp-$(LT_CURRENT_MINUS_AGE).dll -def:libmtp.def -out:$@
+install-data-local: libmtp.lib libmtp.def
+ $(INSTALL) libmtp.def $(DESTDIR)$(libdir)
+ $(INSTALL) libmtp.lib $(DESTDIR)$(libdir)
+endif
diff --git a/src/README b/src/README
new file mode 100644
index 0000000..5a1bf8e
--- /dev/null
+++ b/src/README
@@ -0,0 +1,10 @@
+Lots of docs to follow...
+
+libptp2 is copied (and modified) from version 1.1.0.
+
+For now, to get the endianness right for your system, try configure in libptp2.
+
+I have changed the config script slightly for the le64atoh function in libptp-endian.h.
+This is required for OS X on PowerPC (not sure why). I've just cast the bytes to uint64_t
+to avoid shifting wrongly.
+
diff --git a/src/libmtp.c b/src/libmtp.c
new file mode 100644
index 0000000..13354c5
--- /dev/null
+++ b/src/libmtp.c
@@ -0,0 +1,104 @@
+#include "libmtp.h"
+
+/**
+ * Initialize the library.
+ */
+void LIBMTP_Init(void)
+{
+ return;
+}
+
+/**
+ * Get the first connected MTP device.
+ * @return a device pointer.
+ */
+mtpdevice_t *LIBMTP_Get_First_Device(void)
+{
+ uint8_t interface_number;
+ PTPParams params;
+ PTP_USB ptp_usb;
+ PTPStorageIDs storageIDs;
+ unsigned storageID = 0;
+ PTPDevicePropDesc dpd;
+ uint8_t batteryLevelMax = 100;
+ uint16_t ret;
+ mtpdevice_t *tmpdevice;
+
+ ret = connect_first_device(¶ms, &ptp_usb, &interface_number);
+
+ switch (ret)
+ {
+ case PTP_CD_RC_CONNECTED:
+ printf("Connected to MTP device.\n");
+ break;
+ case PTP_CD_RC_NO_DEVICES:
+ printf("No MTP devices.\n");
+ return NULL;
+ case PTP_CD_RC_ERROR_CONNECTING:
+ printf("Connection error.\n");
+ return NULL;
+ }
+
+ // get storage ID
+ if (ptp_getstorageids (¶ms, &storageIDs) == PTP_RC_OK) {
+ if (storageIDs.n > 0)
+ storageID = storageIDs.Storage[0];
+ free(storageIDs.Storage);
+ }
+
+ // Make sure there are no handlers
+ params.handles.Handler = NULL;
+
+ if (ptp_getdeviceinfo(¶ms, ¶ms.deviceinfo) == PTP_RC_OK) {
+ printf("Model: %s\n", params.deviceinfo.Model);
+ printf("Serial number: %s\n", params.deviceinfo.SerialNumber);
+ printf("Device version: %s\n", params.deviceinfo.DeviceVersion);
+ } else {
+ goto error_handler;
+ }
+
+ // Get battery maximum level
+ if (ptp_getdevicepropdesc(¶ms,PTP_DPC_BatteryLevel,&dpd) != PTP_RC_OK) {
+ printf("Unable to retrieve battery max level.\n");
+ goto error_handler;
+ }
+ // if is NULL, just leave as default
+ if (dpd.FORM.Range.MaximumValue != NULL) {
+ batteryLevelMax = *(uint8_t *)dpd.FORM.Range.MaximumValue;
+ printf("Maximum battery level: %d (%%)\n", batteryLevelMax);
+ }
+ ptp_free_devicepropdesc(&dpd);
+
+ // OK everything got this far, so it is time to create a device struct!
+ tmpdevice = (mtpdevice_t *) malloc(sizeof(mtpdevice_t));
+ tmpdevice->interface_number = interface_number;
+ tmpdevice->params = params;
+ tmpdevice->ptp_usb = ptp_usb;
+ tmpdevice->storage_id = storageID;
+ tmpdevice->maximum_battery_level = batteryLevelMax;
+
+ return tmpdevice;
+
+ // Then close it again.
+ error_handler:
+ close_device(&ptp_usb, ¶ms, interface_number);
+ ptp_free_deviceinfo(¶ms.deviceinfo);
+ if (params.handles.Handler != NULL) {
+ free(params.handles.Handler);
+ }
+ return NULL;
+}
+
+/**
+ * This closes and releases an allocated MTP device.
+ */
+void LIBMTP_Release_Device(mtpdevice_t *device)
+{
+ close_device(&device->ptp_usb, &device->params, &device->interface_number);
+ // Free the device info and any handler
+ ptp_free_deviceinfo(&device->params.deviceinfo);
+ if (device->params.handles.Handler != NULL) {
+ free(device->params.handles.Handler);
+ }
+ free(device);
+}
diff --git a/src/libmtp.h.in b/src/libmtp.h.in
new file mode 100644
index 0000000..c30dedd
--- /dev/null
+++ b/src/libmtp.h.in
@@ -0,0 +1,87 @@
+/**
+ * \file libmtp.h
+ *
+ * Interface to the Media Transfer Protocol library.
+ *
+ * <code>
+ * #include <libmtp.h>
+ * </code>
+ */
+#ifndef LIBMTP_H_INCLUSION_GUARD
+#define LIBMTP_H_INCLUSION_GUARD
+
+#define LIBMTP_VERSION @VERSION@
+
+/* Use our own funny headers */
+#include "mtp-utils.h"
+
+/* This handles MSVC pecularities */
+#ifdef _MSC_VER
+#include <windows.h>
+#define __WIN32__
+#define snprintf _snprintf
+#define ssize_t SSIZE_T
+#endif
+
+#include <sys/types.h>
+
+#ifdef __WIN32__
+/*
+ * Windows specific code, types that do not exist in Windows
+ * sys/types.h
+ */
+typedef char int8_t;
+typedef unsigned char uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#endif
+#include <stdio.h>
+#include <usb.h>
+
+/**
+ * @defgroup types libnjb global type definitions
+ * @{
+ */
+typedef struct mtpdevice_struct mtpdevice_t; /**< @see mtpdevice_struct */
+/** @} */
+
+/**
+ * Main MTP device object struct
+ */
+struct mtpdevice_struct {
+ uint8_t interface_number; /**< Interface number of this device */
+ PTPParams params; /**< Parameters for this device */
+ PTP_USB ptp_usb; /**< USB device for this device */
+ unsigned storage_id; /**< The storage ID for this device */
+ uint8_t maximum_battery_level; /**< The maximum battery level for this device */
+};
+
+/* Make functions available for C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup internals The libmtp internal state manipulation API.
+ * @{
+ */
+void LIBMTP_Init(void);
+/**
+ * @}
+ * @defgroup basic The basic device management API.
+ * @{
+ */
+mtpdevice_t *LIBMTP_Get_First_Device(void);
+void LIBMTP_Release_Device(mtpdevice_t*);
+/** @} */
+
+/* End of C++ exports */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBMTP_H_INCLUSION_GUARD */
+
diff --git a/src/libptp-endian.h b/src/libptp-endian.h
new file mode 100644
index 0000000..90e4d82
--- /dev/null
+++ b/src/libptp-endian.h
@@ -0,0 +1,89 @@
+/* This file is generated automatically by configure */
+/* It is valid only for the system type i686-pc-linux-gnu */
+
+#ifndef __BYTEORDER_H
+#define __BYTEORDER_H
+
+/* ntohl and relatives live here */
+#include <arpa/inet.h>
+
+/* Define generic byte swapping functions */
+#include <byteswap.h>
+#define swap16(x) bswap_16(x)
+#define swap32(x) bswap_32(x)
+#define swap64(x) bswap_64(x)
+
+/* The byte swapping macros have the form: */
+/* EENN[a]toh or htoEENN[a] where EE is be (big endian) or */
+/* le (little-endian), NN is 16 or 32 (number of bits) and a, */
+/* if present, indicates that the endian side is a pointer to an */
+/* array of uint8_t bytes instead of an integer of the specified length. */
+/* h refers to the host's ordering method. */
+
+/* So, to convert a 32-bit integer stored in a buffer in little-endian */
+/* format into a uint32_t usable on this machine, you could use: */
+/* uint32_t value = le32atoh(&buf[3]); */
+/* To put that value back into the buffer, you could use: */
+/* htole32a(&buf[3], value); */
+
+/* Define aliases for the standard byte swapping macros */
+/* Arguments to these macros must be properly aligned on natural word */
+/* boundaries in order to work properly on all architectures */
+#define htobe16(x) htons(x)
+#define htobe32(x) htonl(x)
+#define be16toh(x) ntohs(x)
+#define be32toh(x) ntohl(x)
+
+#define HTOBE16(x) (x) = htobe16(x)
+#define HTOBE32(x) (x) = htobe32(x)
+#define BE32TOH(x) (x) = be32toh(x)
+#define BE16TOH(x) (x) = be16toh(x)
+
+/* On little endian machines, these macros are null */
+#define htole16(x) (x)
+#define htole32(x) (x)
+#define htole64(x) (x)
+#define le16toh(x) (x)
+#define le32toh(x) (x)
+#define le64toh(x) (x)
+
+#define HTOLE16(x) (void) (x)
+#define HTOLE32(x) (void) (x)
+#define HTOLE64(x) (void) (x)
+#define LE16TOH(x) (void) (x)
+#define LE32TOH(x) (void) (x)
+#define LE64TOH(x) (void) (x)
+
+/* These don't have standard aliases */
+#define htobe64(x) swap64(x)
+#define be64toh(x) swap64(x)
+
+#define HTOBE64(x) (x) = htobe64(x)
+#define BE64TOH(x) (x) = be64toh(x)
+
+/* Define the C99 standard length-specific integer types */
+#include "libptp-stdint.h"
+
+/* Here are some macros to create integers from a byte array */
+/* These are used to get and put integers from/into a uint8_t array */
+/* with a specific endianness. This is the most portable way to generate */
+/* and read messages to a network or serial device. Each member of a */
+/* packet structure must be handled separately. */
+
+/* The i386 and compatibles can handle unaligned memory access, */
+/* so use the optimized macros above to do this job */
+#define be16atoh(x) be16toh(*(uint16_t*)(x))
+#define be32atoh(x) be32toh(*(uint32_t*)(x))
+#define be64atoh(x) be64toh(*(uint64_t*)(x))
+#define le16atoh(x) le16toh(*(uint16_t*)(x))
+#define le32atoh(x) le32toh(*(uint32_t*)(x))
+#define le64atoh(x) le64toh(*(uint64_t*)(x))
+
+#define htobe16a(a,x) *(uint16_t*)(a) = htobe16(x)
+#define htobe32a(a,x) *(uint32_t*)(a) = htobe32(x)
+#define htobe64a(a,x) *(uint64_t*)(a) = htobe64(x)
+#define htole16a(a,x) *(uint16_t*)(a) = htole16(x)
+#define htole32a(a,x) *(uint32_t*)(a) = htole32(x)
+#define htole64a(a,x) *(uint64_t*)(a) = htole64(x)
+
+#endif /*__BYTEORDER_H*/
diff --git a/src/libptp-stdint.h b/src/libptp-stdint.h
new file mode 100644
index 0000000..80ecf41
--- /dev/null
+++ b/src/libptp-stdint.h
@@ -0,0 +1,2 @@
+/* This file is generated automatically by configure */
+#include <stdint.h>
diff --git a/src/mtp-pack.c b/src/mtp-pack.c
new file mode 100644
index 0000000..0472eb1
--- /dev/null
+++ b/src/mtp-pack.c
@@ -0,0 +1,75 @@
+/*
+ * mtp-pack.c
+ *
+ * Created by Richard Low on 26/12/2005.
+ *
+ * This adds some extra packing routines
+ *
+ */
+
+#include "mtp-pack.h"
+#include <stdlib.h>
+
+#define PTP_opd_PropertyCode 0
+#define PTP_opd_DataType sizeof(uint16_t)
+#define PTP_opd_GetSet PTP_opd_DataType+sizeof(uint16_t)
+#define PTP_opd_DefaultValue PTP_opd_GetSet+sizeof(uint8_t)
+
+/* this is completely untested */
+inline void
+ptp_unpack_OPD (PTPParams *params, char* data, PTPObjectPropDesc *opd)
+{
+ int totallen=0;
+ uint16_t i=0;
+
+ opd->PropertyCode=dtoh16a(&data[PTP_opd_PropertyCode]);
+ opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
+ opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
+ totallen = ptp_unpack_DPV(params, &data[PTP_opd_DefaultValue], &(opd->DefaultValue), opd->DataType);
+
+ /* if totallen==0 then Data Type format is not supported by this
+ code or the Data Type is a string (with two empty strings as
+ values). In both cases Form Flag should be set to 0x00 and FORM is
+ not present. */
+ opd->FormFlag=PTP_DPFF_None;
+ if (totallen==0) return;
+
+ opd->GroupCode=dtoh32a(&data[PTP_opd_DefaultValue+totallen]);
+ totallen+=sizeof(uint32_t);
+ opd->FormFlag=dtoh8a(&data[PTP_opd_DefaultValue+totallen]);
+ totallen+=sizeof(uint8_t);
+ switch (opd->FormFlag) {
+ case PTP_DPFF_Range:
+ totallen+=ptp_unpack_DPV(params, &data[PTP_opd_DefaultValue+totallen], &(opd->FORM.Range.MinimumValue), opd->DataType);
+ totallen+=ptp_unpack_DPV(params, &data[PTP_opd_DefaultValue+totallen], &(opd->FORM.Range.MaximumValue), opd->DataType);
+ totallen+=ptp_unpack_DPV(params, &data[PTP_opd_DefaultValue+totallen], &(opd->FORM.Range.StepSize), opd->DataType);
+ break;
+ case PTP_DPFF_Enumeration:
+#define N opd->FORM.Enum.NumberOfValues
+ N = dtoh16a(&data[PTP_opd_DefaultValue+totallen]);
+ totallen+=sizeof(uint16_t);
+ opd->FORM.Enum.SupportedValue = malloc(N*sizeof(void *));
+
+ for (i=0; i < N; i++)
+ {
+ totallen+=ptp_unpack_DPV(params, &data[PTP_opd_DefaultValue+totallen], &(opd->FORM.Enum.SupportedValue[i]), opd->DataType);
+ }
+
+ break;
+ case PTP_DPFF_DateTime:
+ /* no extra fields, so do nothing */
+ break;
+ case PTP_DPFF_FixedLengthArray:
+ opd->FORM.Array.Length=dtoh16a(&data[PTP_opd_DefaultValue+totallen]);
+ break;
+ case PTP_DPFF_RegularExpression:
+ ptp_unpack_DPV(params, &data[PTP_opd_DefaultValue+totallen], (void**)&(opd->FORM.RegularExpression.RegEx), PTP_DTC_UNISTR);
+ break;
+ case PTP_DPFF_ByteArray:
+ opd->FORM.ByteArray.MaxLength=dtoh16a(&data[PTP_opd_DefaultValue+totallen]);
+ break;
+ case PTP_DPFF_LongString:
+ opd->FORM.LongString.MaxLength=dtoh16a(&data[PTP_opd_DefaultValue+totallen]);
+ break;
+ }
+}
\ No newline at end of file
diff --git a/src/mtp-pack.h b/src/mtp-pack.h
new file mode 100644
index 0000000..20fa49f
--- /dev/null
+++ b/src/mtp-pack.h
@@ -0,0 +1,17 @@
+/*
+ * mtp-pack.h
+ *
+ * Created by Richard Low on 26/12/2005.
+ *
+ */
+
+#ifndef __MTPPACK_H__
+#define __MTPPACK_H__
+
+#include "ptp.h"
+#include "mtp.h"
+#include "ptp-pack.h"
+
+inline void ptp_unpack_OPD (PTPParams *params, char* data, PTPObjectPropDesc *opd);
+
+#endif /* __MTPPACK_H__ */
diff --git a/src/mtp-utils.c b/src/mtp-utils.c
new file mode 100644
index 0000000..fc1d8ef
--- /dev/null
+++ b/src/mtp-utils.c
@@ -0,0 +1,545 @@
+/*
+ * mtp-utils.c
+ *
+ * Created by Richard Low on 24/12/2005.
+ *
+ * This file adds some utils (many copied from ptpcam.c from libptp2) to
+ * use MTP devices. Include mtp-utils.h to use any of the ptp/mtp functions.
+ *
+ */
+#include "ptp.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <usb.h>
+
+#include "mtp-utils.h"
+#include "ptp-pack.h"
+
+/* OUR APPLICATION USB URB (2MB) ;) */
+#define PTPCAM_USB_URB 2097152
+
+/* this must not be too short - the original 4000 was not long
+ enough for big file transfers. I imagine the player spends a
+ bit of time gearing up to receiving lots of data. This also makes
+ connecting/disconnecting more reliable */
+#define USB_TIMEOUT 10000
+#define USB_CAPTURE_TIMEOUT 20000
+
+/* USB control message data phase direction */
+#ifndef USB_DP_HTD
+#define USB_DP_HTD (0x00 << 7) /* host to device */
+#endif
+#ifndef USB_DP_DTH
+#define USB_DP_DTH (0x01 << 7) /* device to host */
+#endif
+
+/* USB Feature selector HALT */
+#ifndef USB_FEATURE_HALT
+#define USB_FEATURE_HALT 0x00
+#endif
+
+int ptpcam_usb_timeout = USB_TIMEOUT;
+
+void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber);
+struct usb_device* find_device (int busn, int devicen, short force);
+void find_endpoints(struct usb_device *dev, int* inep, int* outep, int* intep);
+void clear_stall(PTP_USB* ptp_usb);
+void init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev);
+static short ptp_write_func (unsigned char *bytes, unsigned int size, void *data);
+static short ptp_read_func (unsigned char *bytes, unsigned int size, void *data);
+static short ptp_check_int (unsigned char *bytes, unsigned int size, void *data);
+int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep);
+int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status);
+
+static short ptp_read_func (unsigned char *bytes, unsigned int size, void *data)
+{
+ int result=-1;
+ PTP_USB *ptp_usb=(PTP_USB *)data;
+ int toread=0;
+ signed long int rbytes=size;
+
+ do {
+ bytes+=toread;
+ if (rbytes>PTPCAM_USB_URB)
+ toread = PTPCAM_USB_URB;
+ else
+ toread = rbytes;
+ result=USB_BULK_READ(ptp_usb->handle, ptp_usb->inep,(char *)bytes, toread,ptpcam_usb_timeout);
+ /* sometimes retry might help */
+ if (result==0)
+ result=USB_BULK_READ(ptp_usb->handle, ptp_usb->inep,(char *)bytes, toread,ptpcam_usb_timeout);
+ if (result < 0)
+ break;
+ rbytes-=PTPCAM_USB_URB;
+ } while (rbytes>0);
+
+ if (result >= 0) {
+ return (PTP_RC_OK);
+ }
+ else
+ {
+ return PTP_ERROR_IO;
+ }
+}
+
+static short ptp_write_func (unsigned char *bytes, unsigned int size, void *data)
+{
+ int result;
+ PTP_USB *ptp_usb=(PTP_USB *)data;
+
+
+ /* only print if size < something */
+ /*int i = 0;
+ if (size < 0xff)
+ {
+ printf("-------------------------\n");
+ printf("Sending data size %d\n", size);
+ for (i = 0; i < size; i += 8)
+ {
+ int j = i;
+ for (; j<size && j<i+8; j++)
+ printf("0x%02x ", bytes[j]);
+ printf("\n");
+ }
+ printf("-------------------------\n");
+ }
+ */
+
+ result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)bytes,size,ptpcam_usb_timeout);
+ if (result >= 0)
+ return (PTP_RC_OK);
+ else
+ {
+ return PTP_ERROR_IO;
+ }
+}
+
+static short ptp_check_int (unsigned char *bytes, unsigned int size, void *data)
+{
+ int result;
+ PTP_USB *ptp_usb=(PTP_USB *)data;
+
+ result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)bytes,size,ptpcam_usb_timeout);
+ if (result==0)
+ result = USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *) bytes, size, ptpcam_usb_timeout);
+ if (result >= 0) {
+ return (PTP_RC_OK);
+ } else {
+ return PTP_ERROR_IO;
+ }
+}
+
+void init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev)
+{
+ usb_dev_handle *device_handle;
+
+ params->write_func=ptp_write_func;
+ params->read_func=ptp_read_func;
+ params->check_int_func=ptp_check_int;
+ params->check_int_fast_func=ptp_check_int;
+ params->error_func=NULL;
+ params->debug_func=NULL;
+ params->sendreq_func=ptp_usb_sendreq;
+ params->senddata_func=ptp_usb_senddata;
+ params->getresp_func=ptp_usb_getresp;
+ params->getdata_func=ptp_usb_getdata;
+ params->data=ptp_usb;
+ params->transaction_id=0;
+ params->byteorder = PTP_DL_LE;
+
+ if ((device_handle=usb_open(dev))){
+ if (!device_handle) {
+ perror("usb_open()");
+ exit(0);
+ }
+ ptp_usb->handle=device_handle;
+ usb_claim_interface(device_handle,
+ dev->config->interface->altsetting->bInterfaceNumber);
+ }
+}
+
+void clear_stall(PTP_USB* ptp_usb)
+{
+ uint16_t status=0;
+ int ret;
+
+ /* check the inep status */
+ ret=usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status);
+ if (ret<0) perror ("inep: usb_get_endpoint_status()");
+ /* and clear the HALT condition if happend */
+ else if (status) {
+ printf("Resetting input pipe!\n");
+ ret=usb_clear_stall_feature(ptp_usb,ptp_usb->inep);
+ /*usb_clear_halt(ptp_usb->handle,ptp_usb->inep); */
+ if (ret<0)perror ("usb_clear_stall_feature()");
+ }
+ status=0;
+
+ /* check the outep status */
+ ret=usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status);
+ if (ret<0) perror ("outep: usb_get_endpoint_status()");
+ /* and clear the HALT condition if happend */
+ else if (status) {
+ printf("Resetting output pipe!\n");
+ ret=usb_clear_stall_feature(ptp_usb,ptp_usb->outep);
+ /*usb_clear_halt(ptp_usb->handle,ptp_usb->outep); */
+ if (ret<0)perror ("usb_clear_stall_feature()");
+ }
+
+ /*usb_clear_halt(ptp_usb->handle,ptp_usb->intep); */
+}
+
+void close_usb(PTP_USB* ptp_usb, uint8_t interfaceNumber)
+{
+ clear_stall(ptp_usb);
+ usb_release_interface(ptp_usb->handle, interfaceNumber);
+ usb_close(ptp_usb->handle);
+}
+
+
+struct usb_bus*
+init_usb()
+{
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ return (usb_get_busses());
+}
+
+/*
+ find_device() returns the pointer to a usb_device structure matching
+ given busn, devicen numbers. If any or both of arguments are 0 then the
+ first matching PTP device structure is returned.
+ */
+struct usb_device* find_device (int busn, int devn, short force)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ bus=init_usb();
+ for (; bus; bus = bus->next)
+ for (dev = bus->devices; dev; dev = dev->next)
+ /* somtimes dev->config is null, not sure why... */
+ if (dev->config != NULL)
+ if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB)
+ {
+ int curbusn, curdevn;
+
+ curbusn=strtol(bus->dirname,NULL,10);
+ curdevn=strtol(dev->filename,NULL,10);
+
+ if (devn==0) {
+ if (busn==0) return dev;
+ if (curbusn==busn) return dev;
+ } else {
+ if ((busn==0)&&(curdevn==devn)) return dev;
+ if ((curbusn==busn)&&(curdevn==devn)) return dev;
+ }
+ }
+ return NULL;
+}
+
+/* this is a temporary function to connect to the first device we can, that has vendor ID CREATIVE_VENDOR_ID */
+
+uint16_t connect_first_device(PTPParams *params, PTP_USB *ptp_usb, uint8_t *interfaceNumber)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ bus=init_usb();
+ for (; bus; bus = bus->next)
+ {
+ for (dev = bus->devices; dev; dev = dev->next)
+ {
+ if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB && dev->descriptor.idVendor==CREATIVE_VENDOR_ID)
+ {
+ uint16_t ret=0;
+ int n;
+ struct usb_endpoint_descriptor *ep;
+ PTPDeviceInfo deviceinfo;
+
+ ep = dev->config->interface->altsetting->endpoint;
+ n=dev->config->interface->altsetting->bNumEndpoints;
+
+ find_endpoints(dev,&(ptp_usb->inep),&(ptp_usb->outep),&(ptp_usb->intep));
+ init_ptp_usb(params, ptp_usb, dev);
+
+ ret = ptp_opensession(params,1);
+ if (ret != PTP_RC_OK)
+ {
+ printf("Could not open session!\n Try to reset the camera.\n");
+ usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
+ continue;
+ }
+
+ ret = ptp_getdeviceinfo(params, &deviceinfo);
+ if (ret != PTP_RC_OK)
+ {
+ printf("Could not get device info!\n");
+ usb_release_interface(ptp_usb->handle,dev->config->interface->altsetting->bInterfaceNumber);
+ return PTP_CD_RC_ERROR_CONNECTING;
+ }
+
+ /* we're connected, return ok */
+ *interfaceNumber = dev->config->interface->altsetting->bInterfaceNumber;
+
+ return PTP_CD_RC_CONNECTED;
+ }
+ }
+ }
+ /* none found */
+ return PTP_CD_RC_NO_DEVICES;
+}
+
+void find_endpoints(struct usb_device *dev, int* inep, int* outep, int* intep)
+{
+ int i,n;
+ struct usb_endpoint_descriptor *ep;
+
+ ep = dev->config->interface->altsetting->endpoint;
+ n=dev->config->interface->altsetting->bNumEndpoints;
+
+ for (i=0;i<n;i++) {
+ if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_BULK) {
+ if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
+ USB_ENDPOINT_DIR_MASK)
+ {
+ *inep=ep[i].bEndpointAddress;
+ }
+ if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0)
+ {
+ *outep=ep[i].bEndpointAddress;
+ }
+ } else if (ep[i].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT){
+ if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==
+ USB_ENDPOINT_DIR_MASK)
+ {
+ *intep=ep[i].bEndpointAddress;
+ }
+ }
+ }
+}
+
+
+int open_device (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev)
+{
+#ifdef DEBUG
+ printf("dev %i\tbus %i\n",devn,busn);
+#endif
+
+ *dev=find_device(busn,devn,force);
+ if (*dev==NULL) {
+ fprintf(stderr,"could not find any device matching given "
+ "bus/dev numbers\n");
+ exit(-1);
+ }
+ find_endpoints(*dev,&ptp_usb->inep,&ptp_usb->outep,&ptp_usb->intep);
+
+ init_ptp_usb(params, ptp_usb, *dev);
+ if (ptp_opensession(params,1)!=PTP_RC_OK) {
+ fprintf(stderr,"ERROR: Could not open session!\n");
+ close_usb(ptp_usb, (*dev)->config->interface->altsetting->bInterfaceNumber);
+ return -1;
+ }
+ return 0;
+}
+
+void close_device (PTP_USB *ptp_usb, PTPParams *params, uint8_t interfaceNumber)
+{
+ if (ptp_closesession(params)!=PTP_RC_OK)
+ fprintf(stderr,"ERROR: Could not close session!\n");
+ close_usb(ptp_usb, interfaceNumber);
+}
+
+int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep)
+{
+
+ return (usb_control_msg(ptp_usb->handle,
+ USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT,
+ ep, NULL, 0, 3000));
+}
+
+int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status)
+{
+ return (usb_control_msg(ptp_usb->handle,
+ USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS,
+ USB_FEATURE_HALT, ep, (char *)status, 2, 3000));
+}
+
+uint16_t send_file(PTPParams* params, const char* filename, const char* friendlyfilename, uint16_t objectFormat, Progress_Callback* callback, uint32_t* handle)
+{
+ int file;
+ uint16_t ret;
+ struct stat sb;
+ uint32_t store = 0;
+ uint32_t parenthandle = 0;
+ PTPUSBBulkContainerSend usbdata;
+ unsigned int remain;
+ int done = 0;
+ PTPContainer ptp;
+
+ PTPObjectInfo newInfo;
+ uint32_t filesize = 0;
+ unsigned char *data = NULL;
+
+ // check file exists
+ if (stat(filename, &sb) == -1)
+ {
+ printf("could not stat file\n");
+ return 0;
+ }
+ filesize = sb.st_size;
+
+ file=open(filename, O_RDONLY);
+
+ if (friendlyfilename != NULL)
+ newInfo.Filename = (char *)friendlyfilename;
+ else
+ newInfo.Filename = (char *)filename;
+ newInfo.ObjectFormat = objectFormat;
+ newInfo.ObjectCompressedSize = filesize;
+
+ ret = ptp_sendobjectinfo(params, &store, &parenthandle, handle, &newInfo);
+ if (ret != PTP_RC_OK)
+ {
+ ptp_perror(params, ret);
+ close(file);
+ printf("Could not send object info\n");
+ return ret;
+ }
+
+ memset(&ptp,0,sizeof(ptp));
+ ptp.Code=PTP_OC_SendObject;
+ ptp.Nparam=0;
+ ptp.Transaction_ID=params->transaction_id++;
+ ptp.SessionID=params->session_id;
+
+ ret = params->sendreq_func(params, &ptp);
+ if (ret != PTP_RC_OK)
+ {
+ ptp_perror(params, ret);
+ close(file);
+ printf("Could not send request\n");
+ return ret;
+ }
+
+ /* build appropriate USB container */
+ usbdata.length=htod32(sizeof(usbdata)+filesize);
+ usbdata.type=htod16(PTP_USB_CONTAINER_DATA);
+ usbdata.code=htod16(PTP_OC_SendObject);
+ usbdata.trans_id=htod32(ptp.Transaction_ID);
+
+ ret=params->write_func((unsigned char *)&usbdata, sizeof(usbdata), params->data);
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+ ptp_perror(params, ret);
+ return ret;
+ }
+
+ /* This space will be used as a reading ring buffer for the transfers */
+ data = (unsigned char *)malloc(BLOCK_SIZE);
+
+ remain = filesize;
+ while (done == 0)
+ {
+ int readsize = remain>BLOCK_SIZE?BLOCK_SIZE:remain;
+ int bytesdone = filesize-remain;
+
+ read(file, data, readsize);
+
+ if (callback != NULL)
+ {
+ if (bytesdone % CALLBACK_SIZE == 0)
+ callback(bytesdone, filesize);
+ }
+ ret=params->write_func(data, readsize, params->data);
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+ break;
+ }
+ if (remain <= BLOCK_SIZE)
+ done = 1;
+ else
+ {
+ remain -= BLOCK_SIZE;
+ }
+ }
+
+ if (done != 0 && callback != NULL)
+ callback(filesize, filesize);
+
+ /* write zero to end for some reason... but only sometimes!! */
+ if (done != 0 && filesize % MTP_DEVICE_BUF_SIZE == 0)
+ {
+ ret=params->write_func(data, 0, params->data);
+ }
+
+ /* get response */
+ if (ret!=PTP_ERROR_IO && params->getresp_func(params, &ptp) != PTP_RC_OK)
+ ret = PTP_ERROR_IO;
+
+ free(data);
+
+ close(file);
+ return ret;
+}
+
+int get_file(PTPParams* params, uint32_t handle, const char* filename, Progress_Callback* callback)
+{
+ int file;
+ PTPObjectInfo oi;
+ char *image;
+ int ret;
+ extern Progress_Callback* globalCallback;
+
+ if (ptp_getobjectinfo(params,handle, &oi) != PTP_RC_OK)
+ {
+ printf("Could not get object info\n");
+ return -1;
+ }
+ if (oi.ObjectFormat == PTP_OFC_Association)
+ return -1;
+
+ file=open(filename, O_EXCL|O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP);
+ if (file==-1) {
+ if (errno==EEXIST) {
+ printf("Skipping file: \"%s\", file exists!\n",filename);
+ return -1;
+ }
+ return -1;
+ }
+ lseek(file,oi.ObjectCompressedSize-1,SEEK_SET);
+ write(file,"",1);
+ if (file<0) return -1;
+ image=mmap(0,oi.ObjectCompressedSize,PROT_READ|PROT_WRITE,MAP_SHARED,file,0);
+ if (image==MAP_FAILED) {
+ close(file);
+ return -1;
+ }
+ fflush(NULL);
+
+ globalCallback=callback;
+ ret=ptp_getobject(params,handle,&image);
+ globalCallback=NULL;
+
+ munmap(image,oi.ObjectCompressedSize);
+ close(file);
+ /*timebuf.actime=oi.ModificationDate;
+ timebuf.modtime=oi.CaptureDate;
+ utime(filename,&timebuf);*/
+ if (ret!=PTP_RC_OK) {
+ printf ("error!\n");
+ }
+ // todo: error return code
+ return 0;
+
+}
diff --git a/src/mtp-utils.h b/src/mtp-utils.h
new file mode 100644
index 0000000..7089d61
--- /dev/null
+++ b/src/mtp-utils.h
@@ -0,0 +1,41 @@
+/*
+ * mtp-utils.h
+ * XNJB
+ *
+ * Created by Richard Low on 24/12/2005.
+ *
+ */
+
+#include "mtp.h"
+#include <usb.h>
+
+#define USB_BULK_READ usb_bulk_read
+#define USB_BULK_WRITE usb_bulk_write
+
+/* the vendor ID for creative devices that we can connect to (temporary) */
+
+#define CREATIVE_VENDOR_ID 0x041e
+
+/*
+ * structures
+ */
+
+typedef struct _PTP_USB PTP_USB;
+struct _PTP_USB {
+ usb_dev_handle* handle;
+ int inep;
+ int outep;
+ int intep;
+};
+
+uint16_t send_file(PTPParams* params, const char* filename, const char* friendlyfilename, uint16_t objectFormat, Progress_Callback* callback, uint32_t* handle);
+int get_file(PTPParams* params, uint32_t handle, const char* filename, Progress_Callback* callback);
+int open_device (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev);
+void close_device (PTP_USB *ptp_usb, PTPParams *params, uint8_t interfaceNumber);
+
+uint16_t connect_first_device(PTPParams *params, PTP_USB *ptp_usb, uint8_t *interfaceNumber);
+
+/* connect_first_device return codes */
+#define PTP_CD_RC_CONNECTED 0
+#define PTP_CD_RC_NO_DEVICES 1
+#define PTP_CD_RC_ERROR_CONNECTING 2
diff --git a/src/mtp.c b/src/mtp.c
new file mode 100644
index 0000000..32216bf
--- /dev/null
+++ b/src/mtp.c
@@ -0,0 +1,127 @@
+/*
+ * mtp.c
+ *
+ * Created by Richard Low on 26/12/2005.
+ *
+ * This adds the MTP commands as the spec v0.83
+ * MTP protocol is Copyright (C) Microsoft Corporation 2005
+ *
+ */
+
+#include "ptp.h"
+#include "mtp.h"
+#include "ptp-pack.h"
+#include "mtp-pack.h"
+#include <stdlib.h>
+#include <string.h>
+
+uint16_t
+ptp_getobjectpropvalue (PTPParams* params, uint16_t propcode, uint32_t handle,
+ void** value, uint16_t datatype)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ char* dpv=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetObjectPropValue;
+ ptp.Param1=handle;
+ ptp.Param2=propcode;
+ ptp.Nparam=2;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpv);
+ if (ret == PTP_RC_OK) ptp_unpack_DPV(params, dpv, value, datatype);
+ free(dpv);
+ return ret;
+}
+
+uint16_t
+ptp_setobjectpropvalue (PTPParams* params, uint16_t propcode, uint32_t handle,
+ void* value, uint16_t datatype)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ uint32_t size;
+ char* dpv=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_SetObjectPropValue;
+ ptp.Param1=handle;
+ ptp.Param2=propcode;
+ ptp.Nparam=2;
+ size=ptp_pack_DPV(params, value, &dpv, datatype);
+ ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &dpv);
+ free(dpv);
+ return ret;
+}
+
+uint16_t
+ptp_getobjectpropssupported (PTPParams* params, uint32_t objectformatcode, uint16_t** opcArray, uint32_t* arraylen)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ char* dpv=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetObjectPropsSupported;
+ ptp.Param1=objectformatcode;
+ ptp.Nparam=1;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpv);
+ if (ret == PTP_RC_OK) ptp_unpack_array(params, dpv, (void**)opcArray, PTP_DTC_AUINT16, arraylen);
+ free(dpv);
+ return ret;
+}
+
+/* this is completely untested */
+uint16_t
+ptp_getobjectpropdesc (PTPParams* params, uint16_t propcode, uint32_t objectformatcode,
+ PTPObjectPropDesc* objectpropertydesc)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ char* opd=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetObjectPropDesc;
+ ptp.Param1=propcode;
+ ptp.Param2=objectformatcode;
+ ptp.Nparam=2;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &opd);
+ if (ret == PTP_RC_OK) ptp_unpack_OPD(params, opd, objectpropertydesc);
+ free(opd);
+ return ret;
+}
+
+uint16_t
+ptp_getobjectreferences (PTPParams* params, uint32_t handle, uint32_t** ohArray, uint32_t* arraylen)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ char* dpv=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetObjectReferences;
+ ptp.Param1=handle;
+ ptp.Nparam=1;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpv);
+ if (ret == PTP_RC_OK) ptp_unpack_array(params, dpv, (void**)ohArray, PTP_DTC_AUINT32, arraylen);
+ free(dpv);
+ return ret;
+}
+
+uint16_t
+ptp_setobjectreferences (PTPParams* params, uint32_t handle, uint32_t* ohArray, uint32_t arraylen)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ uint32_t size;
+ char* dpv=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_SetObjectReferences;
+ ptp.Param1=handle;
+ ptp.Nparam=1;
+ size=ptp_pack_array(params, ohArray, &dpv, PTP_DTC_AUINT32, arraylen);
+ ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &dpv);
+ free(dpv);
+ return ret;
+}
diff --git a/src/mtp.h b/src/mtp.h
new file mode 100644
index 0000000..eec47f0
--- /dev/null
+++ b/src/mtp.h
@@ -0,0 +1,219 @@
+/*
+ * mtp.h
+ *
+ * Created by Richard Low on 26/12/2005.
+ *
+ */
+
+#ifndef __MTP_H__
+#define __MTP_H__
+
+#include "libptp2/src/ptp.h"
+
+/* MTP operation codes */
+
+#define PTP_OC_MTPUndefined 0x9800
+#define PTP_OC_GetObjectPropsSupported 0x9801
+#define PTP_OC_GetObjectPropDesc 0x9802
+#define PTP_OC_GetObjectPropValue 0x9803
+#define PTP_OC_SetObjectPropValue 0x9804
+#define PTP_OC_GetObjectReferences 0x9810
+#define PTP_OC_SetObjectReferences 0x9811
+
+/* MTP Object Format types */
+
+#define PTP_OFC_UndefinedFirmware 0xB802
+#define PTP_OFC_WindowsImageFormat 0xB881
+#define PTP_OFC_UndefinedAudio 0xB900
+#define PTP_OFC_WMA 0xB901
+#define PTP_OFC_OGG 0xB902
+#define PTP_OFC_UndefinedVideo 0xB980
+#define PTP_OFC_WMV 0xB981
+#define PTP_OFC_MP4 0xB982
+#define PTP_OFC_UndefinedCollection 0xBA00
+#define PTP_OFC_AbstractMultimediaAlbum 0xBA01
+#define PTP_OFC_AbstractImageAlbum 0xBA02
+#define PTP_OFC_AbstractAudioAlbum 0xBA03
+#define PTP_OFC_AbstractVideoAlbum 0xBA04
+#define PTP_OFC_AbstractAudioVideoPlaylist 0xBA05
+#define PTP_OFC_AbstractContactGroup 0xBA06
+#define PTP_OFC_AbstractMessageFolder 0xBA07
+#define PTP_OFC_AbstractChapteredProduction 0xBA08
+#define PTP_OFC_WPLPlaylist 0xBA10
+#define PTP_OFC_M3UPlaylist 0xBA11
+#define PTP_OFC_MPLPlaylist 0xBA12
+#define PTP_OFC_ASXPlaylist 0xBA13
+#define PTP_OFC_PLSPlaylist 0xBA14
+#define PTP_OFC_UndefinedDocument 0xBA80
+#define PTP_OFC_AbstractDocument 0xBA81
+#define PTP_OFC_UndefinedMessage 0xBB00
+#define PTP_OFC_AbstractMessage 0xBB01
+#define PTP_OFC_UndefinedContact 0xBB80
+#define PTP_OFC_AbstractContact 0xBB81
+#define PTP_OFC_vCard2 0xBB82
+#define PTP_OFC_vCard3 0xBB83
+#define PTP_OFC_UndefinedCalenderItem 0xBE00
+#define PTP_OFC_AbstractCalenderItem 0xBE01
+#define PTP_OFC_vCalendar1 0xBE02
+#define PTP_OFC_vCalendar2 0xBE03
+#define PTP_OFC_UndefinedWindowsExecutable 0xBE80
+
+/* Device Property Form Flag */
+
+#define PTP_DPFF_DateTime 0x03
+#define PTP_DPFF_FixedLengthArray 0x04
+#define PTP_DPFF_RegularExpression 0x05
+#define PTP_DPFF_ByteArray 0x06
+#define PTP_DPFF_LongString 0xFF
+
+/* MTP Event codes */
+
+#define PTP_EC_MTPUndefined 0xB800
+#define PTP_EC_ObjectPropChanged 0xB801
+#define PTP_EC_ObjectPropDescChanged 0xB802
+#define PTP_EC_ObjectReferencesChanged 0xB803
+#define PTP_EC_DevicePropDescChanged 0xB804
+
+/* MTP Responses */
+
+#define PTP_RC_MTPUndefined 0xA800
+#define PTP_RC_Invalid_ObjectPropCode 0xA801
+#define PTP_RC_Invalid_ObjectProp_Format 0xA802
+#define PTP_RC_Invalid_ObjectProp_Value 0xA803
+#define PTP_RC_Invalid_ObjectReference 0xA804
+#define PTP_RC_Invalid_Dataset 0xA806
+#define PTP_RC_Specification_By_Group_Unsupported 0xA808
+#define PTP_RC_Object_Too_Large 0xA809
+
+struct _PTPObjPropDescFixedLengthArrayForm {
+ uint16_t Length;
+};
+typedef struct _PTPObjPropDescFixedLengthArrayForm PTPObjPropDescFixedLengthArrayForm;
+
+struct _PTPObjPropDescRegularExpressionForm {
+ uint16_t* RegEx;
+};
+typedef struct _PTPObjPropDescRegularExpressionForm PTPObjPropDescRegularExpressionForm;
+
+struct _PTPObjPropDescByteArrayForm {
+ uint16_t MaxLength;
+};
+typedef struct _PTPObjPropDescByteArrayForm PTPObjPropDescByteArrayForm;
+
+struct _PTPObjPropDescLongStringForm {
+ uint16_t MaxLength;
+};
+typedef struct _PTPObjPropDescLongStringForm PTPObjPropDescLongStringForm;
+
+/* Object Property Describing Dataset (ObjectPropDesc) */
+
+struct _PTPObjectPropDesc {
+ uint16_t PropertyCode;
+ uint16_t DataType;
+ uint8_t GetSet;
+ void * DefaultValue;
+ uint32_t GroupCode;
+ uint8_t FormFlag;
+ union {
+ PTPObjPropDescEnumForm Enum;
+ PTPObjPropDescRangeForm Range;
+ PTPObjPropDescFixedLengthArrayForm Array;
+ PTPObjPropDescRegularExpressionForm RegularExpression;
+ PTPObjPropDescByteArrayForm ByteArray;
+ PTPObjPropDescLongStringForm LongString;
+ } FORM;
+};
+typedef struct _PTPObjectPropDesc PTPObjectPropDesc;
+
+/* MTP Device property codes */
+
+#define PTP_DPC_SynchronizationPartner 0xD401
+#define PTP_DPC_DeviceFriendlyName 0xD402
+
+/* MTP object property codes */
+
+#define PTP_OPC_StorageID 0xDC01
+#define PTP_OPC_ObjectFormat 0xDC02
+#define PTP_OPC_ProtectionStatus 0xDC03
+#define PTP_OPC_ObjectSize 0xDC04
+#define PTP_OPC_AssociationType 0xDC05
+#define PTP_OPC_AssociationDesc 0xDC06
+#define PTP_OPC_ObjectFileName 0xDC07
+#define PTP_OPC_DateCreated 0xDC08
+#define PTP_OPC_DateModified 0xDC09
+#define PTP_OPC_Keywords 0xDC0A
+#define PTP_OPC_ParentObject 0xDC0B
+#define PTP_OPC_PersistentUniqueObjectIdentifier 0xDC41
+#define PTP_OPC_SyncID 0xDC42
+#define PTP_OPC_PropertyBag 0xDC43
+#define PTP_OPC_Name 0xDC44
+#define PTP_OPC_CreatedBy 0xDC45
+#define PTP_OPC_Artist 0xDC46
+#define PTP_OPC_DateAuthored 0xDC47
+#define PTP_OPC_Description 0xDC48
+#define PTP_OPC_URLReference 0xDC49
+#define PTP_OPC_LanguageLocale 0xDC4A
+#define PTP_OPC_CopyrightInformation 0xDC4B
+#define PTP_OPC_Source 0xDC4C
+#define PTP_OPC_OriginLocation 0xDC4D
+#define PTP_OPC_DateAdded 0xDC4E
+#define PTP_OPC_NonConsumable 0xDC4F
+#define PTP_OPC_CorruptUnplayable 0xDC50
+#define PTP_OPC_RepresentativeSampleFormat 0xDC81
+#define PTP_OPC_RepresentativeSampleSize 0xDC82
+#define PTP_OPC_RepresentativeSampleHeight 0xDC83
+#define PTP_OPC_RepresentativeSampleWidth 0xDC84
+#define PTP_OPC_RepresentativeSampleDuration 0xDC85
+#define PTP_OPC_RepresentativeSampleData 0xDC86
+#define PTP_OPC_Width 0xDC87
+#define PTP_OPC_Height 0xDC88
+#define PTP_OPC_Duration 0xDC89
+#define PTP_OPC_Rating 0xDC8A
+#define PTP_OPC_Track 0xDC8B
+#define PTP_OPC_Genre 0xDC8C
+#define PTP_OPC_Credits
+#define PTP_OPC_Lyrics 0xDC8E
+#define PTP_OPC_SubscriptionContentID 0xDC8F
+#define PTP_OPC_ProducedBy 0xDC90
+#define PTP_OPC_UseCount 0xDC91
+#define PTP_OPC_SkipCount 0xDC92
+#define PTP_OPC_LastAccessed 0xDC93
+#define PTP_OPC_ParentalRating 0xDC94
+#define PTP_OPC_MetaGenre 0xDC95
+#define PTP_OPC_Composer 0xDC96
+#define PTP_OPC_EffectiveRating 0xDC97
+#define PTP_OPC_Subtitle 0xDC98
+#define PTP_OPC_OriginalReleaseDate 0xDC99
+#define PTP_OPC_AlbumName 0xDC9A
+#define PTP_OPC_AlbumArtist 0xDC9B
+#define PTP_OPC_Mood 0xDC9C
+#define PTP_OPC_DRMStatus 0xDC9D
+#define PTP_OPC_SubDescription 0xDC9E
+#define PTP_OPC_IsCropped 0xDCD1
+#define PTP_OPC_IsColourCorrected 0xDCD2
+#define PTP_OPC_TotalBitRate 0xDE91
+#define PTP_OPC_BitrateType 0xDE92
+#define PTP_OPC_SampleRate 0xDE93
+#define PTP_OPC_NumberOfChannels 0xDE94
+#define PTP_OPC_AudioBitDepth 0xDE95
+#define PTP_OPC_ScanType 0xDE97
+#define PTP_OPC_AudioWAVECodec 0xDE99
+#define PTP_OPC_AudioBitRate 0xDE9A
+#define PTP_OPC_VideoFourCCCodec 0xDE9B
+#define PTP_OPC_VideoBitRate 0xDE9C
+#define PTP_OPC_FramesPerThousandSeconds 0xDE9D
+#define PTP_OPC_KeyFrameDistance 0xDE9E
+#define PTP_OPC_BufferSize 0xDE9F
+#define PTP_OPC_EncodingQuality 0xDEA0
+
+uint16_t ptp_getobjectpropvalue (PTPParams* params, uint16_t propcode, uint32_t handle,
+ void** value, uint16_t datatype);
+uint16_t ptp_setobjectpropvalue (PTPParams* params, uint16_t propcode, uint32_t handle,
+ void* value, uint16_t datatype);
+
+uint16_t ptp_getobjectpropssupported (PTPParams* params, uint32_t ofc, uint16_t** opcArray, uint32_t* arraylen);
+
+uint16_t ptp_getobjectreferences (PTPParams* params, uint32_t handle, uint32_t** ohArray, uint32_t* arraylen);
+uint16_t ptp_setobjectreferences (PTPParams* params, uint32_t handle, uint32_t* ohArray, uint32_t arraylen);
+
+#endif /* __MTP_H__ */
diff --git a/src/ptp-pack.c b/src/ptp-pack.c
new file mode 100644
index 0000000..ce158a4
--- /dev/null
+++ b/src/ptp-pack.c
@@ -0,0 +1,926 @@
+/*
+ * ptp-pack.c
+ *
+ */
+
+#include "ptp.h"
+#include "ptp-pack.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+inline uint16_t
+htod16p (PTPParams *params, uint16_t var)
+{
+ return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
+}
+
+inline uint32_t
+htod32p (PTPParams *params, uint32_t var)
+{
+ return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
+}
+
+inline void
+htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
+{
+ if (params->byteorder==PTP_DL_LE)
+ htole16a(a,val); else
+ htobe16a(a,val);
+}
+
+inline void
+htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
+{
+ if (params->byteorder==PTP_DL_LE)
+ htole32a(a,val); else
+ htobe32a(a,val);
+}
+
+inline uint16_t
+dtoh16p (PTPParams *params, uint16_t var)
+{
+ return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
+}
+
+inline uint32_t
+dtoh32p (PTPParams *params, uint32_t var)
+{
+ return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
+}
+
+inline uint16_t
+dtoh16ap (PTPParams *params, unsigned char *a)
+{
+ return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
+}
+
+inline uint32_t
+dtoh32ap (PTPParams *params, unsigned char *a)
+{
+ return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
+}
+
+inline uint64_t
+dtoh64ap (PTPParams *params, unsigned char *a)
+{
+ return ((params->byteorder==PTP_DL_LE)?le64atoh(a):be64atoh(a));
+}
+
+inline char*
+ptp_unpack_string(PTPParams *params, char* data, uint16_t offset, uint8_t *len)
+{
+ int i;
+ char *string=NULL;
+
+ *len=dtoh8a(&data[offset]);
+ if (*len) {
+ string=malloc(*len);
+ memset(string, 0, *len);
+ for (i=0;i<*len && i< PTP_MAXSTRLEN; i++) {
+ string[i]=(char)dtoh16a(&data[offset+i*2+1]);
+ }
+ /* be paranoid! :( */
+ string[*len-1]=0;
+ }
+ return (string);
+}
+
+inline void
+ptp_pack_string(PTPParams *params, char *string, char* data, uint16_t offset, uint8_t *len)
+{
+ int i;
+ *len = (uint8_t)strlen(string);
+
+ /* XXX: check strlen! */
+ htod8a(&data[offset],*len+1);
+ for (i=0;i<*len && i< PTP_MAXSTRLEN; i++) {
+ htod16a(&data[offset+i*2+1],(uint16_t)string[i]);
+ }
+}
+
+inline uint32_t
+ptp_unpack_uint32_t_array(PTPParams *params, char* data, uint16_t offset, uint32_t **array)
+{
+ uint32_t n, i=0;
+
+ n=dtoh32a(&data[offset]);
+ *array = malloc (n*sizeof(uint32_t));
+ while (n>i) {
+ (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
+ i++;
+ }
+ return n;
+}
+
+inline uint32_t
+ptp_unpack_uint16_t_array(PTPParams *params, char* data, uint16_t offset, uint16_t **array)
+{
+ uint32_t n, i=0;
+
+ n=dtoh32a(&data[offset]);
+ *array = malloc (n*sizeof(uint16_t));
+ while (n>i) {
+ (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
+ i++;
+ }
+ return n;
+}
+
+/* DeviceInfo pack/unpack */
+
+#define PTP_di_StandardVersion 0
+#define PTP_di_VendorExtensionID 2
+#define PTP_di_VendorExtensionVersion 6
+#define PTP_di_VendorExtensionDesc 8
+#define PTP_di_FunctionalMode 8
+#define PTP_di_OperationsSupported 10
+
+inline void
+ptp_unpack_DI (PTPParams *params, char* data, PTPDeviceInfo *di)
+{
+ uint8_t len;
+ unsigned int totallen;
+
+ di->StaqndardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
+ di->VendorExtensionID =
+ dtoh32a(&data[PTP_di_VendorExtensionID]);
+ di->VendorExtensionVersion =
+ dtoh16a(&data[PTP_di_VendorExtensionVersion]);
+ di->VendorExtensionDesc =
+ ptp_unpack_string(params, data,
+ PTP_di_VendorExtensionDesc, &len);
+ totallen=len*2+1;
+ di->FunctionalMode =
+ dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
+ di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->OperationsSupported);
+ totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->EventsSupported);
+ totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->DevicePropertiesSupported_len =
+ ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->DevicePropertiesSupported);
+ totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->CaptureFormats);
+ totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->ImageFormats);
+ totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->Manufacturer = ptp_unpack_string(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &len);
+ totallen+=len*2+1;
+ di->Model = ptp_unpack_string(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &len);
+ totallen+=len*2+1;
+ di->DeviceVersion = ptp_unpack_string(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &len);
+ totallen+=len*2+1;
+ di->SerialNumber = ptp_unpack_string(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &len);
+}
+
+/* ObjectHandles array pack/unpack */
+
+#define PTP_oh 0
+
+inline void
+ptp_unpack_OH (PTPParams *params, char* data, PTPObjectHandles *oh)
+{
+ oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
+}
+
+/* StoreIDs array pack/unpack */
+
+#define PTP_sids 0
+
+inline void
+ptp_unpack_SIDs (PTPParams *params, char* data, PTPStorageIDs *sids)
+{
+ sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
+ &sids->Storage);
+}
+
+/* StorageInfo pack/unpack */
+
+#define PTP_si_StorageType 0
+#define PTP_si_FilesystemType 2
+#define PTP_si_AccessCapability 4
+#define PTP_si_MaxCapability 6
+#define PTP_si_FreeSpaceInBytes 14
+#define PTP_si_FreeSpaceInImages 22
+#define PTP_si_StorageDescription 26
+
+inline void
+ptp_unpack_SI (PTPParams *params, char* data, PTPStorageInfo *si)
+{
+ uint8_t storagedescriptionlen;
+
+ si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
+ si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
+ si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
+ /* next two added by RAL 2005-12-23 */
+ si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
+ si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
+ si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
+ si->StorageDescription=ptp_unpack_string(params, data,
+ PTP_si_StorageDescription, &storagedescriptionlen);
+ si->VolumeLabel=ptp_unpack_string(params, data,
+ PTP_si_StorageDescription+storagedescriptionlen*2+1,
+ &storagedescriptionlen);
+}
+
+/* ObjectInfo pack/unpack */
+
+#define PTP_oi_StorageID 0
+#define PTP_oi_ObjectFormat 4
+#define PTP_oi_ProtectionStatus 6
+#define PTP_oi_ObjectCompressedSize 8
+#define PTP_oi_ThumbFormat 12
+#define PTP_oi_ThumbCompressedSize 14
+#define PTP_oi_ThumbPixWidth 18
+#define PTP_oi_ThumbPixHeight 22
+#define PTP_oi_ImagePixWidth 26
+#define PTP_oi_ImagePixHeight 30
+#define PTP_oi_ImageBitDepth 34
+#define PTP_oi_ParentObject 38
+#define PTP_oi_AssociationType 42
+#define PTP_oi_AssociationDesc 44
+#define PTP_oi_SequenceNumber 48
+#define PTP_oi_filenamelen 52
+#define PTP_oi_Filename 53
+
+inline uint32_t
+ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, char** oidataptr)
+{
+ char* oidata;
+ uint8_t filenamelen;
+ uint8_t capturedatelen=0;
+ /* let's allocate some memory first; XXX i'm sure it's wrong */
+ oidata=malloc(PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4);
+ /* the caller should free it after use! */
+#if 0
+ char *capture_date="20020101T010101"; /* XXX Fake date */
+#endif
+ memset (oidata, 0, (PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4));
+ htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
+ htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
+ htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
+ htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
+ htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
+ htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
+ htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
+ htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
+ htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
+ htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
+ htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
+ htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
+ htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
+ htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
+ htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
+
+ ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
+/*
+ filenamelen=(uint8_t)strlen(oi->Filename);
+ htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
+ for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
+ req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
+ }
+*/
+ /*
+ *XXX Fake date.
+ * for example Kodak sets Capture date on the basis of EXIF data.
+ * Spec says that this field is from perspective of Initiator.
+ */
+#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
+ capturedatelen=strlen(capture_date);
+ htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
+ capturedatelen+1);
+ for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
+ data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
+ }
+ htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
+ capturedatelen+1);
+ for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
+ data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
+ capture_date[i];
+ }
+#endif
+ /* XXX this function should return dataset length */
+
+ *oidataptr=oidata;
+ return (PTP_oi_Filename+(filenamelen+1)*2+(capturedatelen+1)*4);
+}
+
+inline void
+ptp_unpack_OI (PTPParams *params, char* data, PTPObjectInfo *oi)
+{
+ uint8_t filenamelen;
+ uint8_t capturedatelen;
+ char *capture_date;
+ char tmp[16];
+ struct tm tm;
+
+ memset(&tm,0,sizeof(tm));
+
+ oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
+ oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
+ oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
+ oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
+ oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
+ oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
+ oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
+ oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
+ oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
+ oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
+ oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
+ oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
+ oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
+ oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
+ oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
+ oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
+
+ capture_date = ptp_unpack_string(params, data,
+ PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
+ /* subset of ISO 8601, without '.s' tenths of second and
+ * time zone
+ */
+ if (capturedatelen>15)
+ {
+ strncpy (tmp, capture_date, 4);
+ tmp[4] = 0;
+ tm.tm_year=atoi (tmp) - 1900;
+ strncpy (tmp, capture_date + 4, 2);
+ tmp[2] = 0;
+ tm.tm_mon = atoi (tmp) - 1;
+ strncpy (tmp, capture_date + 6, 2);
+ tmp[2] = 0;
+ tm.tm_mday = atoi (tmp);
+ strncpy (tmp, capture_date + 9, 2);
+ tmp[2] = 0;
+ tm.tm_hour = atoi (tmp);
+ strncpy (tmp, capture_date + 11, 2);
+ tmp[2] = 0;
+ tm.tm_min = atoi (tmp);
+ strncpy (tmp, capture_date + 13, 2);
+ tmp[2] = 0;
+ tm.tm_sec = atoi (tmp);
+ oi->CaptureDate=mktime (&tm);
+ }
+ free(capture_date);
+
+ /* now it's modification date ;) */
+ capture_date = ptp_unpack_string(params, data,
+ PTP_oi_filenamelen+filenamelen*2
+ +capturedatelen*2+2,&capturedatelen);
+ if (capturedatelen>15)
+ {
+ strncpy (tmp, capture_date, 4);
+ tmp[4] = 0;
+ tm.tm_year=atoi (tmp) - 1900;
+ strncpy (tmp, capture_date + 4, 2);
+ tmp[2] = 0;
+ tm.tm_mon = atoi (tmp) - 1;
+ strncpy (tmp, capture_date + 6, 2);
+ tmp[2] = 0;
+ tm.tm_mday = atoi (tmp);
+ strncpy (tmp, capture_date + 9, 2);
+ tmp[2] = 0;
+ tm.tm_hour = atoi (tmp);
+ strncpy (tmp, capture_date + 11, 2);
+ tmp[2] = 0;
+ tm.tm_min = atoi (tmp);
+ strncpy (tmp, capture_date + 13, 2);
+ tmp[2] = 0;
+ tm.tm_sec = atoi (tmp);
+ oi->ModificationDate=mktime (&tm);
+ }
+ free(capture_date);
+}
+
+/* Custom Type Value Assignement (without Length) macro frequently used below */
+#define CTVAL(type,func,target) { \
+ *target = malloc(sizeof(type)); \
+ **(type **)target = \
+ func(data);\
+}
+
+/* modified by RAL 2005-12-26 to return value size */
+uint32_t
+ptp_unpack_DPV (PTPParams *params, char* data, void** value, uint16_t datatype)
+{
+ int i=0;
+
+ switch (datatype) {
+ case PTP_DTC_INT8:
+ CTVAL(int8_t,dtoh8a,value);
+ return sizeof(int8_t);
+ break;
+ case PTP_DTC_UINT8:
+ CTVAL(uint8_t,dtoh8a,value);
+ return sizeof(uint8_t);
+ break;
+ case PTP_DTC_INT16:
+ CTVAL(int16_t,dtoh16a,value);
+ return sizeof(int16_t);
+ break;
+ case PTP_DTC_UINT16:
+ CTVAL(uint16_t,dtoh16a,value);
+ return sizeof(uint16_t);
+ break;
+ case PTP_DTC_INT32:
+ CTVAL(int32_t,dtoh32a,value);
+ return sizeof(int32_t);
+ break;
+ case PTP_DTC_UINT32:
+ CTVAL(uint32_t,dtoh32a,value);
+ return sizeof(uint32_t);
+ break;
+ case PTP_DTC_UINT64:
+ CTVAL(uint64_t,dtoh64a,value);
+ return sizeof(uint64_t);
+ break;
+ /* XXX: other int types are unimplemented */
+ /* XXX: int arrays are unimplemented also */
+ case PTP_DTC_STR:
+ {
+ uint8_t len;
+ (char *)(*value)=ptp_unpack_string(params,data,0,&len);
+ return 2*len+1;
+ break;
+ }
+ case PTP_DTC_UNISTR:
+ {
+ /* this length includes the null character */
+ uint8_t len=dtoh8a(&data[0]);
+ if (len==0)
+ {
+ *value=malloc(2);
+ ((uint16_t *)*value)[0]=0;
+ }
+ else
+ {
+ *value=malloc(len*2);
+ for (i=0;i<len;i++)
+ {
+ ((uint16_t *)*value)[i]=dtoh16a(&data[i*2+1]);
+ }
+ /* just to be sure... */
+ ((uint16_t *)*value)[len-1]=0;
+ }
+
+ return 2*len+1;
+
+ break;
+ }
+ default:
+ printf("data type 0x%.04x not supported by ptp_unpack_DPV\n", datatype);
+ return 0;
+ }
+}
+
+
+/* Device Property pack/unpack */
+
+#define PTP_dpd_DevicePropertyCode 0
+#define PTP_dpd_DataType 2
+#define PTP_dpd_GetSet 4
+#define PTP_dpd_FactoryDefaultValue 5
+
+/* Custom Type Value Assignement macro frequently used below */
+#define CTVA(type,func,target) { \
+ target = malloc(sizeof(type)); \
+ *(type *)target = \
+ func(&data[PTP_dpd_FactoryDefaultValue+totallen]);\
+ totallen+=sizeof(type); \
+}
+
+/* Many Custom Types Vale Assignement macro frequently used below */
+
+#define MCTVA(type,func,target,n) { \
+ uint16_t i; \
+ for (i=0;i<n;i++) { \
+ target[i] = malloc(sizeof(type)); \
+ *(type *)target[i] = \
+ func(&data[PTP_dpd_FactoryDefaultValue+totallen]);\
+ totallen+=sizeof(type); \
+ } \
+}
+
+inline void
+ptp_unpack_DPD (PTPParams *params, char* data, PTPDevicePropDesc *dpd)
+{
+ uint8_t len;
+ int totallen=0;
+
+ dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
+ dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
+ dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
+ dpd->FactoryDefaultValue = NULL;
+ dpd->CurrentValue = NULL;
+ switch (dpd->DataType) {
+ case PTP_DTC_INT8:
+ CTVA(int8_t,dtoh8a,dpd->FactoryDefaultValue);
+ CTVA(int8_t,dtoh8a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_UINT8:
+ CTVA(uint8_t,dtoh8a,dpd->FactoryDefaultValue);
+ CTVA(uint8_t,dtoh8a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_INT16:
+ CTVA(int16_t,dtoh16a,dpd->FactoryDefaultValue);
+ CTVA(int16_t,dtoh16a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_UINT16:
+ CTVA(uint16_t,dtoh16a,dpd->FactoryDefaultValue);
+ CTVA(uint16_t,dtoh16a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_INT32:
+ CTVA(int32_t,dtoh32a,dpd->FactoryDefaultValue);
+ CTVA(int32_t,dtoh32a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_UINT32:
+ CTVA(uint32_t,dtoh32a,dpd->FactoryDefaultValue);
+ CTVA(uint32_t,dtoh32a,dpd->CurrentValue);
+ break;
+ /* XXX: other int types are unimplemented */
+ /* XXX: int arrays are unimplemented also */
+ case PTP_DTC_STR:
+ (char *)dpd->FactoryDefaultValue = ptp_unpack_string
+ (params,data,PTP_dpd_FactoryDefaultValue,&len);
+ totallen=len*2+1;
+ (char *)dpd->CurrentValue = ptp_unpack_string
+ (params, data, PTP_dpd_FactoryDefaultValue +
+ totallen, &len);
+ totallen+=len*2+1;
+ break;
+ }
+ /* if totallen==0 then Data Type format is not supported by this
+ code or the Data Type is a string (with two empty strings as
+ values). In both cases Form Flag should be set to 0x00 and FORM is
+ not present. */
+ dpd->FormFlag=PTP_DPFF_None;
+ if (totallen==0) return;
+
+ dpd->FormFlag=dtoh8a(&data[PTP_dpd_FactoryDefaultValue+totallen]);
+ totallen+=sizeof(uint8_t);
+ switch (dpd->FormFlag) {
+ case PTP_DPFF_Range:
+ switch (dpd->DataType) {
+ case PTP_DTC_INT8:
+ CTVA(int8_t,dtoh8a,dpd->FORM.Range.MinimumValue);
+ CTVA(int8_t,dtoh8a,dpd->FORM.Range.MaximumValue);
+ CTVA(int8_t,dtoh8a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_UINT8:
+ CTVA(uint8_t,dtoh8a,dpd->FORM.Range.MinimumValue);
+ CTVA(uint8_t,dtoh8a,dpd->FORM.Range.MaximumValue);
+ CTVA(uint8_t,dtoh8a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_INT16:
+ CTVA(int16_t,dtoh16a,dpd->FORM.Range.MinimumValue);
+ CTVA(int16_t,dtoh16a,dpd->FORM.Range.MaximumValue);
+ CTVA(int16_t,dtoh16a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_UINT16:
+ CTVA(uint16_t,dtoh16a,dpd->FORM.Range.MinimumValue);
+ CTVA(uint16_t,dtoh16a,dpd->FORM.Range.MaximumValue);
+ CTVA(uint16_t,dtoh16a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_INT32:
+ CTVA(int32_t,dtoh32a,dpd->FORM.Range.MinimumValue);
+ CTVA(int32_t,dtoh32a,dpd->FORM.Range.MaximumValue);
+ CTVA(int32_t,dtoh32a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_UINT32:
+ CTVA(uint32_t,dtoh32a,dpd->FORM.Range.MinimumValue);
+ CTVA(uint32_t,dtoh32a,dpd->FORM.Range.MaximumValue);
+ CTVA(uint32_t,dtoh32a,dpd->FORM.Range.StepSize);
+ break;
+ /* XXX: other int types are unimplemented */
+ /* XXX: int arrays are unimplemented also */
+ /* XXX: does it make any sense: "a range of strings"? */
+ }
+ break;
+ case PTP_DPFF_Enumeration:
+#define N dpd->FORM.Enum.NumberOfValues
+ N = dtoh16a(&data[PTP_dpd_FactoryDefaultValue+totallen]);
+ totallen+=sizeof(uint16_t);
+ dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(void *));
+ switch (dpd->DataType) {
+ case PTP_DTC_INT8:
+ MCTVA(int8_t,dtoh8a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_UINT8:
+ MCTVA(uint8_t,dtoh8a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_INT16:
+ MCTVA(int16_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_UINT16:
+ MCTVA(uint16_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_INT32:
+ MCTVA(int32_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_UINT32:
+ MCTVA(uint32_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_STR:
+ {
+ int i;
+ for(i=0;i<N;i++)
+ {
+ (char *)dpd->FORM.Enum.SupportedValue[i]=
+ ptp_unpack_string
+ (params,data,PTP_dpd_FactoryDefaultValue
+ +totallen,&len);
+ totallen+=len*2+1;
+ }
+ }
+ break;
+ }
+ }
+}
+
+#define PACK_ARRAY(type,func) { \
+ size=sizeof(uint32_t)+sizeof(type)*arraylen; \
+ dpv=malloc(size); \
+ htod32a(dpv,arraylen); \
+ for (i=0; i<arraylen; i++) \
+ func(&(dpv[sizeof(uint32_t)+i*sizeof(type)]),((type*)value)[i]); \
+ }
+
+inline uint32_t
+ptp_pack_array (PTPParams *params, void* value, char** dpvptr, uint16_t datatype, uint32_t arraylen)
+{
+ char* dpv=NULL;
+ uint32_t size=0;
+ int i=0;
+
+ switch (datatype) {
+ case PTP_DTC_AINT8:
+ PACK_ARRAY(int8_t,htod8a);
+ break;
+ case PTP_DTC_AUINT8:
+ PACK_ARRAY(uint8_t,htod8a);
+ break;
+ case PTP_DTC_AINT16:
+ PACK_ARRAY(int16_t,htod16a);
+ break;
+ case PTP_DTC_AUINT16:
+ PACK_ARRAY(uint16_t,htod16a);
+ break;
+ case PTP_DTC_AINT32:
+ PACK_ARRAY(int32_t,htod32a);
+ break;
+ case PTP_DTC_AUINT32:
+ PACK_ARRAY(uint32_t,htod32a);
+ break;
+ /*case PTP_DTC_AINT64:
+ PACK_ARRAY(int64_t,htod64a);
+ break;
+ case PTP_DTC_AUINT64:
+ PACK_ARRAY(uint64_t,htod64a);
+ break;
+ case PTP_DTC_AINT128:
+ PACK_ARRAY(int128_t,htod128a);
+ break;
+ case PTP_DTC_AUINT128:
+ PACK_ARRAY(uint128_t,htod128a);
+ break;*/
+ default:
+ printf("data type 0x%.04x not supported by ptp_pack_array\n", datatype);
+ return 0;
+ }
+ *dpvptr=dpv;
+ return size;
+}
+
+#define UNPACK_ARRAY(type,func) { \
+ int i=0; \
+ *arraylen=dtoh32a(&data[0]); \
+ *value=malloc(sizeof(type)*(*arraylen)); \
+ for (i=0; i<*arraylen; i++) \
+ ((type*)(*value))[i]=func(&data[sizeof(uint32_t)+i*sizeof(type)]); \
+ return *arraylen*sizeof(type); \
+ }
+
+inline uint32_t
+ptp_unpack_array (PTPParams *params, char* data, void** value, uint16_t datatype, uint32_t* arraylen)
+{
+ switch (datatype) {
+ case PTP_DTC_AINT8:
+ UNPACK_ARRAY(int8_t,dtoh8a);
+ break;
+ case PTP_DTC_AUINT8:
+ UNPACK_ARRAY(uint8_t,dtoh8a);
+ break;
+ case PTP_DTC_AINT16:
+ UNPACK_ARRAY(int16_t,dtoh16a);
+ break;
+ case PTP_DTC_AUINT16:
+ UNPACK_ARRAY(uint16_t,dtoh16a);
+ break;
+ case PTP_DTC_AINT32:
+ UNPACK_ARRAY(int32_t,dtoh32a);
+ break;
+ case PTP_DTC_AUINT32:
+ UNPACK_ARRAY(uint32_t,dtoh32a);
+ break;
+ case PTP_DTC_AINT64:
+ UNPACK_ARRAY(int64_t,dtoh64a);
+ break;
+ case PTP_DTC_AUINT64:
+ UNPACK_ARRAY(uint64_t,dtoh64a);
+ break;
+ /*case PTP_DTC_AINT128:
+ UNPACK_ARRAY(int128_t,dtoh128a);
+ break;
+ case PTP_DTC_AUINT128:
+ UNPACK_ARRAY(uint128_t,dtoh128a);
+ break;*/
+ default:
+ printf("data type 0x%.04x not supported by ptp_unpack_array\n", datatype);
+ return 0;
+ }
+}
+
+inline uint32_t
+ptp_pack_DPV (PTPParams *params, void* value, char** dpvptr, uint16_t datatype)
+{
+ char* dpv=NULL;
+ uint32_t size=0;
+ int i=0;
+
+ switch (datatype) {
+ case PTP_DTC_INT8:
+ size=sizeof(int8_t);
+ dpv=malloc(size);
+ htod8a(dpv,*(int8_t*)value);
+ break;
+ case PTP_DTC_UINT8:
+ size=sizeof(uint8_t);
+ dpv=malloc(size);
+ htod8a(dpv,*(uint8_t*)value);
+ break;
+ case PTP_DTC_INT16:
+ size=sizeof(int16_t);
+ dpv=malloc(size);
+ htod16a(dpv,*(int16_t*)value);
+ break;
+ case PTP_DTC_UINT16:
+ size=sizeof(uint16_t);
+ dpv=malloc(size);
+ htod16a(dpv,*(uint16_t*)value);
+ break;
+ case PTP_DTC_INT32:
+ size=sizeof(int32_t);
+ dpv=malloc(size);
+ htod32a(dpv,*(int32_t*)value);
+ break;
+ case PTP_DTC_UINT32:
+ size=sizeof(uint32_t);
+ dpv=malloc(size);
+ htod32a(dpv,*(uint32_t*)value);
+ break;
+ /*case PTP_DTC_INT64:
+ size=sizeof(int64_t);
+ dpv=malloc(size);
+ htod64a(dpv,*(int64_t*)value);
+ break;
+ case PTP_DTC_UINT64:
+ size=sizeof(uint64_t);
+ dpv=malloc(size);
+ htod64a(dpv,*(uint64_t*)value);
+ break;
+ case PTP_DTC_INT128:
+ size=sizeof(int128_t);
+ dpv=malloc(size);
+ htod128a(dpv,*(int128_t*)value);
+ break;
+ case PTP_DTC_UINT128:
+ size=sizeof(uint128_t);
+ dpv=malloc(size);
+ htod128a(dpv,*(uint128_t*)value);
+ break;*/
+ case PTP_DTC_STR:
+ {
+ uint8_t len;
+ size=strlen((char*)value)*2+3;
+ dpv=malloc(size);
+ memset(dpv,0,size);
+ ptp_pack_string(params, (char *)value, dpv, 0, &len);
+ }
+ break;
+ case PTP_DTC_UNISTR:
+ {
+ uint8_t len = 0;
+ /* note PTP_MAXSTRLEN includes the null terminator */
+ while (((uint16_t *)value)[len] != 0 && len != PTP_MAXSTRLEN-1)
+ len++;
+ if (len==0)
+ {
+ size=1;
+ dpv=malloc(size);
+ *dpv=0;
+ }
+ else
+ {
+ /* 2 extra bytes for the terminator, 1 for the length at the beginning */
+ size=len*2+3;
+ dpv=malloc(size);
+ memset(dpv,0,size);
+ htod8a(&dpv[0],len+1);
+ for (i = 0; i < len; i++)
+ htod16a(&dpv[i*2+1],((uint16_t *)value)[i]);
+ /* terminator is done by memset above */
+ /*for (i = 0; i < size; i++)
+ printf("dpv[%d] = %d, ", i, dpv[i]);
+ printf("\n");*/
+ }
+ break;
+ }
+ default:
+ printf("data type 0x%.04x not supported by ptp_pack_DPV\n", datatype);
+ return 0;
+ }
+ *dpvptr=dpv;
+ return size;
+}
+
+
+/*
+ PTP USB Event container unpack
+ Copyright (c) 2003 Nikolai Kopanygin
+*/
+
+#define PTP_ec_Length 0
+#define PTP_ec_Type 4
+#define PTP_ec_Code 6
+#define PTP_ec_TransId 8
+#define PTP_ec_Param1 12
+#define PTP_ec_Param2 16
+#define PTP_ec_Param3 20
+
+inline void
+ptp_unpack_EC (PTPParams *params, char* data, PTPUSBEventContainer *ec)
+{
+ if (data==NULL)
+ return;
+ ec->length=dtoh32a(&data[PTP_ec_Length]);
+ ec->type=dtoh16a(&data[PTP_ec_Type]);
+ ec->code=dtoh16a(&data[PTP_ec_Code]);
+ ec->trans_id=dtoh32a(&data[PTP_ec_TransId]);
+ if (ec->length>=(PTP_ec_Param1+4))
+ ec->param1=dtoh32a(&data[PTP_ec_Param1]);
+ else
+ ec->param1=0;
+ if (ec->length>=(PTP_ec_Param2+4))
+ ec->param2=dtoh32a(&data[PTP_ec_Param2]);
+ else
+ ec->param2=0;
+ if (ec->length>=(PTP_ec_Param3+4))
+ ec->param3=dtoh32a(&data[PTP_ec_Param3]);
+ else
+ ec->param3=0;
+}
+
+/*
+ PTP Canon Folder Entry unpack
+ Copyright (c) 2003 Nikolai Kopanygin
+*/
+#define PTP_cfe_ObjectHandle 0
+#define PTP_cfe_ObjectFormatCode 4
+#define PTP_cfe_Flags 6
+#define PTP_cfe_ObjectSize 7
+#define PTP_cfe_Time 11
+#define PTP_cfe_Filename 15
+
+inline void
+ptp_unpack_Canon_FE (PTPParams *params, char* data, PTPCANONFolderEntry *fe)
+{
+ int i;
+ if (data==NULL)
+ return;
+ fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
+ fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
+ fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
+ fe->ObjectSize=dtoh32a(&data[PTP_cfe_ObjectSize]);
+ fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
+ for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
+ fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
+}
+
+
diff --git a/src/ptp-pack.h b/src/ptp-pack.h
new file mode 100644
index 0000000..d7a62ee
--- /dev/null
+++ b/src/ptp-pack.h
@@ -0,0 +1,53 @@
+/*
+ * ptp-pack.h
+ *
+ * Created by Richard Low on 26/12/2005.
+ *
+ */
+
+#ifndef __PTPPACK_H__
+#define __PTPPACK_H__
+
+#define htod8a(a,x) *(uint8_t*)(a) = x
+#define htod16a(a,x) htod16ap(params,a,x)
+#define htod32a(a,x) htod32ap(params,a,x)
+#define htod16(x) htod16p(params,x)
+#define htod32(x) htod32p(params,x)
+
+#define dtoh8a(x) (*(uint8_t*)(x))
+#define dtoh16a(a) dtoh16ap(params,a)
+#define dtoh32a(a) dtoh32ap(params,a)
+#define dtoh64a(a) dtoh64ap(params,a)
+#define dtoh16(x) dtoh16p(params,x)
+#define dtoh32(x) dtoh32p(params,x)
+
+#include "ptp.h"
+
+inline uint16_t htod16p (PTPParams *params, uint16_t var);
+inline uint32_t htod32p (PTPParams *params, uint32_t var);
+inline void htod16ap (PTPParams *params, unsigned char *a, uint16_t val);
+inline void htod32ap (PTPParams *params, unsigned char *a, uint32_t val);
+inline uint16_t dtoh16p (PTPParams *params, uint16_t var);
+inline uint32_t dtoh32p (PTPParams *params, uint32_t var);
+inline uint16_t dtoh16ap (PTPParams *params, unsigned char *a);
+inline uint32_t dtoh32ap (PTPParams *params, unsigned char *a);
+inline uint64_t dtoh64ap (PTPParams *params, unsigned char *a);
+inline char* ptp_unpack_string(PTPParams *params, char* data, uint16_t offset, uint8_t *len);
+inline void ptp_pack_string(PTPParams *params, char *string, char* data, uint16_t offset, uint8_t *len);
+inline uint32_t ptp_unpack_uint32_t_array(PTPParams *params, char* data, uint16_t offset, uint32_t **array);
+inline uint32_t ptp_unpack_uint16_t_array(PTPParams *params, char* data, uint16_t offset, uint16_t **array);
+inline void ptp_unpack_DI (PTPParams *params, char* data, PTPDeviceInfo *di);
+inline void ptp_unpack_OH (PTPParams *params, char* data, PTPObjectHandles *oh);
+inline void ptp_unpack_SIDs (PTPParams *params, char* data, PTPStorageIDs *sids);
+inline void ptp_unpack_SI (PTPParams *params, char* data, PTPStorageInfo *si);
+inline uint32_t ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, char** oidataptr);
+inline void ptp_unpack_OI (PTPParams *params, char* data, PTPObjectInfo *oi);
+inline uint32_t ptp_unpack_DPV (PTPParams *params, char* data, void** value, uint16_t datatype);
+inline void ptp_unpack_DPD (PTPParams *params, char* data, PTPDevicePropDesc *dpd);
+inline uint32_t ptp_pack_DPV (PTPParams *params, void* value, char** dpvptr, uint16_t datatype);
+inline void ptp_unpack_EC (PTPParams *params, char* data, PTPUSBEventContainer *ec);
+inline void ptp_unpack_Canon_FE (PTPParams *params, char* data, PTPCANONFolderEntry *fe);
+
+inline uint32_t ptp_unpack_array (PTPParams *params, char* data, void** value, uint16_t datatype, uint32_t* arraylen);
+inline uint32_t ptp_pack_array (PTPParams *params, void* value, char** dpvptr, uint16_t datatype, uint32_t arraylen);
+#endif /* __PTPPACK_H__ */
diff --git a/src/ptp.c b/src/ptp.c
new file mode 100644
index 0000000..b1e00d6
--- /dev/null
+++ b/src/ptp.c
@@ -0,0 +1,1873 @@
+/* ptp.c
+ *
+ * Copyright (C) 2001-2005 Mariusz Woloszyn <emsi@ipartners.pl>
+ *
+ * This file is part of libptp2.
+ *
+ * libptp2 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libptp2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libptp2; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include "ptp.h"
+#include "ptp-pack.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# undef _
+# define _(String) dgettext (PACKAGE, String)
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+# define textdomain(String) (String)
+# define gettext(String) (String)
+# define dgettext(Domain,Message) (Message)
+# define dcgettext(Domain,Message,Type) (Message)
+# define bindtextdomain(Domain,Directory) (Domain)
+# define _(String) (String)
+# define N_(String) (String)
+#endif
+
+/* global callback function */
+Progress_Callback* globalCallback;
+
+static void
+ptp_debug (PTPParams *params, const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ if (params->debug_func!=NULL)
+ params->debug_func (params->data, format, args);
+ else
+ {
+ vfprintf (stderr, format, args);
+ fprintf (stderr,"\n");
+ fflush (stderr);
+ }
+ va_end (args);
+}
+
+static void
+ptp_error (PTPParams *params, const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ if (params->error_func!=NULL)
+ params->error_func (params->data, format, args);
+ else
+ {
+ vfprintf (stderr, format, args);
+ fprintf (stderr,"\n");
+ fflush (stderr);
+ }
+ va_end (args);
+}
+
+/* send / receive functions */
+
+uint16_t
+ptp_usb_sendreq (PTPParams* params, PTPContainer* req)
+{
+ uint16_t ret;
+ PTPUSBBulkContainer usbreq;
+
+ /* build appropriate USB container */
+ usbreq.length=htod32(PTP_USB_BULK_REQ_LEN-
+ (sizeof(uint32_t)*(5-req->Nparam)));
+ usbreq.type=htod16(PTP_USB_CONTAINER_COMMAND);
+ usbreq.code=htod16(req->Code);
+ usbreq.trans_id=htod32(req->Transaction_ID);
+ usbreq.payload.params.param1=htod32(req->Param1);
+ usbreq.payload.params.param2=htod32(req->Param2);
+ usbreq.payload.params.param3=htod32(req->Param3);
+ usbreq.payload.params.param4=htod32(req->Param4);
+ usbreq.payload.params.param5=htod32(req->Param5);
+ /* send it to responder */
+ ret=params->write_func((unsigned char *)&usbreq,
+ PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam)),
+ params->data);
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+/* ptp_error (params,
+ "PTP: request code 0x%04x sending req error 0x%04x",
+ req->Code,ret); */
+ }
+ return ret;
+}
+
+/*
+ Modified for MTP support by RAL 2005-12-21
+
+ This is much changed from the original libptp ptp_usb_senddata.
+
+ Observations from sniffing WMP10 and some testing:
+
+ Data is sent in blocks of 0xe000 (BLOCK_SIZE). If the filesize
+ is 0 mod 0x200 (MTP_DEVICE_BUF_SIZE), we must make a USB write of
+ zero bytes. I assume this is because the buffer size on the device
+ is 0x200 bytes and end of transfer is signalled by getting an unfull
+ buffer or a transfer of zero bytes. Not obvious why this is required,
+ but it does work.
+ */
+
+uint16_t
+ptp_usb_senddata (PTPParams* params, PTPContainer* ptp,
+ unsigned char *data, unsigned int size)
+{
+ uint16_t ret;
+ PTPUSBBulkContainerSend usbdata;
+ unsigned int remain = size;
+ int done = 0;
+
+ /* build appropriate USB container */
+ usbdata.length=htod32(sizeof(usbdata)+size);
+ usbdata.type=htod16(PTP_USB_CONTAINER_DATA);
+ usbdata.code=htod16(ptp->Code);
+ usbdata.trans_id=htod32(ptp->Transaction_ID);
+
+ /* only print if size < something */
+ /*
+ if (size < BLOCK_SIZE)
+ {
+ printf("-------------------------\n");
+ printf("Sending usbdata size %d\n", sizeof(usbdata));
+ for (i = 0; i < sizeof(usbdata); i += 8)
+ {
+ int j = i;
+ for (; j<sizeof(usbdata) && j<i+8; j++)
+ printf("0x%02x ", ((unsigned char *)&usbdata)[j]);
+ printf("\n");
+ }
+ printf("Sending data size %d\n", size);
+ for (i = 0; i < size; i += 8)
+ {
+ int j = i;
+ for (; j<size && j<i+8; j++)
+ printf("0x%02x ", data[j]);
+ printf("\n");
+ }
+ printf("-------------------------\n");
+ }
+ */
+ ret=params->write_func((unsigned char *)&usbdata, sizeof(usbdata), params->data);
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+ return ret;
+ }
+
+ extern Progress_Callback* globalCallback;
+
+ while (done == 0)
+ {
+ int bytesdone = size-remain;
+ int bytestosend = remain>BLOCK_SIZE?BLOCK_SIZE:remain;
+ if (globalCallback != NULL)
+ {
+ if (bytesdone % CALLBACK_SIZE == 0)
+ globalCallback(bytesdone, size);
+ }
+ ret=params->write_func(data, bytestosend, params->data);
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+ return ret;
+ }
+ if (remain <= BLOCK_SIZE)
+ done = 1;
+ else
+ {
+ remain -= bytestosend;
+ data+=bytestosend;
+ }
+ }
+
+ if (done != 0 && globalCallback != NULL)
+ globalCallback(size, size);
+
+ /* write zero to end for some reason... but only sometimes!! */
+ if (done != 0 && size % MTP_DEVICE_BUF_SIZE == 0)
+ {
+ ret=params->write_func(data, 0, params->data);
+ }
+
+ if (ret!=PTP_RC_OK)
+ ret = PTP_ERROR_IO;
+ return ret;
+}
+
+/*
+ Modified for MTP support by RAL 2005-12-21
+
+ This is changed from the original libptp ptp_usb_getdata.
+
+ It appears as though the MTP devices don't use the usb payload-
+ which is set to all zeroes. So just ignore the zeroes and start
+ after the payload.
+ */
+
+uint16_t
+ptp_usb_getdata (PTPParams* params, PTPContainer* ptp,
+ unsigned char **data)
+{
+ uint16_t ret;
+ PTPUSBBulkContainer usbdata;
+ uint32_t read = 0;
+ uint32_t bytesToRead = CALLBACK_SIZE;
+ extern Progress_Callback* globalCallback;
+
+ PTP_CNT_INIT(usbdata);
+#if 0
+ if (*data!=NULL) return PTP_ERROR_BADPARAM;
+#endif
+ uint32_t len;
+ /* read first(?) part of data */
+ ret=params->read_func((unsigned char *)&usbdata,
+ sizeof(usbdata), params->data);
+
+/* {
+ int i = 0;
+
+ printf("-------------------------\n");
+ printf("got data size %d\n", sizeof(usbdata));
+ for (i = 0; i < sizeof(usbdata); i += 8)
+ {
+ int j = i;
+ for (; j<sizeof(usbdata) && j<i+8; j++)
+ printf("0x%02x ", ((unsigned char *)&usbdata)[j]);
+ printf("\n");
+ }
+ printf("-------------------------\n");
+ }
+*/
+
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+ } else
+ if (dtoh16(usbdata.type)!=PTP_USB_CONTAINER_DATA) {
+ ret = PTP_ERROR_DATA_EXPECTED;
+ } else
+ if (dtoh16(usbdata.code)!=ptp->Code) {
+ ret = dtoh16(usbdata.code);
+ } else {
+ /* evaluate data length */
+ len=dtoh32(usbdata.length)-PTP_USB_BULK_HDR_LEN;
+ /* test by RAL: some data coming back has this length - how do we deal with it? */
+ if (dtoh32(usbdata.length) == 0xffffffff)
+ len = 0x1fffff;
+ /* allocate memory for data if not allocated already */
+ if (*data==NULL) *data=calloc(len,1);
+
+ if (globalCallback == NULL)
+ ret=params->read_func(((unsigned char *)(*data)), len, params->data);
+ else
+ {
+ while (read < len)
+ {
+ bytesToRead=(len-read > CALLBACK_SIZE)?CALLBACK_SIZE:len-read;
+ ret=params->read_func(&(((unsigned char *)(*data))[read]), bytesToRead, params->data);
+ if (ret!=PTP_RC_OK)
+ break;
+ read+=bytesToRead;
+ globalCallback(read, len);
+ }
+ }
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+ }
+ }
+ return ret;
+}
+
+uint16_t
+ptp_usb_getresp (PTPParams* params, PTPContainer* resp)
+{
+ uint16_t ret;
+ PTPUSBBulkContainer usbresp;
+
+ PTP_CNT_INIT(usbresp);
+ /* read response, it should never be longer than sizeof(usbresp) */
+ ret=params->read_func((unsigned char *)&usbresp,
+ sizeof(usbresp), params->data);
+
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+ } else
+ if (dtoh16(usbresp.type)!=PTP_USB_CONTAINER_RESPONSE) {
+ ret = PTP_ERROR_RESP_EXPECTED;
+ } else
+ if (dtoh16(usbresp.code)!=resp->Code) {
+ ret = dtoh16(usbresp.code);
+ }
+ if (ret!=PTP_RC_OK) {
+/* ptp_error (params,
+ "PTP: request code 0x%04x getting resp error 0x%04x",
+ resp->Code, ret);*/
+ return ret;
+ }
+ /* build an appropriate PTPContainer */
+ resp->Code=dtoh16(usbresp.code);
+ resp->SessionID=params->session_id;
+ resp->Transaction_ID=dtoh32(usbresp.trans_id);
+ resp->Param1=dtoh32(usbresp.payload.params.param1);
+ resp->Param2=dtoh32(usbresp.payload.params.param2);
+ resp->Param3=dtoh32(usbresp.payload.params.param3);
+ resp->Param4=dtoh32(usbresp.payload.params.param4);
+ resp->Param5=dtoh32(usbresp.payload.params.param5);
+
+ return ret;
+}
+
+/* major PTP functions */
+
+/**
+ * ptp_transaction:
+ * params: PTPParams*
+ * PTPContainer* ptp - general ptp container
+ * uint16_t flags - lower 8 bits - data phase description
+ * unsigned int sendlen - senddata phase data length
+ * char** data - send or receive data buffer pointer
+ *
+ * Performs PTP transaction. ptp is a PTPContainer with appropriate fields
+ * filled in (i.e. operation code and parameters). It's up to caller to do
+ * so.
+ * The flags decide thether the transaction has a data phase and what is its
+ * direction (send or receive).
+ * If transaction is sending data the sendlen should contain its length in
+ * bytes, otherwise it's ignored.
+ * The data should contain an address of a pointer to data going to be sent
+ * or is filled with such a pointer address if data are received depending
+ * od dataphase direction (send or received) or is beeing ignored (no
+ * dataphase).
+ * The memory for a pointer should be preserved by the caller, if data are
+ * beeing retreived the appropriate amount of memory is beeing allocated
+ * (the caller should handle that!).
+ *
+ * Return values: Some PTP_RC_* code.
+ * Upon success PTPContainer* ptp contains PTP Response Phase container with
+ * all fields filled in.
+ **/
+uint16_t
+ptp_transaction (PTPParams* params, PTPContainer* ptp,
+ uint16_t flags, unsigned int sendlen, char** data)
+{
+ if ((params==NULL) || (ptp==NULL))
+ return PTP_ERROR_BADPARAM;
+
+ ptp->Transaction_ID=params->transaction_id++;
+ ptp->SessionID=params->session_id;
+ /* send request */
+ CHECK_PTP_RC(params->sendreq_func (params, ptp));
+ /* is there a dataphase? */
+ switch (flags&PTP_DP_DATA_MASK) {
+ case PTP_DP_SENDDATA:
+ CHECK_PTP_RC(params->senddata_func(params, ptp,
+ *data, sendlen));
+ break;
+ case PTP_DP_GETDATA:
+ CHECK_PTP_RC(params->getdata_func(params, ptp,
+ (unsigned char**)data));
+ break;
+ case PTP_DP_NODATA:
+ break;
+ default:
+ return PTP_ERROR_BADPARAM;
+ }
+ /* get response */
+ CHECK_PTP_RC(params->getresp_func(params, ptp));
+ return PTP_RC_OK;
+}
+
+/* Enets handling functions */
+
+/* PTP Events wait for or check mode */
+#define PTP_EVENT_CHECK 0x0000 /* waits for */
+#define PTP_EVENT_CHECK_FAST 0x0001 /* checks */
+
+static inline uint16_t
+ptp_usb_event (PTPParams* params, PTPContainer* event, int wait)
+{
+ uint16_t ret;
+ PTPUSBEventContainer usbevent;
+ PTP_CNT_INIT(usbevent);
+
+ if ((params==NULL) || (event==NULL))
+ return PTP_ERROR_BADPARAM;
+
+ switch(wait) {
+ case PTP_EVENT_CHECK:
+ ret=params->check_int_func((unsigned char*)&usbevent,
+ sizeof(usbevent), params->data);
+ break;
+ case PTP_EVENT_CHECK_FAST:
+ ret=params->check_int_fast_func((unsigned char*)
+ &usbevent, sizeof(usbevent), params->data);
+ break;
+ default:
+ ret=PTP_ERROR_BADPARAM;
+ }
+ if (ret!=PTP_RC_OK) {
+ ret = PTP_ERROR_IO;
+ ptp_error (params,
+ "PTP: reading event an error 0x%04x occured", ret);
+ /* reading event error is nonfatal (for example timeout) */
+ return ret;
+ }
+ /* if we read anything over interrupt endpoint it must be an event */
+ /* build an appropriate PTPContainer */
+ event->Code=dtoh16(usbevent.code);
+ event->SessionID=params->session_id;
+ event->Transaction_ID=dtoh32(usbevent.trans_id);
+ event->Param1=dtoh32(usbevent.param1);
+ event->Param2=dtoh32(usbevent.param2);
+ event->Param3=dtoh32(usbevent.param3);
+
+ return PTP_RC_OK;
+}
+
+uint16_t
+ptp_usb_event_check (PTPParams* params, PTPContainer* event) {
+
+ return ptp_usb_event (params, event, PTP_EVENT_CHECK_FAST);
+}
+
+uint16_t
+ptp_usb_event_wait (PTPParams* params, PTPContainer* event) {
+
+ return ptp_usb_event (params, event, PTP_EVENT_CHECK);
+}
+
+/**
+ * PTP operation functions
+ *
+ * all ptp_ functions should take integer parameters
+ * in host byte order!
+ **/
+
+
+/**
+ * ptp_getdeviceinfo:
+ * params: PTPParams*
+ *
+ * Gets device info dataset and fills deviceinfo structure.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_getdeviceinfo (PTPParams* params, PTPDeviceInfo* deviceinfo)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char* di=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetDeviceInfo;
+ ptp.Nparam=0;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &di);
+ if (ret == PTP_RC_OK) ptp_unpack_DI(params, di, deviceinfo);
+ free(di);
+ return ret;
+}
+
+
+/**
+ * ptp_opensession:
+ * params: PTPParams*
+ * session - session number
+ *
+ * Establishes a new session.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_opensession (PTPParams* params, uint32_t session)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+
+ ptp_debug(params,"PTP: Opening session");
+
+ /* SessonID field of the operation dataset should always
+ be set to 0 for OpenSession request! */
+ params->session_id=0x00000000;
+ /* TransactionID should be set to 0 also! */
+ params->transaction_id=0x0000000;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_OpenSession;
+ ptp.Param1=session;
+ ptp.Nparam=1;
+ ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+ /* now set the global session id to current session number */
+ params->session_id=session;
+ return ret;
+}
+
+/**
+ * ptp_closesession:
+ * params: PTPParams*
+ *
+ * Closes session.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_closesession (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ ptp_debug(params,"PTP: Closing session");
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CloseSession;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_getststorageids:
+ * params: PTPParams*
+ *
+ * Gets array of StorageiDs and fills the storageids structure.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_getstorageids (PTPParams* params, PTPStorageIDs* storageids)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char* sids=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetStorageIDs;
+ ptp.Nparam=0;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &sids);
+ if (ret == PTP_RC_OK) ptp_unpack_SIDs(params, sids, storageids);
+ free(sids);
+ return ret;
+}
+
+/**
+ * ptp_getststorageinfo:
+ * params: PTPParams*
+ * storageid - StorageID
+ *
+ * Gets StorageInfo dataset of desired storage and fills storageinfo
+ * structure.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_getstorageinfo (PTPParams* params, uint32_t storageid,
+ PTPStorageInfo* storageinfo)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char* si=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetStorageInfo;
+ ptp.Param1=storageid;
+ ptp.Nparam=1;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &si);
+ if (ret == PTP_RC_OK) ptp_unpack_SI(params, si, storageinfo);
+ free(si);
+ return ret;
+}
+
+/**
+ * ptp_getobjecthandles:
+ * params: PTPParams*
+ * storage - StorageID
+ * objectformatcode - ObjectFormatCode (optional)
+ * associationOH - ObjectHandle of Association for
+ * wich a list of children is desired
+ * (optional)
+ * objecthandles - pointer to structute
+ *
+ * Fills objecthandles with structure returned by device.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_getobjecthandles (PTPParams* params, uint32_t storage,
+ uint32_t objectformatcode, uint32_t associationOH,
+ PTPObjectHandles* objecthandles)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char* oh=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetObjectHandles;
+ ptp.Param1=storage;
+ ptp.Param2=objectformatcode;
+ ptp.Param3=associationOH;
+ ptp.Nparam=3;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &oh);
+ if (ret == PTP_RC_OK) ptp_unpack_OH(params, oh, objecthandles);
+ free(oh);
+ return ret;
+}
+
+uint16_t
+ptp_getobjectinfo (PTPParams* params, uint32_t handle,
+ PTPObjectInfo* objectinfo)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char* oi=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetObjectInfo;
+ ptp.Param1=handle;
+ ptp.Nparam=1;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &oi);
+ if (ret == PTP_RC_OK) ptp_unpack_OI(params, oi, objectinfo);
+ free(oi);
+ return ret;
+}
+
+uint16_t
+ptp_getobject (PTPParams* params, uint32_t handle, char** object)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetObject;
+ ptp.Param1=handle;
+ ptp.Nparam=1;
+ return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object);
+}
+
+uint16_t
+ptp_getthumb (PTPParams* params, uint32_t handle, char** object)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetThumb;
+ ptp.Param1=handle;
+ ptp.Nparam=1;
+ return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object);
+}
+
+/**
+ * ptp_deleteobject:
+ * params: PTPParams*
+ * handle - object handle
+ * ofc - object format code (optional)
+ *
+ * Deletes desired objects.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_deleteobject (PTPParams* params, uint32_t handle,
+ uint32_t ofc)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_DeleteObject;
+ ptp.Param1=handle;
+ ptp.Param2=ofc;
+ ptp.Nparam=2;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_sendobjectinfo:
+ * params: PTPParams*
+ * uint32_t* store - destination StorageID on Responder
+ * uint32_t* parenthandle - Parent ObjectHandle on responder
+ * uint32_t* handle - see Return values
+ * PTPObjectInfo* objectinfo- ObjectInfo that is to be sent
+ *
+ * Sends ObjectInfo of file that is to be sent via SendFileObject.
+ *
+ * Return values: Some PTP_RC_* code.
+ * Upon success : uint32_t* store - Responder StorageID in which
+ * object will be stored
+ * uint32_t* parenthandle- Responder Parent ObjectHandle
+ * in which the object will be stored
+ * uint32_t* handle - Responder's reserved ObjectHandle
+ * for the incoming object
+ **/
+uint16_t
+ptp_sendobjectinfo (PTPParams* params, uint32_t* store,
+ uint32_t* parenthandle, uint32_t* handle,
+ PTPObjectInfo* objectinfo)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char* oidata=NULL;
+ uint32_t size;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_SendObjectInfo;
+ ptp.Param1=*store;
+ ptp.Param2=*parenthandle;
+ ptp.Nparam=2;
+
+ size=ptp_pack_OI(params, objectinfo, &oidata);
+ ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &oidata);
+ free(oidata);
+ *store=ptp.Param1;
+ *parenthandle=ptp.Param2;
+ *handle=ptp.Param3;
+ return ret;
+}
+
+/**
+ * ptp_sendobject:
+ * params: PTPParams*
+ * char* object - contains the object that is to be sent
+ * uint32_t size - object size
+ *
+ * Sends object to Responder.
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ */
+uint16_t
+ptp_sendobject (PTPParams* params, char* object, uint32_t size)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_SendObject;
+ ptp.Nparam=0;
+
+ return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &object);
+}
+
+
+/**
+ * ptp_initiatecapture:
+ * params: PTPParams*
+ * storageid - destination StorageID on Responder
+ * ofc - object format code
+ *
+ * Causes device to initiate the capture of one or more new data objects
+ * according to its current device properties, storing the data into store
+ * indicated by storageid. If storageid is 0x00000000, the object(s) will
+ * be stored in a store that is determined by the capturing device.
+ * The capturing of new data objects is an asynchronous operation.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+
+uint16_t
+ptp_initiatecapture (PTPParams* params, uint32_t storageid,
+ uint32_t ofc)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_InitiateCapture;
+ ptp.Param1=storageid;
+ ptp.Param2=ofc;
+ ptp.Nparam=2;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+uint16_t
+ptp_getdevicepropdesc (PTPParams* params, uint16_t propcode,
+ PTPDevicePropDesc* devicepropertydesc)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ char* dpd=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetDevicePropDesc;
+ ptp.Param1=propcode;
+ ptp.Nparam=1;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpd);
+ if (ret == PTP_RC_OK) ptp_unpack_DPD(params, dpd, devicepropertydesc);
+ free(dpd);
+ return ret;
+}
+
+uint16_t
+ptp_getdevicepropvalue (PTPParams* params, uint16_t propcode,
+ void** value, uint16_t datatype)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ char* dpv=NULL;
+
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_GetDevicePropValue;
+ ptp.Param1=propcode;
+ ptp.Nparam=1;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpv);
+ if (ret == PTP_RC_OK) ptp_unpack_DPV(params, dpv, value, datatype);
+ free(dpv);
+ return ret;
+}
+
+uint16_t
+ptp_setdevicepropvalue (PTPParams* params, uint16_t propcode,
+ void* value, uint16_t datatype)
+{
+ PTPContainer ptp;
+ uint16_t ret;
+ uint32_t size;
+ char* dpv=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_SetDevicePropValue;
+ ptp.Param1=propcode;
+ ptp.Nparam=1;
+ size=ptp_pack_DPV(params, value, &dpv, datatype);
+ ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &dpv);
+ free(dpv);
+ return ret;
+}
+
+/**
+ * ptp_ek_sendfileobjectinfo:
+ * params: PTPParams*
+ * uint32_t* store - destination StorageID on Responder
+ * uint32_t* parenthandle - Parent ObjectHandle on responder
+ * uint32_t* handle - see Return values
+ * PTPObjectInfo* objectinfo- ObjectInfo that is to be sent
+ *
+ * Sends ObjectInfo of file that is to be sent via SendFileObject.
+ *
+ * Return values: Some PTP_RC_* code.
+ * Upon success : uint32_t* store - Responder StorageID in which
+ * object will be stored
+ * uint32_t* parenthandle- Responder Parent ObjectHandle
+ * in which the object will be stored
+ * uint32_t* handle - Responder's reserved ObjectHandle
+ * for the incoming object
+ **/
+uint16_t
+ptp_ek_sendfileobjectinfo (PTPParams* params, uint32_t* store,
+ uint32_t* parenthandle, uint32_t* handle,
+ PTPObjectInfo* objectinfo)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char* oidata=NULL;
+ uint32_t size;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_EK_SendFileObjectInfo;
+ ptp.Param1=*store;
+ ptp.Param2=*parenthandle;
+ ptp.Nparam=2;
+
+ size=ptp_pack_OI(params, objectinfo, &oidata);
+ ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &oidata);
+ free(oidata);
+ *store=ptp.Param1;
+ *parenthandle=ptp.Param2;
+ *handle=ptp.Param3;
+ return ret;
+}
+
+/**
+ * ptp_ek_sendfileobject:
+ * params: PTPParams*
+ * char* object - contains the object that is to be sent
+ * uint32_t size - object size
+ *
+ * Sends object to Responder.
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ */
+uint16_t
+ptp_ek_sendfileobject (PTPParams* params, char* object, uint32_t size)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_EK_SendFileObject;
+ ptp.Nparam=0;
+
+ return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &object);
+}
+
+/*************************************************************************
+ *
+ * Canon PTP extensions support
+ *
+ * (C) Nikolai Kopanygin 2003
+ *
+ *************************************************************************/
+
+
+/**
+ * ptp_canon_getobjectsize:
+ * params: PTPParams*
+ * uint32_t handle - ObjectHandle
+ * uint32_t p2 - Yet unknown parameter,
+ * value 0 works.
+ *
+ * Gets form the responder the size of the specified object.
+ *
+ * Return values: Some PTP_RC_* code.
+ * Upon success : uint32_t* size - The object size
+ * uint32_t rp2 - Yet unknown parameter
+ *
+ **/
+uint16_t
+ptp_canon_getobjectsize (PTPParams* params, uint32_t handle, uint32_t p2,
+ uint32_t* size, uint32_t* rp2)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_GetObjectSize;
+ ptp.Param1=handle;
+ ptp.Param2=p2;
+ ptp.Nparam=2;
+ ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+ *size=ptp.Param1;
+ *rp2=ptp.Param2;
+ return ret;
+}
+
+/**
+ * ptp_canon_startshootingmode:
+ * params: PTPParams*
+ *
+ * Starts shooting session. It emits a StorageInfoChanged
+ * event via the interrupt pipe and pushes the StorageInfoChanged
+ * and CANON_CameraModeChange events onto the event stack
+ * (see operation PTP_OC_CANON_CheckEvent).
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_startshootingmode (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_StartShootingMode;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_canon_endshootingmode:
+ * params: PTPParams*
+ *
+ * This operation is observed after pressing the Disconnect
+ * button on the Remote Capture app. It emits a StorageInfoChanged
+ * event via the interrupt pipe and pushes the StorageInfoChanged
+ * and CANON_CameraModeChange events onto the event stack
+ * (see operation PTP_OC_CANON_CheckEvent).
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_endshootingmode (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_EndShootingMode;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_canon_viewfinderon:
+ * params: PTPParams*
+ *
+ * Prior to start reading viewfinder images, one must call this operation.
+ * Supposedly, this operation affects the value of the CANON_ViewfinderMode
+ * property.
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_viewfinderon (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_ViewfinderOn;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_canon_viewfinderoff:
+ * params: PTPParams*
+ *
+ * Before changing the shooting mode, or when one doesn't need to read
+ * viewfinder images any more, one must call this operation.
+ * Supposedly, this operation affects the value of the CANON_ViewfinderMode
+ * property.
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_viewfinderoff (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_ViewfinderOff;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_canon_reflectchanges:
+ * params: PTPParams*
+ * uint32_t p1 - Yet unknown parameter,
+ * value 7 works
+ *
+ * Make viewfinder reflect changes.
+ * There is a button for this operation in the Remote Capture app.
+ * What it does exactly I don't know. This operation is followed
+ * by the CANON_GetChanges(?) operation in the log.
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_reflectchanges (PTPParams* params, uint32_t p1)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_ReflectChanges;
+ ptp.Param1=p1;
+ ptp.Nparam=1;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+
+/**
+ * ptp_canon_checkevent:
+ * params: PTPParams*
+ *
+ * The camera has a FIFO stack, in which it accumulates events.
+ * Partially these events are communicated also via the USB interrupt pipe
+ * according to the PTP USB specification, partially not.
+ * This operation returns from the device a block of data, empty,
+ * if the event stack is empty, or filled with an event's data otherwise.
+ * The event is removed from the stack in the latter case.
+ * The Remote Capture app sends this command to the camera all the time
+ * of connection, filling with it the gaps between other operations.
+ *
+ * Return values: Some PTP_RC_* code.
+ * Upon success : PTPUSBEventContainer* event - is filled with the event data
+ * if any
+ * int *isevent - returns 1 in case of event
+ * or 0 otherwise
+ **/
+uint16_t
+ptp_canon_checkevent (PTPParams* params, PTPUSBEventContainer* event, int* isevent)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char *evdata = NULL;
+
+ *isevent=0;
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_CheckEvent;
+ ptp.Nparam=0;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &evdata);
+ if (evdata!=NULL) {
+ if (ret == PTP_RC_OK) {
+ ptp_unpack_EC(params, evdata, event);
+ *isevent=1;
+ }
+ free(evdata);
+ }
+ return ret;
+}
+
+
+/**
+ * ptp_canon_focuslock:
+ *
+ * This operation locks the focus. It is followed by the CANON_GetChanges(?)
+ * operation in the log.
+ * It affects the CANON_MacroMode property.
+ *
+ * params: PTPParams*
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_focuslock (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_FocusLock;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_canon_focusunlock:
+ *
+ * This operation unlocks the focus. It is followed by the CANON_GetChanges(?)
+ * operation in the log.
+ * It sets the CANON_MacroMode property value to 1 (where it occurs in the log).
+ *
+ * params: PTPParams*
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_focusunlock (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_FocusUnlock;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_canon_initiatecaptureinmemory:
+ *
+ * This operation starts the image capture according to the current camera
+ * settings. When the capture has happened, the camera emits a CaptureComplete
+ * event via the interrupt pipe and pushes the CANON_RequestObjectTransfer,
+ * CANON_DeviceInfoChanged and CaptureComplete events onto the event stack
+ * (see operation CANON_CheckEvent). From the CANON_RequestObjectTransfer
+ * event's parameter one can learn the just captured image's ObjectHandle.
+ * The image is stored in the camera's own RAM.
+ * On the next capture the image will be overwritten!
+ *
+ * params: PTPParams*
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_initiatecaptureinmemory (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_InitiateCaptureInMemory;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL);
+}
+
+/**
+ * ptp_canon_getpartialobject:
+ *
+ * This operation is used to read from the device a data
+ * block of an object from a specified offset.
+ *
+ * params: PTPParams*
+ * uint32_t handle - the handle of the requested object
+ * uint32_t offset - the offset in bytes from the beginning of the object
+ * uint32_t size - the requested size of data block to read
+ * uint32_t pos - 1 for the first block, 2 - for a block in the middle,
+ * 3 - for the last block
+ *
+ * Return values: Some PTP_RC_* code.
+ * char **block - the pointer to the block of data read
+ * uint32_t* readnum - the number of bytes read
+ *
+ **/
+uint16_t
+ptp_canon_getpartialobject (PTPParams* params, uint32_t handle,
+ uint32_t offset, uint32_t size,
+ uint32_t pos, char** block,
+ uint32_t* readnum)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char *data=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_GetPartialObject;
+ ptp.Param1=handle;
+ ptp.Param2=offset;
+ ptp.Param3=size;
+ ptp.Param4=pos;
+ ptp.Nparam=4;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data);
+ if (ret==PTP_RC_OK) {
+ *block=data;
+ *readnum=ptp.Param1;
+ }
+ return ret;
+}
+
+/**
+ * ptp_canon_getviewfinderimage:
+ *
+ * This operation can be used to read the image which is currently
+ * in the camera's viewfinder. The image size is 320x240, format is JPEG.
+ * Of course, prior to calling this operation, one must turn the viewfinder
+ * on with the CANON_ViewfinderOn command.
+ * Invoking this operation many times, one can get live video from the camera!
+ *
+ * params: PTPParams*
+ *
+ * Return values: Some PTP_RC_* code.
+ * char **image - the pointer to the read image
+ * unit32_t *size - the size of the image in bytes
+ *
+ **/
+uint16_t
+ptp_canon_getviewfinderimage (PTPParams* params, char** image, uint32_t* size)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_GetViewfinderImage;
+ ptp.Nparam=0;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, image);
+ if (ret==PTP_RC_OK) *size=ptp.Param1;
+ return ret;
+}
+
+/**
+ * ptp_canon_getchanges:
+ *
+ * This is an interesting operation, about the effect of which I am not sure.
+ * This command is called every time when a device property has been changed
+ * with the SetDevicePropValue operation, and after some other operations.
+ * This operation reads the array of Device Properties which have been changed
+ * by the previous operation.
+ * Probably, this operation is even required to make those changes work.
+ *
+ * params: PTPParams*
+ *
+ * Return values: Some PTP_RC_* code.
+ * uint16_t** props - the pointer to the array of changed properties
+ * uint32_t* propnum - the number of elements in the *props array
+ *
+ **/
+uint16_t
+ptp_canon_getchanges (PTPParams* params, uint16_t** props, uint32_t* propnum)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char* data=NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_GetChanges;
+ ptp.Nparam=0;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data);
+ if (ret == PTP_RC_OK)
+ *propnum=ptp_unpack_uint16_t_array(params,data,0,props);
+ free(data);
+ return ret;
+}
+
+/**
+ * ptp_canon_getfolderentries:
+ *
+ * This command reads a specified object's record in a device's filesystem,
+ * or the records of all objects belonging to a specified folder (association).
+ *
+ * params: PTPParams*
+ * uint32_t store - StorageID,
+ * uint32_t p2 - Yet unknown (0 value works OK)
+ * uint32_t parent - Parent Object Handle
+ * # If Parent Object Handle is 0xffffffff,
+ * # the Parent Object is the top level folder.
+ * uint32_t handle - Object Handle
+ * # If Object Handle is 0, the records of all objects
+ * # belonging to the Parent Object are read.
+ * # If Object Handle is not 0, only the record of this
+ * # Object is read.
+ *
+ * Return values: Some PTP_RC_* code.
+ * PTPCANONFolderEntry** entries - the pointer to the folder entry array
+ * uint32_t* entnum - the number of elements of the array
+ *
+ **/
+uint16_t
+ptp_canon_getfolderentries (PTPParams* params, uint32_t store, uint32_t p2,
+ uint32_t parent, uint32_t handle,
+ PTPCANONFolderEntry** entries, uint32_t* entnum)
+{
+ uint16_t ret;
+ PTPContainer ptp;
+ char *data = NULL;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_GetFolderEntries;
+ ptp.Param1=store;
+ ptp.Param2=p2;
+ ptp.Param3=parent;
+ ptp.Param4=handle;
+ ptp.Nparam=4;
+ ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data);
+ if (ret == PTP_RC_OK) {
+ int i;
+ *entnum=ptp.Param1;
+ *entries=calloc(*entnum, sizeof(PTPCANONFolderEntry));
+ if (*entries!=NULL) {
+ for(i=0; i<(*entnum); i++)
+ ptp_unpack_Canon_FE(params,
+ data+i*PTP_CANON_FolderEntryLen,
+ &((*entries)[i]) );
+ } else {
+ ret=PTP_ERROR_IO; /* Cannot allocate memory */
+ }
+ }
+ free(data);
+ return ret;
+}
+
+
+/* Non PTP protocol functions */
+/* devinfo testing functions */
+
+int
+ptp_operation_issupported(PTPParams* params, uint16_t operation)
+{
+ int i=0;
+
+ for (;i<params->deviceinfo.OperationsSupported_len;i++) {
+ if (params->deviceinfo.OperationsSupported[i]==operation)
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+ptp_property_issupported(PTPParams* params, uint16_t property)
+{
+ int i=0;
+
+ for (;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
+ if (params->deviceinfo.DevicePropertiesSupported[i]==property)
+ return 1;
+ }
+ return 0;
+}
+
+/* ptp structures feeing functions */
+
+void
+ptp_free_devicepropdesc(PTPDevicePropDesc* dpd)
+{
+ uint16_t i;
+
+ free(dpd->FactoryDefaultValue);
+ free(dpd->CurrentValue);
+ switch (dpd->FormFlag) {
+ case PTP_DPFF_Range:
+ free (dpd->FORM.Range.MinimumValue);
+ free (dpd->FORM.Range.MaximumValue);
+ free (dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DPFF_Enumeration:
+ for (i=0;i<dpd->FORM.Enum.NumberOfValues;i++)
+ free(dpd->FORM.Enum.SupportedValue[i]);
+ free(dpd->FORM.Enum.SupportedValue);
+ }
+}
+
+/* added by RAL 2006-01-01 */
+
+void
+ptp_free_deviceinfo(PTPDeviceInfo* di)
+{
+ free(di->VendorExtensionDesc);
+ free(di->OperationsSupported);
+ free(di->EventsSupported);
+ free(di->DevicePropertiesSupported);
+ free(di->CaptureFormats);
+ free(di->ImageFormats);
+ free(di->Manufacturer);
+ free(di->Model);
+ free(di->DeviceVersion);
+ free(di->SerialNumber);
+}
+
+/* report PTP errors */
+
+void
+ptp_perror(PTPParams* params, uint16_t error) {
+
+ int i;
+ /* PTP error descriptions */
+ static struct {
+ short error;
+ const char *txt;
+ } ptp_errors[] = {
+ {PTP_RC_Undefined, N_("PTP: Undefined Error")},
+ {PTP_RC_OK, N_("PTP: OK!")},
+ {PTP_RC_GeneralError, N_("PTP: General Error")},
+ {PTP_RC_SessionNotOpen, N_("PTP: Session Not Open")},
+ {PTP_RC_InvalidTransactionID, N_("PTP: Invalid Transaction ID")},
+ {PTP_RC_OperationNotSupported, N_("PTP: Operation Not Supported")},
+ {PTP_RC_ParameterNotSupported, N_("PTP: Parameter Not Supported")},
+ {PTP_RC_IncompleteTransfer, N_("PTP: Incomplete Transfer")},
+ {PTP_RC_InvalidStorageId, N_("PTP: Invalid Storage ID")},
+ {PTP_RC_InvalidObjectHandle, N_("PTP: Invalid Object Handle")},
+ {PTP_RC_DevicePropNotSupported, N_("PTP: Device Prop Not Supported")},
+ {PTP_RC_InvalidObjectFormatCode, N_("PTP: Invalid Object Format Code")},
+ {PTP_RC_StoreFull, N_("PTP: Store Full")},
+ {PTP_RC_ObjectWriteProtected, N_("PTP: Object Write Protected")},
+ {PTP_RC_StoreReadOnly, N_("PTP: Store Read Only")},
+ {PTP_RC_AccessDenied, N_("PTP: Access Denied")},
+ {PTP_RC_NoThumbnailPresent, N_("PTP: No Thumbnail Present")},
+ {PTP_RC_SelfTestFailed, N_("PTP: Self Test Failed")},
+ {PTP_RC_PartialDeletion, N_("PTP: Partial Deletion")},
+ {PTP_RC_StoreNotAvailable, N_("PTP: Store Not Available")},
+ {PTP_RC_SpecificationByFormatUnsupported,
+ N_("PTP: Specification By Format Unsupported")},
+ {PTP_RC_NoValidObjectInfo, N_("PTP: No Valid Object Info")},
+ {PTP_RC_InvalidCodeFormat, N_("PTP: Invalid Code Format")},
+ {PTP_RC_UnknownVendorCode, N_("PTP: Unknown Vendor Code")},
+ {PTP_RC_CaptureAlreadyTerminated,
+ N_("PTP: Capture Already Terminated")},
+ {PTP_RC_DeviceBusy, N_("PTP: Device Bus")},
+ {PTP_RC_InvalidParentObject, N_("PTP: Invalid Parent Object")},
+ {PTP_RC_InvalidDevicePropFormat, N_("PTP: Invalid Device Prop Format")},
+ {PTP_RC_InvalidDevicePropValue, N_("PTP: Invalid Device Prop Value")},
+ {PTP_RC_InvalidParameter, N_("PTP: Invalid Parameter")},
+ {PTP_RC_SessionAlreadyOpened, N_("PTP: Session Already Opened")},
+ {PTP_RC_TransactionCanceled, N_("PTP: Transaction Canceled")},
+ {PTP_RC_SpecificationOfDestinationUnsupported,
+ N_("PTP: Specification Of Destination Unsupported")},
+
+ {PTP_ERROR_IO, N_("PTP: I/O error")},
+ {PTP_ERROR_BADPARAM, N_("PTP: Error: bad parameter")},
+ {PTP_ERROR_DATA_EXPECTED, N_("PTP: Protocol error, data expected")},
+ {PTP_ERROR_RESP_EXPECTED, N_("PTP: Protocol error, response expected")},
+ {0, NULL}
+ };
+ static struct {
+ short error;
+ const char *txt;
+ } ptp_errors_EK[] = {
+ {PTP_RC_EK_FilenameRequired, N_("PTP EK: Filename Required")},
+ {PTP_RC_EK_FilenameConflicts, N_("PTP EK: Filename Conflicts")},
+ {PTP_RC_EK_FilenameInvalid, N_("PTP EK: Filename Invalid")},
+ {0, NULL}
+ };
+
+ for (i=0; ptp_errors[i].txt!=NULL; i++)
+ if (ptp_errors[i].error == error){
+ ptp_error(params, ptp_errors[i].txt);
+ return;
+ }
+
+ /*if (error|PTP_RC_EXTENSION_MASK==PTP_RC_EXTENSION)*/
+ switch (params->deviceinfo.VendorExtensionID) {
+ case PTP_VENDOR_EASTMAN_KODAK:
+ for (i=0; ptp_errors_EK[i].txt!=NULL; i++)
+ if (ptp_errors_EK[i].error==error)
+ ptp_error(params, ptp_errors_EK[i].txt);
+ break;
+ }
+}
+
+/* return ptp operation name */
+
+const char*
+ptp_get_operation_name(PTPParams* params, uint16_t oc)
+{
+ int i;
+ /* Operation Codes */
+ struct {
+ uint16_t oc;
+ const char *txt;
+ } ptp_operations[] = {
+ {PTP_OC_Undefined, N_("UndefinedOperation")},
+ {PTP_OC_GetDeviceInfo, N_("GetDeviceInfo")},
+ {PTP_OC_OpenSession, N_("OpenSession")},
+ {PTP_OC_CloseSession, N_("CloseSession")},
+ {PTP_OC_GetStorageIDs, N_("GetStorageIDs")},
+ {PTP_OC_GetStorageInfo, N_("GetStorageInfo")},
+ {PTP_OC_GetNumObjects, N_("GetNumObjects")},
+ {PTP_OC_GetObjectHandles, N_("GetObjectHandles")},
+ {PTP_OC_GetObjectInfo, N_("GetObjectInfo")},
+ {PTP_OC_GetObject, N_("GetObject")},
+ {PTP_OC_GetThumb, N_("GetThumb")},
+ {PTP_OC_DeleteObject, N_("DeleteObject")},
+ {PTP_OC_SendObjectInfo, N_("SendObjectInfo")},
+ {PTP_OC_SendObject, N_("SendObject")},
+ {PTP_OC_InitiateCapture, N_("InitiateCapture")},
+ {PTP_OC_FormatStore, N_("FormatStore")},
+ {PTP_OC_ResetDevice, N_("ResetDevice")},
+ {PTP_OC_SelfTest, N_("SelfTest")},
+ {PTP_OC_SetObjectProtection, N_("SetObjectProtection")},
+ {PTP_OC_PowerDown, N_("PowerDown")},
+ {PTP_OC_GetDevicePropDesc, N_("GetDevicePropDesc")},
+ {PTP_OC_GetDevicePropValue, N_("GetDevicePropValue")},
+ {PTP_OC_SetDevicePropValue, N_("SetDevicePropValue")},
+ {PTP_OC_ResetDevicePropValue, N_("ResetDevicePropValue")},
+ {PTP_OC_TerminateOpenCapture, N_("TerminateOpenCapture")},
+ {PTP_OC_MoveObject, N_("MoveObject")},
+ {PTP_OC_CopyObject, N_("CopyObject")},
+ {PTP_OC_GetPartialObject, N_("GetPartialObject")},
+ {PTP_OC_InitiateOpenCapture, N_("InitiateOpenCapture")},
+ {0,NULL}
+ };
+ struct {
+ uint16_t oc;
+ const char *txt;
+ } ptp_operations_EK[] = {
+ {PTP_OC_EK_SendFileObjectInfo, N_("EK SendFileObjectInfo")},
+ {PTP_OC_EK_SendFileObject, N_("EK SendFileObject")},
+ {0,NULL}
+ };
+ struct {
+ uint16_t oc;
+ const char *txt;
+ } ptp_operations_CANON[] = {
+ {PTP_OC_CANON_GetObjectSize, N_("CANON GetObjectSize")},
+ {PTP_OC_CANON_StartShootingMode,N_("CANON StartShootingMode")},
+ {PTP_OC_CANON_EndShootingMode, N_("CANON EndShootingMode")},
+ {PTP_OC_CANON_ViewfinderOn, N_("CANON ViewfinderOn")},
+ {PTP_OC_CANON_ViewfinderOff, N_("CANON ViewfinderOff")},
+ {PTP_OC_CANON_ReflectChanges, N_("CANON ReflectChanges")},
+ {PTP_OC_CANON_CheckEvent, N_("CANON CheckEvent")},
+ {PTP_OC_CANON_FocusLock, N_("CANON FocusLock")},
+ {PTP_OC_CANON_FocusUnlock, N_("CANON FocusUnlock")},
+ {PTP_OC_CANON_InitiateCaptureInMemory,
+ N_("CANON InitiateCaptureInMemory")},
+ {PTP_OC_CANON_GetPartialObject, N_("CANON GetPartialObject")},
+ {PTP_OC_CANON_GetViewfinderImage,
+ N_("CANON GetViewfinderImage")},
+ {PTP_OC_CANON_GetChanges, N_("CANON GetChanges")},
+ {PTP_OC_CANON_GetFolderEntries, N_("CANON GetFolderEntries")},
+ {0,NULL}
+ };
+
+ switch (params->deviceinfo.VendorExtensionID) {
+ case PTP_VENDOR_EASTMAN_KODAK:
+ for (i=0; ptp_operations_EK[i].txt!=NULL; i++)
+ if (ptp_operations_EK[i].oc==oc)
+ return (ptp_operations_EK[i].txt);
+ break;
+
+ case PTP_VENDOR_CANON:
+ for (i=0; ptp_operations_CANON[i].txt!=NULL; i++)
+ if (ptp_operations_CANON[i].oc==oc)
+ return (ptp_operations_CANON[i].txt);
+ break;
+ }
+ for (i=0; ptp_operations[i].txt!=NULL; i++)
+ if (ptp_operations[i].oc == oc){
+ return (ptp_operations[i].txt);
+ }
+
+ return NULL;
+}
+
+/* return ptp property nam */
+
+const char*
+ptp_get_property_name(PTPParams* params, uint16_t dpc)
+{
+ int i;
+ /* Device Property descriptions */
+ struct {
+ uint16_t dpc;
+ const char *txt;
+ } ptp_device_properties[] = {
+ {PTP_DPC_Undefined, N_("PTP Undefined Property")},
+ {PTP_DPC_BatteryLevel, N_("Battery Level")},
+ {PTP_DPC_FunctionalMode, N_("Functional Mode")},
+ {PTP_DPC_ImageSize, N_("Image Size")},
+ {PTP_DPC_CompressionSetting, N_("Compression Setting")},
+ {PTP_DPC_WhiteBalance, N_("White Balance")},
+ {PTP_DPC_RGBGain, N_("RGB Gain")},
+ {PTP_DPC_FNumber, N_("F-Number")},
+ {PTP_DPC_FocalLength, N_("Focal Length")},
+ {PTP_DPC_FocusDistance, N_("Focus Distance")},
+ {PTP_DPC_FocusMode, N_("Focus Mode")},
+ {PTP_DPC_ExposureMeteringMode, N_("Exposure Metering Mode")},
+ {PTP_DPC_FlashMode, N_("Flash Mode")},
+ {PTP_DPC_ExposureTime, N_("Exposure Time")},
+ {PTP_DPC_ExposureProgramMode, N_("Exposure Program Mode")},
+ {PTP_DPC_ExposureIndex,
+ N_("Exposure Index (film speed ISO)")},
+ {PTP_DPC_ExposureBiasCompensation,
+ N_("Exposure Bias Compensation")},
+ {PTP_DPC_DateTime, N_("Date Time")},
+ {PTP_DPC_CaptureDelay, N_("Pre-Capture Delay")},
+ {PTP_DPC_StillCaptureMode, N_("Still Capture Mode")},
+ {PTP_DPC_Contrast, N_("Contrast")},
+ {PTP_DPC_Sharpness, N_("Sharpness")},
+ {PTP_DPC_DigitalZoom, N_("Digital Zoom")},
+ {PTP_DPC_EffectMode, N_("Effect Mode")},
+ {PTP_DPC_BurstNumber, N_("Burst Number")},
+ {PTP_DPC_BurstInterval, N_("Burst Interval")},
+ {PTP_DPC_TimelapseNumber, N_("Timelapse Number")},
+ {PTP_DPC_TimelapseInterval, N_("Timelapse Interval")},
+ {PTP_DPC_FocusMeteringMode, N_("Focus Metering Mode")},
+ {PTP_DPC_UploadURL, N_("Upload URL")},
+ {PTP_DPC_Artist, N_("Artist")},
+ {PTP_DPC_CopyrightInfo, N_("Copyright Info")},
+ {0,NULL}
+ };
+ struct {
+ uint16_t dpc;
+ const char *txt;
+ } ptp_device_properties_EK[] = {
+ {PTP_DPC_EK_ColorTemperature, N_("EK Color Temperature")},
+ {PTP_DPC_EK_DateTimeStampFormat,
+ N_("EK Date Time Stamp Format")},
+ {PTP_DPC_EK_BeepMode, N_("EK Beep Mode")},
+ {PTP_DPC_EK_VideoOut, N_("EK Video Out")},
+ {PTP_DPC_EK_PowerSaving, N_("EK Power Saving")},
+ {PTP_DPC_EK_UI_Language, N_("EK UI Language")},
+ {0,NULL}
+ };
+
+ struct {
+ uint16_t dpc;
+ const char *txt;
+ } ptp_device_properties_CANON[] = {
+ {PTP_DPC_CANON_BeepMode, N_("CANON Beep Mode")},
+ {PTP_DPC_CANON_UnixTime, N_("CANON Time measured in"
+ " secondssince 01-01-1970")},
+ {PTP_DPC_CANON_FlashMemory,
+ N_("CANON Flash Card Capacity")},
+ {PTP_DPC_CANON_CameraModel, N_("CANON Camera Model")},
+ {0,NULL}
+ };
+/* Nikon Codes added by Corey Manders and Mehreen Chaudary */
+ struct {
+ uint16_t dpc;
+ const char *txt;
+ } ptp_device_properties_NIKON[] = {
+ {PTP_DPC_NIKON_ShootingBank, N_("NIKON Shooting Bank")},
+ {PTP_DPC_NIKON_ShootingBankNameA,
+ N_("NIKON Shooting Bank Name A")},
+ {PTP_DPC_NIKON_ShootingBankNameB,
+ N_("NIKON Shooting Bank Name B")},
+ {PTP_DPC_NIKON_ShootingBankNameC,
+ N_("NIKON Shooting Bank Name C")},
+ {PTP_DPC_NIKON_ShootingBankNameD,
+ N_("NIKON Shooting Bank Name D")},
+ {PTP_DPC_NIKON_RawCompression, N_("NIKON Raw Compression")},
+ {PTP_DPC_NIKON_WhiteBalanceAutoBias,
+ N_("NIKON White Balance Auto Bias")},
+ {PTP_DPC_NIKON_WhiteBalanceTungstenBias,
+ N_("NIKON White Balance Tungsten Bias")},
+ {PTP_DPC_NIKON_WhiteBalanceFlourescentBias,
+ N_("NIKON White Balance Flourescent Bias")},
+ {PTP_DPC_NIKON_WhiteBalanceDaylightBias,
+ N_("NIKON White Balance Daylight Bias")},
+ {PTP_DPC_NIKON_WhiteBalanceFlashBias,
+ N_("NIKON White Balance Flash Bias")},
+ {PTP_DPC_NIKON_WhiteBalanceCloudyBias,
+ N_("NIKON White Balance Cloudy Bias")},
+ {PTP_DPC_NIKON_WhiteBalanceShadeBias,
+ N_("NIKON White Balance Shade Bias")},
+ {PTP_DPC_NIKON_WhiteBalanceColourTemperature,
+ N_("NIKON White Balance Colour Temperature")},
+ {PTP_DPC_NIKON_ImageSharpening,
+ N_("NIKON Image Sharpening")},
+ {PTP_DPC_NIKON_ToneCompensation,
+ N_("NIKON Tone Compensation")},
+ {PTP_DPC_NIKON_ColourMode, N_("NIKON Colour Mode")},
+ {PTP_DPC_NIKON_HueAdjustment, N_("NIKON Hue Adjustment")},
+ {PTP_DPC_NIKON_NonCPULensDataFocalLength,
+ N_("NIKON Non CPU Lens Data Focal Length")},
+ {PTP_DPC_NIKON_NonCPULensDataMaximumAperture,
+ N_("NIKON Non CPU Lens Data Maximum Aperture")},
+ {PTP_DPC_NIKON_CSMMenuBankSelect,
+ N_("NIKON CSM Menu Bank Select")},
+ {PTP_DPC_NIKON_MenuBankNameA, N_("NIKON Menu Bank Name A")},
+ {PTP_DPC_NIKON_MenuBankNameB, N_("NIKON Menu Bank Name B")},
+ {PTP_DPC_NIKON_MenuBankNameC, N_("NIKON Menu Bank Name C")},
+ {PTP_DPC_NIKON_MenuBankNameD, N_("NIKON Menu Bank Name D")},
+ {PTP_DPC_NIKON_A1AFCModePriority,
+ N_("NIKON (A1) AFC Mode Priority")},
+ {PTP_DPC_NIKON_A2AFSModePriority,
+ N_("NIKON (A2) AFS Mode Priority")},
+ {PTP_DPC_NIKON_A3GroupDynamicAF,
+ N_("NIKON (A3) Group Dynamic AF")},
+ {PTP_DPC_NIKON_A4AFActivation,
+ N_("NIKON (A4) AF Activation")},
+ {PTP_DPC_NIKON_A5FocusAreaIllumManualFocus,
+ N_("NIKON (A5) Focus Area Illum Manual Focus")},
+ {PTP_DPC_NIKON_FocusAreaIllumContinuous,
+ N_("NIKON Focus Area Illum Continuous")},
+ {PTP_DPC_NIKON_FocusAreaIllumWhenSelected,
+ N_("NIKON Focus Area Illum When Selected")},
+ {PTP_DPC_NIKON_A6FocusArea, N_("NIKON (A6) Focus Area")},
+ {PTP_DPC_NIKON_A7VerticalAFON,
+ N_("NIKON (A7) Vertical AF ON")},
+ {PTP_DPC_NIKON_B1ISOAuto, N_("NIKON (B1) ISO Auto")},
+ {PTP_DPC_NIKON_B2ISOStep, N_("NIKON (B2) ISO Step")},
+ {PTP_DPC_NIKON_B3EVStep, N_("NIKON (B3) EV Step")},
+ {PTP_DPC_NIKON_B4ExposureCompEv,
+ N_("NIKON (B4) Exposure Comp Ev")},
+ {PTP_DPC_NIKON_B5ExposureComp,
+ N_("NIKON (B5) Exposure Comp")},
+ {PTP_DPC_NIKON_B6CenterWeightArea,
+ N_("NIKON (B6) Center Weight Area")},
+ {PTP_DPC_NIKON_C1AELock, N_("NIKON (C1) AE Lock")},
+ {PTP_DPC_NIKON_C2AELAFL, N_("NIKON (C2) AE_L/AF_L")},
+ {PTP_DPC_NIKON_C3AutoMeterOff,
+ N_("NIKON (C3) Auto Meter Off")},
+ {PTP_DPC_NIKON_C4SelfTimer, N_("NIKON (C4) Self Timer")},
+ {PTP_DPC_NIKON_C5MonitorOff, N_("NIKON (C5) Monitor Off")},
+ {PTP_DPC_NIKON_D1ShootingSpeed,
+ N_("NIKON (D1) Shooting Speed")},
+ {PTP_DPC_NIKON_D2MaximumShots,
+ N_("NIKON (D2) Maximum Shots")},
+ {PTP_DPC_NIKON_D3ExpDelayMode, N_("NIKON (D3) ExpDelayMode")},
+ {PTP_DPC_NIKON_D4LongExposureNoiseReduction,
+ N_("NIKON (D4) Long Exposure Noise Reduction")},
+ {PTP_DPC_NIKON_D5FileNumberSequence,
+ N_("NIKON (D5) File Number Sequence")},
+ {PTP_DPC_NIKON_D6ControlPanelFinderRearControl,
+ N_("NIKON (D6) Control Panel Finder Rear Control")},
+ {PTP_DPC_NIKON_ControlPanelFinderViewfinder,
+ N_("NIKON Control Panel Finder Viewfinder")},
+ {PTP_DPC_NIKON_D7Illumination, N_("NIKON (D7) Illumination")},
+ {PTP_DPC_NIKON_E1FlashSyncSpeed,
+ N_("NIKON (E1) Flash Sync Speed")},
+ {PTP_DPC_NIKON_E2FlashShutterSpeed,
+ N_("NIKON (E2) Flash Shutter Speed")},
+ {PTP_DPC_NIKON_E3AAFlashMode,
+ N_("NIKON (E3) AA Flash Mode")},
+ {PTP_DPC_NIKON_E4ModelingFlash,
+ N_("NIKON (E4) Modeling Flash")},
+ {PTP_DPC_NIKON_E5AutoBracketSet,
+ N_("NIKON (E5) Auto Bracket Set")},
+ {PTP_DPC_NIKON_E6ManualModeBracketing,
+ N_("NIKON (E6) Manual Mode Bracketing")},
+ {PTP_DPC_NIKON_E7AutoBracketOrder,
+ N_("NIKON (E7) Auto Bracket Order")},
+ {PTP_DPC_NIKON_E8AutoBracketSelection,
+ N_("NIKON (E8) Auto Bracket Selection")},
+ {PTP_DPC_NIKON_F1CenterButtonShootingMode,
+ N_("NIKON (F1) Center Button Shooting Mode")},
+ {PTP_DPC_NIKON_CenterButtonPlaybackMode,
+ N_("NIKON Center Button Playback Mode")},
+ {PTP_DPC_NIKON_F2Multiselector,
+ N_("NIKON (F2) Multiselector")},
+ {PTP_DPC_NIKON_F3PhotoInfoPlayback,
+ N_("NIKON (F3) PhotoInfoPlayback")},
+ {PTP_DPC_NIKON_F4AssignFuncButton,
+ N_("NIKON (F4) Assign Function Button")},
+ {PTP_DPC_NIKON_F5CustomizeCommDials,
+ N_("NIKON (F5) Customize Comm Dials")},
+ {PTP_DPC_NIKON_ChangeMainSub, N_("NIKON Change Main Sub")},
+ {PTP_DPC_NIKON_ApertureSetting,
+ N_("NIKON Aperture Setting")},
+ {PTP_DPC_NIKON_MenusAndPlayback,
+ N_("NIKON Menus and Playback")},
+ {PTP_DPC_NIKON_F6ButtonsAndDials,
+ N_("NIKON (F6) Buttons and Dials")},
+ {PTP_DPC_NIKON_F7NoCFCard, N_("NIKON (F7) No CF Card")},
+ {PTP_DPC_NIKON_AutoImageRotation,
+ N_("NIKON Auto Image Rotation")},
+ {PTP_DPC_NIKON_ExposureBracketingOnOff,
+ N_("NIKON Exposure Bracketing On Off")},
+ {PTP_DPC_NIKON_ExposureBracketingIntervalDist,
+ N_("NIKON Exposure Bracketing Interval Distance")},
+ {PTP_DPC_NIKON_ExposureBracketingNumBracketPlace,
+ N_("NIKON Exposure Bracketing Number Bracket Place")},
+ {PTP_DPC_NIKON_AutofocusLCDTopMode2,
+ N_("NIKON Autofocus LCD Top Mode 2")},
+ {PTP_DPC_NIKON_AutofocusLCDTopMode3AndMode4,
+ N_("NIKON Autofocus LCD Top Mode 3 and Mode 4")},
+ {PTP_DPC_NIKON_LightMeter, N_("NIKON Light Meter")},
+ {PTP_DPC_NIKON_ExposureApertureLock,
+ N_("NIKON Exposure Aperture Lock")},
+ {PTP_DPC_NIKON_MaximumShots, N_("NIKON Maximum Shots")},
+ {PTP_DPC_NIKON_Beep, N_("NIKON AF Beep Mode")},
+ {PTP_DPC_NIKON_AFC, N_("NIKON ??? AF Related")},
+ {PTP_DPC_NIKON_AFLampOff, N_("NIKON AF Lamp")},
+ {PTP_DPC_NIKON_PADVPMode, N_("NIKON Auto ISO P/A/DVP Setting")},
+ {PTP_DPC_NIKON_ReviewOff, N_("NIKON Image Review")},
+ {PTP_DPC_NIKON_GridDisplay, N_("NIKON Viewfinder Grid Display")},
+ {PTP_DPC_NIKON_AFAreaIllumination, N_("NIKON AF Area Illumination")},
+ {PTP_DPC_NIKON_FlashMode, N_("NIKON Flash Mode")},
+ {PTP_DPC_NIKON_FlashPower, N_("NIKON Flash Power")},
+ {PTP_DPC_NIKON_FlashSignOff, N_("NIKON Flash Sign")},
+ {PTP_DPC_NIKON_FlashExposureCompensation,
+ N_("NIKON Flash Exposure Compensation")},
+ {PTP_DPC_NIKON_RemoteTimeout, N_("NIKON Remote Timeout")},
+ {PTP_DPC_NIKON_ImageCommentString, N_("NIKON Image Comment String")},
+ {PTP_DPC_NIKON_FlashOpen, N_("NIKON Flash Open")},
+ {PTP_DPC_NIKON_FlashCharged, N_("NIKON Flash Charged")},
+ {PTP_DPC_NIKON_LensID, N_("NIKON Lens ID")},
+ {PTP_DPC_NIKON_FocalLengthMin, N_("NIKON Min. Focal Length")},
+ {PTP_DPC_NIKON_FocalLengthMax, N_("NIKON Max. Focal Length")},
+ {PTP_DPC_NIKON_MaxApAtMinFocalLength,
+ N_("NIKON Max. Aperture at Min. Focal Length")},
+ {PTP_DPC_NIKON_MaxApAtMaxFocalLength,
+ N_("NIKON Max. Aperture at Max. Focal Length")},
+ {PTP_DPC_NIKON_LowLight, N_("NIKON Low Light")},
+ {PTP_DPC_NIKON_ExtendedCSMMenu, N_("NIKON Extended CSM Menu")},
+ {PTP_DPC_NIKON_OptimiseImage, N_("NIKON Optimise Image")},
+ {0,NULL}
+ };
+
+ for (i=0; ptp_device_properties[i].txt!=NULL; i++)
+ if (ptp_device_properties[i].dpc==dpc)
+ return (ptp_device_properties[i].txt);
+
+ /*if (dpc|PTP_DPC_EXTENSION_MASK==PTP_DPC_EXTENSION)*/
+ switch (params->deviceinfo.VendorExtensionID) {
+ case PTP_VENDOR_EASTMAN_KODAK:
+ for (i=0; ptp_device_properties_EK[i].txt!=NULL; i++)
+ if (ptp_device_properties_EK[i].dpc==dpc)
+ return (ptp_device_properties_EK[i].txt);
+ break;
+
+ case PTP_VENDOR_CANON:
+ for (i=0; ptp_device_properties_CANON[i].txt!=NULL; i++)
+ if (ptp_device_properties_CANON[i].dpc==dpc)
+ return (ptp_device_properties_CANON[i].txt);
+ break;
+ case PTP_VENDOR_NIKON:
+ for (i=0; ptp_device_properties_NIKON[i].txt!=NULL; i++)
+ if (ptp_device_properties_NIKON[i].dpc==dpc)
+ return (ptp_device_properties_NIKON[i].txt);
+ break;
+
+
+ }
+ return NULL;
+}
+
diff --git a/src/ptp.h b/src/ptp.h
new file mode 100644
index 0000000..d77e53f
--- /dev/null
+++ b/src/ptp.h
@@ -0,0 +1,895 @@
+/* ptp.h
+ *
+ * Copyright (C) 2001-2004 Mariusz Woloszyn <emsi@ipartners.pl>
+ *
+ * This file is part of libptp2.
+ *
+ * libptp2 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libptp2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libptp2; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __PTP_H__
+#define __PTP_H__
+
+#include <stdarg.h>
+#include <time.h>
+#include "libptp-endian.h"
+
+/** The callback type */
+typedef int Progress_Callback(u_int32_t sent, u_int32_t total);
+
+/* PTP datalayer byteorder */
+
+#define PTP_DL_BE 0xF0
+#define PTP_DL_LE 0x0F
+
+/* PTP request/response/event general PTP container (transport independent) */
+
+struct _PTPContainer {
+ uint16_t Code;
+ uint32_t SessionID;
+ uint32_t Transaction_ID;
+ /* params may be of any type of size less or equal to uint32_t */
+ uint32_t Param1;
+ uint32_t Param2;
+ uint32_t Param3;
+ /* events can only have three parameters */
+ uint32_t Param4;
+ uint32_t Param5;
+ /* the number of meaningfull parameters */
+ uint8_t Nparam;
+};
+typedef struct _PTPContainer PTPContainer;
+
+/* PTP USB Bulk-Pipe container */
+/* USB bulk max max packet length for high speed endpoints */
+#define PTP_USB_BULK_HS_MAX_PACKET_LEN 512
+#define PTP_USB_BULK_HDR_LEN (2*sizeof(uint32_t)+2*sizeof(uint16_t))
+#define PTP_USB_BULK_PAYLOAD_LEN (PTP_USB_BULK_HS_MAX_PACKET_LEN-PTP_USB_BULK_HDR_LEN)
+#define PTP_USB_BULK_REQ_LEN (PTP_USB_BULK_HDR_LEN+5*sizeof(uint32_t))
+
+/* see ptp.c:ptp_usb_senddata for info on these sizes
+ added by RAL 2005-12-21 */
+#define BLOCK_SIZE 0xe000
+#define MTP_DEVICE_BUF_SIZE 0x200
+/* the amount of data between each progress report. Must be multiple of BLOCK_SIZE */
+#define CALLBACK_SIZE (BLOCK_SIZE*16)
+
+struct _PTPUSBBulkContainer {
+ uint32_t length;
+ uint16_t type;
+ uint16_t code;
+ uint32_t trans_id;
+ union {
+ struct {
+ uint32_t param1;
+ uint32_t param2;
+ uint32_t param3;
+ uint32_t param4;
+ uint32_t param5;
+ } params;
+ ////unsigned char data[PTP_USB_BULK_PAYLOAD_LEN];
+ } payload;
+};
+typedef struct _PTPUSBBulkContainer PTPUSBBulkContainer;
+
+/* USB Bulk Container to send - see ptp.c:ptp_usb_senddata for more info
+ added by RAL 2005-12-21 */
+struct _PTPUSBBulkContainerSend {
+ uint32_t length;
+ uint16_t type;
+ uint16_t code;
+ uint32_t trans_id;
+};
+typedef struct _PTPUSBBulkContainerSend PTPUSBBulkContainerSend;
+
+/* PTP USB Asynchronous Event Interrupt Data Format */
+struct _PTPUSBEventContainer {
+ uint32_t length;
+ uint16_t type;
+ uint16_t code;
+ uint32_t trans_id;
+ uint32_t param1;
+ uint32_t param2;
+ uint32_t param3;
+};
+typedef struct _PTPUSBEventContainer PTPUSBEventContainer;
+
+
+/* USB container types */
+
+#define PTP_USB_CONTAINER_UNDEFINED 0x0000
+#define PTP_USB_CONTAINER_COMMAND 0x0001
+#define PTP_USB_CONTAINER_DATA 0x0002
+#define PTP_USB_CONTAINER_RESPONSE 0x0003
+#define PTP_USB_CONTAINER_EVENT 0x0004
+
+/* Vendor IDs */
+#define PTP_VENDOR_EASTMAN_KODAK 0x00000001
+#define PTP_VENDOR_SEIKO_EPSON 0x00000002
+#define PTP_VENDOR_AGILENT 0x00000003
+#define PTP_VENDOR_POLAROID 0x00000004
+#define PTP_VENDOR_AGFA_GEVAERT 0x00000005
+#define PTP_VENDOR_MICROSOFT 0x00000006
+#define PTP_VENDOR_EQUINOX 0x00000007
+#define PTP_VENDOR_VIEWQUEST 0x00000008
+#define PTP_VENDOR_STMICROELECTRONICS 0x00000009
+#define PTP_VENDOR_NIKON 0x0000000A
+#define PTP_VENDOR_CANON 0x0000000B
+
+/* Operation Codes */
+
+#define PTP_OC_Undefined 0x1000
+#define PTP_OC_GetDeviceInfo 0x1001
+#define PTP_OC_OpenSession 0x1002
+#define PTP_OC_CloseSession 0x1003
+#define PTP_OC_GetStorageIDs 0x1004
+#define PTP_OC_GetStorageInfo 0x1005
+#define PTP_OC_GetNumObjects 0x1006
+#define PTP_OC_GetObjectHandles 0x1007
+#define PTP_OC_GetObjectInfo 0x1008
+#define PTP_OC_GetObject 0x1009
+#define PTP_OC_GetThumb 0x100A
+#define PTP_OC_DeleteObject 0x100B
+#define PTP_OC_SendObjectInfo 0x100C
+#define PTP_OC_SendObject 0x100D
+#define PTP_OC_InitiateCapture 0x100E
+#define PTP_OC_FormatStore 0x100F
+#define PTP_OC_ResetDevice 0x1010
+#define PTP_OC_SelfTest 0x1011
+#define PTP_OC_SetObjectProtection 0x1012
+#define PTP_OC_PowerDown 0x1013
+#define PTP_OC_GetDevicePropDesc 0x1014
+#define PTP_OC_GetDevicePropValue 0x1015
+#define PTP_OC_SetDevicePropValue 0x1016
+#define PTP_OC_ResetDevicePropValue 0x1017
+#define PTP_OC_TerminateOpenCapture 0x1018
+#define PTP_OC_MoveObject 0x1019
+#define PTP_OC_CopyObject 0x101A
+#define PTP_OC_GetPartialObject 0x101B
+#define PTP_OC_InitiateOpenCapture 0x101C
+/* Eastman Kodak extension Operation Codes */
+#define PTP_OC_EK_SendFileObjectInfo 0x9005
+#define PTP_OC_EK_SendFileObject 0x9006
+/* Canon extension Operation Codes */
+#define PTP_OC_CANON_GetObjectSize 0x9001
+#define PTP_OC_CANON_StartShootingMode 0x9008
+#define PTP_OC_CANON_EndShootingMode 0x9009
+#define PTP_OC_CANON_ViewfinderOn 0x900B
+#define PTP_OC_CANON_ViewfinderOff 0x900C
+#define PTP_OC_CANON_ReflectChanges 0x900D
+#define PTP_OC_CANON_CheckEvent 0x9013
+#define PTP_OC_CANON_FocusLock 0x9014
+#define PTP_OC_CANON_FocusUnlock 0x9015
+#define PTP_OC_CANON_InitiateCaptureInMemory 0x901A
+#define PTP_OC_CANON_GetPartialObject 0x901B
+#define PTP_OC_CANON_GetViewfinderImage 0x901d
+#define PTP_OC_CANON_GetChanges 0x9020
+#define PTP_OC_CANON_GetFolderEntries 0x9021
+
+/* Proprietary vendor extension operations mask */
+#define PTP_OC_EXTENSION_MASK 0xF000
+#define PTP_OC_EXTENSION 0x9000
+
+/* Response Codes */
+
+#define PTP_RC_Undefined 0x2000
+#define PTP_RC_OK 0x2001
+#define PTP_RC_GeneralError 0x2002
+#define PTP_RC_SessionNotOpen 0x2003
+#define PTP_RC_InvalidTransactionID 0x2004
+#define PTP_RC_OperationNotSupported 0x2005
+#define PTP_RC_ParameterNotSupported 0x2006
+#define PTP_RC_IncompleteTransfer 0x2007
+#define PTP_RC_InvalidStorageId 0x2008
+#define PTP_RC_InvalidObjectHandle 0x2009
+#define PTP_RC_DevicePropNotSupported 0x200A
+#define PTP_RC_InvalidObjectFormatCode 0x200B
+#define PTP_RC_StoreFull 0x200C
+#define PTP_RC_ObjectWriteProtected 0x200D
+#define PTP_RC_StoreReadOnly 0x200E
+#define PTP_RC_AccessDenied 0x200F
+#define PTP_RC_NoThumbnailPresent 0x2010
+#define PTP_RC_SelfTestFailed 0x2011
+#define PTP_RC_PartialDeletion 0x2012
+#define PTP_RC_StoreNotAvailable 0x2013
+#define PTP_RC_SpecificationByFormatUnsupported 0x2014
+#define PTP_RC_NoValidObjectInfo 0x2015
+#define PTP_RC_InvalidCodeFormat 0x2016
+#define PTP_RC_UnknownVendorCode 0x2017
+#define PTP_RC_CaptureAlreadyTerminated 0x2018
+#define PTP_RC_DeviceBusy 0x2019
+#define PTP_RC_InvalidParentObject 0x201A
+#define PTP_RC_InvalidDevicePropFormat 0x201B
+#define PTP_RC_InvalidDevicePropValue 0x201C
+#define PTP_RC_InvalidParameter 0x201D
+#define PTP_RC_SessionAlreadyOpened 0x201E
+#define PTP_RC_TransactionCanceled 0x201F
+#define PTP_RC_SpecificationOfDestinationUnsupported 0x2020
+/* Eastman Kodak extension Response Codes */
+#define PTP_RC_EK_FilenameRequired 0xA001
+#define PTP_RC_EK_FilenameConflicts 0xA002
+#define PTP_RC_EK_FilenameInvalid 0xA003
+
+/* Proprietary vendor extension response code mask */
+#define PTP_RC_EXTENSION_MASK 0xF000
+#define PTP_RC_EXTENSION 0xA000
+
+/* libptp2 extended ERROR codes */
+#define PTP_ERROR_IO 0x02FF
+#define PTP_ERROR_DATA_EXPECTED 0x02FE
+#define PTP_ERROR_RESP_EXPECTED 0x02FD
+#define PTP_ERROR_BADPARAM 0x02FC
+
+/* PTP Event Codes */
+
+#define PTP_EC_Undefined 0x4000
+#define PTP_EC_CancelTransaction 0x4001
+#define PTP_EC_ObjectAdded 0x4002
+#define PTP_EC_ObjectRemoved 0x4003
+#define PTP_EC_StoreAdded 0x4004
+#define PTP_EC_StoreRemoved 0x4005
+#define PTP_EC_DevicePropChanged 0x4006
+#define PTP_EC_ObjectInfoChanged 0x4007
+#define PTP_EC_DeviceInfoChanged 0x4008
+#define PTP_EC_RequestObjectTransfer 0x4009
+#define PTP_EC_StoreFull 0x400A
+#define PTP_EC_DeviceReset 0x400B
+#define PTP_EC_StorageInfoChanged 0x400C
+#define PTP_EC_CaptureComplete 0x400D
+#define PTP_EC_UnreportedStatus 0x400E
+/* Canon extension Event Codes */
+#define PTP_EC_CANON_DeviceInfoChanged 0xC008
+#define PTP_EC_CANON_RequestObjectTransfer 0xC009
+#define PTP_EC_CANON_CameraModeChanged 0xC00C
+
+/* constants for GetObjectHandles */
+#define PTP_GOH_ALL_STORAGE 0xffffffff
+#define PTP_GOH_ALL_FORMATS 0x00000000
+#define PTP_GOH_ALL_ASSOCS 0x00000000
+
+/* PTP device info structure (returned by GetDevInfo) */
+
+struct _PTPDeviceInfo {
+ uint16_t StaqndardVersion;
+ uint32_t VendorExtensionID;
+ uint16_t VendorExtensionVersion;
+ char *VendorExtensionDesc;
+ uint16_t FunctionalMode;
+ uint32_t OperationsSupported_len;
+ uint16_t *OperationsSupported;
+ uint32_t EventsSupported_len;
+ uint16_t *EventsSupported;
+ uint32_t DevicePropertiesSupported_len;
+ uint16_t *DevicePropertiesSupported;
+ uint32_t CaptureFormats_len;
+ uint16_t *CaptureFormats;
+ uint32_t ImageFormats_len;
+ uint16_t *ImageFormats;
+ char *Manufacturer;
+ char *Model;
+ char *DeviceVersion;
+ char *SerialNumber;
+};
+typedef struct _PTPDeviceInfo PTPDeviceInfo;
+
+/* PTP storageIDs structute (returned by GetStorageIDs) */
+
+struct _PTPStorageIDs {
+ uint32_t n;
+ uint32_t *Storage;
+};
+typedef struct _PTPStorageIDs PTPStorageIDs;
+
+/* PTP StorageInfo structure (returned by GetStorageInfo) */
+struct _PTPStorageInfo {
+ uint16_t StorageType;
+ uint16_t FilesystemType;
+ uint16_t AccessCapability;
+ uint64_t MaxCapability;
+ uint64_t FreeSpaceInBytes;
+ uint32_t FreeSpaceInImages;
+ char *StorageDescription;
+ char *VolumeLabel;
+};
+typedef struct _PTPStorageInfo PTPStorageInfo;
+
+/* PTP objecthandles structure (returned by GetObjectHandles) */
+
+struct _PTPObjectHandles {
+ uint32_t n;
+ uint32_t *Handler;
+};
+typedef struct _PTPObjectHandles PTPObjectHandles;
+
+#define PTP_HANDLER_SPECIAL 0xffffffff
+#define PTP_HANDLER_ROOT 0x00000000
+
+
+/* PTP objectinfo structure (returned by GetObjectInfo) */
+
+struct _PTPObjectInfo {
+ uint32_t StorageID;
+ uint16_t ObjectFormat;
+ uint16_t ProtectionStatus;
+ uint32_t ObjectCompressedSize;
+ uint16_t ThumbFormat;
+ uint32_t ThumbCompressedSize;
+ uint32_t ThumbPixWidth;
+ uint32_t ThumbPixHeight;
+ uint32_t ImagePixWidth;
+ uint32_t ImagePixHeight;
+ uint32_t ImageBitDepth;
+ uint32_t ParentObject;
+ uint16_t AssociationType;
+ uint32_t AssociationDesc;
+ uint32_t SequenceNumber;
+ char *Filename;
+ time_t CaptureDate;
+ time_t ModificationDate;
+ char *Keywords;
+};
+typedef struct _PTPObjectInfo PTPObjectInfo;
+
+/* max ptp string length INCLUDING terminating null character */
+
+#define PTP_MAXSTRLEN 255
+
+/* PTP Object Format Codes */
+
+/* ancillary formats */
+#define PTP_OFC_Undefined 0x3000
+#define PTP_OFC_Association 0x3001
+#define PTP_OFC_Script 0x3002
+#define PTP_OFC_Executable 0x3003
+#define PTP_OFC_Text 0x3004
+#define PTP_OFC_HTML 0x3005
+#define PTP_OFC_DPOF 0x3006
+#define PTP_OFC_AIFF 0x3007
+#define PTP_OFC_WAV 0x3008
+#define PTP_OFC_MP3 0x3009
+#define PTP_OFC_AVI 0x300A
+#define PTP_OFC_MPEG 0x300B
+#define PTP_OFC_ASF 0x300C
+#define PTP_OFC_QT 0x300D /* guessing */
+/* image formats */
+#define PTP_OFC_EXIF_JPEG 0x3801
+#define PTP_OFC_TIFF_EP 0x3802
+#define PTP_OFC_FlashPix 0x3803
+#define PTP_OFC_BMP 0x3804
+#define PTP_OFC_CIFF 0x3805
+#define PTP_OFC_Undefined_0x3806 0x3806
+#define PTP_OFC_GIF 0x3807
+#define PTP_OFC_JFIF 0x3808
+#define PTP_OFC_PCD 0x3809
+#define PTP_OFC_PICT 0x380A
+#define PTP_OFC_PNG 0x380B
+#define PTP_OFC_Undefined_0x380C 0x380C
+#define PTP_OFC_TIFF 0x380D
+#define PTP_OFC_TIFF_IT 0x380E
+#define PTP_OFC_JP2 0x380F
+#define PTP_OFC_JPX 0x3810
+/* Eastman Kodak extension ancillary format */
+#define PTP_OFC_EK_M3U 0xb002
+
+/* PTP Association Types */
+
+#define PTP_AT_Undefined 0x0000
+#define PTP_AT_GenericFolder 0x0001
+#define PTP_AT_Album 0x0002
+#define PTP_AT_TimeSequence 0x0003
+#define PTP_AT_HorizontalPanoramic 0x0004
+#define PTP_AT_VerticalPanoramic 0x0005
+#define PTP_AT_2DPanoramic 0x0006
+#define PTP_AT_AncillaryData 0x0007
+
+/* PTP Protection Status */
+
+#define PTP_PS_NoProtection 0x0000
+#define PTP_PS_ReadOnly 0x0001
+
+/* PTP Storage Types */
+
+#define PTP_ST_Undefined 0x0000
+#define PTP_ST_FixedROM 0x0001
+#define PTP_ST_RemovableROM 0x0002
+#define PTP_ST_FixedRAM 0x0003
+#define PTP_ST_RemovableRAM 0x0004
+
+/* PTP FilesystemType Values */
+
+#define PTP_FST_Undefined 0x0000
+#define PTP_FST_GenericFlat 0x0001
+#define PTP_FST_GenericHierarchical 0x0002
+#define PTP_FST_DCF 0x0003
+
+/* PTP StorageInfo AccessCapability Values */
+
+#define PTP_AC_ReadWrite 0x0000
+#define PTP_AC_ReadOnly 0x0001
+#define PTP_AC_ReadOnly_with_Object_Deletion 0x0002
+
+/* Property Describing Dataset, Range Form */
+
+struct _PTPPropDescRangeForm {
+ void * MinimumValue;
+ void * MaximumValue;
+ void * StepSize;
+};
+typedef struct _PTPPropDescRangeForm PTPPropDescRangeForm;
+
+/* Property Describing Dataset, Enum Form */
+
+struct _PTPPropDescEnumForm {
+ uint16_t NumberOfValues;
+ void ** SupportedValue;
+};
+typedef struct _PTPPropDescEnumForm PTPPropDescEnumForm;
+
+/* Device Property Describing Dataset (DevicePropDesc) */
+
+struct _PTPDevicePropDesc {
+ uint16_t DevicePropertyCode;
+ uint16_t DataType;
+ uint8_t GetSet;
+ void * FactoryDefaultValue;
+ void * CurrentValue;
+ uint8_t FormFlag;
+ union {
+ PTPPropDescEnumForm Enum;
+ PTPPropDescRangeForm Range;
+ } FORM;
+};
+typedef struct _PTPDevicePropDesc PTPDevicePropDesc;
+
+
+/* Property Describing Dataset, Range Form */
+
+struct _PTPObjPropDescRangeForm {
+ void * MinimumValue;
+ void * MaximumValue;
+ void * StepSize;
+};
+typedef struct _PTPObjPropDescRangeForm PTPObjPropDescRangeForm;
+
+/* Property Describing Dataset, Enum Form */
+
+struct _PTPObjPropDescEnumForm {
+ uint16_t NumberOfValues;
+ void ** SupportedValue;
+};
+typedef struct _PTPObjPropDescEnumForm PTPObjPropDescEnumForm;
+
+/* Canon filesystem's folder entry Dataset */
+
+#define PTP_CANON_FilenameBufferLen 13
+#define PTP_CANON_FolderEntryLen sizeof(PTPCANONFolderEntry)
+
+struct _PTPCANONFolderEntry {
+ uint32_t ObjectHandle;
+ uint16_t ObjectFormatCode;
+ uint8_t Flags;
+ uint32_t ObjectSize;
+ time_t Time;
+ char Filename[PTP_CANON_FilenameBufferLen];
+};
+typedef struct _PTPCANONFolderEntry PTPCANONFolderEntry;
+
+/* DataType Codes */
+
+#define PTP_DTC_UNDEF 0x0000
+#define PTP_DTC_INT8 0x0001
+#define PTP_DTC_UINT8 0x0002
+#define PTP_DTC_INT16 0x0003
+#define PTP_DTC_UINT16 0x0004
+#define PTP_DTC_INT32 0x0005
+#define PTP_DTC_UINT32 0x0006
+#define PTP_DTC_INT64 0x0007
+#define PTP_DTC_UINT64 0x0008
+#define PTP_DTC_INT128 0x0009
+#define PTP_DTC_UINT128 0x000A
+#define PTP_DTC_AINT8 0x4001
+#define PTP_DTC_AUINT8 0x4002
+#define PTP_DTC_AINT16 0x4003
+#define PTP_DTC_AUINT16 0x4004
+#define PTP_DTC_AINT32 0x4005
+#define PTP_DTC_AUINT32 0x4006
+#define PTP_DTC_AINT64 0x4007
+#define PTP_DTC_AUINT64 0x4008
+#define PTP_DTC_AINT128 0x4009
+#define PTP_DTC_AUINT128 0x400A
+#define PTP_DTC_STR 0xFFFF
+
+/* unicode string defined by RAL */
+#define PTP_DTC_UNISTR 0xFFFE
+
+/* Device Properties Codes */
+
+#define PTP_DPC_Undefined 0x5000
+#define PTP_DPC_BatteryLevel 0x5001
+#define PTP_DPC_FunctionalMode 0x5002
+#define PTP_DPC_ImageSize 0x5003
+#define PTP_DPC_CompressionSetting 0x5004
+#define PTP_DPC_WhiteBalance 0x5005
+#define PTP_DPC_RGBGain 0x5006
+#define PTP_DPC_FNumber 0x5007
+#define PTP_DPC_FocalLength 0x5008
+#define PTP_DPC_FocusDistance 0x5009
+#define PTP_DPC_FocusMode 0x500A
+#define PTP_DPC_ExposureMeteringMode 0x500B
+#define PTP_DPC_FlashMode 0x500C
+#define PTP_DPC_ExposureTime 0x500D
+#define PTP_DPC_ExposureProgramMode 0x500E
+#define PTP_DPC_ExposureIndex 0x500F
+#define PTP_DPC_ExposureBiasCompensation 0x5010
+#define PTP_DPC_DateTime 0x5011
+#define PTP_DPC_CaptureDelay 0x5012
+#define PTP_DPC_StillCaptureMode 0x5013
+#define PTP_DPC_Contrast 0x5014
+#define PTP_DPC_Sharpness 0x5015
+#define PTP_DPC_DigitalZoom 0x5016
+#define PTP_DPC_EffectMode 0x5017
+#define PTP_DPC_BurstNumber 0x5018
+#define PTP_DPC_BurstInterval 0x5019
+#define PTP_DPC_TimelapseNumber 0x501A
+#define PTP_DPC_TimelapseInterval 0x501B
+#define PTP_DPC_FocusMeteringMode 0x501C
+#define PTP_DPC_UploadURL 0x501D
+#define PTP_DPC_Artist 0x501E
+#define PTP_DPC_CopyrightInfo 0x501F
+
+/* Proprietary vendor extension device property mask */
+#define PTP_DPC_EXTENSION_MASK 0xF000
+#define PTP_DPC_EXTENSION 0xD000
+
+/* Vendor Extensions device property codes */
+
+/* Eastman Kodak extension device property codes */
+#define PTP_DPC_EK_ColorTemperature 0xD001
+#define PTP_DPC_EK_DateTimeStampFormat 0xD002
+#define PTP_DPC_EK_BeepMode 0xD003
+#define PTP_DPC_EK_VideoOut 0xD004
+#define PTP_DPC_EK_PowerSaving 0xD005
+#define PTP_DPC_EK_UI_Language 0xD006
+/* Canon extension device property codes */
+#define PTP_DPC_CANON_BeepMode 0xD001
+#define PTP_DPC_CANON_ViewfinderMode 0xD003
+#define PTP_DPC_CANON_ImageQuality 0xD006
+#define PTP_DPC_CANON_D007 0xD007
+#define PTP_DPC_CANON_ImageSize 0xD008
+#define PTP_DPC_CANON_FlashMode 0xD00A
+#define PTP_DPC_CANON_TvAvSetting 0xD00C
+#define PTP_DPC_CANON_MeteringMode 0xD010
+#define PTP_DPC_CANON_MacroMode 0xD011
+#define PTP_DPC_CANON_FocusingPoint 0xD012
+#define PTP_DPC_CANON_WhiteBalance 0xD013
+#define PTP_DPC_CANON_ISOSpeed 0xD01C
+#define PTP_DPC_CANON_Aperture 0xD01D
+#define PTP_DPC_CANON_ShutterSpeed 0xD01E
+#define PTP_DPC_CANON_ExpCompensation 0xD01F
+#define PTP_DPC_CANON_D029 0xD029
+#define PTP_DPC_CANON_Zoom 0xD02A
+#define PTP_DPC_CANON_SizeQualityMode 0xD02C
+#define PTP_DPC_CANON_FlashMemory 0xD031
+#define PTP_DPC_CANON_CameraModel 0xD032
+#define PTP_DPC_CANON_CameraOwner 0xD033
+#define PTP_DPC_CANON_UnixTime 0xD034
+#define PTP_DPC_CANON_RealImageWidth 0xD039
+#define PTP_DPC_CANON_PhotoEffect 0xD040
+#define PTP_DPC_CANON_AssistLight 0xD041
+#define PTP_DPC_CANON_D045 0xD045
+
+/* Nikon extension device property codes */
+#define PTP_DPC_NIKON_ShootingBank 0xD010
+#define PTP_DPC_NIKON_ShootingBankNameA 0xD011
+#define PTP_DPC_NIKON_ShootingBankNameB 0xD012
+#define PTP_DPC_NIKON_ShootingBankNameC 0xD013
+#define PTP_DPC_NIKON_ShootingBankNameD 0xD014
+#define PTP_DPC_NIKON_RawCompression 0xD016
+#define PTP_DPC_NIKON_WhiteBalanceAutoBias 0xD017
+#define PTP_DPC_NIKON_WhiteBalanceTungstenBias 0xD018
+#define PTP_DPC_NIKON_WhiteBalanceFlourescentBias 0xD019
+#define PTP_DPC_NIKON_WhiteBalanceDaylightBias 0xD01a
+#define PTP_DPC_NIKON_WhiteBalanceFlashBias 0xD01b
+#define PTP_DPC_NIKON_WhiteBalanceCloudyBias 0xD01c
+#define PTP_DPC_NIKON_WhiteBalanceShadeBias 0xD01d
+#define PTP_DPC_NIKON_WhiteBalanceColourTemperature 0xD01e
+#define PTP_DPC_NIKON_ImageSharpening 0xD02a
+#define PTP_DPC_NIKON_ToneCompensation 0xD02b
+#define PTP_DPC_NIKON_ColourMode 0xD02c
+#define PTP_DPC_NIKON_HueAdjustment 0xD02d
+#define PTP_DPC_NIKON_NonCPULensDataFocalLength 0xD02e
+#define PTP_DPC_NIKON_NonCPULensDataMaximumAperture 0xD02f
+#define PTP_DPC_NIKON_CSMMenuBankSelect 0xD040
+#define PTP_DPC_NIKON_MenuBankNameA 0xD041
+#define PTP_DPC_NIKON_MenuBankNameB 0xD042
+#define PTP_DPC_NIKON_MenuBankNameC 0xD043
+#define PTP_DPC_NIKON_MenuBankNameD 0xD044
+#define PTP_DPC_NIKON_A1AFCModePriority 0xD048
+#define PTP_DPC_NIKON_A2AFSModePriority 0xD049
+#define PTP_DPC_NIKON_A3GroupDynamicAF 0xD04a
+#define PTP_DPC_NIKON_A4AFActivation 0xD04b
+#define PTP_DPC_NIKON_A5FocusAreaIllumManualFocus 0xD04c
+#define PTP_DPC_NIKON_FocusAreaIllumContinuous 0xD04d
+#define PTP_DPC_NIKON_FocusAreaIllumWhenSelected 0xD04e
+#define PTP_DPC_NIKON_A6FocusArea 0xD04f
+#define PTP_DPC_NIKON_A7VerticalAFON 0xD050
+#define PTP_DPC_NIKON_B1ISOAuto 0xD054
+#define PTP_DPC_NIKON_B2ISOStep 0xD055
+#define PTP_DPC_NIKON_B3EVStep 0xD056
+#define PTP_DPC_NIKON_B4ExposureCompEv 0xD057
+#define PTP_DPC_NIKON_B5ExposureComp 0xD058
+#define PTP_DPC_NIKON_B6CenterWeightArea 0xD059
+#define PTP_DPC_NIKON_C1AELock 0xD05e
+#define PTP_DPC_NIKON_C2AELAFL 0xD05f
+#define PTP_DPC_NIKON_C3AutoMeterOff 0xD062
+#define PTP_DPC_NIKON_C4SelfTimer 0xD063
+#define PTP_DPC_NIKON_C5MonitorOff 0xD064
+#define PTP_DPC_NIKON_D1ShootingSpeed 0xD068
+#define PTP_DPC_NIKON_D2MaximumShots 0xD069
+#define PTP_DPC_NIKON_D3ExpDelayMode 0xD06a
+#define PTP_DPC_NIKON_D4LongExposureNoiseReduction 0xD06b
+#define PTP_DPC_NIKON_D5FileNumberSequence 0xD06c
+#define PTP_DPC_NIKON_D6ControlPanelFinderRearControl 0xD06d
+#define PTP_DPC_NIKON_ControlPanelFinderViewfinder 0xD06e
+#define PTP_DPC_NIKON_D7Illumination 0xD06f
+#define PTP_DPC_NIKON_E1FlashSyncSpeed 0xD074
+#define PTP_DPC_NIKON_E2FlashShutterSpeed 0xD075
+#define PTP_DPC_NIKON_E3AAFlashMode 0xD076
+#define PTP_DPC_NIKON_E4ModelingFlash 0xD077
+#define PTP_DPC_NIKON_E5AutoBracketSet 0xD078
+#define PTP_DPC_NIKON_E6ManualModeBracketing 0xD079
+#define PTP_DPC_NIKON_E7AutoBracketOrder 0xD07a
+#define PTP_DPC_NIKON_E8AutoBracketSelection 0xD07b
+#define PTP_DPC_NIKON_F1CenterButtonShootingMode 0xD080
+#define PTP_DPC_NIKON_CenterButtonPlaybackMode 0xD081
+#define PTP_DPC_NIKON_F2Multiselector 0xD082
+#define PTP_DPC_NIKON_F3PhotoInfoPlayback 0xD083
+#define PTP_DPC_NIKON_F4AssignFuncButton 0xD084
+#define PTP_DPC_NIKON_F5CustomizeCommDials 0xD085
+#define PTP_DPC_NIKON_ChangeMainSub 0xD086
+#define PTP_DPC_NIKON_ApertureSetting 0xD087
+#define PTP_DPC_NIKON_MenusAndPlayback 0xD088
+#define PTP_DPC_NIKON_F6ButtonsAndDials 0xD089
+#define PTP_DPC_NIKON_F7NoCFCard 0xD08a
+#define PTP_DPC_NIKON_ImageCommentString 0xD090
+#define PTP_DPC_NIKON_ImageCommentAttached 0xD091
+#define PTP_DPC_NIKON_AutoImageRotation 0xD092
+#define PTP_DPC_NIKON_ExposureBracketingOnOff 0xD0c0
+#define PTP_DPC_NIKON_ExposureBracketingIntervalDist 0xD0c1
+#define PTP_DPC_NIKON_ExposureBracketingNumBracketPlace 0xD0c2
+#define PTP_DPC_NIKON_AutofocusLCDTopMode2 0xD107
+#define PTP_DPC_NIKON_AutofocusLCDTopMode3AndMode4 0xD108
+#define PTP_DPC_NIKON_LightMeter 0xD10a
+#define PTP_DPC_NIKON_ExposureApertureLock 0xD111
+#define PTP_DPC_NIKON_MaximumShots 0xD103
+#define PTP_DPC_NIKON_Beep 0xD160
+#define PTP_DPC_NIKON_AFC 0xD161
+#define PTP_DPC_NIKON_AFLampOff 0xD163
+#define PTP_DPC_NIKON_PADVPMode 0xD164
+#define PTP_DPC_NIKON_ReviewOff 0xD165
+#define PTP_DPC_NIKON_GridDisplay 0xD16c
+#define PTP_DPC_NIKON_AFAreaIllumination 0xD166
+#define PTP_DPC_NIKON_FlashMode 0xD167
+#define PTP_DPC_NIKON_FlashPower 0xD16d
+#define PTP_DPC_NIKON_FlashSignOff 0xD169
+#define PTP_DPC_NIKON_RemoteTimeout 0xD16B
+#define PTP_DPC_NIKON_LowLight 0xD1B0
+#define PTP_DPC_NIKON_ImageCommentString 0xD090
+#define PTP_DPC_NIKON_FlashOpen 0xD1C0
+#define PTP_DPC_NIKON_FlashCharged 0xD1C1
+#define PTP_DPC_NIKON_LensID 0xD0E0
+#define PTP_DPC_NIKON_FocalLengthMin 0xD0E3
+#define PTP_DPC_NIKON_FocalLengthMax 0xD0E4
+#define PTP_DPC_NIKON_MaxApAtMinFocalLength 0xD0E5
+#define PTP_DPC_NIKON_MaxApAtMaxFocalLength 0xD0E6
+#define PTP_DPC_NIKON_FlashExposureCompensation 0xD126
+#define PTP_DPC_NIKON_ExtendedCSMMenu 0xD180
+#define PTP_DPC_NIKON_OptimiseImage 0xD140
+
+/* Device Property Form Flag */
+
+#define PTP_DPFF_None 0x00
+#define PTP_DPFF_Range 0x01
+#define PTP_DPFF_Enumeration 0x02
+
+/* Device Property GetSet type */
+#define PTP_DPGS_Get 0x00
+#define PTP_DPGS_GetSet 0x01
+
+/* Glue stuff starts here */
+
+typedef struct _PTPParams PTPParams;
+
+/* raw write functions */
+typedef short (* PTPIOReadFunc) (unsigned char *bytes, unsigned int size,
+ void *data);
+typedef short (* PTPIOWriteFunc)(unsigned char *bytes, unsigned int size,
+ void *data);
+/*
+ * This functions take PTP oriented arguments and send them over an
+ * appropriate data layer doing byteorder conversion accordingly.
+ */
+typedef uint16_t (* PTPIOSendReq) (PTPParams* params, PTPContainer* req);
+typedef uint16_t (* PTPIOSendData) (PTPParams* params, PTPContainer* ptp,
+ unsigned char *data, unsigned int size);
+typedef uint16_t (* PTPIOGetResp) (PTPParams* params, PTPContainer* resp);
+typedef uint16_t (* PTPIOGetData) (PTPParams* params, PTPContainer* ptp,
+ unsigned char **data);
+/* debug functions */
+typedef void (* PTPErrorFunc) (void *data, const char *format, va_list args);
+typedef void (* PTPDebugFunc) (void *data, const char *format, va_list args);
+
+struct _PTPParams {
+ /* data layer byteorder */
+ uint8_t byteorder;
+
+ /* Data layer IO functions */
+ PTPIOReadFunc read_func;
+ PTPIOWriteFunc write_func;
+ PTPIOReadFunc check_int_func;
+ PTPIOReadFunc check_int_fast_func;
+
+ /* Custom IO functions */
+ PTPIOSendReq sendreq_func;
+ PTPIOSendData senddata_func;
+ PTPIOGetResp getresp_func;
+ PTPIOGetData getdata_func;
+ PTPIOGetResp event_check;
+ PTPIOGetResp event_wait;
+
+ /* Custom error and debug function */
+ PTPErrorFunc error_func;
+ PTPDebugFunc debug_func;
+
+ /* Data passed to above functions */
+ void *data;
+
+ /* ptp transaction ID */
+ uint32_t transaction_id;
+ /* ptp session ID */
+ uint32_t session_id;
+
+ /* internal structures used by ptp driver */
+ PTPObjectHandles handles;
+ PTPObjectInfo * objectinfo;
+ PTPDeviceInfo deviceinfo;
+};
+
+/* last, but not least - ptp functions */
+uint16_t ptp_usb_sendreq (PTPParams* params, PTPContainer* req);
+uint16_t ptp_usb_senddata (PTPParams* params, PTPContainer* ptp,
+ unsigned char *data, unsigned int size);
+uint16_t ptp_usb_getresp (PTPParams* params, PTPContainer* resp);
+uint16_t ptp_usb_getdata (PTPParams* params, PTPContainer* ptp,
+ unsigned char **data);
+uint16_t ptp_usb_event_check (PTPParams* params, PTPContainer* event);
+uint16_t ptp_usb_event_wait (PTPParams* params, PTPContainer* event);
+
+uint16_t ptp_getdeviceinfo (PTPParams* params, PTPDeviceInfo* deviceinfo);
+
+uint16_t ptp_opensession (PTPParams *params, uint32_t session);
+uint16_t ptp_closesession (PTPParams *params);
+
+uint16_t ptp_getstorageids (PTPParams* params, PTPStorageIDs* storageids);
+uint16_t ptp_getstorageinfo (PTPParams* params, uint32_t storageid,
+ PTPStorageInfo* storageinfo);
+
+uint16_t ptp_getobjecthandles (PTPParams* params, uint32_t storage,
+ uint32_t objectformatcode,
+ uint32_t associationOH,
+ PTPObjectHandles* objecthandles);
+
+uint16_t ptp_getobjectinfo (PTPParams *params, uint32_t handle,
+ PTPObjectInfo* objectinfo);
+
+uint16_t ptp_getobject (PTPParams *params, uint32_t handle,
+ char** object);
+uint16_t ptp_getthumb (PTPParams *params, uint32_t handle,
+ char** object);
+
+uint16_t ptp_deleteobject (PTPParams* params, uint32_t handle,
+ uint32_t ofc);
+
+uint16_t ptp_sendobjectinfo (PTPParams* params, uint32_t* store,
+ uint32_t* parenthandle, uint32_t* handle,
+ PTPObjectInfo* objectinfo);
+uint16_t ptp_sendobject (PTPParams* params, char* object,
+ uint32_t size);
+
+uint16_t ptp_initiatecapture (PTPParams* params, uint32_t storageid,
+ uint32_t ofc);
+
+uint16_t ptp_getdevicepropdesc (PTPParams* params, uint16_t propcode,
+ PTPDevicePropDesc *devicepropertydesc);
+uint16_t ptp_getdevicepropvalue (PTPParams* params, uint16_t propcode,
+ void** value, uint16_t datatype);
+uint16_t ptp_setdevicepropvalue (PTPParams* params, uint16_t propcode,
+ void* value, uint16_t datatype);
+
+
+uint16_t ptp_ek_sendfileobjectinfo (PTPParams* params, uint32_t* store,
+ uint32_t* parenthandle, uint32_t* handle,
+ PTPObjectInfo* objectinfo);
+uint16_t ptp_ek_sendfileobject (PTPParams* params, char* object,
+ uint32_t size);
+
+/* Canon PTP extensions */
+
+uint16_t ptp_canon_getobjectsize (PTPParams* params, uint32_t handle,
+ uint32_t p2, uint32_t* size, uint32_t* rp2);
+
+uint16_t ptp_canon_startshootingmode (PTPParams* params);
+uint16_t ptp_canon_endshootingmode (PTPParams* params);
+
+uint16_t ptp_canon_viewfinderon (PTPParams* params);
+uint16_t ptp_canon_viewfinderoff (PTPParams* params);
+
+uint16_t ptp_canon_reflectchanges (PTPParams* params, uint32_t p1);
+uint16_t ptp_canon_checkevent (PTPParams* params,
+ PTPUSBEventContainer* event, int* isevent);
+uint16_t ptp_canon_focuslock (PTPParams* params);
+uint16_t ptp_canon_focusunlock (PTPParams* params);
+uint16_t ptp_canon_initiatecaptureinmemory (PTPParams* params);
+uint16_t ptp_canon_getpartialobject (PTPParams* params, uint32_t handle,
+ uint32_t offset, uint32_t size,
+ uint32_t pos, char** block,
+ uint32_t* readnum);
+uint16_t ptp_canon_getviewfinderimage (PTPParams* params, char** image,
+ uint32_t* size);
+uint16_t ptp_canon_getchanges (PTPParams* params, uint16_t** props,
+ uint32_t* propnum);
+uint16_t ptp_canon_getfolderentries (PTPParams* params, uint32_t store,
+ uint32_t p2, uint32_t parenthandle,
+ uint32_t handle,
+ PTPCANONFolderEntry** entries,
+ uint32_t* entnum);
+
+
+/* Non PTP protocol functions */
+int ptp_operation_issupported (PTPParams* params, uint16_t operation);
+int ptp_property_issupported (PTPParams* params, uint16_t property);
+
+void ptp_free_devicepropdesc (PTPDevicePropDesc* dpd);
+void ptp_free_deviceinfo (PTPDeviceInfo* di);
+void ptp_perror (PTPParams* params, uint16_t error);
+const char*
+ptp_get_operation_name (PTPParams* params, uint16_t oc);
+const char*
+ptp_get_property_name (PTPParams* params, uint16_t dpc);
+
+/* added to header file by RAL */
+uint16_t ptp_transaction (PTPParams* params, PTPContainer* ptp,
+ uint16_t flags, unsigned int sendlen, char** data);
+
+/* below moved to header file by RAL */
+#define CHECK_PTP_RC(result) {uint16_t r=(result); if (r!=PTP_RC_OK) return r;}
+
+#define PTP_CNT_INIT(cnt) {memset(&cnt,0,sizeof(cnt));}
+
+/* Transaction data phase description */
+#define PTP_DP_NODATA 0x0000 /* no data phase */
+#define PTP_DP_SENDDATA 0x0001 /* sending data */
+#define PTP_DP_GETDATA 0x0002 /* receiving data */
+#define PTP_DP_DATA_MASK 0x00ff /* data phase mask */
+
+/* Number of PTP Request phase parameters */
+#define PTP_RQ_PARAM0 0x0000 /* zero parameters */
+#define PTP_RQ_PARAM1 0x0100 /* one parameter */
+#define PTP_RQ_PARAM2 0x0200 /* two parameters */
+#define PTP_RQ_PARAM3 0x0300 /* three parameters */
+#define PTP_RQ_PARAM4 0x0400 /* four parameters */
+#define PTP_RQ_PARAM5 0x0500 /* five parameters */
+
+#endif /* __PTP_H__ */