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(&params, &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 (&params, &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(&params, &params.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(&params,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, &params, interface_number);
+  ptp_free_deviceinfo(&params.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__ */