From: hackbard <hackbard>
Date: Thu, 19 Jan 2006 23:21:46 +0000 (+0000)
Subject: initial checkin of harald welte's original librfid project
X-Git-Url: https://hackdaworld.org/gitweb/?a=commitdiff_plain;h=6bddaf273b8eb8ececc1d4cc73dcce717c604a10;p=rfid%2Flibrfid.git

initial checkin of harald welte's original librfid project
---

6bddaf273b8eb8ececc1d4cc73dcce717c604a10
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..60549be
--- /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/LICENSING b/LICENSING
new file mode 100644
index 0000000..0ebe6bb
--- /dev/null
+++ b/LICENSING
@@ -0,0 +1,11 @@
+librfid is licensed under GNU General Public License, Version 2 as published
+by the Free Software Foundation (see the file COPYING).
+
+This means that as soon as you wish to distribute a program that links to
+librfid, that other program has to be licensed under the GPL or a compatible
+license, too.
+
+However, an alternative (royalty-based) licensing is possible.  If you want to
+create a proprieatary program based on librfid, contact Harald Welte
+<hwelte@hmw-consulting.de> for licensing details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..69140e2
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,8 @@
+AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
+
+SUBDIRS = include src utils
+LINKOPTS = -lusb
+
+$(OBJECTS): libtool
+libtool: $(LIBTOOL_DEPS)
+	$(SHELL) ./config.status --recheck
diff --git a/README b/README
new file mode 100644
index 0000000..c67a48a
--- /dev/null
+++ b/README
@@ -0,0 +1,52 @@
+librfid - low-level RFID access library
+(C) 2005 by Harald Welte <laforge@gnumonks.org>
+======================================================================
+
+This library intends to provide a reader- and (as much as possible)
+PICC / tag independent API for RFID applications.
+
+1. Supported Prodocols:
+
+At this early stage of implementaition, it offers only ISO 14443-2, ISO 14443-3
+A and B as well as ISO 14443-4 (T=CL) support.  Other protocols, both open
+(such as ISO 15693) and proprietary are to be added as soon as I find some more
+time.
+
+2. Supported Readers:
+
+At this time only the Omnikey Cardman 5121 reader is supported. 
+
+The cm5121 is a relatively stupid piece of hardware.  Basically a contact-based
+cm3121 that was enhanced by putting a Philips CL RC632 reader ASIC next to it.
+There is no RFID protocol implementation on the cm5121, everything is done on
+the host (PC) software.  Four primitives (read/write byte/fifo) are provided
+via simple PC_to_RDR_Escape CCID messages.
+
+This makes it the ideal device to learn and play with RFID, since you don't
+have any (proprietary) software interfere and puts you in full control of
+everything.
+
+Support for more devices shouldn't be too difficult to add, provided the
+devices are stupid enough.  More sophisticated readers like Integrated
+Engineering or Philips Pegoda do much of the protocol handling in firmware on a
+Microcontroller.  This makes them (at least till now) faster, but also of
+limited use, especially in education and research.
+
+So if you happen to run into any other dumb RFID readers, especially those
+based on Philips CL RC531 and RC632, adding support should be very
+straightforward.  If you want to contract me for implementing a driver backend,
+don't hesitate to contact me.
+
+3. Installation
+
+In order to run librfid, you need to provide a PC_to_RDR_Escape function to it.
+This is the low-level transport function for communicating.   Usually that function would point to a CCID device driver.
+
+My svn repository at
+https://svn.gnumonks.org/trunk/omnikey_cardman/new/userspace/ has an openct
+fork with a modified CCID driver.  It allows you to use the contact based part
+via PC/SC, CT-API, and the contactless part via librfid simultaneously.
+
+
+-- Harald Welte <laforge@gnumonks.org>
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..136a254
--- /dev/null
+++ b/TODO
@@ -0,0 +1,30 @@
+rc632:
+- fix handling of timeout (program timer of RC632)
+
+cm5121:
+- fix handling of TX or RX > 0x7f [buffer length in atmel chip?]
+
+iso14443a:
+[none]
+
+iso14443b:
+- implement 'option 2' frame markers
+- test anticollission (need multiple tags)
+
+iso15693:
+- implement anticollision
+- implement all the rest
+
+mifare_clasic:
+- figure out why authentication doensn't work, even though it is exactly like in other drivers
+
+tcl:
+- implement pps for asymmetric (rx/tx) speeds
+- test pps
+
+openct:
+- add ifdhandler driver
+
+other:
+- implementation of code for various passive tags
+- documentation
diff --git a/VERY_IMPORTANT_NOTE b/VERY_IMPORTANT_NOTE
new file mode 100644
index 0000000..b1c293a
--- /dev/null
+++ b/VERY_IMPORTANT_NOTE
@@ -0,0 +1,9 @@
+very important note!
+--------------------
+
+author: hackbard@hackdaworld.org
+
+librfid (openmrtd.org) is the project of 'Harald Welte' (laforge@gnumonks.org). i just created that repository as i want to add support for the gemini2k rfid
+devices and it is much more easier to do development via cvs.
+
+hackbard
diff --git a/autogen.sh b/autogen.sh
new file mode 100644
index 0000000..ccce4f0
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+run ()
+{
+    echo "running: $*"
+    eval $*
+
+    if test $? != 0 ; then
+	echo "error: while running '$*'"
+	exit 1
+    fi
+}
+
+run aclocal
+#run autoheader
+run libtoolize -f
+run automake -a
+run autoconf
diff --git a/ccid/ccid-driver.c b/ccid/ccid-driver.c
new file mode 100644
index 0000000..fce6d0d
--- /dev/null
+++ b/ccid/ccid-driver.c
@@ -0,0 +1,2448 @@
+/* ccid-driver.c - USB ChipCardInterfaceDevices driver
+ *	Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ *      Written by Werner Koch.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU General Public License. If you wish to
+ * allow use of your version of this file only under the terms of the
+ * GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Date: 2006-01-19 23:21:46 $
+ */
+
+
+/* CCID (ChipCardInterfaceDevices) is a specification for accessing
+   smartcard via a reader connected to the USB.  
+
+   This is a limited driver allowing to use some CCID drivers directly
+   without any other specila drivers. This is a fallback driver to be
+   used when nothing else works or the system should be kept minimal
+   for security reasons.  It makes use of the libusb library to gain
+   portable access to USB.
+
+   This driver has been tested with the SCM SCR335 and SPR532
+   smartcard readers and requires that a reader implements the TPDU
+   level exchange and does fully automatic initialization.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined(HAVE_LIBUSB) || defined(TEST)
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <usb.h>
+
+#include "ccid-driver.h"
+
+#define DRVNAME "ccid-driver: "
+
+
+/* Depending on how this source is used we either define our error
+   output to go to stderr or to the jnlib based logging functions.  We
+   use the latter when GNUPG_MAJOR_VERSION is defines or when both,
+   GNUPG_SCD_MAIN_HEADER and HAVE_JNLIB_LOGGING are defined.
+*/
+#if defined(GNUPG_MAJOR_VERSION) \
+    || (defined(GNUPG_SCD_MAIN_HEADER) && defined(HAVE_JNLIB_LOGGING))
+
+#if defined(GNUPG_SCD_MAIN_HEADER)
+#  include GNUPG_SCD_MAIN_HEADER
+#elif GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */
+#  include "options.h"
+#  include "util.h"
+#  include "memory.h"
+#  include "cardglue.h"
+# else /* This is the modularized GnuPG 1.9 or later. */
+#  include "scdaemon.h"
+#endif
+
+
+# define DEBUGOUT(t)         do { if (debug_level) \
+                                  log_debug (DRVNAME t); } while (0)
+# define DEBUGOUT_1(t,a)     do { if (debug_level) \
+                                  log_debug (DRVNAME t,(a)); } while (0)
+# define DEBUGOUT_2(t,a,b)   do { if (debug_level) \
+                                  log_debug (DRVNAME t,(a),(b)); } while (0)
+# define DEBUGOUT_3(t,a,b,c) do { if (debug_level) \
+                                  log_debug (DRVNAME t,(a),(b),(c));} while (0)
+# define DEBUGOUT_4(t,a,b,c,d) do { if (debug_level) \
+                              log_debug (DRVNAME t,(a),(b),(c),(d));} while (0)
+# define DEBUGOUT_CONT(t)    do { if (debug_level) \
+                                  log_printf (t); } while (0)
+# define DEBUGOUT_CONT_1(t,a)  do { if (debug_level) \
+                                  log_printf (t,(a)); } while (0)
+# define DEBUGOUT_CONT_2(t,a,b)   do { if (debug_level) \
+                                  log_printf (t,(a),(b)); } while (0)
+# define DEBUGOUT_CONT_3(t,a,b,c) do { if (debug_level) \
+                                  log_printf (t,(a),(b),(c)); } while (0)
+# define DEBUGOUT_LF()       do { if (debug_level) \
+                                  log_printf ("\n"); } while (0)
+
+#else /* Other usage of this source - don't use gnupg specifics. */
+
+# define DEBUGOUT(t)          do { if (debug_level) \
+                     fprintf (stderr, DRVNAME t); } while (0)
+# define DEBUGOUT_1(t,a)      do { if (debug_level) \
+                     fprintf (stderr, DRVNAME t, (a)); } while (0)
+# define DEBUGOUT_2(t,a,b)    do { if (debug_level) \
+                     fprintf (stderr, DRVNAME t, (a), (b)); } while (0)
+# define DEBUGOUT_3(t,a,b,c)  do { if (debug_level) \
+                     fprintf (stderr, DRVNAME t, (a), (b), (c)); } while (0)
+# define DEBUGOUT_4(t,a,b,c,d)  do { if (debug_level) \
+                     fprintf (stderr, DRVNAME t, (a), (b), (c), (d));} while(0)
+# define DEBUGOUT_CONT(t)     do { if (debug_level) \
+                     fprintf (stderr, t); } while (0)
+# define DEBUGOUT_CONT_1(t,a) do { if (debug_level) \
+                     fprintf (stderr, t, (a)); } while (0)
+# define DEBUGOUT_CONT_2(t,a,b) do { if (debug_level) \
+                     fprintf (stderr, t, (a), (b)); } while (0)
+# define DEBUGOUT_CONT_3(t,a,b,c) do { if (debug_level) \
+                     fprintf (stderr, t, (a), (b), (c)); } while (0)
+# define DEBUGOUT_LF()        do { if (debug_level) \
+                     putc ('\n', stderr); } while (0)
+
+#endif /* This source not used by scdaemon. */
+
+
+
+enum {
+  RDR_to_PC_NotifySlotChange= 0x50,
+  RDR_to_PC_HardwareError   = 0x51,
+
+  PC_to_RDR_SetParameters   = 0x61,
+  PC_to_RDR_IccPowerOn      = 0x62,
+  PC_to_RDR_IccPowerOff     = 0x63,
+  PC_to_RDR_GetSlotStatus   = 0x65,
+  PC_to_RDR_Secure          = 0x69,
+  PC_to_RDR_T0APDU          = 0x6a,
+  PC_to_RDR_Escape          = 0x6b,
+  PC_to_RDR_GetParameters   = 0x6c,
+  PC_to_RDR_ResetParameters = 0x6d,
+  PC_to_RDR_IccClock        = 0x6e,
+  PC_to_RDR_XfrBlock        = 0x6f,
+  PC_to_RDR_Mechanical      = 0x71,
+  PC_to_RDR_Abort           = 0x72,
+  PC_to_RDR_SetDataRate     = 0x73,
+
+  RDR_to_PC_DataBlock       = 0x80,
+  RDR_to_PC_SlotStatus      = 0x81,
+  RDR_to_PC_Parameters      = 0x82,
+  RDR_to_PC_Escape          = 0x83,
+  RDR_to_PC_DataRate        = 0x84
+};
+
+
+/* Two macro to detect whether a CCID command has failed and to get
+   the error code.  These macros assume that we can access the
+   mandatory first 10 bytes of a CCID message in BUF. */
+#define CCID_COMMAND_FAILED(buf) ((buf)[7] & 0x40)
+#define CCID_ERROR_CODE(buf)     (((unsigned char *)(buf))[8])
+
+
+/* We need to know the vendor to do some hacks. */
+enum {
+  VENDOR_SCM    = 0x04e6,
+  VENDOR_CHERRY = 0x046a,
+  VENDOR_OMNIKEY= 0x076b,
+  VENDOR_GEMPC  = 0x08e6
+};
+
+
+/* Store information on the driver's state.  A pointer to such a
+   structure is used as handle for most functions. */
+struct ccid_driver_s 
+{
+  usb_dev_handle *idev;
+  char *rid;
+  unsigned short id_vendor;
+  unsigned short id_product;
+  unsigned short bcd_device;
+  int ifc_no;
+  int ep_bulk_out;
+  int ep_bulk_in;
+  int ep_intr;
+  int seqno;
+  unsigned char t1_ns;
+  unsigned char t1_nr;
+  int nonnull_nad;
+  int auto_ifsd;
+  int max_ifsd;
+  int ifsd;
+  int powered_off;
+  int has_pinpad;
+  int apdu_level;     /* Reader supports short APDU level exchange.  */
+};
+
+
+static int initialized_usb; /* Tracks whether USB has been initialized. */
+static int debug_level;     /* Flag to control the debug output. 
+                               0 = No debugging
+                               1 = USB I/O info
+                               2 = T=1 protocol tracing
+                              */
+
+
+static unsigned int compute_edc (const unsigned char *data, size_t datalen,
+                                 int use_crc);
+static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen);
+static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
+                    size_t *nread, int expected_type, int seqno, int timeout,
+                    int no_debug);
+
+/* Convert a little endian stored 4 byte value into an unsigned
+   integer. */
+static unsigned int 
+convert_le_u32 (const unsigned char *buf)
+{
+  return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 
+}
+
+static void
+set_msg_len (unsigned char *msg, unsigned int length)
+{
+  msg[1] = length;
+  msg[2] = length >> 8;
+  msg[3] = length >> 16;
+  msg[4] = length >> 24;
+}
+
+
+/* Pint an error message for a failed CCID command including a textual
+   error code.  MSG is shall be the CCID message of at least 10 bytes. */
+static void
+print_command_failed (const unsigned char *msg)
+{
+  const char *t;
+  char buffer[100];
+  int ec;
+
+  if (!debug_level)
+    return;
+
+  ec = CCID_ERROR_CODE (msg);
+  switch (ec)
+    {
+    case 0x00: t = "Command not supported"; break;
+    
+    case 0xE0: t = "Slot busy"; break;
+    case 0xEF: t = "PIN cancelled"; break;
+    case 0xF0: t = "PIN timeout"; break;
+
+    case 0xF2: t = "Automatic sequence ongoing"; break;
+    case 0xF3: t = "Deactivated Protocol"; break;
+    case 0xF4: t = "Procedure byte conflict"; break;
+    case 0xF5: t = "ICC class not supported"; break;
+    case 0xF6: t = "ICC protocol not supported"; break;
+    case 0xF7: t = "Bad checksum in ATR"; break;
+    case 0xF8: t = "Bad TS in ATR"; break;
+
+    case 0xFB: t = "An all inclusive hardware error occurred"; break;
+    case 0xFC: t = "Overrun error while talking to the ICC"; break;
+    case 0xFD: t = "Parity error while talking to the ICC"; break;
+    case 0xFE: t = "CCID timed out while talking to the ICC"; break;
+    case 0xFF: t = "Host aborted the current activity"; break;
+
+    default:
+      if (ec > 0 && ec < 128)
+        sprintf (buffer, "Parameter error at offset %d", ec);
+      else
+        sprintf (buffer, "Error code %02X", ec);
+      t = buffer;
+      break;
+    }
+  DEBUGOUT_1 ("CCID command failed: %s\n", t);
+}
+  
+
+
+
+/* Parse a CCID descriptor, optionally print all available features
+   and test whether this reader is usable by this driver.  Returns 0
+   if it is usable.
+
+   Note, that this code is based on the one in lsusb.c of the
+   usb-utils package, I wrote on 2003-09-01. -wk. */
+static int
+parse_ccid_descriptor (ccid_driver_t handle,
+                       const unsigned char *buf, size_t buflen)
+{
+  unsigned int i;
+  unsigned int us;
+  int have_t1 = 0, have_tpdu=0, have_auto_conf = 0;
+
+
+  handle->nonnull_nad = 0;
+  handle->auto_ifsd = 0;
+  handle->max_ifsd = 32;
+  handle->ifsd = 0;
+  handle->has_pinpad = 0;
+  handle->apdu_level = 0;
+  DEBUGOUT_3 ("idVendor: %04X  idProduct: %04X  bcdDevice: %04X\n",
+              handle->id_vendor, handle->id_product, handle->bcd_device);
+  if (buflen < 54 || buf[0] < 54)
+    {
+      DEBUGOUT ("CCID device descriptor is too short\n");
+      return -1;
+    }
+
+  DEBUGOUT   ("ChipCard Interface Descriptor:\n");
+  DEBUGOUT_1 ("  bLength             %5u\n", buf[0]);
+  DEBUGOUT_1 ("  bDescriptorType     %5u\n", buf[1]);
+  DEBUGOUT_2 ("  bcdCCID             %2x.%02x", buf[3], buf[2]);
+    if (buf[3] != 1 || buf[2] != 0) 
+      DEBUGOUT_CONT("  (Warning: Only accurate for version 1.0)");
+  DEBUGOUT_LF ();
+
+  DEBUGOUT_1 ("  nMaxSlotIndex       %5u\n", buf[4]);
+  DEBUGOUT_2 ("  bVoltageSupport     %5u  %s\n",
+              buf[5], (buf[5] == 1? "5.0V" : buf[5] == 2? "3.0V"
+                       : buf[5] == 3? "1.8V":"?"));
+
+  us = convert_le_u32 (buf+6);
+  DEBUGOUT_1 ("  dwProtocols         %5u ", us);
+  if ((us & 1))
+    DEBUGOUT_CONT (" T=0");
+  if ((us & 2))
+    {
+      DEBUGOUT_CONT (" T=1");
+      have_t1 = 1;
+    }
+  if ((us & ~3))
+    DEBUGOUT_CONT (" (Invalid values detected)");
+  DEBUGOUT_LF ();
+
+  us = convert_le_u32(buf+10);
+  DEBUGOUT_1 ("  dwDefaultClock      %5u\n", us);
+  us = convert_le_u32(buf+14);
+  DEBUGOUT_1 ("  dwMaxiumumClock     %5u\n", us);
+  DEBUGOUT_1 ("  bNumClockSupported  %5u\n", buf[18]);
+  us = convert_le_u32(buf+19);
+  DEBUGOUT_1 ("  dwDataRate        %7u bps\n", us);
+  us = convert_le_u32(buf+23);
+  DEBUGOUT_1 ("  dwMaxDataRate     %7u bps\n", us);
+  DEBUGOUT_1 ("  bNumDataRatesSupp.  %5u\n", buf[27]);
+        
+  us = convert_le_u32(buf+28);
+  DEBUGOUT_1 ("  dwMaxIFSD           %5u\n", us);
+  handle->max_ifsd = us;
+
+  us = convert_le_u32(buf+32);
+  DEBUGOUT_1 ("  dwSyncProtocols  %08X ", us);
+  if ((us&1))
+    DEBUGOUT_CONT ( " 2-wire");
+  if ((us&2))
+    DEBUGOUT_CONT ( " 3-wire");
+  if ((us&4))
+    DEBUGOUT_CONT ( " I2C");
+  DEBUGOUT_LF ();
+
+  us = convert_le_u32(buf+36);
+  DEBUGOUT_1 ("  dwMechanical     %08X ", us);
+  if ((us & 1))
+    DEBUGOUT_CONT (" accept");
+  if ((us & 2))
+    DEBUGOUT_CONT (" eject");
+  if ((us & 4))
+    DEBUGOUT_CONT (" capture");
+  if ((us & 8))
+    DEBUGOUT_CONT (" lock");
+  DEBUGOUT_LF ();
+
+  us = convert_le_u32(buf+40);
+  DEBUGOUT_1 ("  dwFeatures       %08X\n", us);
+  if ((us & 0x0002))
+    {
+      DEBUGOUT ("    Auto configuration based on ATR\n");
+      have_auto_conf = 1;
+    }
+  if ((us & 0x0004))
+    DEBUGOUT ("    Auto activation on insert\n");
+  if ((us & 0x0008))
+    DEBUGOUT ("    Auto voltage selection\n");
+  if ((us & 0x0010))
+    DEBUGOUT ("    Auto clock change\n");
+  if ((us & 0x0020))
+    DEBUGOUT ("    Auto baud rate change\n");
+  if ((us & 0x0040))
+    DEBUGOUT ("    Auto parameter negotation made by CCID\n");
+  else if ((us & 0x0080))
+    DEBUGOUT ("    Auto PPS made by CCID\n");
+  else if ((us & (0x0040 | 0x0080)))
+    DEBUGOUT ("    WARNING: conflicting negotation features\n");
+
+  if ((us & 0x0100))
+    DEBUGOUT ("    CCID can set ICC in clock stop mode\n");
+  if ((us & 0x0200))
+    {
+      DEBUGOUT ("    NAD value other than 0x00 accepted\n");
+      handle->nonnull_nad = 1;
+    }
+  if ((us & 0x0400))
+    {
+      DEBUGOUT ("    Auto IFSD exchange\n");
+      handle->auto_ifsd = 1;
+    }
+
+  if ((us & 0x00010000))
+    {
+      DEBUGOUT ("    TPDU level exchange\n");
+      have_tpdu = 1;
+    } 
+  else if ((us & 0x00020000))
+    {
+      DEBUGOUT ("    Short APDU level exchange\n");
+      handle->apdu_level = 1;
+    }
+  else if ((us & 0x00040000))
+    {
+      DEBUGOUT ("    Short and extended APDU level exchange\n");
+      handle->apdu_level = 1;
+    }
+  else if ((us & 0x00070000))
+    DEBUGOUT ("    WARNING: conflicting exchange levels\n");
+
+  us = convert_le_u32(buf+44);
+  DEBUGOUT_1 ("  dwMaxCCIDMsgLen     %5u\n", us);
+
+  DEBUGOUT (  "  bClassGetResponse    ");
+  if (buf[48] == 0xff)
+    DEBUGOUT_CONT ("echo\n");
+  else
+    DEBUGOUT_CONT_1 ("  %02X\n", buf[48]);
+
+  DEBUGOUT (  "  bClassEnvelope       ");
+  if (buf[49] == 0xff)
+    DEBUGOUT_CONT ("echo\n");
+  else
+    DEBUGOUT_CONT_1 ("  %02X\n", buf[48]);
+
+  DEBUGOUT (  "  wlcdLayout           ");
+  if (!buf[50] && !buf[51])
+    DEBUGOUT_CONT ("none\n");
+  else
+    DEBUGOUT_CONT_2 ("%u cols %u lines\n", buf[50], buf[51]);
+        
+  DEBUGOUT_1 ("  bPINSupport         %5u ", buf[52]);
+  if ((buf[52] & 1))
+    {
+      DEBUGOUT_CONT ( " verification");
+      handle->has_pinpad |= 1;
+    }
+  if ((buf[52] & 2))
+    {
+      DEBUGOUT_CONT ( " modification");
+      handle->has_pinpad |= 2;
+    }
+  DEBUGOUT_LF ();
+        
+  DEBUGOUT_1 ("  bMaxCCIDBusySlots   %5u\n", buf[53]);
+
+  if (buf[0] > 54) {
+    DEBUGOUT ("  junk             ");
+    for (i=54; i < buf[0]-54; i++)
+      DEBUGOUT_CONT_1 (" %02X", buf[i]);
+    DEBUGOUT_LF ();
+  }
+
+  if (!have_t1 || !(have_tpdu  || handle->apdu_level) || !have_auto_conf)
+    {
+      DEBUGOUT ("this drivers requires that the reader supports T=1, "
+                "TPDU or APDU level exchange and auto configuration - "
+                "this is not available\n");
+      return -1;
+    }
+
+
+  /* SCM drivers get stuck in their internal USB stack if they try to
+     send a frame of n*wMaxPacketSize back to us.  Given that
+     wMaxPacketSize is 64 for these readers we set the IFSD to a value
+     lower than that:
+        64 - 10 CCID header -  4 T1frame - 2 reserved = 48
+     Product Ids:
+	 0xe001 - SCR 331 
+	 0x5111 - SCR 331-DI 
+	 0x5115 - SCR 335 
+	 0xe003 - SPR 532 
+  */
+  if (handle->id_vendor == VENDOR_SCM
+      && handle->max_ifsd > 48      
+      && (  (handle->id_product == 0xe001 && handle->bcd_device < 0x0516)
+          ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620)
+          ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0514)
+          ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504)
+          ))
+    {
+      DEBUGOUT ("enabling workaround for buggy SCM readers\n");
+      handle->max_ifsd = 48;
+    }
+
+
+  return 0;
+}
+
+
+static char *
+get_escaped_usb_string (usb_dev_handle *idev, int idx,
+                        const char *prefix, const char *suffix)
+{
+  int rc;
+  unsigned char buf[280];
+  unsigned char *s;
+  unsigned int langid;
+  size_t i, n, len;
+  char *result;
+
+  if (!idx)
+    return NULL;
+
+  /* Fixme: The next line is for the current Valgrid without support
+     for USB IOCTLs. */
+  memset (buf, 0, sizeof buf);
+
+  /* First get the list of supported languages and use the first one.
+     If we do don't find it we try to use English.  Note that this is
+     all in a 2 bute Unicode encoding using little endian. */
+  rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+                        (USB_DT_STRING << 8), 0, 
+                        (char*)buf, sizeof buf, 1000 /* ms timeout */);
+  if (rc < 4)
+    langid = 0x0409; /* English.  */
+  else
+    langid = (buf[3] << 8) | buf[2];
+
+  rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+                        (USB_DT_STRING << 8) + idx, langid,
+                        (char*)buf, sizeof buf, 1000 /* ms timeout */);
+  if (rc < 2 || buf[1] != USB_DT_STRING)
+    return NULL; /* Error or not a string. */
+  len = buf[0];
+  if (len > rc)
+    return NULL; /* Larger than our buffer. */
+
+  for (s=buf+2, i=2, n=0; i+1 < len; i += 2, s += 2)
+    {
+      if (s[1])
+        n++; /* High byte set. */
+      else if (*s <= 0x20 || *s >= 0x7f || *s == '%' || *s == ':')
+        n += 3 ;
+      else 
+        n++;
+    }
+
+  result = malloc (strlen (prefix) + n + strlen (suffix) + 1);
+  if (!result)
+    return NULL;
+
+  strcpy (result, prefix);
+  n = strlen (prefix);
+  for (s=buf+2, i=2; i+1 < len; i += 2, s += 2)
+    {
+      if (s[1])
+        result[n++] = '\xff'; /* High byte set. */
+      else if (*s <= 0x20 || *s >= 0x7f || *s == '%' || *s == ':')
+        {
+          sprintf (result+n, "%%%02X", *s);
+          n += 3;
+        }
+      else 
+        result[n++] = *s;
+    }
+  strcpy (result+n, suffix);
+
+  return result;
+}
+
+/* This function creates an reader id to be used to find the same
+   physical reader after a reset.  It returns an allocated and possibly
+   percent escaped string or NULL if not enough memory is available. */
+static char *
+make_reader_id (usb_dev_handle *idev,
+                unsigned int vendor, unsigned int product,
+                unsigned char serialno_index)
+{
+  char *rid;
+  char prefix[20];
+
+  sprintf (prefix, "%04X:%04X:", (vendor & 0xfff), (product & 0xffff));
+  rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0");
+  if (!rid)
+    {
+      rid = malloc (strlen (prefix) + 3 + 1);
+      if (!rid)
+        return NULL;
+      strcpy (rid, prefix);
+      strcat (rid, "X:0");
+    }
+  return rid;
+}
+
+
+/* Helper to find the endpoint from an interface descriptor.  */
+static int
+find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
+{
+  int no;
+  int want_bulk_in = 0;
+
+  if (mode == 1)
+    want_bulk_in = 0x80;
+  for (no=0; no < ifcdesc->bNumEndpoints; no++)
+    {
+      struct usb_endpoint_descriptor *ep = ifcdesc->endpoint + no;
+      if (ep->bDescriptorType != USB_DT_ENDPOINT)
+        ;
+      else if (mode == 2
+          && ((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+              == USB_ENDPOINT_TYPE_INTERRUPT)
+          && (ep->bEndpointAddress & 0x80))
+        return (ep->bEndpointAddress & 0x0f);
+      else if (((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+                == USB_ENDPOINT_TYPE_BULK)
+               && (ep->bEndpointAddress & 0x80) == want_bulk_in)
+        return (ep->bEndpointAddress & 0x0f);
+    }
+  /* Should never happen.  */
+  return mode == 2? 0x83 : mode == 1? 0x82 :1;
+}
+
+
+
+/* Combination function to either scan all CCID devices or to find and
+   open one specific device. 
+
+   With READERNO = -1 and READERID is NULL, scan mode is used and
+   R_RID should be the address where to store the list of reader_ids
+   we found.  If on return this list is empty, no CCID device has been
+   found; otherwise it points to an allocated linked list of reader
+   IDs.  Note that in this mode the function always returns NULL.
+
+   With READERNO >= 0 or READERID is not NULL find mode is used.  This
+   uses the same algorithm as the scan mode but stops and returns at
+   the entry number READERNO and return the handle for the the opened
+   USB device. If R_ID is not NULL it will receive the reader ID of
+   that device.  If R_DEV is not NULL it will the device pointer of
+   that device.  If IFCDESC_EXTRA is NOT NULL it will receive a
+   malloced copy of the interfaces "extra: data filed;
+   IFCDESC_EXTRA_LEN receive the lengtyh of this field.  If there is
+   no reader with number READERNO or that reader is not usable by our
+   implementation NULL will be returned.  The caller must close a
+   returned USB device handle and free (if not passed as NULL) the
+   returned reader ID info as well as the IFCDESC_EXTRA.  On error
+   NULL will get stored at R_RID, R_DEV, IFCDESC_EXTRA and
+   IFCDESC_EXTRA_LEN.  With READERID being -1 the function stops if
+   the READERID was found.
+
+   Note that the first entry of the returned reader ID list in scan mode
+   corresponds with a READERNO of 0 in find mode.
+*/
+static usb_dev_handle *
+scan_or_find_devices (int readerno, const char *readerid,
+                      char **r_rid,
+                      struct usb_device **r_dev,
+                      unsigned char **ifcdesc_extra,
+                      size_t *ifcdesc_extra_len,
+                      int *interface_number,
+                      int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
+{
+  char *rid_list = NULL;
+  int count = 0;
+  struct usb_bus *busses, *bus;
+  struct usb_device *dev = NULL;
+  usb_dev_handle *idev = NULL;
+  int scan_mode = (readerno == -1 && !readerid);
+
+   /* Set return values to a default. */
+  if (r_rid)
+    *r_rid = NULL;
+  if (r_dev)
+    *r_dev = NULL; 
+  if (ifcdesc_extra)
+    *ifcdesc_extra = NULL;
+  if (ifcdesc_extra_len)
+    *ifcdesc_extra_len = 0;
+  if (interface_number)
+    *interface_number = 0;
+
+  /* See whether we want scan or find mode. */
+  if (scan_mode) 
+    {
+      assert (r_rid);
+    }
+
+  usb_find_busses();
+  usb_find_devices();
+
+#ifdef HAVE_USB_GET_BUSSES
+  busses = usb_get_busses();
+#else
+  busses = usb_busses;
+#endif
+
+  for (bus = busses; bus; bus = bus->next) 
+    {
+      for (dev = bus->devices; dev; dev = dev->next)
+        {
+          int cfg_no;
+          
+          for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
+            {
+              struct usb_config_descriptor *config = dev->config + cfg_no;
+              int ifc_no;
+
+              if(!config)
+                continue;
+
+              for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
+                {
+                  struct usb_interface *interface
+                    = config->interface + ifc_no;
+                  int set_no;
+                  
+                  if (!interface)
+                    continue;
+                  
+                  for (set_no=0; set_no < interface->num_altsetting; set_no++)
+                    {
+                      struct usb_interface_descriptor *ifcdesc
+                        = interface->altsetting + set_no;
+                      char *rid;
+                      
+                      /* The second condition is for some SCM Micro
+                         SPR 532 which does not know about the
+                         assigned CCID class. Instead of trying to
+                         interpret the strings we simply look at the
+                         product ID. */
+                      if (ifcdesc && ifcdesc->extra
+                          && (   (ifcdesc->bInterfaceClass == 11
+                                  && ifcdesc->bInterfaceSubClass == 0
+                                  && ifcdesc->bInterfaceProtocol == 0)
+                              || (ifcdesc->bInterfaceClass == 255
+                                  && dev->descriptor.idVendor == 0x04e6
+                                  && dev->descriptor.idProduct == 0xe003)))
+                        {
+                          idev = usb_open (dev);
+                          if (!idev)
+                            {
+                              DEBUGOUT_1 ("usb_open failed: %s\n",
+                                          strerror (errno));
+                              continue;
+                            }
+                              
+                          rid = make_reader_id (idev,
+                                                dev->descriptor.idVendor,
+                                                dev->descriptor.idProduct,
+                                                dev->descriptor.iSerialNumber);
+                          if (rid)
+                            {
+                              if (scan_mode)
+                                {
+                                  char *p;
+
+                                  /* We are collecting infos about all
+                                     available CCID readers.  Store
+                                     them and continue. */
+                                  DEBUGOUT_2 ("found CCID reader %d "
+                                              "(ID=%s)\n",
+                                              count, rid );
+                                  if ((p = malloc ((rid_list?
+                                                    strlen (rid_list):0)
+                                                   + 1 + strlen (rid)
+                                                   + 1)))
+                                    {
+                                      *p = 0;
+                                      if (rid_list)
+                                        {
+                                          strcat (p, rid_list);
+                                          free (rid_list);
+                                        }
+                                      strcat (p, rid);
+                                      strcat (p, "\n");
+                                      rid_list = p;
+                                    }
+                                  else /* Out of memory. */
+                                    free (rid);
+                                  rid = NULL;
+                                  count++;
+                                }
+                              else if (!readerno
+                                       || (readerno < 0
+                                           && readerid
+                                           && !strcmp (readerid, rid)))
+                                {
+                                  /* We found the requested reader. */
+                                  if (ifcdesc_extra && ifcdesc_extra_len)
+                                    {
+                                      *ifcdesc_extra = malloc (ifcdesc
+                                                               ->extralen);
+                                      if (!*ifcdesc_extra)
+                                        {
+                                          usb_close (idev);
+                                          free (rid);
+                                          return NULL; /* Out of core. */
+                                        }
+                                      memcpy (*ifcdesc_extra, ifcdesc->extra,
+                                              ifcdesc->extralen);
+                                      *ifcdesc_extra_len = ifcdesc->extralen;
+                                    }
+                                  if (interface_number)
+                                    *interface_number = (ifcdesc->
+                                                         bInterfaceNumber);
+                                  if (ep_bulk_out)
+                                    *ep_bulk_out = find_endpoint (ifcdesc, 0);
+                                  if (ep_bulk_in)
+                                    *ep_bulk_in = find_endpoint (ifcdesc, 1);
+                                  if (ep_intr)
+                                    *ep_intr = find_endpoint (ifcdesc, 2);
+
+
+                                  if (r_dev)
+                                    *r_dev = dev;
+                                  if (r_rid)
+                                    {
+                                      *r_rid = rid;
+                                      rid = NULL;
+                                    }
+                                  else
+                                    free (rid);
+                                  return idev; /* READY. */
+                                }
+                              else
+                                {
+                                  /* This is not yet the reader we
+                                     want.  fixme: We could avoid the
+                                     extra usb_open in this case. */
+                                  if (readerno >= 0)
+                                    readerno--;
+                                }
+                              free (rid);
+                            }
+                          
+                          usb_close (idev);
+                          idev = NULL;
+                          goto next_device;
+                        }
+                    }
+                }
+            }
+        next_device:
+          ;
+        }
+    }
+
+  if (scan_mode)
+    *r_rid = rid_list;
+
+  return NULL;
+}
+
+
+/* Set the level of debugging to to usea dn return the old level.  -1
+   just returns the old level.  A level of 0 disables debugging, 1
+   enables debugging, 2 enables additional tracing of the T=1
+   protocol, other values are not yet defined. */
+int
+ccid_set_debug_level (int level)
+{
+  int old = debug_level;
+  if (level != -1)
+    debug_level = level;
+  return old;
+}
+
+
+char *
+ccid_get_reader_list (void)
+{
+  char *reader_list;
+
+  if (!initialized_usb)
+    {
+      usb_init ();
+      initialized_usb = 1;
+    }
+
+  scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
+                        NULL, NULL, NULL);
+  return reader_list;
+}
+
+
+/* Open the reader with the internal number READERNO and return a 
+   pointer to be used as handle in HANDLE.  Returns 0 on success. */
+int 
+ccid_open_reader (ccid_driver_t *handle, const char *readerid)
+{
+  int rc = 0;
+  struct usb_device *dev = NULL;
+  usb_dev_handle *idev = NULL;
+  char *rid = NULL;
+  unsigned char *ifcdesc_extra = NULL;
+  size_t ifcdesc_extra_len;
+  int readerno;
+  int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
+
+  *handle = NULL;
+
+  if (!initialized_usb)
+    {
+      usb_init ();
+      initialized_usb = 1;
+    }
+
+  /* See whether we want to use the reader ID string or a reader
+     number. A readerno of -1 indicates that the reader ID string is
+     to be used. */
+  if (readerid && strchr (readerid, ':'))
+    readerno = -1; /* We want to use the readerid.  */
+  else if (readerid)
+    {
+      readerno = atoi (readerid);
+      if (readerno < 0)
+        {
+          DEBUGOUT ("no CCID readers found\n");
+          rc = CCID_DRIVER_ERR_NO_READER;
+          goto leave;
+        }
+    }
+  else
+    readerno = 0;  /* Default. */
+
+  idev = scan_or_find_devices (readerno, readerid, &rid, &dev,
+                               &ifcdesc_extra, &ifcdesc_extra_len,
+                               &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
+  if (!idev)
+    {
+      if (readerno == -1)
+        DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
+      else
+        DEBUGOUT_1 ("no CCID reader with number %d\n", readerno );
+      rc = CCID_DRIVER_ERR_NO_READER;
+      goto leave;
+    }
+
+  /* Okay, this is a CCID reader. */
+  *handle = calloc (1, sizeof **handle);
+  if (!*handle)
+    {
+      DEBUGOUT ("out of memory\n");
+      rc = CCID_DRIVER_ERR_OUT_OF_CORE;
+      goto leave;
+    }
+  (*handle)->idev = idev;
+  (*handle)->rid = rid;
+  (*handle)->id_vendor = dev->descriptor.idVendor;
+  (*handle)->id_product = dev->descriptor.idProduct;
+  (*handle)->bcd_device = dev->descriptor.bcdDevice;
+  (*handle)->ifc_no = ifc_no;
+  (*handle)->ep_bulk_out = ep_bulk_out;
+  (*handle)->ep_bulk_in = ep_bulk_in;
+  (*handle)->ep_intr = ep_intr;
+
+  DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n",  readerno, rid );
+
+
+  if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len))
+    {
+      DEBUGOUT ("device not supported\n");
+      rc = CCID_DRIVER_ERR_NO_READER;
+      goto leave;
+    }
+  
+  rc = usb_claim_interface (idev, ifc_no);
+  if (rc)
+    {
+      DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+      rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+      goto leave;
+    }
+  
+ leave:
+  free (ifcdesc_extra);
+  if (rc)
+    {
+      free (rid);
+      if (idev)
+        usb_close (idev);
+      free (*handle);
+      *handle = NULL;
+    }
+
+  return rc;
+}
+
+
+static void
+do_close_reader (ccid_driver_t handle)
+{
+  int rc;
+  unsigned char msg[100];
+  size_t msglen;
+  unsigned char seqno;
+  
+  if (!handle->powered_off)
+    {
+      msg[0] = PC_to_RDR_IccPowerOff;
+      msg[5] = 0; /* slot */
+      msg[6] = seqno = handle->seqno++;
+      msg[7] = 0; /* RFU */
+      msg[8] = 0; /* RFU */
+      msg[9] = 0; /* RFU */
+      set_msg_len (msg, 0);
+      msglen = 10;
+      
+      rc = bulk_out (handle, msg, msglen);
+      if (!rc)
+        bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+                 seqno, 2000, 0);
+      handle->powered_off = 1;
+    }
+  if (handle->idev)
+    {
+      usb_release_interface (handle->idev, handle->ifc_no);
+      usb_close (handle->idev);
+      handle->idev = NULL;
+    }
+}
+
+
+/* Reset a reader on HANDLE.  This is useful in case a reader has been
+   plugged of and inserted at a different port.  By resetting the
+   handle, the same reader will be get used.  Note, that on error the
+   handle won't get released. 
+
+   This does not return an ATR, so ccid_get_atr should be called right
+   after this one.
+*/
+int 
+ccid_shutdown_reader (ccid_driver_t handle)
+{
+  int rc = 0;
+  struct usb_device *dev = NULL;
+  usb_dev_handle *idev = NULL;
+  unsigned char *ifcdesc_extra = NULL;
+  size_t ifcdesc_extra_len;
+  int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
+
+  if (!handle || !handle->rid)
+    return CCID_DRIVER_ERR_INV_VALUE;
+
+  do_close_reader (handle);
+
+  idev = scan_or_find_devices (-1, handle->rid, NULL, &dev,
+                               &ifcdesc_extra, &ifcdesc_extra_len,
+                               &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
+  if (!idev)
+    {
+      DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
+      return CCID_DRIVER_ERR_NO_READER;
+    }
+
+
+  handle->idev = idev;
+  handle->ifc_no = ifc_no;
+  handle->ep_bulk_out = ep_bulk_out;
+  handle->ep_bulk_in = ep_bulk_in;
+  handle->ep_intr = ep_intr;
+
+  if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len))
+    {
+      DEBUGOUT ("device not supported\n");
+      rc = CCID_DRIVER_ERR_NO_READER;
+      goto leave;
+    }
+  
+  rc = usb_claim_interface (idev, ifc_no);
+  if (rc)
+    {
+      DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+      rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+      goto leave;
+    }
+  
+ leave:
+  free (ifcdesc_extra);
+  if (rc)
+    {
+      usb_close (handle->idev);
+      handle->idev = NULL;
+    }
+
+  return rc;
+
+}
+
+
+/* Close the reader HANDLE. */
+int 
+ccid_close_reader (ccid_driver_t handle)
+{
+  if (!handle || !handle->idev)
+    return 0;
+
+  do_close_reader (handle);
+  free (handle->rid);
+  free (handle);
+  return 0;
+}
+
+
+/* Return False if a card is present and powered. */
+int
+ccid_check_card_presence (ccid_driver_t handle)
+{
+
+  return -1;
+}
+
+
+/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
+   Returns 0 on success. */
+static int
+bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
+{
+  int rc;
+
+  rc = usb_bulk_write (handle->idev, 
+                       handle->ep_bulk_out,
+                       (char*)msg, msglen,
+                       1000 /* ms timeout */);
+  if (rc == msglen)
+    return 0;
+
+  if (rc == -1)
+    DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
+  else
+    DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
+  return CCID_DRIVER_ERR_CARD_IO_ERROR;
+}
+
+
+/* Read a maximum of LENGTH bytes from the bulk in endpoint into
+   BUFFER and return the actual read number if bytes in NREAD. SEQNO
+   is the sequence number used to send the request and EXPECTED_TYPE
+   the type of message we expect. Does checks on the ccid
+   header. TIMEOUT is the timeout value in ms. NO_DEBUG may be set to
+   avoid debug messages in case of no error. Returns 0 on success. */
+static int
+bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
+         size_t *nread, int expected_type, int seqno, int timeout,
+         int no_debug)
+{
+  int i, rc;
+  size_t msglen;
+
+  /* Fixme: The next line for the current Valgrind without support
+     for USB IOCTLs. */
+  memset (buffer, 0, length);
+ retry:
+  rc = usb_bulk_read (handle->idev, 
+                      handle->ep_bulk_in,
+                      (char*)buffer, length,
+                      timeout);
+  if (rc < 0)
+    {
+      DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
+      return CCID_DRIVER_ERR_CARD_IO_ERROR;
+    }
+
+  *nread = msglen = rc;
+
+  if (msglen < 10)
+    {
+      DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
+      return CCID_DRIVER_ERR_INV_VALUE;
+    }
+  if (buffer[0] != expected_type)
+    {
+      DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]);
+      return CCID_DRIVER_ERR_INV_VALUE;
+    }
+  if (buffer[5] != 0)    
+    {
+      DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]);
+      return CCID_DRIVER_ERR_INV_VALUE;
+    }
+  if (buffer[6] != seqno)    
+    {
+      DEBUGOUT_2 ("bulk-in seqno does not match (%d/%d)\n",
+                  seqno, buffer[6]);
+      return CCID_DRIVER_ERR_INV_VALUE;
+    }
+
+  if ( !(buffer[7] & 0x03) && (buffer[7] & 0xC0) == 0x80)
+    { 
+      /* Card present and active, time extension requested. */
+      DEBUGOUT_2 ("time extension requested (%02X,%02X)\n",
+                  buffer[7], buffer[8]);
+      goto retry;
+    }
+
+  if (!no_debug)
+    {
+      DEBUGOUT_3 ("status: %02X  error: %02X  octet[9]: %02X\n"
+                  "               data:",  buffer[7], buffer[8], buffer[9] );
+      for (i=10; i < msglen; i++)
+        DEBUGOUT_CONT_1 (" %02X", buffer[i]);
+      DEBUGOUT_LF ();
+    }
+  if (CCID_COMMAND_FAILED (buffer))
+    print_command_failed (buffer);
+
+  /* Check whether a card is at all available.  Note: If you add new
+     error codes here, check whether they need to be ignored in
+     send_escape_cmd. */
+  switch ((buffer[7] & 0x03))
+    {
+    case 0: /* no error */ break;
+    case 1: return CCID_DRIVER_ERR_CARD_INACTIVE;
+    case 2: return CCID_DRIVER_ERR_NO_CARD;
+    case 3: /* RFU */ break;
+    }
+  return 0;
+}
+
+
+/* Note that this function won't return the error codes NO_CARD or
+   CARD_INACTIVE.  IF RESULT is not NULL, the result from the
+   operation will get returned in RESULT and its length in RESULTLEN.
+   If the response is larger than RESULTMAX, an error is returned and
+   the required buffer length returned in RESULTLEN.  */
+static int 
+send_escape_cmd (ccid_driver_t handle,
+                 const unsigned char *data, size_t datalen,
+                 unsigned char *result, size_t resultmax, size_t *resultlen)
+{
+  int i, rc;
+  unsigned char msg[100];
+  size_t msglen;
+  unsigned char seqno;
+
+  if (resultlen)
+    *resultlen = 0;
+
+  if (datalen > sizeof msg - 10)
+    return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large.  */
+
+  msg[0] = PC_to_RDR_Escape;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 0; /* RFU */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  memcpy (msg+10, data, datalen);
+  msglen = 10 + datalen;
+  set_msg_len (msg, datalen);
+
+  DEBUGOUT ("sending");
+  for (i=0; i < msglen; i++)
+    DEBUGOUT_CONT_1 (" %02X", msg[i]);
+  DEBUGOUT_LF ();
+  rc = bulk_out (handle, msg, msglen);
+  if (rc)
+    return rc;
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
+                seqno, 5000, 0);
+  if (result)
+    switch (rc)
+      {
+        /* We need to ignore certain errorcode here. */
+      case 0:
+      case CCID_DRIVER_ERR_CARD_INACTIVE:
+      case CCID_DRIVER_ERR_NO_CARD:
+        {
+          if (msglen < 10 || (msglen-10) > resultmax )
+            rc = CCID_DRIVER_ERR_INV_VALUE; /* Invalid length of response. */
+          else
+            {
+              memcpy (result, msg+10, msglen-10);
+              *resultlen = msglen-10;
+            }
+          rc = 0;
+        }
+        break;
+      default:
+        break;
+      }
+  
+  return rc;
+}
+
+
+int
+ccid_transceive_escape (ccid_driver_t handle,
+                        const unsigned char *data, size_t datalen,
+                        unsigned char *resp, size_t maxresplen, size_t *nresp)
+{
+  return send_escape_cmd (handle, data, datalen, resp, maxresplen, nresp);
+}
+
+
+
+/* experimental */
+int
+ccid_poll (ccid_driver_t handle)
+{
+  int rc;
+  unsigned char msg[10];
+  size_t msglen;
+  int i, j;
+
+  rc = usb_bulk_read (handle->idev, 
+                      handle->ep_intr,
+                      (char*)msg, sizeof msg,
+                      0 /* ms timeout */ );
+  if (rc < 0 && errno == ETIMEDOUT)
+    return 0;
+
+  if (rc < 0)
+    {
+      DEBUGOUT_1 ("usb_intr_read error: %s\n", strerror (errno));
+      return CCID_DRIVER_ERR_CARD_IO_ERROR;
+    }
+
+  msglen = rc;
+  rc = 0;
+
+  if (msglen < 1)
+    {
+      DEBUGOUT ("intr-in msg too short\n");
+      return CCID_DRIVER_ERR_INV_VALUE;
+    }
+
+  if (msg[0] == RDR_to_PC_NotifySlotChange)
+    {
+      DEBUGOUT ("notify slot change:");
+      for (i=1; i < msglen; i++)
+        for (j=0; j < 4; j++)
+          DEBUGOUT_CONT_3 (" %d:%c%c",
+                           (i-1)*4+j, 
+                           (msg[i] & (1<<(j*2)))? 'p':'-',
+                           (msg[i] & (2<<(j*2)))? '*':' ');
+      DEBUGOUT_LF ();
+    }
+  else if (msg[0] == RDR_to_PC_HardwareError)    
+    {
+      DEBUGOUT ("hardware error occured\n");
+    }
+  else
+    {
+      DEBUGOUT_1 ("unknown intr-in msg of type %02X\n", msg[0]);
+    }
+
+  return 0;
+}
+
+
+/* Note that this fucntion won't return the error codes NO_CARD or
+   CARD_INACTIVE */
+int 
+ccid_slot_status (ccid_driver_t handle, int *statusbits)
+{
+  int rc;
+  unsigned char msg[100];
+  size_t msglen;
+  unsigned char seqno;
+  int retries = 0;
+
+ retry:
+  msg[0] = PC_to_RDR_GetSlotStatus;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 0; /* RFU */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  set_msg_len (msg, 0);
+
+  rc = bulk_out (handle, msg, 10);
+  if (rc)
+    return rc;
+  /* Note that we set the NO_DEBUG flag here, so that the logs won't
+     get cluttered up by a ticker function checking for the slot
+     status and debugging enabled. */
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+                seqno, retries? 1000 : 200, 1);
+  if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3)
+    {
+      if (!retries)
+        {
+          DEBUGOUT ("USB: CALLING USB_CLEAR_HALT\n");
+          usb_clear_halt (handle->idev, handle->ep_bulk_in);
+          usb_clear_halt (handle->idev, handle->ep_bulk_out);
+        }
+      else
+          DEBUGOUT ("USB: RETRYING bulk_in AGAIN\n");
+      retries++;
+      goto retry;
+    }
+  if (rc && rc != CCID_DRIVER_ERR_NO_CARD
+      && rc != CCID_DRIVER_ERR_CARD_INACTIVE)
+    return rc;
+  *statusbits = (msg[7] & 3);
+
+  return 0;
+}
+
+
+int 
+ccid_get_atr (ccid_driver_t handle,
+              unsigned char *atr, size_t maxatrlen, size_t *atrlen)
+{
+  int rc;
+  int statusbits;
+  unsigned char msg[100];
+  unsigned char *tpdu;
+  size_t msglen, tpdulen;
+  unsigned char seqno;
+  int use_crc = 0;
+  unsigned int edc;
+  int i;
+  int tried_iso = 0;
+
+  /* First check whether a card is available.  */
+  rc = ccid_slot_status (handle, &statusbits);
+  if (rc)
+    return rc;
+  if (statusbits == 2)
+    return CCID_DRIVER_ERR_NO_CARD;
+
+  /* For an inactive and also for an active card, issue the PowerOn
+     command to get the ATR.  */
+ again:
+  msg[0] = PC_to_RDR_IccPowerOn;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 0; /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  set_msg_len (msg, 0);
+  msglen = 10;
+
+  rc = bulk_out (handle, msg, msglen);
+  if (rc)
+    return rc;
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
+                seqno, 5000, 0);
+  if (rc)
+    return rc;
+  if (!tried_iso && CCID_COMMAND_FAILED (msg) && CCID_ERROR_CODE (msg) == 0xbb
+      && ((handle->id_vendor == VENDOR_CHERRY
+           && handle->id_product == 0x0005)
+          || (handle->id_vendor == VENDOR_GEMPC
+              && handle->id_product == 0x4433)
+          ))
+    {
+      tried_iso = 1;
+      /* Try switching to ISO mode. */
+      if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2,
+                            NULL, 0, NULL))
+        goto again;
+    }
+  else if (CCID_COMMAND_FAILED (msg))
+    return CCID_DRIVER_ERR_CARD_IO_ERROR;
+
+
+  handle->powered_off = 0;
+  
+  if (atr)
+    {
+      size_t n = msglen - 10;
+
+      if (n > maxatrlen)
+        n = maxatrlen;
+      memcpy (atr, msg+10, n);
+      *atrlen = n;
+    }
+
+  /* Setup parameters to select T=1. */
+  msg[0] = PC_to_RDR_SetParameters;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 1; /* Select T=1. */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+
+  /* FIXME: Get those values from the ATR. */
+  msg[10]= 0x01; /* Fi/Di */
+  msg[11]= 0x10; /* LRC, direct convention. */
+  msg[12]= 0;    /* Extra guardtime. */
+  msg[13]= 0x41; /* BWI/CWI */
+  msg[14]= 0;    /* No clock stoppping. */
+  msg[15]= 254;  /* IFSC */
+  msg[16]= 0;    /* Does not support non default NAD values. */
+  set_msg_len (msg, 7);
+  msglen = 10 + 7;
+
+  DEBUGOUT ("sending");
+  for (i=0; i < msglen; i++)
+    DEBUGOUT_CONT_1 (" %02X", msg[i]);
+  DEBUGOUT_LF ();
+
+  rc = bulk_out (handle, msg, msglen);
+  if (rc)
+    return rc;
+  /* Note that we ignore the error code on purpose. */
+  bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
+           seqno, 5000, 0);
+
+  handle->t1_ns = 0;
+  handle->t1_nr = 0;
+
+  /* Send an S-Block with our maximun IFSD to the CCID.  */
+  if (!handle->auto_ifsd)
+    {
+      tpdu = msg+10;
+      /* NAD: DAD=1, SAD=0 */
+      tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+      tpdu[1] = (0xc0 | 0 | 1); /* S-block request: change IFSD */
+      tpdu[2] = 1;
+      tpdu[3] = handle->max_ifsd? handle->max_ifsd : 32; 
+      tpdulen = 4;
+      edc = compute_edc (tpdu, tpdulen, use_crc);
+      if (use_crc)
+        tpdu[tpdulen++] = (edc >> 8);
+      tpdu[tpdulen++] = edc;
+
+      msg[0] = PC_to_RDR_XfrBlock;
+      msg[5] = 0; /* slot */
+      msg[6] = seqno = handle->seqno++;
+      msg[7] = 0; 
+      msg[8] = 0; /* RFU */
+      msg[9] = 0; /* RFU */
+      set_msg_len (msg, tpdulen);
+      msglen = 10 + tpdulen;
+
+      DEBUGOUT ("sending");
+      for (i=0; i < msglen; i++)
+        DEBUGOUT_CONT_1 (" %02X", msg[i]);
+      DEBUGOUT_LF ();
+
+      if (debug_level > 1)
+        DEBUGOUT_3 ("T=1: put %c-block seq=%d%s\n",
+                      ((msg[11] & 0xc0) == 0x80)? 'R' :
+                                (msg[11] & 0x80)? 'S' : 'I',
+                      ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+                                       : !!(msg[11] & 0x40)),
+                    (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+      rc = bulk_out (handle, msg, msglen);
+      if (rc)
+        return rc;
+
+
+      rc = bulk_in (handle, msg, sizeof msg, &msglen,
+                    RDR_to_PC_DataBlock, seqno, 5000, 0);
+      if (rc)
+        return rc;
+      
+      tpdu = msg + 10;
+      tpdulen = msglen - 10;
+      
+      if (tpdulen < 4) 
+        return CCID_DRIVER_ERR_ABORTED; 
+
+      if (debug_level > 1)
+        DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+                    ((msg[11] & 0xc0) == 0x80)? 'R' :
+                              (msg[11] & 0x80)? 'S' : 'I',
+                    ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+                                     : !!(msg[11] & 0x40)),
+                    ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+                    (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+      if ((tpdu[1] & 0xe0) != 0xe0 || tpdu[2] != 1)
+        {
+          DEBUGOUT ("invalid response for S-block (Change-IFSD)\n");
+          return -1;
+        }
+      DEBUGOUT_1 ("IFSD has been set to %d\n", tpdu[3]);
+    }
+
+  return 0;
+}
+
+
+
+
+static unsigned int 
+compute_edc (const unsigned char *data, size_t datalen, int use_crc)
+{
+  if (use_crc)
+    {
+      return 0x42; /* Not yet implemented. */
+    }
+  else
+    {
+      unsigned char crc = 0;
+      
+      for (; datalen; datalen--)
+        crc ^= *data++;
+      return crc;
+    }
+}
+
+
+/* Helper for ccid_transceive used for APDU level exchanges.  */
+static int
+ccid_transceive_apdu_level (ccid_driver_t handle,
+                            const unsigned char *apdu_buf, size_t apdu_buflen,
+                            unsigned char *resp, size_t maxresplen,
+                            size_t *nresp)
+{
+  int rc;
+  unsigned char send_buffer[10+259], recv_buffer[10+259];
+  const unsigned char *apdu;
+  size_t apdulen;
+  unsigned char *msg;
+  size_t msglen;
+  unsigned char seqno;
+  int i;
+
+  msg = send_buffer;
+
+  apdu = apdu_buf;
+  apdulen = apdu_buflen;
+  assert (apdulen);
+
+  if (apdulen > 254)
+    return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
+
+  msg[0] = PC_to_RDR_XfrBlock;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 4; /* bBWI */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  memcpy (msg+10, apdu, apdulen);
+  set_msg_len (msg, apdulen);
+  msglen = 10 + apdulen;
+
+  DEBUGOUT ("sending");
+  for (i=0; i < msglen; i++)
+    DEBUGOUT_CONT_1 (" %02X", msg[i]);
+  DEBUGOUT_LF ();
+  
+  rc = bulk_out (handle, msg, msglen);
+  if (rc)
+    return rc;
+
+  msg = recv_buffer;
+  rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+                RDR_to_PC_DataBlock, seqno, 5000, 0);
+  if (rc)
+    return rc;
+      
+  apdu = msg + 10;
+  apdulen = msglen - 10;
+      
+  if (resp)
+    {
+      if (apdulen > maxresplen)
+        {
+          DEBUGOUT_2 ("provided buffer too short for received data "
+                      "(%u/%u)\n",
+                      (unsigned int)apdulen, (unsigned int)maxresplen);
+          return CCID_DRIVER_ERR_INV_VALUE;
+        }
+      
+      memcpy (resp, apdu, apdulen); 
+      *nresp = apdulen;
+    }
+          
+  return 0;
+}
+
+
+
+/*
+  Protocol T=1 overview
+
+  Block Structure:
+           Prologue Field:
+   1 byte     Node Address (NAD) 
+   1 byte     Protocol Control Byte (PCB)
+   1 byte     Length (LEN) 
+           Information Field:
+   0-254 byte APDU or Control Information (INF)
+           Epilogue Field:
+   1 byte     Error Detection Code (EDC)
+
+  NAD:  
+   bit 7     unused
+   bit 4..6  Destination Node Address (DAD)
+   bit 3     unused
+   bit 2..0  Source Node Address (SAD)
+
+   If node adresses are not used, SAD and DAD should be set to 0 on
+   the first block sent to the card.  If they are used they should
+   have different values (0 for one is okay); that first block sets up
+   the addresses of the nodes.
+
+  PCB:
+   Information Block (I-Block):
+      bit 7    0
+      bit 6    Sequence number (yep, that is modulo 2)
+      bit 5    Chaining flag 
+      bit 4..0 reserved
+   Received-Ready Block (R-Block):
+      bit 7    1
+      bit 6    0
+      bit 5    0
+      bit 4    Sequence number
+      bit 3..0  0 = no error
+                1 = EDC or parity error
+                2 = other error
+                other values are reserved
+   Supervisory Block (S-Block):
+      bit 7    1
+      bit 6    1
+      bit 5    clear=request,set=response
+      bit 4..0  0 = resyncronisation request
+                1 = information field size request
+                2 = abort request
+                3 = extension of BWT request
+                4 = VPP error
+                other values are reserved
+
+*/
+
+int
+ccid_transceive (ccid_driver_t handle,
+                 const unsigned char *apdu_buf, size_t apdu_buflen,
+                 unsigned char *resp, size_t maxresplen, size_t *nresp)
+{
+  int rc;
+  unsigned char send_buffer[10+259], recv_buffer[10+259];
+  const unsigned char *apdu;
+  size_t apdulen;
+  unsigned char *msg, *tpdu, *p;
+  size_t msglen, tpdulen, last_tpdulen, n;
+  unsigned char seqno;
+  int i;
+  unsigned int edc;
+  int use_crc = 0;
+  size_t dummy_nresp;
+  int next_chunk = 1;
+  int sending = 1;
+  int retries = 0;
+
+  if (!nresp)
+    nresp = &dummy_nresp;
+  *nresp = 0;
+
+  /* Smarter readers allow to send APDUs directly; divert here. */
+  if (handle->apdu_level)
+    return ccid_transceive_apdu_level (handle, apdu_buf, apdu_buflen,
+                                       resp, maxresplen, nresp);
+
+  /* The other readers we support require sending TPDUs.  */
+
+  tpdulen = 0; /* Avoid compiler warning about no initialization. */
+  msg = send_buffer;
+  for (;;)
+    {
+      if (next_chunk)
+        {
+          next_chunk = 0;
+
+          apdu = apdu_buf;
+          apdulen = apdu_buflen;
+          assert (apdulen);
+
+          /* Construct an I-Block. */
+          if (apdulen > 254)
+            return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
+
+          tpdu = msg+10;
+          /* NAD: DAD=1, SAD=0 */
+          tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+          tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
+          if (apdulen > 128 /* fixme: replace by ifsc */)
+            {
+              apdulen = 128;
+              apdu_buf += 128;  
+              apdu_buflen -= 128;
+              tpdu[1] |= (1 << 5); /* Set more bit. */
+            }
+          tpdu[2] = apdulen;
+          memcpy (tpdu+3, apdu, apdulen);
+          tpdulen = 3 + apdulen;
+          edc = compute_edc (tpdu, tpdulen, use_crc);
+          if (use_crc)
+            tpdu[tpdulen++] = (edc >> 8);
+          tpdu[tpdulen++] = edc;
+        }
+
+      msg[0] = PC_to_RDR_XfrBlock;
+      msg[5] = 0; /* slot */
+      msg[6] = seqno = handle->seqno++;
+      msg[7] = 4; /* bBWI */
+      msg[8] = 0; /* RFU */
+      msg[9] = 0; /* RFU */
+      set_msg_len (msg, tpdulen);
+      msglen = 10 + tpdulen;
+      last_tpdulen = tpdulen;
+
+      DEBUGOUT ("sending");
+      for (i=0; i < msglen; i++)
+        DEBUGOUT_CONT_1 (" %02X", msg[i]);
+      DEBUGOUT_LF ();
+
+      if (debug_level > 1)
+          DEBUGOUT_3 ("T=1: put %c-block seq=%d%s\n",
+                      ((msg[11] & 0xc0) == 0x80)? 'R' :
+                                (msg[11] & 0x80)? 'S' : 'I',
+                      ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+                                       : !!(msg[11] & 0x40)),
+                      (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+      rc = bulk_out (handle, msg, msglen);
+      if (rc)
+        return rc;
+
+      msg = recv_buffer;
+      rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+                    RDR_to_PC_DataBlock, seqno, 5000, 0);
+      if (rc)
+        return rc;
+      
+      tpdu = msg + 10;
+      tpdulen = msglen - 10;
+      
+      if (tpdulen < 4) 
+        {
+          usb_clear_halt (handle->idev, handle->ep_bulk_in);
+          return CCID_DRIVER_ERR_ABORTED; 
+        }
+
+      if (debug_level > 1)
+        DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+                    ((msg[11] & 0xc0) == 0x80)? 'R' :
+                              (msg[11] & 0x80)? 'S' : 'I',
+                    ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
+                    ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+                    (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+      if (!(tpdu[1] & 0x80))
+        { /* This is an I-block. */
+          retries = 0;
+          if (sending)
+            { /* last block sent was successful. */
+              handle->t1_ns ^= 1;
+              sending = 0;
+            }
+
+          if (!!(tpdu[1] & 0x40) != handle->t1_nr)
+            { /* Reponse does not match our sequence number. */
+              msg = send_buffer;
+              tpdu = msg+10;
+              /* NAD: DAD=1, SAD=0 */
+              tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+              tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4 | 2); /* R-block */
+              tpdu[2] = 0;
+              tpdulen = 3;
+              edc = compute_edc (tpdu, tpdulen, use_crc);
+              if (use_crc)
+                tpdu[tpdulen++] = (edc >> 8);
+              tpdu[tpdulen++] = edc;
+
+              continue;
+            }
+
+          handle->t1_nr ^= 1;
+
+          p = tpdu + 3; /* Skip the prologue field. */
+          n = tpdulen - 3 - 1; /* Strip the epilogue field. */
+          /* fixme: verify the checksum. */
+          if (resp)
+            {
+              if (n > maxresplen)
+                {
+                  DEBUGOUT_2 ("provided buffer too short for received data "
+                              "(%u/%u)\n",
+                              (unsigned int)n, (unsigned int)maxresplen);
+                  return CCID_DRIVER_ERR_INV_VALUE;
+                }
+              
+              memcpy (resp, p, n); 
+              resp += n;
+              *nresp += n;
+              maxresplen -= n;
+            }
+          
+          if (!(tpdu[1] & 0x20))
+            return 0; /* No chaining requested - ready. */
+          
+          msg = send_buffer;
+          tpdu = msg+10;
+          /* NAD: DAD=1, SAD=0 */
+          tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+          tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4); /* R-block */
+          tpdu[2] = 0;
+          tpdulen = 3;
+          edc = compute_edc (tpdu, tpdulen, use_crc);
+          if (use_crc)
+            tpdu[tpdulen++] = (edc >> 8);
+          tpdu[tpdulen++] = edc;
+        }
+      else if ((tpdu[1] & 0xc0) == 0x80)
+        { /* This is a R-block. */
+          if ( (tpdu[1] & 0x0f)) 
+            { /* Error: repeat last block */
+              if (++retries > 3)
+                {
+                  DEBUGOUT ("3 failed retries\n");
+                  return CCID_DRIVER_ERR_CARD_IO_ERROR;
+                }
+              msg = send_buffer;
+              tpdulen = last_tpdulen;
+            }
+          else if (sending && !!(tpdu[1] & 0x10) == handle->t1_ns)
+            { /* Response does not match our sequence number. */
+              DEBUGOUT ("R-block with wrong seqno received on more bit\n");
+              return CCID_DRIVER_ERR_CARD_IO_ERROR;
+            }
+          else if (sending)
+            { /* Send next chunk. */
+              retries = 0;
+              msg = send_buffer;
+              next_chunk = 1;
+              handle->t1_ns ^= 1;
+            }
+          else
+            {
+              DEBUGOUT ("unexpected ACK R-block received\n");
+              return CCID_DRIVER_ERR_CARD_IO_ERROR;
+            }
+        }
+      else 
+        { /* This is a S-block. */
+          retries = 0;
+          DEBUGOUT_2 ("T=1 S-block %s received cmd=%d\n",
+                      (tpdu[1] & 0x20)? "response": "request",
+                      (tpdu[1] & 0x1f));
+          if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
+            { /* Wait time extension request. */
+              unsigned char bwi = tpdu[3];
+              msg = send_buffer;
+              tpdu = msg+10;
+              /* NAD: DAD=1, SAD=0 */
+              tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+              tpdu[1] = (0xc0 | 0x20 | 3); /* S-block response */
+              tpdu[2] = 1;
+              tpdu[3] = bwi;
+              tpdulen = 4;
+              edc = compute_edc (tpdu, tpdulen, use_crc);
+              if (use_crc)
+                tpdu[tpdulen++] = (edc >> 8);
+              tpdu[tpdulen++] = edc;
+              DEBUGOUT_1 ("T=1 waittime extension of bwi=%d\n", bwi);
+            }
+          else
+            return CCID_DRIVER_ERR_CARD_IO_ERROR;
+        }
+    } /* end T=1 protocol loop. */
+
+  return 0;
+}
+
+
+/* Send the CCID Secure command to the reader.  APDU_BUF should
+   contain the APDU template.  PIN_MODE defines how the pin gets
+   formatted:
+   
+     1 := The PIN is ASCII encoded and of variable length.  The
+          length of the PIN entered will be put into Lc by the reader.
+          The APDU should me made up of 4 bytes without Lc.
+
+   PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0
+   may be used t enable reasonable defaults.  PIN_PADLEN should be 0.
+   
+   When called with RESP and NRESP set to NULL, the function will
+   merely check whether the reader supports the secure command for the
+   given APDU and PIN_MODE. */
+int
+ccid_transceive_secure (ccid_driver_t handle,
+                        const unsigned char *apdu_buf, size_t apdu_buflen,
+                        int pin_mode, int pinlen_min, int pinlen_max,
+                        int pin_padlen, 
+                        unsigned char *resp, size_t maxresplen, size_t *nresp)
+{
+  int rc;
+  unsigned char send_buffer[10+259], recv_buffer[10+259];
+  unsigned char *msg, *tpdu, *p;
+  size_t msglen, tpdulen, n;
+  unsigned char seqno;
+  int i;
+  size_t dummy_nresp;
+  int testmode;
+
+  testmode = !resp && !nresp;
+
+  if (!nresp)
+    nresp = &dummy_nresp;
+  *nresp = 0;
+
+  if (apdu_buflen >= 4 && apdu_buf[1] == 0x20 && (handle->has_pinpad & 1))
+    ;
+  else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
+    return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */
+  else
+    return CCID_DRIVER_ERR_NO_KEYPAD;
+    
+  if (pin_mode != 1)
+    return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+  if (pin_padlen != 0)
+    return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+  if (!pinlen_min)
+    pinlen_min = 1;
+  if (!pinlen_max)
+    pinlen_max = 25;
+
+  /* Note that the 25 is the maximum value the SPR532 allows.  */
+  if (pinlen_min < 1 || pinlen_min > 25
+      || pinlen_max < 1 || pinlen_max > 25 
+      || pinlen_min > pinlen_max)
+    return CCID_DRIVER_ERR_INV_VALUE;
+
+  /* We have only tested this with an SCM reader so better don't risk
+     anything and do not allow the use with other readers. */
+  if (handle->id_vendor != VENDOR_SCM)
+    return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+  if (testmode)
+    return 0; /* Success */
+    
+  msg = send_buffer;
+  if (handle->id_vendor == VENDOR_SCM)
+    {
+      DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
+      rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3,
+                            NULL, 0, NULL);
+      if (rc)
+        return rc;
+    }
+
+  msg[0] = PC_to_RDR_Secure;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 4; /* bBWI */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  msg[10] = 0; /* Perform PIN verification. */
+  msg[11] = 0; /* Timeout in seconds. */
+  msg[12] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
+  if (handle->id_vendor == VENDOR_SCM)
+    {
+      /* For the SPR532 the next 2 bytes need to be zero.  We do this
+         for all SCM product. Kudos to Martin Paljak for this
+         hint.  */
+      msg[13] = msg[14] = 0;
+    }
+  else
+    {
+      msg[13] = 0x00; /* bmPINBlockString:
+                         0 bits of pin length to insert. 
+                         0 bytes of PIN block size.  */
+      msg[14] = 0x00; /* bmPINLengthFormat:
+                         Units are bytes, position is 0. */
+    }
+  msg[15] = pinlen_min;   /* wPINMaxExtraDigit-Minimum.  */
+  msg[16] = pinlen_max;   /* wPINMaxExtraDigit-Maximum.  */
+  msg[17] = 0x02; /* bEntryValidationCondition:
+                     Validation key pressed */
+  if (pinlen_min && pinlen_max && pinlen_min == pinlen_max)
+    msg[17] |= 0x01; /* Max size reached.  */
+  msg[18] = 0xff; /* bNumberMessage: Default. */
+  msg[19] = 0x04; /* wLangId-High. */
+  msg[20] = 0x09; /* wLangId-Low:  English FIXME: use the first entry. */
+  msg[21] = 0;    /* bMsgIndex. */
+  /* bTeoProlog follows: */
+  msg[22] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+  msg[23] = ((handle->t1_ns & 1) << 6); /* I-block */
+  msg[24] = 4; /* apdulen.  */
+  /* APDU follows:  */
+  msg[25] = apdu_buf[0]; /* CLA */
+  msg[26] = apdu_buf[1]; /* INS */
+  msg[27] = apdu_buf[2]; /* P1 */
+  msg[28] = apdu_buf[3]; /* P2 */
+  msglen = 29;
+  set_msg_len (msg, msglen - 10);
+
+  DEBUGOUT ("sending");
+  for (i=0; i < msglen; i++)
+    DEBUGOUT_CONT_1 (" %02X", msg[i]);
+  DEBUGOUT_LF ();
+  
+  rc = bulk_out (handle, msg, msglen);
+  if (rc)
+    return rc;
+  
+  msg = recv_buffer;
+  rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+                RDR_to_PC_DataBlock, seqno, 5000, 0);
+  if (rc)
+    return rc;
+  
+  tpdu = msg + 10;
+  tpdulen = msglen - 10;
+  
+  if (tpdulen < 4) 
+    {
+      usb_clear_halt (handle->idev, handle->ep_bulk_in);
+      return CCID_DRIVER_ERR_ABORTED; 
+    }
+  if (debug_level > 1)
+    DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+                ((msg[11] & 0xc0) == 0x80)? 'R' :
+                          (msg[11] & 0x80)? 'S' : 'I',
+                ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
+                ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+                (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+  if (!(tpdu[1] & 0x80))
+    { /* This is an I-block. */
+      /* Last block sent was successful. */
+      handle->t1_ns ^= 1;
+
+      if (!!(tpdu[1] & 0x40) != handle->t1_nr)
+        { /* Reponse does not match our sequence number. */
+          DEBUGOUT ("I-block with wrong seqno received\n");
+          return CCID_DRIVER_ERR_CARD_IO_ERROR;
+        }
+
+      handle->t1_nr ^= 1;
+
+      p = tpdu + 3; /* Skip the prologue field. */
+      n = tpdulen - 3 - 1; /* Strip the epilogue field. */
+      /* fixme: verify the checksum. */
+      if (resp)
+        {
+          if (n > maxresplen)
+            {
+              DEBUGOUT_2 ("provided buffer too short for received data "
+                          "(%u/%u)\n",
+                          (unsigned int)n, (unsigned int)maxresplen);
+              return CCID_DRIVER_ERR_INV_VALUE;
+            }
+              
+          memcpy (resp, p, n); 
+          resp += n;
+          *nresp += n;
+          maxresplen -= n;
+        }
+          
+      if (!(tpdu[1] & 0x20))
+        return 0; /* No chaining requested - ready. */
+      
+      DEBUGOUT ("chaining requested but not supported for Secure operation\n");
+      return CCID_DRIVER_ERR_CARD_IO_ERROR;
+    }
+  else if ((tpdu[1] & 0xc0) == 0x80)
+    { /* This is a R-block. */
+      if ( (tpdu[1] & 0x0f)) 
+        { /* Error: repeat last block */
+          DEBUGOUT ("No retries supported for Secure operation\n");
+          return CCID_DRIVER_ERR_CARD_IO_ERROR;
+        }
+      else if (!!(tpdu[1] & 0x10) == handle->t1_ns)
+        { /* Reponse does not match our sequence number. */
+          DEBUGOUT ("R-block with wrong seqno received on more bit\n");
+          return CCID_DRIVER_ERR_CARD_IO_ERROR;
+        }
+      else
+        { /* Send next chunk. */
+          DEBUGOUT ("chaining not supported on Secure operation\n");
+          return CCID_DRIVER_ERR_CARD_IO_ERROR;
+        }
+    }
+  else 
+    { /* This is a S-block. */
+      DEBUGOUT_2 ("T=1 S-block %s received cmd=%d for Secure operation\n",
+                  (tpdu[1] & 0x20)? "response": "request",
+                  (tpdu[1] & 0x1f));
+      return CCID_DRIVER_ERR_CARD_IO_ERROR;
+    } 
+
+  return 0;
+}
+
+
+
+
+#ifdef TEST
+
+
+static void
+print_error (int err)
+{
+  const char *p;
+  char buf[50];
+
+  switch (err)
+    {
+    case 0: p = "success";
+    case CCID_DRIVER_ERR_OUT_OF_CORE: p = "out of core"; break;
+    case CCID_DRIVER_ERR_INV_VALUE: p = "invalid value"; break;
+    case CCID_DRIVER_ERR_NO_DRIVER: p = "no driver"; break;
+    case CCID_DRIVER_ERR_NOT_SUPPORTED: p = "not supported"; break;
+    case CCID_DRIVER_ERR_LOCKING_FAILED: p = "locking failed"; break;
+    case CCID_DRIVER_ERR_BUSY: p = "busy"; break;
+    case CCID_DRIVER_ERR_NO_CARD: p = "no card"; break;
+    case CCID_DRIVER_ERR_CARD_INACTIVE: p = "card inactive"; break;
+    case CCID_DRIVER_ERR_CARD_IO_ERROR: p = "card I/O error"; break;
+    case CCID_DRIVER_ERR_GENERAL_ERROR: p = "general error"; break;
+    case CCID_DRIVER_ERR_NO_READER: p = "no reader"; break;
+    case CCID_DRIVER_ERR_ABORTED: p = "aborted"; break;
+    default: sprintf (buf, "0x%05x", err); p = buf; break;
+    }
+  fprintf (stderr, "operation failed: %s\n", p);
+}
+
+static void
+print_data (const unsigned char *data, size_t length)
+{
+  if (length >= 2)
+    {
+      fprintf (stderr, "operation status: %02X%02X\n",
+               data[length-2], data[length-1]);
+      length -= 2;
+    }
+  if (length)
+    {
+        fputs ("   returned data:", stderr);
+        for (; length; length--, data++)
+          fprintf (stderr, " %02X", *data);
+        putc ('\n', stderr);
+    }
+}
+
+static void
+print_result (int rc, const unsigned char *data, size_t length)
+{
+  if (rc)
+    print_error (rc);
+  else if (data)
+    print_data (data, length);
+}
+
+int
+main (int argc, char **argv)
+{
+  int rc;
+  ccid_driver_t ccid;
+  unsigned int slotstat;
+  unsigned char result[512];
+  size_t resultlen;
+  int no_pinpad = 0;
+  int verify_123456 = 0;
+  int did_verify = 0;
+  int no_poll = 0;
+
+  if (argc)
+    {
+      argc--;
+      argv++;
+    }
+
+  while (argc)
+    {
+      if ( !strcmp (*argv, "--list"))
+        {
+          char *p;
+          p = ccid_get_reader_list ();
+          if (!p)
+            return 1;
+          fputs (p, stderr);
+          free (p);
+          return 0;
+        }
+      else if ( !strcmp (*argv, "--debug"))
+        {
+          ccid_set_debug_level (1);
+          argc--; argv++;
+        }
+      else if ( !strcmp (*argv, "--no-poll"))
+        {
+          no_poll = 1;
+          argc--; argv++;
+        }
+      else if ( !strcmp (*argv, "--no-pinpad"))
+        {
+          no_pinpad = 1;
+          argc--; argv++;
+        }
+      else if ( !strcmp (*argv, "--verify-123456"))
+        {
+          verify_123456 = 1;
+          argc--; argv++;
+        }
+      else
+        break;
+    }
+
+  rc = ccid_open_reader (&ccid, argc? *argv:NULL);
+  if (rc)
+    return 1;
+
+  if (!no_poll)
+    ccid_poll (ccid);
+  fputs ("getting ATR ...\n", stderr);
+  rc = ccid_get_atr (ccid, NULL, 0, NULL);
+  if (rc)
+    {
+      print_error (rc);
+      return 1;
+    }
+
+  if (!no_poll)
+    ccid_poll (ccid);
+  fputs ("getting slot status ...\n", stderr);
+  rc = ccid_slot_status (ccid, &slotstat);
+  if (rc)
+    {
+      print_error (rc);
+      return 1;
+    }
+
+  if (!no_poll)
+    ccid_poll (ccid);
+
+  fputs ("selecting application OpenPGP ....\n", stderr);
+  {
+    static unsigned char apdu[] = {
+      0, 0xA4, 4, 0, 6, 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01};
+    rc = ccid_transceive (ccid,
+                          apdu, sizeof apdu,
+                          result, sizeof result, &resultlen);
+    print_result (rc, result, resultlen);
+  }
+  
+
+  if (!no_poll)
+    ccid_poll (ccid);
+
+  fputs ("getting OpenPGP DO 0x65 ....\n", stderr);
+  {
+    static unsigned char apdu[] = { 0, 0xCA, 0, 0x65, 254 };
+    rc = ccid_transceive (ccid, apdu, sizeof apdu,
+                          result, sizeof result, &resultlen);
+    print_result (rc, result, resultlen);
+  }
+
+  if (!no_pinpad)
+    {
+    }
+
+  if (!no_pinpad)
+    {
+      static unsigned char apdu[] = { 0, 0x20, 0, 0x81 };
+
+      
+      if (ccid_transceive_secure (ccid,
+                                  apdu, sizeof apdu,
+                                  1, 0, 0, 0,
+                                  NULL, 0, NULL))
+        fputs ("can't verify using a PIN-Pad reader\n", stderr);
+      else
+        {
+          fputs ("verifying CHV1 using the PINPad ....\n", stderr);
+          
+          rc = ccid_transceive_secure (ccid,
+                                       apdu, sizeof apdu,
+                                       1, 0, 0, 0,
+                                       result, sizeof result, &resultlen);
+          print_result (rc, result, resultlen);
+          did_verify = 1;
+        }
+    }
+  
+  if (verify_123456 && !did_verify)
+    {
+      fputs ("verifying that CHV1 is 123456....\n", stderr);
+      {
+        static unsigned char apdu[] = {0, 0x20, 0, 0x81,
+                                       6, '1','2','3','4','5','6'};
+        rc = ccid_transceive (ccid, apdu, sizeof apdu,
+                              result, sizeof result, &resultlen);
+        print_result (rc, result, resultlen);
+      }
+    }
+
+  if (!rc)
+    {
+      fputs ("getting OpenPGP DO 0x5E ....\n", stderr);
+      {
+        static unsigned char apdu[] = { 0, 0xCA, 0, 0x5E, 254 };
+        rc = ccid_transceive (ccid, apdu, sizeof apdu,
+                              result, sizeof result, &resultlen);
+        print_result (rc, result, resultlen);
+      }
+    }
+
+  ccid_close_reader (ccid);
+
+  return 0;
+}
+
+/*
+ * Local Variables:
+ *  compile-command: "gcc -DTEST -Wall -I/usr/local/include -lusb -g ccid-driver.c"
+ * End:
+ */
+#endif /*TEST*/
+#endif /*HAVE_LIBUSB*/
diff --git a/ccid/ccid-driver.h b/ccid/ccid-driver.h
new file mode 100644
index 0000000..34c27cc
--- /dev/null
+++ b/ccid/ccid-driver.h
@@ -0,0 +1,108 @@
+/* ccid-driver.c - USB ChipCardInterfaceDevices driver
+ *	Copyright (C) 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU General Public License. If you wish to
+ * allow use of your version of this file only under the terms of the
+ * GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ccid-driver.h,v 1.1 2006-01-19 23:21:47 hackbard Exp $
+ */
+
+#ifndef CCID_DRIVER_H
+#define CCID_DRIVER_H
+
+/* The CID driver returns the same error codes as the status words
+   used by GnuPG's apdu.h.  For ease of maintenance they should always
+   match.  */
+#define CCID_DRIVER_ERR_OUT_OF_CORE    0x10001 
+#define CCID_DRIVER_ERR_INV_VALUE      0x10002
+#define CCID_DRIVER_ERR_INCOMPLETE_CARD_RESPONSE = 0x10003
+#define CCID_DRIVER_ERR_NO_DRIVER      0x10004
+#define CCID_DRIVER_ERR_NOT_SUPPORTED  0x10005
+#define CCID_DRIVER_ERR_LOCKING_FAILED 0x10006
+#define CCID_DRIVER_ERR_BUSY           0x10007
+#define CCID_DRIVER_ERR_NO_CARD        0x10008
+#define CCID_DRIVER_ERR_CARD_INACTIVE  0x10009
+#define CCID_DRIVER_ERR_CARD_IO_ERROR  0x1000a
+#define CCID_DRIVER_ERR_GENERAL_ERROR  0x1000b
+#define CCID_DRIVER_ERR_NO_READER      0x1000c
+#define CCID_DRIVER_ERR_ABORTED        0x1000d
+#define CCID_DRIVER_ERR_NO_KEYPAD      0x1000e
+
+struct ccid_driver_s;
+typedef struct ccid_driver_s *ccid_driver_t;
+
+int ccid_set_debug_level (int level);
+char *ccid_get_reader_list (void);
+int ccid_open_reader (ccid_driver_t *handle, const char *readerid);
+int ccid_shutdown_reader (ccid_driver_t handle);
+int ccid_close_reader (ccid_driver_t handle);
+int ccid_get_atr (ccid_driver_t handle,
+                  unsigned char *atr, size_t maxatrlen, size_t *atrlen);
+int ccid_slot_status (ccid_driver_t handle, int *statusbits);
+int ccid_transceive (ccid_driver_t handle,
+                     const unsigned char *apdu, size_t apdulen,
+                     unsigned char *resp, size_t maxresplen, size_t *nresp);
+int ccid_transceive_secure (ccid_driver_t handle,
+                     const unsigned char *apdu, size_t apdulen,
+                     int pin_mode, 
+                     int pinlen_min, int pinlen_max, int pin_padlen, 
+                     unsigned char *resp, size_t maxresplen, size_t *nresp);
+int ccid_transceive_escape (ccid_driver_t handle,
+                            const unsigned char *data, size_t datalen,
+                            unsigned char *resp, size_t maxresplen,
+                            size_t *nresp);
+
+
+
+#endif /*CCID_DRIVER_H*/
+
+
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..1125175
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,15 @@
+dnl Process this file with autoconf to create configure.
+
+AC_INIT
+
+AC_CANONICAL_SYSTEM
+
+AM_INIT_AUTOMAKE(librfid, 0.0.1)
+
+AC_PROG_CC
+AC_EXEEXT
+AM_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+
+dnl Output the makefile
+AC_OUTPUT(Makefile src/Makefile include/Makefile include/librfid/Makefile utils/Makefile)
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..dfaa277
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,2 @@
+
+SUBDIRS = librfid
diff --git a/include/librfid/Makefile.am b/include/librfid/Makefile.am
new file mode 100644
index 0000000..59ce8cb
--- /dev/null
+++ b/include/librfid/Makefile.am
@@ -0,0 +1,10 @@
+
+pkginclude_HEADERS = rfid.h rfid_asic.h rfid_asic_rc632.h \
+			rfid_layer2.h rfid_layer2_iso14443a.h \
+			rfid_layer2_iso14443b.h rfid_layer2_iso15693.h \
+			rfid_protocol.h rfid_protocol_tcl.h \
+			rfid_protocol_mifare_ul.h \
+			rfid_protocol_mifare_classic.h \
+			rfid_reader.h \
+			rfid_reader_cm5121.h
+
diff --git a/include/librfid/rfid.h b/include/librfid/rfid.h
new file mode 100644
index 0000000..76e86e3
--- /dev/null
+++ b/include/librfid/rfid.h
@@ -0,0 +1,32 @@
+#ifndef _RFID_H
+#define _RFID_H
+
+#include <stdio.h>
+
+#ifdef __LIBRFID__
+
+enum rfid_frametype {
+	RFID_14443A_FRAME_REGULAR,
+	RFID_14443B_FRAME_REGULAR,
+	RFID_MIFARE_FRAME,
+};
+
+#if 0
+#define DEBUGP(x, args ...) fprintf(stderr, "%s(%d):%s: " x, __FILE__, __LINE__, __FUNCTION__, ## args)
+#define DEBUGPC(x, args ...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args ...)
+#define DEBUGPC(x, args ...)
+#endif
+
+extern const char *rfid_hexdump(const void *data, unsigned int len);
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#endif /* __LIBRFID__ */
+
+int rfid_init();
+
+#endif /* _RFID_H */
diff --git a/include/librfid/rfid_asic.h b/include/librfid/rfid_asic.h
new file mode 100644
index 0000000..3686a7c
--- /dev/null
+++ b/include/librfid/rfid_asic.h
@@ -0,0 +1,45 @@
+#ifndef _RFID_ASIC_H
+#define _RFID_ASIC_H
+
+enum rfid_frametype;
+
+#include <librfid/rfid_asic_rc632.h>
+
+struct rfid_asic_transport {
+	char *name;
+	union {
+		struct rfid_asic_rc632_transport rc632;
+	} priv;
+};
+
+struct rfid_asic_transport_handle {
+	void *data;		/* handle to stuff like even lower layers */
+
+	struct rfid_asic_transport *rat;
+};
+
+
+struct rfid_asic_handle {
+	struct rfid_asic_transport_handle *rath;
+	unsigned int fc;
+	unsigned int mtu;
+	unsigned int mru;
+
+	union {
+		struct rfid_asic_rc632_handle rc632;
+		//struct rfid_asic_rc531_handle rc531;
+	} priv;
+	struct rfid_asic *asic;
+};
+
+
+struct rfid_asic {
+	char *name;
+	unsigned int fc;		/* carrier frequency */
+	union {
+		struct rfid_asic_rc632 rc632;
+		//struct rfid_asic_rc531 rc531;
+	} priv;
+};
+
+#endif /* _RFID_ASIC_H */
diff --git a/include/librfid/rfid_asic_rc632.h b/include/librfid/rfid_asic_rc632.h
new file mode 100644
index 0000000..893e73b
--- /dev/null
+++ b/include/librfid/rfid_asic_rc632.h
@@ -0,0 +1,160 @@
+#ifndef _RFID_ASIC_RC632_H
+#define _RFID_ASIC_RC632_H
+
+struct rfid_asic_transport_handle;
+
+#include <sys/types.h>
+#include <librfid/rfid_asic.h>
+
+struct rfid_asic_rc632_transport {
+	struct {
+		int (*reg_write)(struct rfid_asic_transport_handle *rath,
+				 u_int8_t reg,
+				 u_int8_t value);
+		int (*reg_read)(struct rfid_asic_transport_handle *rath,
+				u_int8_t reg,
+				u_int8_t *value);
+		int (*fifo_write)(struct rfid_asic_transport_handle *rath,
+				  u_int8_t len,
+				  const u_int8_t *buf,
+				  u_int8_t flags);
+		int (*fifo_read)(struct rfid_asic_transport_handle *rath,
+				 u_int8_t len,
+				 u_int8_t *buf);
+	} fn;
+};
+
+struct rfid_asic_handle;
+
+struct iso14443a_atqa;
+struct iso14443a_anticol_cmd;
+
+struct rfid_asic_rc632 {
+	struct {
+		int (*power_up)(struct rfid_asic_handle *h);
+		int (*power_down)(struct rfid_asic_handle *h);
+		int (*turn_on_rf)(struct rfid_asic_handle *h);
+		int (*turn_off_rf)(struct rfid_asic_handle *h);
+		int (*transcieve)(struct rfid_asic_handle *h,
+				  enum rfid_frametype,
+				  const u_int32_t *tx_buf,
+				  unsigned int tx_len,
+				  u_int32_t *rx_buf,
+				  unsigned int *rx_len,
+				  u_int64_t timeout,
+				  unsigned int flags);
+		struct {
+			int (*init)(struct rfid_asic_handle *h);
+			int (*transcieve_sf)(struct rfid_asic_handle *h,
+					     u_int32_t cmd,
+					     struct iso14443a_atqa *atqa);
+			int (*transcieve_acf)(struct rfid_asic_handle *h,
+					      struct iso14443a_anticol_cmd *cmd,
+					      unsigned int *bit_of_col);
+			int (*set_speed)(struct rfid_asic_handle *h,
+					 unsigned int tx,
+					 unsigned int speed);
+		} iso14443a;
+		struct {
+			int (*init)(struct rfid_asic_handle *h);
+		} iso14443b;
+		struct {
+			int (*init)(struct rfid_asic_handle *h);
+		} iso15693;
+		struct {
+			int (*setkey)(struct rfid_asic_handle *h,
+				      const unsigned char *key);
+			int (*auth)(struct rfid_asic_handle *h, u_int8_t cmd, 
+				    u_int32_t serno, u_int8_t block);
+		} mifare_classic;
+	} fn;
+};
+
+struct rc632_transport_handle {
+};
+
+/* A handle to a specific RC632 chip */
+struct rfid_asic_rc632_handle {
+	struct rc632_transport_handle th;
+};
+
+#if 0
+int 
+rc632_reg_write(struct rfid_asic_handle *handle,
+		u_int8_t reg,
+		u_int8_t val);
+
+int 
+rc632_reg_read(struct rfid_asic_handle *handle,
+	       u_int8_t reg,
+	       u_int8_t *val);
+int 
+rc632_fifo_write(struct rfid_asic_handle *handle,
+		 u_int8_t len,
+		 const u_int32_t *buf,
+		 u_int8_t flags);
+
+int 
+rc632_fifo_read(struct rfid_asic_handle *handle,
+		u_int8_t len,
+		u_int8_t *buf);
+
+int
+rc632_set_bits(struct rfid_asic_handle *handle, u_int8_t reg,
+		u_int82_t val);
+
+int 
+rc632_clear_bits(struct rfid_asic_handle *handle, u_int32_t reg,
+		 u_int32_t val);
+
+
+int 
+rc632_turn_on_rf(struct rfid_asic_handle *handle);
+
+
+int 
+rc632_turn_off_rf(struct rfid_asic_handle *handle);
+
+int
+rc632_power_up(struct rfid_asic_handle *handle);
+
+int
+rc632_power_down(struct rfid_asic_handle *handle);
+
+
+int
+rc632_wait_idle(struct rfid_asic_handle *handle, u_int64_t time);
+
+int
+rc632_transmit(struct rfid_asic_handle *handle,
+		const u_int32_t *buf,
+		u_int32_t len,
+		u_int64_t timeout);
+
+int
+rc632_transcieve(struct rfid_asic_handle *handle,
+		 const u_int32_t *tx_buf,
+		 u_int32_t tx_len,
+		 u_int32_t *rx_buf,
+		 u_int32_t *rx_len,
+		 unsigned int timer,
+		 unsigned int toggle);
+
+int
+rc632_read_eeprom(struct rfid_asic_handle *handle);
+
+
+int
+rc632_calc_crc16_from(struct rfid_asic_handle *handle);
+
+int
+rc632_register_dump(struct rfid_asic_handle *handle, u_int32_t *buf);
+
+
+struct rfid_asic_handle * rc632_open(struct rfid_asic_transport_handle *th);
+
+
+extern struct rfid_asic rc632;
+#endif
+
+#endif
diff --git a/include/librfid/rfid_layer2.h b/include/librfid/rfid_layer2.h
new file mode 100644
index 0000000..4622a02
--- /dev/null
+++ b/include/librfid/rfid_layer2.h
@@ -0,0 +1,76 @@
+#ifndef _RFID_LAYER2_H
+#define _RFID_LAYER2_H
+
+#include <sys/types.h>
+#include <librfid/rfid.h>
+
+struct rfid_layer2_handle;
+struct rfid_reader_handle;
+
+enum rfid_layer2_id {
+	RFID_LAYER2_NONE,
+	RFID_LAYER2_ISO14443A,
+	RFID_LAYER2_ISO14443B,
+	RFID_LAYER2_ISO15693,
+};
+
+struct rfid_layer2_handle *rfid_layer2_init(struct rfid_reader_handle *rh,
+					    unsigned int id);
+int rfid_layer2_open(struct rfid_layer2_handle *l2h);
+int rfid_layer2_transcieve(struct rfid_layer2_handle *l2h,
+			   enum rfid_frametype frametype,
+			   const unsigned char *tx_buf, unsigned int tx_len,
+			   unsigned char *rx_buf, unsigned int *rx_len,
+			   u_int64_t timeout, unsigned int flags);
+int rfid_layer2_close(struct rfid_layer2_handle *l2h);
+int rfid_layer2_fini(struct rfid_layer2_handle *l2h);
+int rfid_layer2_getopt(struct rfid_layer2_handle *ph, int optname,
+			void *optval, unsigned int *optlen);
+int rfid_layer2_setopt(struct rfid_layer2_handle *ph, int optname,
+			const void *optval, unsigned int optlen);
+
+#ifdef __LIBRFID__
+
+#include <librfid/rfid_layer2_iso14443a.h>
+#include <librfid/rfid_layer2_iso14443b.h>
+#include <librfid/rfid_layer2_iso15693.h>
+
+struct rfid_layer2 {
+	unsigned int id;
+	char *name;
+
+	struct {
+		struct rfid_layer2_handle *(*init)(struct rfid_reader_handle *h);
+		int (*open)(struct rfid_layer2_handle *h);
+		int (*transcieve)(struct rfid_layer2_handle *h,
+				  enum rfid_frametype frametype,
+				  const unsigned char *tx_buf, 
+				  unsigned int tx_len, unsigned char *rx_buf, 
+				  unsigned int *rx_len, u_int64_t timeout,
+				  unsigned int flags);
+		int (*close)(struct rfid_layer2_handle *h);
+		int (*fini)(struct rfid_layer2_handle *h);
+		int (*getopt)(struct rfid_layer2_handle *h,
+			      int optname, void *optval, unsigned int *optlen);
+		int (*setopt)(struct rfid_layer2_handle *h,
+			      int optname, const void *optval,
+			      unsigned int optlen);
+	} fn;
+	struct rfid_layer2 *next;
+};
+
+struct rfid_layer2_handle {
+	struct rfid_reader_handle *rh;
+	unsigned char uid[10];	/* triple size 14443a id is 10 bytes */
+	unsigned int uid_len;
+	union {
+		struct iso14443a_handle iso14443a;
+		struct iso14443b_handle iso14443b;
+		struct iso15693_handle iso15693;
+	} priv;
+	struct rfid_layer2 *l2;
+};
+
+#endif /* __LIBRFID__ */
+
+#endif
diff --git a/include/librfid/rfid_layer2_iso14443a.h b/include/librfid/rfid_layer2_iso14443a.h
new file mode 100644
index 0000000..50a6f43
--- /dev/null
+++ b/include/librfid/rfid_layer2_iso14443a.h
@@ -0,0 +1,84 @@
+#ifndef _RFID_ISO14443A_H
+#define _RFID_ISO14443A_H
+
+enum rfid_14443a_opt {
+	RFID_OPT_14443A_SPEED_RX	= 0x00000001,
+	RFID_OPT_14443A_SPEED_TX	= 0x00000002,
+};
+
+enum rfid_14443_opt_speed {
+	RFID_14443A_SPEED_106K	= 0x01,
+	RFID_14443A_SPEED_212K	= 0x02,
+	RFID_14443A_SPEED_424K  = 0x04,
+	RFID_14443A_SPEED_848K  = 0x08,
+};
+
+#ifdef __LIBRFID__
+
+#include <sys/types.h>
+
+/* protocol definitions */
+
+/* ISO 14443-3, Chapter 6.3.1 */
+enum iso14443a_sf_cmd {
+	ISO14443A_SF_CMD_REQA		= 0x26,
+	ISO14443A_SF_CMD_WUPA		= 0x52,
+	ISO14443A_SF_CMD_OPT_TIMESLOT	= 0x35,		/* Annex C */
+	/* 40 to 4f and 78 to 7f: proprietary */
+};
+
+struct iso14443a_atqa {
+	u_int8_t bf_anticol:5,
+		 rfu1:1,
+		 uid_size:2;
+	u_int8_t proprietary:4,
+		 rfu2:4;
+};
+
+#define ISO14443A_HLTA		0x5000
+
+/* ISO 14443-3, Chapter 6.3.2 */
+struct iso14443a_anticol_cmd {
+	unsigned char		sel_code;
+	unsigned char		nvb;
+	unsigned char		uid_bits[5];
+};
+
+enum iso14443a_anticol_sel_code {
+	ISO14443A_AC_SEL_CODE_CL1	= 0x93,
+	ISO14443A_AC_SEL_CODE_CL2	= 0x95,
+	ISO14443A_AC_SEL_CODE_CL3	= 0x97,
+};
+
+#define	ISO14443A_BITOFCOL_NONE		0xffffffff
+
+struct iso14443a_handle {
+	unsigned int state;
+	unsigned int level;
+	unsigned int tcl_capable;
+};
+
+enum iso14443a_level {
+	ISO14443A_LEVEL_NONE,
+	ISO14443A_LEVEL_CL1,
+	ISO14443A_LEVEL_CL2,
+	ISO14443A_LEVEL_CL3,
+};
+
+enum iso14443a_state {
+	ISO14443A_STATE_ERROR,
+	ISO14443A_STATE_NONE,
+	ISO14443A_STATE_REQA_SENT,
+	ISO14443A_STATE_ATQA_RCVD,
+	ISO14443A_STATE_NO_BITFRAME_ANTICOL,
+	ISO14443A_STATE_ANTICOL_RUNNING,
+	ISO14443A_STATE_SELECTED,
+};
+
+#include <librfid/rfid_layer2.h>
+struct rfid_layer2 rfid_layer2_iso14443a;
+
+#endif /* __LIBRFID__ */
+
+
+#endif /* _ISO14443A_H */
diff --git a/include/librfid/rfid_layer2_iso14443b.h b/include/librfid/rfid_layer2_iso14443b.h
new file mode 100644
index 0000000..5d6d979
--- /dev/null
+++ b/include/librfid/rfid_layer2_iso14443b.h
@@ -0,0 +1,85 @@
+#ifndef _RFID_LAYER2_ISO14443B_H
+#define _RFID_LAYER2_ISO14443B_H
+
+#ifdef __LIBRFID__
+
+struct iso14443b_atqb {
+	unsigned char fifty;
+	unsigned char pupi[4];
+	unsigned char app_data[4];
+	struct {
+		unsigned char bit_rate_capability;
+		unsigned char protocol_type:4,
+			      max_frame_size:4;
+		unsigned char fo:2,
+			      adc:2,
+			      fwi:4;
+	} protocol_info;
+};
+
+struct iso14443b_attrib_hdr {
+	unsigned char one_d;
+	unsigned char identifier[4];
+	struct {
+		unsigned char rfu:2,
+			      sof:1,
+			      eof:1,
+			      min_tr1:2,
+			      min_tr0:2;
+	} param1;
+	struct {
+		unsigned char fsdi:4,
+			      spd_out:2,
+			      spd_in:2;
+	} param2;
+	struct {
+		unsigned char protocol_type:4,
+			      rfu:4;
+	} param3;
+	struct {
+		unsigned char cid:4,
+			      rfu:4;
+	} param4;
+};
+
+struct iso14443b_handle {
+	unsigned int tcl_capable; /* do we support T=CL */
+
+	unsigned int cid;	/* Card ID */
+
+	unsigned int fsc;	/* max. frame size card */
+	unsigned int fsd;	/* max. frame size reader */
+
+	unsigned int fwt;	/* frame waiting time (in usec) */
+
+	unsigned int mbl;	/* maximum buffer length */
+
+	unsigned int tr0;	/* pcd-eof to picc-subcarrier-on */
+	unsigned int tr1;	/* picc-subcarrier-on to picc-sof */
+
+	unsigned int flags;
+	unsigned int state;
+};
+
+enum {
+	ISO14443B_CID_SUPPORTED = 0x01,
+	ISO14443B_NAD_SUPPORTED = 0x02,
+};
+
+enum {
+	ISO14443B_STATE_ERROR,
+	ISO14443B_STATE_NONE,
+	ISO14443B_STATE_REQB_SENT,
+	ISO14443B_STATE_ATQB_RCVD,
+	ISO14443B_STATE_ATTRIB_SENT,
+	ISO14443B_STATE_SELECTED,
+	ISO14443B_STATE_HLTB_SENT,
+	ISO14443B_STATE_HALTED,
+};
+
+#include <librfid/rfid_layer2.h>
+struct rfid_layer2 rfid_layer2_iso14443b;
+
+#endif /* __LIBRFID__ */
+
+#endif
diff --git a/include/librfid/rfid_layer2_iso15693.h b/include/librfid/rfid_layer2_iso15693.h
new file mode 100644
index 0000000..ea7f87a
--- /dev/null
+++ b/include/librfid/rfid_layer2_iso15693.h
@@ -0,0 +1,55 @@
+#ifndef _RFID_ISO15693_H
+#define _RFID_ISO15693_H
+
+#include <sys/types.h>
+
+/*
+07h = TagIt
+04h = I.CODE
+05h = Infineon
+02h = ST
+*/
+
+/* protocol definitions */
+
+struct iso15693_handle;
+
+struct iso15693_transport {
+	unsigned char	*name;
+
+	struct {
+		int (*init)(struct iso15693_handle *handle);
+		int (*fini)(struct iso15693_handle *handle);
+
+#if 0
+		int (*transcieve_sf)(struct iso14443a_handle *handle,
+				     unsigned char cmd,
+				     struct iso14443a_atqa *atqa);
+		int (*transcieve_acf)(struct iso14443a_handle *handle,
+				      struct iso14443a_anticol_cmd *acf,
+				      unsigned int *bit_of_col);
+#endif
+		int (*transcieve)(struct iso15693_handle *handle,
+				  const unsigned char *tx_buf,
+				  unsigned int tx_len,
+				  unsigned char *rx_buf,
+				  unsigned int *rx_len);
+	} fn;
+
+	union {
+	} priv;
+};
+
+struct iso15693_handle {
+	unsigned int state;
+};
+
+enum iso15693_state {
+	ISO15693_STATE_ERROR,
+	ISO15693_STATE_NONE,
+};
+
+#include <librfid/rfid_layer2.h>
+extern struct rfid_layer2 rfid_layer2_iso15693;
+
+#endif /* _ISO15693_H */
diff --git a/include/librfid/rfid_protocol.h b/include/librfid/rfid_protocol.h
new file mode 100644
index 0000000..65bda4c
--- /dev/null
+++ b/include/librfid/rfid_protocol.h
@@ -0,0 +1,88 @@
+#ifndef _RFID_PROTOCOL_H
+#define _RFID_PROTOCOL_H
+
+#include <librfid/rfid_layer2.h>
+
+struct rfid_protocol_handle;
+
+struct rfid_protocol_handle *
+rfid_protocol_init(struct rfid_layer2_handle *l2h, unsigned int id);
+int rfid_protocol_open(struct rfid_protocol_handle *ph);
+int rfid_protocol_transcieve(struct rfid_protocol_handle *ph,
+			     const unsigned char *tx_buf, unsigned int tx_len,
+			     unsigned char *rx_buf, unsigned int *rx_len,
+			     unsigned int timeout, unsigned int flags);
+int
+rfid_protocol_read(struct rfid_protocol_handle *ph,
+	 	   unsigned int page,
+		   unsigned char *rx_data,
+		   unsigned int *rx_len);
+
+int
+rfid_protocol_write(struct rfid_protocol_handle *ph,
+	 	   unsigned int page,
+		   unsigned char *tx_data,
+		   unsigned int tx_len);
+
+int rfid_protocol_fini(struct rfid_protocol_handle *ph);
+int rfid_protocol_close(struct rfid_protocol_handle *ph);
+
+enum rfid_protocol_id {
+	RFID_PROTOCOL_UNKNOWN,
+	RFID_PROTOCOL_TCL,
+	RFID_PROTOCOL_MIFARE_UL,
+	RFID_PROTOCOL_MIFARE_CLASSIC,
+};
+
+
+#ifdef __LIBRFID__
+
+struct rfid_protocol {
+	struct rfid_protocol *next;
+	unsigned int id;
+	char *name;
+	struct {
+		struct rfid_protocol_handle *(*init)(struct rfid_layer2_handle *l2h);
+		int (*open)(struct rfid_protocol_handle *ph);
+		int (*close)(struct rfid_protocol_handle *ph);
+		int (*fini)(struct rfid_protocol_handle *ph);
+		/* transcieve for session based transport protocols */
+		int (*transcieve)(struct rfid_protocol_handle *ph,
+				  const unsigned char *tx_buf,
+				  unsigned int tx_len,
+				  unsigned char *rx_buf,
+				  unsigned int *rx_len,
+				  unsigned int timeout,
+				  unsigned int flags);
+		/* read/write for synchronous memory cards */
+		int (*read)(struct rfid_protocol_handle *ph,
+			    unsigned int page,
+			    unsigned char *rx_data,
+			    unsigned int *rx_len);
+		int (*write)(struct rfid_protocol_handle *ph,
+			     unsigned int page,
+			     unsigned char *tx_data,
+			     unsigned int tx_len);
+	} fn;
+};
+
+int rfid_protocol_register(struct rfid_protocol *p);
+
+#include <librfid/rfid_protocol_tcl.h>
+#include <librfid/rfid_protocol_mifare_ul.h>
+#include <librfid/rfid_protocol_mifare_classic.h>
+
+struct rfid_protocol_handle {
+	struct rfid_layer2_handle *l2h;
+	struct rfid_protocol *proto;
+	union {
+		struct tcl_handle tcl;
+	} priv;				/* priv has to be last, since
+					 * it could contain additional
+					 * private data over the end of
+					 * sizeof(priv). */
+};
+
+#endif /* __LIBRFID__ */
+
+#endif /* _RFID_PROTOCOL_H */
diff --git a/include/librfid/rfid_protocol_mifare_classic.h b/include/librfid/rfid_protocol_mifare_classic.h
new file mode 100644
index 0000000..e6b2400
--- /dev/null
+++ b/include/librfid/rfid_protocol_mifare_classic.h
@@ -0,0 +1,28 @@
+#ifndef _MIFARE_CLASSIC_H
+
+#define MIFARE_CL_KEYA_DEFAULT	"\xa0\xa1\xa2\xa3\xa4\xa5"
+#define MIFARE_CL_KEYB_DEFAULT	"\xb0\xb1\xb2\xb3\xb4\xb5"
+
+#define MIFARE_CL_KEYA_DEFAULT_INFINEON	"\xff\xff\xff\xff\xff\xff"
+#define MIFARE_CL_KEYB_DEFAULT_INFINEON MIFARE_CL_KEYA_DEFAULT_INFINEON
+
+#define MIFARE_CL_PAGE_MAX	0xff
+
+#define RFID_CMD_MIFARE_AUTH1A	0x60
+#define RFID_CMD_MIFARE_AUTH1B	0x61
+
+#ifdef __LIBRFID__
+
+extern struct rfid_protocol rfid_protocol_mfcl;
+
+
+#define MIFARE_CL_CMD_WRITE16	0xA0
+#define MIFARE_CL_CMD_READ	0x30
+
+#define MIFARE_CL_RESP_ACK	0x0a
+#define MIFARE_CL_RESP_NAK	0x00
+
+
+#endif /* __LIBRFID__ */
+
+#endif /* _MIFARE_CLASSIC_H */
diff --git a/include/librfid/rfid_protocol_mifare_ul.h b/include/librfid/rfid_protocol_mifare_ul.h
new file mode 100644
index 0000000..cc93b6b
--- /dev/null
+++ b/include/librfid/rfid_protocol_mifare_ul.h
@@ -0,0 +1,24 @@
+#ifndef _RFID_PROTOCOL_MFUL_H
+#define _RFID_PROTOCOL_MFUL_H
+
+int rfid_mful_lock_page(struct rfid_protocol_handle *ph, unsigned int page);
+int rfid_mful_lock_otp(struct rfid_protocol_handle *ph);
+
+#define MIFARE_UL_PAGE_MAX	15
+
+#ifdef __LIBRFID__
+
+#define MIFARE_UL_CMD_WRITE	0xA2
+#define MIFARE_UL_CMD_READ	0x30
+
+#define MIFARE_UL_RESP_ACK	0x0a
+#define MIFARE_UL_RESP_NAK	0x00
+
+#define MIFARE_UL_PAGE_LOCK	2
+#define MIFARE_UL_PAGE_OTP	3
+
+extern struct rfid_protocol rfid_protocol_mful;
+
+#endif /* __LIBRFID__ */
+
+#endif
diff --git a/include/librfid/rfid_protocol_tcl.h b/include/librfid/rfid_protocol_tcl.h
new file mode 100644
index 0000000..f754ad9
--- /dev/null
+++ b/include/librfid/rfid_protocol_tcl.h
@@ -0,0 +1,70 @@
+#ifndef _RFID_PROTOCOL_TCL_H
+#define _RFID_PROTOCOL_TCL_H
+
+#ifdef __LIBRFID__
+
+enum tcl_transport_rate {
+	TCL_RATE_106	= 0x01,
+	TCL_RATE_212	= 0x02,
+	TCL_RATE_424	= 0x04,
+	TCL_RATE_848	= 0x08,
+};
+
+enum tcl_transport_transcieve_flags {
+	TCL_TRANSP_F_TX_CRC	= 0x01,	/* transport adds TX CRC */
+	TCL_TRANSP_F_RX_CRC	= 0x02, 
+};
+
+struct tcl_handle {
+	/* derived from ats */
+	unsigned char *historical_bytes; /* points into ats */
+	unsigned int historical_len;
+
+	unsigned int fsc;	/* max frame size accepted by card */
+	unsigned int fsd;	/* max frame size accepted by reader */
+	unsigned int fwt;	/* frame waiting time (in usec)*/
+	unsigned char ta;	/* divisor information */
+	unsigned char sfgt;	/* start-up frame guard time (in usec) */
+
+	/* otherwise determined */
+	unsigned int cid;	/* Card ID */
+	unsigned int nad;	/* Node Address */
+
+	unsigned int flags;
+	unsigned int state;	/* protocol state */
+
+	unsigned int toggle;	/* send toggle with next frame */
+
+	unsigned int ats_len;
+	unsigned char ats[0];
+};
+
+enum tcl_handle_flags {
+	TCL_HANDLE_F_NAD_SUPPORTED 	= 0x0001,
+	TCL_HANDLE_F_CID_SUPPORTED 	= 0x0002,
+	TCL_HANDLE_F_NAD_USED		= 0x0010,
+	TCL_HANDLE_F_CID_USED		= 0x0020,
+};
+
+
+enum tcl_pcb_bits {
+	TCL_PCB_CID_FOLLOWING		= 0x08,
+	TCL_PCB_NAD_FOLLOWING		= 0x04,
+};
+
+enum tcl_pcd_state {
+	TCL_STATE_NONE = 0x00,
+	TCL_STATE_INITIAL,
+	TCL_STATE_RATS_SENT,		/* waiting for ATS */
+	TCL_STATE_ATS_RCVD,		/* ATS received */
+	TCL_STATE_PPS_SENT,		/* waiting for PPS response */
+	TCL_STATE_ESTABLISHED,		/* xchg transparent data */
+	TCL_STATE_DESELECT_SENT,	/* waiting for DESELECT response */
+	TCL_STATE_DESELECTED,		/* card deselected or HLTA'd */
+};
+
+struct rfid_protocol rfid_protocol_tcl;
+
+#endif /* __LIBRFID__ */
+
+#endif
diff --git a/include/librfid/rfid_reader.h b/include/librfid/rfid_reader.h
new file mode 100644
index 0000000..3581cc1
--- /dev/null
+++ b/include/librfid/rfid_reader.h
@@ -0,0 +1,67 @@
+#ifndef _RFID_READER_H
+#define _RFID_READER_H
+
+#include <librfid/rfid_asic.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+
+struct rfid_reader_handle;
+
+struct rfid_reader {
+	char *name;
+	unsigned int id;
+	int (*transcieve)(struct rfid_reader_handle *h,
+			  enum rfid_frametype frametype,
+			  const unsigned char *tx_buf, unsigned int tx_len,
+			  unsigned char *rx_buf, unsigned int *rx_len,
+			  u_int64_t timeout, unsigned int flags);
+	struct rfid_reader_handle * (*open)(void *data);
+	void (*close)(struct rfid_reader_handle *h);
+
+	struct rfid_14443a_reader {
+		int (*init)(struct rfid_reader_handle *h);
+		int (*transcieve_sf)(struct rfid_reader_handle *h,
+				     unsigned char cmd,
+				     struct iso14443a_atqa *atqa);
+		int (*transcieve_acf)(struct rfid_reader_handle *h,
+				      struct iso14443a_anticol_cmd *cmd,
+				      unsigned int *bit_of_col);
+		int (*set_speed)(struct rfid_reader_handle *h,
+				 unsigned int tx,
+				 unsigned int speed);
+		unsigned int speed;
+	} iso14443a;
+	struct rfid_14443b_reader {
+		int (*init)(struct rfid_reader_handle *rh);
+		unsigned int speed;
+	} iso14443b;
+	struct rfid_15693_reader {
+		int (*init)(struct rfid_reader_handle *rh);
+	} iso15693;
+	struct rfid_mifare_classic_reader {
+		int (*setkey)(struct rfid_reader_handle *h, unsigned char *key);
+		int (*auth)(struct rfid_reader_handle *h, u_int8_t cmd,
+			    u_int32_t serno, u_int8_t block);
+	} mifare_classic;
+	struct rfid_reader *next;
+};
+
+enum rfid_reader_id {
+	RFID_READER_CM5121,
+	RFID_READER_PEGODA,
+};
+
+struct rfid_reader_handle {
+	struct rfid_asic_handle *ah;
+
+	union {
+
+	} priv;
+	struct rfid_reader *reader;
+};
+
+
+extern struct rfid_reader_handle *
+rfid_reader_open(void *data, unsigned int id);
+
+extern void rfid_reader_close(struct rfid_reader_handle *rh);
+#endif
diff --git a/include/librfid/rfid_reader_cm5121.h b/include/librfid/rfid_reader_cm5121.h
new file mode 100644
index 0000000..8d9a312
--- /dev/null
+++ b/include/librfid/rfid_reader_cm5121.h
@@ -0,0 +1,21 @@
+#ifndef _RFID_READER_CM5121_H
+#define _RFID_READER_CM5121_H
+
+#define CM5121_CW_CONDUCTANCE	0x3f
+#define CM5121_MOD_CONDUCTANCE	0x3f
+#define CM5121_14443A_BITPHASE	0xa9
+#define CM5121_14443A_THRESHOLD	0xff
+
+#define CM5121_14443B_BITPHASE	0xad
+#define CM5121_14443B_THRESHOLD	0xff
+
+
+extern int
+PC_to_RDR_Escape(void *handle,
+		const unsigned char *tx_buf, unsigned int tx_len,
+		unsigned char *rx_buf, unsigned int *rx_len);
+
+extern struct rfid_reader rfid_reader_cm5121;
+// extern struct rfid_asic_transport cm5121_ccid;
+
+#endif
diff --git a/pegoda/Makefile b/pegoda/Makefile
new file mode 100644
index 0000000..7310022
--- /dev/null
+++ b/pegoda/Makefile
@@ -0,0 +1,8 @@
+
+all: pegoda
+
+pegoda: pegoda.o
+	$(CC) -lusb -o $@ $^
+
+clean:
+	rm -f pegoda *.o
diff --git a/pegoda/pegoda.c b/pegoda/pegoda.c
new file mode 100644
index 0000000..2eaa61e
--- /dev/null
+++ b/pegoda/pegoda.c
@@ -0,0 +1,292 @@
+/*
+ *  (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <usb.h>
+#include "pegoda.h"
+
+const char *
+hexdump(const void *data, unsigned int len)
+{
+	static char string[1024];
+	unsigned char *d = (unsigned char *) data;
+	unsigned int i, left;
+
+	string[0] = '\0';
+	left = sizeof(string);
+	for (i = 0; len--; i += 3) {
+		if (i >= sizeof(string) -4)
+			break;
+		snprintf(string+i, 4, " %02x", *d++);
+	}
+	return string;
+}
+
+struct pegoda_handle {
+	struct usb_dev_handle *handle;
+	unsigned char seq;
+	unsigned char snr[4];
+};
+
+
+struct usb_device *find_device(u_int16_t vendor, u_int16_t device)
+{
+	struct usb_bus *bus;
+
+	for (bus = usb_get_busses(); bus; bus = bus->next) {
+		struct usb_device *dev;
+		for (dev = bus->devices; dev; dev = dev->next) {
+			if (dev->descriptor.idVendor == vendor &&
+			    dev->descriptor.idProduct == device) {
+				return dev;
+			}
+		}
+	}
+	return NULL;
+}
+
+int pegoda_transcieve(struct pegoda_handle *ph,
+		      u_int8_t cmd, unsigned char *tx, unsigned int tx_len,
+		      unsigned char *rx, unsigned int *rx_len)
+{
+	unsigned char txbuf[256];
+	unsigned char rxbuf[256];
+	int rc;
+	unsigned int len_expected;
+	struct pegoda_cmd_hdr *hdr = (struct pegoda_cmd_hdr *)txbuf;
+	struct pegoda_cmd_hdr *rxhdr = (struct pegoda_cmd_hdr *)rxbuf;
+
+	hdr->seq = ++(ph->seq);
+	hdr->cmd = cmd;
+	hdr->len = htons(tx_len);
+	memcpy(txbuf + sizeof(*hdr), tx, tx_len);
+
+	printf("tx [%u]: %s\n", tx_len+sizeof(*hdr),
+		hexdump(txbuf, tx_len + sizeof(*hdr)));
+	rc = usb_bulk_write(ph->handle, 0x02, (char *)txbuf,
+			    tx_len + sizeof(*hdr), 0);
+	if (rc < 0)
+		return rc;
+
+	rc = usb_bulk_read(ph->handle, 0x81, (char *)rxbuf, sizeof(rxbuf), 0);
+	if (rc <= 0)
+		return rc;
+
+	if (rc != 2) {
+		fprintf(stderr, "unexpected: received %u bytes as length?\n");
+		return -EIO;
+	}
+	printf("len [%u]: %s\n", rc, hexdump(rxbuf, rc));
+
+	len_expected = rxbuf[0];
+
+	if (len_expected > sizeof(rxbuf))
+		return -EIO;
+
+	rc = usb_bulk_read(ph->handle, 0x81, (char *)rxbuf, len_expected, 0);
+	if (rc <= 0)
+		return rc;
+	printf("rx [%u]: %s\n", rc, hexdump(rxbuf, rc));
+
+	if (rc < 4)
+		return -EIO;
+
+	if (rxhdr->seq != hdr->seq)
+		return -EIO;
+
+	*rx_len = ntohs(rxhdr->len);
+
+	memcpy(rx, rxbuf+sizeof(*rxhdr), rc-sizeof(*rxhdr));
+
+	return 0;
+}
+
+struct pegoda_handle *pegoda_open(void)
+{
+	struct usb_device *pegoda;
+	unsigned char rbuf[16];
+	unsigned int rlen = sizeof(rbuf);
+	struct pegoda_handle *ph;
+
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+
+	pegoda = find_device(USB_VENDOR_PHILIPS, USB_DEVICE_PEGODA);
+
+	if (!pegoda)
+		return NULL;
+
+	ph = malloc(sizeof(*ph));
+	if (!ph)
+		return NULL;
+	memset(ph, 0, sizeof(*ph));
+
+	printf("found pegoda, %u configurations\n",
+		pegoda->descriptor.bNumConfigurations);
+
+	printf("config 2 [nr %u] has %u interfaces\n",
+		pegoda->config[1].bConfigurationValue,
+		pegoda->config[1].bNumInterfaces);
+
+	printf("config 2 interface 0 has %u altsettings\n",
+		pegoda->config[1].interface[0].num_altsetting);
+
+	ph->handle = usb_open(pegoda);
+	if (!ph->handle) 
+		goto out_free;
+
+	if (usb_set_configuration(ph->handle, 2))
+		goto out_free;
+
+	printf("configuration 2 successfully set\n");
+
+	if (usb_claim_interface(ph->handle, 0))
+		goto out_free;
+
+	printf("interface 0 claimed\n");
+
+	if (usb_set_altinterface(ph->handle, 1))
+		goto out_free;
+
+	printf("alt setting 1 selected\n");
+
+	pegoda_transcieve(ph, PEGODA_CMD_PCD_CONFIG, NULL, 0, rbuf, &rlen);
+
+	return ph;
+out_free:
+	free(ph);
+	return NULL;
+}
+
+/* Transform crypto1 key from generic 6byte into rc632 specific 12byte */
+static int
+mifare_transform_key(const u_int8_t *key6, u_int8_t *key12)
+{
+	int i;
+	u_int8_t ln;
+	u_int8_t hn;
+
+	for (i = 0; i < 6; i++) {
+		ln = key6[i] & 0x0f;
+		hn = key6[i] >> 4;
+		key12[i * 2 + 1] = (~ln << 4) | ln;
+		key12[i * 2] = (~hn << 4) | hn;
+	}
+	return 0;
+}
+
+static int pegoda_auth_e2(struct pegoda_handle *ph,
+			  u_int8_t keynr, u_int8_t sector)
+{
+	unsigned char buf[3];
+	unsigned char rbuf[16];
+	unsigned int rlen = sizeof(rbuf);
+
+	buf[0] = 0x60;
+	buf[1] = keynr;		/* key number */
+	buf[2] = sector;	/* sector */
+	rlen = sizeof(rbuf);
+	pegoda_transcieve(ph, PEGODA_CMD_PICC_AUTH, buf, 3, rbuf, &rlen);
+
+	/* FIXME: check response */
+
+	return 0;
+}
+
+static int pegoda_auth_key(struct pegoda_handle *ph,
+			   u_int8_t sector, const unsigned char *key6)
+{
+	unsigned char buf[1+4+12+1];
+	unsigned char rbuf[16];
+	unsigned int rlen = sizeof(rbuf);
+
+	buf[0] = 0x60;
+	memcpy(buf+1, ph->snr, 4);
+	mifare_transform_key(key6, buf+5);
+	buf[17] = sector;
+
+	pegoda_transcieve(ph, PEGODA_CMD_PICC_AUTH_KEY, buf, 18, rbuf, &rlen);
+
+	/* FIXME: check response */
+
+	return 0;
+}
+
+static int pegoda_read16(struct pegoda_handle *ph,
+			 u_int8_t page, unsigned char *rx)
+{
+	int rc;
+	unsigned int rlen = 16;
+
+	rc = pegoda_transcieve(ph, PEGODA_CMD_PICC_READ,
+				&page, 1, rx, &rlen);
+	if (rlen != 16)
+		return -EIO;
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	unsigned char buf[256];
+	unsigned char rbuf[256];
+	unsigned int rlen = sizeof(rbuf);
+	struct pegoda_handle *ph;
+
+	ph = pegoda_open();
+	if (!ph)
+		exit(1);
+
+	/* LED off */
+	buf[0] = 0x00;
+	rlen = sizeof(rbuf);
+	pegoda_transcieve(ph, PEGODA_CMD_SWITCH_LED, buf, 1, rbuf, &rlen);
+
+	/* anticollision */
+
+	buf[0] = 0x26;
+	rlen = sizeof(rbuf);
+	pegoda_transcieve(ph, PEGODA_CMD_PICC_COMMON_REQUEST, 
+			  buf, 1, rbuf, &rlen);
+
+	buf[0] = 0x93;
+	memset(buf+1, 0, 5);
+	rlen = sizeof(rbuf);
+	pegoda_transcieve(ph, PEGODA_CMD_PICC_CASC_ANTICOLL, 
+			  buf, 6, rbuf, &rlen);
+
+	memcpy(ph->snr, rbuf, 4);
+
+	buf[0] = 0x93;
+	memcpy(buf+1, ph->snr, 4);
+	rlen = sizeof(rbuf);
+	pegoda_transcieve(ph, PEGODA_CMD_PICC_CASC_SELECT, 
+			  buf, 5, rbuf, &rlen);
+
+	pegoda_auth_key(ph, 0, "\xff\xff\xff\xff\xff\xff");
+	pegoda_read16(ph, 0, rbuf);
+	printf("read16 = %s\n", hexdump(rbuf, 16));
+	
+	exit(0);
+}
diff --git a/pegoda/pegoda.h b/pegoda/pegoda.h
new file mode 100644
index 0000000..236dc0a
--- /dev/null
+++ b/pegoda/pegoda.h
@@ -0,0 +1,140 @@
+#ifndef _PEGODA_H
+#define _PEGODA_H
+/*
+ *  (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#define USB_VENDOR_PHILIPS	0x0742
+#define USB_DEVICE_PEGODA	0xff01
+
+/* header of a pegoda usb command packet */
+struct pegoda_cmd_hdr {
+	u_int8_t seq;
+	u_int8_t cmd;
+	u_int16_t len;
+};
+
+enum {
+	PEGODA_CMD_WRITE_RC			= 0x01,
+	PEGODA_CMD_READ_RC			= 0x02,
+	PEGODA_CMD_EXCHANGE_BYTESTREAM		= 0x03,
+	PEGODA_CMD_WRITE_MULTIPLE		= 0x04,
+	PEGODA_CMD_READ_MULTIPLE		= 0x05,
+	PEGODA_CMD_READ_WORD			= 0x06,
+
+	
+	PEGODA_CMD_PCD_CONFIG			= 0x10,
+	PEGODA_CMD_PICC_REQUEST			= 0x11,
+	PEGODA_CMD_PICC_ANTICOLL		= 0x12,
+	PEGODA_CMD_PICC_SELECT			= 0x13,
+	PEGODA_CMD_PICC_AUTH			= 0x14,
+	PEGODA_CMD_PICC_AUTH_E2			= 0x15,
+	PEGODA_CMD_LOAD_KEY_E2			= 0x17,
+	PEGODA_CMD_PICC_AUTH_KEY		= 0x18,
+	PEGODA_CMD_PICC_READ			= 0x19,
+	PEGODA_CMD_PICC_WRITE			= 0x1a,
+	PEGODA_CMD_PICC_VALUE			= 0x1b,
+	PEGODA_CMD_PICC_VALUE_DEBIT		= 0x1c,
+	PEGODA_CMD_PICC_HALT			= 0x1d,
+	PEGODA_CMD_PICC_WRITE4			= 0x1e,
+	PEGODA_CMD_PICC_COMMON_WRITE		= 0x1f,
+
+	PEGODA_CMD_PCD_RF_RESET			= 0x20,
+	PEGODA_CMD_PCD_RESET			= 0x21,
+	PEGODA_CMD_PCD_GET_SNR			= 0x22,
+	PEGODA_CMD_PCD_READ_E2			= 0x23,
+	PEGODA_CMD_PCD_SET_TMO			= 0x27,
+	PEGODA_CMD_PICC_COMMON_READ		= 0x28,
+	PEGODA_CMD_PCD_INITIALIZE_E2		= 0x29,
+	PEGODA_CMD_ACTIVE_ANTENNA_MASTER	= 0x2a,
+	PEGODA_CMD_ACTIVE_ANTENNA_SLAVE		= 0x2b,
+
+	PEGODA_CMD_HOST_TRANS_TMR_START		= 0x30,
+	PEGODA_CMD_HOST_TRANS_TMR_STOP		= 0x31,
+	PEGODA_CMD_HOST_GET_EXEC_TIME		= 0x32,
+
+	PEGODA_CMD_PICC_COMMON_REQUEST		= 0x40,
+	PEGODA_CMD_PICC_CASC_ANTICOLL		= 0x41,
+	PEGODA_CMD_PICC_CASC_SELECT		= 0x42,
+	PEGODA_CMD_PICC_ACTIVATE_IDLE		= 0x43,
+	PEGODA_CMD_PICC_ACTIVATE_WAKEUP		= 0x44,
+	PEGODA_CMD_PCD_SET_DEFAULT_ATTRIB	= 0x45,
+	PEGODA_CMD_PCD_SET_ATTRIB		= 0x46,
+	PEGODA_CMD_PCD_GET_ATTRIB		= 0x47,
+	PEGODA_CMD_PICC_EXCHANGE_BLOCK		= 0x48,
+	PEGODA_CMD_PICC_ACTIVATE_IDLE_LOOP	= 0x49,
+	PEGODA_CMD_PICC_ACTTIVATION		= 0x4a,
+	PEGODA_CMD_PCD_ENABLE_HIGH_BAUD_RATES	= 0x4b,
+
+	PEGODA_CMD_SWITCH_LED			= 0x60,
+	PEGODA_CMD_TEST_FLASH_NR		= 0x61,
+	PEGODA_CMD_START_DOWNLOAD		= 0x62,
+	PEGODA_CMD_GET_FW_VERSION		= 0x63,
+	PEGODA_CMD_GET_RIC_VERSION		= 0x64,
+	PEGODA_CMD_ENABLE_DEBUG_PINS		= 0x65,
+	PEGODA_CMD_MIRROR_DATA			= 0x66,
+	PEGODA_CMD_TEST_CMDS			= 0x67,
+
+	PEGODA_CMD_TEST_PCD			= 0x70,
+	PEGODA_CMD_TEST_PICC			= 0x71,
+	PEGODA_CMD_GET_ONLINE_STATUS		= 0x72,
+
+	PEGODA_CMD_I1_PCD_CONFIG		= 0x80,
+	PEGODA_CMD_I1_INIT_STD_MODE		= 0x81,
+	PEGODA_CMD_I1_CALC_TSE_HASH		= 0x82,
+	PEGODA_CMD_I1_INIT_FAST_MODE		= 0x83,
+	PEGODA_CMD_I1_OUTPUT_READ		= 0x85,
+	PEGODA_CMD_I1_OUTPUT_ANTICOL_SELECT	= 0x86,
+	PEGODA_CMD_I1_OUTPUT_WRITE		= 0x87,
+	PEGODA_CMD_I1_OUTPUT_HALT		= 0x88,
+	PEGODA_CMD_I1_OUTPUT_EAS		= 0x89,
+	PEGODA_CMD_I1_RESET_QUIET		= 0x8a,
+	PEGODA_CMD_I1_PCD_RF_RESET		= 0x8b,
+	PEGODA_CMD_I1_SET_BIT_PHASE		= 0x8c,
+
+	PEGODA_CMD_I2_INIT_STD_MODE		= 0x90,
+	PEGODA_CMD_I2_INIT_FAST_MODE		= 0x91,
+	PEGODA_CMD_15693_READ_SM		= 0x92,
+	PEGODA_CMD_15693_INVENTORY		= 0x93,
+	PEGODA_CMD_15693_WRITE_SM		= 0x94,
+	PEGODA_CMD_15693_STAY_QUIET		= 0x95,
+	PEGODA_CMD_15693_LOCK_BLOCK		= 0x96,
+	PEGODA_CMD_15693_SELECT			= 0x97,
+	PEGODA_CMD_15693_RESET_TO_READY		= 0x98,
+	PEGODA_CMD_15693_WRITE_AFI		= 0x99,
+	PEGODA_CMD_15693_LOCK_AFI		= 0x9a,
+	PEGODA_CMD_15693_WRITE_DSFID		= 0x9b,
+	PEGODA_CMD_15693_LOCK_DSFID		= 0x9c,
+	PEGODA_CMD_15693_GET_SYSTEM_INFO	= 0x9d,
+	PEGODA_CMD_15693_GET_MULTI_BLOCK_SEC	= 0x9e,
+	PEGODA_CMD_15693_INVENTORY_READ		= 0x9f,
+	PEGODA_CMD_15693_FAST_INVENTORY_READ	= 0xa0,
+	PEGODA_CMD_15693_SET_EAS		= 0xa1,
+	PEGODA_CMD_15693_RESET_EAS		= 0xa2,
+	PEGODA_CMD_15693_LOCK_EAS		= 0xa3,
+	PEGODA_CMD_15693_EAS_ALARM		= 0xa4,
+
+	PEGODA_CMD_PC_PCD_CONFIG		= 0xb0,
+	PEGODA_CMD_PC_BEGIN_ROUND		= 0xb1,
+	PEGODA_CMD_PC_WRITE			= 0xb3,
+
+	PEGODA_CMD_UID_PCD_CONFIG		= 0xb8,
+	PEGODA_CMD_UID_BEGIN_ROUND		= 0xb9,
+	PEGODA_CMD_UID_WRITE			= 0xba,
+	PEGODA_CMD_UID_DESTROY			= 0xbb,
+};
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..dbc608f
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,13 @@
+LIBVERSION= 0:0:0
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -D__LIBRFID__
+
+lib_LTLIBRARIES = librfid.la
+
+CORE=rfid.c rfid_layer2.c rfid_protocol.c rfid_reader.c
+L2=rfid_layer2_iso14443a.c rfid_layer2_iso14443b.c rfid_layer2_iso15693.c rfid_iso14443_common.c
+PROTO=rfid_proto_tcl.c rfid_proto_mifare_ul.c rfid_proto_mifare_classic.c
+READER=rfid_reader_cm5121.c rfid_reader_cm5121_openct.c rfid_asic_rc632.c 
+
+librfid_la_LDFLAGS = -Wc,-nostartfiles -version-info $(LIBVERSION) -lopenct
+librfid_la_SOURCES = $(CORE) $(L2) $(PROTO) $(READER)
+
diff --git a/src/rc632.h b/src/rc632.h
new file mode 100644
index 0000000..977b0ee
--- /dev/null
+++ b/src/rc632.h
@@ -0,0 +1,211 @@
+/* Register definitions for Philips CL RC632 RFID Reader IC
+ *
+ * (C) 2005 Harald Welte <laforge@gnumonks.org>
+ *
+ * Licensed under GNU General Public License, Version 2
+ */
+
+enum rc632_registers {
+	RC632_REG_PAGE0			= 0x00,
+	RC632_REG_COMMAND		= 0x01,
+	RC632_REG_FIFO_DATA		= 0x02,
+	RC632_REG_PRIMARY_STATUS	= 0x03,
+	RC632_REG_FIFO_LENGTH		= 0x04,
+	RC632_REG_SECONDARY_STATUS	= 0x05,
+	RC632_REG_INTERRUPT_EN		= 0x06,
+	RC632_REG_INTERRUPT_RQ		= 0x07,
+
+	RC632_REG_PAGE1			= 0x08,
+	RC632_REG_CONTROL		= 0x09,
+	RC632_REG_ERROR_FLAG		= 0x0a,
+	RC632_REG_COLL_POS		= 0x0b,
+	RC632_REG_TIMER_VALUE		= 0x0c,
+	RC632_REG_CRC_RESULT_LSB	= 0x0d,
+	RC632_REG_CRC_RESULT_MSB	= 0x0e,
+	RC632_REG_BIT_FRAMING		= 0x0f,
+
+	RC632_REG_PAGE2			= 0x10,
+	RC632_REG_TX_CONTROL		= 0x11,
+	RC632_REG_CW_CONDUCTANCE	= 0x12,
+	RC632_REG_MOD_CONDUCTANCE	= 0x13,
+	RC632_REG_CODER_CONTROL		= 0x14,
+	RC632_REG_MOD_WIDTH		= 0x15,
+	RC632_REG_MOD_WIDTH_SOF		= 0x16,
+	RC632_REG_TYPE_B_FRAMING	= 0x17,
+
+	RC632_REG_PAGE3			= 0x18,
+	RC632_REG_RX_CONTROL1		= 0x19,
+	RC632_REG_DECODER_CONTROL	= 0x1a,
+	RC632_REG_BIT_PHASE		= 0x1b,
+	RC632_REG_RX_THRESHOLD		= 0x1c,
+	RC632_REG_BPSK_DEM_CONTROL	= 0x1d,
+	RC632_REG_RX_CONTROL2		= 0x1e,
+	RC632_REG_CLOCK_Q_CONTROL	= 0x1f,
+
+	RC632_REG_PAGE4			= 0x20,
+	RC632_REG_RX_WAIT		= 0x21,
+	RC632_REG_CHANNEL_REDUNDANCY	= 0x22,
+	RC632_REG_CRC_PRESET_LSB	= 0x23,
+	RC632_REG_CRC_PRESET_MSB	= 0x24,
+	RC632_REG_TIME_SLOT_PERIOD	= 0x25,
+	RC632_REG_MFOUT_SELECT		= 0x26,
+	RC632_REG_PRESET_27		= 0x27,
+
+	RC632_REG_PAGE5			= 0x28,
+	RC632_REG_FIFO_LEVEL		= 0x29,
+	RC632_REG_TIMER_CLOCK		= 0x2a,
+	RC632_REG_TIMER_CONTROL		= 0x2b,
+	RC632_REG_TIMER_RELOAD		= 0x2c,
+	RC632_REG_IRQ_PIN_CONFIG	= 0x2d,
+	RC632_REG_PRESET_2E		= 0x2e,
+	RC632_REG_PRESET_2F		= 0x2f,
+
+	RC632_REG_PAGE6			= 0x30,
+
+	RC632_REG_PAGE7			= 0x38,
+	RC632_REG_TEST_ANA_SELECT	= 0x3a,
+	RC632_REG_TEST_DIGI_SELECT	= 0x3d,
+};
+
+enum rc632_reg_command {
+	RC632_CMD_IDLE			= 0x00,
+	RC632_CMD_WRITE_E2		= 0x01,
+	RC632_CMD_READ_E2		= 0x03,
+	RC632_CMD_LOAD_CONFIG		= 0x07,
+	RC632_CMD_LOAD_KEY_E2		= 0x0b,
+	RC632_CMD_AUTHENT1		= 0x0c,
+	RC632_CMD_CALC_CRC		= 0x12,
+	RC632_CMD_AUTHENT2		= 0x14,
+	RC632_CMD_RECEIVE		= 0x16,
+	RC632_CMD_LOAD_KEY		= 0x19,
+	RC632_CMD_TRANSMIT		= 0x1a,
+	RC632_CMD_TRANSCIEVE		= 0x1e,
+	RC632_CMD_STARTUP		= 0x3f,
+};
+
+enum rc632_reg_control {
+	RC632_CONTROL_CRYPTO1_ON	= 0x08,
+	RC632_CONTROL_POWERDOWN		= 0x10,
+};
+
+enum rc632_reg_error_flag {
+	RC632_ERR_FLAG_COL_ERR		= 0x01,
+	RC632_ERR_FLAG_PARITY_ERR	= 0x02,
+	RC632_ERR_FLAG_FRAMING_ERR	= 0x04,
+	RC632_ERR_FLAG_CRC_ERR		= 0x08,
+	RC632_ERR_FLAG_FIFO_OVERFLOW	= 0x10,
+	RC632_ERR_FLAG_ACCESS_ERR	= 0x20,
+	RC632_ERR_FLAG_KEY_ERR		= 0x40,
+};
+
+enum rc632_reg_tx_control {
+	RC632_TXCTRL_TX1_RF_EN		= 0x01,
+	RC632_TXCTRL_TX2_RF_EN		= 0x02,
+	RC632_TXCTRL_TX2_CW		= 0x04,
+	RC632_TXCTRL_TX2_INV		= 0x08,
+	RC632_TXCTRL_FORCE_100_ASK	= 0x10,
+
+	RC632_TXCTRL_MOD_SRC_LOW	= 0x00,
+	RC632_TXCTRL_MOD_SRC_HIGH	= 0x20,
+	RC632_TXCTRL_MOD_SRC_INT	= 0x40,
+	RC632_TXCTRL_MOD_SRC_MFIN	= 0x60,
+};
+
+enum rc632_reg_coder_control {
+	RC632_CDRCTRL_TXCD_NRZ		= 0x00,
+	RC632_CDRCTRL_TXCD_14443A	= 0x01,
+	RC632_CDRCTRL_TXCD_ICODE_STD	= 0x04,
+
+#define RC632_CDRCTRL_RATE_MASK		0x38
+	RC632_CDRCTRL_RATE_848K		= 0x00,
+	RC632_CDRCTRL_RATE_424K		= 0x08,
+	RC632_CDRCTRL_RATE_212K		= 0x10,
+	RC632_CDRCTRL_RATE_106K		= 0x18,
+	RC632_CDRCTRL_RATE_14443B	= 0x20,
+	RC632_CDRCTRL_RATE_15693	= 0x28,
+	RC632_CDRCTRL_RATE_ICODE_FAST	= 0x30,
+};
+
+enum rc632_erg_type_b_framing {
+	RC632_TBFRAMING_SOF_10L_2H	= 0x00,
+	RC632_TBFRAMING_SOF_10L_3H	= 0x01,
+	RC632_TBFRAMING_SOF_11L_2H	= 0x02,
+	RC632_TBFRAMING_SOF_11L_3H	= 0x03,
+
+	RC632_TBFRAMING_EOF_10		= 0x00,
+	RC632_TBFRAMING_EOF_11		= 0x20,
+
+	RC632_TBFRAMING_NO_TX_SOF	= 0x80,
+	RC632_TBFRAMING_NO_TX_EOF	= 0x40,
+};
+#define	RC632_TBFRAMING_SPACE_SHIFT	2
+#define RC632_TBFRAMING_SPACE_MASK	7
+
+enum rc632_reg_rx_control1 {
+	RC632_RXCTRL1_GAIN_20DB		= 0x00,
+	RC632_RXCTRL1_GAIN_24DB		= 0x01,
+	RC632_RXCTRL1_GAIN_31DB		= 0x02,
+	RC632_RXCTRL1_GAIN_35DB		= 0x03,
+
+	RC632_RXCTRL1_LP_OFF		= 0x04,
+	RC632_RXCTRL1_ISO15693		= 0x08,
+	RC632_RXCTRL1_ISO14443		= 0x10,
+
+#define RC632_RXCTRL1_SUBCP_MASK	0xe0
+	RC632_RXCTRL1_SUBCP_1		= 0x00,
+	RC632_RXCTRL1_SUBCP_2		= 0x20,
+	RC632_RXCTRL1_SUBCP_4		= 0x40,
+	RC632_RXCTRL1_SUBCP_8		= 0x60,
+	RC632_RXCTRL1_SUBCP_16		= 0x80,
+};
+
+enum rc632_reg_decoder_control {
+	RC632_DECCTRL_MANCHESTER	= 0x00,
+	RC632_DECCTRL_BPSK		= 0x01,
+
+	RC632_DECCTRL_RX_INVERT		= 0x04,
+
+	RC632_DECCTRL_RXFR_ICODE	= 0x00,
+	RC632_DECCTRL_RXFR_14443A	= 0x08,
+	RC632_DECCTRL_RXFR_15693	= 0x10,
+	RC632_DECCTRL_RXFR_14443B	= 0x18,
+
+	RC632_DECCTRL_ZEROAFTERCOL	= 0x20,
+
+	RC632_DECCTRL_RX_MULTIPLE	= 0x40,
+};
+
+enum rc632_reg_bpsk_dem_control {
+	RC632_BPSKD_TAUB_SHIFT		= 0x00,
+	RC632_BPSKD_TAUB_MASK		= 0x03,
+	
+	RC632_BPSKD_TAUD_SHIFT		= 0x02,
+	RC632_BPSKD_TAUD_MASK		= 0x03,
+
+	RC632_BPSKD_FILTER_AMP_DETECT	= 0x10,
+	RC632_BPSKD_NO_RX_EOF		= 0x20,
+	RC632_BPSKD_NO_RX_EGT		= 0x40,
+	RC632_BPSKD_NO_RX_SOF		= 0x80,
+};
+
+enum rc632_reg_rx_control2 {
+	RC632_RXCTRL2_DECSRC_LOW	= 0x00,
+	RC632_RXCTRL2_DECSRC_INT	= 0x01,
+	RC632_RXCTRL2_DECSRC_SUBC_MFIN	= 0x10,
+	RC632_RXCTRL2_DECSRC_BASE_MFIN	= 0x11,
+
+	RC632_RXCTRL2_AUTO_PD		= 0x40,
+	RC632_RXCTRL2_CLK_I		= 0x80,
+	RC632_RXCTRL2_CLK_Q		= 0x00,
+};
+
+enum rc632_reg_channel_redundancy {
+	RC632_CR_PARITY_ENABLE		= 0x01,
+	RC632_CR_PARITY_ODD		= 0x02,
+	RC632_CR_TX_CRC_ENABLE		= 0x04,
+	RC632_CR_RX_CRC_ENABLE		= 0x08,
+	RC632_CR_CRC8			= 0x10,
+	RC632_CR_CRC3309		= 0x20,
+};
+
+
diff --git a/src/rfid.c b/src/rfid.c
new file mode 100644
index 0000000..6fba46a
--- /dev/null
+++ b/src/rfid.c
@@ -0,0 +1,56 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <librfid/rfid_reader_cm5121.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_protocol_tcl.h>
+#include <librfid/rfid_protocol_mifare_ul.h>
+#include <librfid/rfid_protocol_mifare_classic.h>
+
+const char *
+rfid_hexdump(const void *data, unsigned int len)
+{
+	static char string[1024];
+	unsigned char *d = (unsigned char *) data;
+	unsigned int i, left;
+
+	string[0] = '\0';
+	left = sizeof(string);
+	for (i = 0; len--; i += 3) {
+		if (i >= sizeof(string) -4)
+			break;
+		snprintf(string+i, 4, " %02x", *d++);
+	}
+	return string;
+}
+
+int rfid_init()
+{
+	rfid_reader_register(&rfid_reader_cm5121);
+	rfid_layer2_register(&rfid_layer2_iso14443a);
+	rfid_layer2_register(&rfid_layer2_iso14443b);
+	rfid_protocol_register(&rfid_protocol_tcl);
+	rfid_protocol_register(&rfid_protocol_mful);
+	rfid_protocol_register(&rfid_protocol_mfcl);
+
+	return 0;
+}
+
+void rfid_fini()
+{
+	/* FIXME: implementation */
+}
diff --git a/src/rfid_asic_rc632.c b/src/rfid_asic_rc632.c
new file mode 100644
index 0000000..0c38052
--- /dev/null
+++ b/src/rfid_asic_rc632.c
@@ -0,0 +1,1435 @@
+/* Generic Philips CL RC632 Routines
+ *
+ * (C) Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_asic.h>
+#include <librfid/rfid_asic_rc632.h>
+#include <librfid/rfid_reader_cm5121.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+#include <librfid/rfid_protocol_mifare_classic.h>
+
+#include "rfid_iso14443_common.h"
+#include "rc632.h"
+//#include "rc632_14443a.h"
+
+
+#define RC632_TMO_AUTH1	14000
+
+#define ENTER()		DEBUGP("entering\n")
+struct rfid_asic rc632;
+
+/* Register and FIFO Access functions */
+static int 
+rc632_reg_write(struct rfid_asic_handle *handle,
+		u_int8_t reg,
+		u_int8_t val)
+{
+	return handle->rath->rat->priv.rc632.fn.reg_write(handle->rath, reg, val);
+}
+
+static int 
+rc632_reg_read(struct rfid_asic_handle *handle,
+	       u_int8_t reg,
+	       u_int8_t *val)
+{
+	return handle->rath->rat->priv.rc632.fn.reg_read(handle->rath, reg, val);
+}
+
+static int 
+rc632_fifo_write(struct rfid_asic_handle *handle,
+		 u_int8_t len,
+		 const u_int8_t *buf,
+		 u_int8_t flags)
+{
+	return handle->rath->rat->priv.rc632.fn.fifo_write(handle->rath, 
+							   len, buf, flags);
+}
+
+static int 
+rc632_fifo_read(struct rfid_asic_handle *handle,
+		u_int8_t len,
+		u_int8_t *buf)
+{
+	return handle->rath->rat->priv.rc632.fn.fifo_read(handle->rath, len, buf);
+}
+
+
+static int
+rc632_set_bits(struct rfid_asic_handle *handle, 
+		u_int8_t reg,
+		u_int8_t val)
+{
+	int ret;
+	u_int8_t tmp;
+
+	ret = rc632_reg_read(handle, reg, &tmp);
+	if (ret < 0)
+		return -1;
+
+	/* if bits are already set, no need to set them again */
+	if ((tmp & val) == val)
+		return 0;
+
+	return rc632_reg_write(handle, reg, (tmp|val)&0xff);
+}
+static int 
+rc632_set_bit_mask(struct rfid_asic_handle *handle, 
+		   u_int8_t reg, u_int8_t mask, u_int8_t val)
+{
+	int ret;
+	u_int8_t tmp;
+
+	ret = rc632_reg_read(handle, reg, &tmp);
+	if (ret < 0)
+		return ret;
+
+	/* if bits are already like we want them, abort */
+	if ((tmp & mask) == val)
+		return 0;
+
+	return rc632_reg_write(handle, reg, (tmp & ~mask)|(val & mask));
+}
+
+static int 
+rc632_clear_bits(struct rfid_asic_handle *handle, 
+		 u_int8_t reg,
+		 u_int8_t val)
+{
+	int ret;
+	u_int8_t tmp;
+
+	ret = rc632_reg_read(handle, reg, &tmp);
+	if (ret < 0) {
+		DEBUGP("error during reg_read(%p, %d):%d\n",
+			handle, reg, ret);
+		return -1;
+	}
+	/* if bits are already cleared, no need to clear them again */
+	if ((tmp & val) == 0)
+		return 0;
+
+	return rc632_reg_write(handle, reg, (tmp & ~val)&0xff);
+}
+
+static int 
+rc632_turn_on_rf(struct rfid_asic_handle *handle)
+{
+	ENTER();
+	return rc632_set_bits(handle, RC632_REG_TX_CONTROL, 0x03);
+}
+
+static int 
+rc632_turn_off_rf(struct rfid_asic_handle *handle)
+{
+	ENTER();
+	return rc632_clear_bits(handle, RC632_REG_TX_CONTROL, 0x03);
+}
+
+static int
+rc632_power_up(struct rfid_asic_handle *handle)
+{
+	ENTER();
+	return rc632_clear_bits(handle, RC632_REG_CONTROL, 
+				RC632_CONTROL_POWERDOWN);
+}
+
+static int
+rc632_power_down(struct rfid_asic_handle *handle)
+{
+	return rc632_set_bits(handle, RC632_REG_CONTROL,
+			      RC632_CONTROL_POWERDOWN);
+}
+
+/* Stupid RC623 implementations don't evaluate interrupts but poll the
+ * command register for "status idle" */
+static int
+rc632_wait_idle(struct rfid_asic_handle *handle, u_int64_t timeout)
+{
+	u_int8_t cmd = 0xff;
+	int ret;
+
+	while (cmd != 0) {
+		ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd);
+		if (ret < 0)
+			return ret;
+
+		if (cmd == 0) {
+			/* FIXME: read second time ?? */
+			return 0;
+		}
+
+		{
+			u_int8_t foo;
+			rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo);
+			if (foo & 0x04)
+				rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo);
+		}
+
+		usleep(100);
+
+		/* Fixme: Abort after some timeout */
+	}
+
+	return 0;
+}
+
+static int
+rc632_transmit(struct rfid_asic_handle *handle,
+		const u_int8_t *buf,
+		u_int8_t len,
+		u_int64_t timeout)
+{
+	int ret;
+
+	ret = rc632_fifo_write(handle, len, buf, 0x03);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_TRANSMIT);
+	if (ret < 0)
+		return ret;
+
+	return rc632_wait_idle(handle, timeout);
+}
+
+static int
+tcl_toggle_pcb(struct rfid_asic_handle *handle)
+{
+	// FIXME: toggle something between 0x0a and 0x0b
+	return 0;
+}
+
+static int
+rc632_transcieve(struct rfid_asic_handle *handle,
+		 const u_int8_t *tx_buf,
+		 u_int8_t tx_len,
+		 u_int8_t *rx_buf,
+		 u_int8_t *rx_len,
+		 unsigned int timer,
+		 unsigned int toggle)
+{
+	int ret;
+
+	ret = rc632_fifo_write(handle, tx_len, tx_buf, 0x03);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_TRANSCIEVE);
+	if (ret < 0)
+		return ret;
+
+	if (toggle == 1)
+		tcl_toggle_pcb(handle);
+
+	ret = rc632_wait_idle(handle, timer);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, rx_len);
+	if (ret < 0)
+		return ret;
+
+	if (*rx_len == 0) {
+		u_int8_t tmp;
+
+		DEBUGP("rx_len == 0\n");
+
+		rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &tmp);
+		rc632_reg_read(handle, RC632_REG_CHANNEL_REDUNDANCY, &tmp);
+
+		return -1; 
+	}
+
+	return rc632_fifo_read(handle, *rx_len, rx_buf);
+}
+
+static int
+rc632_read_eeprom(struct rfid_asic_handle *handle)
+{
+	u_int8_t recvbuf[60];
+	u_int8_t sndbuf[3];
+	int ret;
+
+	sndbuf[0] = 0x00;
+	sndbuf[1] = 0x00;
+	sndbuf[2] = 0x3c;
+
+	ret = rc632_fifo_write(handle, 3, sndbuf, 0x03);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_READ_E2);
+	if (ret < 0)
+		return ret;
+
+	usleep(20000);
+
+	ret = rc632_fifo_read(handle, sizeof(recvbuf), recvbuf);
+	if (ret < 0)
+		return ret;
+
+	// FIXME: do something with eeprom contents
+	return ret;
+}
+
+static int
+rc632_calc_crc16_from(struct rfid_asic_handle *handle)
+{
+	u_int8_t sndbuf[2] = { 0x01, 0x02 };
+	u_int8_t crc_lsb = 0x00 , crc_msb = 0x00;
+	int ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x12);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xe0);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_fifo_write(handle, sizeof(sndbuf), sndbuf, 3);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_CALC_CRC);
+	if (ret < 0)
+		return ret;
+	
+	usleep(10000);	// FIXME: no checking for cmd completion?
+
+	ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_LSB, &crc_lsb);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_MSB, &crc_msb);
+	if (ret < 0)
+		return ret;
+
+	// FIXME: what to do with crc result?
+	return ret;
+}
+
+
+int
+rc632_register_dump(struct rfid_asic_handle *handle, u_int8_t *buf)
+{
+	int ret;
+	u_int8_t i;
+
+	for (i = 0; i <= 0x3f; i++) {
+		ret = rc632_reg_read(handle, i, &buf[i]);
+		// do we want error checks?
+	}
+	return 0;
+}
+
+
+
+/* generic FIFO access functions (if no more efficient ones provided by
+ * transport driver) */
+
+static int 
+generic_fifo_write()
+{
+	// FIXME: implementation (not needed for CM 5121)
+	return -1;
+}
+
+static int
+generic_fifo_read()
+{
+	// FIXME: implementation (not neded for CM 5121)
+	return -1;
+}
+
+static int
+rc632_init(struct rfid_asic_handle *ah)
+{
+	int ret;
+
+	/* switch off rf (make sure PICCs are reset at init time) */
+	ret = rc632_power_down(ah);
+	if (ret < 0)
+		return ret;
+
+	usleep(10000);
+
+	/* switch on rf */
+	ret = rc632_power_up(ah);
+	if (ret < 0)
+		return ret;
+
+	/* disable register paging */
+	ret = rc632_reg_write(ah, 0x00, 0x00);
+	if (ret < 0)
+		return ret;
+
+	/* set some sane default values */
+	ret = rc632_reg_write(ah, 0x11, 0x5b);
+	if (ret < 0)
+		return ret;
+
+	/* switch on rf */
+	ret = rc632_turn_on_rf(ah);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int
+rc632_fini(struct rfid_asic_handle *ah)
+{
+	int ret;
+
+	/* switch off rf */
+	ret = rc632_turn_off_rf(ah);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_power_down(ah);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+struct rfid_asic_handle *
+rc632_open(struct rfid_asic_transport_handle *th)
+{
+	struct rfid_asic_handle *h;
+
+	h = malloc(sizeof(*h));
+	if (!h)
+		return NULL;
+	memset(h, 0, sizeof(*h));
+
+	h->asic = &rc632;
+	h->rath = th;
+	h->fc = h->asic->fc;
+	h->mtu = h->mru = 40; /* FIXME */
+
+	if (rc632_init(h) < 0) {
+		free(h);
+		return NULL;
+	}
+
+	return h;
+}
+
+void
+rc632_close(struct rfid_asic_handle *h)
+{
+	rc632_fini(h);
+	free(h);
+}
+
+
+/* 
+ * Philips CL RC632 primitives for ISO 14443-A compliant PICC's
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+static int
+rc632_iso14443a_init(struct rfid_asic_handle *handle)
+{
+	int ret;
+
+	// FIXME: some fifo work (drain fifo?)
+	
+	/* flush fifo (our way) */
+	ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01);
+
+	ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL,
+			(RC632_TXCTRL_TX1_RF_EN |
+			 RC632_TXCTRL_TX2_RF_EN |
+			 RC632_TXCTRL_TX2_INV |
+			 RC632_TXCTRL_FORCE_100_ASK |
+			 RC632_TXCTRL_MOD_SRC_INT));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE,
+				CM5121_CW_CONDUCTANCE);
+	if (ret < 0)
+		return ret;
+
+	/* Since FORCE_100_ASK is set (cf mc073930.pdf), this line may be left out? */
+	ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE,
+				CM5121_MOD_CONDUCTANCE);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL,
+				(RC632_CDRCTRL_TXCD_14443A |
+				 RC632_CDRCTRL_RATE_106K));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, 0x00);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1,
+			      (RC632_RXCTRL1_GAIN_35DB |
+			       RC632_RXCTRL1_ISO14443 |
+			       RC632_RXCTRL1_SUBCP_8));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL,
+			      (RC632_DECCTRL_MANCHESTER |
+			       RC632_DECCTRL_RXFR_14443A));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE,
+				CM5121_14443A_BITPHASE);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD,
+				CM5121_14443A_THRESHOLD);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+	if (ret < 0)
+		return ret;
+			      
+	ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2,
+			      (RC632_RXCTRL2_DECSRC_INT |
+			       RC632_RXCTRL2_CLK_Q));
+	if (ret < 0)
+		return ret;
+
+	/* Omnikey proprietary driver has 0x03, but 0x06 is the default reset value ?!? */
+	ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x06);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+			      (RC632_CR_PARITY_ENABLE |
+			       RC632_CR_PARITY_ODD));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x63);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0x63);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int
+rc632_iso14443a_fini(struct iso14443a_handle *handle_14443)
+{
+
+#if 0
+	ret = rc632_turn_off_rf(handle);
+	if (ret < 0)
+		return ret;
+#endif
+
+
+	return 0;
+}
+
+
+/* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */
+static int
+rc632_iso14443a_transcieve_sf(struct rfid_asic_handle *handle,
+				u_int8_t cmd,
+		    		struct iso14443a_atqa *atqa)
+{
+	int ret;
+	u_int8_t tx_buf[1];
+	u_int8_t rx_len = 2;
+
+	memset(atqa, 0, sizeof(atqa));
+
+	tx_buf[0] = cmd;
+
+	/* transfer only 7 bits of last byte in frame */
+	ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x07);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_clear_bits(handle, RC632_REG_CONTROL,
+				RC632_CONTROL_CRYPTO1_ON);
+	if (ret < 0)
+		return ret;
+
+#if 0
+	ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+				(RC632_CR_PARITY_ENABLE |
+				 RC632_CR_PARITY_ODD));
+#else
+	ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY,
+				RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE);
+				
+#endif
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_transcieve(handle, tx_buf, sizeof(tx_buf),
+				(u_int8_t *)atqa, &rx_len, 0x32, 0);
+	if (ret < 0) {
+		DEBUGP("error during rc632_transcieve()\n");
+		return ret;
+	}
+
+	/* switch back to normal 8bit last byte */
+	ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x00);
+	if (ret < 0)
+		return ret;
+
+	if (rx_len != 2) {
+		DEBUGP("rx_len(%d) != 2\n", rx_len);
+		return -1;
+	}
+
+	return 0;
+}
+
+/* transcieve regular frame */
+static int
+rc632_iso14443ab_transcieve(struct rfid_asic_handle *handle,
+			   unsigned int frametype,
+			   const u_int8_t *tx_buf, unsigned int tx_len,
+			   u_int8_t *rx_buf, unsigned int *rx_len,
+			   u_int64_t timeout, unsigned int flags)
+{
+	int ret;
+	u_int8_t rxl = *rx_len & 0xff;
+	u_int8_t channel_red;
+
+	memset(rx_buf, 0, *rx_len);
+
+	switch (frametype) {
+	case RFID_14443A_FRAME_REGULAR:
+	case RFID_MIFARE_FRAME:
+		channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE
+				|RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD;
+		break;
+	case RFID_14443B_FRAME_REGULAR:
+		channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE
+				|RC632_CR_CRC3309;
+		break;
+#if 0
+	case RFID_MIFARE_FRAME:
+		channel_red = RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD;
+		break;
+#endif
+	default:
+		return -EINVAL;
+		break;
+	}
+	ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+			      channel_red);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0);
+	*rx_len = rxl;
+	if (ret < 0)
+		return ret;
+
+
+	return 0; 
+}
+
+/* transcieve anti collission bitframe */
+static int
+rc632_iso14443a_transcieve_acf(struct rfid_asic_handle *handle,
+				struct iso14443a_anticol_cmd *acf,
+				unsigned int *bit_of_col)
+{
+	int ret;
+	u_int8_t rx_buf[64];
+	u_int8_t rx_len = sizeof(rx_buf);
+	u_int8_t rx_align = 0, tx_last_bits, tx_bytes;
+	u_int8_t boc;
+	u_int8_t error_flag;
+	*bit_of_col = ISO14443A_BITOFCOL_NONE;
+	memset(rx_buf, 0, sizeof(rx_buf));
+
+	/* disable mifare cryto */
+	ret = rc632_clear_bits(handle, RC632_REG_CONTROL,
+				RC632_CONTROL_CRYPTO1_ON);
+	if (ret < 0)
+		return ret;
+
+	/* disable CRC summing */
+#if 0
+	ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+				(RC632_CR_PARITY_ENABLE |
+				 RC632_CR_PARITY_ODD));
+#else
+	ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY,
+				RC632_CR_TX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE);
+#endif
+	if (ret < 0)
+		return ret;
+
+	tx_last_bits = acf->nvb & 0x0f;	/* lower nibble indicates bits */
+	tx_bytes = acf->nvb >> 4;
+	if (tx_last_bits) {
+		tx_bytes++;
+		rx_align = (tx_last_bits+1) % 8;/* rx frame complements tx */
+	}
+
+	//rx_align = 8 - tx_last_bits;/* rx frame complements tx */
+
+	/* set RxAlign and TxLastBits*/
+	ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING,
+				(rx_align << 4) | (tx_last_bits));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_transcieve(handle, (u_int8_t *)acf, tx_bytes,
+				rx_buf, &rx_len, 0x32, 0);
+	if (ret < 0)
+		return ret;
+
+	/* bitwise-OR the two halves of the split byte */
+	acf->uid_bits[tx_bytes-2] = (
+		  (acf->uid_bits[tx_bytes-2] & (0xff >> (8-tx_last_bits)))
+		| rx_buf[0]);
+	/* copy the rest */
+	memcpy(&acf->uid_bits[tx_bytes+1-2], &rx_buf[1], rx_len-1);
+
+	/* determine whether there was a collission */
+	ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &error_flag);
+	if (ret < 0)
+		return ret;
+
+	if (error_flag & RC632_ERR_FLAG_COL_ERR) {
+		/* retrieve bit of collission */
+		ret = rc632_reg_read(handle, RC632_REG_COLL_POS, &boc);
+		if (ret < 0)
+			return ret;
+
+		/* bit of collission relative to start of part 1 of 
+		 * anticollision frame (!) */
+		*bit_of_col = 2*8 + boc;
+	}
+
+	return 0;
+}
+
+enum rc632_rate {
+	RC632_RATE_106	= 0x00,
+	RC632_RATE_212	= 0x01,
+	RC632_RATE_424	= 0x02,
+	RC632_RATE_848	= 0x03,
+};
+
+struct rx_config {
+	u_int8_t	subc_pulses;
+	u_int8_t	rx_coding;
+	u_int8_t	rx_threshold;
+	u_int8_t	bpsk_dem_ctrl;
+};
+
+struct tx_config {
+	u_int8_t	rate;
+	u_int8_t	mod_width;
+};
+
+static struct rx_config rx_configs[] = {
+	{
+		.subc_pulses 	= RC632_RXCTRL1_SUBCP_8,
+		.rx_coding	= RC632_DECCTRL_MANCHESTER,
+		.rx_threshold	= 0x88,
+		.bpsk_dem_ctrl	= 0x00,
+	},
+	{
+		.subc_pulses	= RC632_RXCTRL1_SUBCP_4,
+		.rx_coding	= RC632_DECCTRL_BPSK,
+		.rx_threshold	= 0x50,
+		.bpsk_dem_ctrl	= 0x0c,
+	},
+	{
+		.subc_pulses	= RC632_RXCTRL1_SUBCP_2,
+		.rx_coding	= RC632_DECCTRL_BPSK,
+		.rx_threshold	= 0x50,
+		.bpsk_dem_ctrl	= 0x0c,
+	},
+	{
+		.subc_pulses	= RC632_RXCTRL1_SUBCP_1,
+		.rx_coding	= RC632_DECCTRL_BPSK,
+		.rx_threshold	= 0x50,
+		.bpsk_dem_ctrl	= 0x0c,
+	},
+};
+
+static struct tx_config tx_configs[] = {
+	{
+		.rate 		= RC632_CDRCTRL_RATE_106K,
+		.mod_width	= 0x13,
+	},
+	{
+		.rate		= RC632_CDRCTRL_RATE_212K,
+		.mod_width	= 0x07,
+	},
+	{
+		.rate		= RC632_CDRCTRL_RATE_424K,
+		.mod_width	= 0x03,
+	},
+	{
+		.rate		= RC632_CDRCTRL_RATE_848K,
+		.mod_width	= 0x01,
+	},
+};
+
+static int rc632_iso14443a_set_speed(struct rfid_asic_handle *handle,
+				     unsigned int tx,
+				     u_int8_t rate)
+{
+	int rc;
+	u_int8_t reg;
+
+
+	if (!tx) {
+		/* Rx */
+		if (rate > ARRAY_SIZE(rx_configs))
+			return -EINVAL;
+
+		rc = rc632_set_bit_mask(handle, RC632_REG_RX_CONTROL1,
+					RC632_RXCTRL1_SUBCP_MASK,
+					rx_configs[rate].subc_pulses);
+		if (rc < 0)
+			return rc;
+
+		rc = rc632_set_bit_mask(handle, RC632_REG_DECODER_CONTROL,
+					RC632_DECCTRL_BPSK,
+					rx_configs[rate].rx_coding);
+		if (rc < 0)
+			return rc;
+
+		rc = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD,
+					rx_configs[rate].rx_threshold);
+		if (rc < 0)
+			return rc;
+
+		if (rx_configs[rate].rx_coding == RC632_DECCTRL_BPSK) {
+			rc = rc632_reg_write(handle, 
+					     RC632_REG_BPSK_DEM_CONTROL,
+					     rx_configs[rate].bpsk_dem_ctrl);
+			if (rc < 0)
+				return rc;
+		}
+	} else {
+		/* Tx */
+		if (rate > ARRAY_SIZE(tx_configs))
+			return -EINVAL;
+
+		rc = rc632_set_bit_mask(handle, RC632_REG_CODER_CONTROL,
+					RC632_CDRCTRL_RATE_MASK,
+					tx_configs[rate].rate);
+		if (rc < 0)
+			return rc;
+
+		rc = rc632_reg_write(handle, RC632_REG_MOD_WIDTH,
+				     tx_configs[rate].mod_width);
+		if (rc < 0)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int rc632_iso14443b_init(struct rfid_asic_handle *handle)
+{
+	int ret;
+
+	// FIXME: some FIFO work
+	
+	/* flush fifo (our way) */
+	ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL,
+			(RC632_TXCTRL_TX1_RF_EN |
+			 RC632_TXCTRL_TX2_RF_EN |
+			 RC632_TXCTRL_TX2_INV |
+			 RC632_TXCTRL_MOD_SRC_INT));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, 0x04);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL,
+			      (RC632_CDRCTRL_TXCD_NRZ |
+			       RC632_CDRCTRL_RATE_14443B));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING,
+			      (RC632_TBFRAMING_SOF_11L_3H |
+			       (6 << RC632_TBFRAMING_SPACE_SHIFT) |
+			       RC632_TBFRAMING_EOF_11));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1,
+			      (RC632_RXCTRL1_GAIN_35DB |
+			       RC632_RXCTRL1_ISO14443 |
+			       RC632_RXCTRL1_SUBCP_8));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL,
+			      (RC632_DECCTRL_BPSK |
+			       RC632_DECCTRL_RXFR_14443B));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE,
+				CM5121_14443B_BITPHASE);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD,
+				CM5121_14443B_THRESHOLD);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL,
+			      ((0x2 & RC632_BPSKD_TAUB_MASK)<<RC632_BPSKD_TAUB_SHIFT |
+			       (0x3 & RC632_BPSKD_TAUD_MASK)<<RC632_BPSKD_TAUD_SHIFT |
+			       RC632_BPSKD_FILTER_AMP_DETECT |
+			       RC632_BPSKD_NO_RX_EOF |
+			       RC632_BPSKD_NO_RX_EGT));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2,
+			      (RC632_RXCTRL2_AUTO_PD |
+			       RC632_RXCTRL2_DECSRC_INT));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x03);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+			      (RC632_CR_TX_CRC_ENABLE |
+			       RC632_CR_RX_CRC_ENABLE |
+			       RC632_CR_CRC3309));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0xff);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xff);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int
+rc632_iso15693_init(struct rfid_asic_handle *h)
+{
+	int ret;
+
+	ret = rc632_reg_write(h, RC632_REG_TX_CONTROL,
+						(RC632_TXCTRL_MOD_SRC_INT |
+						 RC632_TXCTRL_TX2_INV |
+						 RC632_TXCTRL_TX2_RF_EN |
+						 RC632_TXCTRL_TX1_RF_EN));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x03);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL,
+						(RC632_CDRCTRL_RATE_15693 |
+						 0x03)); /* FIXME */
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+	if (ret < 0)
+		return ret;
+	
+	ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_TYPE_B_FRAMING, 0x00);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1, 
+						(RC632_RXCTRL1_SUBCP_16 |
+						 RC632_RXCTRL1_ISO15693 |
+						 RC632_RXCTRL1_GAIN_35DB));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL,
+						(RC632_DECCTRL_RXFR_15693 |
+						 RC632_DECCTRL_RX_INVERT));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0xe0);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0xff);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2,
+						(RC632_RXCTRL2_AUTO_PD |
+						 RC632_RXCTRL2_DECSRC_INT));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY,
+						(RC632_CR_CRC3309 |
+						 RC632_CR_RX_CRC_ENABLE |
+						 RC632_CR_TX_CRC_ENABLE));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0xff);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xff);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int
+rc632_iso15693_icode_init(struct rfid_asic_handle *h)
+{
+	int ret;
+
+	ret = rc632_reg_write(h, RC632_REG_TX_CONTROL,
+						(RC632_TXCTRL_MOD_SRC_INT |
+						 RC632_TXCTRL_TX2_INV |
+						 RC632_TXCTRL_TX2_RF_EN |
+						 RC632_TXCTRL_TX1_RF_EN));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x02);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL, 0x2c);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_TYPE_B_FRAMING, 0x00);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1, 0x8b); /* FIXME */
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL, 0x00);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0x52);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0x66);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2, 
+						RC632_RXCTRL2_DECSRC_INT);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY,
+						(RC632_CR_RX_CRC_ENABLE |
+						 RC632_CR_TX_CRC_ENABLE));
+	ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0xfe);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xff);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int
+rc632_iso15693_icl_init(struct rfid_asic_handle *h)
+{
+	int ret;
+	
+	/* ICL */
+
+	ret = rc632_reg_write(h, RC632_REG_TX_CONTROL, 
+						(RC632_TXCTRL_MOD_SRC_INT |	
+						 RC632_TXCTRL_TX2_INV |
+						 RC632_TXCTRL_TX2_RF_EN |
+						 RC632_TXCTRL_TX1_RF_EN));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x11);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL, 
+						(RC632_CDRCTRL_RATE_15693 |
+						 RC632_CDRCTRL_TXCD_ICODE_STD |
+						 0x03)); /* FIXME */
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+	if (ret < 0)
+		return ret;
+	ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1, 
+						(RC632_RXCTRL1_SUBCP_16|
+						 RC632_RXCTRL1_ISO15693|
+						 RC632_RXCTRL1_GAIN_35DB));
+	if (ret < 0)
+		return ret;
+	ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL,
+						(RC632_DECCTRL_RX_INVERT|
+						 RC632_DECCTRL_RXFR_15693));
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0xbd);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0xff);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2, 
+						RC632_RXCTRL2_DECSRC_INT);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY, 0x00);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0x12);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xe0);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+struct mifare_authcmd {
+	u_int8_t auth_cmd;
+	u_int8_t block_address;
+	u_int32_t serno;	/* lsb 1 2 msb */
+} __attribute__ ((packed));
+
+
+#define RFID_MIFARE_KEY_LEN 6
+#define RFID_MIFARE_KEY_CODED_LEN 12
+
+/* Transform crypto1 key from generic 6byte into rc632 specific 12byte */
+static int
+rc632_mifare_transform_key(const u_int8_t *key6, u_int8_t *key12)
+{
+	int i;
+	u_int8_t ln;
+	u_int8_t hn;
+
+	for (i = 0; i < RFID_MIFARE_KEY_LEN; i++) {
+		ln = key6[i] & 0x0f;
+		hn = key6[i] >> 4;
+		key12[i * 2 + 1] = (~ln << 4) | ln;
+		key12[i * 2] = (~hn << 4) | hn;
+	}
+	return 0;
+}
+
+static int
+rc632_mifare_set_key(struct rfid_asic_handle *h, const u_int8_t *key)
+{
+	u_int8_t coded_key[RFID_MIFARE_KEY_CODED_LEN];
+	u_int8_t reg;
+	int ret;
+
+	ret = rc632_mifare_transform_key(key, coded_key);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_fifo_write(h, RFID_MIFARE_KEY_CODED_LEN, coded_key, 0x03);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_LOAD_KEY);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_wait_idle(h, RC632_TMO_AUTH1);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_read(h, RC632_REG_ERROR_FLAG, &reg);
+	if (ret < 0)
+		return ret;
+
+	if (reg & RC632_ERR_FLAG_KEY_ERR)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+rc632_mifare_auth(struct rfid_asic_handle *h, u_int8_t cmd, u_int32_t serno,
+		  u_int8_t block)
+{
+	int ret;
+	struct mifare_authcmd acmd;
+	u_int8_t reg;
+
+	if (cmd != RFID_CMD_MIFARE_AUTH1A && cmd != RFID_CMD_MIFARE_AUTH1B)
+		return -EINVAL;
+
+	/* Initialize acmd */
+	acmd.block_address = block & 0xff;
+	acmd.auth_cmd = cmd;
+	//acmd.serno = htonl(serno);
+	acmd.serno = serno;
+
+	ret = rc632_clear_bits(h, RC632_REG_CONTROL,
+				RC632_CONTROL_CRYPTO1_ON);
+
+	/* Clear Rx CRC */
+	ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY,
+				RC632_CR_RX_CRC_ENABLE);
+	if (ret < 0)
+		return ret;
+
+	/* Send Authent1 Command */
+	ret = rc632_fifo_write(h, sizeof(acmd), (unsigned char *)&acmd, 0x03);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT1);
+	if (ret < 0)
+		return ret;
+
+	/* Wait until transmitter is idle */
+	ret = rc632_wait_idle(h, RC632_TMO_AUTH1);
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_reg_read(h, RC632_REG_SECONDARY_STATUS, &reg);
+	if (ret < 0)
+		return ret;
+	if (reg & 0x07)
+		return -EIO;
+
+	/* Clear Tx CRC */
+	ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY,
+				RC632_CR_TX_CRC_ENABLE);
+	if (ret < 0)
+		return ret;
+
+	/* Send Authent2 Command */
+	ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT2);
+	if (ret < 0)
+		return ret;
+
+	/* Wait until transmitter is idle */
+	ret = rc632_wait_idle(h, RC632_TMO_AUTH1);
+	if (ret < 0)
+		return ret;
+
+	/* Check whether authentication was successful */
+	ret = rc632_reg_read(h, RC632_REG_CONTROL, &reg);
+	if (ret < 0)
+		return ret;
+
+	if (!(reg & RC632_CONTROL_CRYPTO1_ON))
+		return -EACCES;
+
+	return 0;
+
+}
+
+/* transcieve regular frame */
+static int
+rc632_mifare_transcieve(struct rfid_asic_handle *handle,
+			const u_int8_t *tx_buf, unsigned int tx_len,
+			u_int8_t *rx_buf, unsigned int *rx_len,
+			u_int64_t timeout, unsigned int flags)
+{
+	int ret;
+	u_int8_t rxl = *rx_len & 0xff;
+
+	DEBUGP("entered\n");
+	memset(rx_buf, 0, *rx_len);
+
+#if 1
+	ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+				(RC632_CR_PARITY_ENABLE |
+				 RC632_CR_PARITY_ODD |
+				 RC632_CR_TX_CRC_ENABLE |
+				 RC632_CR_RX_CRC_ENABLE));
+#else
+	ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY,
+				RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE);
+#endif
+	if (ret < 0)
+		return ret;
+
+	ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0);
+	*rx_len = rxl;
+	if (ret < 0)
+		return ret;
+
+
+	return 0; 
+}
+
+struct rfid_asic rc632 = {
+	.name 	= "Philips CL RC632",
+	.fc 	= ISO14443_FREQ_CARRIER,
+	.priv.rc632 = {
+		.fn = {
+			.power_up = &rc632_power_up,
+			.power_down = &rc632_power_down,
+			.turn_on_rf = &rc632_turn_on_rf,
+			.turn_off_rf = &rc632_turn_off_rf,
+			.transcieve = &rc632_iso14443ab_transcieve,
+			.iso14443a = {
+				.init = &rc632_iso14443a_init,
+				.transcieve_sf = &rc632_iso14443a_transcieve_sf,
+				.transcieve_acf = &rc632_iso14443a_transcieve_acf,
+				.set_speed = &rc632_iso14443a_set_speed,
+			},
+			.iso14443b = {
+				.init = &rc632_iso14443b_init,
+			},
+			.iso15693 = {
+				.init = &rc632_iso15693_init,
+			},
+			.mifare_classic = {
+				.setkey = &rc632_mifare_set_key,
+				.auth = &rc632_mifare_auth,
+			},
+		},
+	},
+};
diff --git a/src/rfid_iso14443_common.c b/src/rfid_iso14443_common.c
new file mode 100644
index 0000000..38fed6b
--- /dev/null
+++ b/src/rfid_iso14443_common.c
@@ -0,0 +1,58 @@
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+
+static unsigned int fsdi_table[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
+
+int iso14443_fsdi_to_fsd(unsigned int *fsd, unsigned char fsdi)
+{
+	/* ISO 14443-4:2000(E) Section 5.1. */
+	if (fsdi > sizeof(fsdi_table)/sizeof(unsigned int))
+		return -1;
+
+	*fsd = fsdi_table[fsdi];
+	return 0;
+}
+
+int iso14443_fsd_to_fsdi(unsigned char *fsdi, unsigned int fsd)
+{
+	int i;
+
+	for (i = 0; i < sizeof(fsdi_table)/sizeof(unsigned int); i++) {
+		if (fsdi_table[i] == fsd) {
+			*fsdi = i;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+/* calculate the fsd that is equal or the closest smaller value
+ * that can be coded as fsd */
+unsigned int iso14443_fsd_approx(unsigned int fsd)
+{
+	unsigned int tbl_size = sizeof(fsdi_table)/sizeof(unsigned int);
+	int i;
+
+	for (i = tbl_size-1; i >= 0; i--) {
+		if (fsdi_table[i] <= fsd)
+			return fsdi_table[i];
+	}
+	/* not reached: return smallest possible FSD */
+	return fsdi_table[0];
+}
+
diff --git a/src/rfid_iso14443_common.h b/src/rfid_iso14443_common.h
new file mode 100644
index 0000000..848d983
--- /dev/null
+++ b/src/rfid_iso14443_common.h
@@ -0,0 +1,11 @@
+#ifndef __RFID_ISO14443_COMMON_H
+#define __RFID_ISO14443_COMMON_H
+
+int iso14443_fsdi_to_fsd(unsigned int *fsd, unsigned char fsdi);
+int iso14443_fsd_to_fsdi(unsigned char *fsdi, unsigned int fsd);
+unsigned int iso14443_fsd_approx(unsigned int fsd);
+
+#define ISO14443_FREQ_CARRIER		13560000
+#define ISO14443_FREQ_SUBCARRIER	(ISO14443_FREQ_CARRIER/16)
+
+#endif
diff --git a/src/rfid_layer2.c b/src/rfid_layer2.c
new file mode 100644
index 0000000..8d1544a
--- /dev/null
+++ b/src/rfid_layer2.c
@@ -0,0 +1,109 @@
+/* librfid - layer 2 protocol handler 
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_layer2.h>
+
+static struct rfid_layer2 *rfid_layer2_list;
+
+struct rfid_layer2_handle *
+rfid_layer2_init(struct rfid_reader_handle *rh, unsigned int id)
+{
+	struct rfid_layer2 *p;
+
+	for (p = rfid_layer2_list; p; p = p->next)
+		if (p->id == id)
+			return p->fn.init(rh);
+
+	DEBUGP("unable to find matching layer2 protocol\n");
+	return NULL;
+}
+
+int
+rfid_layer2_open(struct rfid_layer2_handle *ph)
+{
+	if (!ph->l2->fn.open)
+		return 0;
+
+	return ph->l2->fn.open(ph);
+}
+
+int
+rfid_layer2_transcieve(struct rfid_layer2_handle *ph,
+			enum rfid_frametype frametype,
+			 const unsigned char *tx_buf, unsigned int len,
+			 unsigned char *rx_buf, unsigned int *rx_len,
+			 u_int64_t timeout, unsigned int flags)
+{
+	if (!ph->l2->fn.transcieve)
+		return -EIO;
+
+	return ph->l2->fn.transcieve(ph, frametype, tx_buf, len, rx_buf,
+				     rx_len, timeout, flags);
+}
+
+int rfid_layer2_fini(struct rfid_layer2_handle *ph)
+{
+	if (!ph->l2->fn.fini)
+		return 0;
+
+	return ph->l2->fn.fini(ph);
+}
+
+int
+rfid_layer2_close(struct rfid_layer2_handle *ph)
+{
+	if (!ph->l2->fn.close)
+		return 0;
+
+	return ph->l2->fn.close(ph);
+}
+
+int
+rfid_layer2_register(struct rfid_layer2 *p)
+{
+	p->next = rfid_layer2_list;
+	rfid_layer2_list = p;
+
+	return 0;
+}
+
+int
+rfid_layer2_getopt(struct rfid_layer2_handle *ph, int optname,
+		   void *optval, unsigned int *optlen)
+{
+	if (!ph->l2->fn.getopt)
+		return -EINVAL;
+
+	return ph->l2->fn.getopt(ph, optname, optval, optlen);
+}
+
+int
+rfid_layer2_setopt(struct rfid_layer2_handle *ph, int optname,
+		   const void *optval, unsigned int optlen)
+{
+	if (!ph->l2->fn.setopt)
+		return -EINVAL;
+
+	return ph->l2->fn.setopt(ph, optname, optval, optlen);
+}
diff --git a/src/rfid_layer2_iso14443a.c b/src/rfid_layer2_iso14443a.c
new file mode 100644
index 0000000..da2628f
--- /dev/null
+++ b/src/rfid_layer2_iso14443a.c
@@ -0,0 +1,323 @@
+/* ISO 14443-3 A anticollision implementation
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+
+#define TIMEOUT 1236
+
+/* Transcieve a 7-bit short frame */
+static int
+iso14443a_transcieve_sf(struct rfid_layer2_handle *handle,
+			 unsigned char cmd,
+			 struct iso14443a_atqa *atqa)
+{
+	struct rfid_reader *rdr = handle->rh->reader;
+
+	return rdr->iso14443a.transcieve_sf(handle->rh, cmd, atqa);
+}
+
+/* Transmit an anticollission bit frame */
+static int
+iso14443a_transcieve_acf(struct rfid_layer2_handle *handle,
+			 struct iso14443a_anticol_cmd *acf,
+			 unsigned int *bit_of_col)
+{
+	struct rfid_reader *rdr = handle->rh->reader;
+
+	return rdr->iso14443a.transcieve_acf(handle->rh, acf, bit_of_col);
+}
+
+/* Transmit a regular frame */
+static int 
+iso14443a_transcieve(struct rfid_layer2_handle *handle,
+		     enum rfid_frametype frametype, 
+			const unsigned char *tx_buf, unsigned int tx_len,
+			unsigned char *rx_buf, unsigned int *rx_len,
+			u_int64_t timeout, unsigned int flags)
+{
+	return handle->rh->reader->transcieve(handle->rh, frametype, tx_buf,
+					tx_len, rx_buf, rx_len, timeout, flags);
+}
+
+static int 
+iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits)
+{
+	unsigned int byte_count = bits / 8;
+	unsigned int bit_count = bits % 8;
+
+	if (byte_count < 2 || byte_count > 7)
+		return -1;
+
+	*nvb = ((byte_count & 0xf) << 4) | bit_count;
+
+	return 0;
+}
+
+/* first bit is '1', second bit '2' */
+static void
+set_bit_in_field(unsigned char *bitfield, unsigned int bit)
+{
+	unsigned int byte_count = bit / 8;
+	unsigned int bit_count = bit % 8;
+
+	DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n",
+			bitfield, byte_count, bit_count);
+	DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count));
+	*(bitfield+byte_count) |= 1 << (bit_count-1);
+	DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count));
+}
+
+static int
+iso14443a_anticol(struct rfid_layer2_handle *handle)
+{
+	int ret;
+	unsigned int uid_size;
+	struct iso14443a_handle *h = &handle->priv.iso14443a;
+	struct iso14443a_atqa atqa;
+	struct iso14443a_anticol_cmd acf;
+	unsigned int bit_of_col;
+	unsigned char sak[3];
+	unsigned int rx_len = sizeof(sak);
+	char *aqptr = (char *) &atqa;
+
+	memset(handle->uid, 0, sizeof(handle->uid));
+	memset(sak, 0, sizeof(sak));
+	memset(&atqa, 0, sizeof(atqa));
+	memset(&acf, 0, sizeof(acf));
+
+	ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_REQA, &atqa);
+	if (ret < 0) {
+		h->state = ISO14443A_STATE_REQA_SENT;
+		DEBUGP("error during transcieve_sf: %d\n", ret);
+		return ret;
+	}
+	h->state = ISO14443A_STATE_ATQA_RCVD;
+
+	DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1));
+
+	if (!atqa.bf_anticol) {
+		h->state = ISO14443A_STATE_NO_BITFRAME_ANTICOL;
+		DEBUGP("no bitframe anticollission bits set, aborting\n");
+		return -1;
+	}
+
+	if (atqa.uid_size == 2 || atqa.uid_size == 3)
+		uid_size = 3;
+	else if (atqa.uid_size == 1)
+		uid_size = 2;
+	else
+		uid_size = 1;
+	
+	acf.sel_code = ISO14443A_AC_SEL_CODE_CL1;
+
+	h->state = ISO14443A_STATE_ANTICOL_RUNNING;
+	h->level = ISO14443A_LEVEL_CL1;
+
+cascade:
+	iso14443a_code_nvb_bits(&acf.nvb, 16);
+
+	ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col);
+	if (ret < 0)
+		return ret;
+	DEBUGP("bit_of_col = %u\n", bit_of_col);
+	
+	while (bit_of_col != ISO14443A_BITOFCOL_NONE) {
+		set_bit_in_field(&acf.uid_bits[0], bit_of_col-16);
+		iso14443a_code_nvb_bits(&acf.nvb, bit_of_col);
+		ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col);
+		DEBUGP("bit_of_col = %u\n", bit_of_col);
+		if (ret < 0)
+			return ret;
+	}
+
+	iso14443a_code_nvb_bits(&acf.nvb, 7*8);
+	ret = iso14443a_transcieve(handle, RFID_14443A_FRAME_REGULAR,
+				   (unsigned char *)&acf, 7, 
+				   (unsigned char *) &sak, &rx_len,
+				   TIMEOUT, 0);
+	if (ret < 0)
+		return ret;
+
+	if (sak[0] & 0x04) {
+		/* Cascade bit set, UID not complete */
+		switch (acf.sel_code) {
+		case ISO14443A_AC_SEL_CODE_CL1:
+			/* cascading from CL1 to CL2 */
+			if (acf.uid_bits[0] != 0x88) {
+				DEBUGP("Cascade bit set, but UID0 != 0x88\n");
+				return -1;
+			}
+			memcpy(&handle->uid[0], &acf.uid_bits[1], 3);
+			acf.sel_code = ISO14443A_AC_SEL_CODE_CL2;
+			h->level = ISO14443A_LEVEL_CL2;
+			break;
+		case ISO14443A_AC_SEL_CODE_CL2:
+			/* cascading from CL2 to CL3 */
+			memcpy(&handle->uid[3], &acf.uid_bits[1], 3);
+			acf.sel_code = ISO14443A_AC_SEL_CODE_CL3;
+			h->level = ISO14443A_LEVEL_CL3;
+			break;
+		default:
+			DEBUGP("cannot cascade any further than CL3\n");
+			h->state = ISO14443A_STATE_ERROR;
+			return -1;
+			break;
+		}
+		goto cascade;
+
+	} else {
+		switch (acf.sel_code) {
+		case ISO14443A_AC_SEL_CODE_CL1:
+			/* single size UID (4 bytes) */
+			memcpy(&handle->uid[0], &acf.uid_bits[0], 4);
+			break;
+		case ISO14443A_AC_SEL_CODE_CL2:
+			/* double size UID (7 bytes) */
+			memcpy(&handle->uid[3], &acf.uid_bits[0], 4);
+			break;
+		case ISO14443A_AC_SEL_CODE_CL3:
+			/* triple size UID (10 bytes) */
+			memcpy(&handle->uid[6], &acf.uid_bits[0], 4);
+			break;
+		}
+	}
+
+	h->level = ISO14443A_LEVEL_NONE;
+	h->state = ISO14443A_STATE_SELECTED;
+
+	{
+		if (uid_size == 1)
+			handle->uid_len = 4;
+		else if (uid_size == 2)
+			handle->uid_len = 7;
+		else 
+			handle->uid_len = 10;
+
+		DEBUGP("UID %s\n", rfid_hexdump(handle->uid, handle->uid_len));
+	}
+
+	if (sak[0] & 0x20) {
+		DEBUGP("we have a T=CL compliant PICC\n");
+		h->tcl_capable = 1;
+	} else {
+		DEBUGP("we have a T!=CL PICC\n");
+		h->tcl_capable = 0;
+	}
+
+	return 0;
+}
+
+static int
+iso14443a_hlta(struct rfid_layer2_handle *handle)
+{
+	int ret;
+	unsigned char tx_buf[2] = { 0x50, 0x00 };
+	unsigned char rx_buf[10];
+	unsigned int rx_len = sizeof(rx_buf);
+
+	ret = iso14443a_transcieve(handle, RFID_14443A_FRAME_REGULAR,
+				   tx_buf, sizeof(tx_buf),
+				   rx_buf, &rx_len, 1000 /* 1ms */, 0);
+	if (ret < 0) {
+		/* "error" case: we don't get somethng back from the card */
+		return 0;
+	}
+	return -1;
+}
+
+static int
+iso14443a_setopt(struct rfid_layer2_handle *handle, int optname,
+		 const void *optval, unsigned int optlen)
+{
+	int ret = -EINVAL;
+	struct rfid_reader *rdr = handle->rh->reader;
+	unsigned int speed;
+
+	switch (optname) {
+	case RFID_OPT_14443A_SPEED_RX:
+		if (!rdr->iso14443a.set_speed)
+			return -ENOTSUP;
+		speed = *(unsigned int *)optval;
+		ret = rdr->iso14443a.set_speed(handle->rh, 0, speed);
+		break;
+	case RFID_OPT_14443A_SPEED_TX:
+		if (!rdr->iso14443a.set_speed)
+			return -ENOTSUP;
+		speed = *(unsigned int *)optval;
+		ret = rdr->iso14443a.set_speed(handle->rh, 1, speed);
+		break;
+	};
+
+	return ret;
+}
+
+
+static struct rfid_layer2_handle *
+iso14443a_init(struct rfid_reader_handle *rh)
+{
+	int ret;
+	struct rfid_layer2_handle *h = malloc(sizeof(*h));
+	if (!h)
+		return NULL;
+
+	h->l2 = &rfid_layer2_iso14443a;
+	h->rh = rh;
+	h->priv.iso14443a.state = ISO14443A_STATE_NONE;
+	h->priv.iso14443a.level = ISO14443A_LEVEL_NONE;
+
+	ret = h->rh->reader->iso14443a.init(h->rh);
+	if (ret < 0) {
+		free(h);
+		return NULL;
+	}
+
+	return h;
+}
+
+static int
+iso14443a_fini(struct rfid_layer2_handle *handle)
+{
+	free(handle);
+	return 0;
+}
+
+
+struct rfid_layer2 rfid_layer2_iso14443a = {
+	.id	= RFID_LAYER2_ISO14443A,
+	.name 	= "ISO 14443-3 A",
+	.fn	= {
+		.init 		= &iso14443a_init,
+		.open 		= &iso14443a_anticol,
+		.transcieve 	= &iso14443a_transcieve,
+		.close 		= &iso14443a_hlta,
+		.fini 		= &iso14443a_fini,
+		.setopt		= &iso14443a_setopt,
+	},
+};
+
diff --git a/src/rfid_layer2_iso14443b.c b/src/rfid_layer2_iso14443b.c
new file mode 100644
index 0000000..7c92562
--- /dev/null
+++ b/src/rfid_layer2_iso14443b.c
@@ -0,0 +1,344 @@
+/* ISO 14443-3 B anticollision implementation
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/rfid_layer2_iso14443b.h>
+
+#include "rfid_iso14443_common.h"
+
+#define ATQB_TIMEOUT 	((256*10e6/ISO14443_FREQ_SUBCARRIER)		\
+			 +(200*10e6/ISO14443_FREQ_SUBCARRIER))
+
+static inline int
+fwi_to_fwt(struct rfid_layer2_handle *h, unsigned int *fwt, unsigned int fwi)
+{
+	unsigned int multiplier, tmp;
+
+	/* 15 is RFU */
+	if (fwi > 14)
+		return -1;
+
+	/* According to ISO 14443-3:200(E), Chapter 7.9.4.3, the forumala is
+	 * (256 * 16 / fC) * 2^fwi We avoid floating point computations by
+	 * shifting everything into the microsecond range.  In integer
+	 * calculations 1000000*256*16/13560000 evaluates to 302 (instead of
+	 * 302.064897), which provides sufficient precision, IMHO.  The max
+	 * result is 302 * 16384 (4947968), which fits well within the 31/32
+	 * bit range of an integer */
+
+	multiplier = 1 << fwi;		/* 2 to the power of fwi */
+
+	tmp = (unsigned int) 1000000 * 256 * 16;
+
+	return (tmp / h->rh->ah->asic->fc) * multiplier;
+}
+
+static int
+parse_atqb(struct rfid_layer2_handle *h, struct iso14443b_atqb *atqb)
+{
+	int ret;
+
+	if (atqb->fifty != 0x50)
+		return -1; 
+
+	if (atqb->protocol_info.fo & 0x01)
+		h->priv.iso14443b.flags |= ISO14443B_CID_SUPPORTED;
+	if (atqb->protocol_info.fo & 0x02)
+		h->priv.iso14443b.flags |= ISO14443B_NAD_SUPPORTED;
+
+	ret = fwi_to_fwt(h, &h->priv.iso14443b.fwt, atqb->protocol_info.fwi);
+	if (ret < 0) {
+		DEBUGP("invalid fwi %u\n", atqb->protocol_info.fwi);
+		return ret;
+	}
+
+	if (atqb->protocol_info.protocol_type == 0x1) {
+		DEBUGP("we have a T=CL compliant PICC\n");
+		h->priv.iso14443b.tcl_capable = 1;
+	} else {
+		DEBUGP("we have a T!=CL PICC\n");
+		h->priv.iso14443b.tcl_capable = 0;
+	}
+
+	iso14443_fsdi_to_fsd(&h->priv.iso14443b.fsc, 
+			     atqb->protocol_info.max_frame_size);
+
+	/* FIXME: speed capability */
+
+	memcpy(h->uid, atqb->pupi, sizeof(atqb->pupi));
+	h->uid_len = sizeof(atqb->pupi);
+
+	return 0;
+}
+
+static int
+send_reqb(struct rfid_layer2_handle *h, unsigned char afi,
+	  unsigned int is_wup, unsigned int num_initial_slots)
+{
+	int ret;
+	unsigned char reqb[3];
+	struct iso14443b_atqb atqb;
+	unsigned int atqb_len = sizeof(atqb);
+	unsigned int num_slot_idx = num_initial_slots;
+
+	reqb[0] = 0x05;
+	reqb[1] = afi;
+
+	for (num_slot_idx = num_initial_slots; num_slot_idx <= 4;
+	     num_slot_idx++) {
+		reqb[2] = num_slot_idx & 0x07;
+		if (is_wup)
+			reqb[2] |= 0x08;
+
+		ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR,
+						reqb, sizeof(reqb),
+						 (unsigned char *)&atqb, 
+						 &atqb_len, ATQB_TIMEOUT, 0);
+		h->priv.iso14443b.state = ISO14443B_STATE_REQB_SENT;
+		if (ret < 0) {
+			DEBUGP("error during transcieve of REQB/WUBP\n");
+			continue;
+		}
+
+		/* FIXME: send N-1 slot marker frames */
+	
+		if (atqb_len != sizeof(atqb)) {
+			DEBUGP("error: atqb_len = %u instead of %Zu\n",
+				atqb_len, sizeof(atqb));
+			continue;
+		}
+
+		/* FIXME: how to detect a collission at 14443B ?  I guess we
+		 * can only rely on the CRC checking (CRCErr in ErrorFlag
+		 * register?) */
+
+		if (parse_atqb(h, &atqb) >= 0) {
+			h->priv.iso14443b.state = ISO14443B_STATE_ATQB_RCVD;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static inline unsigned int mbli_to_mbl(struct rfid_layer2_handle *h,
+					unsigned int mbli)
+{
+	return (h->priv.iso14443b.fsc * 2 ^ (mbli-1));
+}
+
+static int
+transcieve_attrib(struct rfid_layer2_handle *h, const unsigned char *inf,
+	    unsigned int inf_len, unsigned char *rx_data, unsigned int *rx_len)
+{
+	struct iso14443b_attrib_hdr *attrib;
+	unsigned int attrib_size = sizeof(*attrib) + inf_len;
+	unsigned char *rx_buf;
+	unsigned char fsdi;
+	int ret = 0;
+	
+	DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd);
+	attrib = malloc(attrib_size);
+	if (!attrib) {
+		perror("attrib_alloc");
+		return -1;
+	}
+
+	DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd);
+	rx_buf = malloc(*rx_len+1);
+	if (!rx_buf) {
+		perror("rx_buf malloc");
+		ret = -1;
+		goto out_attrib;
+	}
+
+	/* initialize attrib frame */
+	memset(attrib, 0, attrib_size);
+	if (inf_len)
+		memcpy((unsigned char *)attrib+sizeof(*attrib), inf, inf_len);
+
+	attrib->one_d = 0x1d;
+	memcpy(attrib->identifier, h->uid, 4);
+
+	/* FIXME: do we want to change TR0/TR1 from its default ? */
+	/* FIXME: do we want to change SOF/EOF from its default ? */
+
+	ret = iso14443_fsd_to_fsdi(&fsdi, h->priv.iso14443b.fsd);
+	if (ret < 0) {
+		DEBUGP("unable to map FSD(%u) to FSDI\n",
+			h->priv.iso14443b.fsd);
+		goto out_rx;
+	}
+	attrib->param2.fsdi = fsdi;
+
+	/* FIXME: spd_in / spd_out */
+	if (h->priv.iso14443b.tcl_capable == 1)
+		attrib->param3.protocol_type = 0x1;
+
+	*rx_len = *rx_len + 1;
+	ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR,
+					(unsigned char *) attrib,
+					sizeof(*attrib)+inf_len,
+					rx_buf, rx_len, h->priv.iso14443b.fwt,
+					0);
+	h->priv.iso14443b.state = ISO14443B_STATE_ATTRIB_SENT;
+	if (ret < 0) {
+		DEBUGP("transcieve problem\n");
+		goto out_rx;
+	}
+
+	if ((rx_buf[0] & 0x0f) != h->priv.iso14443b.cid) {
+		DEBUGP("ATTRIB response with invalid CID %u\n",
+			rx_buf[0] & 0x0f);
+		ret = -1;
+		goto out_rx;
+	}
+
+	h->priv.iso14443b.state = ISO14443B_STATE_SELECTED;
+	
+	h->priv.iso14443b.mbl = mbli_to_mbl(h, (rx_data[0] & 0xf0) >> 4);
+
+	*rx_len = *rx_len - 1;
+	memcpy(rx_data, rx_buf+1, *rx_len);
+
+out_rx:
+	free(rx_buf);
+out_attrib:
+	free(attrib);
+
+	return ret;
+}
+
+static int
+iso14443b_hltb(struct rfid_layer2_handle *h)
+{
+	int ret;
+	unsigned char hltb[5];
+	unsigned char hltb_resp[1];
+	unsigned int hltb_len = 1;
+
+	hltb[0] = 0x50;
+	memcpy(hltb+1, h->uid, 4);
+
+	ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR,
+					hltb, 5,
+					hltb_resp, &hltb_len,
+					h->priv.iso14443b.fwt, 0);
+	h->priv.iso14443b.state = ISO14443B_STATE_HLTB_SENT;
+	if (ret < 0) {
+		DEBUGP("transcieve problem\n");
+		return ret;
+	}
+
+	if (hltb_len != 1 || hltb_resp[0] != 0x00) {
+		DEBUGP("bad HLTB response\n");
+		return -1;
+	}
+	h->priv.iso14443b.state = ISO14443B_STATE_HALTED;
+						
+	return 0;
+}
+
+static int
+iso14443b_anticol(struct rfid_layer2_handle *handle)
+{
+	unsigned char afi = 0; /* FIXME */
+	int ret;
+	unsigned char buf[255];
+	unsigned int buf_len = sizeof(buf);
+
+	ret = send_reqb(handle, afi, 0, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = transcieve_attrib(handle, NULL, 0, buf, &buf_len);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct rfid_layer2_handle *
+iso14443b_init(struct rfid_reader_handle *rh)
+{
+	int ret;
+	struct rfid_layer2_handle *h = malloc(sizeof(*h));
+	if (!h)
+		return NULL;
+
+	h->l2 = &rfid_layer2_iso14443b;
+	h->rh = rh;
+	h->priv.iso14443b.state = ISO14443B_STATE_NONE;
+
+	h->priv.iso14443b.fsd = iso14443_fsd_approx(rh->ah->mru);
+	DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd);
+
+	/* 14443-3 Section 7.1.6 */
+	h->priv.iso14443b.tr0 = (256/ISO14443_FREQ_SUBCARRIER)*10e6;
+	h->priv.iso14443b.tr1 = (200/ISO14443_FREQ_SUBCARRIER)*10e6;
+
+	ret = h->rh->reader->iso14443b.init(h->rh);
+	if (ret < 0) {
+		DEBUGP("error during reader 14443b init\n");
+		free(h);
+		return NULL;
+	}
+
+	return h;
+}
+
+static int
+iso14443b_fini(struct rfid_layer2_handle *handle)
+{
+	free(handle);
+	return 0;
+}
+
+static int
+iso14443b_transcieve(struct rfid_layer2_handle *handle,
+		     enum rfid_frametype frametype,
+		     const unsigned char *tx_buf, unsigned int tx_len,
+		     unsigned char *rx_buf, unsigned int *rx_len,
+		     u_int64_t timeout, unsigned int flags)
+{
+	DEBUGP("transcieving %u bytes, expecting max %u\n", tx_len, *rx_len);
+	return handle->rh->reader->transcieve(handle->rh, frametype,
+					      tx_buf, tx_len,
+					      rx_buf, rx_len, timeout, flags);
+}
+
+struct rfid_layer2 rfid_layer2_iso14443b = {
+	.id	= RFID_LAYER2_ISO14443B,
+	.name 	= "ISO 14443-3 B",
+	.fn	= {
+		.init 		= &iso14443b_init,
+		.open 		= &iso14443b_anticol,
+		.transcieve 	= &iso14443b_transcieve,
+		.close 		= &iso14443b_hltb,
+		.fini 		= &iso14443b_fini,
+	},
+};
diff --git a/src/rfid_layer2_iso15693.c b/src/rfid_layer2_iso15693.c
new file mode 100644
index 0000000..1a93a19
--- /dev/null
+++ b/src/rfid_layer2_iso15693.c
@@ -0,0 +1,302 @@
+/* ISO 15693 anticollision implementation
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/rfid_layer2_iso15693.h>
+
+#if 0
+/* Transcieve a 7-bit short frame */
+static int
+iso14443a_transcieve_sf(struct rfid_layer2_handle *handle,
+			 unsigned char cmd,
+			 struct iso14443a_atqa *atqa)
+{
+	struct rfid_reader *rdr = handle->rh->reader;
+
+	return rdr->iso14443a.transcieve_sf(handle->rh, cmd, atqa);
+}
+
+/* Transmit an anticollission bit frame */
+static int
+iso14443a_transcieve_acf(struct rfid_layer2_handle *handle,
+			 struct iso14443a_anticol_cmd *acf,
+			 unsigned int *bit_of_col)
+{
+	struct rfid_reader *rdr = handle->rh->reader;
+
+	return rdr->iso14443a.transcieve_acf(handle->rh, acf, bit_of_col);
+}
+
+/* Transmit a regular frame */
+static int 
+iso14443a_transcieve(struct rfid_layer2_handle *handle,
+			const unsigned char *tx_buf, unsigned int tx_len,
+			unsigned char *rx_buf, unsigned int *rx_len,
+			u_int64_t, unsigned int flags)
+{
+	return handle->rh->reader->transcieve(handle->rh, tx_buf, tx_len, 
+						rx_buf, rx_len, timeout, flags);
+}
+
+static int 
+iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits)
+{
+	unsigned int byte_count = bits / 8;
+	unsigned int bit_count = bits % 8;
+
+	if (byte_count < 2 || byte_count > 7)
+		return -1;
+
+	*nvb = ((byte_count & 0xf) << 4) | bit_count;
+
+	return 0;
+}
+
+/* first bit is '1', second bit '2' */
+static void
+set_bit_in_field(unsigned char *bitfield, unsigned int bit)
+{
+	unsigned int byte_count = bit / 8;
+	unsigned int bit_count = bit % 8;
+
+	DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n",
+			bitfield, byte_count, bit_count);
+	DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count));
+	*(bitfield+byte_count) |= 1 << (bit_count-1);
+	DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count));
+}
+
+static int
+iso14443a_anticol(struct rfid_layer2_handle *handle)
+{
+	int ret;
+	unsigned int uid_size;
+	struct iso14443a_atqa atqa;
+	struct iso14443a_anticol_cmd acf;
+	unsigned int bit_of_col;
+	unsigned char sak[3];
+	unsigned char uid[10];	// triple size equals 10 bytes;
+	unsigned int rx_len = sizeof(sak);
+	char *aqptr = (char *) &atqa;
+	static int first = 0;
+
+	memset(uid, 0, sizeof(uid));
+	memset(sak, 0, sizeof(sak));
+	memset(&atqa, 0, sizeof(atqa));
+	memset(&acf, 0, sizeof(acf));
+
+	if (first == 0) {
+	DEBUGP("Sending REQA\n");
+	ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_REQA, &atqa);
+	first = 1;
+	} else {
+	DEBUGP("Sending WUPA\n");
+	ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_WUPA, &atqa);
+	}
+
+	if (ret < 0) {
+		handle->priv.iso14443a.state = ISO14443A_STATE_REQA_SENT;
+		DEBUGP("error during transcieve_sf: %d\n", ret);
+		return ret;
+	}
+	handle->priv.iso14443a.state = ISO14443A_STATE_ATQA_RCVD;
+
+	DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1));
+
+	if (!atqa.bf_anticol) {
+		handle->priv.iso14443a.state =ISO14443A_STATE_NO_BITFRAME_ANTICOL;
+		DEBUGP("no bitframe anticollission bits set, aborting\n");
+		return -1;
+	}
+
+	if (atqa.uid_size == 2 || atqa.uid_size == 3)
+		uid_size = 3;
+	else if (atqa.uid_size == 1)
+		uid_size = 2;
+	else
+		uid_size = 1;
+	
+	acf.sel_code = ISO14443A_AC_SEL_CODE_CL1;
+
+	handle->priv.iso14443a.state = ISO14443A_STATE_ANTICOL_RUNNING;
+	handle->priv.iso14443a.level = ISO14443A_LEVEL_CL1;
+
+cascade:
+	iso14443a_code_nvb_bits(&acf.nvb, 16);
+
+	ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col);
+	if (ret < 0)
+		return ret;
+	DEBUGP("bit_of_col = %u\n", bit_of_col);
+	
+	while (bit_of_col != ISO14443A_BITOFCOL_NONE) {
+		set_bit_in_field(&acf.uid_bits[0], bit_of_col-16);
+		iso14443a_code_nvb_bits(&acf.nvb, bit_of_col);
+		ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col);
+		DEBUGP("bit_of_col = %u\n", bit_of_col);
+		if (ret < 0)
+			return ret;
+	}
+
+	iso14443a_code_nvb_bits(&acf.nvb, 7*8);
+	ret = iso14443a_transcieve(handle, (unsigned char *)&acf, 7, 
+				   (unsigned char *) &sak, &rx_len,
+				   TIMEOUT, 0);
+	if (ret < 0)
+		return ret;
+
+	if (sak[0] & 0x04) {
+		/* Cascade bit set, UID not complete */
+		switch (acf.sel_code) {
+		case ISO14443A_AC_SEL_CODE_CL1:
+			/* cascading from CL1 to CL2 */
+			if (acf.uid_bits[0] != 0x88) {
+				DEBUGP("Cascade bit set, but UID0 != 0x88\n");
+				return -1;
+			}
+			memcpy(&uid[0], &acf.uid_bits[1], 3);
+			acf.sel_code = ISO14443A_AC_SEL_CODE_CL2;
+			handle->priv.iso14443a.level = ISO14443A_LEVEL_CL2;
+			break;
+		case ISO14443A_AC_SEL_CODE_CL2:
+			/* cascading from CL2 to CL3 */
+			memcpy(&uid[3], &acf.uid_bits[1], 3);
+			acf.sel_code = ISO14443A_AC_SEL_CODE_CL3;
+			handle->priv.iso14443a.level = ISO14443A_LEVEL_CL3;
+			break;
+		default:
+			DEBUGP("cannot cascade any further than CL3\n");
+			handle->priv.iso14443a.state = ISO14443A_STATE_ERROR;
+			return -1;
+			break;
+		}
+		goto cascade;
+
+	} else {
+		switch (acf.sel_code) {
+		case ISO14443A_AC_SEL_CODE_CL1:
+			/* single size UID (4 bytes) */
+			memcpy(&uid[0], &acf.uid_bits[0], 4);
+			break;
+		case ISO14443A_AC_SEL_CODE_CL2:
+			/* double size UID (7 bytes) */
+			memcpy(&uid[3], &acf.uid_bits[0], 4);
+			break;
+		case ISO14443A_AC_SEL_CODE_CL3:
+			/* triple size UID (10 bytes) */
+			memcpy(&uid[6], &acf.uid_bits[0], 4);
+			break;
+		}
+	}
+
+	handle->priv.iso14443a.level = ISO14443A_LEVEL_NONE;
+	handle->priv.iso14443a.state = ISO14443A_STATE_SELECTED;
+
+	{
+		int uid_len;
+		if (uid_size == 1)
+			uid_len = 4;
+		else if (uid_size == 2)
+			uid_len = 7;
+		else 
+			uid_len = 10;
+
+		DEBUGP("UID %s\n", rfid_hexdump(uid, uid_len));
+	}
+
+	if (sak[0] & 0x20) {
+		DEBUGP("we have a T=CL compliant PICC\n");
+		handle->priv.iso14443a.tcl_capable = 1;
+	} else {
+		DEBUGP("we have a T!=CL PICC\n");
+		handle->priv.iso14443a.tcl_capable = 0;
+	}
+
+	return 0;
+}
+
+static int
+iso14443a_hlta(struct rfid_layer2_handle *handle)
+{
+	int ret;
+	unsigned char tx_buf[2] = { 0x50, 0x00 };
+	unsigned char rx_buf[10];
+	unsigned int rx_len = sizeof(rx_buf);
+
+	return 0;
+
+	ret = iso14443a_transcieve(handle, tx_buf, sizeof(tx_buf),
+				   rx_buf, &rx_len, 1000 /* 1ms */, 0);
+	if (ret < 0) {
+		/* "error" case: we don't get somethng back from the card */
+		return 0;
+	}
+	return -1;
+}
+#endif
+
+static struct rfid_layer2_handle *
+iso15693_init(struct rfid_reader_handle *rh)
+{
+	int ret;
+	struct rfid_layer2_handle *h = malloc(sizeof(*h));
+	if (!h)
+		return NULL;
+
+	h->l2 = &rfid_layer2_iso15693;
+	h->rh = rh;
+	h->priv.iso15693.state = ISO15693_STATE_NONE;
+
+	ret = h->rh->reader->iso15693.init(h->rh);
+	if (ret < 0) {
+		free(h);
+		return NULL;
+	}
+
+	return h;
+}
+
+static int
+iso15693_fini(struct rfid_layer2_handle *handle)
+{
+	free(handle);
+	return 0;
+}
+
+
+struct rfid_layer2 rfid_layer2_iso15693 = {
+	.id	= RFID_LAYER2_ISO15693,
+	.name 	= "ISO 15693",
+	.fn	= {
+		.init 		= &iso15693_init,
+		//.open 		= &iso15693_anticol,
+		//.transcieve 	= &iso15693_transcieve,
+		//.close 		= &iso14443a_hlta,
+		.fini 		= &iso15693_fini,
+	},
+};
+
diff --git a/src/rfid_proto_mifare_classic.c b/src/rfid_proto_mifare_classic.c
new file mode 100644
index 0000000..e2ee80c
--- /dev/null
+++ b/src/rfid_proto_mifare_classic.c
@@ -0,0 +1,151 @@
+
+/* Mifare Classic implementation, PCD side.
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_protocol_mifare_classic.h>
+
+#include <librfid/rfid_reader.h>
+
+#include "rfid_iso14443_common.h"
+
+
+#define MIFARE_UL_CMD_WRITE	0xA2
+#define MIFARE_UL_CMD_READ	0x30
+
+/* FIXME */
+#define MIFARE_CL_READ_FWT	100
+#define MIFARE_CL_WRITE_FWT	100
+
+static int
+mfcl_read(struct rfid_protocol_handle *ph, unsigned int page,
+	  unsigned char *rx_data, unsigned int *rx_len)
+{
+	unsigned char rx_buf[16];
+	unsigned int real_rx_len = sizeof(rx_buf);
+	unsigned char tx[2];
+	int ret;
+
+	if (page > MIFARE_CL_PAGE_MAX)
+		return -EINVAL;
+
+	tx[0] = MIFARE_CL_CMD_READ;
+	tx[1] = page & 0xff;
+
+	ret = rfid_layer2_transcieve(ph->l2h, RFID_MIFARE_FRAME, tx,
+				     sizeof(tx), rx_buf, &real_rx_len,
+				     MIFARE_CL_READ_FWT, 0);
+
+	if (ret < 0)
+		return ret;
+
+	if (real_rx_len == 1 && *rx_buf == 0x04)
+		return -EPERM;
+
+	if (real_rx_len < *rx_len)
+		*rx_len = real_rx_len;
+
+	memcpy(rx_data, rx_buf, *rx_len);
+
+	return ret;
+}
+
+static int
+mfcl_write(struct rfid_protocol_handle *ph, unsigned int page,
+	   unsigned char *tx_data, unsigned int tx_len)
+{
+	unsigned int i;
+	unsigned char tx[18];
+	unsigned char rx[1];
+	unsigned int rx_len;
+	int ret;
+
+	if (tx_len != 16 || page > MIFARE_CL_PAGE_MAX)
+		return -EINVAL;
+
+	tx[0] = MIFARE_CL_CMD_WRITE16;
+	tx[1] = page & 0xff;
+
+	memcpy(tx+2, tx_data, 16);
+
+	ret = rfid_layer2_transcieve(ph->l2h, RFID_MIFARE_FRAME, tx,
+				     sizeof(tx), rx, &rx_len, 
+				     MIFARE_CL_WRITE_FWT, 0);
+					
+	if (ret < 0)
+		return ret;
+
+	if (rx[0] != MIFARE_UL_RESP_ACK)
+		return -EIO;
+
+	return ret;
+}
+
+static struct rfid_protocol_handle *
+mfcl_init(struct rfid_layer2_handle *l2h)
+{
+	struct rfid_protocol_handle *ph;
+	ph = malloc(sizeof(struct rfid_protocol_handle));
+	return ph;
+}
+
+static int mfcl_fini(struct rfid_protocol_handle *ph)
+{
+	free(ph);
+	return 0;
+}
+
+struct rfid_protocol rfid_protocol_mfcl = {
+	.id	= RFID_PROTOCOL_MIFARE_CLASSIC,
+	.name	= "Mifare Classic",
+	.fn	= {
+		.init 		= &mfcl_init,
+		.read		= &mfcl_read,
+		.write 		= &mfcl_write,
+		.fini		= &mfcl_fini,
+	},
+};
+
+int mfcl_set_key(struct rfid_protocol_handle *ph, unsigned char *key)
+{
+	if (!ph->l2h->rh->reader->mifare_classic.setkey)
+		return -ENODEV;
+
+	return ph->l2h->rh->reader->mifare_classic.setkey(ph->l2h->rh, key);
+}
+
+int mfcl_auth(struct rfid_protocol_handle *ph, u_int8_t cmd, u_int8_t block)
+{
+	u_int32_t serno = *((u_int32_t *)ph->l2h->uid);
+
+	if (!ph->l2h->rh->reader->mifare_classic.auth)
+		return -ENODEV;
+
+	return ph->l2h->rh->reader->mifare_classic.auth(ph->l2h->rh, cmd,
+						       serno, block);
+}
diff --git a/src/rfid_proto_mifare_ul.c b/src/rfid_proto_mifare_ul.c
new file mode 100644
index 0000000..747f38c
--- /dev/null
+++ b/src/rfid_proto_mifare_ul.c
@@ -0,0 +1,162 @@
+
+/* Mifare Ultralight implementation, PCD side.
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_protocol_mifare_ul.h>
+
+#include "rfid_iso14443_common.h"
+
+
+/* FIXME */
+#define MIFARE_UL_READ_FWT	100
+#define MIFARE_UL_WRITE_FWT	100
+
+static int
+mful_read(struct rfid_protocol_handle *ph, unsigned int page,
+	  unsigned char *rx_data, unsigned int *rx_len)
+{
+	unsigned char rx_buf[16];
+	unsigned int real_rx_len = sizeof(rx_buf);
+	unsigned char tx[2];
+	int ret;
+
+	if (page > MIFARE_UL_PAGE_MAX)
+		return -EINVAL;
+
+	tx[0] = MIFARE_UL_CMD_READ;
+	tx[1] = page & 0xff;
+
+	ret = rfid_layer2_transcieve(ph->l2h, RFID_14443A_FRAME_REGULAR,
+				     tx, sizeof(tx), rx_buf, 
+				     &real_rx_len, MIFARE_UL_READ_FWT, 0);
+
+	if (ret < 0)
+		return ret;
+
+	if (real_rx_len < *rx_len)
+		*rx_len = real_rx_len;
+
+	memcpy(rx_data, rx_buf, *rx_len);
+
+	return ret;
+}
+
+static int
+mful_write(struct rfid_protocol_handle *ph, unsigned int page,
+	   unsigned char *tx_data, unsigned int tx_len)
+{
+	unsigned int i;
+	unsigned char tx[6];
+	unsigned char rx[10];
+	unsigned int rx_len = sizeof(rx);
+	int ret;
+
+	if (tx_len != 4 || page > MIFARE_UL_PAGE_MAX)
+		return -EINVAL;
+
+	tx[0] = MIFARE_UL_CMD_WRITE;
+	tx[1] = page & 0xff;
+
+	for (i = 0; i < 4; i++)
+		tx[2+i] = tx_data[i];
+
+	ret = rfid_layer2_transcieve(ph->l2h, RFID_14443A_FRAME_REGULAR,
+				     tx, sizeof(tx), rx, &rx_len, 
+				     MIFARE_UL_WRITE_FWT, 0);
+					
+	if (ret < 0)
+		return ret;
+
+	if (rx[0] != MIFARE_UL_RESP_ACK)
+		return -EIO;
+
+	return ret;
+}
+
+static int
+mful_transcieve(struct rfid_protocol_handle *ph,
+		const unsigned char *tx_data, unsigned int tx_len,
+		unsigned char *rx_data, unsigned int *rx_len,
+		unsigned int timeout, unsigned int flags)
+{
+	return -EINVAL;
+}
+
+static struct rfid_protocol_handle *
+mful_init(struct rfid_layer2_handle *l2h)
+{
+	struct rfid_protocol_handle *ph;
+	ph = malloc(sizeof(struct rfid_protocol_handle));
+	return ph;
+}
+
+static int mful_fini(struct rfid_protocol_handle *ph)
+{
+	free(ph);
+	return 0;
+}
+
+struct rfid_protocol rfid_protocol_mful = {
+	.id	= RFID_PROTOCOL_MIFARE_UL,
+	.name	= "Mifare Ultralight",
+	.fn	= {
+		.init 		= &mful_init,
+		.read		= &mful_read,
+		.write 		= &mful_write,
+		.fini		= &mful_fini,
+	},
+};
+
+/* Functions below are not (yet? covered in the generic librfid api */
+
+
+/* lock a certain page */
+int rfid_mful_lock_page(struct rfid_protocol_handle *ph, unsigned int page)
+{
+	unsigned char buf[4] = { 0x00, 0x00, 0x00, 0x00 };
+
+	if (ph->proto != &rfid_protocol_mful)
+		return -EINVAL;
+
+	if (page < 3 || page > 15)
+		return -EINVAL;
+
+	if (page > 8)
+		buf[2] = (1 << page);
+	else
+		buf[3] = (1 << (page - 8));
+
+	return mful_write(ph, MIFARE_UL_PAGE_LOCK, buf, sizeof(buf));
+}
+
+/* convenience wrapper to lock the otp page */
+int rfid_mful_lock_otp(struct rfid_protocol_handle *ph)
+{
+	return rfid_mful_lock_page(ph, MIFARE_UL_PAGE_OTP);
+}
diff --git a/src/rfid_proto_tcl.c b/src/rfid_proto_tcl.c
new file mode 100644
index 0000000..901e42c
--- /dev/null
+++ b/src/rfid_proto_tcl.c
@@ -0,0 +1,720 @@
+/* ISO 14443-4 (T=CL) implementation, PCD side.
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_protocol_tcl.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_layer2_iso14443b.h>
+
+#include <librfid/rfid_asic.h>
+#include <librfid/rfid_reader.h>
+
+#include "rfid_iso14443_common.h"
+
+static enum rfid_frametype l2_to_frame(unsigned int layer2)
+{
+	switch (layer2) {
+		case RFID_LAYER2_ISO14443A:
+			return RFID_14443A_FRAME_REGULAR;
+			break;
+		case RFID_LAYER2_ISO14443B:
+			return RFID_14443B_FRAME_REGULAR;
+			break;
+	}
+	return 0;
+}
+
+static unsigned int sfgi_to_sfgt(struct rfid_protocol_handle *h, 
+				 unsigned char sfgi)
+{
+	unsigned int multiplier;
+	unsigned int tmp;
+
+	if (sfgi > 14)
+		sfgi = 14;
+
+	multiplier = 1 << sfgi; /* 2 to the power of sfgi */
+
+	/* ISO 14443-4:2000(E) Section 5.2.5:
+	 * (256 * 16 / h->l2h->rh->ah->fc) * (2 ^ sfgi) */
+	tmp = (unsigned int) 1000000 * 256 * 16;
+
+	return (tmp / h->l2h->rh->ah->fc) * multiplier;
+}
+
+static unsigned int fwi_to_fwt(struct rfid_protocol_handle *h, 
+				unsigned char fwi)
+{
+	unsigned int multiplier, tmp;
+
+	if (fwi > 14)
+		fwi = 14;
+
+	multiplier  = 1 << fwi; /* 2 to the power of fwi */
+
+	/* ISO 14443-4:2000(E) Section 7.2.:
+	 * (256*16 / h->l2h->rh->ah->fc) * (2 ^ fwi) */
+
+	tmp = (unsigned int) 1000000 * 256 * 16;
+
+	return (tmp / h->l2h->rh->ah->fc) * multiplier;
+}
+
+/* 4.9seconds as microseconds (4.9 billion seconds) exceeds 2^32 */
+#define activation_fwt(x) (((u_int64_t)1000000 * 65536 / x->l2h->rh->ah->fc))
+#define deactivation_fwt(x) activation_fwt(x)
+
+static int
+tcl_parse_ats(struct rfid_protocol_handle *h, 
+		unsigned char *ats, unsigned int size)
+{
+	unsigned char len = ats[0];
+	unsigned char t0;
+	unsigned char *cur;
+
+	if (len == 0 || size == 0) 
+		return -1;
+
+	if (size < len)
+		len = size;
+
+	h->priv.tcl.ta = 0;
+
+	if (len == 1) {
+		/* FIXME: assume some default values */
+		h->priv.tcl.fsc = 32;
+		h->priv.tcl.ta = 0x80;	/* 0x80 (same d for both dirs) */
+		h->priv.tcl.sfgt = sfgi_to_sfgt(h, 0);
+		if (h->l2h->l2->id == RFID_LAYER2_ISO14443A) {
+			/* Section 7.2: fwi default for type A is 4 */
+			h->priv.tcl.fwt = fwi_to_fwt(h, 4);
+		} else {
+			/* Section 7.2: fwi for type B is always in ATQB */
+			/* Value is assigned in tcl_connect() */
+			/* This function is never called for Type B, since it has no (R)ATS */
+		}
+		return 0;
+	}
+
+	/* guarateed to be at least 2 bytes in size */
+
+	t0 = ats[1];
+	cur = &ats[2];
+
+	iso14443_fsdi_to_fsd(&h->priv.tcl.fsc, t0 & 0x0f);
+
+	if (t0 & (1 << 4)) {
+		/* TA is transmitted */
+		h->priv.tcl.ta = *cur++;
+	}
+
+	if (t0 & (1 << 5)) {
+		/* TB is transmitted */
+		h->priv.tcl.sfgt = sfgi_to_sfgt(h, *cur & 0x0f);
+		h->priv.tcl.fwt = fwi_to_fwt(h, (*cur & 0xf0) >> 4);
+		cur++;
+	}
+
+	if (t0 & (1 << 6)) {
+		/* TC is transmitted */
+		if (*cur & 0x01)
+			h->priv.tcl.flags |= TCL_HANDLE_F_NAD_SUPPORTED;
+		if (*cur & 0x02)
+			h->priv.tcl.flags |= TCL_HANDLE_F_CID_SUPPORTED;
+		cur++;
+	}
+
+	h->priv.tcl.historical_len = (ats+len) - cur;
+	h->priv.tcl.historical_bytes = cur;
+
+	return 0;
+}
+
+
+/* request an ATS from the PICC */
+static int
+tcl_request_ats(struct rfid_protocol_handle *h)
+{
+	int ret;
+	unsigned char rats[2];
+	unsigned char fsdi;
+
+	if (h->priv.tcl.state != TCL_STATE_INITIAL)
+		return -1;
+
+	ret = iso14443_fsd_to_fsdi(&fsdi, h->priv.tcl.fsd);
+	if (ret < 0) {
+		DEBUGP("unable to encode FSD of %u as FSDI\n", h->priv.tcl.fsd);
+		return ret;
+	}
+
+	rats[0] = 0xe0;
+	rats[1] = (h->priv.tcl.cid & 0x0f) | ((fsdi << 4) & 0xf0);
+
+	/* transcieve (with CRC) */
+	ret = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR,
+				     rats, 2, h->priv.tcl.ats,
+				     &h->priv.tcl.ats_len, activation_fwt(h),
+				     TCL_TRANSP_F_TX_CRC);
+	if (ret < 0) {
+		DEBUGP("transcieve of rats failed\n");
+		h->priv.tcl.state = TCL_STATE_RATS_SENT;
+		/* FIXME: retransmit */
+		return ret;
+	}
+	h->priv.tcl.state = TCL_STATE_ATS_RCVD;
+
+	ret = tcl_parse_ats(h, h->priv.tcl.ats, h->priv.tcl.ats_len);
+	if (ret < 0) {
+		DEBUGP("parsing of ats failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+#define ATS_TA_DIV_2	1
+#define ATS_TA_DIV_4	2
+#define ATS_TA_DIV_8	4
+
+#define PPS_DIV_8	3
+#define PPS_DIV_4	2
+#define PPS_DIV_2	1
+#define PPS_DIV_1	0
+static unsigned char d_to_di(struct rfid_protocol_handle *h, unsigned char D)
+{
+	static char DI;
+	unsigned int speed = h->l2h->rh->reader->iso14443a.speed;
+	
+	if ((D & ATS_TA_DIV_8) && (speed & RFID_14443A_SPEED_848K))
+		DI = PPS_DIV_8;
+	else if ((D & ATS_TA_DIV_4) && (speed & RFID_14443A_SPEED_424K))
+		DI = PPS_DIV_4;
+	else if ((D & ATS_TA_DIV_2) && (speed & RFID_14443A_SPEED_212K))
+		DI = PPS_DIV_2;
+	else
+		DI = PPS_DIV_1;
+
+	return DI;
+}
+
+static unsigned int di_to_speed(unsigned char DI)
+{
+	switch (DI) {
+	case PPS_DIV_8:
+		return RFID_14443A_SPEED_848K;
+		break;
+	case PPS_DIV_4:
+		return RFID_14443A_SPEED_424K;
+		break;
+	case PPS_DIV_2:
+		return RFID_14443A_SPEED_212K;
+		break;
+	case PPS_DIV_1:
+		return RFID_14443A_SPEED_106K;
+		break;
+	}
+}
+
+/* start a PPS run (autimatically configure highest possible speed */
+static int 
+tcl_do_pps(struct rfid_protocol_handle *h)
+{
+	int ret;
+	unsigned char ppss[3];
+	unsigned char pps_response[1];
+	unsigned int rx_len = 1;
+	unsigned char Dr, Ds, DrI, DsI;
+	unsigned int speed;
+
+	if (h->priv.tcl.state != TCL_STATE_ATS_RCVD)
+		return -1;
+
+	Dr = h->priv.tcl.ta & 0x07;
+	Ds = h->priv.tcl.ta & 0x70 >> 4;
+	DEBUGP("Dr = 0x%x, Ds = 0x%x\n", Dr, Ds);
+
+	if (Dr != Ds && !(h->priv.tcl.ta & 0x80)) {
+		/* device supports different divisors for rx and tx, but not
+		 * really ?!? */
+		DEBUGP("PICC has contradictory TA, aborting PPS\n");
+		return -1;
+	};
+
+	/* ISO 14443-4:2000(E) Section 5.3. */
+
+	ppss[0] = 0xd0 | (h->priv.tcl.cid & 0x0f);
+	ppss[1] = 0x11;
+	ppss[2] = 0x00;
+
+	/* FIXME: deal with different speed for each direction */
+	DrI = d_to_di(h, Dr);
+	DsI = d_to_di(h, Ds);
+	DEBUGP("DrI = 0x%x, DsI = 0x%x\n", DrI, DsI);
+
+	ppss[2] = (ppss[2] & 0xf0) | (DrI | DsI << 2);
+
+	ret = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR,
+					ppss, 3, pps_response, &rx_len,
+					h->priv.tcl.fwt, TCL_TRANSP_F_TX_CRC);
+	if (ret < 0)
+		return ret;
+
+	if (pps_response[0] != ppss[0]) {
+		DEBUGP("PPS Response != PPSS\n");
+		return -1;
+	}
+
+	speed = di_to_speed(DrI);
+
+	ret = rfid_layer2_setopt(h->l2h, RFID_OPT_14443A_SPEED_RX,
+				 &speed, sizeof(speed));
+	if (ret < 0)
+		return ret;
+
+	ret = rfid_layer2_setopt(h->l2h, RFID_OPT_14443A_SPEED_TX,
+				 &speed, sizeof(speed));
+	if (ret < 0)
+		return ret;
+	
+	return 0;
+}
+
+
+static int
+tcl_build_prologue2(struct tcl_handle *th, 
+		    unsigned char *prlg, unsigned int *prlg_len, 
+		    unsigned char pcb)
+{
+	*prlg_len = 1;
+
+	*prlg = pcb;
+
+	if (th->toggle) {
+		/* we've sent a toggle bit last time */
+		th->toggle = 0;
+	} else {
+		/* we've not sent a toggle last time: send one */
+		th->toggle = 1;
+		*prlg |= 0x01;
+	}
+
+	if (th->flags & TCL_HANDLE_F_CID_USED) {
+		/* ISO 14443-4:2000(E) Section 7.1.1.2 */
+		*prlg |= TCL_PCB_CID_FOLLOWING;
+		(*prlg_len)++;
+		prlg[*prlg_len] = th->cid & 0x0f;
+	}
+
+	/* nad only for I-block (0xc0 == 00) */
+	if ((th->flags & TCL_HANDLE_F_NAD_USED) &&
+	    ((pcb & 0xc0) == 0x00)) {
+		/* ISO 14443-4:2000(E) Section 7.1.1.3 */
+		/* FIXME: in case of chaining only for first frame */
+		*prlg |= TCL_PCB_NAD_FOLLOWING;
+		prlg[*prlg_len] = th->nad;
+		(*prlg_len)++;
+	}
+
+	return 0;
+}
+
+static int
+tcl_build_prologue_i(struct tcl_handle *th,
+		     unsigned char *prlg, unsigned int *prlg_len)
+{
+	/* ISO 14443-4:2000(E) Section 7.1.1.1 */
+	return tcl_build_prologue2(th, prlg, prlg_len, 0x02);
+}
+
+static int
+tcl_build_prologue_r(struct tcl_handle *th,
+		     unsigned char *prlg, unsigned int *prlg_len,
+		     unsigned int nak)
+{
+	unsigned char pcb = 0xa2;
+	/* ISO 14443-4:2000(E) Section 7.1.1.1 */
+
+	if (nak)
+		pcb |= 0x10;
+
+	return tcl_build_prologue2(th, prlg, prlg_len, pcb);
+}
+
+static int
+tcl_build_prologue_s(struct tcl_handle *th,
+		     unsigned char *prlg, unsigned int *prlg_len)
+{
+	/* ISO 14443-4:2000(E) Section 7.1.1.1 */
+
+	/* the only S-block from PCD->PICC is DESELECT,
+	 * well, actually there is the S(WTX) response. */
+	return tcl_build_prologue2(th, prlg, prlg_len, 0xc2);
+}
+
+/* FIXME: WTXM implementation */
+
+static int tcl_prlg_len(struct tcl_handle *th)
+{
+	int prlg_len = 1;
+
+	if (th->flags & TCL_HANDLE_F_CID_USED)
+		prlg_len++;
+
+	if (th->flags & TCL_HANDLE_F_NAD_USED)
+		prlg_len++;
+
+	return prlg_len;
+}
+
+#define max_net_tx_framesize(x)	(x->fsc - tcl_prlg_len(x))
+
+static int
+tcl_connect(struct rfid_protocol_handle *h)
+{
+	int ret; 
+
+	if (h->priv.tcl.state != TCL_STATE_DESELECTED &&
+	    h->priv.tcl.state != TCL_STATE_INITIAL)
+		return -1;
+
+	switch (h->l2h->l2->id) {
+	case RFID_LAYER2_ISO14443A:
+		/* Start Type A T=CL Activation Sequence */
+		ret = tcl_request_ats(h);
+		if (ret < 0)
+			return ret;
+
+		/* Only do PPS if any non-default divisors supported */
+		if (h->priv.tcl.ta & 0x77) {
+			ret = tcl_do_pps(h);
+			if (ret < 0)
+				return ret;
+		}
+		break;
+	case RFID_LAYER2_ISO14443B:
+		/* initialized T=CL state from Type B Activation Data */
+		h->priv.tcl.cid = h->l2h->priv.iso14443b.cid;
+		h->priv.tcl.fsc = h->l2h->priv.iso14443b.fsc;
+		h->priv.tcl.fsd = h->l2h->priv.iso14443b.fsd;
+		h->priv.tcl.fwt = h->l2h->priv.iso14443b.fwt;
+
+		/* what about ta? sfgt? */
+
+		if (h->l2h->priv.iso14443b.flags & ISO14443B_CID_SUPPORTED)
+			h->priv.tcl.flags |= TCL_HANDLE_F_CID_SUPPORTED;
+		if (h->l2h->priv.iso14443b.flags & ISO14443B_NAD_SUPPORTED)
+			h->priv.tcl.flags |= TCL_HANDLE_F_NAD_SUPPORTED;
+
+		switch (h->l2h->priv.iso14443b.state) {
+			case ISO14443B_STATE_SELECTED:
+				h->priv.tcl.state = TCL_STATE_ATS_RCVD;
+				break;
+			case ISO14443B_STATE_ATTRIB_SENT:
+				h->priv.tcl.state = TCL_STATE_RATS_SENT;
+				break;
+		}
+
+		/* PUPI will be presented as ATS/historical bytes */
+		memcpy(h->priv.tcl.ats, h->l2h->uid, 4);
+		h->priv.tcl.ats_len = 4;
+		h->priv.tcl.historical_bytes = h->priv.tcl.ats;
+
+		break;
+	default:
+		DEBUGP("unsupported l2: %u\n", h->l2h->l2->id);
+		return -1;
+		break;
+	}
+
+	h->priv.tcl.state = TCL_STATE_ESTABLISHED;
+
+	return 0;
+}
+
+static int
+tcl_deselect(struct rfid_protocol_handle *h)
+{
+	/* ISO 14443-4:2000(E) Section 8 */
+	int ret;
+	unsigned char frame[3];		/* 3 bytes prologue, no information */
+	unsigned char rx[3];
+	unsigned int rx_len = sizeof(rx);
+	unsigned int prlg_len;
+	struct tcl_handle *th = &h->priv.tcl;
+
+	if (th->state != TCL_STATE_ESTABLISHED) {
+		/* FIXME: not sure whether deselect is possible here,
+		 * probably better send a HLTA? */
+	}
+
+	/* build DESELECT S-block */
+	ret = tcl_build_prologue_s(th, frame, &prlg_len);
+	if (ret < 0)
+		return ret;
+
+	ret = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR,
+				     frame, prlg_len, rx,
+				     &rx_len, deactivation_fwt(h),
+				     TCL_TRANSP_F_TX_CRC);
+	if (ret < 0) {
+		/* FIXME: retransmit, HLT(A|B) */
+		return ret;
+	}
+
+	th->state = TCL_STATE_DESELECTED;
+
+	return 0;
+}
+
+#define is_s_block(x) ((x & 0xc0) == 0xc0)
+#define is_r_block(x) ((x & 0xc0) == 0x80)
+#define is_i_block(x) ((x & 0xc0) == 0x00)
+
+static int
+tcl_transcieve(struct rfid_protocol_handle *h,
+		const unsigned char *tx_data, unsigned int tx_len,
+		unsigned char *rx_data, unsigned int *rx_len,
+		unsigned int timeout, unsigned int flags)
+{
+	int ret;
+	unsigned char *tx_buf, *rx_buf;
+	unsigned char *_rx_data = rx_data;
+	unsigned int _rx_len;
+	unsigned int max_rx_len = *rx_len; /* maximum number of payoload that
+					      caller has requested */
+	unsigned int prlg_len;
+	struct tcl_handle *th = &h->priv.tcl;
+
+	unsigned char *_tx;
+	unsigned int _tx_len, _timeout;
+	unsigned char wtx_resp[3];
+	unsigned char ack[10];
+	unsigned int ack_len;
+
+	if (tx_len > max_net_tx_framesize(th)) {
+		/* slow path: we need to use chaining */
+		return -1;
+	}
+
+	tx_buf = malloc(tcl_prlg_len(th) + tx_len);
+	if (!tx_buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	rx_buf = malloc(tcl_prlg_len(th) + *rx_len);
+	if (!rx_buf) {
+		ret = -ENOMEM;
+		goto out_txb;
+	}
+
+	if (tcl_build_prologue_i(th, tx_buf, &prlg_len) < 0) {
+		ret = -1;
+		goto out_rxb;
+	}
+	memcpy(tx_buf + prlg_len, tx_data, tx_len);
+
+	/* intialize to data-to-be-transferred */
+	_tx = tx_buf;
+	_tx_len = tx_len+prlg_len;
+	_timeout = th->fwt;
+	_rx_len = *rx_len;
+	*rx_len = 0;
+
+do_tx:
+	ret = rfid_layer2_transcieve(h->l2h, l2_to_frame(h->l2h->l2->id),
+				     _tx, _tx_len,
+				     rx_buf, &_rx_len, _timeout, 0);
+	DEBUGP("l2 transcieve finished\n");
+	if (ret < 0)
+		goto out_rxb;
+
+	if ((*rx_buf & 0x01) != h->priv.tcl.toggle) {
+		DEBUGP("response with wrong toggle bit\n");
+		goto out_rxb;
+	}
+
+	if (is_r_block(*rx_buf)) {
+		unsigned int txed = _tx - tx_buf;
+		DEBUGP("R-Block\n");
+		/* Handle ACK frame in case of chaining */
+		if (*rx_buf & TCL_PCB_CID_FOLLOWING) {
+			if (*(rx_buf+1) != h->priv.tcl.cid) {
+				DEBUGP("CID %u is not valid\n", *(rx_buf)+1);
+				goto out_rxb;
+			}
+		}
+		/* set up parameters for next frame in chain */
+		if (txed < tx_len) {
+			/* move tx pointer by the amount of bytes transferred
+			 * in last frame */
+			_tx += _tx_len;
+			_tx_len = (tx_len - txed);
+			if (_tx_len > max_net_tx_framesize(th)) {
+				/* not last frame in chain */
+				_tx_len = max_net_tx_framesize(th);
+			} else {
+				/* last frame in chain */
+			}
+			goto do_tx;
+		} else {
+			DEBUGP("Received ACK in response to last frame in "
+			       "chain?!? Expected I-frame.\n");
+			ret = -1;
+			goto out_rxb;
+		}
+	} else if (is_s_block(*rx_buf)) {
+		unsigned char inf;
+		unsigned int prlg_len;
+
+		DEBUGP("S-Block\n");
+		/* Handle Wait Time Extension */
+		if (*rx_buf & TCL_PCB_CID_FOLLOWING) {
+			if (_rx_len < 3) {
+				DEBUGP("S-Block with CID but short len\n");
+				ret = -1;
+				goto out_rxb;
+			}
+			if (*(rx_buf+1) != h->priv.tcl.cid) {
+				DEBUGP("CID %u is not valid\n", *(rx_buf)+1);
+				goto out_rxb;
+			}
+			inf = *(rx_buf+2);
+		} else
+			inf = *(rx_buf+1);
+
+		if ((*rx_buf & 0x30) != 0x30) {
+			DEBUGP("S-Block but not WTX?\n");
+			ret = -1;
+			goto out_rxb;
+		}
+		inf &= 0x3f;	/* only lower 6 bits code WTXM */
+		if (inf == 0 || (inf >= 60 && inf <= 63)) {
+			DEBUGP("WTXM %u is RFU!\n", inf);
+			ret = -1;
+			goto out_rxb;
+		}
+		
+		/* Acknowledge WTXM */
+		tcl_build_prologue_s(&h->priv.tcl, wtx_resp, &prlg_len);
+		/* set two bits that make this block a wtx */
+		wtx_resp[0] |= 0x30;
+		wtx_resp[prlg_len] = inf;
+		_tx = wtx_resp;
+		_tx_len = prlg_len+1;
+		_timeout = th->fwt * inf;
+
+		/* start over with next transcieve */
+		goto do_tx; /* FIXME: do transcieve locally since we use
+				totally different buffer */
+
+	} else if (is_i_block(*rx_buf)) {
+		unsigned char *inf = rx_buf+1;
+		unsigned int net_payload_len;
+		/* we're actually receiving payload data */
+
+		DEBUGP("I-Block: ");
+		if (*rx_buf & TCL_PCB_CID_FOLLOWING) {
+			if (*(rx_buf+1) != h->priv.tcl.cid) {
+				DEBUGPC("CID %u is not valid\n", *(rx_buf)+1);
+				goto out_rxb;
+			}
+			inf++;
+		}
+		if (*rx_buf & TCL_PCB_NAD_FOLLOWING) {
+			inf++;
+		}
+		net_payload_len = _rx_len - (inf - rx_buf);
+		DEBUGPC("%u bytes\n", net_payload_len);
+		memcpy(_rx_data, inf, net_payload_len);
+		/* increment the number of payload bytes that we actually
+		 * received */
+		*rx_len += net_payload_len;
+		_rx_data += net_payload_len;
+
+		if (*rx_buf & 0x10) {
+			/* we're not the last frame in the chain, continue rx */
+			DEBUGP("not the last frame in the chain, continue\n");
+			ack_len = sizeof(ack);
+			tcl_build_prologue_r(&h->priv.tcl, ack, &ack_len, 0);
+			_tx = ack;
+			_tx_len = ack_len;
+			goto do_tx;
+		}
+	}
+
+out_rxb:
+	free(rx_buf);
+out_txb:
+	free(tx_buf);
+out:
+	return ret;
+}
+
+static struct rfid_protocol_handle *
+tcl_init(struct rfid_layer2_handle *l2h)
+{
+	struct rfid_protocol_handle *th;
+	unsigned int mru = l2h->rh->ah->mru;
+
+	th = malloc(sizeof(struct rfid_protocol_handle) + mru);
+	if (!th)
+		return NULL;
+
+	/* FIXME: mru should be attribute of layer2 (in case it adds/removes
+	 * some overhead */
+	memset(th, 0, sizeof(struct rfid_protocol_handle) + mru);
+
+	/* maximum received ats length equals mru of asic/reader */
+	th->priv.tcl.state = TCL_STATE_INITIAL;
+	th->priv.tcl.ats_len = mru;
+	th->priv.tcl.toggle = 1;
+
+	th->priv.tcl.fsd = iso14443_fsd_approx(mru);
+
+	return th;
+}
+
+static int
+tcl_fini(struct rfid_protocol_handle *ph)
+{
+	free(ph);
+	return 0;
+}
+
+struct rfid_protocol rfid_protocol_tcl = {
+	.id	= RFID_PROTOCOL_TCL,
+	.name	= "ISO 14443-4 / T=CL",
+	.fn	= {
+		.init = &tcl_init,
+		.open = &tcl_connect,
+		.transcieve = &tcl_transcieve,
+		.close = &tcl_deselect,
+		.fini = &tcl_fini,
+	},
+};
diff --git a/src/rfid_protocol.c b/src/rfid_protocol.c
new file mode 100644
index 0000000..c401a2c
--- /dev/null
+++ b/src/rfid_protocol.c
@@ -0,0 +1,113 @@
+/* librfid - layer 3 protocol handler 
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_protocol.h>
+
+static struct rfid_protocol *rfid_protocol_list;
+
+struct rfid_protocol_handle *
+rfid_protocol_init(struct rfid_layer2_handle *l2h, unsigned int id)
+{
+	struct rfid_protocol *p;
+	struct rfid_protocol_handle *ph = NULL;
+
+	for (p = rfid_protocol_list; p; p = p->next) {
+		if (p->id == id) {
+			ph = p->fn.init(l2h);
+			break;
+		}
+	}
+
+	if (!ph)
+		return NULL;
+
+	ph->proto = p;
+	ph->l2h = l2h;
+
+	return ph;
+}
+
+int
+rfid_protocol_open(struct rfid_protocol_handle *ph)
+{
+	if (ph->proto->fn.open)
+		return ph->proto->fn.open(ph);
+	return 0;
+}
+
+int
+rfid_protocol_transcieve(struct rfid_protocol_handle *ph,
+			 const unsigned char *tx_buf, unsigned int len,
+			 unsigned char *rx_buf, unsigned int *rx_len,
+			 unsigned int timeout, unsigned int flags)
+{
+	return ph->proto->fn.transcieve(ph, tx_buf, len, rx_buf, rx_len,
+					timeout, flags);
+}
+
+int
+rfid_protocol_read(struct rfid_protocol_handle *ph,
+	 	   unsigned int page,
+		   unsigned char *rx_data,
+		   unsigned int *rx_len)
+{
+	if (ph->proto->fn.read)
+		return ph->proto->fn.read(ph, page, rx_data, rx_len);
+	else
+		return -EINVAL;
+}
+
+int
+rfid_protocol_write(struct rfid_protocol_handle *ph,
+	 	   unsigned int page,
+		   unsigned char *tx_data,
+		   unsigned int tx_len)
+{
+	if (ph->proto->fn.write)
+		return ph->proto->fn.write(ph, page, tx_data, tx_len);
+	else
+		return -EINVAL;
+}
+
+int rfid_protocol_fini(struct rfid_protocol_handle *ph)
+{
+	return ph->proto->fn.fini(ph);
+}
+
+int
+rfid_protocol_close(struct rfid_protocol_handle *ph)
+{
+	if (ph->proto->fn.close)
+		return ph->proto->fn.close(ph);
+	return 0;
+}
+
+int
+rfid_protocol_register(struct rfid_protocol *p)
+{
+	p->next = rfid_protocol_list;
+	rfid_protocol_list = p;
+
+	return 0;
+}
diff --git a/src/rfid_reader.c b/src/rfid_reader.c
new file mode 100644
index 0000000..9486cae
--- /dev/null
+++ b/src/rfid_reader.c
@@ -0,0 +1,65 @@
+/* librfid - core reader handling
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_reader.h>
+
+static struct rfid_reader *rfid_reader_list;
+
+struct rfid_reader_handle *
+rfid_reader_open(void *data, unsigned int id)
+{
+	struct rfid_reader *p;
+
+	for (p = rfid_reader_list; p; p = p->next)
+		if (p->id == id)
+			return p->open(data);
+
+	DEBUGP("unable to find matching reader\n");
+	return NULL;
+}
+
+int
+rfid_reader_transcieve(struct rfid_reader_handle *rh,
+			enum rfid_frametype frametype,
+			 const unsigned char *tx_buf, unsigned int len,
+			 unsigned char *rx_buf, unsigned int *rx_len,
+			 u_int64_t timeout, unsigned int flags)
+{
+	return rh->reader->transcieve(rh, frametype, tx_buf, len, rx_buf,
+				      rx_len, timeout, flags);
+}
+
+void
+rfid_reader_close(struct rfid_reader_handle *rh)
+{
+	rh->reader->close(rh);
+}
+
+int
+rfid_reader_register(struct rfid_reader *r)
+{
+	r->next = rfid_reader_list;
+	rfid_reader_list = r;
+
+	return 0;
+}
diff --git a/src/rfid_reader_cm5121.c b/src/rfid_reader_cm5121.c
new file mode 100644
index 0000000..697ac64
--- /dev/null
+++ b/src/rfid_reader_cm5121.c
@@ -0,0 +1,367 @@
+/* Omnikey CardMan 5121 specific RC632 transport layer 
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ * The 5121 is an Atmel AT89C5122 based USB CCID reader (probably the same
+ * design like the 3121).  It's CL RC632 is connected via address/data bus,
+ * not via SPI.
+ *
+ * The vendor-supplied reader firmware provides some undocumented extensions 
+ * to CCID (via PC_to_RDR_Escape) that allow access to registers and FIFO of
+ * the RC632.
+ * 
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/rfid_asic.h>
+#include <librfid/rfid_asic_rc632.h>
+#include <librfid/rfid_reader_cm5121.h>
+
+/* FIXME */
+#include "rc632.h"
+
+//#define SENDBUF_LEN	40
+#define SENDBUF_LEN	100
+#define RECVBUF_LEN	40
+
+static
+int Write1ByteToReg(struct rfid_asic_transport_handle *rath,
+		    unsigned char reg, unsigned char value)
+{
+	unsigned char sndbuf[SENDBUF_LEN];
+	unsigned char rcvbuf[RECVBUF_LEN];
+	unsigned int retlen = RECVBUF_LEN;
+
+	sndbuf[0] = 0x20;
+	sndbuf[1] = 0x00;
+	sndbuf[2] = 0x01;
+	sndbuf[3] = 0x00;
+	sndbuf[4] = 0x00;
+	sndbuf[5] = 0x00;
+	sndbuf[6] = reg;
+	sndbuf[7] = value;
+
+	DEBUGP("reg=0x%02x, val=%02x: ", reg, value);
+
+	if (PC_to_RDR_Escape(rath->data, sndbuf, 8, rcvbuf, 
+			     &retlen) == 0) {
+		DEBUGPC("OK\n");
+		return 0;
+	}
+
+	DEBUGPC("ERROR\n");
+	return -1;
+}
+
+static int Read1ByteFromReg(struct rfid_asic_transport_handle *rath,
+			    unsigned char reg,
+			    unsigned char *value)
+{
+	unsigned char sndbuf[SENDBUF_LEN];
+	unsigned char recvbuf[RECVBUF_LEN];
+	unsigned int retlen = sizeof(recvbuf);
+
+	sndbuf[0] = 0x20;
+	sndbuf[1] = 0x00;
+	sndbuf[2] = 0x00;
+	sndbuf[3] = 0x00;
+	sndbuf[4] = 0x01;
+	sndbuf[5] = 0x00;
+	sndbuf[6] = reg;
+
+	if (PC_to_RDR_Escape(rath->data, sndbuf, 7, recvbuf, 
+			     &retlen) == 0) {
+		*value = recvbuf[1];
+		DEBUGP("reg=0x%02x, val=%02x: ", reg, *value);
+		DEBUGPC("OK\n");
+		return 0;
+	}
+
+	DEBUGPC("ERROR\n");
+	return -1;
+}
+
+static int ReadNBytesFromFIFO(struct rfid_asic_transport_handle *rath,
+			      unsigned char num_bytes,
+			      unsigned char *buf)
+{
+	unsigned char sndbuf[SENDBUF_LEN];
+	unsigned char recvbuf[0x7f];
+	unsigned int retlen = sizeof(recvbuf);
+
+	sndbuf[0] = 0x20;
+	sndbuf[1] = 0x00;
+	sndbuf[2] = 0x00;
+	sndbuf[3] = 0x00;
+	sndbuf[4] = num_bytes;
+	sndbuf[5] = 0x00;
+	sndbuf[6] = 0x02;
+
+	DEBUGP("num_bytes=%u: ", num_bytes);
+	if (PC_to_RDR_Escape(rath->data, sndbuf, 7, recvbuf, &retlen) == 0) {
+		DEBUGPC("%u [%s]\n", retlen,
+			rfid_hexdump(recvbuf+1, num_bytes));
+		memcpy(buf, recvbuf+1, num_bytes); // len == 0x7f
+		return 0;
+	}
+
+	DEBUGPC("ERROR\n");
+	return -1;
+}
+
+static int WriteNBytesToFIFO(struct rfid_asic_transport_handle *rath,
+			     unsigned char len,
+			     const unsigned char *bytes,
+			     unsigned char flags)
+{
+	unsigned char sndbuf[SENDBUF_LEN];
+	unsigned char recvbuf[0x7f];
+	unsigned int retlen = sizeof(recvbuf);
+
+	sndbuf[0] = 0x20;
+	sndbuf[1] = 0x00;
+	sndbuf[2] = len;
+	sndbuf[3] = 0x00;
+	sndbuf[4] = 0x00;
+	sndbuf[5] = flags;
+	sndbuf[6] = 0x02;
+
+	DEBUGP("%u [%s]: ", len, rfid_hexdump(bytes, len));
+
+	memcpy(sndbuf+7, bytes, len);
+
+	if (PC_to_RDR_Escape(rath->data, sndbuf, len+7, recvbuf, &retlen) == 0) {
+		DEBUGPC("OK (%u [%s])\n", retlen, rfid_hexdump(recvbuf, retlen));
+		return 0;
+	}
+
+	DEBUGPC("ERROR\n");
+	return -1;
+}
+
+#if 0
+static int TestFIFO(struct rc632_handle *handle)
+{
+	unsigned char sndbuf[60]; // 0x3c
+
+	// FIXME: repne stosd, call
+
+	memset(sndbuf, 0, sizeof(sndbuf));
+
+	if (WriteNBytesToFIFO(handle, sizeof(sndbuf), sndbuf, 0) < 0)
+		return -1;
+
+	return ReadNBytesFromFIFO(handle, sizeof(sndbuf), sndbuf);
+}
+#endif
+
+static int cm5121_transcieve(struct rfid_reader_handle *rh,
+			     enum rfid_frametype frametype,
+			     const unsigned char *tx_data, unsigned int tx_len,
+			     unsigned char *rx_data, unsigned int *rx_len,
+			     u_int64_t timeout, unsigned int flags)
+{
+	return rh->ah->asic->priv.rc632.fn.transcieve(rh->ah, frametype,
+						tx_data, tx_len, rx_data,
+						rx_len, timeout, flags);
+}
+
+static int cm5121_transcieve_sf(struct rfid_reader_handle *rh,
+			       unsigned char cmd, struct iso14443a_atqa *atqa)
+{
+	return rh->ah->asic->priv.rc632.fn.iso14443a.transcieve_sf(rh->ah,
+								   cmd,
+								   atqa);
+}
+
+static int
+cm5121_transcieve_acf(struct rfid_reader_handle *rh,
+		      struct iso14443a_anticol_cmd *cmd,
+		      unsigned int *bit_of_col)
+{
+	return rh->ah->asic->priv.rc632.fn.iso14443a.transcieve_acf(rh->ah,
+							 cmd, bit_of_col);
+}
+
+static int
+cm5121_14443a_init(struct rfid_reader_handle *rh)
+{
+	return rh->ah->asic->priv.rc632.fn.iso14443a.init(rh->ah);
+}
+
+static int
+cm5121_14443a_set_speed(struct rfid_reader_handle *rh, 
+			unsigned int tx,
+			unsigned int speed)
+{
+	u_int8_t rate;
+	
+	DEBUGP("setting rate: ");
+	switch (speed) {
+	case RFID_14443A_SPEED_106K:
+		rate = 0x00;
+		DEBUGPC("106K\n");
+		break;
+	case RFID_14443A_SPEED_212K:
+		rate = 0x01;
+		DEBUGPC("212K\n");
+		break;
+	case RFID_14443A_SPEED_424K:
+		rate = 0x02;
+		DEBUGPC("424K\n");
+		break;
+	case RFID_14443A_SPEED_848K:
+		rate = 0x03;
+		DEBUGPC("848K\n");
+		break;
+	default:
+		return -EINVAL;
+		break;
+	}
+	return rh->ah->asic->priv.rc632.fn.iso14443a.set_speed(rh->ah,
+								tx, rate);
+}
+
+static int
+cm5121_14443b_init(struct rfid_reader_handle *rh)
+{
+	return rh->ah->asic->priv.rc632.fn.iso14443b.init(rh->ah);
+}
+
+static int
+cm5121_15693_init(struct rfid_reader_handle *rh)
+{
+	return rh->ah->asic->priv.rc632.fn.iso15693.init(rh->ah);
+}
+
+static int
+cm5121_mifare_setkey(struct rfid_reader_handle *rh, const u_int8_t *key)
+{
+	return rh->ah->asic->priv.rc632.fn.mifare_classic.setkey(rh->ah, key);
+}
+
+static int
+cm5121_mifare_auth(struct rfid_reader_handle *rh, u_int8_t cmd, 
+		   u_int32_t serno, u_int8_t block)
+{
+	return rh->ah->asic->priv.rc632.fn.mifare_classic.auth(rh->ah, 
+							cmd, serno, block);
+}
+
+struct rfid_asic_transport cm5121_ccid = {
+	.name = "CM5121 OpenCT",
+	.priv.rc632 = {
+		.fn = {
+			.reg_write 	= &Write1ByteToReg,
+			.reg_read 	= &Read1ByteFromReg,
+			.fifo_write	= &WriteNBytesToFIFO,
+			.fifo_read	= &ReadNBytesFromFIFO,
+		},
+	},
+};
+
+static int cm5121_enable_rc632(struct rfid_asic_transport_handle *rath)
+{
+	unsigned char tx_buf[1] = { 0x01 };	
+	unsigned char rx_buf[64];
+	unsigned int rx_len = sizeof(rx_buf);
+
+	PC_to_RDR_Escape(rath->data, tx_buf, 1, rx_buf, &rx_len);
+	printf("received %u bytes from 01 command\n", rx_len);
+
+	return 0;
+}
+
+static struct rfid_reader_handle *
+cm5121_open(void *data)
+{
+	struct rfid_reader_handle *rh;
+	struct rfid_asic_transport_handle *rath;
+
+	rh = malloc(sizeof(*rh));
+	if (!rh)
+		return NULL;
+	memset(rh, 0, sizeof(*rh));
+
+	rath = malloc(sizeof(*rath));
+	if (!rath)
+		goto out_rh;
+	memset(rath, 0, sizeof(*rath));
+
+	rath->rat = &cm5121_ccid;
+	rh->reader = &rfid_reader_cm5121;
+
+	if (cm5121_source_init(rath) < 0)
+		goto out_rath;
+
+	if (cm5121_enable_rc632(rath) < 0)
+		goto out_rath;
+
+	rh->ah = rc632_open(rath);
+	if (!rh->ah) 
+		goto out_rath;
+
+	DEBUGP("returning %p\n", rh);
+	return rh;
+
+out_rath:
+	free(rath);
+out_rh:
+	free(rh);
+
+	return NULL;
+}
+
+static void
+cm5121_close(struct rfid_reader_handle *rh)
+{
+	struct rfid_asic_transport_handle *rath = rh->ah->rath;
+	rc632_close(rh->ah);
+	free(rath);
+	free(rh);
+}
+
+struct rfid_reader rfid_reader_cm5121 = {
+	.name 	= "Omnikey CardMan 5121 RFID",
+	.open = &cm5121_open,
+	.close = &cm5121_close,
+	.transcieve = &cm5121_transcieve,
+	.iso14443a = {
+		.init = &cm5121_14443a_init,
+		.transcieve_sf = &cm5121_transcieve_sf,
+		.transcieve_acf = &cm5121_transcieve_acf,
+		.speed = RFID_14443A_SPEED_106K | RFID_14443A_SPEED_212K |
+			 RFID_14443A_SPEED_424K, //| RFID_14443A_SPEED_848K,
+		.set_speed = &cm5121_14443a_set_speed,
+	},
+	.iso14443b = {
+		.init = &cm5121_14443b_init,
+	},
+	.mifare_classic = {
+		.setkey = &cm5121_mifare_setkey,
+		.auth = &cm5121_mifare_auth,
+	},
+};
+
+
diff --git a/src/rfid_reader_cm5121_ccid_direct.c b/src/rfid_reader_cm5121_ccid_direct.c
new file mode 100644
index 0000000..3161059
--- /dev/null
+++ b/src/rfid_reader_cm5121_ccid_direct.c
@@ -0,0 +1,36 @@
+/* CM5121 backend for 'internal' CCID driver */
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <librfid/rfid_asic.h>
+
+#include "ccid/ccid-driver.h"
+
+/* this is the sole function required by rfid_reader_cm5121.c */
+int 
+PC_to_RDR_Escape(void *handle, 
+		 const unsigned char *tx_buf, unsigned int tx_len,
+		 unsigned char *rx_buf, unsigned int *rx_len)
+{
+	int rc;
+        ccid_driver_t ch = handle;
+        size_t maxrxlen = *rx_len;
+
+        rc = ccid_transceive_escape (ch, tx_buf, tx_len,
+                                     rx_buf, maxrxlen, rx_len);
+
+	return rc;
+}
+
+int cm5121_source_init(struct rfid_asic_transport_handle *rath)
+{
+	int rc;
+
+        rc = ccid_open_reader(&rath->data, NULL);
+        if (rc) {
+                fprintf (stderr, "failed to open CCID reader: %#x\n", rc);
+                return -1;
+        }
+	return 0;
+}
diff --git a/src/rfid_reader_cm5121_openct.c b/src/rfid_reader_cm5121_openct.c
new file mode 100644
index 0000000..4bc879c
--- /dev/null
+++ b/src/rfid_reader_cm5121_openct.c
@@ -0,0 +1,59 @@
+/* CM5121 backend for OpenCT virtual slot */
+
+#include <stdio.h>
+
+#include <librfid/rfid_asic.h>
+#include <openct/openct.h>
+
+/* FIXME: get rid of this global crap.  In fact this needs to become part of
+ * struct rfid_reader_handle  */
+static ct_lock_handle lock;
+static int slot = 1;
+
+/* this is the sole function required by rfid_reader_cm5121.c */
+int 
+PC_to_RDR_Escape(void *handle, 
+		 const unsigned char *tx_buf, unsigned int tx_len,
+		 unsigned char *rx_buf, unsigned int *rx_len)
+{
+	int rc;
+	ct_handle *h = (ct_handle *) handle;
+
+	rc = ct_card_transact(h, 1, tx_buf, tx_len, rx_buf, *rx_len);
+	if (rc >= 0) {
+		*rx_len = rc;
+		return 0;
+	}
+
+	return rc;
+}
+
+
+int cm5121_source_init(struct rfid_asic_transport_handle *rath)
+{
+	struct ct_handle *h;
+	int rc;
+	unsigned char atr[64];
+
+	h = ct_reader_connect(0);
+	if (!h)
+		return -1;
+
+	printf("acquiring card lock\n");
+	rc = ct_card_lock(h, slot, IFD_LOCK_EXCLUSIVE, &lock);
+	if (rc < 0) {
+		fprintf(stderr, "error, no card lock\n");
+		return -1;
+	}
+
+	rc = ct_card_reset(h, slot, atr, sizeof(atr));
+	if (rc < 0) {
+		fprintf(stderr, "error, can't reset virtual card\n");
+		return -1;
+	}
+
+	rath->data = h;
+
+	return 0;
+}
+
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644
index 0000000..cddde17
--- /dev/null
+++ b/utils/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+
+bin_PROGRAMS = openct-escape
+
+openct_escape_SOURCES = openct-escape.c
+openct_escape_LDADD = ../src/librfid.la
+openct_escape_LDFLAGS = -dynamic
+
diff --git a/utils/openct-escape.c b/utils/openct-escape.c
new file mode 100644
index 0000000..8f087b2
--- /dev/null
+++ b/utils/openct-escape.c
@@ -0,0 +1,356 @@
+/*                                                 -*- linux-c -*-
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 
+ *  as published by the Free Software Foundation
+ *
+ *  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
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_protocol.h>
+
+#include <librfid/rfid_protocol_mifare_classic.h>
+#include <librfid/rfid_protocol_mifare_ul.h>
+
+static const char *
+hexdump(const void *data, unsigned int len)
+{
+	static char string[1024];
+	unsigned char *d = (unsigned char *) data;
+	unsigned int i, left;
+
+	string[0] = '\0';
+	left = sizeof(string);
+	for (i = 0; len--; i += 3) {
+		if (i >= sizeof(string) -4)
+			break;
+		snprintf(string+i, 4, " %02x", *d++);
+	}
+	return string;
+}
+
+static struct rfid_reader_handle *rh;
+static struct rfid_layer2_handle *l2h;
+static struct rfid_protocol_handle *ph;
+
+static int init()
+{
+	unsigned char buf[0x3f];
+	int rc;
+
+	printf("initializing librfid\n");
+	rfid_init();
+
+	printf("opening reader handle\n");
+	rh = rfid_reader_open(NULL, RFID_READER_CM5121);
+	if (!rh) {
+		fprintf(stderr, "error, no cm5121 handle\n");
+		return -1;
+	}
+
+	printf("opening layer2 handle\n");
+	l2h = rfid_layer2_init(rh, RFID_LAYER2_ISO14443A);
+	//l2h = rfid_layer2_init(rh, RFID_LAYER2_ISO14443B);
+	if (!l2h) {
+		fprintf(stderr, "error during iso14443a_init\n");
+		return -1;
+	}
+
+	//rc632_register_dump(rh->ah, buf);
+
+	printf("running layer2 anticol\n");
+	rc = rfid_layer2_open(l2h);
+	if (rc < 0) {
+		fprintf(stderr, "error during layer2_open\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int l3(int protocol)
+{
+	printf("running layer3 (ats)\n");
+	ph = rfid_protocol_init(l2h, protocol);
+	if (!ph) {
+		fprintf(stderr, "error during protocol_init\n");
+		return -1;
+	}
+	if (rfid_protocol_open(ph) < 0) {
+		fprintf(stderr, "error during protocol_open\n");
+		return -1;
+	}
+
+	printf("we now have layer3 up and running\n");
+
+	return 0;
+}
+
+static int select_mf(void)
+{
+	unsigned char cmd[] = { 0x00, 0xa4, 0x00, 0x00, 0x02, 0x3f, 0x00, 0x00 };
+	unsigned char ret[256];
+	unsigned int rlen = sizeof(ret);
+
+	int rv;
+
+	rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), ret, &rlen, 0, 0);
+	if (rv < 0)
+		return rv;
+
+	printf("%d: [%s]\n", rlen, hexdump(ret, rlen));
+
+	return 0;
+}
+
+
+static int iso7816_get_challenge(unsigned char len)
+{
+	unsigned char cmd[] = { 0x00, 0x84, 0x00, 0x00, 0x08 };
+	unsigned char ret[256];
+	unsigned int rlen = sizeof(ret);
+
+	cmd[4] = len;
+
+	int rv;
+
+	rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), ret, &rlen, 0, 0);
+	if (rv < 0)
+		return rv;
+
+	printf("%d: [%s]\n", rlen, hexdump(ret, rlen));
+
+	return 0;
+}
+
+int
+iso7816_select_application(void)
+{
+	unsigned char cmd[] = { 0x00, 0xa4, 0x04, 0x0c, 0x07,
+		       0xa0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01 };
+	unsigned char resp[7];
+	unsigned int rlen = sizeof(resp);
+
+	int rv;
+
+	rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), resp, &rlen, 0, 0);
+	if (rv < 0)
+		return rv;
+
+	/* FIXME: parse response */
+	printf("%s\n", hexdump(resp, rlen));
+
+	return 0;
+}
+
+int
+iso7816_select_ef(u_int16_t fid)
+{
+	unsigned char cmd[7] = { 0x00, 0xa4, 0x02, 0x0c, 0x02, 0x00, 0x00 };
+	unsigned char resp[7];
+	unsigned int rlen = sizeof(resp);
+
+	int rv;
+
+	cmd[5] = (fid >> 8) & 0xff;
+	cmd[6] = fid & 0xff;
+
+	rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), resp, &rlen, 0, 0);
+	if (rv < 0)
+		return rv;
+
+	/* FIXME: parse response */
+	printf("%s\n", hexdump(resp, rlen));
+
+	return 0;
+}
+
+int
+iso7816_read_binary(unsigned char *buf, unsigned int *len)
+{
+	unsigned char cmd[] = { 0x00, 0xb0, 0x00, 0x00, 0x00 };
+	unsigned char resp[256];
+	unsigned int rlen = sizeof(resp);
+	
+	int rv;
+
+	rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), resp, &rlen, 0, 0);
+	if (rv < 0)
+		return rv;
+
+	/* FIXME: parse response, determine whether we need additional reads */
+
+	/* FIXME: copy 'len' number of response bytes to 'buf' */
+	return 0;
+}
+
+/* wrapper function around SELECT EF and READ BINARY */
+int
+iso7816_read_ef(u_int16_t fid, unsigned char *buf, unsigned int *len)
+{
+	int rv;
+
+	rv = iso7816_select_ef(fid);
+	if (rv < 0)
+		return rv;
+
+	return iso7816_read_binary(buf, len);
+}
+
+/* mifare ultralight helpers */
+int
+mifare_ulight_write(struct rfid_protocol_handle *ph)
+{
+	unsigned char buf[4] = { 0xa1, 0xa2, 0xa3, 0xa4 };
+
+	return rfid_protocol_write(ph, 10, buf, 4);
+}
+
+int
+mifare_ulight_blank(struct rfid_protocol_handle *ph)
+{
+	unsigned char buf[4] = { 0x00, 0x00, 0x00, 0x00 };
+	int i, ret;
+
+	for (i = 4; i <= MIFARE_UL_PAGE_MAX; i++) {
+		ret = rfid_protocol_write(ph, i, buf, 4);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static int
+mifare_ulight_read(struct rfid_protocol_handle *ph)
+{
+	unsigned char buf[20];
+	unsigned int len = sizeof(buf);
+	int ret;
+	int i;
+
+	for (i = 0; i <= MIFARE_UL_PAGE_MAX; i++) {
+		ret = rfid_protocol_read(ph, i, buf, &len);
+		if (ret < 0)
+			return ret;
+
+		printf("Page 0x%x: %s\n", i, hexdump(buf, 4));
+	}
+	return 0;
+}
+
+/* mifare classic helpers */
+static int
+mifare_classic_read(struct rfid_protocol_handle *ph)
+{
+	unsigned char buf[20];
+	unsigned int len = sizeof(buf);
+	int ret;
+	int i;
+
+	for (i = 0; i <= MIFARE_CL_PAGE_MAX; i++) {
+		ret = rfid_protocol_read(ph, i, buf, &len);
+		if (ret < 0)
+			return ret;
+
+		printf("Page 0x%x: %s\n", i, hexdump(buf, len));
+	}
+	return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+	int rc;
+	char buf[0x40];
+	int i, protocol;
+
+#if 0
+        if (argc) {
+                argc--;
+                argv++;
+        }
+        
+        while (argc) {
+                if ( !strcmp (*argv, "--list")) {
+                        char *p;
+                        p = ccid_get_reader_list ();
+                        if (!p)
+                                return 1;
+                        fputs (p, stderr);
+                        free (p);
+                        return 0;
+                }
+                else if ( !strcmp (*argv, "--debug")) {
+                        ccid_set_debug_level (ccid_set_debug_level (-1) + 1);
+                        argc--; argv++;
+                }
+                else
+                        break;
+        }
+#endif
+
+	if (init() < 0)
+		exit(1);
+
+	//protocol = RFID_PROTOCOL_MIFARE_UL;
+	//protocol = RFID_PROTOCOL_MIFARE_CLASSIC;
+	protocol = RFID_PROTOCOL_TCL;
+
+	if (l3(protocol) < 0)
+		exit(1);
+
+	switch (protocol) {
+	case RFID_PROTOCOL_TCL:
+		/* we've established T=CL at this point */
+		select_mf();
+
+		iso7816_select_application();
+		iso7816_select_ef(0x011e);
+		iso7816_select_ef(0x0101);
+#if 1
+		for (i = 0; i < 4; i++)
+			iso7816_get_challenge(0x06);
+#endif
+		break;
+	case RFID_PROTOCOL_MIFARE_UL:
+		mifare_ulight_read(ph);
+#if 0
+		mifare_ulight_blank(ph);
+		mifare_ulight_write(ph);
+		mifare_ulight_read(ph);
+#endif
+		break;
+	case RFID_PROTOCOL_MIFARE_CLASSIC:
+		rc = mfcl_set_key(ph, MIFARE_CL_KEYA_DEFAULT_INFINEON);
+		if (rc < 0) {
+			printf("key format error\n");
+			exit(1);
+		}
+		rc = mfcl_auth(ph, RFID_CMD_MIFARE_AUTH1A, 0);
+		if (rc < 0) {
+			printf("mifare auth error\n");
+			exit(1);
+		} else 
+			printf("mifare authe succeeded!\n");
+		mifare_classic_read(ph);
+		break;
+	}
+
+	rfid_reader_close(rh);
+	
+	exit(0);
+}