initial checkin of harald welte's original librfid project
authorhackbard <hackbard>
Thu, 19 Jan 2006 23:21:46 +0000 (23:21 +0000)
committerhackbard <hackbard>
Thu, 19 Jan 2006 23:21:46 +0000 (23:21 +0000)
48 files changed:
COPYING [new file with mode: 0644]
LICENSING [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
VERY_IMPORTANT_NOTE [new file with mode: 0644]
autogen.sh [new file with mode: 0644]
ccid/ccid-driver.c [new file with mode: 0644]
ccid/ccid-driver.h [new file with mode: 0644]
configure.in [new file with mode: 0644]
include/Makefile.am [new file with mode: 0644]
include/librfid/Makefile.am [new file with mode: 0644]
include/librfid/rfid.h [new file with mode: 0644]
include/librfid/rfid_asic.h [new file with mode: 0644]
include/librfid/rfid_asic_rc632.h [new file with mode: 0644]
include/librfid/rfid_layer2.h [new file with mode: 0644]
include/librfid/rfid_layer2_iso14443a.h [new file with mode: 0644]
include/librfid/rfid_layer2_iso14443b.h [new file with mode: 0644]
include/librfid/rfid_layer2_iso15693.h [new file with mode: 0644]
include/librfid/rfid_protocol.h [new file with mode: 0644]
include/librfid/rfid_protocol_mifare_classic.h [new file with mode: 0644]
include/librfid/rfid_protocol_mifare_ul.h [new file with mode: 0644]
include/librfid/rfid_protocol_tcl.h [new file with mode: 0644]
include/librfid/rfid_reader.h [new file with mode: 0644]
include/librfid/rfid_reader_cm5121.h [new file with mode: 0644]
pegoda/Makefile [new file with mode: 0644]
pegoda/pegoda.c [new file with mode: 0644]
pegoda/pegoda.h [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/rc632.h [new file with mode: 0644]
src/rfid.c [new file with mode: 0644]
src/rfid_asic_rc632.c [new file with mode: 0644]
src/rfid_iso14443_common.c [new file with mode: 0644]
src/rfid_iso14443_common.h [new file with mode: 0644]
src/rfid_layer2.c [new file with mode: 0644]
src/rfid_layer2_iso14443a.c [new file with mode: 0644]
src/rfid_layer2_iso14443b.c [new file with mode: 0644]
src/rfid_layer2_iso15693.c [new file with mode: 0644]
src/rfid_proto_mifare_classic.c [new file with mode: 0644]
src/rfid_proto_mifare_ul.c [new file with mode: 0644]
src/rfid_proto_tcl.c [new file with mode: 0644]
src/rfid_protocol.c [new file with mode: 0644]
src/rfid_reader.c [new file with mode: 0644]
src/rfid_reader_cm5121.c [new file with mode: 0644]
src/rfid_reader_cm5121_ccid_direct.c [new file with mode: 0644]
src/rfid_reader_cm5121_openct.c [new file with mode: 0644]
utils/Makefile.am [new file with mode: 0644]
utils/openct-escape.c [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+           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 (file)
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 (file)
index 0000000..69140e2
--- /dev/null
@@ -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 (file)
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 (file)
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 (file)
index 0000000..b1c293a
--- /dev/null
@@ -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 (file)
index 0000000..ccce4f0
--- /dev/null
@@ -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 (file)
index 0000000..fce6d0d
--- /dev/null
@@ -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 (file)
index 0000000..34c27cc
--- /dev/null
@@ -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 (file)
index 0000000..1125175
--- /dev/null
@@ -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 (file)
index 0000000..dfaa277
--- /dev/null
@@ -0,0 +1,2 @@
+
+SUBDIRS = librfid
diff --git a/include/librfid/Makefile.am b/include/librfid/Makefile.am
new file mode 100644 (file)
index 0000000..59ce8cb
--- /dev/null
@@ -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 (file)
index 0000000..76e86e3
--- /dev/null
@@ -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 (file)
index 0000000..3686a7c
--- /dev/null
@@ -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 (file)
index 0000000..893e73b
--- /dev/null
@@ -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 (file)
index 0000000..4622a02
--- /dev/null
@@ -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 (file)
index 0000000..50a6f43
--- /dev/null
@@ -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 (file)
index 0000000..5d6d979
--- /dev/null
@@ -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 (file)
index 0000000..ea7f87a
--- /dev/null
@@ -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 (file)
index 0000000..65bda4c
--- /dev/null
@@ -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 (file)
index 0000000..e6b2400
--- /dev/null
@@ -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 (file)
index 0000000..cc93b6b
--- /dev/null
@@ -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 (file)
index 0000000..f754ad9
--- /dev/null
@@ -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 (file)
index 0000000..3581cc1
--- /dev/null
@@ -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 (file)
index 0000000..8d9a312
--- /dev/null
@@ -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 (file)
index 0000000..7310022
--- /dev/null
@@ -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 (file)
index 0000000..2eaa61e
--- /dev/null
@@ -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 (file)
index 0000000..236dc0a
--- /dev/null
@@ -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 (file)
index 0000000..dbc608f
--- /dev/null
@@ -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 (file)
index 0000000..977b0ee
--- /dev/null
@@ -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 (file)
index 0000000..6fba46a
--- /dev/null
@@ -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 (file)
index 0000000..0c38052
--- /dev/null
@@ -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 (file)
index 0000000..38fed6b
--- /dev/null
@@ -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 (file)
index 0000000..848d983
--- /dev/null
@@ -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 (file)
index 0000000..8d1544a
--- /dev/null
@@ -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 (file)
index 0000000..da2628f
--- /dev/null
@@ -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 (file)
index 0000000..7c92562
--- /dev/null
@@ -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 (file)
index 0000000..1a93a19
--- /dev/null
@@ -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 (file)
index 0000000..e2ee80c
--- /dev/null
@@ -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 (file)
index 0000000..747f38c
--- /dev/null
@@ -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 (file)
index 0000000..901e42c
--- /dev/null
@@ -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 (file)
index 0000000..c401a2c
--- /dev/null
@@ -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 (file)
index 0000000..9486cae
--- /dev/null
@@ -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 (file)
index 0000000..697ac64
--- /dev/null
@@ -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&