diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU Affero General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/OpenCL.cabal b/OpenCL.cabal
new file mode 100644
--- /dev/null
+++ b/OpenCL.cabal
@@ -0,0 +1,43 @@
+Name: OpenCL
+Version: 1.0.1.3
+License: GPL
+License-File: LICENSE
+Author: Luis Cabellos
+Copyright: (c) 2011 Luis Cabellos
+Category: GPU, FFI, Graphics
+Build-Type: Simple
+Stability: Experimental
+Maintainer: Luis Cabellos
+Homepage: https://github.com/zhensydow/opencl
+Synopsis: Haskell high-level wrapper for OpenCL
+Description: Haskell FFI binding to OpenCL library. It includes high-level wrappers to help development. Based on OpenCLRaw package.
+bug-reports: https://github.com/zhensydow/opencl/issues
+Cabal-Version: >=1.8
+Tested-With: GHC
+
+source-repository this
+  type: git
+  location: https://zhensydow@github.com/zhensydow/opencl.git
+  tag: 1.0.1.3
+  branch: master
+
+source-repository head
+  type: git
+  location: https://zhensydow@github.com/zhensydow/opencl.git
+  branch: develop
+
+Library
+  Build-tools: c2hs
+  hs-Source-Dirs: src
+  ghc-options: -Wall
+  Build-Depends: base >=4.0 && < 5, bytestring -any, mtl==2.0.*
+  Exposed-Modules: 
+    System.GPU.OpenCL
+    System.GPU.OpenCL.Query
+    System.GPU.OpenCL.Context
+    System.GPU.OpenCL.CommandQueue
+    System.GPU.OpenCL.Memory
+    System.GPU.OpenCL.Event
+    System.GPU.OpenCL.Program
+  Other-Modules: 
+    System.GPU.OpenCL.Types
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/System/GPU/OpenCL.hs b/src/System/GPU/OpenCL.hs
new file mode 100644
--- /dev/null
+++ b/src/System/GPU/OpenCL.hs
@@ -0,0 +1,39 @@
+-- -----------------------------------------------------------------------------
+-- This file is part of Haskell-Opencl.
+
+-- Haskell-Opencl is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- Haskell-Opencl is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with Haskell-Opencl.  If not, see <http://www.gnu.org/licenses/>.
+-- -----------------------------------------------------------------------------
+module System.GPU.OpenCL( 
+  -- * Basic Types
+  CLError(..), CLint, CLuint, CLulong,
+  -- * Modules
+  module System.GPU.OpenCL.Query,
+  module System.GPU.OpenCL.Context,
+  module System.GPU.OpenCL.CommandQueue, 
+  module System.GPU.OpenCL.Memory,
+  module System.GPU.OpenCL.Event,
+  module System.GPU.OpenCL.Program )
+       where
+
+-- -----------------------------------------------------------------------------
+import System.GPU.OpenCL.Query
+import System.GPU.OpenCL.Context
+import System.GPU.OpenCL.CommandQueue
+import System.GPU.OpenCL.Memory
+import System.GPU.OpenCL.Event
+import System.GPU.OpenCL.Program
+import System.GPU.OpenCL.Types( 
+  CLError(..), CLint, CLuint, CLulong )
+
+-- -----------------------------------------------------------------------------
diff --git a/src/System/GPU/OpenCL/CommandQueue.chs b/src/System/GPU/OpenCL/CommandQueue.chs
new file mode 100644
--- /dev/null
+++ b/src/System/GPU/OpenCL/CommandQueue.chs
@@ -0,0 +1,553 @@
+-- -----------------------------------------------------------------------------
+-- This file is part of Haskell-Opencl.
+
+-- Haskell-Opencl is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- Haskell-Opencl is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with Haskell-Opencl.  If not, see <http://www.gnu.org/licenses/>.
+-- -----------------------------------------------------------------------------
+{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}
+module System.GPU.OpenCL.CommandQueue(
+  -- * Types
+  CLCommandQueue, CLCommandQueueProperty(..), 
+  -- * Command Queue Functions
+  clCreateCommandQueue, clRetainCommandQueue, clReleaseCommandQueue,
+  clGetCommandQueueContext, clGetCommandQueueDevice, 
+  clGetCommandQueueReferenceCount, clGetCommandQueueProperties,
+  clSetCommandQueueProperty,
+  -- * Memory Commands
+  clEnqueueReadBuffer, clEnqueueWriteBuffer,
+  -- * Executing Kernels
+  clEnqueueNDRangeKernel, clEnqueueTask, clEnqueueMarker, 
+  clEnqueueWaitForEvents, clEnqueueBarrier,
+  -- * Flush and Finish
+  clFlush, clFinish
+  ) where
+
+-- -----------------------------------------------------------------------------
+import Foreign
+import Foreign.C.Types
+import System.GPU.OpenCL.Types( 
+  CLint, CLbool, CLuint, CLCommandQueueProperty_, CLCommandQueueInfo_, 
+  CLError(..), CLCommandQueue, CLDeviceID, CLContext, CLCommandQueueProperty(..), 
+  CLEvent, CLMem, CLKernel,
+  wrapCheckSuccess, wrapPError, wrapGetInfo, getCLValue, getEnumCL,
+  bitmaskToCommandQueueProperties, bitmaskFromFlags )
+
+#include <CL/cl.h>
+
+-- -----------------------------------------------------------------------------
+foreign import ccall "clCreateCommandQueue" raw_clCreateCommandQueue :: 
+  CLContext -> CLDeviceID -> CLCommandQueueProperty_ -> Ptr CLint -> IO CLCommandQueue
+foreign import ccall "clRetainCommandQueue" raw_clRetainCommandQueue :: 
+  CLCommandQueue -> IO CLint
+foreign import ccall "clReleaseCommandQueue" raw_clReleaseCommandQueue :: 
+  CLCommandQueue -> IO CLint
+foreign import ccall "clGetCommandQueueInfo" raw_clGetCommandQueueInfo :: 
+  CLCommandQueue -> CLCommandQueueInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+foreign import ccall "clSetCommandQueueProperty" raw_clSetCommandQueueProperty :: 
+  CLCommandQueue -> CLCommandQueueProperty_ -> CLbool -> Ptr CLCommandQueueProperty_ -> IO CLint
+foreign import ccall "clEnqueueReadBuffer" raw_clEnqueueReadBuffer ::
+  CLCommandQueue -> CLMem -> CLbool -> CSize -> CSize -> Ptr () -> CLuint -> Ptr CLEvent -> Ptr CLEvent -> IO CLint
+foreign import ccall "clEnqueueWriteBuffer" raw_clEnqueueWriteBuffer ::
+  CLCommandQueue -> CLMem -> CLbool -> CSize -> CSize -> Ptr () -> CLuint -> Ptr CLEvent -> Ptr CLEvent -> IO CLint
+foreign import ccall "clEnqueueNDRangeKernel" raw_clEnqueueNDRangeKernel :: 
+  CLCommandQueue -> CLKernel -> CLuint -> Ptr CSize -> Ptr CSize -> Ptr CSize -> CLuint -> Ptr CLEvent -> Ptr CLEvent -> IO CLint
+foreign import ccall "clEnqueueTask" raw_clEnqueueTask :: 
+  CLCommandQueue -> CLKernel -> CLuint -> Ptr CLEvent -> Ptr CLEvent -> IO CLint
+foreign import ccall "clEnqueueMarker" raw_clEnqueueMarker :: 
+  CLCommandQueue -> Ptr CLEvent -> IO CLint 
+foreign import ccall "clEnqueueWaitForEvents" raw_clEnqueueWaitForEvents :: 
+  CLCommandQueue -> CLuint -> Ptr CLEvent -> IO CLint
+foreign import ccall "clEnqueueBarrier" raw_clEnqueueBarrier :: 
+  CLCommandQueue -> IO CLint 
+foreign import ccall "clFlush" raw_clFlush ::
+  CLCommandQueue -> IO CLint
+foreign import ccall "clFinish" raw_clFinish ::
+  CLCommandQueue -> IO CLint
+
+-- -----------------------------------------------------------------------------
+{-| Create a command-queue on a specific device.
+
+The OpenCL functions that are submitted to a command-queue are enqueued in the 
+order the calls are made but can be configured to execute in-order or 
+out-of-order. The properties argument in clCreateCommandQueue can be used to 
+specify the execution order.
+
+If the 'CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE' property of a command-queue is 
+not set, the commands enqueued to a command-queue execute in order. For example, 
+if an application calls 'clEnqueueNDRangeKernel' to execute kernel A followed by 
+a 'clEnqueueNDRangeKernel' to execute kernel B, the application can assume that 
+kernel A finishes first and then kernel B is executed. If the memory objects 
+output by kernel A are inputs to kernel B then kernel B will see the correct 
+data in memory objects produced by execution of kernel A. If the 
+'CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE' property of a commandqueue is set, then 
+there is no guarantee that kernel A will finish before kernel B starts execution.
+
+Applications can configure the commands enqueued to a command-queue to execute 
+out-of-order by setting the 'CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE' property of 
+the command-queue. This can be specified when the command-queue is created or 
+can be changed dynamically using 'clCreateCommandQueue'. In out-of-order 
+execution mode there is no guarantee that the enqueued commands will finish 
+execution in the order they were queued. As there is no guarantee that kernels 
+will be executed in order, i.e. based on when the 'clEnqueueNDRangeKernel' calls 
+are made within a command-queue, it is therefore possible that an earlier 
+'clEnqueueNDRangeKernel' call to execute kernel A identified by event A may 
+execute and/or finish later than a 'clEnqueueNDRangeKernel' call to execute 
+kernel B which was called by the application at a later point in time. To 
+guarantee a specific order of execution of kernels, a wait on a particular event 
+(in this case event A) can be used. The wait for event A can be specified in the 
+event_wait_list argument to 'clEnqueueNDRangeKernel' for kernel B.
+
+In addition, a wait for events or a barrier command can be enqueued to the 
+command-queue. The wait for events command ensures that previously enqueued 
+commands identified by the list of events to wait for have finished before the 
+next batch of commands is executed. The barrier command ensures that all 
+previously enqueued commands in a command-queue have finished execution before 
+the next batch of commands is executed.
+
+Similarly, commands to read, write, copy or map memory objects that are enqueued 
+after 'clEnqueueNDRangeKernel', 'clEnqueueTask' or 'clEnqueueNativeKernel' 
+commands are not guaranteed to wait for kernels scheduled for execution to have 
+completed (if the 'CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE' property is set). To 
+ensure correct ordering of commands, the event object returned by 
+'clEnqueueNDRangeKernel', 'clEnqueueTask' or 'clEnqueueNativeKernel' can be 
+used to enqueue a wait for event or a barrier command can be enqueued that must 
+complete before reads or writes to the memory object(s) occur.
+-}
+clCreateCommandQueue :: CLContext -> CLDeviceID -> [CLCommandQueueProperty] 
+                     -> IO (Either CLError CLCommandQueue)
+clCreateCommandQueue ctx did xs = wrapPError $ \perr -> do
+  raw_clCreateCommandQueue ctx did props perr
+    where
+      props = bitmaskFromFlags xs
+
+{-| Increments the command_queue reference count. 'clCreateCommandQueue'
+performs an implicit retain. This is very helpful for 3rd party libraries, which
+typically get a command-queue passed to them by the application. However, it is
+possible that the application may delete the command-queue without informing the
+library. Allowing functions to attach to (i.e. retain) and release a
+command-queue solves the problem of a command-queue being used by a library no
+longer being valid.  Returns 'True' if the function is executed successfully. It
+returns 'False' if command_queue is not a valid command-queue.  
+-}
+clRetainCommandQueue :: CLCommandQueue -> IO Bool
+clRetainCommandQueue = wrapCheckSuccess . raw_clRetainCommandQueue
+
+-- | Decrements the command_queue reference count.
+-- After the command_queue reference count becomes zero and all commands queued 
+-- to command_queue have finished (e.g., kernel executions, memory object 
+-- updates, etc.), the command-queue is deleted.
+-- Returns 'True' if the function is executed successfully. It returns 'False'
+-- if command_queue is not a valid command-queue.
+clReleaseCommandQueue :: CLCommandQueue -> IO Bool
+clReleaseCommandQueue = wrapCheckSuccess . raw_clReleaseCommandQueue
+
+#c
+enum CLCommandQueueInfo {
+  cL_QUEUE_CONTEXT=CL_QUEUE_CONTEXT,
+  cL_QUEUE_DEVICE=CL_QUEUE_DEVICE,
+  cL_QUEUE_REFERENCE_COUNT=CL_QUEUE_REFERENCE_COUNT,
+  cL_QUEUE_PROPERTIES=CL_QUEUE_PROPERTIES,
+  };
+#endc
+{#enum CLCommandQueueInfo {upcaseFirstLetter} #}
+
+-- | Return the context specified when the command-queue is created.
+clGetCommandQueueContext :: CLCommandQueue -> IO (Either CLError CLContext)
+clGetCommandQueueContext cq = wrapGetInfo (\(dat :: Ptr CLContext) 
+                                           -> raw_clGetCommandQueueInfo cq infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_QUEUE_CONTEXT
+      size = fromIntegral $ sizeOf (nullPtr::CLContext)
+
+-- | Return the device specified when the command-queue is created.
+clGetCommandQueueDevice :: CLCommandQueue -> IO (Either CLError CLDeviceID)
+clGetCommandQueueDevice cq = wrapGetInfo (\(dat :: Ptr CLDeviceID) 
+                                           -> raw_clGetCommandQueueInfo cq infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_QUEUE_DEVICE
+      size = fromIntegral $ sizeOf (nullPtr::CLDeviceID)
+
+-- | Return the command-queue reference count.
+-- The reference count returned should be considered immediately stale. It is 
+-- unsuitable for general use in applications. This feature is provided for 
+-- identifying memory leaks.
+clGetCommandQueueReferenceCount :: CLCommandQueue -> IO (Either CLError CLuint)
+clGetCommandQueueReferenceCount cq = wrapGetInfo (\(dat :: Ptr CLuint) 
+                                           -> raw_clGetCommandQueueInfo cq infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_QUEUE_REFERENCE_COUNT
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+
+-- | Return the currently specified properties for the command-queue. These 
+-- properties are specified by the properties argument in 'clCreateCommandQueue'
+-- , and can be changed by 'clSetCommandQueueProperty'.
+clGetCommandQueueProperties :: CLCommandQueue -> IO (Either CLError [CLCommandQueueProperty])
+clGetCommandQueueProperties cq = wrapGetInfo (\(dat :: Ptr CLCommandQueueProperty_) 
+                                           -> raw_clGetCommandQueueInfo cq infoid size (castPtr dat)) bitmaskToCommandQueueProperties
+    where 
+      infoid = getCLValue CL_QUEUE_PROPERTIES
+      size = fromIntegral $ sizeOf (0::CLCommandQueueProperty_)
+
+{-| Enable or disable the properties of a command-queue.  Returns the
+command-queue properties before they were changed by
+'clSetCommandQueueProperty'.  As specified for 'clCreateCommandQueue', the
+'CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE' command-queue property determines
+whether the commands in a command-queue are executed in-order or
+out-of-order. Changing this command-queue property will cause the OpenCL
+implementation to block until all previously queued commands in command_queue
+have completed. This can be an expensive operation and therefore changes to the
+'CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE' property should be only done when
+absolutely necessary.
+
+ It is possible that a device(s) becomes unavailable after a context and
+command-queues that use this device(s) have been created and commands have been
+queued to command-queues. In this case the behavior of OpenCL API calls that use
+this context (and command-queues) are considered to be
+implementation-defined. The user callback function, if specified when the
+context is created, can be used to record appropriate information when the
+device becomes unavailable.
+-}
+clSetCommandQueueProperty :: CLCommandQueue -> [CLCommandQueueProperty] -> Bool 
+                          -> IO (Either CLError [CLCommandQueueProperty])
+clSetCommandQueueProperty cq xs val = alloca $ \(dat :: Ptr CLCommandQueueProperty_) -> do
+  errcode <- raw_clSetCommandQueueProperty cq props (fromBool val) dat
+  if errcode == getCLValue CL_SUCCESS
+    then fmap (Right . bitmaskToCommandQueueProperties) $ peek dat
+    else return . Left . getEnumCL $ errcode
+    where
+      props = bitmaskFromFlags xs
+
+-- -----------------------------------------------------------------------------
+clEnqueue :: (CLuint -> Ptr CLEvent -> Ptr CLEvent -> IO CLint) -> [CLEvent] 
+             -> IO (Either CLError CLEvent)
+clEnqueue f [] = alloca $ \event -> do
+  errcode <- f 0 nullPtr event
+  if errcode == getCLValue CL_SUCCESS
+    then fmap Right $ peek event
+    else return . Left . getEnumCL $ errcode
+clEnqueue f events = allocaArray nevents $ \pevents -> do
+  pokeArray pevents events
+  alloca $ \event -> do
+    errcode <- f cnevents pevents event
+    if errcode == getCLValue CL_SUCCESS
+      then fmap Right $ peek event
+      else return . Left . getEnumCL $ errcode
+    where
+      nevents = length events
+      cnevents = fromIntegral nevents
+
+-- -----------------------------------------------------------------------------
+{-| Enqueue commands to read from a buffer object to host memory. Calling
+clEnqueueReadBuffer to read a region of the buffer object with the ptr argument
+value set to host_ptr + offset, where host_ptr is a pointer to the memory region
+specified when the buffer object being read is created with
+'CL_MEM_USE_HOST_PTR', must meet the following requirements in order to avoid
+undefined behavior:
+
+ * All commands that use this buffer object have finished execution before the
+read command begins execution
+
+ * The buffer object is not mapped
+
+ * The buffer object is not used by any command-queue until the read command has
+finished execution Errors
+
+'clEnqueueReadBuffer' returns the event if the function is executed
+successfully. Otherwise, it returns one of the following errors:
+
+ * 'CL_INVALID_COMMAND_QUEUE' if command_queue is not a valid command-queue.
+
+ * 'CL_INVALID_CONTEXT' if the context associated with command_queue and buffer
+are not the same or if the context associated with command_queue and events in
+event_wait_list are not the same.
+
+ * 'CL_INVALID_MEM_OBJECT' if buffer is not a valid buffer object.
+
+ * 'CL_INVALID_VALUE' if the region being read specified by (offset, cb) is out
+of bounds or if ptr is a NULL value.
+
+ * 'CL_INVALID_EVENT_WAIT_LIST' if event_wait_list is NULL and
+num_events_in_wait_list greater than 0, or event_wait_list is not NULL and
+num_events_in_wait_list is 0, or if event objects in event_wait_list are not
+valid events.
+
+ * 'CL_MEM_OBJECT_ALLOCATION_FAILURE' if there is a failure to allocate memory
+for data store associated with buffer.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.
+-}
+clEnqueueReadBuffer :: Integral a => CLCommandQueue -> CLMem -> Bool -> a -> a
+                       -> Ptr () -> [CLEvent] -> IO (Either CLError CLEvent)
+clEnqueueReadBuffer cq mem check off size dat = clEnqueue (raw_clEnqueueReadBuffer cq mem (fromBool check) (fromIntegral off) (fromIntegral size) dat)
+
+{-| Enqueue commands to write to a buffer object from host memory.Calling
+clEnqueueWriteBuffer to update the latest bits in a region of the buffer object
+with the ptr argument value set to host_ptr + offset, where host_ptr is a
+pointer to the memory region specified when the buffer object being written is
+created with 'CL_MEM_USE_HOST_PTR', must meet the following requirements in
+order to avoid undefined behavior:
+
+ * The host memory region given by (host_ptr + offset, cb) contains the latest
+bits when the enqueued write command begins execution.
+
+ * The buffer object is not mapped.
+
+ * The buffer object is not used by any command-queue until the write command
+has finished execution.
+
+'clEnqueueWriteBuffer' returns the Event if the function is executed
+successfully. Otherwise, it returns one of the following errors:
+
+ * 'CL_INVALID_COMMAND_QUEUE' if command_queue is not a valid command-queue.
+
+ * 'CL_INVALID_CONTEXT' if the context associated with command_queue and buffer
+are not the same or if the context associated with command_queue and events in
+event_wait_list are not the same.
+
+ * 'CL_INVALID_MEM_OBJECT' if buffer is not a valid buffer object.
+
+ * 'CL_INVALID_VALUE' if the region being written specified by (offset, cb) is
+out of bounds or if ptr is a NULL value.
+
+ * 'CL_INVALID_EVENT_WAIT_LIST' if event_wait_list is NULL and
+num_events_in_wait_list greater than 0, or event_wait_list is not NULL and
+num_events_in_wait_list is 0, or if event objects in event_wait_list are not
+valid events.
+
+ * 'CL_MEM_OBJECT_ALLOCATION_FAILURE' if there is a failure to allocate memory
+for data store associated with buffer.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.
+-}
+clEnqueueWriteBuffer :: Integral a => CLCommandQueue -> CLMem -> Bool -> a -> a
+                       -> Ptr () -> [CLEvent] -> IO (Either CLError CLEvent)
+clEnqueueWriteBuffer cq mem check off size dat = clEnqueue (raw_clEnqueueWriteBuffer cq mem (fromBool check) (fromIntegral off) (fromIntegral size) dat)
+
+-- -----------------------------------------------------------------------------
+{-| Enqueues a command to execute a kernel on a device. Each work-item is
+uniquely identified by a global identifier. The global ID, which can be read
+inside the kernel, is computed using the value given by global_work_size and
+global_work_offset. In OpenCL 1.0, the starting global ID is always (0, 0,
+... 0). In addition, a work-item is also identified within a work-group by a
+unique local ID. The local ID, which can also be read by the kernel, is computed
+using the value given by local_work_size. The starting local ID is always (0, 0,
+... 0).
+
+Returns the event if the kernel execution was successfully queued. Otherwise, it
+returns one of the following errors:
+
+ * 'CL_INVALID_PROGRAM_EXECUTABLE' if there is no successfully built program
+executable available for device associated with command_queue.
+
+ * 'CL_INVALID_COMMAND_QUEUE' if command_queue is not a valid command-queue.
+
+ * 'CL_INVALID_KERNEL' if kernel is not a valid kernel object.
+
+ * 'CL_INVALID_CONTEXT' if context associated with command_queue and kernel is
+not the same or if the context associated with command_queue and events in
+event_wait_list are not the same.
+
+ * 'CL_INVALID_KERNEL_ARGS' if the kernel argument values have not been
+specified.
+
+ * 'CL_INVALID_WORK_DIMENSION' if work_dim is not a valid value (i.e. a value
+between 1 and 3).
+
+ * 'CL_INVALID_WORK_GROUP_SIZE' if local_work_size is specified and number of
+work-items specified by global_work_size is not evenly divisable by size of
+work-group given by local_work_size or does not match the work-group size
+specified for kernel using the __attribute__((reqd_work_group_size(X, Y, Z)))
+qualifier in program source.
+
+ * 'CL_INVALID_WORK_GROUP_SIZE' if local_work_size is specified and the total
+number of work-items in the work-group computed as local_work_size[0]
+*... local_work_size[work_dim - 1] is greater than the value specified by
+'CL_DEVICE_MAX_WORK_GROUP_SIZE' in the table of OpenCL Device Queries for
+clGetDeviceInfo.
+
+ * 'CL_INVALID_WORK_GROUP_SIZE' if local_work_size is NULL and the
+__attribute__((reqd_work_group_size(X, Y, Z))) qualifier is used to declare the
+work-group size for kernel in the program source.
+
+ * 'CL_INVALID_WORK_ITEM_SIZE' if the number of work-items specified in any of
+local_work_size[0], ... local_work_size[work_dim - 1] is greater than the
+corresponding values specified by 'CL_DEVICE_MAX_WORK_ITEM_SIZES'[0],
+.... 'CL_DEVICE_MAX_WORK_ITEM_SIZES'[work_dim - 1].
+
+ * 'CL_OUT_OF_RESOURCES' if there is a failure to queue the execution instance
+of kernel on the command-queue because of insufficient resources needed to
+execute the kernel. For example, the explicitly specified local_work_size causes
+a failure to execute the kernel because of insufficient resources such as
+registers or local memory. Another example would be the number of read-only
+image args used in kernel exceed the 'CL_DEVICE_MAX_READ_IMAGE_ARGS' value for
+device or the number of write-only image args used in kernel exceed the
+'CL_DEVICE_MAX_WRITE_IMAGE_ARGS' value for device or the number of samplers used
+in kernel exceed 'CL_DEVICE_MAX_SAMPLERS' for device.
+
+ * 'CL_MEM_OBJECT_ALLOCATION_FAILURE' if there is a failure to allocate memory for data store associated with image or buffer objects specified as arguments to kernel.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required by
+the OpenCL implementation on the host.
+-}
+clEnqueueNDRangeKernel :: Integral a => CLCommandQueue -> CLKernel -> [a] -> [a] -> [CLEvent] -> IO (Either CLError CLEvent)
+clEnqueueNDRangeKernel cq krn gws lws events = withArray (map fromIntegral gws) $ \pgws -> withArray (map fromIntegral lws) $ \plws -> do
+  clEnqueue (raw_clEnqueueNDRangeKernel cq krn num nullPtr pgws plws) events
+    where
+      num = fromIntegral $ length gws
+      
+{-| Enqueues a command to execute a kernel on a device. The kernel is executed
+using a single work-item.
+
+'clEnqueueTask' is equivalent to calling 'clEnqueueNDRangeKernel' with work_dim
+= 1, global_work_offset = [], global_work_size[0] set to 1, and
+local_work_size[0] set to 1.
+
+Returns the evens if the kernel execution was successfully queued, or one of the
+errors below:
+
+ * 'CL_INVALID_PROGRAM_EXECUTABLE' if there is no successfully built program
+executable available for device associated with command_queue.
+
+ * 'CL_INVALID_COMMAND_QUEUE if' command_queue is not a valid command-queue.
+
+ * 'CL_INVALID_KERNEL' if kernel is not a valid kernel object.
+
+ * 'CL_INVALID_CONTEXT' if context associated with command_queue and kernel is
+not the same or if the context associated with command_queue and events in
+event_wait_list are not the same.
+
+ * 'CL_INVALID_KERNEL_ARGS' if the kernel argument values have not been specified.
+
+ * 'CL_INVALID_WORK_GROUP_SIZE' if a work-group size is specified for kernel
+using the __attribute__((reqd_work_group_size(X, Y, Z))) qualifier in program
+source and is not (1, 1, 1).
+
+ * 'CL_OUT_OF_RESOURCES' if there is a failure to queue the execution instance
+of kernel on the command-queue because of insufficient resources needed to
+execute the kernel.
+
+ * 'CL_MEM_OBJECT_ALLOCATION_FAILURE' if there is a failure to allocate memory
+for data store associated with image or buffer objects specified as arguments to
+kernel.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.
+-}
+clEnqueueTask :: CLCommandQueue -> CLKernel -> [CLEvent] 
+                 -> IO (Either CLError CLEvent)
+clEnqueueTask cq krn = clEnqueue (raw_clEnqueueTask cq krn)
+  
+-- -----------------------------------------------------------------------------
+-- | Enqueues a marker command to command_queue. The marker command returns an
+-- event which can be used to queue a wait on this marker event i.e. wait for
+-- all commands queued before the marker command to complete. Returns the event
+-- if the function is successfully executed. It returns
+-- 'CL_INVALID_COMMAND_QUEUE' if command_queue is not a valid command-queue and
+-- returns 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources
+-- required by the OpenCL implementation on the host.
+clEnqueueMarker :: CLCommandQueue -> IO (Either CLError CLEvent)
+clEnqueueMarker cq = alloca $ \event -> do
+  errcode <- raw_clEnqueueMarker cq event
+  if errcode == getCLValue CL_SUCCESS
+    then fmap Right $ peek event
+    else return . Left . getEnumCL $ errcode
+         
+{-| Enqueues a wait for a specific event or a list of events to complete before
+any future commands queued in the command-queue are executed. The context
+associated with events in event_list and command_queue must be the same.
+
+Returns one of the errors below when fails:
+
+ * 'CL_INVALID_COMMAND_QUEUE' if command_queue is not a valid command-queue.
+
+ * 'CL_INVALID_CONTEXT' if the context associated with command_queue and events
+in event_list are not the same.
+
+ * 'CL_INVALID_VALUE' if num_events is zero.
+
+ * 'CL_INVALID_EVENT' if event objects specified in event_list are not valid
+events.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.
+-}
+clEnqueueWaitForEvents :: CLCommandQueue -> [CLEvent] -> IO (Either CLError ())
+clEnqueueWaitForEvents cq [] = do
+  errcode <- raw_clEnqueueWaitForEvents cq 0 nullPtr
+  if errcode == getCLValue CL_SUCCESS
+    then return $ Right ()
+    else return . Left . getEnumCL $ errcode
+clEnqueueWaitForEvents cq events = allocaArray nevents $ \pevents -> do
+  pokeArray pevents events
+  errcode <- raw_clEnqueueWaitForEvents cq cnevents pevents
+  if errcode == getCLValue CL_SUCCESS
+    then return $ Right ()
+    else return . Left . getEnumCL $ errcode
+    where
+      nevents = length events
+      cnevents = fromIntegral nevents
+
+-- | 'clEnqueueBarrier' is a synchronization point that ensures that all queued
+-- commands in command_queue have finished execution before the next batch of
+-- commands can begin execution. It returns 'CL_INVALID_COMMAND_QUEUE' if
+-- command_queue is not a valid command-queue and returns
+-- 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+-- by the OpenCL implementation on the host.
+clEnqueueBarrier :: CLCommandQueue -> IO (Either CLError ())
+clEnqueueBarrier cq = do
+  errcode <- raw_clEnqueueBarrier cq
+  if errcode == getCLValue CL_SUCCESS
+    then return $ Right ()
+    else return . Left . getEnumCL $ errcode
+  
+-- -----------------------------------------------------------------------------
+{-| Issues all previously queued OpenCL commands in a command-queue to the
+device associated with the command-queue.  'clFlush' only guarantees that all
+queued commands to command_queue get issued to the appropriate device. There is
+no guarantee that they will be complete after 'clFlush' returns.
+
+ 'clFlush' returns 'True' if the function call was executed successfully. It
+returns 'False' if command_queue is not a valid command-queue or if there is a
+failure to allocate resources required by the OpenCL implementation on the host.
+
+ Any blocking commands queued in a command-queue such as 'clEnqueueReadImage' or
+'clEnqueueReadBuffer' with blocking_read set to 'True', 'clEnqueueWriteImage' or
+'clEnqueueWriteBuffer' with blocking_write set to 'True', 'clEnqueueMapImage' or
+'clEnqueueMapBuffer' with blocking_map set to 'True' or 'clWaitForEvents'
+perform an implicit flush of the command-queue.
+
+ To use event objects that refer to commands enqueued in a command-queue as
+event objects to wait on by commands enqueued in a different command-queue, the
+application must call a 'clFlush' or any blocking commands that perform an
+implicit flush of the command-queue where the commands that refer to these event
+objects are enqueued.
+-}
+clFlush :: CLCommandQueue -> IO Bool
+clFlush = wrapCheckSuccess . raw_clFlush
+             
+-- | Blocks until all previously queued OpenCL commands in a command-queue are 
+-- issued to the associated device and have completed.
+-- 'clFinish' does not return until all queued commands in command_queue have 
+-- been processed and completed. 'clFinish' is also a synchronization point.
+--
+-- 'clFinish' returns 'True' if the function call was executed successfully. It 
+-- returns 'False' if command_queue is not a valid command-queue or if there is 
+-- a failure to allocate resources required by the OpenCL implementation on the 
+-- host.
+clFinish :: CLCommandQueue -> IO Bool
+clFinish = wrapCheckSuccess . raw_clFinish
+             
+-- -----------------------------------------------------------------------------
diff --git a/src/System/GPU/OpenCL/Context.chs b/src/System/GPU/OpenCL/Context.chs
new file mode 100644
--- /dev/null
+++ b/src/System/GPU/OpenCL/Context.chs
@@ -0,0 +1,150 @@
+-- -----------------------------------------------------------------------------
+-- This file is part of Haskell-Opencl.
+
+-- Haskell-Opencl is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- Haskell-Opencl is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with Haskell-Opencl.  If not, see <http://www.gnu.org/licenses/>.
+-- -----------------------------------------------------------------------------
+{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}
+module System.GPU.OpenCL.Context(
+  -- * Types
+  CLContext,
+  -- * Context Functions
+  clCreateContext, clCreateContextFromType, clRetainContext, clReleaseContext,
+  clGetContextReferenceCount, clGetContextDevices )
+    where
+
+-- -----------------------------------------------------------------------------
+import Foreign( 
+  Ptr, FunPtr, nullPtr, castPtr, alloca, allocaArray, peek, peekArray, 
+  pokeArray )
+import Foreign.C.Types( CSize )
+import Foreign.C.String( CString, peekCString )
+import Foreign.Storable( sizeOf )
+import System.GPU.OpenCL.Types( 
+  CLuint, CLint, CLDeviceType_, CLContextInfo_, CLContextProperty_, CLDeviceID, 
+  CLContext, CLDeviceType, CLError(..), bitmaskFromFlags, getCLValue, getEnumCL, 
+  wrapCheckSuccess, wrapPError, wrapGetInfo )
+
+#include <CL/cl.h>
+
+-- -----------------------------------------------------------------------------
+type ContextCallback = CString -> Ptr () -> CSize -> Ptr () -> IO ()
+foreign import ccall "wrapper" wrapContextCallback :: 
+  ContextCallback -> IO (FunPtr ContextCallback)
+foreign import ccall "clCreateContext" raw_clCreateContext ::
+  Ptr CLContextProperty_ -> CLuint -> Ptr CLDeviceID -> FunPtr ContextCallback -> 
+  Ptr () -> Ptr CLint -> IO CLContext
+foreign import ccall "clCreateContextFromType" raw_clCreateContextFromType :: 
+  Ptr CLContextProperty_ -> CLDeviceType_ -> FunPtr ContextCallback -> 
+  Ptr () -> Ptr CLint -> IO CLContext
+foreign import ccall "clRetainContext" raw_clRetainContext :: 
+  CLContext -> IO CLint
+foreign import ccall "clReleaseContext" raw_clReleaseContext :: 
+  CLContext -> IO CLint
+foreign import ccall "clGetContextInfo" raw_clGetContextInfo :: 
+  CLContext -> CLContextInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+
+-- -----------------------------------------------------------------------------
+mkContextCallback :: (String -> IO ()) -> ContextCallback
+mkContextCallback f msg _ _ _ = peekCString msg >>= f
+
+-- | Creates an OpenCL context.
+-- An OpenCL context is created with one or more devices. Contexts are used by 
+-- the OpenCL runtime for managing objects such as command-queues, memory, 
+-- program and kernel objects and for executing kernels on one or more devices 
+-- specified in the context.
+clCreateContext :: [CLDeviceID] -> (String -> IO ()) 
+                   -> IO (Either CLError CLContext)
+clCreateContext devs f = allocaArray ndevs $ \pdevs -> do
+  pokeArray pdevs devs
+  wrapPError $ \perr -> do
+    fptr <- wrapContextCallback $ mkContextCallback f
+    raw_clCreateContext nullPtr cndevs pdevs fptr nullPtr perr
+    where
+      ndevs = length devs
+      cndevs = fromIntegral ndevs
+
+-- | Create an OpenCL context from a device type that identifies the specific 
+-- device(s) to use.
+clCreateContextFromType :: [CLDeviceType] -> (String -> IO ()) 
+                           -> IO (Either CLError CLContext)
+clCreateContextFromType xs f = wrapPError $ \perr -> do
+  fptr <- wrapContextCallback $ mkContextCallback f
+  raw_clCreateContextFromType nullPtr types fptr nullPtr perr
+    where
+      types = bitmaskFromFlags xs
+
+-- | Increment the context reference count.
+-- 'clCreateContext' and 'clCreateContextFromType' perform an implicit retain. 
+-- This is very helpful for 3rd party libraries, which typically get a context 
+-- passed to them by the application. However, it is possible that the 
+-- application may delete the context without informing the library. Allowing 
+-- functions to attach to (i.e. retain) and release a context solves the 
+-- problem of a context being used by a library no longer being valid.
+-- Returns 'True' if the function is executed successfully, or 'False' if 
+-- context is not a valid OpenCL context.
+clRetainContext :: CLContext -> IO Bool
+clRetainContext ctx = wrapCheckSuccess $ raw_clRetainContext ctx 
+
+-- | Decrement the context reference count.
+-- After the context reference count becomes zero and all the objects attached 
+-- to context (such as memory objects, command-queues) are released, the 
+-- context is deleted.
+-- Returns 'True' if the function is executed successfully, or 'False' if 
+-- context is not a valid OpenCL context.
+clReleaseContext :: CLContext -> IO Bool
+clReleaseContext ctx = wrapCheckSuccess $ raw_clReleaseContext ctx 
+
+getContextInfoSize :: CLContext -> CLContextInfo_ -> IO (Either CLError CSize)
+getContextInfoSize ctx infoid = alloca $ \(value_size :: Ptr CSize) -> do
+  errcode <- raw_clGetContextInfo ctx infoid 0 nullPtr value_size
+  if errcode == getCLValue CL_SUCCESS
+    then fmap Right $ peek value_size
+    else return . Left . getEnumCL $ errcode
+
+#c
+enum CLContextInfo {
+  cL_CONTEXT_REFERENCE_COUNT=CL_CONTEXT_REFERENCE_COUNT,
+  cL_CONTEXT_DEVICES=CL_CONTEXT_DEVICES,
+  cL_CONTEXT_PROPERTIES=CL_CONTEXT_PROPERTIES
+  };
+#endc
+{#enum CLContextInfo {upcaseFirstLetter} #}
+
+-- | Return the context reference count. The reference count returned should be 
+-- considered immediately stale. It is unsuitable for general use in 
+-- applications. This feature is provided for identifying memory leaks.
+clGetContextReferenceCount :: CLContext -> IO (Either CLError CLuint)
+clGetContextReferenceCount ctx = wrapGetInfo (\(dat :: Ptr CLuint) 
+                                              -> raw_clGetContextInfo ctx infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_CONTEXT_REFERENCE_COUNT
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+-- | Return the list of devices in context.
+clGetContextDevices :: CLContext -> IO (Either CLError [CLDeviceID])
+clGetContextDevices ctx = do
+  val <- getContextInfoSize ctx infoid
+  case val of
+    Left err -> return . Left $ err
+    Right size -> let n = (fromIntegral size) `div` elemSize
+                 in allocaArray n $ \(buff :: Ptr CLDeviceID) -> do
+      errcode <- raw_clGetContextInfo ctx infoid size (castPtr buff) nullPtr
+      if errcode == getCLValue CL_SUCCESS
+        then fmap Right $ peekArray n buff
+        else return . Left . getEnumCL $ errcode
+    where
+      infoid = getCLValue CL_CONTEXT_DEVICES
+      elemSize = sizeOf (nullPtr :: CLDeviceID)
+
+-- -----------------------------------------------------------------------------
diff --git a/src/System/GPU/OpenCL/Event.chs b/src/System/GPU/OpenCL/Event.chs
new file mode 100644
--- /dev/null
+++ b/src/System/GPU/OpenCL/Event.chs
@@ -0,0 +1,158 @@
+-- -----------------------------------------------------------------------------
+-- This file is part of Haskell-Opencl.
+
+-- Haskell-Opencl is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- Haskell-Opencl is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with Haskell-Opencl.  If not, see <http://www.gnu.org/licenses/>.
+-- -----------------------------------------------------------------------------
+{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}
+module System.GPU.OpenCL.Event(  
+  -- * Types
+  CLEvent, CLCommandType(..), CLProfilingInfo(..), CLCommandExecutionStatus(..),
+  -- * Functions
+  clWaitForEvents, clRetainEvent, clReleaseEvent, clGetEventCommandQueue, 
+  clGetEventCommandType, clGetEventReferenceCount, 
+  clGetEventCommandExecutionStatus, clGetEventProfilingInfo
+  ) where
+
+-- -----------------------------------------------------------------------------
+import Foreign
+import Foreign.C.Types
+import System.GPU.OpenCL.Types( 
+  CLEvent, CLint, CLuint, CLulong, CLEventInfo_, CLProfilingInfo_, CLError(..),
+  CLCommandQueue, CLCommandType(..), CLCommandType_, 
+  CLCommandExecutionStatus(..), CLProfilingInfo(..), getCommandExecutionStatus, 
+  getCLValue, getEnumCL, wrapCheckSuccess, wrapGetInfo )
+
+#include <CL/cl.h>
+
+-- -----------------------------------------------------------------------------
+foreign import ccall "clWaitForEvents" raw_clWaitForEvents :: 
+  CLuint -> Ptr CLEvent -> IO CLint
+foreign import ccall "clGetEventInfo" raw_clGetEventInfo :: 
+  CLEvent -> CLEventInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+foreign import ccall "clRetainEvent" raw_clRetainEvent :: 
+  CLEvent -> IO CLint 
+foreign import ccall "clReleaseEvent" raw_clReleaseEvent :: 
+  CLEvent -> IO CLint 
+foreign import ccall "clGetEventProfilingInfo" raw_clGetEventProfilingInfo :: 
+  CLEvent -> CLProfilingInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+
+-- -----------------------------------------------------------------------------
+-- | Waits on the host thread for commands identified by event objects in 
+-- event_list to complete. A command is considered complete if its execution 
+-- status is 'CL_COMPLETE' or a negative value.
+-- Returns 'True' if the function was executed successfully. It returns 'False'
+-- if the list of events is empty, or if events specified in event_list do not 
+-- belong to the same context, or if event objects specified in event_list are 
+-- not valid event objects.
+clWaitForEvents :: [CLEvent] -> IO Bool
+clWaitForEvents [] = return False
+clWaitForEvents xs = allocaArray nevents $ \pevents -> do
+  pokeArray pevents xs
+  wrapCheckSuccess $ raw_clWaitForEvents (fromIntegral nevents) pevents
+    where
+      nevents = length xs
+  
+-- | Increments the event reference count.
+-- The OpenCL commands that return an event perform an implicit retain.
+-- Returns 'True' if the function is executed successfully. It returns 'False' 
+-- if event is not a valid event object.
+clRetainEvent :: CLEvent -> IO Bool
+clRetainEvent ev = wrapCheckSuccess $ raw_clRetainEvent ev
+
+-- | Decrements the event reference count.
+-- Decrements the event reference count. The event object is deleted once the 
+-- reference count becomes zero, the specific command identified by this event 
+-- has completed (or terminated) and there are no commands in the command-queues 
+-- of a context that require a wait for this event to complete.
+-- Returns 'True' if the function is executed successfully. It returns 'False' 
+-- if event is not a valid event object.
+clReleaseEvent :: CLEvent -> IO Bool
+clReleaseEvent ev = wrapCheckSuccess $ raw_clReleaseEvent ev
+
+#c
+enum CLEventInfo {
+  cL_EVENT_COMMAND_QUEUE=CL_EVENT_COMMAND_QUEUE,
+  cL_EVENT_COMMAND_TYPE=CL_EVENT_COMMAND_TYPE,
+  cL_EVENT_COMMAND_EXECUTION_STATUS=CL_EVENT_COMMAND_EXECUTION_STATUS,
+  cL_EVENT_REFERENCE_COUNT=CL_EVENT_REFERENCE_COUNT
+  };
+#endc
+{#enum CLEventInfo {upcaseFirstLetter} #}
+
+
+-- | Return the command-queue associated with event.
+clGetEventCommandQueue :: CLEvent -> IO (Either CLError CLCommandQueue)
+clGetEventCommandQueue ev = wrapGetInfo (\(dat :: Ptr CLCommandQueue) 
+                                         -> raw_clGetEventInfo ev infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_EVENT_COMMAND_QUEUE
+      size = fromIntegral $ sizeOf (nullPtr::CLCommandQueue)
+      
+-- | Return the command associated with event.
+clGetEventCommandType :: CLEvent -> IO (Either CLError CLCommandType)
+clGetEventCommandType ev = wrapGetInfo (\(dat :: Ptr CLCommandType_) 
+                                        -> raw_clGetEventInfo ev infoid size (castPtr dat)) getEnumCL
+    where 
+      infoid = getCLValue CL_EVENT_COMMAND_TYPE
+      size = fromIntegral $ sizeOf (0::CLCommandType_)
+      
+-- | Return the event reference count. The reference count returned should be 
+-- considered immediately stale. It is unsuitable for general use in applications. 
+-- This feature is provided for identifying memory leaks.
+clGetEventReferenceCount :: CLEvent -> IO (Either CLError CLint)
+clGetEventReferenceCount ev = wrapGetInfo (\(dat :: Ptr CLint) 
+                                           -> raw_clGetEventInfo ev infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_EVENT_REFERENCE_COUNT
+      size = fromIntegral $ sizeOf (0::CLint)
+
+-- | Return the execution status of the command identified by event.
+clGetEventCommandExecutionStatus :: CLEvent -> IO (Either CLError CLCommandExecutionStatus)
+clGetEventCommandExecutionStatus ev = wrapGetInfo (\(dat :: Ptr CLint) 
+                                                   -> raw_clGetEventInfo ev infoid size (castPtr dat)) getCommandExecutionStatus
+    where 
+      infoid = getCLValue CL_EVENT_COMMAND_EXECUTION_STATUS
+      size = fromIntegral $ sizeOf (0::CLint)
+      
+{-| Returns profiling information for the command associated with event if 
+profiling is enabled. The unsigned 64-bit values returned can be used to measure 
+the time in nano-seconds consumed by OpenCL commands.
+
+OpenCL devices are required to correctly track time across changes in device 
+frequency and power states. The 'CL_DEVICE_PROFILING_TIMER_RESOLUTION' specifies 
+the resolution of the timer i.e. the number of nanoseconds elapsed before the 
+timer is incremented.
+
+Event objects can be used to capture profiling information that measure 
+execution time of a command. Profiling of OpenCL commands can be enabled either 
+by using a command-queue created with 'CL_QUEUE_PROFILING_ENABLE' flag set in 
+properties argument to clCreateCommandQueue or by setting the 
+'CL_QUEUE_PROFILING_ENABLE' flag in properties argument to 
+'clSetCommandQueueProperty'.
+
+'clGetEventProfilingInfo' returns the valueif the function is executed 
+successfully and the profiling information has been recorded, and returns 
+'Nothing'  if the 'CL_QUEUE_PROFILING_ENABLE' flag is not set for the 
+command-queue and if the profiling information is currently not available 
+(because the command identified by event has not completed), or if event is a 
+not a valid event object.
+-} 
+clGetEventProfilingInfo :: CLEvent -> CLProfilingInfo -> IO (Either CLError CLulong)
+clGetEventProfilingInfo ev prof = wrapGetInfo (\(dat :: Ptr CLulong) 
+                                               -> raw_clGetEventProfilingInfo ev infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue prof
+      size = fromIntegral $ sizeOf (0::CLulong)
+
+-- -----------------------------------------------------------------------------
diff --git a/src/System/GPU/OpenCL/Memory.chs b/src/System/GPU/OpenCL/Memory.chs
new file mode 100644
--- /dev/null
+++ b/src/System/GPU/OpenCL/Memory.chs
@@ -0,0 +1,286 @@
+-- -----------------------------------------------------------------------------
+-- This file is part of Haskell-Opencl.
+
+-- Haskell-Opencl is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- Haskell-Opencl is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with Haskell-Opencl.  If not, see <http://www.gnu.org/licenses/>.
+-- -----------------------------------------------------------------------------
+{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}
+module System.GPU.OpenCL.Memory(
+  -- * Types
+  CLMem, CLSampler, CLMemFlag(..), CLMemObjectType(..), CLAddressingMode(..), 
+  CLFilterMode(..),
+  -- * Memory Functions
+  clCreateBuffer, clRetainMemObject, clReleaseMemObject, clGetMemType, 
+  clGetMemFlags, clGetMemSize, clGetMemHostPtr, clGetMemMapCount, 
+  clGetMemReferenceCount, clGetMemContext,
+  -- * Sampler Functions
+  clCreateSampler, clRetainSampler, clReleaseSampler, clGetSamplerReferenceCount, 
+  clGetSamplerContext, clGetSamplerAddressingMode, clGetSamplerFilterMode, 
+  clGetSamplerNormalizedCoords
+  ) where
+
+-- -----------------------------------------------------------------------------
+import Foreign
+import Foreign.C.Types
+import System.GPU.OpenCL.Types( 
+  CLMem, CLContext, CLSampler, CLint, CLuint, CLbool, CLMemFlags_, CLError(..), 
+  CLMemInfo_, CLAddressingMode_, CLFilterMode_, CLSamplerInfo_, 
+  CLAddressingMode(..), CLFilterMode(..), CLMemFlag(..), CLMemObjectType_, 
+  CLMemObjectType(..), 
+  wrapPError, wrapCheckSuccess, wrapGetInfo, getEnumCL, bitmaskFromFlags, 
+  bitmaskToMemFlags, getCLValue )
+
+#include <CL/cl.h>
+
+-- -----------------------------------------------------------------------------
+foreign import ccall "clCreateBuffer" raw_clCreateBuffer :: 
+  CLContext -> CLMemFlags_ -> CSize -> Ptr () -> Ptr CLint -> IO CLMem
+--foreign import ccall "clCreateImage2D" raw_clCreateImage2D :: 
+--  CLContext -> CLMemFlags_ -> CLImageFormat_p -> CSize -> CSize -> CSize 
+--  -> Ptr () -> Ptr CLint -> IO CLMem
+--foreign import ccall "clCreateImage3D" raw_clCreateImage3D :: 
+--  CLContext -> CLMemFlags_-> CLImageFormat_p -> CSize -> CSize -> CSize -> CSize 
+--  -> CSize -> Ptr () -> Ptr CLint -> IO CLMem
+foreign import ccall "clRetainMemObject" raw_clRetainMemObject :: 
+  CLMem -> IO CLint
+foreign import ccall "clReleaseMemObject" raw_clReleaseMemObject :: 
+  CLMem -> IO CLint
+--foreign import ccall "clGetSupportedImageFormats" raw_clGetSupportedImageFormats :: 
+--  CLContext -> CLMemFlags_ -> CLMemObjectType_ -> CLuint -> CLImageFormat_p 
+--  -> Ptr CLuint -> IO CLint
+foreign import ccall "clGetMemObjectInfo" raw_clGetMemObjectInfo :: 
+  CLMem -> CLMemInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+--foreign import ccall "clGetImageInfo" raw_clGetImageInfo :: 
+--  CLMem -> CLImageInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+foreign import ccall "clCreateSampler" raw_clCreateSampler :: 
+  CLContext -> CLbool -> CLAddressingMode_ -> CLFilterMode_ -> Ptr CLint -> IO CLSampler
+foreign import ccall "clRetainSampler" raw_clRetainSampler :: 
+  CLSampler -> IO CLint
+foreign import ccall "clReleaseSampler" raw_clReleaseSampler :: 
+  CLSampler -> IO CLint
+foreign import ccall "clGetSamplerInfo" raw_clGetSamplerInfo :: 
+  CLSampler -> CLSamplerInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+
+-- -----------------------------------------------------------------------------
+{-| Creates a buffer object. Returns a valid non-zero buffer object if the
+buffer object is created successfully. Otherwise, it returns: 
+
+ * 'CL_INVALID_CONTEXT' if context is not a valid context.
+
+ * 'CL_INVALID_VALUE' if values specified in flags are not valid.
+
+ * 'CL_INVALID_BUFFER_SIZE' if size is 0 or is greater than
+'clDeviceMaxMemAllocSize' value for all devices in context.
+
+ * 'CL_INVALID_HOST_PTR' if host_ptr is NULL and 'CL_MEM_USE_HOST_PTR' or
+'CL_MEM_COPY_HOST_PTR' are set in flags or if host_ptr is not NULL but
+'CL_MEM_COPY_HOST_PTR' or 'CL_MEM_USE_HOST_PTR' are not set in flags.
+
+ * 'CL_MEM_OBJECT_ALLOCATION_FAILURE' if there is a failure to allocate memory
+for buffer object.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.
+-}
+clCreateBuffer :: Integral a => CLContext -> [CLMemFlag] -> (a, Ptr ()) -> IO (Either CLError CLMem)
+clCreateBuffer ctx xs (sbuff,buff) = wrapPError $ \perr -> do
+  raw_clCreateBuffer ctx flags (fromIntegral sbuff) buff perr
+    where
+      flags = bitmaskFromFlags xs
+    
+-- | Increments the memory object reference count. returns 'True' if the
+-- function is executed successfully. After the memobj reference count becomes
+-- zero and commands queued for execution on a command-queue(s) that use memobj
+-- have finished, the memory object is deleted. It returns 'False' if memobj is
+-- not a valid memory object.
+clRetainMemObject :: CLMem -> IO Bool
+clRetainMemObject mem = wrapCheckSuccess $ raw_clRetainMemObject mem
+
+-- | Decrements the memory object reference count. After the memobj reference
+-- count becomes zero and commands queued for execution on a command-queue(s)
+-- that use memobj have finished, the memory object is deleted. Returns 'True'
+-- if the function is executed successfully. It returns 'False' if memobj is not
+-- a valid memory object.
+clReleaseMemObject :: CLMem -> IO Bool
+clReleaseMemObject mem = wrapCheckSuccess $ raw_clReleaseMemObject mem
+
+#c
+enum CLMemInfo {
+  cL_MEM_TYPE=CL_MEM_TYPE,
+  cL_MEM_FLAGS=CL_MEM_FLAGS,
+  cL_MEM_SIZE=CL_MEM_SIZE,
+  cL_MEM_HOST_PTR=CL_MEM_HOST_PTR,
+  cL_MEM_MAP_COUNT=CL_MEM_MAP_COUNT,
+  cL_MEM_REFERENCE_COUNT=CL_MEM_REFERENCE_COUNT,
+  cL_MEM_CONTEXT=CL_MEM_CONTEXT,
+  };
+#endc
+{#enum CLMemInfo {upcaseFirstLetter} #}
+
+-- | Returns the mem object type.
+clGetMemType :: CLMem -> IO (Either CLError CLMemObjectType)
+clGetMemType mem = wrapGetInfo (\(dat :: Ptr CLMemObjectType_) 
+                                -> raw_clGetMemObjectInfo mem infoid size (castPtr dat)) getEnumCL
+    where 
+      infoid = getCLValue CL_MEM_TYPE
+      size = fromIntegral $ sizeOf (0::CLMemObjectType_)
+
+-- | Return the flags argument value specified when memobj was created.
+clGetMemFlags :: CLMem -> IO (Either CLError [CLMemFlag])
+clGetMemFlags mem = wrapGetInfo (\(dat :: Ptr CLMemFlags_)
+                                  -> raw_clGetMemObjectInfo mem infoid size (castPtr dat)) bitmaskToMemFlags
+    where 
+      infoid = getCLValue CL_MEM_FLAGS
+      size = fromIntegral $ sizeOf (0::CLMemFlags_)
+
+-- | Return actual size of memobj in bytes.
+clGetMemSize :: CLMem -> IO (Either CLError CSize)
+clGetMemSize mem = wrapGetInfo (\(dat :: Ptr CSize)
+                                 -> raw_clGetMemObjectInfo mem infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_MEM_SIZE
+      size = fromIntegral $ sizeOf (0::CSize)
+
+-- | Return the host_ptr argument value specified when memobj is created.
+clGetMemHostPtr :: CLMem -> IO (Either CLError (Ptr ()))
+clGetMemHostPtr mem = wrapGetInfo (\(dat :: Ptr (Ptr ()))
+                                   -> raw_clGetMemObjectInfo mem infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_MEM_HOST_PTR
+      size = fromIntegral $ sizeOf (nullPtr::Ptr ())
+
+-- | Map count. The map count returned should be considered immediately
+-- stale. It is unsuitable for general use in applications. This feature is
+-- provided for debugging.
+clGetMemMapCount :: CLMem -> IO (Either CLError CLuint)
+clGetMemMapCount mem = wrapGetInfo (\(dat :: Ptr CLuint)
+                                   -> raw_clGetMemObjectInfo mem infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_MEM_MAP_COUNT
+      size = fromIntegral $ sizeOf (0 :: CLuint)
+
+-- | Return memobj reference count. The reference count returned should be
+-- considered immediately stale. It is unsuitable for general use in
+-- applications. This feature is provided for identifying memory leaks.
+clGetMemReferenceCount :: CLMem -> IO (Either CLError CLuint)
+clGetMemReferenceCount mem = wrapGetInfo (\(dat :: Ptr CLuint)
+                                   -> raw_clGetMemObjectInfo mem infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_MEM_REFERENCE_COUNT
+      size = fromIntegral $ sizeOf (0 :: CLuint)
+
+-- | Return context specified when memory object is created.
+clGetMemContext :: CLMem -> IO (Either CLError CLContext)
+clGetMemContext mem = wrapGetInfo (\(dat :: Ptr CLContext)
+                                   -> raw_clGetMemObjectInfo mem infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_MEM_CONTEXT
+      size = fromIntegral $ sizeOf (0 :: CLuint)
+
+-- -----------------------------------------------------------------------------
+{-| Creates a sampler object. A sampler object describes how to sample an image
+when the image is read in the kernel. The built-in functions to read from an
+image in a kernel take a sampler as an argument. The sampler arguments to the
+image read function can be sampler objects created using OpenCL functions and
+passed as argument values to the kernel or can be samplers declared inside a
+kernel. In this section we discuss how sampler objects are created using OpenCL
+functions.
+
+Returns a valid non-zero sampler object if the sampler object is created
+successfully. Otherwise, it returns one of the following error values:
+
+ * 'CL_INVALID_CONTEXT' if context is not a valid context.
+
+ * 'CL_INVALID_VALUE' if addressing_mode, filter_mode, or normalized_coords or a
+combination of these argument values are not valid.
+
+ * 'CL_INVALID_OPERATION' if images are not supported by any device associated
+with context (i.e. 'CL_DEVICE_IMAGE_SUPPORT' specified in the table of OpenCL
+Device Queries for clGetDeviceInfo is 'False').
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.
+-}
+clCreateSampler :: CLContext -> Bool -> CLAddressingMode -> CLFilterMode -> IO (Either CLError CLSampler)
+clCreateSampler ctx norm am fm = wrapPError $ \perr -> do
+  raw_clCreateSampler ctx (fromBool norm) (getCLValue am) (getCLValue fm) perr
+
+-- | Increments the sampler reference count. 'clCreateSampler' does an implicit
+-- retain. Returns 'True' if the function is executed successfully. It returns
+-- 'False' if sampler is not a valid sampler object.
+clRetainSampler :: CLSampler -> IO Bool
+clRetainSampler mem = wrapCheckSuccess $ raw_clRetainSampler mem
+
+-- | Decrements the sampler reference count. The sampler object is deleted after
+-- the reference count becomes zero and commands queued for execution on a
+-- command-queue(s) that use sampler have finished. 'clReleaseSampler' returns
+-- 'True' if the function is executed successfully. It returns 'False' if
+-- sampler is not a valid sampler object.
+clReleaseSampler :: CLSampler -> IO Bool
+clReleaseSampler mem = wrapCheckSuccess $ raw_clReleaseSampler mem
+
+#c
+enum CLSamplerInfo {
+  cL_SAMPLER_REFERENCE_COUNT=CL_SAMPLER_REFERENCE_COUNT,
+  cL_SAMPLER_CONTEXT=CL_SAMPLER_CONTEXT,
+  cL_SAMPLER_ADDRESSING_MODE=CL_SAMPLER_ADDRESSING_MODE,
+  cL_SAMPLER_FILTER_MODE=CL_SAMPLER_FILTER_MODE,
+  cL_SAMPLER_NORMALIZED_COORDS=CL_SAMPLER_NORMALIZED_COORDS
+  };
+#endc
+{#enum CLSamplerInfo {upcaseFirstLetter} #}
+
+-- | Return the sampler reference count. The reference count returned should be
+-- considered immediately stale. It is unsuitable for general use in
+-- applications. This feature is provided for identifying memory leaks.
+clGetSamplerReferenceCount :: CLSampler -> IO (Either CLError CLuint)
+clGetSamplerReferenceCount sam = wrapGetInfo (\(dat :: Ptr CLuint)
+                                   -> raw_clGetSamplerInfo sam infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_SAMPLER_REFERENCE_COUNT
+      size = fromIntegral $ sizeOf (0 :: CLuint)
+
+-- | Return the context specified when the sampler is created.
+clGetSamplerContext :: CLSampler -> IO (Either CLError CLContext)
+clGetSamplerContext sam = wrapGetInfo (\(dat :: Ptr CLContext)
+                                       -> raw_clGetSamplerInfo sam infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_SAMPLER_CONTEXT
+      size = fromIntegral $ sizeOf (nullPtr :: CLContext)
+
+-- | Return the value specified by addressing_mode argument to clCreateSampler.
+clGetSamplerAddressingMode :: CLSampler -> IO (Either CLError CLAddressingMode)
+clGetSamplerAddressingMode sam = wrapGetInfo (\(dat :: Ptr CLAddressingMode_)
+                                              -> raw_clGetSamplerInfo sam infoid size (castPtr dat)) getEnumCL
+    where 
+      infoid = getCLValue CL_SAMPLER_ADDRESSING_MODE
+      size = fromIntegral $ sizeOf (0 :: CLAddressingMode_)
+
+-- | Return the value specified by filter_mode argument to clCreateSampler.
+clGetSamplerFilterMode :: CLSampler -> IO (Either CLError CLFilterMode)
+clGetSamplerFilterMode sam = wrapGetInfo (\(dat :: Ptr CLFilterMode_)
+                                          -> raw_clGetSamplerInfo sam infoid size (castPtr dat)) getEnumCL
+    where 
+      infoid = getCLValue CL_SAMPLER_FILTER_MODE
+      size = fromIntegral $ sizeOf (0 :: CLFilterMode_)
+
+-- | Return the value specified by normalized_coords argument to
+-- clCreateSampler.
+clGetSamplerNormalizedCoords :: CLSampler -> IO (Either CLError Bool)
+clGetSamplerNormalizedCoords sam = wrapGetInfo (\(dat :: Ptr CLbool)
+                                                -> raw_clGetSamplerInfo sam infoid size (castPtr dat)) (/=0)
+    where 
+      infoid = getCLValue CL_SAMPLER_NORMALIZED_COORDS
+      size = fromIntegral $ sizeOf (0 :: CLbool)
+
+-- -----------------------------------------------------------------------------
diff --git a/src/System/GPU/OpenCL/Program.chs b/src/System/GPU/OpenCL/Program.chs
new file mode 100644
--- /dev/null
+++ b/src/System/GPU/OpenCL/Program.chs
@@ -0,0 +1,745 @@
+-- -----------------------------------------------------------------------------
+-- This file is part of Haskell-Opencl.
+
+-- Haskell-Opencl is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- Haskell-Opencl is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with Haskell-Opencl.  If not, see <http://www.gnu.org/licenses/>.
+-- -----------------------------------------------------------------------------
+{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}
+module System.GPU.OpenCL.Program(  
+  -- * Types
+  CLProgram, CLBuildStatus(..), CLKernel,
+  -- * Program Functions
+  clCreateProgramWithSource, clRetainProgram, clReleaseProgram, 
+  clUnloadCompiler, clBuildProgram, clGetProgramReferenceCount, 
+  clGetProgramContext, clGetProgramNumDevices, clGetProgramDevices,
+  clGetProgramSource, clGetProgramBinarySizes, clGetProgramBinaries, 
+  clGetProgramBuildStatus, clGetProgramBuildOptions, clGetProgramBuildLog,
+  -- * Kernel Functions
+  clCreateKernel, clCreateKernelsInProgram, clRetainKernel, clReleaseKernel, 
+  clSetKernelArg, clGetKernelFunctionName, clGetKernelNumArgs, 
+  clGetKernelReferenceCount, clGetKernelContext, clGetKernelProgram, 
+  clGetKernelWorkGroupSize, clGetKernelCompileWorkGroupSize, 
+  clGetKernelLocalMemSize
+  ) where
+
+-- -----------------------------------------------------------------------------
+import Control.Monad( zipWithM )
+import Foreign
+import Foreign.C.Types
+import Foreign.C.String( CString, withCString, newCString, peekCString )
+import System.GPU.OpenCL.Types( 
+  CLint, CLuint, CLulong, CLProgram, CLContext, CLKernel, CLDeviceID, 
+  CLError(..), CLProgramInfo_, CLBuildStatus(..), CLBuildStatus_, 
+  CLProgramBuildInfo_, CLKernelInfo_, CLKernelWorkGroupInfo_, wrapCheckSuccess, 
+  wrapPError, wrapGetInfo, getCLValue, getEnumCL )
+
+#include <CL/cl.h>
+
+-- -----------------------------------------------------------------------------
+type BuildCallback = CLProgram -> Ptr () -> IO ()
+foreign import ccall "clCreateProgramWithSource" raw_clCreateProgramWithSource :: 
+  CLContext -> CLuint -> Ptr CString -> Ptr CSize -> Ptr CLint -> IO CLProgram
+--foreign import ccall "clCreateProgramWithBinary" raw_clCreateProgramWithBinary :: 
+--  CLContext -> CLuint -> Ptr CLDeviceID -> Ptr CSize -> Ptr (Ptr Word8) -> Ptr CLint -> Ptr CLint -> IO CLProgram
+foreign import ccall "clRetainProgram" raw_clRetainProgram :: 
+  CLProgram -> IO CLint
+foreign import ccall "clReleaseProgram" raw_clReleaseProgram :: 
+  CLProgram -> IO CLint
+foreign import ccall "clBuildProgram" raw_clBuildProgram :: 
+  CLProgram -> CLuint -> Ptr CLDeviceID -> CString -> FunPtr BuildCallback -> Ptr () -> IO CLint
+foreign import ccall "clUnloadCompiler" raw_clUnloadCompiler :: 
+  IO CLint
+foreign import ccall "clGetProgramInfo" raw_clGetProgramInfo :: 
+  CLProgram -> CLProgramInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+foreign import ccall "clGetProgramBuildInfo"  raw_clGetProgramBuildInfo :: 
+  CLProgram -> CLDeviceID -> CLProgramBuildInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+foreign import ccall "clCreateKernel" raw_clCreateKernel :: 
+  CLProgram -> CString -> Ptr CLint -> IO CLKernel 
+foreign import ccall "clCreateKernelsInProgram" raw_clCreateKernelsInProgram :: 
+  CLProgram -> CLuint -> Ptr CLKernel -> Ptr CLuint -> IO CLint 
+foreign import ccall "clRetainKernel" raw_clRetainKernel :: 
+  CLKernel -> IO CLint 
+foreign import ccall "clReleaseKernel" raw_clReleaseKernel :: 
+  CLKernel -> IO CLint 
+foreign import ccall "clSetKernelArg" raw_clSetKernelArg :: 
+  CLKernel -> CLuint -> CSize -> Ptr () -> IO CLint
+foreign import ccall "clGetKernelInfo" raw_clGetKernelInfo :: 
+  CLKernel -> CLKernelInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+foreign import ccall "clGetKernelWorkGroupInfo" raw_clGetKernelWorkGroupInfo :: 
+  CLKernel -> CLDeviceID -> CLKernelWorkGroupInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+
+-- -----------------------------------------------------------------------------
+{-| Creates a program object for a context, and loads the source code specified
+by the text strings in the strings array into the program object. The devices
+associated with the program object are the devices associated with context.
+
+OpenCL allows applications to create a program object using the program source
+or binary and build appropriate program executables. This allows applications to
+determine whether they want to use the pre-built offline binary or load and
+compile the program source and use the executable compiled/linked online as the
+program executable. This can be very useful as it allows applications to load
+and build program executables online on its first instance for appropriate
+OpenCL devices in the system. These executables can now be queried and cached by
+the application. Future instances of the application launching will no longer
+need to compile and build the program executables. The cached executables can be
+read and loaded by the application, which can help significantly reduce the
+application initialization time.
+
+An OpenCL program consists of a set of kernels that are identified as functions
+declared with the __kernel qualifier in the program source. OpenCL programs may
+also contain auxiliary functions and constant data that can be used by __kernel
+functions. The program executable can be generated online or offline by the
+OpenCL compiler for the appropriate target device(s).
+
+'clCreateProgramWithSource' returns a valid non-zero program object if the
+program object is created successfully. Otherwise, it returns one of the
+following error values:
+
+ * 'CL_INVALID_CONTEXT' if context is not a valid context.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.  
+-}
+clCreateProgramWithSource :: CLContext -> String -> IO (Either CLError CLProgram)
+clCreateProgramWithSource ctx source = wrapPError $ \perr -> do
+  let strings = lines source
+      count = fromIntegral $ length strings
+  cstrings <- mapM newCString strings
+  prog <- withArray cstrings $ \srcArray -> do
+    raw_clCreateProgramWithSource ctx count srcArray nullPtr perr
+  mapM_ free cstrings
+  return prog
+  
+-- | Increments the program reference count. 'clRetainProgram' returns 'True' if 
+-- the function is executed successfully. It returns 'False' if program is not a 
+-- valid program object.
+clRetainProgram :: CLProgram -> IO Bool
+clRetainProgram prg = wrapCheckSuccess $ raw_clRetainProgram prg
+
+-- | Decrements the program reference count. The program object is deleted after 
+-- all kernel objects associated with program have been deleted and the program 
+-- reference count becomes zero. 'clReleseProgram' returns 'True' if 
+-- the function is executed successfully. It returns 'False' if program is not a 
+-- valid program object.
+clReleaseProgram :: CLProgram -> IO Bool
+clReleaseProgram prg = wrapCheckSuccess $ raw_clReleaseProgram prg
+
+-- | Allows the implementation to release the resources allocated by the OpenCL
+-- compiler. This is a hint from the application and does not guarantee that the
+-- compiler will not be used in the future or that the compiler will actually be
+-- unloaded by the implementation. Calls to 'clBuildProgram' after
+-- 'clUnloadCompiler' will reload the compiler, if necessary, to build the
+-- appropriate program executable.
+clUnloadCompiler :: IO ()
+clUnloadCompiler = raw_clUnloadCompiler >> return ()
+
+{-| Builds (compiles and links) a program executable from the program source or
+binary. OpenCL allows program executables to be built using the source or the
+binary. The build options are categorized as pre-processor options, options for
+math intrinsics, options that control optimization and miscellaneous
+options. This specification defines a standard set of options that must be
+supported by an OpenCL compiler when building program executables online or
+offline. These may be extended by a set of vendor- or platform-specific options.
+
+ * Preprocessor Options
+
+These options control the OpenCL preprocessor which is run on each program
+source before actual compilation. -D options are processed in the order they are
+given in the options argument to clBuildProgram.
+
+ [-D name] Predefine name as a macro, with definition 1.
+
+ [-D name=definition] The contents of definition are tokenized and processed as
+if they appeared during translation phase three in a `#define' directive. In
+particular, the definition will be truncated by embedded newline characters.
+
+ [-I dir] Add the directory dir to the list of directories to be searched for
+header files.
+
+ * Math Intrinsics Options
+
+These options control compiler behavior regarding floating-point
+arithmetic. These options trade off between speed and correctness.
+
+ [-cl-single-precision-constant] Treat double precision floating-point constant
+as single precision constant.
+
+ [-cl-denorms-are-zero] This option controls how single precision and double
+precision denormalized numbers are handled. If specified as a build option, the
+single precision denormalized numbers may be flushed to zero and if the optional
+extension for double precision is supported, double precision denormalized
+numbers may also be flushed to zero. This is intended to be a performance hint
+and the OpenCL compiler can choose not to flush denorms to zero if the device
+supports single precision (or double precision) denormalized numbers.
+
+This option is ignored for single precision numbers if the device does not
+support single precision denormalized numbers i.e. 'CL_FP_DENORM' bit is not set
+in 'clGetDeviceSingleFPConfig'.
+
+This option is ignored for double precision numbers if the device does not
+support double precision or if it does support double precison but
+'CL_FP_DENORM' bit is not set in 'clGetDeviceDoubleFPConfig'.
+
+This flag only applies for scalar and vector single precision floating-point
+variables and computations on these floating-point variables inside a
+program. It does not apply to reading from or writing to image objects.
+
+ * Optimization Options
+
+These options control various sorts of optimizations. Turning on optimization
+flags makes the compiler attempt to improve the performance and/or code size at
+the expense of compilation time and possibly the ability to debug the program.
+
+ [-cl-opt-disable] This option disables all optimizations. The default is
+optimizations are enabled.
+
+ [-cl-strict-aliasing] This option allows the compiler to assume the strictest
+aliasing rules.
+
+The following options control compiler behavior regarding floating-point
+arithmetic. These options trade off between performance and correctness and must
+be specifically enabled. These options are not turned on by default since it can
+result in incorrect output for programs which depend on an exact implementation
+of IEEE 754 rules/specifications for math functions.
+
+ [-cl-mad-enable] Allow a * b + c to be replaced by a mad. The mad computes a *
+b + c with reduced accuracy. For example, some OpenCL devices implement mad as
+truncate the result of a * b before adding it to c.
+
+ [-cl-no-signed-zeros] Allow optimizations for floating-point arithmetic that
+ignore the signedness of zero. IEEE 754 arithmetic specifies the behavior of
+distinct +0.0 and -0.0 values, which then prohibits simplification of
+expressions such as x+0.0 or 0.0*x (even with -clfinite-math only). This option
+implies that the sign of a zero result isn't significant.
+
+ [-cl-unsafe-math-optimizations] Allow optimizations for floating-point
+arithmetic that (a) assume that arguments and results are valid, (b) may violate
+IEEE 754 standard and (c) may violate the OpenCL numerical compliance
+requirements as defined in section 7.4 for single-precision floating-point,
+section 9.3.9 for double-precision floating-point, and edge case behavior in
+section 7.5. This option includes the -cl-no-signed-zeros and -cl-mad-enable
+options.
+
+ [-cl-finite-math-only] Allow optimizations for floating-point arithmetic that
+assume that arguments and results are not NaNs or ±∞. This option may violate
+the OpenCL numerical compliance requirements defined in in section 7.4 for
+single-precision floating-point, section 9.3.9 for double-precision
+floating-point, and edge case behavior in section 7.5.
+
+ [-cl-fast-relaxed-math] Sets the optimization options -cl-finite-math-only and
+-cl-unsafe-math-optimizations. This allows optimizations for floating-point
+arithmetic that may violate the IEEE 754 standard and the OpenCL numerical
+compliance requirements defined in the specification in section 7.4 for
+single-precision floating-point, section 9.3.9 for double-precision
+floating-point, and edge case behavior in section 7.5. This option causes the
+preprocessor macro __FAST_RELAXED_MATH__ to be defined in the OpenCL program.
+
+ * Options to Request or Suppress Warnings
+
+Warnings are diagnostic messages that report constructions which are not
+inherently erroneous but which are risky or suggest there may have been an
+error. The following languageindependent options do not enable specific warnings
+but control the kinds of diagnostics produced by the OpenCL compiler.
+
+ [-w] Inhibit all warning messages.
+ 
+ [-Werror] Make all warnings into errors.
+
+clBuildProgram returns the following errors when fails:
+
+ * 'CL_INVALID_PROGRAM' if program is not a valid program object.
+
+ * 'CL_INVALID_DEVICE' if OpenCL devices listed in device_list are not in the
+list of devices associated with program.
+
+ * 'CL_INVALID_BINARY' if program is created with
+'clCreateWithProgramWithBinary' and devices listed in device_list do not have a
+valid program binary loaded.
+
+ * 'CL_INVALID_BUILD_OPTIONS' if the build options specified by options are
+invalid.
+
+ * 'CL_INVALID_OPERATION' if the build of a program executable for any of the
+devices listed in device_list by a previous call to 'clBuildProgram' for program
+has not completed.
+
+ * 'CL_COMPILER_NOT_AVAILABLE' if program is created with
+'clCreateProgramWithSource' and a compiler is not available
+i.e. 'clGetDeviceCompilerAvailable' is set to 'False'.
+
+ * 'CL_BUILD_PROGRAM_FAILURE' if there is a failure to build the program
+executable. This error will be returned if 'clBuildProgram' does not return
+until the build has completed.
+
+ * 'CL_INVALID_OPERATION' if there are kernel objects attached to program.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.  
+-}
+clBuildProgram :: CLProgram -> [CLDeviceID] -> String -> IO (Either CLError ())
+clBuildProgram prg devs opts = allocaArray ndevs $ \pdevs -> do
+  pokeArray pdevs devs
+  withCString opts $ \copts -> do
+    errcode <- raw_clBuildProgram prg cndevs pdevs copts nullFunPtr nullPtr
+    if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+      then return $ Right ()
+      else return . Left . toEnum . fromIntegral $ errcode
+    where
+      ndevs = length devs
+      cndevs = fromIntegral ndevs
+
+#c
+enum CLProgramInfo {
+  cL_PROGRAM_REFERENCE_COUNT=CL_PROGRAM_REFERENCE_COUNT,
+  cL_PROGRAM_CONTEXT=CL_PROGRAM_CONTEXT,
+  cL_PROGRAM_NUM_DEVICES=CL_PROGRAM_NUM_DEVICES,
+  cL_PROGRAM_DEVICES=CL_PROGRAM_DEVICES,
+  cL_PROGRAM_SOURCE=CL_PROGRAM_SOURCE,
+  cL_PROGRAM_BINARY_SIZES=CL_PROGRAM_BINARY_SIZES,
+  cL_PROGRAM_BINARIES=CL_PROGRAM_BINARIES,
+  };
+#endc
+{#enum CLProgramInfo {upcaseFirstLetter} #}
+
+getProgramInfoSize :: CLProgram -> CLProgramInfo_ -> IO (Either CLError CSize)
+getProgramInfoSize prg infoid = alloca $ \(value_size :: Ptr CSize) -> do
+  errcode <- raw_clGetProgramInfo prg infoid 0 nullPtr value_size
+  if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+    then fmap Right $ peek value_size
+    else return . Left . toEnum . fromIntegral $ errcode
+  
+-- | Return the program reference count. The reference count returned should be
+-- considered immediately stale. It is unsuitable for general use in
+-- applications. This feature is provided for identifying memory leaks.
+clGetProgramReferenceCount :: CLProgram -> IO (Either CLError CLuint)
+clGetProgramReferenceCount prg = wrapGetInfo (\(dat :: Ptr CLuint) 
+                                              -> raw_clGetProgramInfo prg infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_PROGRAM_REFERENCE_COUNT
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+-- | Return the context specified when the program object is created.
+clGetProgramContext :: CLProgram -> IO (Either CLError CLContext)
+clGetProgramContext prg = wrapGetInfo (\(dat :: Ptr CLContext) 
+                                       -> raw_clGetProgramInfo prg infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_PROGRAM_CONTEXT
+      size = fromIntegral $ sizeOf (nullPtr::CLContext)
+
+-- | Return the number of devices associated with program.
+clGetProgramNumDevices :: CLProgram -> IO (Either CLError CLuint)
+clGetProgramNumDevices prg = wrapGetInfo (\(dat :: Ptr CLuint) 
+                                       -> raw_clGetProgramInfo prg infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_PROGRAM_NUM_DEVICES
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+-- | Return the list of devices associated with the program object. This can be
+-- the devices associated with context on which the program object has been
+-- created or can be a subset of devices that are specified when a progam object
+-- is created using 'clCreateProgramWithBinary'.
+clGetProgramDevices :: CLProgram -> IO (Either CLError [CLDeviceID])
+clGetProgramDevices prg = do
+  sval <- getProgramInfoSize prg infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right size -> allocaArray (numElems size) $ \(buff :: Ptr CLDeviceID) -> do
+      errcode <- raw_clGetProgramInfo prg infoid size (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekArray (numElems size) buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_DEVICES
+      numElems s = (fromIntegral s) `div` elemSize
+      elemSize = sizeOf (nullPtr::CLDeviceID)
+
+-- | Return the program source code specified by
+-- 'clCreateProgramWithSource'. The source string returned is a concatenation of
+-- all source strings specified to 'clCreateProgramWithSource' with a null
+-- terminator. The concatenation strips any nulls in the original source
+-- strings. The actual number of characters that represents the program source
+-- code including the null terminator is returned in param_value_size_ret.
+clGetProgramSource :: CLProgram -> IO (Either CLError String)
+clGetProgramSource prg = do
+  sval <- getProgramInfoSize prg infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      errcode <- raw_clGetProgramInfo prg infoid n (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekCString buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_SOURCE
+  
+-- | Returns an array that contains the size in bytes of the program binary for
+-- each device associated with program. The size of the array is the number of
+-- devices associated with program. If a binary is not available for a
+-- device(s), a size of zero is returned.
+clGetProgramBinarySizes :: CLProgram -> IO (Either CLError [CSize])
+clGetProgramBinarySizes prg = do
+  sval <- getProgramInfoSize prg infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right size -> allocaArray (numElems size) $ \(buff :: Ptr CSize) -> do
+      errcode <- raw_clGetProgramInfo prg infoid size (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekArray (numElems size) buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_BINARY_SIZES
+      numElems s = (fromIntegral s) `div` elemSize
+      elemSize = sizeOf (0::CSize)
+
+{-| Return the program binaries for all devices associated with program. For
+each device in program, the binary returned can be the binary specified for the
+device when program is created with 'clCreateProgramWithBinary' or it can be the
+executable binary generated by 'clBuildProgram'. If program is created with
+'clCreateProgramWithSource', the binary returned is the binary generated by
+'clBuildProgram'. The bits returned can be an implementation-specific
+intermediate representation (a.k.a. IR) or device specific executable bits or
+both. The decision on which information is returned in the binary is up to the
+OpenCL implementation.
+
+To find out which device the program binary in the array refers to, use the
+'clGetProgramDevices' query to get the list of devices. There is a one-to-one
+correspondence between the array of data returned by 'clGetProgramBinaries' and
+array of devices returned by 'clGetProgramDevices'.  
+-}
+clGetProgramBinaries :: CLProgram -> IO (Either CLError [[Word8]])
+clGetProgramBinaries prg = do
+  sval <- clGetProgramBinarySizes prg
+  case sval of
+    Left err -> return . Left $ err
+    Right sizes -> do
+      let numElems = length sizes
+          size = fromIntegral $ numElems * elemSize
+      buffers <- (mapM (mallocArray.fromIntegral) sizes) :: IO [Ptr Word8]
+      ret <- withArray buffers $ \(parray :: Ptr (Ptr Word8)) -> do
+        errcode <- raw_clGetProgramInfo prg infoid size (castPtr parray) nullPtr
+        if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+          then do
+            vals <- zipWithM peekArray (map fromIntegral sizes) buffers
+            return . Right $ vals
+          else return . Left . toEnum . fromIntegral $ errcode
+      mapM_ free buffers
+      return ret
+    where 
+      infoid = getCLValue CL_PROGRAM_BINARIES
+      elemSize = sizeOf (nullPtr::Ptr Word8)
+
+-- -----------------------------------------------------------------------------
+#c
+enum CLProgramBuildInfo {
+  cL_PROGRAM_BUILD_STATUS=CL_PROGRAM_BUILD_STATUS,
+  cL_PROGRAM_BUILD_OPTIONS=CL_PROGRAM_BUILD_OPTIONS,
+  cL_PROGRAM_BUILD_LOG=CL_PROGRAM_BUILD_LOG,
+  };
+#endc
+{#enum CLProgramBuildInfo {upcaseFirstLetter} #}
+
+getProgramBuildInfoSize :: CLProgram -> CLDeviceID -> CLProgramInfo_ -> IO (Either CLError CSize)
+getProgramBuildInfoSize prg device infoid = alloca $ \(value_size :: Ptr CSize) -> do
+  errcode <- raw_clGetProgramBuildInfo prg device infoid 0 nullPtr value_size
+  if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+    then fmap Right $ peek value_size
+    else return . Left . toEnum . fromIntegral $ errcode
+  
+-- | Returns the build status of program for a specific device as given by
+-- device.
+clGetProgramBuildStatus :: CLProgram -> CLDeviceID -> IO (Either CLError CLBuildStatus)
+clGetProgramBuildStatus prg device = wrapGetInfo (\(dat :: Ptr CLBuildStatus_) 
+                                           -> raw_clGetProgramBuildInfo prg device infoid size (castPtr dat)) getEnumCL
+    where 
+      infoid = getCLValue CL_PROGRAM_BUILD_STATUS
+      size = fromIntegral $ sizeOf (0::CLBuildStatus_)
+
+-- | Return the build options specified by the options argument in
+-- clBuildProgram for device. If build status of program for device is
+-- 'CL_BUILD_NONE', an empty string is returned.
+clGetProgramBuildOptions :: CLProgram -> CLDeviceID -> IO (Either CLError String)
+clGetProgramBuildOptions prg device = do
+  sval <- getProgramBuildInfoSize prg device infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      errcode <- raw_clGetProgramBuildInfo prg device infoid n (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekCString buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_BUILD_OPTIONS
+  
+-- | Return the build log when 'clBuildProgram' was called for device. If build
+-- status of program for device is 'CL_BUILD_NONE', an empty string is returned.
+clGetProgramBuildLog :: CLProgram -> CLDeviceID -> IO (Either CLError String)
+clGetProgramBuildLog prg device = do
+  sval <- getProgramBuildInfoSize prg device infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      errcode <- raw_clGetProgramBuildInfo prg device infoid n (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekCString buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_BUILD_LOG
+  
+-- -----------------------------------------------------------------------------
+{-| Creates a kernal object. A kernel is a function declared in a program. A
+kernel is identified by the __kernel qualifier applied to any function in a
+program. A kernel object encapsulates the specific __kernel function declared in
+a program and the argument values to be used when executing this __kernel
+function.
+
+'clCreateKernel' returns a valid non-zero kernel object if the kernel object is
+created successfully. Otherwise, it returns one of the following error values:
+
+ * 'CL_INVALID_PROGRAM' if program is not a valid program object.
+
+ * 'CL_INVALID_PROGRAM_EXECUTABLE' if there is no successfully built executable
+ for program.
+
+ * 'CL_INVALID_KERNEL_NAME' if kernel_name is not found in program.
+
+ * 'CL_INVALID_KERNEL_DEFINITION' if the function definition for __kernel
+function given by kernel_name such as the number of arguments, the argument
+types are not the same for all devices for which the program executable has been
+built.
+
+ * 'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required
+by the OpenCL implementation on the host.  
+-}
+clCreateKernel :: CLProgram -> String -> IO (Either CLError CLKernel)
+clCreateKernel prg name = withCString name $ \cname -> wrapPError $ \perr -> do
+  raw_clCreateKernel prg cname perr
+
+{-| Creates kernel objects for all kernel functions in a program object. Kernel
+objects are not created for any __kernel functions in program that do not have
+the same function definition across all devices for which a program executable
+has been successfully built.
+
+Kernel objects can only be created once you have a program object with a valid
+program source or binary loaded into the program object and the program
+executable has been successfully built for one or more devices associated with
+program. No changes to the program executable are allowed while there are kernel
+objects associated with a program object. This means that calls to
+'clBuildProgram' return 'CL_INVALID_OPERATION' if there are kernel objects
+attached to a program object. The OpenCL context associated with program will be
+the context associated with kernel. The list of devices associated with program
+are the devices associated with kernel. Devices associated with a program object
+for which a valid program executable has been built can be used to execute
+kernels declared in the program object.
+
+'clCreateKernelsInProgram' will return the kernel objects if the kernel objects
+were successfully allocated, returns 'CL_INVALID_PROGRAM' if program is not a
+valid program object, returns 'CL_INVALID_PROGRAM_EXECUTABLE' if there is no
+successfully built executable for any device in program and returns
+'CL_OUT_OF_HOST_MEMORY' if there is a failure to allocate resources required by
+the OpenCL implementation on the host.
+-}
+clCreateKernelsInProgram :: CLProgram -> IO (Either CLError [CLKernel])
+clCreateKernelsInProgram prg = do
+  nks <- alloca $ \pn -> do
+    errcode <- raw_clCreateKernelsInProgram prg 0 nullPtr pn
+    if errcode == (getCLValue CL_SUCCESS)
+      then peek pn >>= (return . Right)
+      else return $ Left errcode
+  
+  case nks of
+    Left err -> return . Left . getEnumCL $ err
+    Right n -> allocaArray (fromIntegral n) $ \pks -> do
+      errcode <- raw_clCreateKernelsInProgram prg n pks nullPtr
+      if errcode == (getCLValue CL_SUCCESS)
+        then peekArray (fromIntegral n) pks >>= (return . Right)
+        else return . Left .getEnumCL $ errcode
+
+-- | Increments the program program reference count. 'clRetainKernel' returns
+-- 'True' if the function is executed successfully. 'clCreateKernel' or
+-- 'clCreateKernelsInProgram' do an implicit retain.
+clRetainKernel :: CLKernel -> IO Bool
+clRetainKernel krn = wrapCheckSuccess $ raw_clRetainKernel krn
+
+-- | Decrements the kernel reference count. The kernel object is deleted once
+-- the number of instances that are retained to kernel become zero and the
+-- kernel object is no longer needed by any enqueued commands that use
+-- kernel. 'clReleaseKernel' returns 'True' if the function is executed
+-- successfully.
+clReleaseKernel :: CLKernel -> IO Bool
+clReleaseKernel krn = wrapCheckSuccess $ raw_clReleaseKernel krn
+
+{-| Used to set the argument value for a specific argument of a kernel.
+
+A kernel object does not update the reference count for objects such as memory,
+sampler objects specified as argument values by 'clSetKernelArg', Users may not
+rely on a kernel object to retain objects specified as argument values to the
+kernel.
+
+Implementations shall not allow 'CLKernel' objects to hold reference counts to
+'CLKernel' arguments, because no mechanism is provided for the user to tell the
+kernel to release that ownership right. If the kernel holds ownership rights on
+kernel args, that would make it impossible for the user to tell with certainty
+when he may safely release user allocated resources associated with OpenCL
+objects such as the CLMem backing store used with 'CL_MEM_USE_HOST_PTR'.
+
+'clSetKernelArg' returns returns one of the following errors when fails:
+
+ * 'CL_INVALID_KERNEL' if kernel is not a valid kernel object.
+ 
+ * 'CL_INVALID_ARG_INDEX' if arg_index is not a valid argument index.
+
+ * 'CL_INVALID_ARG_VALUE' if arg_value specified is NULL for an argument that is
+not declared with the __local qualifier or vice-versa.
+
+ * 'CL_INVALID_MEM_OBJECT' for an argument declared to be a memory object when
+the specified arg_value is not a valid memory object.
+
+ * 'CL_INVALID_SAMPLER' for an argument declared to be of type sampler_t when
+the specified arg_value is not a valid sampler object.
+
+ * 'CL_INVALID_ARG_SIZE' if arg_size does not match the size of the data type
+for an argument that is not a memory object or if the argument is a memory
+object and arg_size != sizeof(cl_mem) or if arg_size is zero and the argument is
+declared with the __local qualifier or if the argument is a sampler and arg_size
+!= sizeof(cl_sampler).  
+-}
+clSetKernelArg :: Storable a => CLKernel -> CLuint -> a -> IO (Either CLError ())
+clSetKernelArg krn idx val = with val $ \pval -> do
+  errcode <- raw_clSetKernelArg krn idx (fromIntegral . sizeOf $ val) (castPtr pval)
+  if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+    then return $ Right ()
+    else return . Left . toEnum . fromIntegral $ errcode
+
+#c
+enum CLKernelInfo {
+  cL_KERNEL_FUNCTION_NAME=CL_KERNEL_FUNCTION_NAME,
+  cL_KERNEL_NUM_ARGS=CL_KERNEL_NUM_ARGS,
+  cL_KERNEL_REFERENCE_COUNT=CL_KERNEL_REFERENCE_COUNT,
+  cL_KERNEL_CONTEXT=CL_KERNEL_CONTEXT,
+  cL_KERNEL_PROGRAM=CL_KERNEL_PROGRAM
+  };
+#endc
+{#enum CLKernelInfo {upcaseFirstLetter} #}
+
+getKernelInfoSize :: CLKernel -> CLKernelInfo_ -> IO (Either CLError CSize)
+getKernelInfoSize krn infoid = alloca $ \(value_size :: Ptr CSize) -> do
+  errcode <- raw_clGetKernelInfo krn infoid 0 nullPtr value_size
+  if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+    then fmap Right $ peek value_size
+    else return . Left . toEnum . fromIntegral $ errcode
+  
+-- | Return the kernel function name.
+clGetKernelFunctionName :: CLKernel -> IO (Either CLError String)
+clGetKernelFunctionName krn = do
+  sval <- getKernelInfoSize krn infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      errcode <- raw_clGetKernelInfo krn infoid n (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekCString buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_KERNEL_FUNCTION_NAME
+
+-- | Return the number of arguments to kernel.
+clGetKernelNumArgs :: CLKernel -> IO (Either CLError CLuint)
+clGetKernelNumArgs krn = wrapGetInfo (\(dat :: Ptr CLuint) 
+                                      -> raw_clGetKernelInfo krn infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_KERNEL_NUM_ARGS
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+-- | Return the kernel reference count. The reference count returned should be
+-- considered immediately stale. It is unsuitable for general use in
+-- applications. This feature is provided for identifying memory leaks.
+clGetKernelReferenceCount :: CLKernel -> IO (Either CLError CLuint)
+clGetKernelReferenceCount krn = wrapGetInfo (\(dat :: Ptr CLuint) 
+                                             -> raw_clGetKernelInfo krn infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_KERNEL_REFERENCE_COUNT
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+-- | Return the context associated with kernel.
+clGetKernelContext :: CLKernel -> IO (Either CLError CLContext)
+clGetKernelContext krn = wrapGetInfo (\(dat :: Ptr CLContext) 
+                                      -> raw_clGetKernelInfo krn infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_KERNEL_CONTEXT
+      size = fromIntegral $ sizeOf (nullPtr::CLContext)
+
+-- | Return the program object associated with kernel.
+clGetKernelProgram :: CLKernel -> IO (Either CLError CLProgram)
+clGetKernelProgram krn = wrapGetInfo (\(dat :: Ptr CLProgram) 
+                                      -> raw_clGetKernelInfo krn infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_KERNEL_PROGRAM
+      size = fromIntegral $ sizeOf (nullPtr::CLProgram)
+
+
+#c
+enum CLKernelGroupInfo {
+  cL_KERNEL_WORK_GROUP_SIZE=CL_KERNEL_WORK_GROUP_SIZE,
+  cL_KERNEL_COMPILE_WORK_GROUP_SIZE=CL_KERNEL_COMPILE_WORK_GROUP_SIZE,
+  cL_KERNEL_LOCAL_MEM_SIZE=CL_KERNEL_LOCAL_MEM_SIZE,
+  };
+#endc
+{#enum CLKernelGroupInfo {upcaseFirstLetter} #}
+
+-- | This provides a mechanism for the application to query the work-group size
+-- that can be used to execute a kernel on a specific device given by
+-- device. The OpenCL implementation uses the resource requirements of the
+-- kernel (register usage etc.) to determine what this work-group size should
+-- be.
+clGetKernelWorkGroupSize :: CLKernel -> CLDeviceID -> IO (Either CLError CSize)
+clGetKernelWorkGroupSize krn device = wrapGetInfo (\(dat :: Ptr CSize)
+                                                   -> raw_clGetKernelWorkGroupInfo krn device infoid size (castPtr dat)) id
+    where
+      infoid = getCLValue CL_KERNEL_WORK_GROUP_SIZE
+      size = fromIntegral $ sizeOf (0::CSize)
+
+-- | Returns the work-group size specified by the __attribute__((reqd_work_gr
+-- oup_size(X, Y, Z))) qualifier. See Function Qualifiers. If the work-group
+-- size is not specified using the above attribute qualifier (0, 0, 0) is
+-- returned.
+clGetKernelCompileWorkGroupSize :: CLKernel -> CLDeviceID -> IO (Either CLError [CSize])
+clGetKernelCompileWorkGroupSize krn device = do
+  allocaArray num $ \(buff :: Ptr CSize) -> do
+    errcode <- raw_clGetKernelWorkGroupInfo krn device infoid size (castPtr buff) nullPtr
+    if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+      then fmap Right $ peekArray num buff
+      else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_KERNEL_COMPILE_WORK_GROUP_SIZE
+      num = 3
+      elemSize = fromIntegral $ sizeOf (0::CSize)
+      size = fromIntegral $ num * elemSize
+
+
+-- | Returns the amount of local memory in bytes being used by a kernel. This
+-- includes local memory that may be needed by an implementation to execute the
+-- kernel, variables declared inside the kernel with the __local address
+-- qualifier and local memory to be allocated for arguments to the kernel
+-- declared as pointers with the __local address qualifier and whose size is
+-- specified with 'clSetKernelArg'.
+--
+-- If the local memory size, for any pointer argument to the kernel declared
+-- with the __local address qualifier, is not specified, its size is assumed to
+-- be 0.
+clGetKernelLocalMemSize :: CLKernel -> CLDeviceID -> IO (Either CLError CLulong)
+clGetKernelLocalMemSize krn device = wrapGetInfo (\(dat :: Ptr CLulong)
+                                                  -> raw_clGetKernelWorkGroupInfo krn device infoid size (castPtr dat)) id
+    where
+      infoid = getCLValue CL_KERNEL_LOCAL_MEM_SIZE
+      size = fromIntegral $ sizeOf (0::CLulong)
+-- -----------------------------------------------------------------------------
diff --git a/src/System/GPU/OpenCL/Query.chs b/src/System/GPU/OpenCL/Query.chs
new file mode 100644
--- /dev/null
+++ b/src/System/GPU/OpenCL/Query.chs
@@ -0,0 +1,590 @@
+-- -----------------------------------------------------------------------------
+-- This file is part of Haskell-Opencl.
+
+-- Haskell-Opencl is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- Haskell-Opencl is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with Haskell-Opencl.  If not, see <http://www.gnu.org/licenses/>.
+-- -----------------------------------------------------------------------------
+{-# LANGUAGE ForeignFunctionInterface, ScopedTypeVariables #-}
+module System.GPU.OpenCL.Query( 
+  -- * Types
+  CLPlatformInfo(..), CLPlatformID, CLDeviceID, CLDeviceType(..),
+  CLDeviceFPConfig(..), CLDeviceExecCapability(..), CLDeviceLocalMemType(..),
+  CLDeviceMemCacheType(..),
+  -- * Platform Query Functions
+  clGetPlatformIDs, clGetPlatformInfo, 
+  -- * Device Query Functions
+  clGetDeviceIDs, clGetDeviceExecutionCapabilities,
+  clGetDeviceAddressBits, clGetDeviceAvailable, clGetDeviceCompilerAvailable, 
+  clGetDeviceEndianLittle, clGetDeviceErrorCorrectionSupport, 
+  clGetDeviceExtensions, clGetDeviceGlobalMemCacheSize, 
+  clGetDeviceGlobalMemCachelineSize, clGetDeviceGlobalMemSize, 
+  clGetDeviceImageSupport, clGetDeviceImage2DMaxHeight, 
+  clGetDeviceImage2DMaxWidth, clGetDeviceImage3DMaxDepth, 
+  clGetDeviceImage3DMaxHeight, clGetDeviceImage3DMaxWidth, 
+  clGetDeviceLocalMemSize, clGetDeviceMaxClockFrequency, 
+  clGetDeviceMaxComputeUnits, clGetDeviceMaxConstantArgs, 
+  clGetDeviceMaxConstantBufferSize, clGetDeviceMaxMemAllocSize, 
+  clGetDeviceMaxParameterSize, clGetDeviceMaxReadImageArgs, 
+  clGetDeviceMaxSamplers, clGetDeviceMaxWorkGroupSize, 
+  clGetDeviceMaxWorkItemDimensions, clGetDeviceMaxWorkItemSizes, 
+  clGetDeviceMaxWriteImageArgs, clGetDeviceMemBaseAddrAlign, 
+  clGetDeviceMinDataTypeAlignSize, clGetDeviceName, clGetDevicePlatform, 
+  clGetDevicePreferredVectorWidthChar, clGetDevicePreferredVectorWidthShort, 
+  clGetDevicePreferredVectorWidthInt, clGetDevicePreferredVectorWidthLong, 
+  clGetDevicePreferredVectorWidthFloat, clGetDevicePreferredVectorWidthDouble, 
+  clGetDeviceProfile, clGetDeviceProfilingTimerResolution, clGetDeviceVendor, 
+  clGetDeviceVendorID, clGetDeviceVersion, clGetDeviceDriverVersion, 
+  clGetDeviceSingleFPConfig, clGetDeviceDoubleFPConfig, 
+  clGetDeviceHalfFPConfig, clGetDeviceLocalMemType, 
+  clGetDeviceGlobalMemCacheType, clGetDeviceQueueProperties, clGetDeviceType )
+       where
+
+-- -----------------------------------------------------------------------------
+import Foreign( Ptr, nullPtr, castPtr, alloca, allocaArray, peek, peekArray )
+import Foreign.C.String( CString, peekCString )
+import Foreign.C.Types( CSize )
+import Foreign.Storable( sizeOf )
+import System.GPU.OpenCL.Types( 
+  CLbool, CLint, CLuint, CLulong, CLPlatformInfo_, CLDeviceType_, CLError(..),
+  CLDeviceInfo_, CLDeviceFPConfig(..), CLDeviceExecCapability(..),
+  CLDeviceLocalMemType(..), CLDeviceMemCacheType(..), CLPlatformInfo(..),
+  CLPlatformID, CLDeviceID, CLDeviceType(..), CLCommandQueueProperty, 
+  getCLValue, getEnumCL, bitmaskToDeviceTypes, bitmaskToCommandQueueProperties, 
+  whenSuccess, bitmaskToFPConfig, bitmaskToExecCapability )
+
+-- -----------------------------------------------------------------------------
+foreign import ccall "clGetPlatformIDs" raw_clGetPlatformIDs :: 
+  CLuint -> Ptr CLPlatformID -> Ptr CLuint -> IO CLint
+foreign import ccall "clGetPlatformInfo" raw_clGetPlatformInfo :: 
+  CLPlatformID -> CLPlatformInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint 
+foreign import ccall "clGetDeviceIDs" raw_clGetDeviceIDs :: 
+  CLPlatformID -> CLDeviceType_ -> CLuint -> Ptr CLDeviceID -> Ptr CLuint -> IO CLint
+foreign import ccall "clGetDeviceInfo" raw_clGetDeviceInfo :: 
+  CLDeviceID -> CLDeviceInfo_ -> CSize -> Ptr () -> Ptr CSize -> IO CLint
+
+#include <CL/cl.h>
+
+-- -----------------------------------------------------------------------------
+getNumPlatforms :: IO (Either CLError CLuint)
+getNumPlatforms = alloca $ \(num_platforms :: Ptr CLuint) -> do 
+  whenSuccess (raw_clGetPlatformIDs 0 nullPtr num_platforms) 
+    $ peek num_platforms
+
+-- | Obtain the list of platforms available. Returns the list if the function 
+-- is executed successfully. Otherwise it returns the empty list.
+clGetPlatformIDs :: IO (Either CLError [CLPlatformID])
+clGetPlatformIDs = do
+  nplats <- getNumPlatforms
+  case nplats of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(plats :: Ptr CLPlatformID) -> do
+      whenSuccess (raw_clGetPlatformIDs n plats nullPtr) 
+        $ peekArray (fromIntegral n) plats
+  
+getPlatformInfoSize :: CLPlatformID -> CLuint -> IO (Either CLError CSize)
+getPlatformInfoSize platform infoid = alloca $ \(value_size :: Ptr CSize) -> do
+  whenSuccess (raw_clGetPlatformInfo platform infoid 0 nullPtr value_size) 
+    $ peek value_size
+  
+-- | Get specific information about the OpenCL platform. It returns Nothing if
+-- platform is not a valid platform.
+clGetPlatformInfo :: CLPlatformID -> CLPlatformInfo -> IO (Either CLError String)
+clGetPlatformInfo platform infoid = do
+  sval <- getPlatformInfoSize platform infocl
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      whenSuccess (raw_clGetPlatformInfo platform infocl n (castPtr buff) nullPtr)
+        $ peekCString buff
+    where
+      infocl = getCLValue infoid
+
+-- -----------------------------------------------------------------------------
+getNumDevices :: CLPlatformID -> CLDeviceType_ -> IO (Either CLError CLuint)
+getNumDevices platform dtype = alloca $ \(num_devices :: Ptr CLuint) -> do
+  whenSuccess (raw_clGetDeviceIDs platform dtype 0 nullPtr num_devices)
+    $ peek num_devices
+
+-- | Obtain the list of devices available on a platform. Returns the list if 
+-- the function is executed successfully. Otherwise it returns the empty list 
+-- if platform is not a valid platform or no OpenCL devices that matched 
+-- device_type were found.
+clGetDeviceIDs :: CLPlatformID -> CLDeviceType -> IO (Either CLError [CLDeviceID])
+clGetDeviceIDs platform dtype = do
+  ndevs <- getNumDevices platform dval
+  case ndevs of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(devs :: Ptr CLDeviceID) -> do
+      whenSuccess (raw_clGetDeviceIDs platform dval n devs nullPtr)
+        $ peekArray (fromIntegral n) devs
+    where
+      dval = getCLValue dtype
+
+getDeviceInfoSize :: CLDeviceID -> CLDeviceInfo_ -> IO (Either CLError CSize)
+getDeviceInfoSize device infoid = alloca $ \(value_size :: Ptr CSize) -> do
+  whenSuccess (raw_clGetDeviceInfo device infoid 0 nullPtr value_size)
+    $ peek value_size
+  
+getDeviceInfoString :: CLDeviceInfo_ -> CLDeviceID -> IO (Either CLError String)
+getDeviceInfoString infoid device = do
+  sval <- getDeviceInfoSize device infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      whenSuccess (raw_clGetDeviceInfo device infoid n (castPtr buff) nullPtr)
+        $ peekCString buff
+  
+getDeviceInfoUint :: CLDeviceInfo_ -> CLDeviceID -> IO (Either CLError CLuint)
+getDeviceInfoUint infoid device = alloca $ \(dat :: Ptr CLuint) -> do
+  whenSuccess (raw_clGetDeviceInfo device infoid size (castPtr dat) nullPtr)
+    $ peek dat
+    where 
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+getDeviceInfoUlong :: CLDeviceInfo_ -> CLDeviceID -> IO (Either CLError CLulong)
+getDeviceInfoUlong infoid device = alloca $ \(dat :: Ptr CLulong) -> do
+  whenSuccess (raw_clGetDeviceInfo device infoid size (castPtr dat) nullPtr)
+    $ peek dat
+    where 
+      size = fromIntegral $ sizeOf (0::CLulong)
+
+getDeviceInfoSizet :: CLDeviceInfo_ -> CLDeviceID -> IO (Either CLError CSize)
+getDeviceInfoSizet infoid device = alloca $ \(dat :: Ptr CSize) -> do
+  whenSuccess (raw_clGetDeviceInfo device infoid size (castPtr dat) nullPtr)
+    $ peek dat
+    where 
+      size = fromIntegral $ sizeOf (0::CSize)
+  
+getDeviceInfoBool :: CLDeviceInfo_ -> CLDeviceID -> IO (Either CLError Bool)
+getDeviceInfoBool infoid device = alloca $ \(dat :: Ptr CLbool) -> do
+  whenSuccess (raw_clGetDeviceInfo device infoid size (castPtr dat) nullPtr)
+    $ peek dat >>= return . (/=0)
+    where 
+      size = fromIntegral $ sizeOf (0::CLbool)
+  
+getDeviceInfoFP :: CLDeviceInfo_ -> CLDeviceID -> IO (Either CLError [CLDeviceFPConfig])
+getDeviceInfoFP infoid device = do
+  val <- getDeviceInfoUlong infoid device
+  case val of
+    Left err -> return . Left $ err
+    Right flags -> return . Right . bitmaskToFPConfig $ flags
+
+#c
+enum CLDeviceInfo {
+  cL_DEVICE_ADDRESS_BITS=CL_DEVICE_ADDRESS_BITS,
+  cL_DEVICE_AVAILABLE=CL_DEVICE_AVAILABLE,
+  cL_DEVICE_COMPILER_AVAILABLE=CL_DEVICE_COMPILER_AVAILABLE,
+#ifdef CL_DEVICE_DOUBLE_FP_CONFIG  
+  cL_DEVICE_DOUBLE_FP_CONFIG=CL_DEVICE_DOUBLE_FP_CONFIG,
+#else
+  cL_DEVICE_DOUBLE_FP_CONFIG=0x1032,
+#endif
+  cL_DEVICE_ENDIAN_LITTLE=CL_DEVICE_ENDIAN_LITTLE,
+  cL_DEVICE_ERROR_CORRECTION_SUPPORT=CL_DEVICE_ERROR_CORRECTION_SUPPORT,
+  cL_DEVICE_EXECUTION_CAPABILITIES=CL_DEVICE_EXECUTION_CAPABILITIES,
+  cL_DEVICE_EXTENSIONS=CL_DEVICE_EXTENSIONS,
+  cL_DEVICE_GLOBAL_MEM_CACHE_SIZE=CL_DEVICE_GLOBAL_MEM_CACHE_SIZE,
+  cL_DEVICE_GLOBAL_MEM_CACHE_TYPE=CL_DEVICE_GLOBAL_MEM_CACHE_TYPE,
+  cL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE=CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE,
+  cL_DEVICE_GLOBAL_MEM_SIZE=CL_DEVICE_GLOBAL_MEM_SIZE,
+#ifdef CL_DEVICE_HALF_FP_CONFIG
+  cL_DEVICE_HALF_FP_CONFIG=CL_DEVICE_HALF_FP_CONFIG,
+#else
+  cL_DEVICE_HALF_FP_CONFIG=0x1033,
+#endif
+  cL_DEVICE_IMAGE_SUPPORT=CL_DEVICE_IMAGE_SUPPORT,
+  cL_DEVICE_IMAGE2D_MAX_HEIGHT=CL_DEVICE_IMAGE2D_MAX_HEIGHT,
+  cL_DEVICE_IMAGE2D_MAX_WIDTH=CL_DEVICE_IMAGE2D_MAX_WIDTH,
+  cL_DEVICE_IMAGE3D_MAX_DEPTH=CL_DEVICE_IMAGE3D_MAX_DEPTH,
+  cL_DEVICE_IMAGE3D_MAX_HEIGHT=CL_DEVICE_IMAGE3D_MAX_HEIGHT,
+  cL_DEVICE_IMAGE3D_MAX_WIDTH=CL_DEVICE_IMAGE3D_MAX_WIDTH,
+  cL_DEVICE_LOCAL_MEM_SIZE=CL_DEVICE_LOCAL_MEM_SIZE,
+  cL_DEVICE_LOCAL_MEM_TYPE=CL_DEVICE_LOCAL_MEM_TYPE,
+  cL_DEVICE_MAX_CLOCK_FREQUENCY=CL_DEVICE_MAX_CLOCK_FREQUENCY,
+  cL_DEVICE_MAX_COMPUTE_UNITS=CL_DEVICE_MAX_COMPUTE_UNITS,
+  cL_DEVICE_MAX_CONSTANT_ARGS=CL_DEVICE_MAX_CONSTANT_ARGS,
+  cL_DEVICE_MAX_CONSTANT_BUFFER_SIZE=CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE,
+  cL_DEVICE_MAX_MEM_ALLOC_SIZE=CL_DEVICE_MAX_MEM_ALLOC_SIZE,
+  cL_DEVICE_MAX_PARAMETER_SIZE=CL_DEVICE_MAX_PARAMETER_SIZE,
+  cL_DEVICE_MAX_READ_IMAGE_ARGS=CL_DEVICE_MAX_READ_IMAGE_ARGS,
+  cL_DEVICE_MAX_SAMPLERS=CL_DEVICE_MAX_SAMPLERS,
+  cL_DEVICE_MAX_WORK_GROUP_SIZE=CL_DEVICE_MAX_WORK_GROUP_SIZE,
+  cL_DEVICE_MAX_WORK_ITEM_DIMENSIONS=CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS,
+  cL_DEVICE_MAX_WORK_ITEM_SIZES=CL_DEVICE_MAX_WORK_ITEM_SIZES,
+  cL_DEVICE_MAX_WRITE_IMAGE_ARGS=CL_DEVICE_MAX_WRITE_IMAGE_ARGS,
+  cL_DEVICE_MEM_BASE_ADDR_ALIGN=CL_DEVICE_MEM_BASE_ADDR_ALIGN,
+  cL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE=CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE,
+  cL_DEVICE_NAME=CL_DEVICE_NAME,
+  cL_DEVICE_PLATFORM=CL_DEVICE_PLATFORM,
+  cL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR=CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR,
+  cL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT=CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT,
+  cL_DEVICE_PREFERRED_VECTOR_WIDTH_INT=CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT,
+  cL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG=CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG,
+  cL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT=CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT,
+  cL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE=CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE,
+  cL_DEVICE_PROFILE=CL_DEVICE_PROFILE,
+  cL_DEVICE_PROFILING_TIMER_RESOLUTION=CL_DEVICE_PROFILING_TIMER_RESOLUTION,
+  cL_DEVICE_QUEUE_PROPERTIES=CL_DEVICE_QUEUE_PROPERTIES,
+  cL_DEVICE_SINGLE_FP_CONFIG=CL_DEVICE_SINGLE_FP_CONFIG,
+  cL_DEVICE_TYPE=CL_DEVICE_TYPE,
+  cL_DEVICE_VENDOR=CL_DEVICE_VENDOR,
+  cL_DEVICE_VENDOR_ID=CL_DEVICE_VENDOR_ID,
+  cL_DEVICE_VERSION=CL_DEVICE_VERSION,
+  cL_DRIVER_VERSION=CL_DRIVER_VERSION,
+  };
+#endc
+{#enum CLDeviceInfo {upcaseFirstLetter} #}
+
+-- | The default compute device address space size specified as an unsigned 
+-- integer value in bits. Currently supported values are 32 or 64 bits.
+clGetDeviceAddressBits :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceAddressBits = getDeviceInfoUint . getCLValue $ CL_DEVICE_ADDRESS_BITS
+
+-- | Is 'True' if the device is available and 'False' if the device is not 
+-- available.
+clGetDeviceAvailable :: CLDeviceID -> IO (Either CLError Bool)
+clGetDeviceAvailable = getDeviceInfoBool . getCLValue $ CL_DEVICE_AVAILABLE
+
+-- | Is 'False' if the implementation does not have a compiler available to 
+-- compile the program source. Is 'True' if the compiler is available. This can 
+-- be 'False' for the embededed platform profile only.
+clGetDeviceCompilerAvailable :: CLDeviceID -> IO (Either CLError Bool)
+clGetDeviceCompilerAvailable = getDeviceInfoBool . getCLValue $ CL_DEVICE_COMPILER_AVAILABLE
+
+-- | Describes the OPTIONAL double precision floating-point capability of the 
+-- OpenCL device. This is a bit-field that describes one or more of the 
+-- 'CLDeviceFPConfig' values.
+-- The mandated minimum double precision floating-point capability is 
+-- 'CL_FP_FMA' | 'CL_FP_ROUND_TO_NEAREST' | 'CL_FP_ROUND_TO_ZERO' | 
+-- 'CL_FP_ROUND_TO_INF' | 'CL_FP_INF_NAN' | 'CL_FP_DENORM'.
+clGetDeviceDoubleFPConfig :: CLDeviceID -> IO (Either CLError [CLDeviceFPConfig])
+clGetDeviceDoubleFPConfig = getDeviceInfoFP . getCLValue $ CL_DEVICE_DOUBLE_FP_CONFIG
+
+-- | Is 'True' if the OpenCL device is a little endian device and 'False' 
+-- otherwise.
+clGetDeviceEndianLittle :: CLDeviceID -> IO (Either CLError Bool)
+clGetDeviceEndianLittle = getDeviceInfoBool . getCLValue $ CL_DEVICE_ENDIAN_LITTLE
+
+-- | Is 'True' if the device implements error correction for the memories, 
+-- caches, registers etc. in the device. Is 'False' if the device does not 
+-- implement error correction. This can be a requirement for certain clients of 
+-- OpenCL.
+clGetDeviceErrorCorrectionSupport :: CLDeviceID -> IO (Either CLError Bool)
+clGetDeviceErrorCorrectionSupport = getDeviceInfoBool . getCLValue $ CL_DEVICE_ERROR_CORRECTION_SUPPORT
+
+-- | Describes the execution capabilities of the device. This is a list that 
+-- describes one or more of the 'CLDeviceExecCapability' values.
+-- The mandated minimum capability is 'CL_EXEC_KERNEL'.
+clGetDeviceExecutionCapabilities :: CLDeviceID -> IO (Either CLError [CLDeviceExecCapability])
+clGetDeviceExecutionCapabilities device = do
+  val <- getDeviceInfoUlong (getCLValue CL_DEVICE_EXECUTION_CAPABILITIES) device
+  case val of
+    Left err -> return . Left $ err
+    Right flags -> return . Right . bitmaskToExecCapability $ flags
+
+-- | Returns a space separated list of extension names (the extension names 
+-- themselves do not contain any spaces). The list of extension names returned 
+-- currently can include one or more of the following approved extension names:
+--
+-- * cl_khr_fp64
+--
+-- * cl_khr_select_fprounding_mode
+--
+-- * cl_khr_global_int32_base_atomics
+--
+-- * cl_khr_global_int32_extended_atomics
+--
+-- * cl_khr_local_int32_base_atomics
+--
+-- * cl_khr_local_int32_extended_atomics
+--
+-- * cl_khr_int64_base_atomics
+--
+-- * cl_khr_int64_extended_atomics
+--
+-- * cl_khr_3d_image_writes
+--
+-- * cl_khr_byte_addressable_store
+--
+-- * cl_khr_fp16
+clGetDeviceExtensions :: CLDeviceID -> IO (Either CLError String)
+clGetDeviceExtensions = getDeviceInfoString . getCLValue $ CL_DEVICE_EXTENSIONS
+
+-- | Size of global memory cache in bytes.
+clGetDeviceGlobalMemCacheSize :: CLDeviceID -> IO (Either CLError CLulong)
+clGetDeviceGlobalMemCacheSize = getDeviceInfoUlong . getCLValue $ CL_DEVICE_GLOBAL_MEM_CACHE_SIZE
+
+-- | Type of global memory cache supported. Valid values are: 'CL_NONE', 
+-- 'CL_READ_ONLY_CACHE', and 'CL_READ_WRITE_CACHE'.
+clGetDeviceGlobalMemCacheType :: CLDeviceID -> IO (Either CLError CLDeviceMemCacheType)
+clGetDeviceGlobalMemCacheType device = do
+  val <- getDeviceInfoUint (getCLValue CL_DEVICE_GLOBAL_MEM_CACHE_TYPE) device 
+  case val of
+    Left err -> return . Left $ err
+    Right typ -> return . Right . getEnumCL $ typ
+
+-- | Size of global memory cache line in bytes.
+clGetDeviceGlobalMemCachelineSize :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceGlobalMemCachelineSize = getDeviceInfoUint . getCLValue $ CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE
+
+-- | Size of global device memory in bytes.
+clGetDeviceGlobalMemSize :: CLDeviceID -> IO (Either CLError CLulong)
+clGetDeviceGlobalMemSize = getDeviceInfoUlong . getCLValue $ CL_DEVICE_GLOBAL_MEM_SIZE
+
+-- | Describes the OPTIONAL half precision floating-point capability of the 
+-- OpenCL device. This is a bit-field that describes one or more of the 
+-- 'CLDeviceFPConfig' values.
+-- The required minimum half precision floating-point capability as implemented 
+-- by this extension is 'CL_FP_ROUND_TO_ZERO' | 'CL_FP_ROUND_TO_INF' | 
+-- 'CL_FP_INF_NAN'.
+clGetDeviceHalfFPConfig :: CLDeviceID -> IO (Either CLError [CLDeviceFPConfig])
+clGetDeviceHalfFPConfig = getDeviceInfoFP . getCLValue $ CL_DEVICE_HALF_FP_CONFIG
+
+-- | Is 'True' if images are supported by the OpenCL device and 'False' otherwise.
+clGetDeviceImageSupport :: CLDeviceID -> IO (Either CLError Bool)
+clGetDeviceImageSupport = getDeviceInfoBool . getCLValue $ CL_DEVICE_IMAGE_SUPPORT
+
+-- | Max height of 2D image in pixels. The minimum value is 8192 if
+-- 'clGetDeviceImageSupport' is 'True'.
+clGetDeviceImage2DMaxHeight :: CLDeviceID -> IO (Either CLError CSize)
+clGetDeviceImage2DMaxHeight = getDeviceInfoSizet . getCLValue $ CL_DEVICE_IMAGE2D_MAX_HEIGHT
+
+-- | Max width of 2D image in pixels. The minimum value is 8192 if
+-- 'clGetDeviceImageSupport' is 'True'.
+clGetDeviceImage2DMaxWidth :: CLDeviceID -> IO (Either CLError CSize)
+clGetDeviceImage2DMaxWidth = getDeviceInfoSizet . getCLValue $ CL_DEVICE_IMAGE2D_MAX_WIDTH
+
+-- | Max depth of 3D image in pixels. The minimum value is 2048 if 
+-- 'clGetDeviceImageSupport' is 'True'.
+clGetDeviceImage3DMaxDepth :: CLDeviceID -> IO (Either CLError CSize)
+clGetDeviceImage3DMaxDepth = getDeviceInfoSizet . getCLValue $ CL_DEVICE_IMAGE3D_MAX_DEPTH
+
+-- | Max height of 3D image in pixels. The minimum value is 2048 if 
+-- 'clGetDeviceImageSupport' is 'True'.
+clGetDeviceImage3DMaxHeight :: CLDeviceID -> IO (Either CLError CSize)
+clGetDeviceImage3DMaxHeight = getDeviceInfoSizet . getCLValue $ CL_DEVICE_IMAGE3D_MAX_HEIGHT
+
+-- | Max width of 3D image in pixels. The minimum value is 2048 if 
+-- 'clGetDeviceImageSupport' is 'True'.
+clGetDeviceImage3DMaxWidth :: CLDeviceID -> IO (Either CLError CSize)
+clGetDeviceImage3DMaxWidth = getDeviceInfoSizet . getCLValue $ CL_DEVICE_IMAGE3D_MAX_WIDTH
+
+-- | Size of local memory arena in bytes. The minimum value is 16 KB.
+clGetDeviceLocalMemSize :: CLDeviceID -> IO (Either CLError CLulong)
+clGetDeviceLocalMemSize = getDeviceInfoUlong . getCLValue $ CL_DEVICE_LOCAL_MEM_SIZE
+
+-- | Type of local memory supported. This can be set to 'CL_LOCAL' implying 
+-- dedicated local memory storage such as SRAM, or 'CL_GLOBAL'.
+clGetDeviceLocalMemType :: CLDeviceID -> IO (Either CLError CLDeviceLocalMemType)
+clGetDeviceLocalMemType device = do
+  val <- getDeviceInfoUint (getCLValue CL_DEVICE_LOCAL_MEM_TYPE) device 
+  case val of
+    Left err -> return . Left $ err
+    Right typ -> return . Right . getEnumCL $ typ
+
+-- | Maximum configured clock frequency of the device in MHz.
+clGetDeviceMaxClockFrequency :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMaxClockFrequency = getDeviceInfoUint . getCLValue $ CL_DEVICE_MAX_CLOCK_FREQUENCY
+
+-- | The number of parallel compute cores on the OpenCL device. The minimum 
+-- value is 1.
+clGetDeviceMaxComputeUnits :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMaxComputeUnits = getDeviceInfoUint . getCLValue $ CL_DEVICE_MAX_COMPUTE_UNITS
+
+-- | Max number of arguments declared with the __constant qualifier in a kernel. 
+-- The minimum value is 8.
+clGetDeviceMaxConstantArgs :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMaxConstantArgs = getDeviceInfoUint . getCLValue $ CL_DEVICE_MAX_CONSTANT_ARGS
+
+-- | Max size in bytes of a constant buffer allocation. The minimum value is 
+-- 64 KB.
+clGetDeviceMaxConstantBufferSize :: CLDeviceID -> IO (Either CLError CLulong)
+clGetDeviceMaxConstantBufferSize = getDeviceInfoUlong . getCLValue $ CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE
+
+-- | Max size of memory object allocation in bytes. The minimum value is max 
+-- (1/4th of 'clGetDeviceGlobalMemSize', 128*1024*1024)
+clGetDeviceMaxMemAllocSize :: CLDeviceID -> IO (Either CLError CLulong)
+clGetDeviceMaxMemAllocSize = getDeviceInfoUlong . getCLValue $ CL_DEVICE_MAX_MEM_ALLOC_SIZE
+
+-- | Max size in bytes of the arguments that can be passed to a kernel. The 
+-- minimum value is 256.
+clGetDeviceMaxParameterSize :: CLDeviceID -> IO (Either CLError CSize)
+clGetDeviceMaxParameterSize = getDeviceInfoSizet . getCLValue $ CL_DEVICE_MAX_PARAMETER_SIZE
+
+-- | Max number of simultaneous image objects that can be read by a kernel. The 
+-- minimum value is 128 if 'clGetDeviceImageSupport' is 'True'.
+clGetDeviceMaxReadImageArgs :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMaxReadImageArgs = getDeviceInfoUint . getCLValue $ CL_DEVICE_MAX_READ_IMAGE_ARGS
+
+-- | Maximum number of samplers that can be used in a kernel. The minimum value 
+-- is 16 if 'clGetDeviceImageSupport' is 'True'. (Also see sampler type.)
+clGetDeviceMaxSamplers :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMaxSamplers = getDeviceInfoUint . getCLValue $ CL_DEVICE_MAX_SAMPLERS
+
+-- | Maximum number of work-items in a work-group executing a kernel using the 
+-- data parallel execution model. (Refer to 'clEnqueueNDRangeKernel'). The 
+-- minimum value is 1.
+clGetDeviceMaxWorkGroupSize :: CLDeviceID -> IO (Either CLError CSize)
+clGetDeviceMaxWorkGroupSize = getDeviceInfoSizet . getCLValue $ CL_DEVICE_MAX_WORK_GROUP_SIZE
+
+-- | Maximum dimensions that specify the global and local work-item IDs used by 
+-- the data parallel execution model. (Refer to 'clEnqueueNDRangeKernel'). 
+-- The minimum value is 3.
+clGetDeviceMaxWorkItemDimensions :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMaxWorkItemDimensions = getDeviceInfoUint . getCLValue $ CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS
+
+-- | Maximum number of work-items that can be specified in each dimension of the 
+-- work-group to 'clEnqueueNDRangeKernel'.
+-- Returns n entries, where n is the value returned by the query for 
+-- clDeviceMaxWorkItemDimensions. The minimum value is (1, 1, 1).
+clGetDeviceMaxWorkItemSizes :: CLDeviceID -> IO (Either CLError [CSize])
+clGetDeviceMaxWorkItemSizes device = do
+  val <- clGetDeviceMaxWorkItemDimensions device
+  case val of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: Ptr CSize) -> do
+      whenSuccess (raw_clGetDeviceInfo device infoid (size n) (castPtr buff) nullPtr)
+        $ peekArray (fromIntegral n) buff
+    where
+      infoid = getCLValue CL_DEVICE_MAX_WORK_ITEM_SIZES
+      size n = fromIntegral $ (fromIntegral n) * (sizeOf (0::CSize))
+
+-- | Max number of simultaneous image objects that can be written to by a 
+-- kernel. The minimum value is 8 if 'clGetDeviceImageSupport' is 'True'.
+clGetDeviceMaxWriteImageArgs :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMaxWriteImageArgs = getDeviceInfoUint . getCLValue $ CL_DEVICE_MAX_WRITE_IMAGE_ARGS
+
+-- | Describes the alignment in bits of the base address of any allocated 
+-- memory object.
+clGetDeviceMemBaseAddrAlign :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMemBaseAddrAlign = getDeviceInfoUint . getCLValue $ CL_DEVICE_MEM_BASE_ADDR_ALIGN
+
+-- | The smallest alignment in bytes which can be used for any data type.
+clGetDeviceMinDataTypeAlignSize :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceMinDataTypeAlignSize = getDeviceInfoUint . getCLValue $ CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE
+
+-- | Device name string.
+clGetDeviceName :: CLDeviceID -> IO (Either CLError String)
+clGetDeviceName = getDeviceInfoString . getCLValue $ CL_DEVICE_NAME
+
+-- | The platform associated with this device.
+clGetDevicePlatform :: CLDeviceID -> IO (Either CLError CLPlatformID)
+clGetDevicePlatform device = alloca $ \(dat :: Ptr CLPlatformID) -> do
+  whenSuccess (raw_clGetDeviceInfo device infoid size (castPtr dat) nullPtr)
+    $ peek dat
+    where 
+      infoid = getCLValue CL_DEVICE_PLATFORM
+      size = fromIntegral $ sizeOf (nullPtr :: CLPlatformID)
+
+-- | Preferred native vector width size for built-in char types that can be put 
+-- into vectors. The vector width is defined as the number of scalar elements 
+-- that can be stored in the vector.
+clGetDevicePreferredVectorWidthChar :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDevicePreferredVectorWidthChar = getDeviceInfoUint . getCLValue $ CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR
+
+-- | Preferred native vector width size for built-in short types that can be put 
+-- into vectors. The vector width is defined as the number of scalar elements 
+-- that can be stored in the vector.
+clGetDevicePreferredVectorWidthShort :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDevicePreferredVectorWidthShort = getDeviceInfoUint . getCLValue $ CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT
+
+-- | Preferred native vector width size for built-in int types that can be put 
+-- into vectors. The vector width is defined as the number of scalar elements 
+-- that can be stored in the vector.
+clGetDevicePreferredVectorWidthInt :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDevicePreferredVectorWidthInt = getDeviceInfoUint . getCLValue $ CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT
+
+-- | Preferred native vector width size for built-in long types that can be put 
+-- into vectors. The vector width is defined as the number of scalar elements 
+-- that can be stored in the vector.
+clGetDevicePreferredVectorWidthLong :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDevicePreferredVectorWidthLong = getDeviceInfoUint . getCLValue $ CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG
+
+-- | Preferred native vector width size for built-in float types that can be put 
+-- into vectors. The vector width is defined as the number of scalar elements 
+-- that can be stored in the vector.
+clGetDevicePreferredVectorWidthFloat :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDevicePreferredVectorWidthFloat = getDeviceInfoUint . getCLValue $ CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT
+
+-- | Preferred native vector width size for built-in double types that can be put 
+-- into vectors. The vector width is defined as the number of scalar elements 
+-- that can be stored in the vector.
+-- | If the cl_khr_fp64 extension is not supported, 
+-- 'clGetDevicePreferredVectorWidthDouble' must return 0.
+clGetDevicePreferredVectorWidthDouble :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDevicePreferredVectorWidthDouble = getDeviceInfoUint . getCLValue $ CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE
+
+-- | OpenCL profile string. Returns the profile name supported by the device 
+-- (see note). The profile name returned can be one of the following strings:
+-- 
+-- * FULL_PROFILE - if the device supports the OpenCL specification 
+-- (functionality defined as part of the core specification and does not require 
+-- any extensions to be supported).
+-- 
+-- * EMBEDDED_PROFILE - if the device supports the OpenCL embedded profile.
+clGetDeviceProfile :: CLDeviceID -> IO (Either CLError String)
+clGetDeviceProfile = getDeviceInfoString . getCLValue $ CL_DEVICE_PROFILE
+
+-- | Describes the resolution of device timer. This is measured in nanoseconds.
+clGetDeviceProfilingTimerResolution :: CLDeviceID -> IO (Either CLError CSize)
+clGetDeviceProfilingTimerResolution = getDeviceInfoSizet . getCLValue $ CL_DEVICE_PROFILING_TIMER_RESOLUTION
+
+-- | Describes the command-queue properties supported by the device. This is a 
+-- list that describes one or more of the CLCommandQueueProperty values.
+-- These properties are described in the table for 'clCreateCommandQueue'. 
+-- The mandated minimum capability is 'CL_QUEUE_PROFILING_ENABLE'.
+clGetDeviceQueueProperties :: CLDeviceID -> IO (Either CLError [CLCommandQueueProperty])
+clGetDeviceQueueProperties device = do
+  val <- getDeviceInfoUlong (getCLValue CL_DEVICE_QUEUE_PROPERTIES) device
+  case val of
+    Left err -> return . Left $ err
+    Right flags -> return . Right . bitmaskToCommandQueueProperties $ flags
+    
+-- | Describes single precision floating-point capability of the device. This is 
+-- a bit-field that describes one or more of the 'CLDeviceFPConfig' values.
+-- The mandated minimum floating-point capability is 'CL_FP_ROUND_TO_NEAREST' | 
+-- 'CL_FP_INF_NAN'.
+clGetDeviceSingleFPConfig :: CLDeviceID -> IO (Either CLError [CLDeviceFPConfig])
+clGetDeviceSingleFPConfig = getDeviceInfoFP . getCLValue $ CL_DEVICE_SINGLE_FP_CONFIG
+
+-- | The OpenCL device type. Currently supported values are one of or a 
+-- combination of: 'CL_DEVICE_TYPE_CPU', 'CL_DEVICE_TYPE_GPU', 
+-- 'CL_DEVICE_TYPE_ACCELERATOR', or 'CL_DEVICE_TYPE_DEFAULT'.
+clGetDeviceType :: CLDeviceID -> IO (Either CLError [CLDeviceType])
+clGetDeviceType device = do
+  val <- getDeviceInfoUlong (getCLValue CL_DEVICE_TYPE) device
+  case val of
+    Left err -> return . Left $ err
+    Right flags -> return . Right . bitmaskToDeviceTypes $ flags
+
+-- | Vendor name string.
+clGetDeviceVendor :: CLDeviceID -> IO (Either CLError String)
+clGetDeviceVendor = getDeviceInfoString . getCLValue $ CL_DEVICE_VENDOR
+
+-- | A unique device vendor identifier. An example of a unique device identifier 
+-- could be the PCIe ID.
+clGetDeviceVendorID :: CLDeviceID -> IO (Either CLError CLuint)
+clGetDeviceVendorID = getDeviceInfoUint . getCLValue $ CL_DEVICE_VENDOR_ID
+
+-- | OpenCL version string. Returns the OpenCL version supported by the device. 
+-- This version string has the following format:
+-- /OpenCL major_version.minor_version vendor-specific information/
+-- The major_version.minor_version value returned will be 1.0.
+clGetDeviceVersion :: CLDeviceID -> IO (Either CLError String)
+clGetDeviceVersion = getDeviceInfoString . getCLValue $ CL_DEVICE_VERSION
+
+-- | OpenCL software driver version string in the form major_number.minor_number.
+clGetDeviceDriverVersion :: CLDeviceID -> IO (Either CLError String)
+clGetDeviceDriverVersion = getDeviceInfoString . getCLValue $ CL_DRIVER_VERSION
+
+-- -----------------------------------------------------------------------------
diff --git a/src/System/GPU/OpenCL/Types.chs b/src/System/GPU/OpenCL/Types.chs
new file mode 100644
--- /dev/null
+++ b/src/System/GPU/OpenCL/Types.chs
@@ -0,0 +1,692 @@
+-- -----------------------------------------------------------------------------
+-- This file is part of Haskell-Opencl.
+
+-- Haskell-Opencl is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- Haskell-Opencl is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with Haskell-Opencl.  If not, see <http://www.gnu.org/licenses/>.
+-- -----------------------------------------------------------------------------
+module System.GPU.OpenCL.Types( 
+  -- * Symple CL Types
+  CLbool, CLint, CLuint, CLulong, CLProgram, CLEvent, CLMem, CLPlatformID, 
+  CLDeviceID, CLContext, CLCommandQueue, CLPlatformInfo_, CLDeviceType_, 
+  CLDeviceInfo_, CLContextInfo_, CLContextProperty_, CLCommandQueueInfo_, 
+  CLEventInfo_, CLProfilingInfo_, CLCommandType_, CLCommandQueueProperty_, 
+  CLMemFlags_, CLImageFormat_p, CLMemObjectType_, CLMemInfo_, CLImageInfo_,
+  CLProgramInfo_, CLBuildStatus_,CLKernel, CLProgramBuildInfo_, CLKernelInfo_,
+  CLKernelWorkGroupInfo_, CLDeviceLocalMemType_, CLDeviceMemCacheType_,
+  CLSampler, CLFilterMode_, CLSamplerInfo_, CLAddressingMode_,
+  -- * High Level Types
+  CLError(..), CLDeviceFPConfig(..), CLDeviceMemCacheType(..), 
+  CLDeviceExecCapability(..), CLDeviceLocalMemType(..), CLDeviceType(..), 
+  CLCommandQueueProperty(..), CLCommandType(..),  CLCommandExecutionStatus(..), 
+  CLProfilingInfo(..), CLPlatformInfo(..), CLMemFlag(..), CLMemObjectType(..),
+  CLBuildStatus(..), CLAddressingMode(..), CLFilterMode(..),
+  -- * Functions
+  wrapPError, wrapCheckSuccess, wrapGetInfo, whenSuccess, getCLValue, 
+  getEnumCL, bitmaskToFlags, getCommandExecutionStatus, bitmaskToDeviceTypes, 
+  bitmaskFromFlags, bitmaskToCommandQueueProperties, bitmaskToFPConfig, 
+  bitmaskToExecCapability, bitmaskToMemFlags )
+       where
+
+-- -----------------------------------------------------------------------------
+import Foreign
+import Foreign.C.Types
+import Data.List( foldl' )
+
+#include <CL/cl.h>
+
+-- -----------------------------------------------------------------------------
+
+type CLPlatformID = {#type cl_platform_id#}
+type CLDeviceID = {#type cl_device_id#}
+type CLContext = {#type cl_context#}
+type CLCommandQueue = {#type cl_command_queue#}
+type CLMem = {#type cl_mem#}
+type CLEvent = {#type cl_event#}
+type CLProgram = {#type cl_program#}
+type CLKernel = {#type cl_kernel#}
+type CLSampler = {#type cl_sampler#}
+
+type CLint = {#type cl_int#}
+type CLuint = {#type cl_uint#}
+type CLulong = {#type cl_ulong#}
+type CLbool = {#type cl_bool#}
+
+type CLPlatformInfo_ = {#type cl_platform_info#}
+type CLDeviceType_ = {#type cl_device_type#}
+type CLDeviceInfo_ = {#type cl_device_info#}
+type CLDeviceFPConfig_ = {#type cl_device_fp_config#}
+type CLDeviceMemCacheType_ = {#type cl_device_mem_cache_type#}
+type CLDeviceLocalMemType_ = {#type cl_device_local_mem_type#}
+type CLDeviceExecCapability_ = {#type cl_device_exec_capabilities#}
+type CLContextInfo_ = {#type cl_context_info#}
+type CLContextProperty_ = {#type cl_context_properties#}
+type CLCommandQueueInfo_ = {#type cl_command_queue_info#}
+type CLCommandQueueProperty_ = {#type cl_command_queue_properties#}
+type CLEventInfo_ = {#type cl_event_info#}
+type CLProfilingInfo_ = {#type cl_profiling_info#}
+type CLCommandType_ = {#type cl_command_type#}
+type CLMemFlags_ = {#type cl_mem_flags#}
+type CLMemObjectType_ = {#type cl_mem_object_type#}
+type CLMemInfo_ = {#type cl_mem_info#}
+type CLImageInfo_ = {#type cl_image_info#}
+type CLProgramInfo_ = {#type cl_program_info#}
+type CLProgramBuildInfo_ = {#type cl_program_build_info#}
+type CLBuildStatus_ = {#type cl_build_status#}
+type CLKernelInfo_ = {#type cl_kernel_info#}
+type CLKernelWorkGroupInfo_ = {#type cl_kernel_work_group_info#}
+type CLFilterMode_ = {#type cl_filter_mode#}
+type CLSamplerInfo_ = {#type cl_sampler_info#}
+type CLAddressingMode_ = {#type cl_addressing_mode#}
+
+{#pointer *cl_image_format as CLImageFormat_p#}
+
+--type CLImageChannelOrder_ = {#type cl_channel_order#}
+--type CLImageChannelDataType_ = {#type cl_channel_type#}
+
+-- -----------------------------------------------------------------------------
+#c
+enum CLError {
+  cL_BUILD_PROGRAM_FAILURE=CL_BUILD_PROGRAM_FAILURE,
+  cL_COMPILER_NOT_AVAILABLE=CL_COMPILER_NOT_AVAILABLE,
+  cL_DEVICE_NOT_AVAILABLE=CL_DEVICE_NOT_AVAILABLE,
+  cL_DEVICE_NOT_FOUND=CL_DEVICE_NOT_FOUND,
+  cL_IMAGE_FORMAT_MISMATCH=CL_IMAGE_FORMAT_MISMATCH,
+  cL_IMAGE_FORMAT_NOT_SUPPORTED=CL_IMAGE_FORMAT_NOT_SUPPORTED,
+  cL_INVALID_ARG_INDEX=CL_INVALID_ARG_INDEX,
+  cL_INVALID_ARG_SIZE=CL_INVALID_ARG_SIZE,
+  cL_INVALID_ARG_VALUE=CL_INVALID_ARG_VALUE,
+  cL_INVALID_BINARY=CL_INVALID_BINARY,
+  cL_INVALID_BUFFER_SIZE=CL_INVALID_BUFFER_SIZE,
+  cL_INVALID_BUILD_OPTIONS=CL_INVALID_BUILD_OPTIONS,
+  cL_INVALID_COMMAND_QUEUE=CL_INVALID_COMMAND_QUEUE,
+  cL_INVALID_CONTEXT=CL_INVALID_CONTEXT,
+  cL_INVALID_DEVICE=CL_INVALID_DEVICE,
+  cL_INVALID_DEVICE_TYPE=CL_INVALID_DEVICE_TYPE,
+  cL_INVALID_EVENT=CL_INVALID_EVENT,
+  cL_INVALID_EVENT_WAIT_LIST=CL_INVALID_EVENT_WAIT_LIST,
+  cL_INVALID_GL_OBJECT=CL_INVALID_GL_OBJECT,
+  cL_INVALID_GLOBAL_OFFSET=CL_INVALID_GLOBAL_OFFSET,
+  cL_INVALID_HOST_PTR=CL_INVALID_HOST_PTR,
+  cL_INVALID_IMAGE_FORMAT_DESCRIPTOR=CL_INVALID_IMAGE_FORMAT_DESCRIPTOR,
+  cL_INVALID_IMAGE_SIZE=CL_INVALID_IMAGE_SIZE,
+  cL_INVALID_KERNEL_NAME=CL_INVALID_KERNEL_NAME,
+  cL_INVALID_KERNEL=CL_INVALID_KERNEL,
+  cL_INVALID_KERNEL_ARGS=CL_INVALID_KERNEL_ARGS,
+  cL_INVALID_KERNEL_DEFINITION=CL_INVALID_KERNEL_DEFINITION,
+  cL_INVALID_MEM_OBJECT=CL_INVALID_MEM_OBJECT,
+  cL_INVALID_OPERATION=CL_INVALID_OPERATION,
+  cL_INVALID_PLATFORM=CL_INVALID_PLATFORM,
+  cL_INVALID_PROGRAM=CL_INVALID_PROGRAM,
+  cL_INVALID_PROGRAM_EXECUTABLE=CL_INVALID_PROGRAM_EXECUTABLE,
+  cL_INVALID_QUEUE_PROPERTIES=CL_INVALID_QUEUE_PROPERTIES,
+  cL_INVALID_SAMPLER=CL_INVALID_SAMPLER,
+  cL_INVALID_VALUE=CL_INVALID_VALUE,
+  cL_INVALID_WORK_DIMENSION=CL_INVALID_WORK_DIMENSION,
+  cL_INVALID_WORK_GROUP_SIZE=CL_INVALID_WORK_GROUP_SIZE,
+  cL_INVALID_WORK_ITEM_SIZE=CL_INVALID_WORK_ITEM_SIZE,
+  cL_MAP_FAILURE=CL_MAP_FAILURE,
+  cL_MEM_OBJECT_ALLOCATION_FAILURE=CL_MEM_OBJECT_ALLOCATION_FAILURE,
+  cL_MEM_COPY_OVERLAP=CL_MEM_COPY_OVERLAP,
+  cL_OUT_OF_HOST_MEMORY=CL_OUT_OF_HOST_MEMORY,
+  cL_OUT_OF_RESOURCES=CL_OUT_OF_RESOURCES,
+  cL_PROFILING_INFO_NOT_AVAILABLE=CL_PROFILING_INFO_NOT_AVAILABLE,
+  cL_SUCCESS=CL_SUCCESS
+  };
+#endc
+
+{-| 
+ * 'CL_BUILD_PROGRAM_FAILURE', Returned if there is a failure to build the
+program executable.
+
+ * 'CL_COMPILER_NOT_AVAILABLE', Returned if the parameter program is created with
+'clCreateProgramWithSource' and a compiler is not available. For example
+'clDeviceCompilerAvalaible' is set to 'False'.
+
+ * 'CL_DEVICE_NOT_AVAILABLE', Returned if the specified device is not currently
+available.
+
+ * 'CL_DEVICE_NOT_FOUND', Returned if no OpenCL devices that match the specified
+devices were found.
+
+ * 'CL_IMAGE_FORMAT_MISMATCH', Returned if the specified source and destination
+images are not valid image objects.
+
+ * 'CL_IMAGE_FORMAT_NOT_SUPPORTED', Returned if the specified image format is not
+supported.
+
+ * 'CL_INVALID_ARG_INDEX', Returned if an invalid argument index is specified.
+
+ * 'CL_INVALID_ARG_SIZE', Returned if argument size specified (arg_size) does not
+match the size of the data type for an argument that is not a memory object, or
+if the argument is a memory object and arg_size != sizeof(cl_mem) or if arg_size
+is zero and the argument is declared with the __local qualifier or if the
+argument is a sampler and arg_size != sizeof(cl_sampler).
+
+ * 'CL_INVALID_ARG_VALUE', Returned if the argument value specified is NULL for
+an argument that is not declared with the __local qualifier or vice-versa.
+
+ * 'CL_INVALID_BINARY', Returned if the program binary is not a valid binary for
+the specified device.
+
+ * 'CL_INVALID_BUFFER_SIZE', Returned if the value of the parameter size is 0 or
+is greater than 'clDeviceMaxMemAllocSize' for all devices specified in the
+parameter context.
+
+ * 'CL_INVALID_BUILD_OPTIONS', Returned if the specified build options are
+invalid.
+
+ * 'CL_INVALID_COMMAND_QUEUE', Returned if the specified command-queue is not a
+valid command-queue.
+
+ * 'CL_INVALID_CONTEXT', Returned if the specified context is not a valid OpenCL
+context, or the context associated with certain parameters are not the same.
+
+ * 'CL_INVALID_DEVICE', Returned if the device or devices specified are not
+valid.
+
+ * 'CL_INVALID_DEVICE_TYPE', Returned if device type specified is not valid.
+
+ * 'CL_INVALID_EVENT', Returned if the event objects specified are not valid.
+
+ * 'CL_INVALID_EVENT_WAIT_LIST', Returned if event_wait_list is NULL and
+num_events_in_wait_list > 0, or event_wait_list_list is not NULL and
+num_events_in_wait_list is 0, or specified event objects are not valid events.
+
+ * 'CL_INVALID_GL_OBJECT', Returned if obj is not a vaild GL object or is a GL
+object but does not have an existing data store.
+
+ * 'CL_INVALID_GLOBAL_OFFSET', Returned if global_work_offset is not NULL.
+
+ * 'CL_INVALID_HOST_PTR', Returned if host_ptr is NULL and 'CL_MEM_USE_HOST_PTR'
+or 'CL_MEM_COPY_HOST_PTR' are set in flags or if host_ptr is not NULL but
+'CL_MEM_COPY_HOST_PTR' or 'CL_MEM_USE_HOST_PTR' are not set in flags.
+
+ * 'CL_INVALID_IMAGE_FORMAT_DESCRIPTOR', Returned if the image format specified
+is not valid or is NULL or does not map to a supported OpenCL image format.
+
+ * 'CL_INVALID_IMAGE_SIZE', Returned if the specified image width or height are
+invalid or if the image row pitch and image slice pitch do not follow the rules.
+
+ * 'CL_INVALID_KERNEL_NAME', Returned if the specified kernel name is not found
+in program.
+
+ * 'CL_INVALID_KERNEL', Returned if the specified kernel is not a valid kernel
+object.
+
+ * 'CL_INVALID_KERNEL_ARGS', Returned if the kernel argument values have not been
+specified.
+
+ * 'CL_INVALID_KERNEL_DEFINITION', Returned if the function definition for
+__kernel function given by kernel_name such as the number of arguments, the
+argument types are not the same for all devices for which the program executable
+has been built.
+
+ * 'CL_INVALID_MEM_OBJECT', Returned if a parameter is not a valid memory, image,
+or buffer object.
+
+ * 'CL_INVALID_OPERATION', Returned if there are no devices in context that
+support images. Returned if the build of a program executable for any of the
+devices specified by a previous call to 'clBuildProgram' for program has not
+completed, or if there are kernel objects attached to program. Returned by
+'clEnqueueNativeKernel' if the specified device cannot execute the native
+kernel.
+
+ * 'CL_INVALID_PLATFORM', Returned if the specified platform is not a valid
+platform, or no platform could be selected, or if platform value specified in
+properties is not a valid platform.
+
+ * 'CL_INVALID_PROGRAM', Returned if the specified program is not a valid program
+object.
+
+ * 'CL_INVALID_PROGRAM_EXECUTABLE', Returned if there is no successfully built
+executable for program, or if there is no device in program. Returned if there
+is no successfully built program executable available for device associated with
+command_queue.
+
+ * 'CL_INVALID_QUEUE_PROPERTIES', Returned if specified properties are valid but
+are not supported by the device.
+
+ * 'CL_INVALID_SAMPLER', Returned if the specified sampler is not a valid sampler
+object, or for an argument declared to be of type sampler_t when the specified
+arg_value is not a valid sampler object.
+
+ * 'CL_INVALID_VALUE', Returned if a parameter is not an expected value.
+
+ * 'CL_INVALID_WORK_DIMENSION', Returned if work_dim is not a valid value.
+
+ * 'CL_INVALID_WORK_GROUP_SIZE', Returned if local_work_size is specified and
+number of workitems specified by global_work_size is not evenly divisible by
+size of work-group given by local_work_size or does not match the work-group
+size specified for kernel using the __attribute__((reqd_work_group_size(X, Y,
+Z))) qualifier in program source.
+
+ * 'CL_INVALID_WORK_ITEM_SIZE', Returned if the number of work-items specified in
+any of local_work_size... [0]... local_work_size[work_dim - 1] is greater than
+the corresponding values specified by 'clDeviceMaxWorkItemSizes'.
+
+ * 'CL_MAP_FAILURE', Returned by if there is a failure to map the requested
+region into the host address space. This error cannot occur for buffer objects
+created with 'CLMEM_USE_HOST_PTR' or 'CLMEM_ALLOC_HOST_PTR'.
+
+ * 'CL_MEM_OBJECT_ALLOCATION_FAILURE', Returned if there is a failure to allocate
+memory for data store associated with image or buffer objects specified as
+arguments to kernel.
+
+ * 'CL_MEM_COPY_OVERLAP', Returned if the source and destination images are the
+same image (or the source and destination buffers are the same buffer), and the
+source and destination regions overlap.
+
+ * 'CL_OUT_OF_HOST_MEMORY', Returned in the event of a failure to allocate
+resources required by the OpenCL implementation on the host.
+
+ * 'CL_OUT_OF_RESOURCES', Returned in the event of a failure to queue the
+execution instance of kernel on the command-queue because of insufficient
+resources needed to execute the kernel.
+
+ * 'CL_PROFILING_INFO_NOT_AVAILABLE', Returned if the 'CL_QUEUE_PROFILING_ENABLE'
+flag is not set for the command-queue and the profiling information is currently
+not available (because the command identified by event has not completed).
+
+ * 'CL_SUCCESS', Indicates that the function executed successfully.
+-}
+{#enum CLError {upcaseFirstLetter} deriving( Show, Eq ) #}
+
+wrapPError :: (Ptr CLint -> IO a) -> IO (Either CLError a)
+wrapPError f = alloca $ \perr -> do
+  v <- f perr
+  errcode <- peek perr >>= return . toEnum . fromIntegral
+  if errcode == CL_SUCCESS
+    then return $ Right v
+    else return $ Left errcode
+  
+wrapCheckSuccess :: IO CLint -> IO Bool
+wrapCheckSuccess f = f >>= return . (==CL_SUCCESS) . toEnum . fromIntegral
+
+wrapGetInfo :: Storable a => (Ptr a -> Ptr CSize -> IO CLint) -> (a -> b) 
+               -> IO (Either CLError b)
+wrapGetInfo fget fconvert= alloca $ \dat -> do
+  errcode <- fget dat nullPtr
+  if errcode == (fromIntegral . fromEnum $ CL_SUCCESS )
+    then fmap (Right . fconvert) $ peek dat
+    else return . Left . toEnum . fromIntegral $ errcode
+
+whenSuccess :: IO CLint -> IO a -> IO (Either CLError a)
+whenSuccess fcheck fval = do
+  errcode <- fcheck
+  if errcode == getCLValue CL_SUCCESS
+    then fval >>= return . Right
+    else return . Left . getEnumCL $ errcode
+         
+-- -----------------------------------------------------------------------------
+#c
+enum CLPlatformInfo {
+  cL_PLATFORM_PROFILE=CL_PLATFORM_PROFILE,
+  cL_PLATFORM_VERSION=CL_PLATFORM_VERSION,
+  cL_PLATFORM_NAME=CL_PLATFORM_NAME,
+  cL_PLATFORM_VENDOR=CL_PLATFORM_VENDOR,
+  cL_PLATFORM_EXTENSIONS=CL_PLATFORM_EXTENSIONS
+  };
+#endc
+
+{-|
+ * 'CL_PLATFORM_PROFILE', OpenCL profile string. Returns the profile name 
+supported by the implementation. The profile name returned can be one of the 
+following strings:
+
+ [@FULL_PROFILE@] If the implementation supports the OpenCL specification
+(functionality defined as part of the core specification and does not require
+any extensions to be supported).
+
+ [@EMBEDDED_PROFILE@] If the implementation supports the OpenCL embedded 
+profile. The embedded profile is  defined to be a subset for each version of 
+OpenCL.
+
+ * 'CL_PLATFORM_VERSION', OpenCL version string. Returns the OpenCL version 
+supported by the implementation. This version string has the following format: 
+/OpenCL major_version.minor_version platform-specific information/ The 
+/major_version.minor_version/ value returned will be 1.0.
+                    
+ * 'CL_PLATFORM_NAME', Platform name string.
+ 
+ * 'CL_PLATFORM_VENDOR', Platform vendor string.
+                   
+ * 'CL_PLATFORM_EXTENSIONS', Returns a space-separated list of extension names 
+(the extension names themselves do not contain any spaces) supported by the 
+platform. Extensions defined here must be supported by all devices associated 
+with this platform.
+-}
+{#enum CLPlatformInfo {upcaseFirstLetter} deriving( Show ) #}
+
+-- -----------------------------------------------------------------------------
+#c
+enum CLDeviceType {
+  cL_DEVICE_TYPE_CPU=CL_DEVICE_TYPE_CPU,
+  cL_DEVICE_TYPE_GPU=CL_DEVICE_TYPE_GPU,
+  cL_DEVICE_TYPE_ACCELERATOR=CL_DEVICE_TYPE_ACCELERATOR,
+  cL_DEVICE_TYPE_DEFAULT=CL_DEVICE_TYPE_DEFAULT,
+  cL_DEVICE_TYPE_ALL=CL_DEVICE_TYPE_ALL
+  };
+#endc
+
+{-|
+ * 'CL_DEVICE_TYPE_CPU', An OpenCL device that is the host processor. The host 
+processor runs the OpenCL implementations and is a single or multi-core CPU.
+                  
+ * 'CL_DEVICE_TYPE_GPU', An OpenCL device that is a GPU. By this we mean that the 
+device can also be used to accelerate a 3D API such as OpenGL or DirectX.
+                  
+ * 'CL_DEVICE_TYPE_ACCELERATOR', Dedicated OpenCL accelerators (for example the 
+IBM CELL Blade). These devices communicate with the host processor using a 
+peripheral interconnect such as PCIe.
+                
+ * 'CL_DEVICE_TYPE_DEFAULT', The default OpenCL device in the system.
+           
+ * 'CL_DEVICE_TYPE_ALL', All OpenCL devices available in the system.
+-}
+{#enum CLDeviceType {upcaseFirstLetter} deriving( Show ) #}
+
+#c
+enum CLCommandQueueProperty { 
+  cL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE=CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE,
+  cL_QUEUE_PROFILING_ENABLE=CL_QUEUE_PROFILING_ENABLE
+  };
+#endc
+
+{-|
+ * 'CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE', Determines whether the commands 
+queued in the command-queue are executed in-order or out-of-order. If set, the 
+commands in the command-queue are executed out-of-order. Otherwise, commands are 
+executed in-order.
+                            
+ * 'CL_QUEUE_PROFILING_ENABLE', Enable or disable profiling of commands in the 
+command-queue. If set, the profiling of commands is enabled. Otherwise profiling 
+of commands is disabled. See 'clGetEventProfilingInfo' for more information.
+-}
+{#enum CLCommandQueueProperty {upcaseFirstLetter} deriving( Show, Bounded, Eq, Ord ) #}
+
+#c
+enum CLDeviceFPConfig {
+  cL_FP_DENORM=CL_FP_DENORM, cL_FP_INF_NAN=CL_FP_INF_NAN,
+  cL_FP_ROUND_TO_NEAREST=CL_FP_ROUND_TO_NEAREST,
+  cL_FP_ROUND_TO_ZERO=CL_FP_ROUND_TO_ZERO,
+  cL_FP_ROUND_TO_INF=CL_FP_ROUND_TO_INF, cL_FP_FMA=CL_FP_FMA,
+  };
+#endc
+
+{-|
+ * 'CL_FP_DENORM', denorms are supported.
+                      
+ * 'CL_FP_INF_NAN', INF and NaNs are supported.
+                      
+ * 'CL_FP_ROUND_TO_NEAREST', round to nearest even rounding mode supported.
+                      
+ * 'CL_FP_ROUND_TO_ZERO', round to zero rounding mode supported.
+                      
+ * 'CL_FP_ROUND_TO_INF', round to +ve and -ve infinity rounding modes supported.
+                      
+ * 'CL_FP_FMA', IEEE754-2008 fused multiply-add is supported.
+-}
+{#enum CLDeviceFPConfig {upcaseFirstLetter} deriving( Show, Bounded, Eq, Ord ) #}
+
+#c
+enum CLDeviceExecCapability {
+  cL_EXEC_KERNEL=CL_EXEC_KERNEL,
+  cL_EXEC_NATIVE_KERNEL=CL_EXEC_NATIVE_KERNEL
+  };
+#endc
+
+{-|
+ * 'CL_EXEC_KERNEL', The OpenCL device can execute OpenCL kernels.
+                            
+ * 'CL_EXEC_NATIVE_KERNEL', The OpenCL device can execute native kernels.
+-}
+{#enum CLDeviceExecCapability {upcaseFirstLetter} deriving( Show, Bounded, Eq, Ord ) #}
+
+#c
+enum CLDeviceMemCacheType {
+  cL_NONE=CL_NONE, cL_READ_ONLY_CACHE=CL_READ_ONLY_CACHE,
+  cL_READ_WRITE_CACHE=CL_READ_WRITE_CACHE
+  };
+#endc
+
+{#enum CLDeviceMemCacheType {upcaseFirstLetter} deriving( Show ) #}
+
+#c
+enum CLDeviceLocalMemType {
+  cL_LOCAL=CL_LOCAL, cL_GLOBAL=CL_GLOBAL
+  };
+#endc
+
+{#enum CLDeviceLocalMemType {upcaseFirstLetter} deriving( Show ) #}
+
+-- -----------------------------------------------------------------------------
+#c
+enum CLCommandType {
+  cL_COMMAND_NDRANGE_KERNEL=CL_COMMAND_NDRANGE_KERNEL,
+  cL_COMMAND_TASK=CL_COMMAND_TASK ,
+  cL_COMMAND_NATIVE_KERNEL=CL_COMMAND_NATIVE_KERNEL,
+  cL_COMMAND_READ_BUFFER=CL_COMMAND_READ_BUFFER,
+  cL_COMMAND_WRITE_BUFFER=CL_COMMAND_WRITE_BUFFER,
+  cL_COMMAND_COPY_BUFFER=CL_COMMAND_COPY_BUFFER,
+  cL_COMMAND_READ_IMAGE=CL_COMMAND_READ_IMAGE,
+  cL_COMMAND_WRITE_IMAGE=CL_COMMAND_WRITE_IMAGE,
+  cL_COMMAND_COPY_IMAGE=CL_COMMAND_COPY_IMAGE,
+  cL_COMMAND_COPY_BUFFER_TO_IMAGE=CL_COMMAND_COPY_BUFFER_TO_IMAGE,
+  cL_COMMAND_COPY_IMAGE_TO_BUFFER=CL_COMMAND_COPY_IMAGE_TO_BUFFER,
+  cL_COMMAND_MAP_BUFFER=CL_COMMAND_MAP_BUFFER,
+  cL_COMMAND_MAP_IMAGE=CL_COMMAND_MAP_IMAGE,
+  cL_COMMAND_UNMAP_MEM_OBJECT=CL_COMMAND_UNMAP_MEM_OBJECT,
+  cL_COMMAND_MARKER=CL_COMMAND_MARKER,
+  cL_COMMAND_ACQUIRE_GL_OBJECTS=CL_COMMAND_ACQUIRE_GL_OBJECTS,
+  cL_COMMAND_RELEASE_GL_OBJECTS=CL_COMMAND_RELEASE_GL_OBJECTS
+  };
+#endc
+
+-- | Command associated with an event.
+{#enum CLCommandType {upcaseFirstLetter} deriving( Show ) #}
+
+#c
+enum CLCommandExecutionStatus {
+  cL_QUEUED=CL_QUEUED, cL_SUBMITTED=CL_SUBMITTED, cL_RUNNING=CL_RUNNING,
+  cL_COMPLETE=CL_COMPLETE, cL_EXEC_ERROR= -1
+  };
+#endc
+
+{-|
+ * 'CL_QUEUED', command has been enqueued in the command-queue.
+
+ * 'CL_SUBMITTED', enqueued command has been submitted by the host to the 
+device associated with the command-queue.
+
+ * 'CL_RUNNING', device is currently executing this command.
+                            
+ * 'CL_COMPLETE', the command has completed.
+                              
+ * 'CL_EXEC_ERROR', command was abnormally terminated.
+-}
+{#enum CLCommandExecutionStatus {upcaseFirstLetter} deriving( Show ) #}
+
+#c
+enum CLProfilingInfo {
+  cL_PROFILING_COMMAND_QUEUED=CL_PROFILING_COMMAND_QUEUED,
+  cL_PROFILING_COMMAND_SUBMIT=CL_PROFILING_COMMAND_SUBMIT,
+  cL_PROFILING_COMMAND_START=CL_PROFILING_COMMAND_START,
+  cL_PROFILING_COMMAND_END=CL_PROFILING_COMMAND_END
+  };
+#endc
+
+{-| Specifies the profiling data.
+
+ * 'CL_PROFILING_COMMAND_QUEUED', A 64-bit value that describes the current 
+device time counter in nanoseconds when the command identified by event is 
+enqueued in a command-queue by the host.
+ 
+ * 'CL_PROFILING_COMMAND_SUBMIT', A 64-bit value that describes the current 
+device time counter in nanoseconds when the command identified by event that has 
+been enqueued is submitted by the host to the device associated with the 
+commandqueue.
+ 
+ * 'CL_PROFILING_COMMAND_START', A 64-bit value that describes the current 
+device time counter in nanoseconds when the command identified by event starts 
+execution on the device.
+ 
+ * 'CL_PROFILING_COMMAND_END', A 64-bit value that describes the current device 
+time counter in nanoseconds when the command identified by event has finished 
+execution on the device.
+-}
+{#enum CLProfilingInfo {upcaseFirstLetter} deriving( Show ) #}
+
+-- -----------------------------------------------------------------------------
+#c
+enum CLMemFlag {
+  cL_MEM_READ_WRITE=CL_MEM_READ_WRITE,
+  cL_MEM_WRITE_ONLY=CL_MEM_WRITE_ONLY,
+  cL_MEM_READ_ONLY=CL_MEM_READ_ONLY,
+  cL_MEM_USE_HOST_PTR=CL_MEM_USE_HOST_PTR,
+  cL_MEM_ALLOC_HOST_PTR=CL_MEM_ALLOC_HOST_PTR,
+  cL_MEM_COPY_HOST_PTR=CL_MEM_COPY_HOST_PTR
+  };
+#endc
+{-| 
+ * 'CL_MEM_READ_WRITE', This flag specifies that the memory object will be
+read and written by a kernel. This is the default.
+
+ * 'CL_MEM_WRITE_ONLY', This flags specifies that the memory object will be
+written but not read by a kernel. Reading from a buffer or image object created
+with 'CLMEM_WRITE_ONLY' inside a kernel is undefined.
+
+ * 'CL_MEM_READ_ONLY', This flag specifies that the memory object is a read-only
+memory object when used inside a kernel. Writing to a buffer or image object
+created with 'CLMEM_READ_ONLY' inside a kernel is undefined.
+
+ * 'CL_MEM_USE_HOST_PTR', This flag is valid only if host_ptr is not NULL. If
+specified, it indicates that the application wants the OpenCL implementation to
+use memory referenced by host_ptr as the storage bits for the memory
+object. OpenCL implementations are allowed to cache the buffer contents pointed
+to by host_ptr in device memory. This cached copy can be used when kernels are
+executed on a device. The result of OpenCL commands that operate on multiple
+buffer objects created with the same host_ptr or overlapping host regions is
+considered to be undefined.
+
+ * 'CL_MEM_ALLOC_HOST_PTR', This flag specifies that the application wants the
+OpenCL implementation to allocate memory from host accessible
+memory. 'CL_MEM_ALLOC_HOST_PTR' and 'CL_MEM_USE_HOST_PTR' are mutually exclusive.
+
+ * 'CL_MEM_COPY_HOST_PTR', This flag is valid only if host_ptr is not NULL. If
+specified, it indicates that the application wants the OpenCL implementation to
+allocate memory for the memory object and copy the data from memory referenced
+by host_ptr. 'CL_MEM_COPY_HOST_PTR' and 'CL_MEM_USE_HOST_PTR' are mutually
+exclusive. 'CL_MEM_COPY_HOST_PTR' can be used with 'CL_MEM_ALLOC_HOST_PTR' to
+initialize the contents of the cl_mem object allocated using host-accessible
+(e.g. PCIe) memory.  
+-} 
+{#enum CLMemFlag {upcaseFirstLetter} deriving( Show, Bounded, Eq, Ord ) #}
+
+#c
+enum CLMemObjectType {
+  cL_MEM_OBJECT_BUFFER=CL_MEM_OBJECT_BUFFER,
+  cL_MEM_OBJECT_IMAGE2D=CL_MEM_OBJECT_IMAGE2D,
+  cL_MEM_OBJECT_IMAGE3D=CL_MEM_OBJECT_IMAGE3D
+  };
+#endc
+
+{-| * 'CL_MEM_OBJECT_BUFFER' if memobj is created with 'clCreateBuffer'. 
+ 
+ * 'CL_MEM_OBJECT_IMAGE2D' if memobj is created with 'clCreateImage2D' 
+
+ * 'CL_MEM_OBJECT_IMAGE3D' if memobj is created with 'clCreateImage3D'.
+-}
+{#enum CLMemObjectType {upcaseFirstLetter} deriving( Show ) #}
+
+#c
+enum CLBuildStatus {
+  cL_BUILD_NONE=CL_BUILD_NONE,
+  cL_BUILD_ERROR=CL_BUILD_ERROR,
+  cL_BUILD_SUCCESS=CL_BUILD_SUCCESS,
+  cL_BUILD_IN_PROGRESS=CL_BUILD_IN_PROGRESS,
+  };
+#endc
+
+{-| * 'CL_BUILD_NONE'. The build status returned if no build has been performed
+on the specified program object for device.
+
+ * 'CL_BUILD_ERROR'. The build status returned if the last call to
+'clBuildProgram' on the specified program object for device generated an error.
+
+ * 'CL_BUILD_SUCCESS'. The build status retrned if the last call to
+'clBuildProgram' on the specified program object for device was successful.
+
+ * 'CL_BUILD_IN_PROGRESS'. The build status returned if the last call to 
+'clBuildProgram' on the specified program object for device has not finished.
+-}
+{#enum CLBuildStatus {upcaseFirstLetter} deriving( Show ) #}
+
+#c
+enum CLAddressingMode {
+  cL_ADDRESS_REPEAT=CL_ADDRESS_REPEAT,
+  cL_ADDRESS_CLAMP_TO_EDGE =CL_ADDRESS_CLAMP_TO_EDGE ,
+  cL_ADDRESS_CLAMP=CL_ADDRESS_CLAMP,
+  cL_ADDRESS_NONE=CL_ADDRESS_NONE
+  };
+#endc
+{#enum CLAddressingMode {upcaseFirstLetter} deriving( Show ) #}
+
+#c
+enum CLFilterMode {
+  cL_FILTER_NEAREST=CL_FILTER_NEAREST,
+  cL_FILTER_LINEAR=CL_FILTER_LINEAR,
+  };
+#endc
+{#enum CLFilterMode {upcaseFirstLetter} deriving( Show ) #}
+
+-- -----------------------------------------------------------------------------
+getCLValue :: (Enum a, Integral b) => a -> b
+getCLValue = fromIntegral . fromEnum
+
+getEnumCL :: (Integral a, Enum b) => a -> b
+getEnumCL = toEnum . fromIntegral 
+
+getCommandExecutionStatus :: CLint -> CLCommandExecutionStatus
+getCommandExecutionStatus n 
+  | n < 0 = CL_EXEC_ERROR
+  | otherwise = getEnumCL $ n
+                
+-- -----------------------------------------------------------------------------
+binaryFlags :: (Ord b, Enum b, Bounded b) => b -> [b]
+binaryFlags m = map toEnum . takeWhile (<= (fromEnum m)) $ [1 `shiftL` n | n <- [0..]]
+  
+testMask :: Bits b => b -> b -> Bool
+testMask mask v = (v .&. mask) == v
+
+bitmaskFromFlags :: (Enum a, Bits b) => [a] -> b
+bitmaskFromFlags = foldl' (.|.) 0 . map (fromIntegral . fromEnum)
+
+bitmaskToFlags :: (Enum a, Bits b) => [a] -> b -> [a]
+bitmaskToFlags xs mask = filter (testMask mask . fromIntegral . fromEnum) xs
+
+bitmaskToDeviceTypes :: CLDeviceType_ -> [CLDeviceType]
+bitmaskToDeviceTypes = bitmaskToFlags [CL_DEVICE_TYPE_CPU,CL_DEVICE_TYPE_GPU,CL_DEVICE_TYPE_ACCELERATOR,CL_DEVICE_TYPE_DEFAULT,CL_DEVICE_TYPE_ALL]
+
+bitmaskToCommandQueueProperties :: CLCommandQueueProperty_ -> [CLCommandQueueProperty]
+bitmaskToCommandQueueProperties = bitmaskToFlags (binaryFlags maxBound)
+      
+bitmaskToFPConfig :: CLDeviceFPConfig_ -> [CLDeviceFPConfig]
+bitmaskToFPConfig = bitmaskToFlags (binaryFlags maxBound)
+
+bitmaskToExecCapability :: CLDeviceExecCapability_ -> [CLDeviceExecCapability]
+bitmaskToExecCapability = bitmaskToFlags (binaryFlags maxBound)
+
+bitmaskToMemFlags :: CLMemFlags_ -> [CLMemFlag]
+bitmaskToMemFlags = bitmaskToFlags (binaryFlags maxBound)
+
+-- -----------------------------------------------------------------------------
