Import CIS tools from pcmcia-cs 3.2.8
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..bf9c3e7
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,23 @@
+Copyright (C) 1998, 1999, 2000 David A. Hinds
+
+Unless otherwise indicated, this code is distributed under version 1.1
+of the Mozilla Public License ("MPL"), included in the LICENSE file.
+
+Alternatively, these files may be used under the terms of the GNU
+Public License version 2 (the "GPL"), in which case the provisions of
+the GPL are applicable instead of the above.  If you wish to allow the
+use of your version of these files only under the terms of the GPL and
+not to allow others to use your version of these files under the MPL,
+indicate your decision by deleting the provisions above and replace
+them with the notice and other provisions required by the GPL.  If you
+do not delete the provisions above, a recipient may use your version
+of these files under either the MPL or the GPL.
+
+Some of the client drivers (nmclan_cs.c, 3c589_cs.c, 3c574_cs.c,
+3c575_cb.c, ibmtr_cs.c, pcnet_cs.c, smc91c92_cs.c, fmvj18x_cs.c,
+wavelan_cs.c, wvlan_cs.c, netwave_cs.c, xirc2ps_cs.c, serial_cb.c)
+contain code written by others, subject to more restrictive (GPL)
+licensing requirements.
+
+	-- David Hinds
+	   dahinds@users.sourceforge.net
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8d23a4c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,563 @@
+                           MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ----------------
+
+1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. ''Contributor'' means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. ''Contributor Version'' means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. ''Covered Code'' means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. ''Electronic Distribution Mechanism'' means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. ''Executable'' means Covered Code in any form other than Source
+     Code.
+
+     1.6. ''Initial Developer'' means the individual or entity identified as
+     the Initial Developer in the Source Code notice required by Exhibit A.
+
+     1.7. ''Larger Work'' means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. ''License'' means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. ''Modifications'' means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+     
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. ''Original Code'' means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this License
+     is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process, and
+     apparatus claims, in any patent Licensable by grantor.
+
+     1.11. ''Source Code'' means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus any
+     associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You'' (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You'' includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control'' means (a) the power, direct or indirect, to
+     cause the direction or management of such entity, whether by contract
+     or otherwise, or (b) ownership of more than fifty percent (50%) of the
+     outstanding shares or beneficial ownership of such entity.
+
+2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+     
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or selling
+          of Original Code, to make, have made, use, practice, sell, and
+          offer for sale, and/or otherwise dispose of the Original Code (or
+          portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes Original
+          Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code and/or
+          as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or selling
+          of  Modifications made by that Contributor either alone and/or in
+          combination with its Contributor Version (or portions of such
+          combination), to make, use, sell, offer for sale, have made,
+          and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be distributed
+     only under the terms of this License or a future version of this
+     License released under Section 6.1, and You must include a copy of this
+     License with every copy of the Source Code You distribute. You may not
+     offer or impose any terms on any Source Code version that alters or
+     restricts the applicable version of this License or the recipients'
+     rights hereunder. However, You may include an additional document
+     offering the additional rights described in Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that the
+     Modification is derived, directly or indirectly, from Original Code
+     provided by the Initial Developer and including the name of the Initial
+     Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+     
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2, Contributor
+          must include a text file with the Source Code distribution titled
+          "LEGAL'' which describes the claim and the party making the claim
+          in sufficient detail that a recipient will know whom to contact.
+          If Contributor obtains such knowledge after the Modification is
+          made available as described in Section 3.2, Contributor shall
+          promptly modify the LEGAL file in all copies Contributor makes
+          available thereafter and shall take other steps (such as notifying
+          appropriate mailing lists or newsgroups) reasonably calculated to
+          inform those who received the Covered Code that new knowledge has
+          been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+          (c) Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely to
+     look for such a notice.  If You created one or more Modification(s) You
+     may add your name as a Contributor to the notice described in Exhibit
+     A.  You must also duplicate this License in any documentation for the
+     Source Code where You describe recipients' rights or ownership rights
+     relating to Covered Code.  You may choose to offer, and to charge a fee
+     for, warranty, support, indemnity or liability obligations to one or
+     more recipients of Covered Code. However, You may do so only on Your
+     own behalf, and not on behalf of the Initial Developer or any
+     Contributor. You must make it absolutely clear than any such warranty,
+     support, indemnity or liability obligation is offered by You alone, and
+     You hereby agree to indemnify the Initial Developer and every
+     Contributor for any liability incurred by the Initial Developer or such
+     Contributor as a result of warranty, support, indemnity or liability
+     terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of the
+     Covered Code is available under the terms of this License, including a
+     description of how and where You have fulfilled the obligations of
+     Section 3.2. The notice must be conspicuously included in any notice in
+     an Executable version, related documentation or collateral in which You
+     describe recipients' rights relating to the Covered Code. You may
+     distribute the Executable version of Covered Code or ownership rights
+     under a license of Your choice, which may contain terms different from
+     this License, provided that You are in compliance with the terms of
+     this License and that the license for the Executable version does not
+     attempt to limit or alter the recipient's rights in the Source Code
+     version from the rights set forth in this License. If You distribute
+     the Executable version under a different license You must make it
+     absolutely clear that any terms which differ from this License are
+     offered by You alone, not by the Initial Developer or any Contributor.
+     You hereby agree to indemnify the Initial Developer and every
+     Contributor for any liability incurred by the Initial Developer or such
+     Contributor as a result of any such terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to statute,
+     judicial order, or regulation then You must: (a) comply with the terms
+     of this License to the maximum extent possible; and (b) describe the
+     limitations and the code they affect. Such description must be included
+     in the LEGAL file described in Section 3.4 and must be included with
+     all distributions of the Source Code. Except to the extent prohibited
+     by statute or regulation, such description must be sufficiently
+     detailed for a recipient of ordinary skill to be able to understand it.
+
+5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation (''Netscape'') may publish revised
+     and/or new versions of the License from time to time. Each version will
+     be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that the
+     phrases ''Mozilla'', ''MOZILLAPL'', ''MOZPL'', ''Netscape'', "MPL",
+     ''NPL'' or any confusingly similar phrase do not appear in your license
+     (except to note that your license differs from this License) and (b)
+     otherwise make it clear that Your version of the license contains terms
+     which differ from the Mozilla Public License and Netscape Public
+     License. (Filling in the name of the Initial Developer, Original Code
+     or Contributor in the notice described in Exhibit A shall not of
+     themselves be deemed to be modifications of this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS'' BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom You
+     file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License shall,
+     upon 60 days notice from Participant terminate prospectively, unless if
+     within 60 days after receipt of notice You either: (i)  agree in
+     writing to pay Participant a mutually agreeable reasonable royalty for
+     Your past and future use of Modifications made by such Participant, or
+     (ii) withdraw Your litigation claim with respect to the Contributor
+     Version against such Participant.  If within 60 days of notice, a
+     reasonable royalty and payment arrangement are not mutually agreed upon
+     in writing by the parties or the litigation claim is not withdrawn, the
+     rights granted by Participant to You under Sections 2.1 and/or 2.2
+     automatically terminate at the expiration of the 60 day notice period
+     specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b) and
+     2.2(b) are revoked effective as of the date You first made, used, sold,
+     distributed, or had made, Modifications made by that Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,  all
+     end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY
+     INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS
+     EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a ''commercial item,'' as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of ''commercial computer
+     software'' and ''commercial computer software documentation,'' as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if any,
+     provides otherwise), excluding its conflict-of-law provisions. With
+     respect to disputes in which at least one party is a citizen of, or an
+     entity chartered or registered to do business in the United States of
+     America, any litigation relating to this License shall be subject to
+     the jurisdiction of the Federal Courts of the Northern District of
+     California, with venue lying in Santa Clara County, California, with
+     the losing party responsible for costs, including without limitation,
+     court costs and reasonable attorneys' fees and expenses. The
+     application of the United Nations Convention on Contracts for the
+     International Sale of Goods is expressly excluded. Any law or
+     regulation which provides that the language of a contract shall be
+     construed against the drafter shall not apply to this License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly, out
+     of its utilization of rights under this License and You agree to work
+     with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+     ``The contents of this file are subject to the Mozilla Public License
+     Version 1.1 (the "License"); you may not use this file except in
+     compliance with the License. You may obtain a copy of the License at
+     http://www.mozilla.org/MPL/
+
+     Software distributed under the License is distributed on an "AS IS"
+     basis, WITHOUT WARRANTY OF
+     ANY KIND, either express or implied. See the License for the specific
+     language governing rights and
+     limitations under the License.
+
+     The Original Code is ______________________________________.
+
+     The Initial Developer of the Original Code is ________________________.
+     Portions created by ______________________ are Copyright (C) ______
+     _______________________. All Rights Reserved.
+
+     Contributor(s): ______________________________________.
+
+     Alternatively, the contents of this file may be used under the terms of
+     the _____ license (the "[___] License"), in which case the provisions
+     of [______] License are applicable  instead of those above.  If you
+     wish to allow use of your version of this file only under the terms of
+     the [____] License and not to allow others to use your version of this
+     file under the MPL, indicate your decision by deleting  the provisions
+     above and replace  them with the notice and other provisions required
+     by the [___] License.  If you do not delete the provisions above, a
+     recipient may use your version of this file under either the MPL or the
+     [___] License."
+
+     [NOTE: The text of this Exhibit A may differ slightly from the text of
+     the notices in the Source Code files of the Original Code. You should
+     use the text of this Exhibit A rather than the text found in the
+     Original Code Source Code for Your Modifications.]
+
+     -----------------------------------------------------------------------
+
+     AMENDMENTS
+
+     The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla
+     Public License Version 1.1 with the following Amendments, including
+     Exhibit A-Netscape Public License.  Files identified with "Exhibit
+     A-Netscape Public License" are governed by the Netscape Public License
+     Version 1.1.
+
+     Additional Terms applicable to the Netscape Public License.
+          I. Effect.
+          These additional terms described in this Netscape Public
+          License -- Amendments shall apply to the Mozilla Communicator
+          client code and to all Covered Code under this License.
+
+          II. ''Netscape's Branded Code'' means Covered Code that Netscape
+          distributes and/or permits others to distribute under one or more
+          trademark(s) which are controlled by Netscape but which are not
+          licensed for use under this License.
+
+          III. Netscape and logo.
+          This License does not grant any rights to use the trademarks
+          "Netscape'', the "Netscape N and horizon'' logo or the "Netscape
+          lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript",
+          "Smart Browsing" even if such marks are included in the Original
+          Code or Modifications.
+
+          IV. Inability to Comply Due to Contractual Obligation.
+          Prior to licensing the Original Code under this License, Netscape
+          has licensed third party code for use in Netscape's Branded Code.
+          To the extent that Netscape is limited contractually from making
+          such third party code available under this License, Netscape may
+          choose to reintegrate such code into Covered Code without being
+          required to distribute such code in Source Code form, even if such
+          code would otherwise be considered ''Modifications'' under this
+          License.
+
+          V. Use of Modifications and Covered Code by Initial Developer.
+               V.1. In General.
+               The obligations of Section 3 apply to Netscape, except to the
+               extent specified in this Amendment, Section V.2 and V.3.
+
+               V.2. Other Products.
+               Netscape may include Covered Code in products other than the
+               Netscape's Branded Code which are released by Netscape during
+               the two (2) years following the release date of the Original
+               Code, without such additional products becoming subject to
+               the terms of this License, and may license such additional
+               products on different terms from those contained in this
+               License.
+
+               V.3. Alternative Licensing.
+               Netscape may license the Source Code of Netscape's Branded
+               Code, including Modifications incorporated therein, without
+               such Netscape Branded Code becoming subject to the terms of
+               this License, and may license such Netscape Branded Code on
+               different terms from those contained in this License.
+
+          VI. Litigation.
+          Notwithstanding the limitations of Section 11 above, the
+          provisions regarding litigation in Section 11(a), (b) and (c) of
+          the License shall apply to all disputes relating to this License.
+
+     EXHIBIT A-Netscape Public License.
+
+          ''The contents of this file are subject to the Netscape Public
+          License Version 1.1 (the "License"); you may not use this file
+          except in compliance with the License. You may obtain a copy of
+          the License at http://www.mozilla.org/NPL/
+
+          Software distributed under the License is distributed on an "AS
+          IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+          implied. See the License for the specific language governing
+          rights and limitations under the License.
+
+          The Original Code is Mozilla Communicator client code, released
+          March 31, 1998.
+
+          The Initial Developer of the Original Code is Netscape
+          Communications Corporation. Portions created by Netscape are
+          Copyright (C) 1998-1999 Netscape Communications Corporation. All
+          Rights Reserved.
+
+          Contributor(s): ______________________________________.
+
+          Alternatively, the contents of this file may be used under the
+          terms of the _____ license (the "[___] License"), in which case
+          the provisions of [______] License are applicable  instead of
+          those above.  If you wish to allow use of your version of this
+          file only under the terms of the [____] License and not to allow
+          others to use your version of this file under the NPL, indicate
+          your decision by deleting  the provisions above and replace  them
+          with the notice and other provisions required by the [___]
+          License.  If you do not delete the provisions above, a recipient
+          may use your version of this file under either the NPL or the
+          [___] License."
diff --git a/cistpl.c b/cistpl.c
new file mode 100644
index 0000000..404b8e4
--- /dev/null
+++ b/cistpl.c
@@ -0,0 +1,1502 @@
+/*======================================================================
+
+    PCMCIA Card Information Structure parser
+
+    cistpl.c 1.101 2003/12/15 03:58:03
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/bus_ops.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+static const u_char mantissa[] = {
+    10, 12, 13, 15, 20, 25, 30, 35,
+    40, 45, 50, 55, 60, 70, 80, 90
+};
+
+static const u_int exponent[] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+/* Convert an extended speed byte to a time in nanoseconds */
+#define SPEED_CVT(v) \
+    (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
+/* Convert a power byte to a current in 0.1 microamps */
+#define POWER_CVT(v) \
+    (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
+#define POWER_SCALE(v)		(exponent[(v)&7])
+
+/* Upper limit on reasonable # of tuples */
+#define MAX_TUPLES		200
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+
+INT_MODULE_PARM(cis_width,	0);		/* 16-bit CIS? */
+
+/*======================================================================
+
+    Low-level functions to read and write CIS memory.  I think the
+    write routine is only useful for writing one-byte registers.
+    
+======================================================================*/
+
+/* Bits in attr field */
+#define IS_ATTR		1
+#define IS_INDIRECT	8
+
+static int setup_cis_mem(socket_info_t *s);
+
+static void set_cis_map(socket_info_t *s, pccard_mem_map *mem)
+{
+    s->ss_entry(s->sock, SS_SetMemMap, mem);
+    if (s->cap.features & SS_CAP_STATIC_MAP) {
+	if (s->cis_virt)
+	    bus_iounmap(s->cap.bus, s->cis_virt);
+	s->cis_virt = bus_ioremap(s->cap.bus, mem->sys_start,
+				  s->cap.map_size);
+    }
+}
+
+int read_cis_mem(socket_info_t *s, int attr, u_int addr,
+		 u_int len, void *ptr)
+{
+    pccard_mem_map *mem = &s->cis_mem;
+    u_char *sys, *buf = ptr;
+    
+    DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    if (setup_cis_mem(s) != 0) {
+	memset(ptr, 0xff, len);
+	return -1;
+    }
+    mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
+
+    if (attr & IS_INDIRECT) {
+	/* Indirect accesses use a bunch of special registers at fixed
+	   locations in common memory */
+	u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+	if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
+	mem->card_start = 0; mem->flags = MAP_ACTIVE;
+	set_cis_map(s, mem);
+	sys = s->cis_virt;
+	bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0);
+	bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0);
+	bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1);
+	bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2);
+	bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3);
+	for ( ; len > 0; len--, buf++)
+	    *buf = bus_readb(s->cap.bus, sys+CISREG_IDATA0);
+    } else {
+	u_int inc = 1;
+	if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+	sys += (addr & (s->cap.map_size-1));
+	mem->card_start = addr & ~(s->cap.map_size-1);
+	while (len) {
+	    set_cis_map(s, mem);
+	    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+	    for ( ; len > 0; len--, buf++, sys += inc) {
+		if (sys == s->cis_virt+s->cap.map_size) break;
+		*buf = bus_readb(s->cap.bus, sys);
+	    }
+	    mem->card_start += s->cap.map_size;
+	    addr = 0;
+	}
+    }
+    DEBUG(3, "cs:  %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+	  *(u_char *)(ptr+0), *(u_char *)(ptr+1),
+	  *(u_char *)(ptr+2), *(u_char *)(ptr+3));
+    return 0;
+}
+
+void write_cis_mem(socket_info_t *s, int attr, u_int addr,
+		   u_int len, void *ptr)
+{
+    pccard_mem_map *mem = &s->cis_mem;
+    u_char *sys, *buf = ptr;
+    
+    DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    if (setup_cis_mem(s) != 0) return;
+    mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
+
+    if (attr & IS_INDIRECT) {
+	/* Indirect accesses use a bunch of special registers at fixed
+	   locations in common memory */
+	u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+	if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
+	mem->card_start = 0; mem->flags = MAP_ACTIVE;
+	set_cis_map(s, mem);
+	sys = s->cis_virt;
+	bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0);
+	bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0);
+	bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1);
+	bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2);
+	bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3);
+	for ( ; len > 0; len--, buf++)
+	    bus_writeb(s->cap.bus, *buf, sys+CISREG_IDATA0);
+    } else {
+	int inc = 1;
+	if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+	mem->card_start = addr & ~(s->cap.map_size-1);
+	while (len) {
+	    set_cis_map(s, mem);
+	    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+	    for ( ; len > 0; len--, buf++, sys += inc) {
+		if (sys == s->cis_virt+s->cap.map_size) break;
+		bus_writeb(s->cap.bus, *buf, sys);
+	    }
+	    mem->card_start += s->cap.map_size;
+	    addr = 0;
+	}
+    }
+}
+
+/*======================================================================
+
+    This is tricky... when we set up CIS memory, we try to validate
+    the memory window space allocations.
+    
+======================================================================*/
+
+/* Scratch pointer to the socket we use for validation */
+static socket_info_t *vs = NULL;
+
+/* Validation function for cards with a valid CIS */
+static int cis_readable(u_long base)
+{
+    cisinfo_t info1, info2;
+    int ret;
+    vs->cis_mem.sys_start = base;
+    vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
+    ret = validate_cis(vs->clients, &info1);
+    /* invalidate mapping and CIS cache */
+    bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
+    if ((ret != 0) || (info1.Chains == 0))
+	return 0;
+    vs->cis_mem.sys_start = base+vs->cap.map_size;
+    vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size,
+			       vs->cap.map_size);
+    ret = validate_cis(vs->clients, &info2);
+    bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
+    return ((ret == 0) && (info1.Chains == info2.Chains));
+}
+
+/* Validation function for simple memory cards */
+static int checksum(u_long base)
+{
+    int i, a, b, d;
+    vs->cis_mem.sys_start = base;
+    vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
+    vs->cis_mem.card_start = 0;
+    vs->cis_mem.flags = MAP_ACTIVE;
+    vs->ss_entry(vs->sock, SS_SetMemMap, &vs->cis_mem);
+    /* Don't bother checking every word... */
+    a = 0; b = -1;
+    for (i = 0; i < vs->cap.map_size; i += 44) {
+	d = bus_readl(vs->cap.bus, vs->cis_virt+i);
+	a += d; b &= d;
+    }
+    bus_iounmap(vs->cap.bus, vs->cis_virt);
+    return (b == -1) ? -1 : (a>>1);
+}
+
+static int checksum_match(u_long base)
+{
+    int a = checksum(base), b = checksum(base+vs->cap.map_size);
+    return ((a == b) && (a >= 0));
+}
+
+static int setup_cis_mem(socket_info_t *s)
+{
+    if (!(s->cap.features & SS_CAP_STATIC_MAP) &&
+	(s->cis_mem.sys_start == 0)) {
+	int low = !(s->cap.features & SS_CAP_PAGE_REGS);
+	vs = s;
+	validate_mem(cis_readable, checksum_match, low);
+	s->cis_mem.sys_start = 0;
+	vs = NULL;
+	if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
+			    s->cap.map_size, low, "card services")) {
+	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
+	    return -1;
+	}
+	s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
+	s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
+				  s->cap.map_size);
+    }
+    return 0;
+}
+
+void release_cis_mem(socket_info_t *s)
+{
+    if (s->cis_mem.sys_start != 0) {
+	s->cis_mem.flags &= ~MAP_ACTIVE;
+	s->ss_entry(s->sock, SS_SetMemMap, &s->cis_mem);
+	if (!(s->cap.features & SS_CAP_STATIC_MAP))
+	    release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
+	bus_iounmap(s->cap.bus, s->cis_virt);
+	s->cis_mem.sys_start = 0;
+	s->cis_virt = NULL;
+    }
+}
+
+/*======================================================================
+
+    This is a wrapper around read_cis_mem, with the same interface,
+    but which caches information, for cards whose CIS may not be
+    readable all the time.
+    
+======================================================================*/
+
+static void read_cis_cache(socket_info_t *s, int attr, u_int addr,
+			   u_int len, void *ptr)
+{
+    int i, ret;
+    char *caddr;
+
+    if (s->fake_cis) {
+	if (s->fake_cis_len > addr+len)
+	    memcpy(ptr, s->fake_cis+addr, len);
+	else
+	    memset(ptr, 0xff, len);
+	return;
+    }
+    caddr = s->cis_cache;
+    for (i = 0; i < s->cis_used; i++) {
+	if ((s->cis_table[i].addr == addr) &&
+	    (s->cis_table[i].len == len) &&
+	    (s->cis_table[i].attr == attr)) break;
+	caddr += s->cis_table[i].len;
+    }
+    if (i < s->cis_used) {
+	memcpy(ptr, caddr, len);
+	return;
+    }
+#ifdef CONFIG_CARDBUS
+    if (s->state & SOCKET_CARDBUS)
+	ret = read_cb_mem(s, 0, attr, addr, len, ptr);
+    else
+#endif
+	ret = read_cis_mem(s, attr, addr, len, ptr);
+    /* Copy data into the cache, if there is room */
+    if ((ret == 0) && (i < MAX_CIS_TABLE) &&
+	(caddr+len < s->cis_cache+MAX_CIS_DATA)) {
+	s->cis_table[i].addr = addr;
+	s->cis_table[i].len = len;
+	s->cis_table[i].attr = attr;
+	s->cis_used++;
+	memcpy(caddr, ptr, len);
+    }	    
+}
+
+/*======================================================================
+
+    This verifies if the CIS of a card matches what is in the CIS
+    cache.
+    
+======================================================================*/
+
+int verify_cis_cache(socket_info_t *s)
+{
+    char *buf, *caddr;
+    int i;
+
+    buf = kmalloc(256, GFP_KERNEL);
+    if (buf == NULL)
+	return -1;
+    caddr = s->cis_cache;
+    for (i = 0; i < s->cis_used; i++) {
+#ifdef CONFIG_CARDBUS
+	if (s->state & SOCKET_CARDBUS)
+	    read_cb_mem(s, 0, s->cis_table[i].attr, s->cis_table[i].addr,
+			s->cis_table[i].len, buf);
+	else
+#endif
+	    read_cis_mem(s, s->cis_table[i].attr, s->cis_table[i].addr,
+			 s->cis_table[i].len, buf);
+	if (memcmp(buf, caddr, s->cis_table[i].len) != 0)
+	    break;
+	caddr += s->cis_table[i].len;
+    }
+    kfree(buf);
+    return (i < s->cis_used);
+}
+
+/*======================================================================
+
+    For really bad cards, we provide a facility for uploading a
+    replacement CIS.
+    
+======================================================================*/
+
+int replace_cis(client_handle_t handle, cisdump_t *cis)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (s->fake_cis != NULL) {
+	kfree(s->fake_cis);
+	s->fake_cis = NULL;
+    }
+    if (cis->Length > CISTPL_MAX_CIS_SIZE)
+	return CS_BAD_SIZE;
+    s->fake_cis = kmalloc(cis->Length, GFP_KERNEL);
+    if (s->fake_cis == NULL)
+	return CS_OUT_OF_RESOURCE;
+    s->fake_cis_len = cis->Length;
+    memcpy(s->fake_cis, cis->Data, cis->Length);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    The high-level CIS tuple services
+    
+======================================================================*/
+
+typedef struct tuple_flags {
+    u_int		link_space:4;
+    u_int		has_link:1;
+    u_int		mfc_fn:3;
+    u_int		space:4;
+} tuple_flags;
+
+#define LINK_SPACE(f)	(((tuple_flags *)(&(f)))->link_space)
+#define HAS_LINK(f)	(((tuple_flags *)(&(f)))->has_link)
+#define MFC_FN(f)	(((tuple_flags *)(&(f)))->mfc_fn)
+#define SPACE(f)	(((tuple_flags *)(&(f)))->space)
+
+int get_next_tuple(client_handle_t handle, tuple_t *tuple);
+
+int get_first_tuple(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    tuple->TupleLink = tuple->Flags = 0;
+#ifdef CONFIG_CARDBUS
+    if (s->state & SOCKET_CARDBUS) {
+	u_int ptr;
+	pcibios_read_config_dword(s->cap.cardbus, 0, 0x28, &ptr);
+	tuple->CISOffset = ptr & ~7;
+	SPACE(tuple->Flags) = (ptr & 7);
+    } else
+#endif
+    {
+	/* Assume presence of a LONGLINK_C to address 0 */
+	tuple->CISOffset = tuple->LinkOffset = 0;
+	SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
+    }
+    if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) &&
+	!(tuple->Attributes & TUPLE_RETURN_COMMON)) {
+	cisdata_t req = tuple->DesiredTuple;
+	tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
+	if (get_next_tuple(handle, tuple) == CS_SUCCESS) {
+	    tuple->DesiredTuple = CISTPL_LINKTARGET;
+	    if (get_next_tuple(handle, tuple) != CS_SUCCESS)
+		return CS_NO_MORE_ITEMS;
+	} else
+	    tuple->CISOffset = tuple->TupleLink = 0;
+	tuple->DesiredTuple = req;
+    }
+    return get_next_tuple(handle, tuple);
+}
+
+static int follow_link(socket_info_t *s, tuple_t *tuple)
+{
+    u_char link[5];
+    u_int ofs;
+
+    if (MFC_FN(tuple->Flags)) {
+	/* Get indirect link from the MFC tuple */
+	read_cis_cache(s, LINK_SPACE(tuple->Flags),
+		       tuple->LinkOffset, 5, link);
+	ofs = le32_to_cpu(*(u_int *)(link+1));
+	SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
+	/* Move to the next indirect link */
+	tuple->LinkOffset += 5;
+	MFC_FN(tuple->Flags)--;
+    } else if (HAS_LINK(tuple->Flags)) {
+	ofs = tuple->LinkOffset;
+	SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
+	HAS_LINK(tuple->Flags) = 0;
+    } else {
+	return -1;
+    }
+    if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) {
+	/* This is ugly, but a common CIS error is to code the long
+	   link offset incorrectly, so we check the right spot... */
+	read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+	if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+	    (strncmp(link+2, "CIS", 3) == 0))
+	    return ofs;
+	/* Then, we try the wrong spot... */
+	ofs = ofs >> 1;
+    }
+    read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+    if ((link[0] != CISTPL_LINKTARGET) || (link[1] < 3) ||
+	(strncmp(link+2, "CIS", 3) != 0))
+	return -1;
+    return ofs;
+}
+
+int get_next_tuple(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    u_char link[2], tmp;
+    int ofs, i, attr;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+
+    link[1] = tuple->TupleLink;
+    ofs = tuple->CISOffset + tuple->TupleLink;
+    attr = SPACE(tuple->Flags);
+
+    for (i = 0; i < MAX_TUPLES; i++) {
+	if (link[1] == 0xff) {
+	    link[0] = CISTPL_END;
+	} else {
+	    read_cis_cache(s, attr, ofs, 2, link);
+	    if (link[0] == CISTPL_NULL) {
+		ofs++; continue;
+	    }
+	}
+	
+	/* End of chain?  Follow long link if possible */
+	if (link[0] == CISTPL_END) {
+	    if ((ofs = follow_link(s, tuple)) < 0)
+		return CS_NO_MORE_ITEMS;
+	    attr = SPACE(tuple->Flags);
+	    read_cis_cache(s, attr, ofs, 2, link);
+	}
+
+	/* Is this a link tuple?  Make a note of it */
+	if ((link[0] == CISTPL_LONGLINK_A) ||
+	    (link[0] == CISTPL_LONGLINK_C) ||
+	    (link[0] == CISTPL_LONGLINK_MFC) ||
+	    (link[0] == CISTPL_LINKTARGET) ||
+	    (link[0] == CISTPL_INDIRECT) ||
+	    (link[0] == CISTPL_NO_LINK)) {
+	    switch (link[0]) {
+	    case CISTPL_LONGLINK_A:
+		HAS_LINK(tuple->Flags) = 1;
+		LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
+		read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+		break;
+	    case CISTPL_LONGLINK_C:
+		HAS_LINK(tuple->Flags) = 1;
+		LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
+		read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+		break;
+	    case CISTPL_INDIRECT:
+		HAS_LINK(tuple->Flags) = 1;
+		LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT;
+		tuple->LinkOffset = 0;
+		break;
+	    case CISTPL_LONGLINK_MFC:
+		tuple->LinkOffset = ofs + 3;
+		LINK_SPACE(tuple->Flags) = attr;
+		if (handle->Function == BIND_FN_ALL) {
+		    /* Follow all the MFC links */
+		    read_cis_cache(s, attr, ofs+2, 1, &tmp);
+		    MFC_FN(tuple->Flags) = tmp;
+		} else {
+		    /* Follow exactly one of the links */
+		    MFC_FN(tuple->Flags) = 1;
+		    tuple->LinkOffset += handle->Function * 5;
+		}
+		break;
+	    case CISTPL_NO_LINK:
+		HAS_LINK(tuple->Flags) = 0;
+		break;
+	    }
+	    if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
+		(tuple->DesiredTuple == RETURN_FIRST_TUPLE))
+		break;
+	} else
+	    if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
+		break;
+	
+	if (link[0] == tuple->DesiredTuple)
+	    break;
+	ofs += link[1] + 2;
+    }
+    if (i == MAX_TUPLES) {
+	DEBUG(1, "cs: overrun in get_next_tuple for socket %d\n",
+	      handle->Socket);
+	return CS_NO_MORE_ITEMS;
+    }
+    
+    tuple->TupleCode = link[0];
+    tuple->TupleLink = link[1];
+    tuple->CISOffset = ofs + 2;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+#define _MIN(a, b)		(((a) < (b)) ? (a) : (b))
+
+int get_tuple_data(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    u_int len;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+
+    s = SOCKET(handle);
+
+    if (tuple->TupleLink < tuple->TupleOffset)
+	return CS_NO_MORE_ITEMS;
+    len = tuple->TupleLink - tuple->TupleOffset;
+    tuple->TupleDataLen = tuple->TupleLink;
+    if (len == 0)
+	return CS_SUCCESS;
+    read_cis_cache(s, SPACE(tuple->Flags),
+		   tuple->CISOffset + tuple->TupleOffset,
+		   _MIN(len, tuple->TupleDataMax), tuple->TupleData);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    Parsing routines for individual tuples
+    
+======================================================================*/
+
+static int parse_device(tuple_t *tuple, cistpl_device_t *device)
+{
+    int i;
+    u_char scale;
+    u_char *p, *q;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    device->ndev = 0;
+    for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
+	
+	if (*p == 0xff) break;
+	device->dev[i].type = (*p >> 4);
+	device->dev[i].wp = (*p & 0x08) ? 1 : 0;
+	switch (*p & 0x07) {
+	case 0: device->dev[i].speed = 0;   break;
+	case 1: device->dev[i].speed = 250; break;
+	case 2: device->dev[i].speed = 200; break;
+	case 3: device->dev[i].speed = 150; break;
+	case 4: device->dev[i].speed = 100; break;
+	case 7:
+	    if (++p == q) return CS_BAD_TUPLE;
+	    device->dev[i].speed = SPEED_CVT(*p);
+	    while (*p & 0x80)
+		if (++p == q) return CS_BAD_TUPLE;
+	    break;
+	default:
+	    return CS_BAD_TUPLE;
+	}
+
+	if (++p == q) return CS_BAD_TUPLE;
+	if (*p == 0xff) break;
+	scale = *p & 7;
+	if (scale == 7) return CS_BAD_TUPLE;
+	device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
+	device->ndev++;
+	if (++p == q) break;
+    }
+    
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 5)
+	return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
+    csum->len = le16_to_cpu(*(u_short *)(p + 2));
+    csum->sum = *(p+4);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
+{
+    if (tuple->TupleDataLen < 4)
+	return CS_BAD_TUPLE;
+    link->addr = le32_to_cpu(*(u_int *)tuple->TupleData);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_longlink_mfc(tuple_t *tuple,
+			      cistpl_longlink_mfc_t *link)
+{
+    u_char *p;
+    int i;
+    
+    p = (u_char *)tuple->TupleData;
+    
+    link->nfn = *p; p++;
+    if (tuple->TupleDataLen <= link->nfn*5)
+	return CS_BAD_TUPLE;
+    for (i = 0; i < link->nfn; i++) {
+	link->fn[i].space = *p; p++;
+	link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4;
+    }
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_strings(u_char *p, u_char *q, int max,
+			 char *s, u_char *ofs, u_char *found)
+{
+    int i, j, ns;
+
+    if (p == q) return CS_BAD_TUPLE;
+    ns = 0; j = 0;
+    for (i = 0; i < max; i++) {
+	if (*p == 0xff) break;
+	ofs[i] = j;
+	ns++;
+	for (;;) {
+	    s[j++] = (*p == 0xff) ? '\0' : *p;
+	    if ((*p == '\0') || (*p == 0xff)) break;
+	    if (++p == q) return CS_BAD_TUPLE;
+	}
+	if ((*p == 0xff) || (++p == q)) break;
+    }
+    if (found) {
+	*found = ns;
+	return CS_SUCCESS;
+    } else {
+	return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE;
+    }
+}
+
+/*====================================================================*/
+
+static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
+{
+    u_char *p, *q;
+    
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    
+    vers_1->major = *p; p++;
+    vers_1->minor = *p; p++;
+    if (p >= q) return CS_BAD_TUPLE;
+
+    return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
+			 vers_1->str, vers_1->ofs, &vers_1->ns);
+}
+
+/*====================================================================*/
+
+static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
+{
+    u_char *p, *q;
+    
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    
+    return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
+			 altstr->str, altstr->ofs, &altstr->ns);
+}
+
+/*====================================================================*/
+
+static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
+{
+    u_char *p, *q;
+    int nid;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
+	if (p > q-2) break;
+	jedec->id[nid].mfr = p[0];
+	jedec->id[nid].info = p[1];
+	p += 2;
+    }
+    jedec->nid = nid;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
+{
+    u_short *p;
+    if (tuple->TupleDataLen < 4)
+	return CS_BAD_TUPLE;
+    p = (u_short *)tuple->TupleData;
+    m->manf = le16_to_cpu(p[0]);
+    m->card = le16_to_cpu(p[1]);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 2)
+	return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    f->func = p[0];
+    f->sysinit = p[1];
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
+{
+    u_char *p;
+    int i;
+    if (tuple->TupleDataLen < 1)
+	return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    f->type = p[0];
+    for (i = 1; i < tuple->TupleDataLen; i++)
+	f->data[i-1] = p[i];
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_config(tuple_t *tuple, cistpl_config_t *config)
+{
+    int rasz, rmsz, i;
+    u_char *p;
+
+    p = (u_char *)tuple->TupleData;
+    rasz = *p & 0x03;
+    rmsz = (*p & 0x3c) >> 2;
+    if (tuple->TupleDataLen < rasz+rmsz+4)
+	return CS_BAD_TUPLE;
+    config->last_idx = *(++p);
+    p++;
+    config->base = 0;
+    for (i = 0; i <= rasz; i++)
+	config->base += p[i] << (8*i);
+    p += rasz+1;
+    for (i = 0; i < 4; i++)
+	config->rmask[i] = 0;
+    for (i = 0; i <= rmsz; i++)
+	config->rmask[i>>2] += p[i] << (8*(i%4));
+    config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    The following routines are all used to parse the nightmarish
+    config table entries.
+    
+======================================================================*/
+
+static u_char *parse_power(u_char *p, u_char *q,
+			   cistpl_power_t *pwr)
+{
+    int i;
+    u_int scale;
+
+    if (p == q) return NULL;
+    pwr->present = *p;
+    pwr->flags = 0;
+    p++;
+    for (i = 0; i < 7; i++)
+	if (pwr->present & (1<<i)) {
+	    if (p == q) return NULL;
+	    pwr->param[i] = POWER_CVT(*p);
+	    scale = POWER_SCALE(*p);
+	    while (*p & 0x80) {
+		if (++p == q) return NULL;
+		if ((*p & 0x7f) < 100)
+		    pwr->param[i] += (*p & 0x7f) * scale / 100;
+		else if (*p == 0x7d)
+		    pwr->flags |= CISTPL_POWER_HIGHZ_OK;
+		else if (*p == 0x7e)
+		    pwr->param[i] = 0;
+		else if (*p == 0x7f)
+		    pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
+		else
+		    return NULL;
+	    }
+	    p++;
+	}
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_timing(u_char *p, u_char *q,
+			    cistpl_timing_t *timing)
+{
+    u_char scale;
+
+    if (p == q) return NULL;
+    scale = *p;
+    if ((scale & 3) != 3) {
+	if (++p == q) return NULL;
+	timing->wait = SPEED_CVT(*p);
+	timing->waitscale = exponent[scale & 3];
+    } else
+	timing->wait = 0;
+    scale >>= 2;
+    if ((scale & 7) != 7) {
+	if (++p == q) return NULL;
+	timing->ready = SPEED_CVT(*p);
+	timing->rdyscale = exponent[scale & 7];
+    } else
+	timing->ready = 0;
+    scale >>= 3;
+    if (scale != 7) {
+	if (++p == q) return NULL;
+	timing->reserved = SPEED_CVT(*p);
+	timing->rsvscale = exponent[scale];
+    } else
+	timing->reserved = 0;
+    p++;
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
+{
+    int i, j, bsz, lsz;
+
+    if (p == q) return NULL;
+    io->flags = *p;
+
+    if (!(*p & 0x80)) {
+	io->nwin = 1;
+	io->win[0].base = 0;
+	io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
+	return p+1;
+    }
+    
+    if (++p == q) return NULL;
+    io->nwin = (*p & 0x0f) + 1;
+    bsz = (*p & 0x30) >> 4;
+    if (bsz == 3) bsz++;
+    lsz = (*p & 0xc0) >> 6;
+    if (lsz == 3) lsz++;
+    p++;
+    
+    for (i = 0; i < io->nwin; i++) {
+	io->win[i].base = 0;
+	io->win[i].len = 1;
+	for (j = 0; j < bsz; j++, p++) {
+	    if (p == q) return NULL;
+	    io->win[i].base += *p << (j*8);
+	}
+	for (j = 0; j < lsz; j++, p++) {
+	    if (p == q) return NULL;
+	    io->win[i].len += *p << (j*8);
+	}
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
+{
+    int i, j, asz, lsz, has_ha;
+    u_int len, ca, ha;
+
+    if (p == q) return NULL;
+
+    mem->nwin = (*p & 0x07) + 1;
+    lsz = (*p & 0x18) >> 3;
+    asz = (*p & 0x60) >> 5;
+    has_ha = (*p & 0x80);
+    if (++p == q) return NULL;
+    
+    for (i = 0; i < mem->nwin; i++) {
+	len = ca = ha = 0;
+	for (j = 0; j < lsz; j++, p++) {
+	    if (p == q) return NULL;
+	    len += *p << (j*8);
+	}
+	for (j = 0; j < asz; j++, p++) {
+	    if (p == q) return NULL;
+	    ca += *p << (j*8);
+	}
+	if (has_ha)
+	    for (j = 0; j < asz; j++, p++) {
+		if (p == q) return NULL;
+		ha += *p << (j*8);
+	    }
+	mem->win[i].len = len << 8;
+	mem->win[i].card_addr = ca << 8;
+	mem->win[i].host_addr = ha << 8;
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
+{
+    if (p == q) return NULL;
+    irq->IRQInfo1 = *p; p++;
+    if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
+	if (p+2 > q) return NULL;
+	irq->IRQInfo2 = (p[1]<<8) + p[0];
+	p += 2;
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static int parse_cftable_entry(tuple_t *tuple,
+			       cistpl_cftable_entry_t *entry)
+{
+    u_char *p, *q, features;
+
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    entry->index = *p & 0x3f;
+    entry->flags = 0;
+    if (*p & 0x40)
+	entry->flags |= CISTPL_CFTABLE_DEFAULT;
+    if (*p & 0x80) {
+	if (++p == q) return CS_BAD_TUPLE;
+	if (*p & 0x10)
+	    entry->flags |= CISTPL_CFTABLE_BVDS;
+	if (*p & 0x20)
+	    entry->flags |= CISTPL_CFTABLE_WP;
+	if (*p & 0x40)
+	    entry->flags |= CISTPL_CFTABLE_RDYBSY;
+	if (*p & 0x80)
+	    entry->flags |= CISTPL_CFTABLE_MWAIT;
+	entry->interface = *p & 0x0f;
+    } else
+	entry->interface = 0;
+
+    /* Process optional features */
+    if (++p == q) return CS_BAD_TUPLE;
+    features = *p; p++;
+
+    /* Power options */
+    if ((features & 3) > 0) {
+	p = parse_power(p, q, &entry->vcc);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vcc.present = 0;
+    if ((features & 3) > 1) {
+	p = parse_power(p, q, &entry->vpp1);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vpp1.present = 0;
+    if ((features & 3) > 2) {
+	p = parse_power(p, q, &entry->vpp2);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vpp2.present = 0;
+
+    /* Timing options */
+    if (features & 0x04) {
+	p = parse_timing(p, q, &entry->timing);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else {
+	entry->timing.wait = 0;
+	entry->timing.ready = 0;
+	entry->timing.reserved = 0;
+    }
+    
+    /* I/O window options */
+    if (features & 0x08) {
+	p = parse_io(p, q, &entry->io);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->io.nwin = 0;
+    
+    /* Interrupt options */
+    if (features & 0x10) {
+	p = parse_irq(p, q, &entry->irq);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->irq.IRQInfo1 = 0;
+
+    switch (features & 0x60) {
+    case 0x00:
+	entry->mem.nwin = 0;
+	break;
+    case 0x20:
+	entry->mem.nwin = 1;
+	entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+	entry->mem.win[0].card_addr = 0;
+	entry->mem.win[0].host_addr = 0;
+	p += 2;
+	if (p > q) return CS_BAD_TUPLE;
+	break;
+    case 0x40:
+	entry->mem.nwin = 1;
+	entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+	entry->mem.win[0].card_addr =
+	    le16_to_cpu(*(u_short *)(p+2)) << 8;
+	entry->mem.win[0].host_addr = 0;
+	p += 4;
+	if (p > q) return CS_BAD_TUPLE;
+	break;
+    case 0x60:
+	p = parse_mem(p, q, &entry->mem);
+	if (p == NULL) return CS_BAD_TUPLE;
+	break;
+    }
+
+    /* Misc features */
+    if (features & 0x80) {
+	if (p == q) return CS_BAD_TUPLE;
+	entry->flags |= (*p << 8);
+	while (*p & 0x80)
+	    if (++p == q) return CS_BAD_TUPLE;
+	p++;
+    }
+
+    entry->subtuples = q-p;
+    
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 6)
+	return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    bar->attr = *p;
+    p += 2;
+    bar->size = le32_to_cpu(*(u_int *)p);
+    return CS_SUCCESS;
+}
+
+static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
+{
+    u_char *p;
+    
+    p = (u_char *)tuple->TupleData;
+    if ((*p != 3) || (tuple->TupleDataLen < 6))
+	return CS_BAD_TUPLE;
+    config->last_idx = *(++p);
+    p++;
+    config->base = le32_to_cpu(*(u_int *)p);
+    config->subtuples = tuple->TupleDataLen - 6;
+    return CS_SUCCESS;
+}
+
+static int parse_cftable_entry_cb(tuple_t *tuple,
+				  cistpl_cftable_entry_cb_t *entry)
+{
+    u_char *p, *q, features;
+
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    entry->index = *p & 0x3f;
+    entry->flags = 0;
+    if (*p & 0x40)
+	entry->flags |= CISTPL_CFTABLE_DEFAULT;
+
+    /* Process optional features */
+    if (++p == q) return CS_BAD_TUPLE;
+    features = *p; p++;
+
+    /* Power options */
+    if ((features & 3) > 0) {
+	p = parse_power(p, q, &entry->vcc);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vcc.present = 0;
+    if ((features & 3) > 1) {
+	p = parse_power(p, q, &entry->vpp1);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vpp1.present = 0;
+    if ((features & 3) > 2) {
+	p = parse_power(p, q, &entry->vpp2);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vpp2.present = 0;
+
+    /* I/O window options */
+    if (features & 0x08) {
+	if (p == q) return CS_BAD_TUPLE;
+	entry->io = *p; p++;
+    } else
+	entry->io = 0;
+    
+    /* Interrupt options */
+    if (features & 0x10) {
+	p = parse_irq(p, q, &entry->irq);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->irq.IRQInfo1 = 0;
+
+    if (features & 0x20) {
+	if (p == q) return CS_BAD_TUPLE;
+	entry->mem = *p; p++;
+    } else
+	entry->mem = 0;
+
+    /* Misc features */
+    if (features & 0x80) {
+	if (p == q) return CS_BAD_TUPLE;
+	entry->flags |= (*p << 8);
+	if (*p & 0x80) {
+	    if (++p == q) return CS_BAD_TUPLE;
+	    entry->flags |= (*p << 16);
+	}
+	while (*p & 0x80)
+	    if (++p == q) return CS_BAD_TUPLE;
+	p++;
+    }
+
+    entry->subtuples = q-p;
+    
+    return CS_SUCCESS;
+}
+
+#endif
+
+/*====================================================================*/
+
+static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
+{
+    u_char *p, *q;
+    int n;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
+	if (p > q-6) break;
+	geo->geo[n].buswidth = p[0];
+	geo->geo[n].erase_block = 1 << (p[1]-1);
+	geo->geo[n].read_block  = 1 << (p[2]-1);
+	geo->geo[n].write_block = 1 << (p[3]-1);
+	geo->geo[n].partition   = 1 << (p[4]-1);
+	geo->geo[n].interleave  = 1 << (p[5]-1);
+	p += 6;
+    }
+    geo->ngeo = n;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
+{
+    u_char *p, *q;
+
+    if (tuple->TupleDataLen < 10)
+	return CS_BAD_TUPLE;
+    
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    v2->vers = p[0];
+    v2->comply = p[1];
+    v2->dindex = le16_to_cpu(*(u_short *)(p+2));
+    v2->vspec8 = p[6];
+    v2->vspec9 = p[7];
+    v2->nhdr = p[8];
+    p += 9;
+    return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
+}
+
+/*====================================================================*/
+
+static int parse_org(tuple_t *tuple, cistpl_org_t *org)
+{
+    u_char *p, *q;
+    int i;
+    
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    if (p == q) return CS_BAD_TUPLE;
+    org->data_org = *p;
+    if (++p == q) return CS_BAD_TUPLE;
+    for (i = 0; i < 30; i++) {
+	org->desc[i] = *p;
+	if (*p == '\0') break;
+	if (++p == q) return CS_BAD_TUPLE;
+    }
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
+{
+    u_char *p;
+
+    if (tuple->TupleDataLen < 10)
+	return CS_BAD_TUPLE;
+
+    p = tuple->TupleData;
+
+    fmt->type = p[0];
+    fmt->edc = p[1];
+    fmt->offset = le32_to_cpu(*(u_int *)(p+2));
+    fmt->length = le32_to_cpu(*(u_int *)(p+6));
+
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+    int ret = CS_SUCCESS;
+    
+    if (tuple->TupleDataLen > tuple->TupleDataMax)
+	return CS_BAD_TUPLE;
+    switch (tuple->TupleCode) {
+    case CISTPL_DEVICE:
+    case CISTPL_DEVICE_A:
+	ret = parse_device(tuple, &parse->device);
+	break;
+#ifdef CONFIG_CARDBUS
+    case CISTPL_BAR:
+	ret = parse_bar(tuple, &parse->bar);
+	break;
+    case CISTPL_CONFIG_CB:
+	ret = parse_config_cb(tuple, &parse->config);
+	break;
+    case CISTPL_CFTABLE_ENTRY_CB:
+	ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb);
+	break;
+#endif
+    case CISTPL_CHECKSUM:
+	ret = parse_checksum(tuple, &parse->checksum);
+	break;
+    case CISTPL_LONGLINK_A:
+    case CISTPL_LONGLINK_C:
+	ret = parse_longlink(tuple, &parse->longlink);
+	break;
+    case CISTPL_LONGLINK_MFC:
+	ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
+	break;
+    case CISTPL_VERS_1:
+	ret = parse_vers_1(tuple, &parse->version_1);
+	break;
+    case CISTPL_ALTSTR:
+	ret = parse_altstr(tuple, &parse->altstr);
+	break;
+    case CISTPL_JEDEC_A:
+    case CISTPL_JEDEC_C:
+	ret = parse_jedec(tuple, &parse->jedec);
+	break;
+    case CISTPL_MANFID:
+	ret = parse_manfid(tuple, &parse->manfid);
+	break;
+    case CISTPL_FUNCID:
+	ret = parse_funcid(tuple, &parse->funcid);
+	break;
+    case CISTPL_FUNCE:
+	ret = parse_funce(tuple, &parse->funce);
+	break;
+    case CISTPL_CONFIG:
+	ret = parse_config(tuple, &parse->config);
+	break;
+    case CISTPL_CFTABLE_ENTRY:
+	ret = parse_cftable_entry(tuple, &parse->cftable_entry);
+	break;
+    case CISTPL_DEVICE_GEO:
+    case CISTPL_DEVICE_GEO_A:
+	ret = parse_device_geo(tuple, &parse->device_geo);
+	break;
+    case CISTPL_VERS_2:
+	ret = parse_vers_2(tuple, &parse->vers_2);
+	break;
+    case CISTPL_ORG:
+	ret = parse_org(tuple, &parse->org);
+	break;
+    case CISTPL_FORMAT:
+    case CISTPL_FORMAT_A:
+	ret = parse_format(tuple, &parse->format);
+	break;
+    case CISTPL_NO_LINK:
+    case CISTPL_LINKTARGET:
+	ret = CS_SUCCESS;
+	break;
+    default:
+	ret = CS_UNSUPPORTED_FUNCTION;
+	break;
+    }
+    return ret;
+}
+
+/*======================================================================
+
+    This is used internally by Card Services to look up CIS stuff.
+    
+======================================================================*/
+
+int read_tuple(client_handle_t handle, cisdata_t code, void *parse)
+{
+    tuple_t tuple;
+    cisdata_t *buf;
+    int ret;
+
+    buf = kmalloc(255, GFP_KERNEL);
+    if (buf == NULL)
+	return CS_OUT_OF_RESOURCE;
+    tuple.DesiredTuple = code;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    ret = CardServices(GetFirstTuple, handle, &tuple, NULL);
+    if (ret != CS_SUCCESS) goto done;
+    tuple.TupleData = buf;
+    tuple.TupleOffset = 0;
+    tuple.TupleDataMax = 255;
+    ret = CardServices(GetTupleData, handle, &tuple, NULL);
+    if (ret != CS_SUCCESS) goto done;
+    ret = CardServices(ParseTuple, handle, &tuple, parse);
+done:
+    kfree(buf);
+    return ret;
+}
+
+/*======================================================================
+
+    This tries to determine if a card has a sensible CIS.  It returns
+    the number of tuples in the CIS, or 0 if the CIS looks bad.  The
+    checks include making sure several critical tuples are present and
+    valid; seeing if the total number of tuples is reasonable; and
+    looking for tuples that use reserved codes.
+    
+======================================================================*/
+
+int validate_cis(client_handle_t handle, cisinfo_t *info)
+{
+    tuple_t tuple;
+    cisparse_t *p;
+    int ret, reserved, dev_ok = 0, ident_ok = 0;
+
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    p = kmalloc(sizeof(*p), GFP_KERNEL);
+    if (p == NULL)
+	return CS_OUT_OF_RESOURCE;
+
+    info->Chains = reserved = 0;
+    tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    ret = get_first_tuple(handle, &tuple);
+    if (ret != CS_SUCCESS)
+	goto done;
+
+    /* First tuple should be DEVICE; we should really have either that
+       or a CFTABLE_ENTRY of some sort */
+    if ((tuple.TupleCode == CISTPL_DEVICE) ||
+	(read_tuple(handle, CISTPL_CFTABLE_ENTRY, p) == CS_SUCCESS) ||
+	(read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, p) == CS_SUCCESS))
+	dev_ok++;
+
+    /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
+       tuple, for card identification.  Certain old D-Link and Linksys
+       cards have only a broken VERS_2 tuple; hence the bogus test. */
+    if ((read_tuple(handle, CISTPL_MANFID, p) == CS_SUCCESS) ||
+	(read_tuple(handle, CISTPL_VERS_1, p) == CS_SUCCESS) ||
+	(read_tuple(handle, CISTPL_VERS_2, p) != CS_NO_MORE_ITEMS))
+	ident_ok++;
+
+    if (!dev_ok && !ident_ok)
+	goto done;
+
+    for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) {
+	ret = get_next_tuple(handle, &tuple);
+	if (ret != CS_SUCCESS) break;
+	if (((tuple.TupleCode > 0x23) && (tuple.TupleCode < 0x40)) ||
+	    ((tuple.TupleCode > 0x47) && (tuple.TupleCode < 0x80)) ||
+	    ((tuple.TupleCode > 0x90) && (tuple.TupleCode < 0xff)))
+	    reserved++;
+    }
+    if ((info->Chains == MAX_TUPLES) || (reserved > 5) ||
+	((!dev_ok || !ident_ok) && (info->Chains > 10)))
+	info->Chains = 0;
+
+done:
+    kfree(p);
+    return CS_SUCCESS;
+}
+
diff --git a/dump_cis.c b/dump_cis.c
new file mode 100644
index 0000000..aa5cd9f
--- /dev/null
+++ b/dump_cis.c
@@ -0,0 +1,1102 @@
+/*======================================================================
+
+    PC Card CIS dump utility
+
+    dump_cis.c 1.63 2001/11/30 23:10:17
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+static int verbose = 0;
+static char indent[10] = "  ";
+
+/*====================================================================*/
+
+static int major = 0;
+
+static int lookup_dev(char *name)
+{
+    FILE *f;
+    int n;
+    char s[32], t[32];
+    
+    f = fopen("/proc/devices", "r");
+    if (f == NULL)
+	return -1;
+    while (fgets(s, 32, f) != NULL) {
+	if (sscanf(s, "%d %s", &n, t) == 2)
+	    if (strcmp(name, t) == 0)
+		break;
+    }
+    fclose(f);
+    if (strcmp(name, t) == 0)
+	return n;
+    else
+	return -1;
+}
+
+/*====================================================================*/
+
+static int open_sock(int sock)
+{
+    static char *paths[] = {
+	"/var/lib/pcmcia", "/var/run", "/dev", "/tmp", NULL
+    };
+    int fd;
+    char **p, fn[64];
+    dev_t dev = (major<<8) + sock;
+
+    for (p = paths; *p; p++) {
+	sprintf(fn, "%s/dc%d", *p, getpid());
+	if (mknod(fn, (S_IFCHR|S_IREAD|S_IWRITE), dev) == 0) {
+	    fd = open(fn, O_RDONLY);
+	    unlink(fn);
+	    if (fd >= 0)
+		return fd;
+	    if (errno == ENODEV) break;
+	}
+    }
+    return -1;
+} /* open_sock */
+
+/*====================================================================*/
+
+static void print_tuple(tuple_parse_t *tup)
+{
+    int i;
+    printf("%soffset 0x%2.2x, tuple 0x%2.2x, link 0x%2.2x\n",
+	   indent, tup->tuple.CISOffset, tup->tuple.TupleCode,
+	   tup->tuple.TupleLink);
+    for (i = 0; i < tup->tuple.TupleDataLen; i++) {
+	if ((i % 16) == 0) printf("%s  ", indent);
+	printf("%2.2x ", (u_char)tup->data[i]);
+	if ((i % 16) == 15) putchar('\n');
+    }
+    if ((i % 16) != 0) putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_funcid(cistpl_funcid_t *fn)
+{
+    printf("%sfuncid ", indent);
+    switch (fn->func) {
+    case CISTPL_FUNCID_MULTI:
+	printf("multi_function"); break;
+    case CISTPL_FUNCID_MEMORY:
+	printf("memory_card"); break;
+    case CISTPL_FUNCID_SERIAL:
+	printf("serial_port"); break;
+    case CISTPL_FUNCID_PARALLEL:
+	printf("parallel_port"); break;
+    case CISTPL_FUNCID_FIXED:
+	printf("fixed_disk"); break;
+    case CISTPL_FUNCID_VIDEO:
+	printf("video_adapter"); break;
+    case CISTPL_FUNCID_NETWORK:
+	printf("network_adapter"); break;
+    case CISTPL_FUNCID_AIMS:
+	printf("aims_card"); break;
+    case CISTPL_FUNCID_SCSI:
+	printf("scsi_adapter"); break;
+    default:
+	printf("unknown"); break;
+    }
+    if (fn->sysinit & CISTPL_SYSINIT_POST)
+	printf(" [post]");
+    if (fn->sysinit & CISTPL_SYSINIT_ROM)
+	printf(" [rom]");
+    putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_size(u_int size)
+{
+    if (size < 1024)
+	printf("%ub", size);
+    else if (size < 1024*1024)
+	printf("%ukb", size/1024);
+    else
+	printf("%umb", size/(1024*1024));
+}
+
+static void print_unit(u_int v, char *unit, char tag)
+{
+    int n;
+    for (n = 0; (v % 1000) == 0; n++) v /= 1000;
+    printf("%u", v);
+    if (n < strlen(unit)) putchar(unit[n]);
+    putchar(tag);
+}
+
+static void print_time(u_int tm, u_long scale)
+{
+    print_unit(tm * scale, "num", 's');
+}
+
+static void print_volt(u_int vi)
+{
+    print_unit(vi * 10, "um", 'V');
+}
+    
+static void print_current(u_int ii)
+{
+    print_unit(ii / 10, "um", 'A');
+}
+
+static void print_speed(u_int b)
+{
+    if (b < 1000)
+	printf("%u bits/sec", b);
+    else if (b < 1000000)
+	printf("%u kb/sec", b/1000);
+    else
+	printf("%u mb/sec", b/1000000);
+}
+
+/*====================================================================*/
+
+static const char *dtype[] = {
+    "NULL", "ROM", "OTPROM", "EPROM", "EEPROM", "FLASH", "SRAM",
+    "DRAM", "rsvd", "rsvd", "rsvd", "rsvd", "rsvd", "fn_specific",
+    "extended", "rsvd"
+};
+
+static void print_device(cistpl_device_t *dev)
+{
+    int i;
+    for (i = 0; i < dev->ndev; i++) {
+	printf("%s  %s ", indent, dtype[dev->dev[i].type]);
+	printf("%uns, ", dev->dev[i].speed);
+	print_size(dev->dev[i].size);
+	putchar('\n');
+    }
+    if (dev->ndev == 0)
+	printf("%s  no_info\n", indent);
+}
+
+/*====================================================================*/
+
+static void print_power(char *tag, cistpl_power_t *power)
+{
+    int i, n;
+    for (i = n = 0; i < 8; i++)
+	if (power->present & (1<<i)) n++;
+    i = 0;
+    printf("%s  %s", indent, tag);
+    if (power->present & (1<<CISTPL_POWER_VNOM)) {
+	printf(" Vnom "); i++;
+	print_volt(power->param[CISTPL_POWER_VNOM]);
+    }
+    if (power->present & (1<<CISTPL_POWER_VMIN)) {
+	printf(" Vmin "); i++;
+	print_volt(power->param[CISTPL_POWER_VMIN]);
+    }
+    if (power->present & (1<<CISTPL_POWER_VMAX)) {
+ 	printf(" Vmax "); i++;
+	print_volt(power->param[CISTPL_POWER_VMAX]);
+    }
+    if (power->present & (1<<CISTPL_POWER_ISTATIC)) {
+	printf(" Istatic "); i++;
+	print_current(power->param[CISTPL_POWER_ISTATIC]);
+    }
+    if (power->present & (1<<CISTPL_POWER_IAVG)) {
+	if (++i == 5) printf("\n%s   ", indent);
+	printf(" Iavg ");
+	print_current(power->param[CISTPL_POWER_IAVG]);
+    }
+    if (power->present & (1<<CISTPL_POWER_IPEAK)) {
+	if (++i == 5) printf("\n%s ", indent);
+	printf(" Ipeak ");
+	print_current(power->param[CISTPL_POWER_IPEAK]);
+    }
+    if (power->present & (1<<CISTPL_POWER_IDOWN)) {
+	if (++i == 5) printf("\n%s ", indent);
+	printf(" Idown ");
+	print_current(power->param[CISTPL_POWER_IDOWN]);
+    }
+    if (power->flags & CISTPL_POWER_HIGHZ_OK) {
+	if (++i == 5) printf("\n%s ", indent);
+	printf(" [highz OK]");
+    }
+    if (power->flags & CISTPL_POWER_HIGHZ_REQ) {
+	printf(" [highz]");
+    }
+    putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_cftable_entry(cistpl_cftable_entry_t *entry)
+{
+    int i;
+    
+    printf("%scftable_entry 0x%2.2x%s\n", indent, entry->index,
+	   (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
+
+    if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
+	printf("%s ", indent);
+	if (entry->flags & CISTPL_CFTABLE_BVDS)
+	    printf(" [bvd]");
+	if (entry->flags & CISTPL_CFTABLE_WP)
+	    printf(" [wp]");
+	if (entry->flags & CISTPL_CFTABLE_RDYBSY)
+	    printf(" [rdybsy]");
+	if (entry->flags & CISTPL_CFTABLE_MWAIT)
+	    printf(" [mwait]");
+	if (entry->flags & CISTPL_CFTABLE_AUDIO)
+	    printf(" [audio]");
+	if (entry->flags & CISTPL_CFTABLE_READONLY)
+	    printf(" [readonly]");
+	if (entry->flags & CISTPL_CFTABLE_PWRDOWN)
+	    printf(" [pwrdown]");
+	putchar('\n');
+    }
+    
+    if (entry->vcc.present)
+	print_power("Vcc", &entry->vcc);
+    if (entry->vpp1.present)
+	print_power("Vpp1", &entry->vpp1);
+    if (entry->vpp2.present)
+	print_power("Vpp2", &entry->vpp2);
+
+    if ((entry->timing.wait != 0) || (entry->timing.ready != 0) ||
+	(entry->timing.reserved != 0)) {
+	printf("%s  timing", indent);
+	if (entry->timing.wait != 0) {
+	    printf(" wait ");
+	    print_time(entry->timing.wait, entry->timing.waitscale);
+	}
+	if (entry->timing.ready != 0) {
+	    printf(" ready ");
+	    print_time(entry->timing.ready, entry->timing.rdyscale);
+	}
+	if (entry->timing.reserved != 0) {
+	    printf(" reserved ");
+	    print_time(entry->timing.reserved, entry->timing.rsvscale);
+	}
+	putchar('\n');
+    }
+    
+    if (entry->io.nwin) {
+	cistpl_io_t *io = &entry->io;
+	printf("%s  io", indent);
+	for (i = 0; i < io->nwin; i++) {
+	    if (i) putchar(',');
+	    printf(" 0x%4.4x-0x%4.4x", io->win[i].base,
+		   io->win[i].base+io->win[i].len-1);
+	}
+	printf(" [lines=%d]", io->flags & CISTPL_IO_LINES_MASK);
+	if (io->flags & CISTPL_IO_8BIT) printf(" [8bit]");
+	if (io->flags & CISTPL_IO_16BIT) printf(" [16bit]");
+	if (io->flags & CISTPL_IO_RANGE) printf(" [range]");
+	putchar('\n');
+    }
+
+    if (entry->irq.IRQInfo1) {
+	printf("%s  irq ", indent);
+	if (entry->irq.IRQInfo1 & IRQ_INFO2_VALID)
+	    printf("mask 0x%04x", entry->irq.IRQInfo2);
+	else
+	    printf("%u", entry->irq.IRQInfo1 & IRQ_MASK);
+	if (entry->irq.IRQInfo1 & IRQ_LEVEL_ID) printf(" [level]");
+	if (entry->irq.IRQInfo1 & IRQ_PULSE_ID) printf(" [pulse]");
+	if (entry->irq.IRQInfo1 & IRQ_SHARE_ID) printf(" [shared]");
+	putchar('\n');
+    }
+
+    if (entry->mem.nwin) {
+	cistpl_mem_t *mem = &entry->mem;
+	printf("%s  memory", indent);
+	for (i = 0; i < mem->nwin; i++) {
+	    if (i) putchar(',');
+	    printf(" 0x%4.4x-0x%4.4x @ 0x%4.4x", mem->win[i].card_addr,
+		   mem->win[i].card_addr + mem->win[i].len-1,
+		   mem->win[i].host_addr);
+	}
+	putchar('\n');
+    }
+
+    if (verbose && entry->subtuples)
+	printf("%s  %d bytes in subtuples\n", indent, entry->subtuples);
+    
+}
+
+/*====================================================================*/
+
+static void print_cftable_entry_cb(cistpl_cftable_entry_cb_t *entry)
+{
+    int i;
+    
+    printf("%scftable_entry_cb 0x%2.2x%s\n", indent, entry->index,
+	   (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
+
+    if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
+	printf("%s ", indent);
+	if (entry->flags & CISTPL_CFTABLE_MASTER)
+	    printf(" [master]");
+	if (entry->flags & CISTPL_CFTABLE_INVALIDATE)
+	    printf(" [invalidate]");
+	if (entry->flags & CISTPL_CFTABLE_VGA_PALETTE)
+	    printf(" [vga palette]");
+	if (entry->flags & CISTPL_CFTABLE_PARITY)
+	    printf(" [parity]");
+	if (entry->flags & CISTPL_CFTABLE_WAIT)
+	    printf(" [wait]");
+	if (entry->flags & CISTPL_CFTABLE_SERR)
+	    printf(" [serr]");
+	if (entry->flags & CISTPL_CFTABLE_FAST_BACK)
+	    printf(" [fast back]");
+	if (entry->flags & CISTPL_CFTABLE_BINARY_AUDIO)
+	    printf(" [binary audio]");
+	if (entry->flags & CISTPL_CFTABLE_PWM_AUDIO)
+	    printf(" [pwm audio]");
+	putchar('\n');
+    }
+    
+    if (entry->vcc.present)
+	print_power("Vcc", &entry->vcc);
+    if (entry->vpp1.present)
+	print_power("Vpp1", &entry->vpp1);
+    if (entry->vpp2.present)
+	print_power("Vpp2", &entry->vpp2);
+
+    if (entry->io) {
+	printf("%s  io_base", indent);
+	for (i = 0; i < 8; i++)
+	    if (entry->io & (1<<i)) printf(" %d", i);
+	putchar('\n');
+    }
+
+    if (entry->irq.IRQInfo1) {
+	printf("%s  irq ", indent);
+	if (entry->irq.IRQInfo1 & IRQ_INFO2_VALID)
+	    printf("mask 0x%4.4x", entry->irq.IRQInfo2);
+	else
+	    printf("%u", entry->irq.IRQInfo1 & IRQ_MASK);
+	if (entry->irq.IRQInfo1 & IRQ_LEVEL_ID) printf(" [level]");
+	if (entry->irq.IRQInfo1 & IRQ_PULSE_ID) printf(" [pulse]");
+	if (entry->irq.IRQInfo1 & IRQ_SHARE_ID) printf(" [shared]");
+	putchar('\n');
+    }
+
+    if (entry->mem) {
+	printf("%s  mem_base", indent);
+	for (i = 0; i < 8; i++)
+	    if (entry->mem & (1<<i)) printf(" %d", i);
+	putchar('\n');
+    }
+
+    if (verbose && entry->subtuples)
+	printf("%s  %d bytes in subtuples\n", indent,  entry->subtuples);
+    
+}
+
+/*====================================================================*/
+
+static void print_jedec(cistpl_jedec_t *j)
+{
+    int i;
+    for (i = 0; i < j->nid; i++) {
+	if (i != 0) putchar(',');
+	printf(" 0x%02x 0x%02x", j->id[i].mfr, j->id[i].info);
+    }
+    putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_device_geo(cistpl_device_geo_t *geo)
+{
+    int i;
+    for (i = 0; i < geo->ngeo; i++) {
+	printf("%s  width %d erase 0x%x read 0x%x write 0x%x "
+	       "partition 0x%x interleave 0x%x\n", indent,
+	       geo->geo[i].buswidth, geo->geo[i].erase_block,
+	       geo->geo[i].read_block, geo->geo[i].write_block,
+	       geo->geo[i].partition, geo->geo[i].interleave);
+    }
+}
+
+/*====================================================================*/
+
+static void print_org(cistpl_org_t *org)
+{
+    printf("%sdata_org ", indent);
+    switch (org->data_org) {
+    case CISTPL_ORG_FS:
+	printf("[filesystem]"); break;
+    case CISTPL_ORG_APPSPEC:
+	printf("[app_specific]"); break;
+    case CISTPL_ORG_XIP:
+	printf("[code]"); break;
+    default:
+	if (org->data_org < 0x80)
+	    printf("[reserved]");
+	else
+	    printf("[vendor_specific]");
+    }
+    printf(", \"%s\"\n", org->desc);
+}
+
+/*====================================================================*/
+
+static char *data_mod[] = {
+    "Bell103", "V.21", "V.23", "V.22", "Bell212A", "V.22bis",
+    "V.26", "V.26bis", "V.27bis", "V.29", "V.32", "V.32bis",
+    "V.34", "rfu", "rfu", "rfu"
+};
+static char *fax_mod[] = {
+    "V.21-C2", "V.27ter", "V.29", "V.17", "V.33", "rfu", "rfu", "rfu"
+};
+static char *fax_features[] = {
+    "T.3", "T.4", "T.6", "error", "voice", "poll", "file", "passwd"
+};
+static char *cmd_protocol[] = {
+    "AT1", "AT2", "AT3", "MNP_AT", "V.25bis", "V.25A", "DMCL"
+};
+static char *uart[] = {
+    "8250", "16450", "16550", "8251", "8530", "85230"
+};
+static char *parity[] = { "space", "mark", "odd", "even" };
+static char *stop[] = { "1", "1.5", "2" };
+static char *flow[] = {
+    "XON/XOFF xmit", "XON/XOFF rcv", "hw xmit", "hw rcv", "transparent"
+};
+static void print_serial(cistpl_funce_t *funce)
+{
+    cistpl_serial_t *s;
+    cistpl_data_serv_t *ds;
+    cistpl_fax_serv_t *fs;
+    cistpl_modem_cap_t *cp;
+    int i, j;
+    
+    switch (funce->type & 0x0f) {
+    case CISTPL_FUNCE_SERIAL_IF:
+    case CISTPL_FUNCE_SERIAL_IF_DATA:
+    case CISTPL_FUNCE_SERIAL_IF_FAX:
+    case CISTPL_FUNCE_SERIAL_IF_VOICE:
+	s = (cistpl_serial_t *)(funce->data);
+	printf("%sserial_interface", indent);
+	if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_DATA)
+	    printf("_data");
+	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_FAX)
+	    printf("_fax");
+	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_VOICE)
+	    printf("_voice");
+	printf("\n%s  uart %s", indent,
+	       (s->uart_type < 6) ? uart[s->uart_type] : "reserved");
+	if (s->uart_cap_0) {
+	    printf(" [");
+	    for (i = 0; i < 4; i++)
+	        if (s->uart_cap_0 & (1<<i))
+		    printf("%s%s", parity[i],
+			   (s->uart_cap_0 >= (2<<i)) ? "/" : "]");
+	}
+	if (s->uart_cap_1) {
+	    int m = s->uart_cap_1 & 0x0f;
+	    int n = s->uart_cap_1 >> 4;
+	    printf(" [");
+	    for (i = 0; i < 4; i++)
+		if (m & (1<<i))
+		    printf("%d%s", i+5, (m >= (2<<i)) ? "/" : "");
+	    printf("] [");
+	    for (i = 0; i < 3; i++)
+	        if (n & (1<<i))
+		    printf("%s%s", stop[i], (n >= (2<<i)) ? "/" : "]");
+	}
+	printf("\n");
+	break;
+    case CISTPL_FUNCE_SERIAL_CAP:
+    case CISTPL_FUNCE_SERIAL_CAP_DATA:
+    case CISTPL_FUNCE_SERIAL_CAP_FAX:
+    case CISTPL_FUNCE_SERIAL_CAP_VOICE:
+	cp = (cistpl_modem_cap_t *)(funce->data);
+	printf("%sserial_modem_cap", indent);
+	if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_DATA)
+	    printf("_data");
+	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_FAX)
+	    printf("_fax");
+	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_VOICE)
+	    printf("_voice");
+	if (cp->flow) {
+	    printf("\n%s  flow", indent);
+	    for (i = 0; i < 5; i++)
+		if (cp->flow & (1<<i))
+		    printf(" [%s]", flow[i]);
+	}
+	printf("\n%s  cmd_buf %d rcv_buf %d xmit_buf %d\n",
+	       indent, 4*(cp->cmd_buf+1),
+	       cp->rcv_buf_0+(cp->rcv_buf_1<<8)+(cp->rcv_buf_2<<16),
+	       cp->xmit_buf_0+(cp->xmit_buf_1<<8)+(cp->xmit_buf_2<<16));
+	break;
+    case CISTPL_FUNCE_SERIAL_SERV_DATA:
+	ds = (cistpl_data_serv_t *)(funce->data);
+	printf("%sserial_data_services\n", indent);
+	printf("%s  data_rate %d\n", indent,
+	       75*((ds->max_data_0<<8) + ds->max_data_1));
+	printf("%s  modulation", indent);
+	for (i = j = 0; i < 16; i++)
+	    if (((ds->modulation_1<<8) + ds->modulation_0) & (1<<i)) {
+		if (++j % 6 == 0)
+		    printf("\n%s   ", indent);
+		printf(" [%s]", data_mod[i]);
+	    }
+	printf("\n");
+	if (ds->error_control) {
+	    printf("%s  error_control", indent);
+	    if (ds->error_control & CISTPL_SERIAL_ERR_MNP2_4)
+		printf(" [MNP2-4]");
+	    if (ds->error_control & CISTPL_SERIAL_ERR_V42_LAPM)
+		printf(" [V.42/LAPM]");
+	    printf("\n");
+	}
+	if (ds->compression) {
+	    printf("%s  compression", indent);
+	    if (ds->compression & CISTPL_SERIAL_CMPR_V42BIS)
+		printf(" [V.42bis]");
+	    if (ds->compression & CISTPL_SERIAL_CMPR_MNP5)
+		printf(" [MNP5]");
+	    printf("\n");
+	}
+	if (ds->cmd_protocol) {
+	    printf("%s  cmd_protocol", indent);
+	    for (i = 0; i < 7; i++)
+		if (ds->cmd_protocol & (1<<i))
+		    printf(" [%s]", cmd_protocol[i]);
+	    printf("\n");
+	}
+	break;
+	
+    case CISTPL_FUNCE_SERIAL_SERV_FAX:
+	fs = (cistpl_fax_serv_t *)(funce->data);
+	printf("%sserial_fax_services [class=%d]\n",
+	       indent, funce->type>>4);
+	printf("%s  data_rate %d\n", indent,
+	       75*((fs->max_data_0<<8) + fs->max_data_1));
+	printf("%s  modulation", indent);
+	for (i = 0; i < 8; i++)
+	    if (fs->modulation & (1<<i))
+		printf(" [%s]", fax_mod[i]);
+	printf("\n");
+	if (fs->features_0) {
+	    printf("%s  features", indent);
+	    for (i = 0; i < 8; i++)
+		if (fs->features_0 & (1<<i))
+		    printf(" [%s]", fax_features[i]);
+	    printf("\n");
+	}
+	break;
+    }
+}
+
+/*====================================================================*/
+
+static void print_fixed(cistpl_funce_t *funce)
+{
+    cistpl_ide_interface_t *i;
+    cistpl_ide_feature_t *f;
+    
+    switch (funce->type) {
+    case CISTPL_FUNCE_IDE_IFACE:
+	i = (cistpl_ide_interface_t *)(funce->data);
+	printf("%sdisk_interface ", indent);
+	if (i->interface == CISTPL_IDE_INTERFACE)
+	    printf("[ide]\n");
+	else
+	    printf("[undefined]\n");
+	break;
+    case CISTPL_FUNCE_IDE_MASTER:
+    case CISTPL_FUNCE_IDE_SLAVE:
+	f = (cistpl_ide_feature_t *)(funce->data);
+	printf("%sdisk_features", indent);
+	if (f->feature1 & CISTPL_IDE_SILICON)
+	    printf(" [silicon]");
+	else
+	    printf(" [rotating]");
+	if (f->feature1 & CISTPL_IDE_UNIQUE)
+	    printf(" [unique]");
+	if (f->feature1 & CISTPL_IDE_DUAL)
+	    printf(" [dual]");
+	else
+	    printf(" [single]");
+	if (f->feature1 && f->feature2)
+	    printf("\n%s ", indent);
+	if (f->feature2 & CISTPL_IDE_HAS_SLEEP)
+	    printf(" [sleep]");
+	if (f->feature2 & CISTPL_IDE_HAS_STANDBY)
+	    printf(" [standby]");
+	if (f->feature2 & CISTPL_IDE_HAS_IDLE)
+	    printf(" [idle]");
+	if (f->feature2 & CISTPL_IDE_LOW_POWER)
+	    printf(" [low power]");
+	if (f->feature2 & CISTPL_IDE_REG_INHIBIT)
+	    printf(" [reg inhibit]");
+	if (f->feature2 & CISTPL_IDE_HAS_INDEX)
+	    printf(" [index]");
+	if (f->feature2 & CISTPL_IDE_IOIS16)
+	    printf(" [iois16]");
+	putchar('\n');
+	break;
+    }
+}
+
+/*====================================================================*/
+
+static const char *tech[] = {
+    "undefined", "ARCnet", "ethernet", "token_ring", "localtalk",
+    "FDDI/CDDI", "ATM", "wireless"
+};
+
+static const char *media[] = {
+    "undefined", "unshielded_twisted_pair", "shielded_twisted_pair",
+    "thin_coax", "thick_coax", "fiber", "900_MHz", "2.4_GHz",
+    "5.4_GHz", "diffuse_infrared", "point_to_point_infrared"
+};
+
+static void print_network(cistpl_funce_t *funce)
+{
+    cistpl_lan_tech_t *t;
+    cistpl_lan_speed_t *s;
+    cistpl_lan_media_t *m;
+    cistpl_lan_node_id_t *n;
+    cistpl_lan_connector_t *c;
+    int i;
+    
+    switch (funce->type) {
+    case CISTPL_FUNCE_LAN_TECH:
+	t = (cistpl_lan_tech_t *)(funce->data);
+	printf("%slan_technology %s\n", indent, tech[t->tech]);
+	break;
+    case CISTPL_FUNCE_LAN_SPEED:
+	s = (cistpl_lan_speed_t *)(funce->data);
+	printf("%slan_speed ", indent);
+	print_speed(s->speed);
+	putchar('\n');
+	break;
+    case CISTPL_FUNCE_LAN_MEDIA:
+	m = (cistpl_lan_media_t *)(funce->data);
+	printf("%slan_media %s\n", indent, media[m->media]);
+	break;
+    case CISTPL_FUNCE_LAN_NODE_ID:
+	n = (cistpl_lan_node_id_t *)(funce->data);
+	printf("%slan_node_id", indent);
+	for (i = 0; i < n->nb; i++)
+	    printf(" %02x", n->id[i]);
+	putchar('\n');
+	break;
+    case CISTPL_FUNCE_LAN_CONNECTOR:
+	c = (cistpl_lan_connector_t *)(funce->data);
+	printf("%slan_connector ", indent);
+	if (c->code == 0)
+	    printf("Open connector standard\n");
+	else
+	    printf("Closed connector standard\n");
+	break;
+    }
+}
+
+/*====================================================================*/
+
+static void print_vers_1(cistpl_vers_1_t *v1)
+{
+    int i, n;
+    char s[32];
+    sprintf(s, "%svers_1 %d.%d", indent, v1->major, v1->minor);
+    printf("%s", s);
+    n = strlen(s);
+    for (i = 0; i < v1->ns; i++) {
+	if (n + strlen(v1->str + v1->ofs[i]) + 4 > 72) {
+	    n = strlen(indent) + 2;
+	    printf(",\n%s  ", indent);
+	} else {
+	    printf(", ");
+	    n += 2;
+	}
+	printf("\"%s\"", v1->str + v1->ofs[i]);
+	n += strlen(v1->str + v1->ofs[i]) + 2;
+    }
+    putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_vers_2(cistpl_vers_2_t *v2)
+{
+    printf("%sversion 0x%2.2x, compliance 0x%2.2x, dindex 0x%4.4x\n",
+	   indent, v2->vers, v2->comply, v2->dindex);
+    printf("%s  vspec8 0x%2.2x, vspec9 0x%2.2x, nhdr %d\n",
+	   indent, v2->vspec8, v2->vspec9, v2->nhdr);
+    printf("%s  vendor \"%s\"\n", indent, v2->str+v2->vendor);
+    printf("%s  info \"%s\"\n", indent, v2->str+v2->info);
+}
+
+/*====================================================================*/
+
+#ifdef CISTPL_FORMAT_DISK
+static void print_format(cistpl_format_t *fmt)
+{
+    if (fmt->type == CISTPL_FORMAT_DISK)
+	printf("%s  [disk]", indent);
+    else if (fmt->type == CISTPL_FORMAT_MEM)
+	printf("%s  [memory]", indent);
+    else
+	printf("%s  [type 0x%02x]\n", indent, fmt->type);
+    if (fmt->edc == CISTPL_EDC_NONE)
+	printf(" [no edc]");
+    else if (fmt->edc == CISTPL_EDC_CKSUM)
+	printf(" [cksum]");
+    else if (fmt->edc == CISTPL_EDC_CRC)
+	printf(" [crc]");
+    else if (fmt->edc == CISTPL_EDC_PCC)
+	printf(" [pcc]");
+    else
+	printf(" [edc 0x%02x]", fmt->edc);
+    printf(" offset 0x%04x length ", fmt->offset);
+    print_size(fmt->length);
+    putchar('\n');
+}
+#endif
+
+/*====================================================================*/
+
+static void print_config(int code, cistpl_config_t *cfg)
+{
+    printf("%sconfig%s base 0x%4.4x", indent,
+	   (code == CISTPL_CONFIG_CB) ? "_cb" : "",
+	   cfg->base);
+    if (code == CISTPL_CONFIG)
+	printf(" mask 0x%4.4x", cfg->rmask[0]);
+    printf(" last_index 0x%2.2x\n", cfg->last_idx);
+    if (verbose && cfg->subtuples)
+	printf("%s  %d bytes in subtuples\n", indent, cfg->subtuples);
+}
+
+/*====================================================================*/
+
+static int nfn = 0, cur = 0;
+
+static void print_parse(tuple_parse_t *tup)
+{
+    static int func = 0;
+    int i;
+    
+    switch (tup->tuple.TupleCode) {
+    case CISTPL_DEVICE:
+    case CISTPL_DEVICE_A:
+	if (tup->tuple.TupleCode == CISTPL_DEVICE)
+	    printf("%sdev_info\n", indent);
+	else
+	    printf("%sattr_dev_info\n", indent);
+	print_device(&tup->parse.device);
+	break;
+    case CISTPL_CHECKSUM:
+	printf("%schecksum 0x%04x-0x%04x = 0x%02x\n",
+	       indent, tup->parse.checksum.addr,
+	       tup->parse.checksum.addr+tup->parse.checksum.len-1,
+	       tup->parse.checksum.sum);
+	break;
+    case CISTPL_LONGLINK_A:
+	if (verbose)
+	    printf("%slong_link_attr 0x%04x\n", indent,
+		   tup->parse.longlink.addr);
+	break;
+    case CISTPL_LONGLINK_C:
+	if (verbose)
+	    printf("%slong_link 0x%04x\n", indent,
+		   tup->parse.longlink.addr);
+	break;
+    case CISTPL_LONGLINK_MFC:
+	if (verbose) {
+	    printf("%smfc_long_link\n", indent);
+	    for (i = 0; i < tup->parse.longlink_mfc.nfn; i++)
+		printf("%s function %d: %s 0x%04x\n", indent, i,
+		       tup->parse.longlink_mfc.fn[i].space ? "common" : "attr",
+		       tup->parse.longlink_mfc.fn[i].addr);
+	} else {
+	    printf("%smfc {\n", indent);
+	    nfn = tup->parse.longlink_mfc.nfn;
+	    cur = 0;
+	    strcat(indent, "  ");
+	}
+	break;
+    case CISTPL_NO_LINK:
+	if (verbose)
+	    printf("%sno_long_link\n", indent);
+	break;
+#ifdef CISTPL_INDIRECT
+    case CISTPL_INDIRECT:
+	if (verbose)
+	    printf("%sindirect_access\n", indent);
+	break;
+#endif
+    case CISTPL_LINKTARGET:
+	if (verbose)
+	    printf("%slink_target\n", indent);
+	else {
+	    if (cur++) printf("%s}, {\n", indent+2);
+	}
+	break;
+    case CISTPL_VERS_1:
+	print_vers_1(&tup->parse.version_1);
+	break;
+    case CISTPL_ALTSTR:
+	break;
+    case CISTPL_JEDEC_A:
+    case CISTPL_JEDEC_C:
+	if (tup->tuple.TupleCode == CISTPL_JEDEC_C)
+	    printf("%scommon_jedec", indent);
+	else
+	    printf("%sattr_jedec", indent);
+	print_jedec(&tup->parse.jedec);
+	break;
+    case CISTPL_DEVICE_GEO:
+    case CISTPL_DEVICE_GEO_A:
+	if (tup->tuple.TupleCode == CISTPL_DEVICE_GEO)
+	    printf("%scommon_geometry\n", indent);
+	else
+	    printf("%sattr_geometry\n", indent);
+	print_device_geo(&tup->parse.device_geo);
+	break;
+    case CISTPL_MANFID:
+	printf("%smanfid 0x%4.4x, 0x%4.4x\n", indent,
+	       tup->parse.manfid.manf, tup->parse.manfid.card);
+	break;
+    case CISTPL_FUNCID:
+	print_funcid(&tup->parse.funcid);
+	func = tup->parse.funcid.func;
+	break;
+    case CISTPL_FUNCE:
+	switch (func) {
+	case CISTPL_FUNCID_SERIAL:
+	    print_serial(&tup->parse.funce);
+	    break;
+	case CISTPL_FUNCID_FIXED:
+	    print_fixed(&tup->parse.funce);
+	    break;
+	case CISTPL_FUNCID_NETWORK:
+	    print_network(&tup->parse.funce);
+	    break;
+	}
+	break;
+    case CISTPL_BAR:
+	printf("%sBAR %d size ", indent,
+	       tup->parse.bar.attr & CISTPL_BAR_SPACE);
+	print_size(tup->parse.bar.size);
+	if (tup->parse.bar.attr & CISTPL_BAR_SPACE_IO)
+	    printf(" [io]");
+	else
+	    printf(" [mem]");
+	if (tup->parse.bar.attr & CISTPL_BAR_PREFETCH)
+	    printf(" [prefetch]");
+	if (tup->parse.bar.attr & CISTPL_BAR_CACHEABLE)
+	    printf(" [cacheable]");
+	if (tup->parse.bar.attr & CISTPL_BAR_1MEG_MAP)
+	    printf(" [<1mb]");
+	putchar('\n');
+	break;
+    case CISTPL_CONFIG:
+    case CISTPL_CONFIG_CB:
+	print_config(tup->tuple.TupleCode, &tup->parse.config);
+	break;
+    case CISTPL_CFTABLE_ENTRY:
+	print_cftable_entry(&tup->parse.cftable_entry);
+	break;
+    case CISTPL_CFTABLE_ENTRY_CB:
+	print_cftable_entry_cb(&tup->parse.cftable_entry_cb);
+	break;
+    case CISTPL_VERS_2:
+	print_vers_2(&tup->parse.vers_2);
+	break;
+    case CISTPL_ORG:
+	print_org(&tup->parse.org);
+	break;
+#ifdef CISTPL_FORMAT_DISK
+    case CISTPL_FORMAT:
+    case CISTPL_FORMAT_A:
+	if (tup->tuple.TupleCode == CISTPL_FORMAT)
+	    printf("%scommon_format\n", indent);
+	else
+	    printf("%sattr_format\n", indent);
+	print_format(&tup->parse.format);
+#endif
+    }
+}
+
+/*====================================================================*/
+
+static int get_tuple_buf(int fd, ds_ioctl_arg_t *arg, int first)
+{
+    u_int ofs;
+    static int nb = 0;
+    static u_char buf[1024];
+    
+    if (first) {
+	nb = read(fd, buf, sizeof(buf));
+	arg->tuple.TupleLink = arg->tuple.CISOffset = 0;
+    }
+    ofs = arg->tuple.CISOffset + arg->tuple.TupleLink;
+    if (ofs >= nb) return -1;
+    arg->tuple.TupleCode = buf[ofs++];
+    arg->tuple.TupleDataLen = arg->tuple.TupleLink = buf[ofs++];
+    arg->tuple.CISOffset = ofs;
+    memcpy(arg->tuple_parse.data, buf+ofs, arg->tuple.TupleLink);
+    return 0;
+}
+
+static int get_tuple(int fd, ds_ioctl_arg_t *arg, int first)
+{
+    int cmd = (first) ? DS_GET_FIRST_TUPLE : DS_GET_NEXT_TUPLE;
+    if (ioctl(fd, cmd, arg) != 0) {
+	if (errno == ENODEV)
+	    printf("%sno card\n", indent);
+	else if (errno != ENODATA)
+	    printf("%sget tuple: %s\n", indent, strerror(errno));
+	return -1;
+    }
+    if (ioctl(fd, DS_GET_TUPLE_DATA, arg) != 0) {
+	printf("%sget tuple data: %s\n", indent, strerror(errno));
+	return -1;
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+#define MAX_SOCKS 8
+
+int main(int argc, char *argv[])
+{
+    int i, fd, pfd = -1;
+    ds_ioctl_arg_t arg;
+    int optch, errflg, first;
+    int force = 0;
+    char *infile = NULL;
+
+    errflg = 0;
+    while ((optch = getopt(argc, argv, "fvi:")) != -1) {
+	switch (optch) {
+	case 'f':
+	    force = 1; break;
+	case 'v':
+	    verbose = 1; break;
+	case 'i':
+	    infile = strdup(optarg); break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind < argc)) {
+	fprintf(stderr, "usage: %s [-v] [-f] [-i infile]\n", argv[0]);
+	exit(EXIT_FAILURE);
+    }
+    
+    major = lookup_dev("pcmcia");
+    if (major < 0) {
+	fprintf(stderr, "no pcmcia driver in /proc/devices\n");
+	exit(EXIT_FAILURE);
+    }
+    
+    for (i = 0; (i < MAX_SOCKS) && !(i && infile); i++) {
+	nfn = cur = 0;
+	if (infile) {
+	    indent[0] = '\0';
+	    fd = open(infile, O_RDONLY);
+	    if (fd < 0) {
+		perror("open()");
+		return -1;
+	    }
+	    pfd = open_sock(0);
+	} else {
+	    strcpy(indent, "  ");
+	    fd = pfd = open_sock(i);
+	}
+	if (pfd < 0)
+	    break;
+	if (!verbose && (i > 0)) putchar('\n');
+	if (!infile) printf("Socket %d:\n", i);
+	
+	if (!force && !infile) {
+	    if (ioctl(fd, DS_VALIDATE_CIS, &arg) != 0) {
+		printf("%svalidate CIS: %s\n", indent, strerror(errno));
+		continue;
+	    }
+	    if (arg.cisinfo.Chains == 0) {
+		printf("%sno CIS present\n", indent);
+		continue;
+	    }
+	}
+	
+	arg.tuple.TupleDataMax = sizeof(arg.tuple_parse.data);
+	arg.tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+	arg.tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+	arg.tuple.TupleOffset = 0;
+
+	for (first = 1; ; first = 0) {
+	    if (infile) {
+		if (get_tuple_buf(fd, &arg, first) != 0) break;
+	    } else {
+		if (get_tuple(fd, &arg, first) != 0) break;
+	    }
+	    if (verbose) print_tuple(&arg.tuple_parse);
+	    if (ioctl(pfd, DS_PARSE_TUPLE, &arg) == 0)
+		print_parse(&arg.tuple_parse);
+	    else if (errno != ENOSYS)
+		printf("%sparse error: %s\n", indent,
+		       strerror(errno));
+	    if (verbose) putchar('\n');
+	    if (arg.tuple.TupleCode == CISTPL_END)
+		break;
+	}
+	
+	if (!verbose && (nfn > 0))
+	    printf("%s}\n", indent+2);
+    }
+    if ((i == 0) && (pfd < 0)) {
+	perror("open()");
+	return -1;
+    }
+    
+    return 0;
+}
diff --git a/lex_cis.l b/lex_cis.l
new file mode 100644
index 0000000..92316aa
--- /dev/null
+++ b/lex_cis.l
@@ -0,0 +1,234 @@
+/* Special state for handling include files */
+%x src
+
+%{
+/*
+ * lex_cis.l 1.15 2001/08/24 12:21:41
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#undef src
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#define src 1
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cistpl.h>
+
+#include "pack_cis.h"
+#include "yacc_cis.h"
+
+/* For assembling nice error messages */
+int current_lineno;
+
+static int lex_number(char *);
+static int lex_units(char *, int, int);
+static int lex_float(char *);
+static int lex_string(char *);
+
+%}
+
+int	[0-9]+
+hex	0x[0-9a-fA-F]+
+flt	[0-9]+\.[0-9]*
+str	\"([^"]|\\.)*\"
+
+%%
+
+\n		current_lineno++;
+[ \t]*		/* skip */ ;
+[ ]*[#;].*	/* skip */ ;
+
+funcid		return FUNCID;
+mfc		return MFC;
+manfid		return MANFID;
+vers_1		return VERS_1;
+checksum	return CHECKSUM;
+
+common_jedec	return CJEDEC;
+attr_jedec	return AJEDEC;
+
+dev_info	return DEV_INFO;
+attr_dev_info	return ATTR_DEV_INFO;
+no_info		return NO_INFO;
+NULL		return lex_number("0");
+ROM		return lex_number("1");
+EPROM		return lex_number("3");
+EEPROM		return lex_number("4");
+FLASH		return lex_number("5");
+SRAM		return lex_number("6");
+DRAM		return lex_number("7");
+fn_specific	return lex_number("13");
+
+config		return CONFIG;
+base		return BASE;
+mask		return MASK;
+last_index	return LAST_INDEX;
+\[post\]	return POST;
+\[rom\]		return ROM;
+
+cftable_entry	return CFTABLE;
+\[default\]	return DEFAULT;
+\[bvd\]		return BVD;
+\[wp\]		return WP;
+\[rdybsy\]	return RDYBSY;
+\[mwait\]	return MWAIT;
+\[audio\]	return AUDIO;
+\[readonly\]	return READONLY;
+\[pwrdown\]	return PWRDOWN;
+
+Vcc		return VCC;
+Vpp1		return VPP1;
+Vpp2		return VPP2;
+Vnom		return VNOM;
+Vmin		return VMIN;
+Vmax		return VMAX;
+Istatic		return ISTATIC;
+Iavg		return IAVG;
+Ipeak		return IPEAK;
+Idown		return IDOWN;
+
+io		return IO;
+memory		return MEM;
+\[8bit\]	return BIT8;
+\[16bit\]	return BIT16;
+\[lines		return LINES;
+\[range\]	return RANGE;
+
+irq		return IRQ_NO;
+\[level\]	return LEVEL;
+\[pulse\]	return PULSE;
+\[shared\]	return SHARED;
+
+timing		return TIMING;
+wait		return WAIT;
+ready		return READY;
+reserved	return RESERVED;
+
+multi_function	return lex_number("0");
+memory_card	return lex_number("1");
+serial_port	return lex_number("2");
+parallel_port	return lex_number("3");
+fixed_disk	return lex_number("4");
+video_adapter	return lex_number("5");
+network_adapter	return lex_number("6");
+aims_card	return lex_number("7");
+scsi_adapter	return lex_number("8");
+
+{int}		return lex_number(yytext);
+{hex}		return lex_number(yytext);
+
+{int}b		return lex_units(yytext, 1, SIZE);
+{int}kb		return lex_units(yytext, 1024, SIZE);
+{int}mb		return lex_units(yytext, 1024*1024, SIZE);
+
+{flt}s		return lex_units(yytext, 1000000000, TIME);
+{flt}ms		return lex_units(yytext, 1000000, TIME);
+{flt}us		return lex_units(yytext, 1000, TIME);
+{flt}ns		return lex_units(yytext, 1, TIME);
+{int}s		return lex_units(yytext, 1000000000, TIME);
+{int}ms		return lex_units(yytext, 1000000, TIME);
+{int}us		return lex_units(yytext, 1000, TIME);
+{int}ns		return lex_units(yytext, 1, TIME);
+
+{flt}V		return lex_units(yytext, 100000, VOLTAGE);
+{flt}mV		return lex_units(yytext, 100, VOLTAGE);
+{flt}uV		return lex_units(yytext, 0.1, VOLTAGE);
+{int}V		return lex_units(yytext, 100000, VOLTAGE);
+{int}mV		return lex_units(yytext, 100, VOLTAGE);
+{int}uV		return lex_units(yytext, 0.1, VOLTAGE);
+
+{flt}A		return lex_units(yytext, 10000000, CURRENT);
+{flt}mA		return lex_units(yytext, 10000, CURRENT);
+{flt}uA		return lex_units(yytext, 10, CURRENT);
+{int}A		return lex_units(yytext, 10000000, CURRENT);
+{int}mA		return lex_units(yytext, 10000, CURRENT);
+{int}uA		return lex_units(yytext, 10, CURRENT);
+
+{flt}		return lex_float(yytext);
+
+{str}		return lex_string(yytext);
+
+.		return yytext[0];
+
+%%
+
+#ifndef yywrap
+int yywrap() { return 1; }
+#endif
+
+/*======================================================================
+
+    Stuff to parse basic data types
+
+======================================================================*/
+
+static int lex_number(char *s)
+{
+    yylval.num = strtoul(s, NULL, 0);
+    return NUMBER;
+}
+
+static int lex_float(char *s)
+{
+    yylval.flt = strtod(s, NULL);
+    return FLOAT;
+}
+
+static int lex_units(char *s, int scale, int token)
+{
+    float f;
+    sscanf(s, "%f", &f);
+    yylval.num = scale*f + 0.5;
+    return token;
+}
+
+static int lex_string(char *s)
+{
+    int n = strlen(s);
+    yylval.str = malloc(n-1);
+    strncpy(yylval.str, s+1, n-2);
+    yylval.str[n-2] = '\0';
+    return STRING;
+}
+
+/*======================================================================
+
+    The main parser entry point
+
+======================================================================*/
+
+void parse_cis(FILE *f)
+{
+    current_lineno = 1;
+    yyrestart(f);
+    yyparse();
+    fclose(f);
+}
+
diff --git a/pack_cis.c b/pack_cis.c
new file mode 100644
index 0000000..67ebbba
--- /dev/null
+++ b/pack_cis.c
@@ -0,0 +1,447 @@
+/*======================================================================
+
+    A utility to convert a plain text description of a Card
+    Information Structure into its packed binary representation.
+
+    pack_cis.c 1.20 2002/10/16 16:38:18
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+
+    Usage:
+
+    pack_cis [-o outfile] [infile]
+
+    [infile] defaults to stdin, and [outfile] defaults to stdout.
+    
+======================================================================*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+
+#include "pack_cis.h"
+
+tuple_info_t *cis_root = NULL, *mfc[8] = { NULL };
+int nf = 0;
+
+/*======================================================================
+
+    Support routines for packing parts of configuration table entries
+    
+======================================================================*/
+
+static u_int mantissa[] = {
+    10, 12, 13, 15, 20, 25, 30, 35,
+    40, 45, 50, 55, 60, 70, 80, 90
+};
+static int pack_power(cistpl_power_t *pwr, u_char *b)
+{
+    u_int tmp, i;
+    u_char m, e, x, *c = b;
+    *c = pwr->present; c++;
+    for (i = 0; i < 7; i++) {
+	if (!(pwr->present & (1<<i)))
+	    continue;
+	tmp = pwr->param[i];
+	for (e = 1; ((tmp % 10) == 0) || (tmp > 999); e++)
+	    tmp /= 10;
+	x = m = 0;
+	if (tmp < 100) {
+	    if (tmp < 10) { tmp *= 10; e--; }
+	    for (m = 0; m < 16; m++)
+		if (mantissa[m] == tmp) break;
+	    if (m == 16) { tmp *= 10; e--; }
+	}
+	if (tmp >= 100) {
+	    e++;
+	    x = (tmp/10) - ((tmp/10) % 10);
+	    for (m = 0; m < 16; m++)
+		if (mantissa[m] == x) break;
+	    x = (u_char)(tmp - 10*(u_int)x);
+	}
+	*c = (m<<3) | e | (x ? 0x80 : 0); c++;
+	if (x) { *c = x; c++; }
+    }
+    return c-b;
+}
+
+static int pack_io(cistpl_io_t *p, u_char *b)
+{
+    u_char *c = b;
+    u_int i, j, ml, ma;
+    *c = p->flags & (CISTPL_IO_8BIT|CISTPL_IO_16BIT);
+    if ((p->nwin == 1) && (p->win[0].base == 0)) {
+	for (i = 1, j = 0; i < p->win[0].len; i *= 2, j++) ;
+	*c |= j; c++;
+    } else {
+	for (i = ma = ml = 0; i < p->nwin; i++) {
+	    ma |= p->win[i].base;
+	    ml |= p->win[i].len-1;
+	}
+	ma = (ma > 0xffff) ? 3 : ((ma > 0xff) ? 2 : 1);
+	ml = (ml > 0xffff) ? 3 : ((ml > 0xff) ? 2 : 1);
+	*c |= 0x80 | (p->flags & CISTPL_IO_LINES_MASK); c++;
+	*c = (p->nwin-1) | (ma<<4) | (ml<<6); c++;
+	if (ma == 3) ma++; if (ml == 3) ml++;
+	for (i = 0; i < p->nwin; i++) {
+	    for (j = 0; j < ma; j++) {
+		*c = (p->win[i].base >> (8*j)) & 0xff; c++;
+	    }
+	    for (j = 0; j < ml; j++) {
+		*c = ((p->win[i].len-1) >> (8*j)) & 0xff; c++;
+	    }
+	}
+    }
+    return c-b;
+}
+
+static int pack_mem(cistpl_mem_t *p, u_char *b)
+{
+    u_char *c = b;
+    u_int i, j, ml, ma, ha;
+    for (i = ma = ml = ha = 0; i < p->nwin; i++) {
+	ma |= p->win[i].card_addr;
+	ml |= p->win[i].len;
+	ha |= p->win[i].host_addr;
+    }
+    ma = (ma|ha) >> 8; ml >>= 8;
+    ma = (ma > 0xffff) ? 3 : ((ma > 0xff) ? 2 : 1);
+    ml = (ml > 0xffff) ? 3 : ((ml > 0xff) ? 2 : 1);
+    *c = (p->nwin-1) | (ma<<5) | (ml<<3) | (ha ? 0x80 : 0); c++;
+    for (i = 0; i < p->nwin; i++) {
+	for (j = 1; j <= ml; j++) {
+	    *c = (p->win[i].len >> (8*j)) & 0xff; c++;
+	}
+	for (j = 1; j <= ma; j++) {
+	    *c = (p->win[i].card_addr >> (8*j)) & 0xff; c++;
+	}
+	if (ha)
+	    for (j = 1; j <= ma; j++) {
+		*c = (p->win[i].host_addr >> (8*j)) & 0xff; c++;
+	    }
+    }
+    return c-b;
+}
+
+static int pack_irq(cistpl_irq_t *p, u_char *b)
+{
+    b[0] = p->IRQInfo1;
+    if (p->IRQInfo1 & IRQ_INFO2_VALID) {
+	b[1] = p->IRQInfo2 & 0xff;
+	b[2] = (p->IRQInfo2 >> 8) & 0xff;
+	return 3;
+    }
+    return 1;
+}
+
+static void pack_cftable(cistpl_cftable_entry_t *p, u_char *b)
+{
+    u_char *c;
+    b[2] = p->index | 0x80;
+    if (p->flags & CISTPL_CFTABLE_DEFAULT)
+	b[2] |= 0x40;
+    b[3] = 0x01;
+    b[3] |= (p->flags & CISTPL_CFTABLE_BVDS) ? 0x10 : 0;
+    b[3] |= (p->flags & CISTPL_CFTABLE_WP) ? 0x20 : 0;
+    b[3] |= (p->flags & CISTPL_CFTABLE_RDYBSY) ? 0x40 : 0;
+    b[3] |= (p->flags & CISTPL_CFTABLE_MWAIT) ? 0x80 : 0;
+    b[4] = 0;
+    c = b+5;
+    if (p->vcc.present) {
+	b[4]++; c += pack_power(&p->vcc, c);
+	if (p->vpp1.present) {
+	    b[4]++; c += pack_power(&p->vpp1, c);
+	    if (p->vpp2.present) {
+		b[4]++; c += pack_power(&p->vpp2, c);
+	    }
+	}
+    }
+    if (p->io.nwin > 0) {
+	b[4] |= 0x08;
+	c += pack_io(&p->io, c);
+    }
+    if (p->irq.IRQInfo1 > 0) {
+	b[4] |= 0x10;
+	c += pack_irq(&p->irq, c);
+    }
+    if (p->mem.nwin > 0) {
+	b[4] |= 0x60;
+	c += pack_mem(&p->mem, c);
+    }
+    if (p->flags >> 8) {
+	b[4] |= 0x80;
+	*c++ = p->flags >> 8;
+    }
+    b[1] = c-b-2;
+}
+
+/*======================================================================
+
+    Routines for packing device info tuples
+    
+======================================================================*/
+
+static int pack_speed(u_int speed, u_char *b)
+{
+    u_char e, m, *c = b;
+    switch (speed) {
+    case 0:	*c |= 0; c++; break;
+    case 250:	*c |= 1; c++; break;
+    case 200:	*c |= 2; c++; break;
+    case 150:	*c |= 3; c++; break;
+    case 100:	*c |= 4; c++; break;
+    default:
+	*c |= 7; c++;
+	for (e = 1; speed > 80; e++)
+	    speed /= 10;
+	for (m = 0; m < 15; m++)
+	    if (mantissa[m] >= speed) break;
+	*c = ((m+1)<<3) | e; c++;
+    }
+    return c-b;
+}
+
+static void pack_device(cistpl_device_t *d, u_char *b)
+{
+    u_int i, sz;
+    u_char e, *c = b+2;
+    for (i = 0; i < d->ndev; i++) {
+	*c = (d->dev[i].type<<4);
+	c += pack_speed(d->dev[i].speed, c);
+	sz = d->dev[i].size/512;
+	for (e = 0; sz > 32; e++)
+	    sz /= 4;
+	*c = (e & 7) | ((sz-1) << 3); c++;
+    }
+    *c = 0xff; c++;
+    b[1] = c-b-2;
+}
+
+/*======================================================================
+
+    For now, I only implement a subset of tuples types, intended to be
+    enough to handle most IO-oriented cards.
+    
+======================================================================*/
+
+static int pack_tuple(tuple_info_t *t, u_char *b)
+{
+    cisparse_t *p = t->parse;
+    u_int i, m;
+    u_char *c;
+
+    *b = t->type;
+    switch (t->type) {
+    case CISTPL_DEVICE:
+    case CISTPL_DEVICE_A:
+	if (p) {
+	    pack_device(&p->device, b);
+	} else {
+	    /* Fake null device tuple */
+	    b[1] = 3; b[2] = 0; b[3] = 0; b[4] = 0xff;
+	}
+	break;
+    case CISTPL_MANFID:
+	b[1] = 4;
+	b[2] = p->manfid.manf & 0xff;
+	b[3] = p->manfid.manf >> 8;
+	b[4] = p->manfid.card & 0xff;
+	b[5] = p->manfid.card >> 8;
+	break;
+    case CISTPL_FUNCID:
+	b[1] = 2;
+	b[2] = p->funcid.func;
+	b[3] = p->funcid.sysinit;
+	break;
+    case CISTPL_JEDEC_C:
+    case CISTPL_JEDEC_A:
+	b[1] = 2*p->jedec.nid;
+	for (i = 0; i < p->jedec.nid; i++) {
+	    b[2*i+1] = p->jedec.id[i].mfr;
+	    b[2*i+2] = p->jedec.id[i].info;
+	}
+	break;
+    case CISTPL_CONFIG:
+	b[3] = p->config.last_idx;
+	i = p->config.base;
+	for (c = b+4, m = 0; (i > 0) || !m; i >>= 8, m++) {
+	    c[m] = i & 0xff;
+	}
+	b[2] = m-1;
+	i = p->config.rmask[0];
+	for (c = c+m, m = 0; (i > 0) || !m; i >>= 8, m++) {
+	    c[m] = i & 0xff;
+	}
+	b[2] |= ((m-1) << 2);
+	b[1] = c+m-b-2;
+	break;
+    case CISTPL_VERS_1:
+	b[2] = p->version_1.major;
+	b[3] = p->version_1.minor;
+	c = b+4;
+	for (i = 0; i < p->version_1.ns; i++) {
+	    strcpy((char *)c, p->version_1.str+p->version_1.ofs[i]);
+	    c += strlen((char *)c) + 1;
+	}
+	for (; i < 4; i++) { *c = 0; c++; }
+	*c = 0xff; c++;
+	b[1] = c-b-2;
+	break;
+    case CISTPL_CFTABLE_ENTRY:
+	pack_cftable(&p->cftable_entry, b);
+	break;
+    case CISTPL_LINKTARGET:
+	b[1] = 3; b[2] = 'C'; b[3] = 'I'; b[4] = 'S';
+	break;
+    case CISTPL_NO_LINK:
+    case CISTPL_END:
+	b[1] = 0;
+	break;
+    }
+    return b[1]+2;
+}
+
+/*======================================================================
+
+    The following routines handle parsing of aggregates of tuples.
+    pack_chain() is the simplest: just return a string of tuples and
+    terminate with an END tuple.  pack_mfc() is used to tie the
+    function-specific tuple chains for a multifunction card together
+    using a LONGLINK_MFC tuple.  And pack_cis() handles a complete
+    CIS, whether it is multifunction or not.
+    
+======================================================================*/
+
+static int pack_chain(tuple_info_t *t, u_char *b)
+{
+    int n = 0;
+    tuple_info_t end = { CISTPL_END, NULL, NULL };
+    while (t) {
+	n += pack_tuple(t, b+n);
+	t = t->next;
+    }
+    n += pack_tuple(&end, b+n);
+    return n;
+}
+
+static int pack_mfc(u_int ofs, u_char *b)
+{
+    u_int i, j, pos;
+    tuple_info_t target = { CISTPL_LINKTARGET, NULL, NULL };
+    
+    b[0] = CISTPL_LONGLINK_MFC;
+    b[1] = 5*nf + 1;
+    b[2] = nf;
+    b[5*nf+3] = CISTPL_END;
+    b[5*nf+4] = 0;
+    /* Leave space for this tuple and the CISTPL_END tuple */
+    pos = 5*nf+5;
+    for (i = 0; i < nf; i++) {
+	b[3+i*5] = 0;
+	for (j = 0; j < 4; j++)
+	    b[4+i*5+j] = ((ofs+pos) >> (8*j)) & 0xff;
+	pos += pack_tuple(&target, b+pos);
+	pos += pack_chain(mfc[i], b+pos);
+    }
+    return ofs+pos;
+}
+
+static int pack_cis(tuple_info_t *t, u_char *b)
+{
+    int n = 0;
+    tuple_info_t device = { CISTPL_DEVICE, NULL, NULL };
+    tuple_info_t nolink = { CISTPL_NO_LINK, NULL, NULL };
+    tuple_info_t end = { CISTPL_END, NULL, NULL };
+    if (t->type != CISTPL_DEVICE)
+	n = pack_tuple(&device, b);
+    while (t) {
+	n += pack_tuple(t, b+n);
+	t = t->next;
+    }
+    if (nf > 0) {
+	n = pack_mfc(n, b+n);
+    } else {
+	n += pack_tuple(&nolink, b+n);
+	n += pack_tuple(&end, b+n);
+    }
+     return n;
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int optch, errflg = 0;
+    char *out = NULL;
+    u_char buf[1024];
+    int n;
+    FILE *f;
+
+    while ((optch = getopt(argc, argv, "o:")) != -1) {
+	switch (optch) {
+	case 'o':
+	    out = strdup(optarg); break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind < argc-1)) {
+	fprintf(stderr, "usage: %s [-o outfile] [infile]\n",
+		argv[0]);
+	exit(EXIT_FAILURE);
+    }
+    if (optind < argc) {
+	f = fopen(argv[optind], "r");
+	if (!f) {
+	    fprintf(stderr, "could not open '%s': %s\n", argv[optind],
+		    strerror(errno));
+	    return -1;
+	}
+    } else
+	f = stdin;
+    parse_cis(f);
+    fclose(f);
+    n = pack_cis(cis_root, buf);
+    if (out) {
+	f = fopen(out, "w");
+	if (!f) {
+	    fprintf(stderr, "could not open '%s': %s\n", out,
+		    strerror(errno));
+	    return -1;
+	}
+    } else f = stdout;
+    fwrite(buf, n, 1, f);
+    fclose(f);
+    
+    return 0;
+}
diff --git a/pack_cis.h b/pack_cis.h
new file mode 100644
index 0000000..c212444
--- /dev/null
+++ b/pack_cis.h
@@ -0,0 +1,38 @@
+/*
+ * pack_cis.h 1.7 2001/08/24 12:16:45
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+typedef struct tuple_info_t {
+    u_char		type;
+    cisparse_t		*parse;
+    struct tuple_info_t	*next;
+} tuple_info_t;
+
+extern tuple_info_t *cis_root, *mfc[8];
+extern int nf;
+
+void parse_cis(FILE *f);
diff --git a/pcmcia/bulkmem.h b/pcmcia/bulkmem.h
new file mode 100644
index 0000000..7748d44
--- /dev/null
+++ b/pcmcia/bulkmem.h
@@ -0,0 +1,195 @@
+/*
+ * Definitions for bulk memory services
+ *
+ * bulkmem.h 1.13 2001/08/24 12:16:12
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * bulkmem.h 1.3 1995/05/27 04:49:49
+ */
+
+#ifndef _LINUX_BULKMEM_H
+#define _LINUX_BULKMEM_H
+
+/* For GetFirstRegion and GetNextRegion */
+typedef struct region_info_t {
+    u_int		Attributes;
+    u_int		CardOffset;
+    u_int		RegionSize;
+    u_int		AccessSpeed;
+    u_int		BlockSize;
+    u_int		PartMultiple;
+    u_char		JedecMfr, JedecInfo;
+    memory_handle_t	next;
+} region_info_t;
+
+#define REGION_TYPE		0x0001
+#define REGION_TYPE_CM		0x0000
+#define REGION_TYPE_AM		0x0001
+#define REGION_PREFETCH		0x0008
+#define REGION_CACHEABLE	0x0010
+#define REGION_BAR_MASK		0xe000
+#define REGION_BAR_SHIFT	13
+
+/* For OpenMemory */
+typedef struct open_mem_t {
+    u_int		Attributes;
+    u_int		Offset;
+} open_mem_t;
+
+/* Attributes for OpenMemory */
+#define MEMORY_TYPE		0x0001
+#define MEMORY_TYPE_CM		0x0000
+#define MEMORY_TYPE_AM		0x0001
+#define MEMORY_EXCLUSIVE	0x0002
+#define MEMORY_PREFETCH		0x0008
+#define MEMORY_CACHEABLE	0x0010
+#define MEMORY_BAR_MASK		0xe000
+#define MEMORY_BAR_SHIFT	13
+
+typedef struct eraseq_entry_t {
+    memory_handle_t	Handle;
+    u_char		State;
+    u_int		Size;
+    u_int		Offset;
+    void		*Optional;
+} eraseq_entry_t;
+
+typedef struct eraseq_hdr_t {
+    int			QueueEntryCnt;
+    eraseq_entry_t	*QueueEntryArray;
+} eraseq_hdr_t;
+
+#define ERASE_QUEUED		0x00
+#define ERASE_IN_PROGRESS(n)	(((n) > 0) && ((n) < 0x80))
+#define ERASE_IDLE		0xff
+#define ERASE_PASSED		0xe0
+#define ERASE_FAILED		0xe1
+
+#define ERASE_MISSING		0x80
+#define ERASE_MEDIA_WRPROT	0x84
+#define ERASE_NOT_ERASABLE	0x85
+#define ERASE_BAD_OFFSET	0xc1
+#define ERASE_BAD_TECH		0xc2
+#define ERASE_BAD_SOCKET	0xc3
+#define ERASE_BAD_VCC		0xc4
+#define ERASE_BAD_VPP		0xc5
+#define ERASE_BAD_SIZE		0xc6
+
+/* For CopyMemory */
+typedef struct copy_op_t {
+    u_int		Attributes;
+    u_int		SourceOffset;
+    u_int		DestOffset;
+    u_int		Count;
+} copy_op_t;
+
+/* For ReadMemory and WriteMemory */
+typedef struct mem_op_t {
+    u_int	Attributes;
+    u_int	Offset;
+    u_int	Count;
+} mem_op_t;
+
+#define MEM_OP_BUFFER		0x01
+#define MEM_OP_BUFFER_USER	0x00
+#define MEM_OP_BUFFER_KERNEL	0x01
+#define MEM_OP_DISABLE_ERASE	0x02
+#define MEM_OP_VERIFY		0x04
+
+/* For RegisterMTD */
+typedef struct mtd_reg_t {
+    u_int	Attributes;
+    u_int	Offset;
+    u_long	MediaID;
+} mtd_reg_t;
+
+/*
+ *  Definitions for MTD requests
+ */
+
+typedef struct mtd_request_t {
+    u_int	SrcCardOffset;
+    u_int	DestCardOffset;
+    u_int	TransferLength;
+    u_int	Function;
+    u_long	MediaID;
+    u_int	Status;
+    u_int	Timeout;
+} mtd_request_t;
+
+/* Fields in MTD Function */
+#define MTD_REQ_ACTION		0x003
+#define MTD_REQ_ERASE		0x000
+#define MTD_REQ_READ		0x001
+#define MTD_REQ_WRITE		0x002
+#define MTD_REQ_COPY		0x003
+#define MTD_REQ_NOERASE		0x004
+#define MTD_REQ_VERIFY		0x008
+#define MTD_REQ_READY		0x010
+#define MTD_REQ_TIMEOUT		0x020
+#define MTD_REQ_LAST		0x040
+#define MTD_REQ_FIRST		0x080
+#define MTD_REQ_KERNEL		0x100
+
+/* Status codes */
+#define MTD_WAITREQ	0x00
+#define MTD_WAITTIMER	0x01
+#define MTD_WAITRDY	0x02
+#define MTD_WAITPOWER	0x03
+
+/*
+ *  Definitions for MTD helper functions
+ */
+
+/* For MTDModifyWindow */
+typedef struct mtd_mod_win_t {
+    u_int	Attributes;
+    u_int	AccessSpeed;
+    u_int	CardOffset;
+} mtd_mod_win_t;
+
+/* For MTDSetVpp */
+typedef struct mtd_vpp_req_t {
+    u_char	Vpp1, Vpp2;
+} mtd_vpp_req_t;
+
+/* For MTDRDYMask */
+typedef struct mtd_rdy_req_t {
+    u_int	Mask;
+} mtd_rdy_req_t;
+
+enum mtd_helper {
+    MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow,
+    MTDSetVpp, MTDRDYMask
+};
+
+#ifdef IN_CARD_SERVICES
+extern int MTDHelperEntry(int func, void *a1, void *a2);
+#else
+extern int MTDHelperEntry(int func, ...);
+#endif
+
+#endif /* _LINUX_BULKMEM_H */
diff --git a/pcmcia/cistpl.h b/pcmcia/cistpl.h
new file mode 100644
index 0000000..1d4cac2
--- /dev/null
+++ b/pcmcia/cistpl.h
@@ -0,0 +1,604 @@
+/*
+ * cistpl.h 1.35 2001/08/24 12:16:12
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISTPL_H
+#define _LINUX_CISTPL_H
+
+#define CISTPL_NULL		0x00
+#define CISTPL_DEVICE		0x01
+#define CISTPL_LONGLINK_CB	0x02
+#define CISTPL_INDIRECT		0x03
+#define CISTPL_CONFIG_CB	0x04
+#define CISTPL_CFTABLE_ENTRY_CB	0x05
+#define CISTPL_LONGLINK_MFC	0x06
+#define CISTPL_BAR		0x07
+#define CISTPL_PWR_MGMNT	0x08
+#define CISTPL_EXTDEVICE	0x09
+#define CISTPL_CHECKSUM		0x10
+#define CISTPL_LONGLINK_A	0x11
+#define CISTPL_LONGLINK_C	0x12
+#define CISTPL_LINKTARGET	0x13
+#define CISTPL_NO_LINK		0x14
+#define CISTPL_VERS_1		0x15
+#define CISTPL_ALTSTR		0x16
+#define CISTPL_DEVICE_A		0x17
+#define CISTPL_JEDEC_C		0x18
+#define CISTPL_JEDEC_A		0x19
+#define CISTPL_CONFIG		0x1a
+#define CISTPL_CFTABLE_ENTRY	0x1b
+#define CISTPL_DEVICE_OC	0x1c
+#define CISTPL_DEVICE_OA	0x1d
+#define CISTPL_DEVICE_GEO	0x1e
+#define CISTPL_DEVICE_GEO_A	0x1f
+#define CISTPL_MANFID		0x20
+#define CISTPL_FUNCID		0x21
+#define CISTPL_FUNCE		0x22
+#define CISTPL_SWIL		0x23
+#define CISTPL_END		0xff
+/* Layer 2 tuples */
+#define CISTPL_VERS_2		0x40
+#define CISTPL_FORMAT		0x41
+#define CISTPL_GEOMETRY		0x42
+#define CISTPL_BYTEORDER	0x43
+#define CISTPL_DATE		0x44
+#define CISTPL_BATTERY		0x45
+#define CISTPL_FORMAT_A		0x47
+/* Layer 3 tuples */
+#define CISTPL_ORG		0x46
+#define CISTPL_SPCL		0x90
+
+typedef struct cistpl_longlink_t {
+    u_int	addr;
+} cistpl_longlink_t;
+
+typedef struct cistpl_checksum_t {
+    u_short	addr;
+    u_short	len;
+    u_char	sum;
+} cistpl_checksum_t;
+
+#define CISTPL_MAX_FUNCTIONS	8
+#define CISTPL_MFC_ATTR		0x00
+#define CISTPL_MFC_COMMON	0x01
+
+typedef struct cistpl_longlink_mfc_t {
+    u_char	nfn;
+    struct {
+	u_char	space;
+	u_int	addr;
+    } fn[CISTPL_MAX_FUNCTIONS];
+} cistpl_longlink_mfc_t;
+
+#define CISTPL_MAX_ALTSTR_STRINGS	4
+
+typedef struct cistpl_altstr_t {
+    u_char	ns;
+    u_char	ofs[CISTPL_MAX_ALTSTR_STRINGS];
+    char	str[254];
+} cistpl_altstr_t;
+
+#define CISTPL_DTYPE_NULL	0x00
+#define CISTPL_DTYPE_ROM	0x01
+#define CISTPL_DTYPE_OTPROM	0x02
+#define CISTPL_DTYPE_EPROM	0x03
+#define CISTPL_DTYPE_EEPROM	0x04
+#define CISTPL_DTYPE_FLASH	0x05
+#define CISTPL_DTYPE_SRAM	0x06
+#define CISTPL_DTYPE_DRAM	0x07
+#define CISTPL_DTYPE_FUNCSPEC	0x0d
+#define CISTPL_DTYPE_EXTEND	0x0e
+
+#define CISTPL_MAX_DEVICES	4
+
+typedef struct cistpl_device_t {
+    u_char	ndev;
+    struct {
+	u_char 	type;
+	u_char	wp;
+	u_int	speed;
+	u_int	size;
+    } dev[CISTPL_MAX_DEVICES];
+} cistpl_device_t;
+
+#define CISTPL_DEVICE_MWAIT	0x01
+#define CISTPL_DEVICE_3VCC	0x02
+
+typedef struct cistpl_device_o_t {
+    u_char		flags;
+    cistpl_device_t	device;
+} cistpl_device_o_t;
+
+#define CISTPL_VERS_1_MAX_PROD_STRINGS	4
+
+typedef struct cistpl_vers_1_t {
+    u_char	major;
+    u_char	minor;
+    u_char	ns;
+    u_char	ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
+    char	str[254];
+} cistpl_vers_1_t;
+
+typedef struct cistpl_jedec_t {
+    u_char	nid;
+    struct {
+	u_char	mfr;
+	u_char	info;
+    } id[CISTPL_MAX_DEVICES];
+} cistpl_jedec_t;
+
+typedef struct cistpl_manfid_t {
+    u_short	manf;
+    u_short	card;
+} cistpl_manfid_t;
+
+#define CISTPL_FUNCID_MULTI	0x00
+#define CISTPL_FUNCID_MEMORY	0x01
+#define CISTPL_FUNCID_SERIAL	0x02
+#define CISTPL_FUNCID_PARALLEL	0x03
+#define CISTPL_FUNCID_FIXED	0x04
+#define CISTPL_FUNCID_VIDEO	0x05
+#define CISTPL_FUNCID_NETWORK	0x06
+#define CISTPL_FUNCID_AIMS	0x07
+#define CISTPL_FUNCID_SCSI	0x08
+
+#define CISTPL_SYSINIT_POST	0x01
+#define CISTPL_SYSINIT_ROM	0x02
+
+typedef struct cistpl_funcid_t {
+    u_char	func;
+    u_char	sysinit;
+} cistpl_funcid_t;
+
+typedef struct cistpl_funce_t {
+    u_char	type;
+    u_char	data[0];
+} cistpl_funce_t;
+
+/*======================================================================
+
+    Modem Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_SERIAL_IF		0x00
+#define CISTPL_FUNCE_SERIAL_CAP		0x01
+#define CISTPL_FUNCE_SERIAL_SERV_DATA	0x02
+#define CISTPL_FUNCE_SERIAL_SERV_FAX	0x03
+#define CISTPL_FUNCE_SERIAL_SERV_VOICE	0x04
+#define CISTPL_FUNCE_SERIAL_CAP_DATA	0x05
+#define CISTPL_FUNCE_SERIAL_CAP_FAX	0x06
+#define CISTPL_FUNCE_SERIAL_CAP_VOICE	0x07
+#define CISTPL_FUNCE_SERIAL_IF_DATA	0x08
+#define CISTPL_FUNCE_SERIAL_IF_FAX	0x09
+#define CISTPL_FUNCE_SERIAL_IF_VOICE	0x0a
+
+/* UART identification */
+#define CISTPL_SERIAL_UART_8250		0x00
+#define CISTPL_SERIAL_UART_16450	0x01
+#define CISTPL_SERIAL_UART_16550	0x02
+#define CISTPL_SERIAL_UART_8251		0x03
+#define CISTPL_SERIAL_UART_8530		0x04
+#define CISTPL_SERIAL_UART_85230	0x05
+
+/* UART capabilities */
+#define CISTPL_SERIAL_UART_SPACE	0x01
+#define CISTPL_SERIAL_UART_MARK		0x02
+#define CISTPL_SERIAL_UART_ODD		0x04
+#define CISTPL_SERIAL_UART_EVEN		0x08
+#define CISTPL_SERIAL_UART_5BIT		0x01
+#define CISTPL_SERIAL_UART_6BIT		0x02
+#define CISTPL_SERIAL_UART_7BIT		0x04
+#define CISTPL_SERIAL_UART_8BIT		0x08
+#define CISTPL_SERIAL_UART_1STOP	0x10
+#define CISTPL_SERIAL_UART_MSTOP	0x20
+#define CISTPL_SERIAL_UART_2STOP	0x40
+
+typedef struct cistpl_serial_t {
+    u_char	uart_type;
+    u_char	uart_cap_0;
+    u_char	uart_cap_1;
+} cistpl_serial_t;
+
+typedef struct cistpl_modem_cap_t {
+    u_char	flow;
+    u_char	cmd_buf;
+    u_char	rcv_buf_0, rcv_buf_1, rcv_buf_2;
+    u_char	xmit_buf_0, xmit_buf_1, xmit_buf_2;
+} cistpl_modem_cap_t;
+
+#define CISTPL_SERIAL_MOD_103		0x01
+#define CISTPL_SERIAL_MOD_V21		0x02
+#define CISTPL_SERIAL_MOD_V23		0x04
+#define CISTPL_SERIAL_MOD_V22		0x08
+#define CISTPL_SERIAL_MOD_212A		0x10
+#define CISTPL_SERIAL_MOD_V22BIS	0x20
+#define CISTPL_SERIAL_MOD_V26		0x40
+#define CISTPL_SERIAL_MOD_V26BIS	0x80
+#define CISTPL_SERIAL_MOD_V27BIS	0x01
+#define CISTPL_SERIAL_MOD_V29		0x02
+#define CISTPL_SERIAL_MOD_V32		0x04
+#define CISTPL_SERIAL_MOD_V32BIS	0x08
+#define CISTPL_SERIAL_MOD_V34		0x10
+
+#define CISTPL_SERIAL_ERR_MNP2_4	0x01
+#define CISTPL_SERIAL_ERR_V42_LAPM	0x02
+
+#define CISTPL_SERIAL_CMPR_V42BIS	0x01
+#define CISTPL_SERIAL_CMPR_MNP5		0x02
+
+#define CISTPL_SERIAL_CMD_AT1		0x01
+#define CISTPL_SERIAL_CMD_AT2		0x02
+#define CISTPL_SERIAL_CMD_AT3		0x04
+#define CISTPL_SERIAL_CMD_MNP_AT	0x08
+#define CISTPL_SERIAL_CMD_V25BIS	0x10
+#define CISTPL_SERIAL_CMD_V25A		0x20
+#define CISTPL_SERIAL_CMD_DMCL		0x40
+
+typedef struct cistpl_data_serv_t {
+    u_char	max_data_0;
+    u_char	max_data_1;
+    u_char	modulation_0;
+    u_char	modulation_1;
+    u_char	error_control;
+    u_char	compression;
+    u_char	cmd_protocol;
+    u_char	escape;
+    u_char	encrypt;
+    u_char	misc_features;
+    u_char	ccitt_code[0];
+} cistpl_data_serv_t;
+
+typedef struct cistpl_fax_serv_t {
+    u_char	max_data_0;
+    u_char	max_data_1;
+    u_char	modulation;
+    u_char	encrypt;
+    u_char	features_0;
+    u_char	features_1;
+    u_char	ccitt_code[0];
+} cistpl_fax_serv_t;
+
+typedef struct cistpl_voice_serv_t {
+    u_char	max_data_0;
+    u_char	max_data_1;
+} cistpl_voice_serv_t;
+
+/*======================================================================
+
+    LAN Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_LAN_TECH		0x01
+#define CISTPL_FUNCE_LAN_SPEED		0x02
+#define CISTPL_FUNCE_LAN_MEDIA		0x03
+#define CISTPL_FUNCE_LAN_NODE_ID	0x04
+#define CISTPL_FUNCE_LAN_CONNECTOR	0x05
+
+/* LAN technologies */
+#define CISTPL_LAN_TECH_ARCNET		0x01
+#define CISTPL_LAN_TECH_ETHERNET	0x02
+#define CISTPL_LAN_TECH_TOKENRING	0x03
+#define CISTPL_LAN_TECH_LOCALTALK	0x04
+#define CISTPL_LAN_TECH_FDDI		0x05
+#define CISTPL_LAN_TECH_ATM		0x06
+#define CISTPL_LAN_TECH_WIRELESS	0x07
+
+typedef struct cistpl_lan_tech_t {
+    u_char	tech;
+} cistpl_lan_tech_t;
+
+typedef struct cistpl_lan_speed_t {
+    u_int	speed;
+} cistpl_lan_speed_t;
+
+/* LAN media definitions */
+#define CISTPL_LAN_MEDIA_UTP		0x01
+#define CISTPL_LAN_MEDIA_STP		0x02
+#define CISTPL_LAN_MEDIA_THIN_COAX	0x03
+#define CISTPL_LAN_MEDIA_THICK_COAX	0x04
+#define CISTPL_LAN_MEDIA_FIBER		0x05
+#define CISTPL_LAN_MEDIA_900MHZ		0x06
+#define CISTPL_LAN_MEDIA_2GHZ		0x07
+#define CISTPL_LAN_MEDIA_5GHZ		0x08
+#define CISTPL_LAN_MEDIA_DIFF_IR	0x09
+#define CISTPL_LAN_MEDIA_PTP_IR		0x0a
+
+typedef struct cistpl_lan_media_t {
+    u_char	media;
+} cistpl_lan_media_t;
+
+typedef struct cistpl_lan_node_id_t {
+    u_char	nb;
+    u_char	id[16];
+} cistpl_lan_node_id_t;
+
+typedef struct cistpl_lan_connector_t {
+    u_char	code;
+} cistpl_lan_connector_t;
+
+/*======================================================================
+
+    IDE Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_IDE_INTERFACE		0x01
+
+typedef struct cistpl_ide_interface_t {
+    u_char	interface;
+} cistpl_ide_interface_t;
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON		0x04
+#define CISTPL_IDE_UNIQUE		0x08
+#define CISTPL_IDE_DUAL			0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP		0x01
+#define CISTPL_IDE_HAS_STANDBY		0x02
+#define CISTPL_IDE_HAS_IDLE		0x04
+#define CISTPL_IDE_LOW_POWER		0x08
+#define CISTPL_IDE_REG_INHIBIT		0x10
+#define CISTPL_IDE_HAS_INDEX		0x20
+#define CISTPL_IDE_IOIS16		0x40
+
+typedef struct cistpl_ide_feature_t {
+    u_char	feature1;
+    u_char	feature2;
+} cistpl_ide_feature_t;
+
+#define CISTPL_FUNCE_IDE_IFACE		0x01
+#define CISTPL_FUNCE_IDE_MASTER		0x02
+#define CISTPL_FUNCE_IDE_SLAVE		0x03
+
+/*======================================================================
+
+    Configuration Table Entries
+
+======================================================================*/
+
+#define CISTPL_BAR_SPACE	0x07
+#define CISTPL_BAR_SPACE_IO	0x10
+#define CISTPL_BAR_PREFETCH	0x20
+#define CISTPL_BAR_CACHEABLE	0x40
+#define CISTPL_BAR_1MEG_MAP	0x80
+
+typedef struct cistpl_bar_t {
+    u_char	attr;
+    u_int	size;
+} cistpl_bar_t;
+
+typedef struct cistpl_config_t {
+    u_char	last_idx;
+    u_int	base;
+    u_int	rmask[4];
+    u_char	subtuples;
+} cistpl_config_t;
+
+/* These are bits in the 'present' field, and indices in 'param' */
+#define CISTPL_POWER_VNOM	0
+#define CISTPL_POWER_VMIN	1
+#define CISTPL_POWER_VMAX	2
+#define CISTPL_POWER_ISTATIC	3
+#define CISTPL_POWER_IAVG	4
+#define CISTPL_POWER_IPEAK	5
+#define CISTPL_POWER_IDOWN	6
+
+#define CISTPL_POWER_HIGHZ_OK	0x01
+#define CISTPL_POWER_HIGHZ_REQ	0x02
+
+typedef struct cistpl_power_t {
+    u_char	present;
+    u_char	flags;
+    u_int	param[7];
+} cistpl_power_t;
+
+typedef struct cistpl_timing_t {
+    u_int	wait, waitscale;
+    u_int	ready, rdyscale;
+    u_int	reserved, rsvscale;
+} cistpl_timing_t;
+
+#define CISTPL_IO_LINES_MASK	0x1f
+#define CISTPL_IO_8BIT		0x20
+#define CISTPL_IO_16BIT		0x40
+#define CISTPL_IO_RANGE		0x80
+
+#define CISTPL_IO_MAX_WIN	16
+
+typedef struct cistpl_io_t {
+    u_char	flags;
+    u_char	nwin;
+    struct {
+	u_int	base;
+	u_int	len;
+    } win[CISTPL_IO_MAX_WIN];
+} cistpl_io_t;
+
+typedef struct cistpl_irq_t {
+    u_int	IRQInfo1;
+    u_int	IRQInfo2;
+} cistpl_irq_t;
+
+#define CISTPL_MEM_MAX_WIN	8
+
+typedef struct cistpl_mem_t {
+    u_char	flags;
+    u_char	nwin;
+    struct {
+	u_int	len;
+	u_int	card_addr;
+	u_int	host_addr;
+    } win[CISTPL_MEM_MAX_WIN];
+} cistpl_mem_t;
+
+#define CISTPL_CFTABLE_DEFAULT		0x0001
+#define CISTPL_CFTABLE_BVDS		0x0002
+#define CISTPL_CFTABLE_WP		0x0004
+#define CISTPL_CFTABLE_RDYBSY		0x0008
+#define CISTPL_CFTABLE_MWAIT		0x0010
+#define CISTPL_CFTABLE_AUDIO		0x0800
+#define CISTPL_CFTABLE_READONLY		0x1000
+#define CISTPL_CFTABLE_PWRDOWN		0x2000
+
+typedef struct cistpl_cftable_entry_t {
+    u_char		index;
+    u_short		flags;
+    u_char		interface;
+    cistpl_power_t	vcc, vpp1, vpp2;
+    cistpl_timing_t	timing;
+    cistpl_io_t		io;
+    cistpl_irq_t	irq;
+    cistpl_mem_t	mem;
+    u_char		subtuples;
+} cistpl_cftable_entry_t;
+
+#define CISTPL_CFTABLE_MASTER		0x000100
+#define CISTPL_CFTABLE_INVALIDATE	0x000200
+#define CISTPL_CFTABLE_VGA_PALETTE	0x000400
+#define CISTPL_CFTABLE_PARITY		0x000800
+#define CISTPL_CFTABLE_WAIT		0x001000
+#define CISTPL_CFTABLE_SERR		0x002000
+#define CISTPL_CFTABLE_FAST_BACK	0x004000
+#define CISTPL_CFTABLE_BINARY_AUDIO	0x010000
+#define CISTPL_CFTABLE_PWM_AUDIO	0x020000
+
+typedef struct cistpl_cftable_entry_cb_t {
+    u_char		index;
+    u_int		flags;
+    cistpl_power_t	vcc, vpp1, vpp2;
+    u_char		io;
+    cistpl_irq_t	irq;
+    u_char		mem;
+    u_char		subtuples;
+} cistpl_cftable_entry_cb_t;
+
+typedef struct cistpl_device_geo_t {
+    u_char		ngeo;
+    struct {
+	u_char		buswidth;
+	u_int		erase_block;
+	u_int		read_block;
+	u_int		write_block;
+	u_int		partition;
+	u_int		interleave;
+    } geo[CISTPL_MAX_DEVICES];
+} cistpl_device_geo_t;
+
+typedef struct cistpl_vers_2_t {
+    u_char	vers;
+    u_char	comply;
+    u_short	dindex;
+    u_char	vspec8, vspec9;
+    u_char	nhdr;
+    u_char	vendor, info;
+    char	str[244];
+} cistpl_vers_2_t;
+
+typedef struct cistpl_org_t {
+    u_char	data_org;
+    char	desc[30];
+} cistpl_org_t;
+
+#define CISTPL_ORG_FS		0x00
+#define CISTPL_ORG_APPSPEC	0x01
+#define CISTPL_ORG_XIP		0x02
+
+typedef struct cistpl_format_t {
+    u_char	type;
+    u_char	edc;
+    u_int	offset;
+    u_int	length;
+} cistpl_format_t;
+
+#define CISTPL_FORMAT_DISK	0x00
+#define CISTPL_FORMAT_MEM	0x01
+
+#define CISTPL_EDC_NONE		0x00
+#define CISTPL_EDC_CKSUM	0x01
+#define CISTPL_EDC_CRC		0x02
+#define CISTPL_EDC_PCC		0x03
+
+typedef union cisparse_t {
+    cistpl_device_t		device;
+    cistpl_checksum_t		checksum;
+    cistpl_longlink_t		longlink;
+    cistpl_longlink_mfc_t	longlink_mfc;
+    cistpl_vers_1_t		version_1;
+    cistpl_altstr_t		altstr;
+    cistpl_jedec_t		jedec;
+    cistpl_manfid_t		manfid;
+    cistpl_funcid_t		funcid;
+    cistpl_funce_t		funce;
+    cistpl_bar_t		bar;
+    cistpl_config_t		config;
+    cistpl_cftable_entry_t	cftable_entry;
+    cistpl_cftable_entry_cb_t	cftable_entry_cb;
+    cistpl_device_geo_t		device_geo;
+    cistpl_vers_2_t		vers_2;
+    cistpl_org_t		org;
+    cistpl_format_t		format;
+} cisparse_t;
+
+typedef struct tuple_t {
+    u_int	Attributes;
+    cisdata_t 	DesiredTuple;
+    u_int	Flags;		/* internal use */
+    u_int	LinkOffset;	/* internal use */
+    u_int	CISOffset;	/* internal use */
+    cisdata_t	TupleCode;
+    cisdata_t	TupleLink;
+    cisdata_t	TupleOffset;
+    cisdata_t	TupleDataMax;
+    cisdata_t	TupleDataLen;
+    cisdata_t	*TupleData;
+} tuple_t;
+
+/* Special cisdata_t value */
+#define RETURN_FIRST_TUPLE	0xff
+
+/* Attributes for tuple calls */
+#define TUPLE_RETURN_LINK	0x01
+#define TUPLE_RETURN_COMMON	0x02
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+    u_int	Chains;
+} cisinfo_t;
+
+#define CISTPL_MAX_CIS_SIZE	0x200
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+    u_int	Length;
+    cisdata_t	Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+#endif /* LINUX_CISTPL_H */
diff --git a/pcmcia/cs.h b/pcmcia/cs.h
new file mode 100644
index 0000000..8e202c6
--- /dev/null
+++ b/pcmcia/cs.h
@@ -0,0 +1,441 @@
+/*
+ * cs.h 1.74 2001/10/04 03:15:22
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_H
+#define _LINUX_CS_H
+
+/* For AccessConfigurationRegister */
+typedef struct conf_reg_t {
+    u_char	Function;
+    u_int	Action;
+    off_t	Offset;
+    u_int	Value;
+} conf_reg_t;
+
+/* Actions */
+#define CS_READ		1
+#define CS_WRITE	2
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+    u_int	Action;
+    u_int	Resource;
+    u_int	Attributes;
+    union {
+	struct memory {
+	    u_long	Base;
+	    u_long	Size;
+	} memory;
+	struct io {
+	    ioaddr_t	BasePort;
+	    ioaddr_t	NumPorts;
+	    u_int	IOAddrLines;
+	} io;
+	struct irq {
+	    u_int	IRQ;
+	} irq;
+    } resource;
+} adjust_t;
+
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE		1
+#define ADD_MANAGED_RESOURCE		2
+#define GET_FIRST_MANAGED_RESOURCE	3
+#define GET_NEXT_MANAGED_RESOURCE	4
+/* Resource field */
+#define RES_MEMORY_RANGE		1
+#define RES_IO_RANGE			2
+#define RES_IRQ				3
+/* Attribute field */
+#define RES_IRQ_TYPE			0x03
+#define RES_IRQ_TYPE_EXCLUSIVE		0
+#define RES_IRQ_TYPE_TIME		1
+#define RES_IRQ_TYPE_DYNAMIC		2
+#define RES_IRQ_CSC			0x04
+#define RES_SHARED			0x08
+#define RES_RESERVED			0x10
+#define RES_ALLOCATED			0x20
+#define RES_REMOVED			0x40
+
+typedef struct servinfo_t {
+    char	Signature[2];
+    u_int	Count;
+    u_int	Revision;
+    u_int	CSLevel;
+    char	*VendorString;
+} servinfo_t;
+
+typedef struct event_callback_args_t {
+    client_handle_t client_handle;
+    void	*info;
+    void	*mtdrequest;
+    void	*buffer;
+    void	*misc;
+    void	*client_data;
+    struct bus_operations *bus;
+} event_callback_args_t;
+
+/* for GetConfigurationInfo */
+typedef struct config_info_t {
+    u_char	Function;
+    u_int	Attributes;
+    u_int	Vcc, Vpp1, Vpp2;
+    u_int	IntType;
+    u_int	ConfigBase;
+    u_char	Status, Pin, Copy, Option, ExtStatus;
+    u_int	Present;
+    u_int	CardValues;
+    u_int	AssignedIRQ;
+    u_int	IRQAttributes;
+    ioaddr_t	BasePort1;
+    ioaddr_t	NumPorts1;
+    u_int	Attributes1;
+    ioaddr_t	BasePort2;
+    ioaddr_t	NumPorts2;
+    u_int	Attributes2;
+    u_int	IOAddrLines;
+} config_info_t;
+
+/* For CardValues field */
+#define CV_OPTION_VALUE		0x01
+#define CV_STATUS_VALUE		0x02
+#define CV_PIN_REPLACEMENT	0x04
+#define CV_COPY_VALUE		0x08
+#define CV_EXT_STATUS		0x10
+
+/* For GetFirst/NextClient */
+typedef struct client_req_t {
+    socket_t	Socket;
+    u_int	Attributes;
+} client_req_t;
+
+#define CLIENT_THIS_SOCKET	0x01
+
+/* For RegisterClient */
+typedef struct client_reg_t {
+    dev_info_t	*dev_info;
+    u_int	Attributes;
+    u_int	EventMask;
+    int		(*event_handler)(event_t event, int priority,
+				 event_callback_args_t *);
+    event_callback_args_t event_callback_args;
+    u_int	Version;
+} client_reg_t;
+
+/* ModifyConfiguration */
+typedef struct modconf_t {
+    u_int	Attributes;
+    u_int	Vcc, Vpp1, Vpp2;
+} modconf_t;
+
+/* Attributes for ModifyConfiguration */
+#define CONF_IRQ_CHANGE_VALID	0x100
+#define CONF_VCC_CHANGE_VALID	0x200
+#define CONF_VPP1_CHANGE_VALID	0x400
+#define CONF_VPP2_CHANGE_VALID	0x800
+
+/* For RequestConfiguration */
+typedef struct config_req_t {
+    u_int	Attributes;
+    u_int	Vcc, Vpp1, Vpp2;
+    u_int	IntType;
+    u_int	ConfigBase;
+    u_char	Status, Pin, Copy, ExtStatus;
+    u_char	ConfigIndex;
+    u_int	Present;
+} config_req_t;
+
+/* Attributes for RequestConfiguration */
+#define CONF_ENABLE_IRQ		0x01
+#define CONF_ENABLE_DMA		0x02
+#define CONF_ENABLE_SPKR	0x04
+#define CONF_VALID_CLIENT	0x100
+
+/* IntType field */
+#define INT_MEMORY		0x01
+#define INT_MEMORY_AND_IO	0x02
+#define INT_CARDBUS		0x04
+#define INT_ZOOMED_VIDEO	0x08
+
+/* For RequestIO and ReleaseIO */
+typedef struct io_req_t {
+    ioaddr_t	BasePort1;
+    ioaddr_t	NumPorts1;
+    u_int	Attributes1;
+    ioaddr_t	BasePort2;
+    ioaddr_t	NumPorts2;
+    u_int	Attributes2;
+    u_int	IOAddrLines;
+} io_req_t;
+
+/* Attributes for RequestIO and ReleaseIO */
+#define IO_SHARED		0x01
+#define IO_FIRST_SHARED		0x02
+#define IO_FORCE_ALIAS_ACCESS	0x04
+#define IO_DATA_PATH_WIDTH	0x18
+#define IO_DATA_PATH_WIDTH_8	0x00
+#define IO_DATA_PATH_WIDTH_16	0x08
+#define IO_DATA_PATH_WIDTH_AUTO	0x10
+
+/* For RequestIRQ and ReleaseIRQ */
+typedef struct irq_req_t {
+    u_int	Attributes;
+    u_int	AssignedIRQ;
+    u_int	IRQInfo1, IRQInfo2;
+    void	*Handler;
+    void	*Instance;
+} irq_req_t;
+
+/* Attributes for RequestIRQ and ReleaseIRQ */
+#define IRQ_TYPE			0x03
+#define IRQ_TYPE_EXCLUSIVE		0x00
+#define IRQ_TYPE_TIME			0x01
+#define IRQ_TYPE_DYNAMIC_SHARING	0x02
+#define IRQ_FORCED_PULSE		0x04
+#define IRQ_FIRST_SHARED		0x08
+#define IRQ_HANDLE_PRESENT		0x10
+#define IRQ_PULSE_ALLOCATED		0x100
+
+/* Bits in IRQInfo1 field */
+#define IRQ_MASK		0x0f
+#define IRQ_NMI_ID		0x01
+#define IRQ_IOCK_ID		0x02
+#define IRQ_BERR_ID		0x04
+#define IRQ_VEND_ID		0x08
+#define IRQ_INFO2_VALID		0x10
+#define IRQ_LEVEL_ID		0x20
+#define IRQ_PULSE_ID		0x40
+#define IRQ_SHARE_ID		0x80
+
+typedef struct eventmask_t {
+    u_int	Attributes;
+    u_int	EventMask;
+} eventmask_t;
+
+#define CONF_EVENT_MASK_VALID	0x01
+
+/* Configuration registers present */
+#define PRESENT_OPTION		0x001
+#define PRESENT_STATUS		0x002
+#define PRESENT_PIN_REPLACE	0x004
+#define PRESENT_COPY		0x008
+#define PRESENT_EXT_STATUS	0x010
+#define PRESENT_IOBASE_0	0x020
+#define PRESENT_IOBASE_1	0x040
+#define PRESENT_IOBASE_2	0x080
+#define PRESENT_IOBASE_3	0x100
+#define PRESENT_IOSIZE		0x200
+
+/* For GetMemPage, MapMemPage */
+typedef struct memreq_t {
+    u_int	CardOffset;
+    page_t	Page;
+} memreq_t;
+
+/* For ModifyWindow */
+typedef struct modwin_t {
+    u_int	Attributes;
+    u_int	AccessSpeed;
+} modwin_t;
+
+/* For RequestWindow */
+typedef struct win_req_t {
+    u_int	Attributes;
+    u_long	Base;
+    u_int	Size;
+    u_int	AccessSpeed;
+} win_req_t;
+
+/* Attributes for RequestWindow */
+#define WIN_ADDR_SPACE		0x0001
+#define WIN_ADDR_SPACE_MEM	0x0000
+#define WIN_ADDR_SPACE_IO	0x0001
+#define WIN_MEMORY_TYPE		0x0002
+#define WIN_MEMORY_TYPE_CM	0x0000
+#define WIN_MEMORY_TYPE_AM	0x0002
+#define WIN_ENABLE		0x0004
+#define WIN_DATA_WIDTH		0x0018
+#define WIN_DATA_WIDTH_8	0x0000
+#define WIN_DATA_WIDTH_16	0x0008
+#define WIN_DATA_WIDTH_32	0x0010
+#define WIN_PAGED		0x0020
+#define WIN_SHARED		0x0040
+#define WIN_FIRST_SHARED	0x0080
+#define WIN_USE_WAIT		0x0100
+#define WIN_STRICT_ALIGN	0x0200
+#define WIN_MAP_BELOW_1MB	0x0400
+#define WIN_PREFETCH		0x0800
+#define WIN_CACHEABLE		0x1000
+#define WIN_BAR_MASK		0xe000
+#define WIN_BAR_SHIFT		13
+
+/* Attributes for RegisterClient */
+#define INFO_MASTER_CLIENT	0x01
+#define INFO_IO_CLIENT		0x02
+#define INFO_MTD_CLIENT		0x04
+#define INFO_MEM_CLIENT		0x08
+#define MAX_NUM_CLIENTS		3
+
+#define INFO_CARD_SHARE		0x10
+#define INFO_CARD_EXCL		0x20
+
+typedef struct cs_status_t {
+    u_char	Function;
+    event_t 	CardState;
+    event_t	SocketState;
+} cs_status_t;
+
+typedef struct error_info_t {
+    int		func;
+    int		retcode;
+} error_info_t;
+
+/* Special stuff for binding drivers to sockets */
+typedef struct bind_req_t {
+    socket_t	Socket;
+    u_char	Function;
+    dev_info_t	*dev_info;
+} bind_req_t;
+
+/* Flag to bind to all functions */
+#define BIND_FN_ALL	0xff
+
+typedef struct mtd_bind_t {
+    socket_t	Socket;
+    u_int	Attributes;
+    u_int	CardOffset;
+    dev_info_t	*dev_info;
+} mtd_bind_t;
+
+/* Events */
+#define CS_EVENT_PRI_LOW		0
+#define CS_EVENT_PRI_HIGH		1
+
+#define CS_EVENT_WRITE_PROTECT		0x000001
+#define CS_EVENT_CARD_LOCK		0x000002
+#define CS_EVENT_CARD_INSERTION		0x000004
+#define CS_EVENT_CARD_REMOVAL		0x000008
+#define CS_EVENT_BATTERY_DEAD		0x000010
+#define CS_EVENT_BATTERY_LOW		0x000020
+#define CS_EVENT_READY_CHANGE		0x000040
+#define CS_EVENT_CARD_DETECT		0x000080
+#define CS_EVENT_RESET_REQUEST		0x000100
+#define CS_EVENT_RESET_PHYSICAL		0x000200
+#define CS_EVENT_CARD_RESET		0x000400
+#define CS_EVENT_REGISTRATION_COMPLETE	0x000800
+#define CS_EVENT_RESET_COMPLETE		0x001000
+#define CS_EVENT_PM_SUSPEND		0x002000
+#define CS_EVENT_PM_RESUME		0x004000
+#define CS_EVENT_INSERTION_REQUEST	0x008000
+#define CS_EVENT_EJECTION_REQUEST	0x010000
+#define CS_EVENT_MTD_REQUEST		0x020000
+#define CS_EVENT_ERASE_COMPLETE		0x040000
+#define CS_EVENT_REQUEST_ATTENTION	0x080000
+#define CS_EVENT_CB_DETECT		0x100000
+#define CS_EVENT_3VCARD			0x200000
+#define CS_EVENT_XVCARD			0x400000
+
+/* Return codes */
+#define CS_SUCCESS		0x00
+#define CS_BAD_ADAPTER		0x01
+#define CS_BAD_ATTRIBUTE	0x02
+#define CS_BAD_BASE		0x03
+#define CS_BAD_EDC		0x04
+#define CS_BAD_IRQ		0x06
+#define CS_BAD_OFFSET		0x07
+#define CS_BAD_PAGE		0x08
+#define CS_READ_FAILURE		0x09
+#define CS_BAD_SIZE		0x0a
+#define CS_BAD_SOCKET		0x0b
+#define CS_BAD_TYPE		0x0d
+#define CS_BAD_VCC		0x0e
+#define CS_BAD_VPP		0x0f
+#define CS_BAD_WINDOW		0x11
+#define CS_WRITE_FAILURE	0x12
+#define CS_NO_CARD		0x14
+#define CS_UNSUPPORTED_FUNCTION	0x15
+#define CS_UNSUPPORTED_MODE	0x16
+#define CS_BAD_SPEED		0x17
+#define CS_BUSY			0x18
+#define CS_GENERAL_FAILURE	0x19
+#define CS_WRITE_PROTECTED	0x1a
+#define CS_BAD_ARG_LENGTH	0x1b
+#define CS_BAD_ARGS		0x1c
+#define CS_CONFIGURATION_LOCKED	0x1d
+#define CS_IN_USE		0x1e
+#define CS_NO_MORE_ITEMS	0x1f
+#define CS_OUT_OF_RESOURCE	0x20
+#define CS_BAD_HANDLE		0x21
+
+#define CS_BAD_TUPLE		0x40
+
+#ifdef __KERNEL__
+
+/*
+ *  Calls to set up low-level "Socket Services" drivers
+ */
+
+typedef int (*ss_entry_t)(u_int sock, u_int cmd, void *arg);
+extern int register_ss_entry(int nsock, ss_entry_t entry);
+extern void unregister_ss_entry(ss_entry_t entry);
+
+/*
+ *  The main Card Services entry point
+ */
+
+enum service {
+    AccessConfigurationRegister, AddSocketServices,
+    AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
+    DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
+    GetClientInfo, GetConfigurationInfo, GetEventMask,
+    GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
+    GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
+    GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
+    MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
+    OpenMemory, ParseTuple, ReadMemory, RegisterClient,
+    RegisterEraseQueue, RegisterMTD, RegisterTimer,
+    ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
+    ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
+    RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
+    RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
+    SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
+    WriteMemory, BindDevice, BindMTD, ReportError,
+    SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS,
+    GetFirstWindow, GetNextWindow, GetMemPage
+};
+
+#ifdef IN_CARD_SERVICES
+extern int CardServices(int func, void *a1, void *a2, void *a3);
+#else
+extern int CardServices(int func, ...);
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_CS_H */
diff --git a/pcmcia/cs_types.h b/pcmcia/cs_types.h
new file mode 100644
index 0000000..88471f9
--- /dev/null
+++ b/pcmcia/cs_types.h
@@ -0,0 +1,70 @@
+/*
+ * cs_types.h 1.20 2002/04/17 02:52:39
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_TYPES_H
+#define _LINUX_CS_TYPES_H
+
+#ifdef __linux__
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#endif
+
+#ifdef __arm__
+typedef u_int	ioaddr_t;
+#else
+typedef u_short	ioaddr_t;
+#endif
+
+typedef u_short	socket_t;
+typedef u_int	event_t;
+typedef u_char	cisdata_t;
+typedef u_short	page_t;
+
+struct client_t;
+typedef struct client_t *client_handle_t;
+
+struct window_t;
+typedef struct window_t *window_handle_t;
+
+struct region_t;
+typedef struct region_t *memory_handle_t;
+
+struct eraseq_t;
+typedef struct eraseq_t *eraseq_handle_t;
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+typedef char dev_info_t[DEV_NAME_LEN];
+
+#endif /* _LINUX_CS_TYPES_H */
diff --git a/pcmcia/ds.h b/pcmcia/ds.h
new file mode 100644
index 0000000..b372e59
--- /dev/null
+++ b/pcmcia/ds.h
@@ -0,0 +1,148 @@
+/*
+ * ds.h 1.58 2001/10/04 03:15:22
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DS_H
+#define _LINUX_DS_H
+
+#include <pcmcia/driver_ops.h>
+#include <pcmcia/bulkmem.h>
+
+typedef struct tuple_parse_t {
+    tuple_t		tuple;
+    cisdata_t		data[255];
+    cisparse_t		parse;
+} tuple_parse_t;
+
+typedef struct win_info_t {
+    window_handle_t	handle;
+    win_req_t		window;
+    memreq_t		map;
+} win_info_t;
+    
+typedef struct bind_info_t {
+    dev_info_t		dev_info;
+    u_char		function;
+    struct dev_link_t	*instance;
+    char		name[DEV_NAME_LEN];
+    u_short		major, minor;
+    void		*next;
+} bind_info_t;
+
+typedef struct mtd_info_t {
+    dev_info_t		dev_info;
+    u_int		Attributes;
+    u_int		CardOffset;
+} mtd_info_t;
+
+typedef union ds_ioctl_arg_t {
+    servinfo_t		servinfo;
+    adjust_t		adjust;
+    config_info_t	config;
+    tuple_t		tuple;
+    tuple_parse_t	tuple_parse;
+    client_req_t	client_req;
+    cs_status_t		status;
+    conf_reg_t		conf_reg;
+    cisinfo_t		cisinfo;
+    region_info_t	region;
+    bind_info_t		bind_info;
+    mtd_info_t		mtd_info;
+    win_info_t		win_info;
+    cisdump_t		cisdump;
+} ds_ioctl_arg_t;
+
+#define DS_GET_CARD_SERVICES_INFO	_IOR ('d', 1, servinfo_t)
+#define DS_ADJUST_RESOURCE_INFO		_IOWR('d', 2, adjust_t)
+#define DS_GET_CONFIGURATION_INFO	_IOWR('d', 3, config_info_t)
+#define DS_GET_FIRST_TUPLE		_IOWR('d', 4, tuple_t)
+#define DS_GET_NEXT_TUPLE		_IOWR('d', 5, tuple_t)
+#define DS_GET_TUPLE_DATA		_IOWR('d', 6, tuple_parse_t)
+#define DS_PARSE_TUPLE			_IOWR('d', 7, tuple_parse_t)
+#define DS_RESET_CARD			_IO  ('d', 8)
+#define DS_GET_STATUS			_IOWR('d', 9, cs_status_t)
+#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
+#define DS_VALIDATE_CIS			_IOR ('d', 11, cisinfo_t)
+#define DS_SUSPEND_CARD			_IO  ('d', 12)
+#define DS_RESUME_CARD			_IO  ('d', 13)
+#define DS_EJECT_CARD			_IO  ('d', 14)
+#define DS_INSERT_CARD			_IO  ('d', 15)
+#define DS_GET_FIRST_REGION		_IOWR('d', 16, region_info_t)
+#define DS_GET_NEXT_REGION		_IOWR('d', 17, region_info_t)
+#define DS_REPLACE_CIS			_IOWR('d', 18, cisdump_t)
+#define DS_GET_FIRST_WINDOW		_IOR ('d', 19, win_info_t)
+#define DS_GET_NEXT_WINDOW		_IOWR('d', 20, win_info_t)
+#define DS_GET_MEM_PAGE			_IOWR('d', 21, win_info_t)
+
+#define DS_BIND_REQUEST			_IOWR('d', 60, bind_info_t)
+#define DS_GET_DEVICE_INFO		_IOWR('d', 61, bind_info_t) 
+#define DS_GET_NEXT_DEVICE		_IOWR('d', 62, bind_info_t) 
+#define DS_UNBIND_REQUEST		_IOW ('d', 63, bind_info_t)
+#define DS_BIND_MTD			_IOWR('d', 64, mtd_info_t)
+
+#ifdef __KERNEL__
+
+typedef struct dev_link_t {
+    dev_node_t		*dev;
+    u_int		state, open;
+    wait_queue_head_t	pending;
+    struct timer_list	release;
+    client_handle_t	handle;
+    io_req_t		io;
+    irq_req_t		irq;
+    config_req_t	conf;
+    window_handle_t	win;
+    void		*priv;
+    struct dev_link_t	*next;
+} dev_link_t;
+
+/* Flags for device state */
+#define DEV_PRESENT		0x01
+#define DEV_CONFIG		0x02
+#define DEV_STALE_CONFIG	0x04	/* release on close */
+#define DEV_STALE_LINK		0x08	/* detach on release */
+#define DEV_CONFIG_PENDING	0x10
+#define DEV_RELEASE_PENDING	0x20
+#define DEV_SUSPEND		0x40
+#define DEV_BUSY		0x80
+
+#define DEV_OK(l) \
+    ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
+
+int register_pccard_driver(dev_info_t *dev_info,
+			   dev_link_t *(*attach)(void),
+			   void (*detach)(dev_link_t *));
+
+int unregister_pccard_driver(dev_info_t *dev_info);
+
+#define register_pcmcia_driver register_pccard_driver
+#define unregister_pcmcia_driver unregister_pccard_driver
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DS_H */
diff --git a/yacc_cis.y b/yacc_cis.y
new file mode 100644
index 0000000..c6188c5
--- /dev/null
+++ b/yacc_cis.y
@@ -0,0 +1,418 @@
+%{
+/*
+ * yacc_cis.y 1.13 2001/08/24 12:21:41
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+
+#include "pack_cis.h"
+
+/* If bison: generate nicer error messages */ 
+#define YYERROR_VERBOSE 1
+ 
+extern int current_lineno;
+
+void yyerror(char *msg, ...);
+static tuple_info_t *new_tuple(u_char type, cisparse_t *parse);
+
+%}
+
+%token STRING NUMBER FLOAT VOLTAGE CURRENT SIZE
+%token VERS_1 MANFID FUNCID CONFIG CFTABLE MFC CHECKSUM
+%token POST ROM BASE LAST_INDEX CJEDEC AJEDEC
+%token DEV_INFO ATTR_DEV_INFO NO_INFO
+%token TIME TIMING WAIT READY RESERVED
+%token VNOM VMIN VMAX ISTATIC IAVG IPEAK IDOWN
+%token VCC VPP1 VPP2 IO MEM
+%token DEFAULT BVD WP RDYBSY MWAIT AUDIO READONLY PWRDOWN
+%token BIT8 BIT16 LINES RANGE
+%token IRQ_NO MASK LEVEL PULSE SHARED
+
+%union {
+    char *str;
+    u_long num;
+    float flt;
+    cistpl_power_t pwr;
+    cisparse_t *parse;
+    tuple_info_t *tuple;
+}
+
+%type <str> STRING
+%type <num> NUMBER SIZE VOLTAGE CURRENT TIME
+%type <flt> FLOAT
+%type <pwr> pwr pwrlist
+%type <parse> vers_1 manfid funcid config cftab io mem irq timing
+%type <parse> dev_info attr_dev_info checksum cjedec ajedec
+%type <tuple> tuple chain cis;
+%%
+
+cis:	  chain
+		{ cis_root = $1; }
+	| chain mfc
+		{ cis_root = $1; }
+	;
+
+chain:	  /* nothing */
+		{ $$ = NULL; }
+	| chain tuple
+		{
+		    if ($1 == NULL) {
+			$$ = $2;
+		    } else if ($2 == NULL) {
+			$$ = $1;
+		    } else {
+			tuple_info_t *tail = $1;
+			while (tail->next != NULL) tail = tail->next;
+			tail->next = $2;
+			$$ = $1;
+		    }
+		} 
+	;
+
+mfc:	  MFC '{' chain '}'
+		{ mfc[nf++] = $3; }
+	| mfc ',' '{' chain '}'
+		{ mfc[nf++] = $4; }
+	;
+	
+tuple:	  dev_info
+		{ $$ = new_tuple(CISTPL_DEVICE, $1); }
+	| attr_dev_info
+		{ $$ = new_tuple(CISTPL_DEVICE_A, $1); }
+	| vers_1
+		{ $$ = new_tuple(CISTPL_VERS_1, $1); }
+	| manfid
+		{ $$ = new_tuple(CISTPL_MANFID, $1); }
+	| funcid
+		{ $$ = new_tuple(CISTPL_FUNCID, $1); }
+	| config
+		{ $$ = new_tuple(CISTPL_CONFIG, $1); }
+	| cftab
+		{ $$ = new_tuple(CISTPL_CFTABLE_ENTRY, $1); }
+	| checksum
+		{ $$ = NULL; }
+	| error
+		{ $$ = NULL; }
+	| cjedec
+		{ $$ = new_tuple(CISTPL_JEDEC_C, $1); }
+	| ajedec
+		{ $$ = new_tuple(CISTPL_JEDEC_A, $1); }
+	;
+
+dev_info: DEV_INFO
+		{ $$ = calloc(1, sizeof(cisparse_t)); }
+	| dev_info NUMBER TIME ',' SIZE
+		{
+		    $$->device.dev[$$->device.ndev].type = $2;
+		    $$->device.dev[$$->device.ndev].speed = $3;
+		    $$->device.dev[$$->device.ndev].size = $5;
+		    $$->device.ndev++;
+		}
+	| dev_info NO_INFO
+	;
+
+attr_dev_info: ATTR_DEV_INFO
+		{ $$ = calloc(1, sizeof(cisparse_t)); }
+	| attr_dev_info NUMBER TIME ',' SIZE
+		{
+		    $$->device.dev[$$->device.ndev].type = $2;
+		    $$->device.dev[$$->device.ndev].speed = $3;
+		    $$->device.dev[$$->device.ndev].size = $5;
+		    $$->device.ndev++;
+		}
+	| attr_dev_info NO_INFO
+	;
+
+vers_1:	  VERS_1 FLOAT
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->version_1.major = $2;
+		    $2 -= floor($2+0.01);
+		    while (fabs($2 - floor($2+0.5)) > 0.01) {
+			$2 *= 10;
+		    }
+		    $$->version_1.minor = $2+0.01;
+		}
+	| vers_1 ',' STRING
+		{
+		    cistpl_vers_1_t *v = &$$->version_1;
+		    u_int pos = 0;
+		    if (v->ns) {
+			pos = v->ofs[v->ns-1];
+			pos += strlen(v->str+pos)+1;
+		    }
+		    v->ofs[v->ns] = pos;
+		    strcpy(v->str+pos, $3);
+		    v->ns++;
+		}
+	;
+
+manfid:	  MANFID NUMBER ',' NUMBER
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->manfid.manf = $2;
+		    $$->manfid.card = $4;
+		}
+	;
+
+funcid:	  FUNCID NUMBER 
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->funcid.func = $2;
+		}
+	| funcid POST
+		{ $$->funcid.sysinit |= CISTPL_SYSINIT_POST; }
+	| funcid ROM
+		{ $$->funcid.sysinit |= CISTPL_SYSINIT_ROM; }
+	;
+
+cjedec:	  CJEDEC NUMBER NUMBER
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->jedec.id[0].mfr = $2;
+		    $$->jedec.id[0].info = $3;
+		    $$->jedec.nid = 1;
+		}
+	| cjedec ',' NUMBER NUMBER
+		{
+		    $$->jedec.id[$$->jedec.nid].mfr = $3;
+		    $$->jedec.id[$$->jedec.nid++].info = $4;
+		}
+	;
+
+ajedec:	  AJEDEC NUMBER NUMBER
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->jedec.id[0].mfr = $2;
+		    $$->jedec.id[0].info = $3;
+		    $$->jedec.nid = 1;
+		}
+	| ajedec ',' NUMBER NUMBER
+		{
+		    $$->jedec.id[$$->jedec.nid].mfr = $3;
+		    $$->jedec.id[$$->jedec.nid++].info = $4;
+		}
+	;
+
+config:	  CONFIG BASE NUMBER MASK NUMBER  LAST_INDEX NUMBER
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->config.base = $3;
+		    $$->config.rmask[0] = $5;
+		    $$->config.last_idx = $7;
+		}
+	;
+
+pwr:	  VNOM VOLTAGE
+		{
+		    $$.present = CISTPL_POWER_VNOM;
+		    $$.param[0] = $2;
+		}
+	| VMIN VOLTAGE
+		{
+		    $$.present = CISTPL_POWER_VMIN;
+		    $$.param[0] = $2;
+		}
+	| VMAX VOLTAGE
+		{
+		    $$.present = CISTPL_POWER_VMAX;
+		    $$.param[0] = $2;
+		}
+	| ISTATIC CURRENT
+		{
+		    $$.present = CISTPL_POWER_ISTATIC;
+		    $$.param[0] = $2;
+		}
+	| IAVG CURRENT
+		{
+		    $$.present = CISTPL_POWER_IAVG;
+		    $$.param[0] = $2;
+		}
+	| IPEAK CURRENT
+		{
+		    $$.present = CISTPL_POWER_IPEAK;
+		    $$.param[0] = $2;
+		}
+	| IDOWN CURRENT
+		{
+		    $$.present = CISTPL_POWER_IDOWN;
+		    $$.param[0] = $2;
+		}
+	;
+
+pwrlist:  /* nothing */
+		{
+		    $$.present = 0;
+		}
+	| pwrlist pwr
+		{
+		    $$.present |= 1<<($2.present);
+		    $$.param[$2.present] = $2.param[0];
+		}
+	;
+
+timing:	  cftab TIMING
+	| timing WAIT TIME
+	| timing READY TIME
+	| timing RESERVED TIME
+	;
+
+io:	  cftab IO NUMBER '-' NUMBER
+		{
+		    int n = $$->cftable_entry.io.nwin;
+		    $$->cftable_entry.io.win[n].base = $3;
+		    $$->cftable_entry.io.win[n].len = $5-$3+1;
+		    $$->cftable_entry.io.nwin++;
+		}
+	| io ',' NUMBER '-' NUMBER
+		{
+		    int n = $$->cftable_entry.io.nwin;
+		    $$->cftable_entry.io.win[n].base = $3;
+		    $$->cftable_entry.io.win[n].len = $5-$3+1;
+		    $$->cftable_entry.io.nwin++;
+		}
+	| io BIT8
+		{ $$->cftable_entry.io.flags |= CISTPL_IO_8BIT; }
+	| io BIT16
+		{ $$->cftable_entry.io.flags |= CISTPL_IO_16BIT; }
+	| io LINES '=' NUMBER ']'
+		{ $$->cftable_entry.io.flags |= $4; }
+	| io RANGE
+	;	
+
+mem:	  cftab MEM NUMBER '-' NUMBER '@' NUMBER
+		{
+		    int n = $$->cftable_entry.mem.nwin;
+		    $$->cftable_entry.mem.win[n].card_addr = $3;
+		    $$->cftable_entry.mem.win[n].host_addr = $7;
+		    $$->cftable_entry.mem.win[n].len = $5-$3+1;
+		    $$->cftable_entry.mem.nwin++;
+		}
+	| mem ',' NUMBER '-' NUMBER '@' NUMBER
+		{
+		    int n = $$->cftable_entry.mem.nwin;
+		    $$->cftable_entry.mem.win[n].card_addr = $3;
+		    $$->cftable_entry.mem.win[n].host_addr = $7;
+		    $$->cftable_entry.mem.win[n].len = $5-$3+1;
+		    $$->cftable_entry.mem.nwin++;
+		}
+	| mem BIT8
+		{ $$->cftable_entry.io.flags |= CISTPL_IO_8BIT; }
+	| mem BIT16
+		{ $$->cftable_entry.io.flags |= CISTPL_IO_16BIT; }
+	;	
+
+irq:	  cftab IRQ_NO NUMBER
+		{ $$->cftable_entry.irq.IRQInfo1 = ($3 & 0x0f); }
+	| cftab IRQ_NO MASK NUMBER
+		{
+		    $$->cftable_entry.irq.IRQInfo1 = IRQ_INFO2_VALID;
+		    $$->cftable_entry.irq.IRQInfo2 = $4;
+		}
+	| irq PULSE
+		{ $$->cftable_entry.irq.IRQInfo1 |= IRQ_PULSE_ID; }
+	| irq LEVEL
+		{ $$->cftable_entry.irq.IRQInfo1 |= IRQ_LEVEL_ID; }
+	| irq SHARED
+		{ $$->cftable_entry.irq.IRQInfo1 |= IRQ_SHARE_ID; }
+	;
+
+cftab:	  CFTABLE NUMBER
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->cftable_entry.index = $2;
+		}
+	| cftab DEFAULT
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_DEFAULT; }
+	| cftab BVD
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_BVDS; }
+	| cftab WP
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_WP; }
+	| cftab RDYBSY
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_RDYBSY; }
+	| cftab MWAIT
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_MWAIT; }
+	| cftab AUDIO
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_AUDIO; }
+	| cftab READONLY
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_READONLY; }
+	| cftab PWRDOWN
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_PWRDOWN; }
+	| cftab VCC pwrlist
+		{ $$->cftable_entry.vcc = $3; }
+	| cftab VPP1 pwrlist
+		{ $$->cftable_entry.vpp1 = $3; }
+	| cftab VPP2 pwrlist
+		{ $$->cftable_entry.vpp2 = $3; }
+	| io
+	| mem
+	| irq
+	| timing
+	;
+
+checksum: CHECKSUM NUMBER '-' NUMBER '=' NUMBER
+	{ $$ = NULL; }
+
+%%
+
+static tuple_info_t *new_tuple(u_char type, cisparse_t *parse)
+{
+    tuple_info_t *t = calloc(1, sizeof(tuple_info_t));
+    t->type = type;
+    t->parse = parse;
+    t->next = NULL;
+}
+
+void yyerror(char *msg, ...)
+{
+    va_list ap;
+    char str[256];
+
+    va_start(ap, msg);
+    sprintf(str, "error at line %d: ", current_lineno);
+    vsprintf(str+strlen(str), msg, ap);
+    fprintf(stderr, "%s\n", str);
+    va_end(ap);
+}
+
+#ifdef DEBUG
+void main(int argc, char *argv[])
+{
+    if (argc > 1)
+	parse_cis(argv[1]);
+}
+#endif