Exynos Camera module for Galaxy S2 stable
authorPaul Kocialkowski <contact@paulk.fr>
Mon, 4 Feb 2013 17:37:11 +0000 (18:37 +0100)
committerPaul Kocialkowski <contact@paulk.fr>
Mon, 4 Feb 2013 17:37:11 +0000 (18:37 +0100)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Android.mk [new file with mode: 0644]
MODULE_LICENSE_GPL [new file with mode: 0644]
NOTICE [new file with mode: 0644]
exynos_camera.c [new file with mode: 0644]
exynos_camera.h [new file with mode: 0644]
exynos_exif.c [new file with mode: 0644]
exynos_param.c [new file with mode: 0644]
exynos_v4l2.c [new file with mode: 0644]
include/linux/videodev2_samsung.h [new file with mode: 0644]

diff --git a/Android.mk b/Android.mk
new file mode 100644 (file)
index 0000000..2e31d99
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2013 Paul Kocialkowski
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       exynos_camera.c \
+       exynos_exif.c \
+       exynos_param.c \
+       exynos_v4l2.c
+
+LOCAL_C_INCLUDES := \
+       $(LOCAL_PATH)/include \
+       hardware/samsung/exynos4/hal/include
+
+LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libcamera_client libhardware libs5pjpeg
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_MODULE := camera.exynos4
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/MODULE_LICENSE_GPL b/MODULE_LICENSE_GPL
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/NOTICE b/NOTICE
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 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 General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is 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.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+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.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  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 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. Use with the GNU Affero General Public License.
+
+  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 Affero 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 special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 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 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 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 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 General Public License for more details.
+
+    You should have received a copy of the GNU 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 the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  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 GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/exynos_camera.c b/exynos_camera.c
new file mode 100644 (file)
index 0000000..fa01588
--- /dev/null
@@ -0,0 +1,2853 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * Based on crespo libcamera and exynos4 hal libcamera:
+ * Copyright 2008, The Android Open Source Project
+ * Copyright 2010, Samsung Electronics Co. LTD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>
+#include <jpeg_api.h>
+
+#define LOG_TAG "exynos_camera"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+#include "exynos_camera.h"
+
+/*
+ * Devices configurations
+ */
+
+struct exynos_camera_preset exynos_camera_presets_galaxys2[] = {
+       {
+               .name = "M5MO",
+               .facing = CAMERA_FACING_BACK,
+               .orientation = 90,
+               .rotation = 0,
+               .hflip = 0,
+               .vflip = 0,
+               .picture_format = V4L2_PIX_FMT_JPEG,
+               .focal_length = 4.03f,
+               .horizontal_view_angle = 60.5f,
+               .vertical_view_angle = 47.1f,
+               .metering = METERING_CENTER,
+               .params = {
+                       .preview_size_values = "1280x720,640x480,720x480,800x480,800x450,352x288,320x240,176x144",
+                       .preview_size = "640x480",
+                       .preview_format_values = "yuv420sp,yuv420p,rgb565",
+                       .preview_format = "yuv420sp",
+                       .preview_frame_rate_values = "30,25,20,15,10,7",
+                       .preview_frame_rate = 30,
+                       .preview_fps_range_values = "(7000,30000)",
+                       .preview_fps_range = "7000,30000",
+
+                       .picture_size_values = "3264x2448,3264x1968,2048x1536,2048x1232,800x480,640x480",
+                       .picture_size = "3264x2448",
+                       .picture_format_values = "jpeg",
+                       .picture_format = "jpeg",
+                       .jpeg_thumbnail_size_values = "320x240,400x240,0x0",
+                       .jpeg_thumbnail_width = 320,
+                       .jpeg_thumbnail_height = 240,
+                       .jpeg_thumbnail_quality = 100,
+                       .jpeg_quality = 90,
+
+                       .recording_size = "720x480",
+                       .recording_size_values = "1920x1080,1280x720,720x480,640x480",
+                       .recording_format = "yuv420sp",
+
+                       .focus_mode = "auto",
+                       .focus_mode_values = "auto,infinity,macro,fixed,facedetect,continuous-video",
+                       .focus_distances = "0.15,1.20,Infinity",
+                       .focus_areas = "(0,0,0,0,0)",
+                       .max_num_focus_areas = 1,
+
+                       .zoom_supported = 1,
+                       .smooth_zoom_supported = 0,
+                       .zoom_ratios = "100,102,104,109,111,113,119,121,124,131,134,138,146,150,155,159,165,170,182,189,200,213,222,232,243,255,283,300,319,364,400",
+                       .zoom = 0,
+                       .max_zoom = 30,
+
+                       .flash_mode = "off",
+                       .flash_mode_values = "off,auto,on,torch",
+
+                       .exposure_compensation = 0,
+                       .exposure_compensation_step = 0.5,
+                       .min_exposure_compensation = -4,
+                       .max_exposure_compensation = 4,
+
+                       .whitebalance = "auto",
+                       .whitebalance_values = "auto,incandescent,fluorescent,daylight,cloudy-daylight",
+
+                       .scene_mode = "auto",
+                       .scene_mode_values = "auto,portrait,landscape,night,beach,snow,sunset,fireworks,sports,party,candlelight,dusk-dawn,fall-color,back-light,text",
+
+                       .effect = "none",
+                       .effect_values = "none,mono,negative,sepia,aqua",
+
+                       .iso = "auto",
+                       .iso_values = "auto,ISO50,ISO100,ISO200,ISO400,ISO800",
+               },
+       },
+       {
+               .name = "S5K5BAFX",
+               .facing = CAMERA_FACING_FRONT,
+               .orientation = 270,
+               .rotation = 0,
+               .hflip = 0,
+               .vflip = 0,
+               .picture_format = V4L2_PIX_FMT_YUYV,
+               .focal_length = 2.73f,
+               .horizontal_view_angle = 51.2f,
+               .vertical_view_angle = 39.4f,
+               .metering = METERING_CENTER,
+               .params = {
+                       .preview_size_values = "640x480,352x288,320x240,176x144",
+                       .preview_size = "640x480",
+                       .preview_format_values = "yuv420sp,yuv420p,rgb565",
+                       .preview_format = "yuv420sp",
+                       .preview_frame_rate_values = "30,25,20,15,10,7",
+                       .preview_frame_rate = 30,
+                       .preview_fps_range_values = "(7000,30000)",
+                       .preview_fps_range = "7000,30000",
+
+                       .picture_size_values = "1600x1200,640x480",
+                       .picture_size = "1600x1200",
+                       .picture_format_values = "jpeg",
+                       .picture_format = "jpeg",
+                       .jpeg_thumbnail_size_values = "160x120,0x0",
+                       .jpeg_thumbnail_width = 160,
+                       .jpeg_thumbnail_height = 120,
+                       .jpeg_thumbnail_quality = 100,
+                       .jpeg_quality = 90,
+
+                       .recording_size = "640x480",
+                       .recording_size_values = "640x480",
+                       .recording_format = "yuv420sp",
+
+                       .focus_mode = "fixed",
+                       .focus_mode_values = "fixed",
+                       .focus_distances = "0.20,0.25,Infinity",
+                       .focus_areas = NULL,
+                       .max_num_focus_areas = 0,
+
+                       .zoom_supported = 0,
+
+                       .flash_mode = NULL,
+                       .flash_mode_values = NULL,
+
+                       .exposure_compensation = 0,
+                       .exposure_compensation_step = 0.5,
+                       .min_exposure_compensation = -4,
+                       .max_exposure_compensation = 4,
+
+                       .whitebalance = NULL,
+                       .whitebalance_values = NULL,
+
+                       .scene_mode = NULL,
+                       .scene_mode_values = NULL,
+
+                       .effect = NULL,
+                       .effect_values = NULL,
+
+                       .iso = "auto",
+                       .iso_values = "auto",
+               },
+       },
+};
+
+struct exynos_v4l2_node exynos_v4l2_nodes_galaxys2[] = {
+       {
+               .id = 0,
+               .node = "/dev/video0",
+       },
+       {
+               .id = 1,
+               .node = "/dev/video1",
+       },
+       {
+               .id = 2,
+               .node = "/dev/video2",
+       },
+};
+
+struct exynox_camera_config exynos_camera_config_galaxys2 = {
+       .presets = (struct exynos_camera_preset *) &exynos_camera_presets_galaxys2,
+       .presets_count = 2,
+       .v4l2_nodes = (struct exynos_v4l2_node *) &exynos_v4l2_nodes_galaxys2,
+       .v4l2_nodes_count = 3,
+};
+
+/*
+ * Exynos Camera
+ */
+
+struct exynox_camera_config *exynos_camera_config =
+       &exynos_camera_config_galaxys2;
+
+int exynos_camera_init(struct exynos_camera *exynos_camera, int id)
+{
+       char firmware_version[7] = { 0 };
+       struct exynos_v4l2_ext_control control;
+       int rc;
+
+       if (exynos_camera == NULL || id >= exynos_camera->config->presets_count)
+               return -EINVAL;
+
+       // Init FIMC1
+       rc = exynos_v4l2_open(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("Unable to open v4l2 device");
+               return -1;
+       }
+
+       rc = exynos_v4l2_querycap_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: querycap failed", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_enum_input(exynos_camera, 0, id);
+       if (rc < 0) {
+               LOGE("%s: enum input failed", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_input(exynos_camera, 0, id);
+       if (rc < 0) {
+               LOGE("%s: s input failed", __func__);
+               return -1;
+       }
+
+       // Init FIMC2
+       rc = exynos_v4l2_open(exynos_camera, 2);
+       if (rc < 0) {
+               LOGE("Unable to open v4l2 device");
+               return -1;
+       }
+
+       rc = exynos_v4l2_querycap_cap(exynos_camera, 2);
+       if (rc < 0) {
+               LOGE("%s: querycap failed", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_enum_input(exynos_camera, 2, id);
+       if (rc < 0) {
+               LOGE("%s: enum input failed", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_input(exynos_camera, 2, id);
+       if (rc < 0) {
+               LOGE("%s: s input failed", __func__);
+               return -1;
+       }
+
+       // Get firmware information
+       memset(&control, 0, sizeof(control));
+       control.id = V4L2_CID_CAM_SENSOR_FW_VER;
+       control.data.string = firmware_version;
+
+       rc = exynos_v4l2_g_ext_ctrls(exynos_camera, 0, (struct v4l2_ext_control *) &control, 1);
+       if (rc < 0) {
+               LOGE("%s: g ext ctrls failed", __func__);
+       } else {
+               LOGD("Firmware version: %s", firmware_version);
+       }
+
+       // Params
+       rc = exynos_camera_params_init(exynos_camera, id);
+       if (rc < 0)
+               LOGE("%s: Unable to init params", __func__);
+
+       // Gralloc
+       rc = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const struct hw_module_t **) &exynos_camera->gralloc);
+       if (rc)
+               LOGE("%s: Unable to get gralloc module", __func__);
+
+       return 0;
+}
+
+void exynos_camera_deinit(struct exynos_camera *exynos_camera)
+{
+       int i;
+       int id;
+
+       if (exynos_camera == NULL || exynos_camera->config == NULL)
+               return;
+
+       exynos_v4l2_close(exynos_camera, 0);
+       exynos_v4l2_close(exynos_camera, 2);
+}
+
+// Params
+
+int exynos_camera_params_init(struct exynos_camera *exynos_camera, int id)
+{
+       int rc;
+
+       if (exynos_camera == NULL || id >= exynos_camera->config->presets_count)
+               return -EINVAL;
+
+       // Camera params
+       exynos_camera->camera_rotation = exynos_camera->config->presets[id].rotation;
+       exynos_camera->camera_hflip = exynos_camera->config->presets[id].hflip;
+       exynos_camera->camera_vflip = exynos_camera->config->presets[id].vflip;
+       exynos_camera->camera_picture_format = exynos_camera->config->presets[id].picture_format;
+       exynos_camera->camera_focal_length = (int) (exynos_camera->config->presets[id].focal_length * 100);
+       exynos_camera->camera_metering = exynos_camera->config->presets[id].metering;
+
+       // Recording preview
+       exynos_param_string_set(exynos_camera, "preferred-preview-size-for-video",
+               exynos_camera->config->presets[id].params.preview_size);
+
+       // Preview
+       exynos_param_string_set(exynos_camera, "preview-size-values",
+               exynos_camera->config->presets[id].params.preview_size_values);
+       exynos_param_string_set(exynos_camera, "preview-size",
+               exynos_camera->config->presets[id].params.preview_size);
+       exynos_param_string_set(exynos_camera, "preview-format-values",
+               exynos_camera->config->presets[id].params.preview_format_values);
+       exynos_param_string_set(exynos_camera, "preview-format",
+               exynos_camera->config->presets[id].params.preview_format);
+       exynos_param_string_set(exynos_camera, "preview-frame-rate-values",
+               exynos_camera->config->presets[id].params.preview_frame_rate_values);
+       exynos_param_int_set(exynos_camera, "preview-frame-rate",
+               exynos_camera->config->presets[id].params.preview_frame_rate);
+       exynos_param_string_set(exynos_camera, "preview-fps-range-values",
+               exynos_camera->config->presets[id].params.preview_fps_range_values);
+       exynos_param_string_set(exynos_camera, "preview-fps-range",
+               exynos_camera->config->presets[id].params.preview_fps_range);
+
+       // Picture
+       exynos_param_string_set(exynos_camera, "picture-size-values",
+               exynos_camera->config->presets[id].params.picture_size_values);
+       exynos_param_string_set(exynos_camera, "picture-size",
+               exynos_camera->config->presets[id].params.picture_size);
+       exynos_param_string_set(exynos_camera, "picture-format-values",
+               exynos_camera->config->presets[id].params.picture_format_values);
+       exynos_param_string_set(exynos_camera, "picture-format",
+               exynos_camera->config->presets[id].params.picture_format);
+       exynos_param_string_set(exynos_camera, "jpeg-thumbnail-size-values",
+               exynos_camera->config->presets[id].params.jpeg_thumbnail_size_values);
+       exynos_param_int_set(exynos_camera, "jpeg-thumbnail-width",
+               exynos_camera->config->presets[id].params.jpeg_thumbnail_width);
+       exynos_param_int_set(exynos_camera, "jpeg-thumbnail-height",
+               exynos_camera->config->presets[id].params.jpeg_thumbnail_height);
+       exynos_param_int_set(exynos_camera, "jpeg-thumbnail-quality",
+               exynos_camera->config->presets[id].params.jpeg_thumbnail_quality);
+       exynos_param_int_set(exynos_camera, "jpeg-quality",
+               exynos_camera->config->presets[id].params.jpeg_quality);
+
+       // Recording
+       exynos_param_string_set(exynos_camera, "video-size",
+               exynos_camera->config->presets[id].params.recording_size);
+       exynos_param_string_set(exynos_camera, "video-size-values",
+               exynos_camera->config->presets[id].params.recording_size_values);
+       exynos_param_string_set(exynos_camera, "video-frame-format",
+               exynos_camera->config->presets[id].params.recording_format);
+
+       // Focus
+       exynos_param_string_set(exynos_camera, "focus-mode",
+               exynos_camera->config->presets[id].params.focus_mode);
+       exynos_param_string_set(exynos_camera, "focus-mode-values",
+               exynos_camera->config->presets[id].params.focus_mode_values);
+       exynos_param_string_set(exynos_camera, "focus-distances",
+               exynos_camera->config->presets[id].params.focus_distances);
+       if (exynos_camera->config->presets[id].params.max_num_focus_areas > 0) {
+               exynos_param_string_set(exynos_camera, "focus-areas",
+                       exynos_camera->config->presets[id].params.focus_areas);
+               exynos_param_int_set(exynos_camera, "max-num-focus-areas",
+                       exynos_camera->config->presets[id].params.max_num_focus_areas);
+       }
+
+       // Zoom
+       if (exynos_camera->config->presets[id].params.zoom_supported == 1) {
+               exynos_param_string_set(exynos_camera, "zoom-supported", "true");
+
+               if (exynos_camera->config->presets[id].params.smooth_zoom_supported == 1)
+                       exynos_param_string_set(exynos_camera, "smooth-zoom-supported", "true");
+
+               if (exynos_camera->config->presets[id].params.zoom_ratios != NULL)
+                       exynos_param_string_set(exynos_camera, "zoom-ratios", exynos_camera->config->presets[id].params.zoom_ratios);
+
+               exynos_param_int_set(exynos_camera, "zoom", exynos_camera->config->presets[id].params.zoom);
+               exynos_param_int_set(exynos_camera, "max-zoom", exynos_camera->config->presets[id].params.max_zoom);
+
+       } else {
+               exynos_param_string_set(exynos_camera, "zoom-supported", "false");
+       }
+
+       // Flash
+       exynos_param_string_set(exynos_camera, "flash-mode",
+               exynos_camera->config->presets[id].params.flash_mode);
+       exynos_param_string_set(exynos_camera, "flash-mode-values",
+               exynos_camera->config->presets[id].params.flash_mode_values);
+
+       // Exposure
+       exynos_param_int_set(exynos_camera, "exposure-compensation",
+               exynos_camera->config->presets[id].params.exposure_compensation);
+       exynos_param_float_set(exynos_camera, "exposure-compensation-step",
+               exynos_camera->config->presets[id].params.exposure_compensation_step);
+       exynos_param_int_set(exynos_camera, "min-exposure-compensation",
+               exynos_camera->config->presets[id].params.min_exposure_compensation);
+       exynos_param_int_set(exynos_camera, "max-exposure-compensation",
+               exynos_camera->config->presets[id].params.max_exposure_compensation);
+
+       // WB
+       exynos_param_string_set(exynos_camera, "whitebalance",
+               exynos_camera->config->presets[id].params.whitebalance);
+       exynos_param_string_set(exynos_camera, "whitebalance-values",
+               exynos_camera->config->presets[id].params.whitebalance_values);
+
+       // Scene mode
+       exynos_param_string_set(exynos_camera, "scene-mode",
+               exynos_camera->config->presets[id].params.scene_mode);
+       exynos_param_string_set(exynos_camera, "scene-mode-values",
+               exynos_camera->config->presets[id].params.scene_mode_values);
+
+       // Effect
+       exynos_param_string_set(exynos_camera, "effect",
+               exynos_camera->config->presets[id].params.effect);
+       exynos_param_string_set(exynos_camera, "effect-values",
+               exynos_camera->config->presets[id].params.effect_values);
+
+       // ISO
+       exynos_param_string_set(exynos_camera, "iso",
+               exynos_camera->config->presets[id].params.iso);
+       exynos_param_string_set(exynos_camera, "iso-values",
+               exynos_camera->config->presets[id].params.iso_values);
+
+       // Camera
+       exynos_param_float_set(exynos_camera, "focal-length",
+               exynos_camera->config->presets[id].focal_length);
+       exynos_param_float_set(exynos_camera, "horizontal-view-angle",
+               exynos_camera->config->presets[id].horizontal_view_angle);
+       exynos_param_float_set(exynos_camera, "vertical-view-angle",
+               exynos_camera->config->presets[id].vertical_view_angle);
+
+       rc = exynos_camera_params_apply(exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to apply params", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_camera_params_apply(struct exynos_camera *exynos_camera)
+{
+       char *recording_hint_string;
+       char *recording_preview_size_string;
+
+       char *preview_size_string;
+       int preview_width = 0;
+       int preview_height = 0;
+       char *preview_format_string;
+       int preview_format;
+       float preview_format_bpp;
+       int preview_fps;
+
+       char *picture_size_string;
+       int picture_width = 0;
+       int picture_height = 0;
+       char *picture_format_string;
+       int picture_format;
+
+       int jpeg_thumbnail_width;
+       int jpeg_thumbnail_height;
+       int jpeg_thumbnail_quality;
+       int jpeg_quality;
+
+       char *video_size_string;
+       int recording_width = 0;
+       int recording_height = 0;
+       char *video_frame_format_string;
+       int recording_format;
+       int camera_sensor_mode;
+       int camera_sensor_output_size;
+
+       char *focus_mode_string;
+       int focus_mode;
+       char *focus_areas_string;
+       int focus_left, focus_top, focus_right, focus_bottom, focus_weigth;
+       int focus_x;
+       int focus_y;
+
+       char *zoom_supported_string;
+       int zoom, max_zoom;
+
+       char *flash_mode_string;
+       int flash_mode;
+
+       int exposure_compensation;
+       int min_exposure_compensation;
+       int max_exposure_compensation;
+
+       char *whitebalance_string;
+       int whitebalance;
+
+       char *scene_mode_string;
+       int scene_mode;
+
+       char *effect_string;
+       int effect;
+
+       char *iso_string;
+       int iso;
+
+       int force ;
+
+       int w, h;
+       char *k;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       if (!exynos_camera->preview_params_set) {
+               LOGE("%s: Setting preview params", __func__);
+               exynos_camera->preview_params_set = 1;
+               force = 1;
+       } else {
+               force = 0;
+       }
+
+       // Preview
+       preview_size_string = exynos_param_string_get(exynos_camera, "preview-size");
+       if (preview_size_string != NULL) {
+               sscanf(preview_size_string, "%dx%d", &preview_width, &preview_height);
+
+               if (preview_width != 0 && preview_width != exynos_camera->preview_width)
+                       exynos_camera->preview_width = preview_width;
+               if (preview_height != 0 && preview_height != exynos_camera->preview_height)
+                       exynos_camera->preview_height = preview_height;
+       }
+
+       preview_format_string = exynos_param_string_get(exynos_camera, "preview-format");
+       if (preview_format_string != NULL) {
+               if (strcmp(preview_format_string, "yuv420sp") == 0) {
+                       preview_format = V4L2_PIX_FMT_NV21;
+                       preview_format_bpp = 1.5f;
+               } else if (strcmp(preview_format_string, "yuv420p") == 0) {
+                       preview_format = V4L2_PIX_FMT_YUV420;
+                       preview_format_bpp = 1.5f;
+               } else if (strcmp(preview_format_string, "rgb565") == 0) {
+                       preview_format = V4L2_PIX_FMT_RGB565;
+                       preview_format_bpp = 2.0f;
+               } else if (strcmp(preview_format_string, "rgb8888") == 0) {
+                       preview_format = V4L2_PIX_FMT_RGB32;
+                       preview_format_bpp = 4.0f;
+               } else {
+                       LOGE("%s: Unsupported preview format: %s", __func__, preview_format_string);
+                       preview_format = V4L2_PIX_FMT_NV21;
+                       preview_format_bpp = 1.5f;
+               }
+
+               if (preview_format != exynos_camera->preview_format) {
+                       exynos_camera->preview_format = preview_format;
+                       exynos_camera->preview_format_bpp = preview_format_bpp;
+               }
+       }
+
+       preview_fps = exynos_param_int_get(exynos_camera, "preview-frame-rate");
+       if (preview_fps > 0)
+               exynos_camera->preview_fps = preview_fps;
+       else
+               exynos_camera->preview_fps = 0;
+
+       // Picture
+       picture_size_string = exynos_param_string_get(exynos_camera, "picture-size");
+       if (picture_size_string != NULL) {
+               sscanf(picture_size_string, "%dx%d", &picture_width, &picture_height);
+
+               if (picture_width != 0 && picture_height != 0 &&
+                       picture_width != exynos_camera->picture_width &&
+                       picture_height != exynos_camera->picture_height) {
+                       exynos_camera->picture_width = picture_width;
+                       exynos_camera->picture_height = picture_height;
+               }
+               
+       }
+
+       picture_format_string = exynos_param_string_get(exynos_camera, "picture-format");
+       if (picture_format_string != NULL) {
+               if (strcmp(picture_format_string, "jpeg") == 0) {
+                       picture_format = V4L2_PIX_FMT_JPEG;
+               } else {
+                       LOGE("%s: Unsupported picture format: %s", __func__, picture_format_string);
+                       picture_format = V4L2_PIX_FMT_JPEG;
+               }
+
+               if (picture_format != exynos_camera->picture_format)
+                       exynos_camera->picture_format = picture_format;
+       }
+
+       jpeg_thumbnail_width = exynos_param_int_get(exynos_camera, "jpeg-thumbnail-width");
+       if (jpeg_thumbnail_width > 0)
+               exynos_camera->jpeg_thumbnail_width = jpeg_thumbnail_width;
+
+       jpeg_thumbnail_height = exynos_param_int_get(exynos_camera, "jpeg-thumbnail-height");
+       if (jpeg_thumbnail_height > 0)
+               exynos_camera->jpeg_thumbnail_height = jpeg_thumbnail_height;
+
+       jpeg_thumbnail_quality = exynos_param_int_get(exynos_camera, "jpeg-thumbnail-quality");
+       if (jpeg_thumbnail_quality > 0)
+               exynos_camera->jpeg_thumbnail_quality = jpeg_thumbnail_quality;
+
+       jpeg_quality = exynos_param_int_get(exynos_camera, "jpeg-quality");
+       if (jpeg_quality <= 100 && jpeg_quality >= 0 && (jpeg_quality != exynos_camera->jpeg_quality || force)) {
+               exynos_camera->jpeg_quality = jpeg_quality;
+               rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_QUALITY, jpeg_quality);
+               if (rc < 0)
+                       LOGE("%s: s ctrl failed!", __func__);
+       }
+
+       // Recording
+       video_size_string = exynos_param_string_get(exynos_camera, "video-size");
+       if (video_size_string == NULL)
+               video_size_string = exynos_param_string_get(exynos_camera, "preview-size");
+
+       if (video_size_string != NULL) {
+               sscanf(video_size_string, "%dx%d", &recording_width, &recording_height);
+
+               if (recording_width != 0 && recording_width != exynos_camera->recording_width)
+                       exynos_camera->recording_width = recording_width;
+               if (recording_height != 0 && recording_height != exynos_camera->recording_height)
+                       exynos_camera->recording_height = recording_height;
+       }
+
+       video_frame_format_string = exynos_param_string_get(exynos_camera, "video-frame-format");
+       if (video_frame_format_string != NULL) {
+               if (strcmp(video_frame_format_string, "yuv420sp") == 0) {
+                       recording_format = V4L2_PIX_FMT_NV12;
+               } else if (strcmp(video_frame_format_string, "yuv420p") == 0) {
+                       recording_format = V4L2_PIX_FMT_YUV420;
+               } else if (strcmp(video_frame_format_string, "rgb565") == 0) {
+                       recording_format = V4L2_PIX_FMT_RGB565;
+               } else if (strcmp(video_frame_format_string, "rgb8888") == 0) {
+                       recording_format = V4L2_PIX_FMT_RGB32;
+               } else {
+                       LOGE("%s: Unsupported recording format: %s", __func__, video_frame_format_string);
+                       recording_format = V4L2_PIX_FMT_NV12;
+               }
+
+               if (recording_format != exynos_camera->recording_format)
+                       exynos_camera->recording_format = recording_format;
+       }
+
+       recording_hint_string = exynos_param_string_get(exynos_camera, "recording-hint");
+       if (recording_hint_string != NULL && strcmp(recording_hint_string, "true") == 0) {
+               camera_sensor_mode = SENSOR_MOVIE;
+
+               k = exynos_param_string_get(exynos_camera, "preview-size-values");
+               while (recording_width != 0 && recording_height != 0) {
+                       if (k == NULL)
+                               break;
+
+                       sscanf(k, "%dx%d", &w, &h);
+
+                       // Look for same aspect ratio
+                       if ((recording_width * h) / recording_height == w) {
+                               preview_width = w;
+                               preview_height = h;
+                               break;
+                       }
+
+                       k = strchr(k, ',');
+                       if (k == NULL)
+                               break;
+
+                       k++;
+               }
+
+               if (preview_width != 0 && preview_width != exynos_camera->preview_width)
+                       exynos_camera->preview_width = preview_width;
+               if (preview_height != 0 && preview_height != exynos_camera->preview_height)
+                       exynos_camera->preview_height = preview_height;
+
+               camera_sensor_output_size = ((recording_width & 0xffff) << 16) | (recording_height & 0xffff);
+               rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SENSOR_OUTPUT_SIZE,
+                       camera_sensor_output_size);
+               if (rc < 0)
+                       LOGE("%s: s ctrl failed!", __func__);
+       } else {
+               camera_sensor_mode = SENSOR_CAMERA;
+       }
+
+       // Switching modes
+       if (camera_sensor_mode != exynos_camera->camera_sensor_mode) {
+               exynos_camera->camera_sensor_mode = camera_sensor_mode;
+               rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SENSOR_MODE, camera_sensor_mode);
+               if (rc < 0)
+                       LOGE("%s: s ctrl failed!", __func__);
+       }
+
+       // Focus
+       focus_mode_string = exynos_param_string_get(exynos_camera, "focus-mode");
+       if (focus_mode_string != NULL) {
+               if (strcmp(focus_mode_string, "auto") == 0)
+                       focus_mode = FOCUS_MODE_AUTO;
+               else if (strcmp(focus_mode_string, "infinity") == 0)
+                       focus_mode = FOCUS_MODE_INFINITY;
+               else if (strcmp(focus_mode_string, "macro") == 0)
+                       focus_mode = FOCUS_MODE_MACRO;
+               else if (strcmp(focus_mode_string, "fixed") == 0)
+                       focus_mode = FOCUS_MODE_FIXED;
+               else if (strcmp(focus_mode_string, "facedetect") == 0)
+                       focus_mode = FOCUS_MODE_FACEDETECT;
+               else if (strcmp(focus_mode_string, "continuous-video") == 0)
+                       focus_mode = FOCUS_MODE_CONTINOUS;
+               else if (strcmp(focus_mode_string, "continuous-picture") == 0)
+                       focus_mode = FOCUS_MODE_CONTINOUS;
+               else
+                       focus_mode = FOCUS_MODE_AUTO;
+
+               if (focus_mode != exynos_camera->focus_mode || force) {
+                       exynos_camera->focus_mode = focus_mode;
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_FOCUS_MODE, focus_mode);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+       }
+
+       focus_areas_string = exynos_param_string_get(exynos_camera, "focus-areas");
+       if (focus_areas_string != NULL) {
+               focus_left = focus_top = focus_right = focus_bottom = focus_weigth = 0;
+
+               rc = sscanf(focus_areas_string, "(%d,%d,%d,%d,%d)",
+                       &focus_left, &focus_top, &focus_right, &focus_bottom, &focus_weigth);
+               if (rc != 5)
+                       LOGE("%s: sscanf failed!", __func__);
+
+               focus_x = (((focus_left + focus_right) / 2) + 1000) * preview_width / 2000;
+               focus_y =  (((focus_top + focus_bottom) / 2) + 1000) * preview_height / 2000;
+
+               if (focus_x != exynos_camera->focus_x || force) {
+                       exynos_camera->focus_x = focus_x;
+
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_OBJECT_POSITION_X, focus_x);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+
+               if (focus_y != exynos_camera->focus_y || force) {
+                       exynos_camera->focus_y = focus_y;
+
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_OBJECT_POSITION_Y, focus_y);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+       }
+
+       // Zoom
+       zoom_supported_string = exynos_param_string_get(exynos_camera, "zoom-supported");
+       if (zoom_supported_string != NULL && strcmp(zoom_supported_string, "true") == 0) {
+               zoom = exynos_param_int_get(exynos_camera, "zoom");
+               max_zoom = exynos_param_int_get(exynos_camera, "max-zoom");
+               if (zoom <= max_zoom && zoom >= 0 && (zoom != exynos_camera->zoom || force)) {
+                       exynos_camera->zoom = zoom;
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_ZOOM, zoom);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+
+       }
+
+       // Flash
+       flash_mode_string = exynos_param_string_get(exynos_camera, "flash-mode");
+       if (flash_mode_string != NULL) {
+               if (strcmp(flash_mode_string, "off") == 0)
+                       flash_mode = FLASH_MODE_OFF;
+               else if (strcmp(flash_mode_string, "auto") == 0)
+                       flash_mode = FLASH_MODE_AUTO;
+               else if (strcmp(flash_mode_string, "on") == 0)
+                       flash_mode = FLASH_MODE_ON;
+               else if (strcmp(flash_mode_string, "torch") == 0)
+                       flash_mode = FLASH_MODE_TORCH;
+               else
+                       flash_mode = FLASH_MODE_AUTO;
+
+               if (flash_mode != exynos_camera->flash_mode || force) {
+                       exynos_camera->flash_mode = flash_mode;
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_FLASH_MODE, flash_mode);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+       }
+
+       // Exposure
+       exposure_compensation = exynos_param_int_get(exynos_camera, "exposure-compensation");
+       min_exposure_compensation = exynos_param_int_get(exynos_camera, "min-exposure-compensation");
+       max_exposure_compensation = exynos_param_int_get(exynos_camera, "max-exposure-compensation");
+
+       if (exposure_compensation <= max_exposure_compensation && exposure_compensation >= min_exposure_compensation &&
+               (exposure_compensation != exynos_camera->exposure_compensation || force)) {
+               exynos_camera->exposure_compensation = exposure_compensation;
+               rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_BRIGHTNESS, exposure_compensation);
+               if (rc < 0)
+                       LOGE("%s: s ctrl failed!", __func__);
+       }
+
+       // WB
+       whitebalance_string = exynos_param_string_get(exynos_camera, "whitebalance");
+       if (whitebalance_string != NULL) {
+               if (strcmp(whitebalance_string, "auto") == 0)
+                       whitebalance = WHITE_BALANCE_AUTO;
+               else if (strcmp(whitebalance_string, "incandescent") == 0)
+                       whitebalance = WHITE_BALANCE_TUNGSTEN;
+               else if (strcmp(whitebalance_string, "fluorescent") == 0)
+                       whitebalance = WHITE_BALANCE_FLUORESCENT;
+               else if (strcmp(whitebalance_string, "daylight") == 0)
+                       whitebalance = WHITE_BALANCE_SUNNY;
+               else if (strcmp(whitebalance_string, "cloudy-daylight") == 0)
+                       whitebalance = WHITE_BALANCE_CLOUDY;
+               else
+                       whitebalance = WHITE_BALANCE_AUTO;
+
+               if (whitebalance != exynos_camera->whitebalance || force) {
+                       exynos_camera->whitebalance = whitebalance;
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_WHITE_BALANCE, whitebalance);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+       }
+
+       // Scene mode
+       scene_mode_string = exynos_param_string_get(exynos_camera, "scene-mode");
+       if (scene_mode_string != NULL) {
+               if (strcmp(scene_mode_string, "auto") == 0)
+                       scene_mode = SCENE_MODE_NONE;
+               else if (strcmp(scene_mode_string, "portrait") == 0)
+                       scene_mode = SCENE_MODE_PORTRAIT;
+               else if (strcmp(scene_mode_string, "landscape") == 0)
+                       scene_mode = SCENE_MODE_LANDSCAPE;
+               else if (strcmp(scene_mode_string, "night") == 0)
+                       scene_mode = SCENE_MODE_NIGHTSHOT;
+               else if (strcmp(scene_mode_string, "beach") == 0)
+                       scene_mode = SCENE_MODE_BEACH_SNOW;
+               else if (strcmp(scene_mode_string, "snow") == 0)
+                       scene_mode = SCENE_MODE_BEACH_SNOW;
+               else if (strcmp(scene_mode_string, "sunset") == 0)
+                       scene_mode = SCENE_MODE_SUNSET;
+               else if (strcmp(scene_mode_string, "fireworks") == 0)
+                       scene_mode = SCENE_MODE_FIREWORKS;
+               else if (strcmp(scene_mode_string, "sports") == 0)
+                       scene_mode = SCENE_MODE_SPORTS;
+               else if (strcmp(scene_mode_string, "party") == 0)
+                       scene_mode = SCENE_MODE_PARTY_INDOOR;
+               else if (strcmp(scene_mode_string, "candlelight") == 0)
+                       scene_mode = SCENE_MODE_CANDLE_LIGHT;
+               else if (strcmp(scene_mode_string, "dusk-dawn") == 0)
+                       scene_mode = SCENE_MODE_DUSK_DAWN;
+               else if (strcmp(scene_mode_string, "fall-color") == 0)
+                       scene_mode = SCENE_MODE_FALL_COLOR;
+               else if (strcmp(scene_mode_string, "back-light") == 0)
+                       scene_mode = SCENE_MODE_BACK_LIGHT;
+               else if (strcmp(scene_mode_string, "text") == 0)
+                       scene_mode = SCENE_MODE_TEXT;
+               else
+                       scene_mode = SCENE_MODE_NONE;
+
+               if (scene_mode != exynos_camera->scene_mode || force) {
+                       exynos_camera->scene_mode = scene_mode;
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SCENE_MODE, scene_mode);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+       }
+
+       // Effect
+       effect_string = exynos_param_string_get(exynos_camera, "effect");
+       if (effect_string != NULL) {
+               if (strcmp(effect_string, "auto") == 0)
+                       effect = IMAGE_EFFECT_NONE;
+               else if (strcmp(effect_string, "mono") == 0)
+                       effect = IMAGE_EFFECT_BNW;
+               else if (strcmp(effect_string, "negative") == 0)
+                       effect = IMAGE_EFFECT_NEGATIVE;
+               else if (strcmp(effect_string, "sepia") == 0)
+                       effect = IMAGE_EFFECT_SEPIA;
+               else if (strcmp(effect_string, "aqua") == 0)
+                       effect = IMAGE_EFFECT_AQUA;
+               else
+                       effect = IMAGE_EFFECT_NONE;
+
+               if (effect != exynos_camera->effect || force) {
+                       exynos_camera->effect = effect;
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EFFECT, effect);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+       }
+
+       // ISO
+       iso_string = exynos_param_string_get(exynos_camera, "iso");
+       if (iso_string != NULL) {
+               if (strcmp(iso_string, "auto") == 0)
+                       iso = ISO_AUTO;
+               else if (strcmp(iso_string, "ISO50") == 0)
+                       iso = ISO_50;
+               else if (strcmp(iso_string, "ISO100") == 0)
+                       iso = ISO_100;
+               else if (strcmp(iso_string, "ISO200") == 0)
+                       iso = ISO_200;
+               else if (strcmp(iso_string, "ISO400") == 0)
+                       iso = ISO_400;
+               else if (strcmp(iso_string, "ISO800") == 0)
+                       iso = ISO_800;
+               else
+                       iso = ISO_AUTO;
+
+               if (iso != exynos_camera->iso || force) {
+                       exynos_camera->iso = iso;
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_ISO, iso);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+       }
+
+       LOGD("%s: Preview size: %dx%d, picture size: %dx%d, recording size: %dx%d",
+               __func__, preview_width, preview_height, picture_width, picture_height,
+               recording_width, recording_height);
+
+       return 0;
+}
+
+// Picture
+
+int exynos_camera_picture(struct exynos_camera *exynos_camera)
+{
+       camera_memory_t *data_memory = NULL;
+       camera_memory_t *exif_data_memory = NULL;
+       camera_memory_t *picture_data_memory = NULL;
+       camera_memory_t *jpeg_thumbnail_data_memory = NULL;
+
+       int camera_picture_format;
+       int picture_width;
+       int picture_height;
+       int picture_format;
+
+       int jpeg_thumbnail_width;
+       int jpeg_thumbnail_height;
+       int jpeg_thumbnail_quality;
+       int jpeg_quality;
+
+       int data_size;
+
+       int offset = 0;
+       void *picture_addr = NULL;
+       int picture_size = 0;
+       void *jpeg_thumbnail_addr = NULL;
+       int jpeg_thumbnail_size = 0;
+
+       int jpeg_fd;
+       struct jpeg_enc_param jpeg_enc_params;
+       enum jpeg_frame_format jpeg_in_format;
+       enum jpeg_stream_format jpeg_out_format;
+       enum jpeg_ret_type jpeg_result;
+       void *jpeg_in_buffer;
+       int jpeg_in_size;
+       void *jpeg_out_buffer;
+       int jpeg_out_size;
+
+       exif_attribute_t exif_attributes;
+       int exif_size = 0;
+
+       int index;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       picture_width = exynos_camera->picture_width;
+       picture_height = exynos_camera->picture_height;
+       picture_format = exynos_camera->picture_format;
+       camera_picture_format = exynos_camera->camera_picture_format;
+       jpeg_thumbnail_width = exynos_camera->jpeg_thumbnail_width;
+       jpeg_thumbnail_height = exynos_camera->jpeg_thumbnail_height;
+       jpeg_thumbnail_quality = exynos_camera->jpeg_thumbnail_quality;
+       jpeg_quality = exynos_camera->jpeg_quality;
+
+       if (camera_picture_format == 0)
+               camera_picture_format = picture_format;
+
+       // V4L2
+
+       rc = exynos_v4l2_poll(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: poll failed!", __func__);
+               return -1;
+       } else if (rc == 0) {
+               LOGE("%s: poll timeout!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_streamoff_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: streamoff failed!", __func__);
+               return -1;
+       }
+
+       index = exynos_v4l2_dqbuf_cap(exynos_camera, 0);
+       if (index < 0) {
+               LOGE("%s: dqbuf failed!", __func__);
+               return -1;
+       }
+
+       // This assumes that the output format is JPEG
+
+       if (camera_picture_format == V4L2_PIX_FMT_JPEG) {
+               rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_MAIN_SIZE,
+                       &picture_size);
+               if (rc < 0) {
+                       LOGE("%s: g ctrl failed!", __func__);
+                       return -1;
+               }
+
+               rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_MAIN_OFFSET,
+                       &offset);
+               if (rc < 0) {
+                       LOGE("%s: g ctrl failed!", __func__);
+                       return -1;
+               }
+
+               picture_addr = (void *) ((int) exynos_camera->picture_memory->data + offset);
+
+               rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_THUMB_SIZE,
+                       &jpeg_thumbnail_size);
+               if (rc < 0) {
+                       LOGE("%s: g ctrl failed!", __func__);
+                       return -1;
+               }
+
+               rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_THUMB_OFFSET,
+                       &offset);
+               if (rc < 0) {
+                       LOGE("%s: g ctrl failed!", __func__);
+                       return -1;
+               }
+
+               jpeg_thumbnail_addr = (void *) ((int) exynos_camera->picture_memory->data + offset);
+       }
+
+       // Thumbnail
+
+       if (camera_picture_format == V4L2_PIX_FMT_JPEG && jpeg_thumbnail_addr != NULL && jpeg_thumbnail_size >= 0) {
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       jpeg_thumbnail_data_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       jpeg_thumbnail_size, 1, 0);
+                       if (jpeg_thumbnail_data_memory == NULL) {
+                               LOGE("%s: thumb memory request failed!", __func__);
+                               goto error;
+                       }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       goto error;
+               }
+
+               memcpy(jpeg_thumbnail_data_memory->data, jpeg_thumbnail_addr, jpeg_thumbnail_size);
+       } else {
+               jpeg_fd = api_jpeg_encode_init();
+               if (jpeg_fd < 0) {
+                       LOGE("%s: Failed to init JPEG", __func__);
+                       goto error;
+               }
+
+               switch (camera_picture_format) {
+                       case V4L2_PIX_FMT_RGB565:
+                               jpeg_in_format = RGB_565;
+                               jpeg_out_format = JPEG_420;
+                               jpeg_in_size = (picture_width * picture_height * 2);
+                               break;
+                       case V4L2_PIX_FMT_NV12:
+                       case V4L2_PIX_FMT_NV21:
+                       case V4L2_PIX_FMT_NV12T:
+                       case V4L2_PIX_FMT_YUV420:
+                               jpeg_in_format = YUV_420;
+                               jpeg_out_format = JPEG_420;
+                               jpeg_in_size = (picture_width * picture_height * 1.5);
+                               break;
+                       case V4L2_PIX_FMT_YUYV:
+                       case V4L2_PIX_FMT_UYVY:
+                       case V4L2_PIX_FMT_YUV422P:
+                       default:
+                               jpeg_in_format = YUV_422;
+                               jpeg_out_format = JPEG_422;
+                               jpeg_in_size = (picture_width * picture_height * 2);
+                               break;
+               }
+
+               memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params));
+
+               jpeg_enc_params.width = jpeg_thumbnail_width;
+               jpeg_enc_params.height = jpeg_thumbnail_height;
+               jpeg_enc_params.in_fmt = jpeg_in_format;
+               jpeg_enc_params.out_fmt = jpeg_out_format;
+
+               if (jpeg_thumbnail_quality >= 90)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_1;
+               else if (jpeg_thumbnail_quality >= 80)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_2;
+               else if (jpeg_thumbnail_quality >= 70)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_3;
+               else
+                       jpeg_enc_params.quality = QUALITY_LEVEL_4;
+
+               api_jpeg_set_encode_param(&jpeg_enc_params);
+
+               jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size);
+               if (jpeg_in_buffer == NULL) {
+                       LOGE("%s: Failed to get JPEG in buffer", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd);
+               if (jpeg_out_buffer == NULL) {
+                       LOGE("%s: Failed to get JPEG out buffer", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               memcpy(jpeg_in_buffer, exynos_camera->picture_memory->data, jpeg_in_size);
+
+               jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params);
+               if (jpeg_result != JPEG_ENCODE_OK) {
+                       LOGE("%s: Failed to encode JPEG", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               jpeg_out_size = jpeg_enc_params.size;
+               if (jpeg_out_size <= 0) {
+                       LOGE("%s: Failed to get JPEG out size", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       jpeg_thumbnail_data_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       jpeg_out_size, 1, 0);
+                       if (jpeg_thumbnail_data_memory == NULL) {
+                               LOGE("%s: thumbnail memory request failed!", __func__);
+                               api_jpeg_encode_deinit(jpeg_fd);
+                               goto error;
+                       }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               memcpy(jpeg_thumbnail_data_memory->data, jpeg_out_buffer, jpeg_out_size);
+               jpeg_thumbnail_size = jpeg_out_size;
+
+               api_jpeg_encode_deinit(jpeg_fd);
+       }
+
+       // Picture
+
+       if (camera_picture_format == V4L2_PIX_FMT_JPEG && picture_addr != NULL && picture_size >= 0) {
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       picture_data_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       picture_size, 1, 0);
+                       if (picture_data_memory == NULL) {
+                               LOGE("%s: picture memory request failed!", __func__);
+                               goto error;
+                       }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       goto error;
+               }
+
+               memcpy(picture_data_memory->data, picture_addr, picture_size);
+       } else {
+               jpeg_fd = api_jpeg_encode_init();
+               if (jpeg_fd < 0) {
+                       LOGE("%s: Failed to init JPEG", __func__);
+                       goto error;
+               }
+
+               switch (camera_picture_format) {
+                       case V4L2_PIX_FMT_RGB565:
+                               jpeg_in_format = RGB_565;
+                               jpeg_out_format = JPEG_420;
+                               jpeg_in_size = (picture_width * picture_height * 2);
+                               break;
+                       case V4L2_PIX_FMT_NV12:
+                       case V4L2_PIX_FMT_NV21:
+                       case V4L2_PIX_FMT_NV12T:
+                       case V4L2_PIX_FMT_YUV420:
+                               jpeg_in_format = YUV_420;
+                               jpeg_out_format = JPEG_420;
+                               jpeg_in_size = (picture_width * picture_height * 1.5);
+                               break;
+                       case V4L2_PIX_FMT_YUYV:
+                       case V4L2_PIX_FMT_UYVY:
+                       case V4L2_PIX_FMT_YUV422P:
+                       default:
+                               jpeg_in_format = YUV_422;
+                               jpeg_out_format = JPEG_422;
+                               jpeg_in_size = (picture_width * picture_height * 2);
+                               break;
+               }
+
+               memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params));
+
+               jpeg_enc_params.width = picture_width;
+               jpeg_enc_params.height = picture_height;
+               jpeg_enc_params.in_fmt = jpeg_in_format;
+               jpeg_enc_params.out_fmt = jpeg_out_format;
+
+               if (jpeg_quality >= 90)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_1;
+               else if (jpeg_quality >= 80)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_2;
+               else if (jpeg_quality >= 70)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_3;
+               else
+                       jpeg_enc_params.quality = QUALITY_LEVEL_4;
+
+               api_jpeg_set_encode_param(&jpeg_enc_params);
+
+               jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size);
+               if (jpeg_in_buffer == NULL) {
+                       LOGE("%s: Failed to get JPEG in buffer", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd);
+               if (jpeg_out_buffer == NULL) {
+                       LOGE("%s: Failed to get JPEG out buffer", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               memcpy(jpeg_in_buffer, exynos_camera->picture_memory->data, jpeg_in_size);
+
+               jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params);
+               if (jpeg_result != JPEG_ENCODE_OK) {
+                       LOGE("%s: Failed to encode JPEG", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               jpeg_out_size = jpeg_enc_params.size;
+               if (jpeg_out_size <= 0) {
+                       LOGE("%s: Failed to get JPEG out size", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       picture_data_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       jpeg_out_size, 1, 0);
+                       if (picture_data_memory == NULL) {
+                               LOGE("%s: picture memory request failed!", __func__);
+                               api_jpeg_encode_deinit(jpeg_fd);
+                               goto error;
+                       }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
+
+               memcpy(picture_data_memory->data, jpeg_out_buffer, jpeg_out_size);
+               picture_size = jpeg_out_size;
+
+               api_jpeg_encode_deinit(jpeg_fd);
+       }
+
+       // EXIF
+
+       memset(&exif_attributes, 0, sizeof(exif_attributes));
+       exynos_exif_attributes_create_static(exynos_camera, &exif_attributes);
+       exynos_exif_attributes_create_params(exynos_camera, &exif_attributes);
+
+       rc = exynos_exif_create(exynos_camera, &exif_attributes,
+               jpeg_thumbnail_data_memory, jpeg_thumbnail_size,
+               &exif_data_memory, &exif_size);
+       if (rc < 0 || exif_data_memory == NULL || exif_size <= 0) {
+               LOGE("%s: EXIF create failed!", __func__);
+               goto error;
+       }
+
+       data_size = exif_size + picture_size;
+
+       if (exynos_camera->callbacks.request_memory != NULL) {
+               data_memory =
+                       exynos_camera->callbacks.request_memory(-1,
+                               data_size, 1, 0);
+               if (data_memory == NULL) {
+                       LOGE("%s: data memory request failed!", __func__);
+                       goto error;
+               }
+       } else {
+               LOGE("%s: No memory request function!", __func__);
+               goto error;
+       }
+
+       // Copy the first two bytes of the JPEG picture
+       memcpy(data_memory->data, picture_data_memory->data, 2);
+
+       // Copy the EXIF data
+       memcpy((void *) ((int) data_memory->data + 2), exif_data_memory->data,
+               exif_size);
+
+       // Copy the JPEG picture
+       memcpy((void *) ((int) data_memory->data + 2 + exif_size),
+               (void *) ((int) picture_data_memory->data + 2), picture_size - 2);
+
+       // Callbacks
+
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_SHUTTER) && EXYNOS_CAMERA_CALLBACK_DEFINED(notify))
+               exynos_camera->callbacks.notify(CAMERA_MSG_SHUTTER, 0, 0,
+                       exynos_camera->callbacks.user);
+
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_RAW_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data) &&
+               jpeg_thumbnail_data_memory != NULL)
+               exynos_camera->callbacks.data(CAMERA_MSG_RAW_IMAGE,
+                       jpeg_thumbnail_data_memory, 0, NULL, exynos_camera->callbacks.user);
+
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_COMPRESSED_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data) &&
+               data_memory != NULL)
+               exynos_camera->callbacks.data(CAMERA_MSG_COMPRESSED_IMAGE,
+                       data_memory, 0, NULL, exynos_camera->callbacks.user);
+
+       // Release memory
+
+       if (jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_data_memory->release != NULL)
+               jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory);
+
+       if (picture_data_memory != NULL && picture_data_memory->release != NULL)
+               picture_data_memory->release(picture_data_memory);
+
+       if (exif_data_memory != NULL && exif_data_memory->release != NULL)
+               exif_data_memory->release(exif_data_memory);
+
+       if (data_memory != NULL && data_memory->release != NULL)
+               data_memory->release(data_memory);
+
+       return 0;
+
+error:
+       if (jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_data_memory->release != NULL)
+               jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory);
+
+       if (picture_data_memory != NULL && picture_data_memory->release != NULL)
+               picture_data_memory->release(picture_data_memory);
+
+       if (exif_data_memory != NULL && exif_data_memory->release != NULL)
+               exif_data_memory->release(exif_data_memory);
+
+       if (data_memory != NULL && data_memory->release != NULL)
+               data_memory->release(data_memory);
+
+       return -1;
+}
+
+void *exynos_camera_picture_thread(void *data)
+{
+       struct exynos_camera *exynos_camera;
+       int rc;
+       int i;
+
+       if (data == NULL)
+               return NULL;
+
+       exynos_camera = (struct exynos_camera *) data;
+
+       LOGE("%s: Starting thread", __func__);
+       exynos_camera->picture_thread_running = 1;
+
+       if (exynos_camera->picture_enabled == 1) {
+               pthread_mutex_lock(&exynos_camera->picture_mutex);
+
+               rc = exynos_camera_picture(exynos_camera);
+               if (rc < 0) {
+                       LOGE("%s: picture failed!", __func__);
+                       exynos_camera->picture_enabled = 0;
+               }
+
+               if (exynos_camera->picture_memory != NULL && exynos_camera->picture_memory->release != NULL) {
+                       exynos_camera->picture_memory->release(exynos_camera->picture_memory);
+                       exynos_camera->picture_memory = NULL;
+               }
+
+               pthread_mutex_unlock(&exynos_camera->picture_mutex);
+       }
+
+       exynos_camera->picture_thread_running = 0;
+       exynos_camera->picture_enabled = 0;
+
+       LOGE("%s: Exiting thread", __func__);
+
+       return NULL;
+}
+
+int exynos_camera_picture_start(struct exynos_camera *exynos_camera)
+{
+       pthread_attr_t thread_attr;
+
+       int width, height, format, camera_format;
+
+       int fd;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       // Stop preview thread
+       exynos_camera_preview_stop(exynos_camera);
+
+       width = exynos_camera->picture_width;
+       height = exynos_camera->picture_height;
+       format = exynos_camera->picture_format;
+       camera_format = exynos_camera->camera_picture_format;
+
+       // V4L2
+
+       if (camera_format == 0)
+               camera_format = format;
+
+       rc = exynos_v4l2_enum_fmt_cap(exynos_camera, 0, camera_format);
+       if (rc < 0) {
+               LOGE("%s: enum fmt failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 0, width, height, camera_format, V4L2_PIX_FMT_MODE_CAPTURE);
+       if (rc < 0) {
+               LOGE("%s: s fmt failed!", __func__);
+               return -1;
+       }
+
+       // Only use 1 buffer
+       rc = exynos_v4l2_reqbufs_cap(exynos_camera, 0, 1);
+       if (rc < 0) {
+               LOGE("%s: reqbufs failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_querybuf_cap(exynos_camera, 0, 0);
+       if (rc < 0) {
+               LOGE("%s: querybuf failed!", __func__);
+               return -1;
+       }
+
+       exynos_camera->picture_buffer_length = rc;
+
+       if (exynos_camera->callbacks.request_memory != NULL) {
+               fd = exynos_v4l2_find_fd(exynos_camera, 0);
+               if (fd < 0) {
+                       LOGE("%s: Unable to find v4l2 fd", __func__);
+                       return -1;
+               }
+
+               if (exynos_camera->picture_memory != NULL && exynos_camera->picture_memory->release != NULL)
+                       exynos_camera->picture_memory->release(exynos_camera->picture_memory);
+
+               exynos_camera->picture_memory =
+                       exynos_camera->callbacks.request_memory(fd,
+                               exynos_camera->picture_buffer_length, 1, 0);
+               if (exynos_camera->picture_memory == NULL) {
+                       LOGE("%s: memory request failed!", __func__);
+                       return -1;
+               }
+       } else {
+               LOGE("%s: No memory request function!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, 0);
+       if (rc < 0) {
+               LOGE("%s: qbuf failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_streamon_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: streamon failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_CAPTURE, 0);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       // Thread
+
+       if (exynos_camera->picture_thread_running) {
+               LOGE("Picture thread is already running!");
+               return -1;
+       }
+
+       pthread_mutex_init(&exynos_camera->picture_mutex, NULL);
+
+       pthread_attr_init(&thread_attr);
+       pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+
+       exynos_camera->picture_enabled = 1;
+
+       rc = pthread_create(&exynos_camera->picture_thread, &thread_attr,
+               exynos_camera_picture_thread, (void *) exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to create thread", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+void exynos_camera_picture_stop(struct exynos_camera *exynos_camera)
+{
+       int rc;
+       int i;
+
+       if (exynos_camera == NULL)
+               return;
+
+       if (!exynos_camera->picture_enabled) {
+               LOGE("Picture was already stopped!");
+               return;
+       }
+
+       pthread_mutex_lock(&exynos_camera->picture_mutex);
+
+       // Disable picture to make the thread end
+       exynos_camera->picture_enabled = 0;
+
+       pthread_mutex_unlock(&exynos_camera->picture_mutex);
+
+       // Wait for the thread to end
+       for (i=0 ; i < 10 ; i++) {
+               if (!exynos_camera->picture_thread_running)
+                       break;
+
+               usleep(500);
+       }
+
+       pthread_mutex_destroy(&exynos_camera->picture_mutex);
+}
+
+// Auto-focus
+
+void *exynos_camera_auto_focus_thread(void *data)
+{
+       struct exynos_camera *exynos_camera;
+       int auto_focus_status = -1;
+       int auto_focus_result = 0;
+       int rc;
+       int i;
+
+       if (data == NULL)
+               return NULL;
+
+       exynos_camera = (struct exynos_camera *) data;
+
+       LOGE("%s: Starting thread", __func__);
+       exynos_camera->auto_focus_thread_running = 1;
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_ON);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               auto_focus_result = 0;
+               goto thread_exit;
+       }
+
+       while (exynos_camera->auto_focus_enabled == 1) {
+               pthread_mutex_lock(&exynos_camera->auto_focus_mutex);
+
+               rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_AUTO_FOCUS_RESULT, &auto_focus_status);
+               if (rc < 0) {
+                       LOGE("%s: g ctrl failed!", __func__);
+                       auto_focus_result = 0;
+                       pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+                       goto thread_exit;
+               }
+
+               switch (auto_focus_status) {
+                       case CAMERA_AF_STATUS_IN_PROGRESS:
+                               usleep(500);
+                               break;
+                       case CAMERA_AF_STATUS_SUCCESS:
+                       case CAMERA_AF_STATUS_1ST_SUCCESS:
+                               auto_focus_result = 1;
+                               pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+                               goto thread_exit;
+                       case CAMERA_AF_STATUS_FAIL:
+                       default:
+                               auto_focus_result = 0;
+                               pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+                               goto thread_exit;                               
+               }
+
+               pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+       }
+
+thread_exit:
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, AUTO_FOCUS_OFF);
+       if (rc < 0)
+               LOGE("%s: s ctrl failed!", __func__);
+
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_FOCUS) && EXYNOS_CAMERA_CALLBACK_DEFINED(notify))
+               exynos_camera->callbacks.notify(CAMERA_MSG_FOCUS,
+                       (int32_t) auto_focus_result, 0, exynos_camera->callbacks.user);
+               
+       exynos_camera->auto_focus_thread_running = 0;
+       exynos_camera->auto_focus_enabled = 0;
+
+       LOGE("%s: Exiting thread", __func__);
+
+       return NULL;
+}
+
+int exynos_camera_auto_focus_start(struct exynos_camera *exynos_camera)
+{
+       pthread_attr_t thread_attr;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       // Thread
+
+       if (exynos_camera->auto_focus_thread_running) {
+               LOGE("Auto-focus thread is already running!");
+               return -1;
+       }
+
+       pthread_mutex_init(&exynos_camera->auto_focus_mutex, NULL);
+
+       pthread_attr_init(&thread_attr);
+       pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+
+       exynos_camera->auto_focus_enabled = 1;
+
+       rc = pthread_create(&exynos_camera->auto_focus_thread, &thread_attr,
+               exynos_camera_auto_focus_thread, (void *) exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to create thread", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+void exynos_camera_auto_focus_stop(struct exynos_camera *exynos_camera)
+{
+       int rc;
+       int i;
+
+       if (exynos_camera == NULL)
+               return;
+
+       if (!exynos_camera->auto_focus_enabled) {
+               LOGE("Auto-focus was already stopped!");
+               return;
+       }
+
+       pthread_mutex_lock(&exynos_camera->auto_focus_mutex);
+
+       // Disable auto-focus to make the thread end
+       exynos_camera->auto_focus_enabled = 0;
+
+       pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+
+       // Wait for the thread to end
+       for (i=0 ; i < 10 ; i++) {
+               if (!exynos_camera->auto_focus_thread_running)
+                       break;
+
+               usleep(500);
+       }
+
+       pthread_mutex_destroy(&exynos_camera->auto_focus_mutex);
+}
+
+// Preview
+
+int exynos_camera_preview(struct exynos_camera *exynos_camera)
+{
+       buffer_handle_t *buffer;
+       int stride;
+
+       int width, height;
+       float format_bpp;
+
+       char *preview_format_string;
+       int frame_size, offset;
+       void *preview_data;
+       void *window_data;
+
+       unsigned int recording_y_addr;
+       unsigned int recording_cbcr_addr;
+       nsecs_t timestamp;
+       struct exynos_camera_addrs *addrs;
+       struct timespec ts;
+
+       int index;
+       int rc;
+       int i;
+
+       if (exynos_camera == NULL || exynos_camera->preview_memory == NULL ||
+               exynos_camera->preview_window == NULL)
+               return -EINVAL;
+
+       timestamp = systemTime(1);
+
+       // V4L2
+
+       rc = exynos_v4l2_poll(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: poll failed!", __func__);
+               return -1;
+       } else if (rc == 0) {
+               LOGE("%s: poll timeout!", __func__);
+               return -1;
+       }
+
+       index = exynos_v4l2_dqbuf_cap(exynos_camera, 0);
+       if (index < 0 || index >= exynos_camera->preview_buffers_count) {
+               LOGE("%s: dqbuf failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, index);
+       if (rc < 0) {
+               LOGE("%s: qbuf failed!", __func__);
+               return -1;
+       }
+
+       // Preview window
+
+       width = exynos_camera->preview_width;
+       height = exynos_camera->preview_height;
+       format_bpp = exynos_camera->preview_format_bpp;
+
+       exynos_camera->preview_window->dequeue_buffer(exynos_camera->preview_window,
+               &buffer, &stride);
+       exynos_camera->gralloc->lock(exynos_camera->gralloc, *buffer, GRALLOC_USAGE_SW_WRITE_OFTEN,
+               0, 0, width, height, &window_data);
+
+       if (window_data == NULL) {
+               LOGE("%s: gralloc lock failed!", __func__);
+               return -1;
+       }
+
+       frame_size = (int) ((float) width * (float) height * format_bpp);
+       offset = index * frame_size;
+
+       preview_data = (void *) ((int) exynos_camera->preview_memory->data + offset);
+       memcpy(window_data, preview_data, frame_size);
+
+       exynos_camera->gralloc->unlock(exynos_camera->gralloc, *buffer);
+       exynos_camera->preview_window->enqueue_buffer(exynos_camera->preview_window,
+               buffer);
+
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_PREVIEW_FRAME) && EXYNOS_CAMERA_CALLBACK_DEFINED(data)) {
+               exynos_camera->callbacks.data(CAMERA_MSG_PREVIEW_FRAME,
+                       exynos_camera->preview_memory, index, NULL, exynos_camera->callbacks.user);
+       }
+
+       // Recording
+
+       if (exynos_camera->recording_enabled && exynos_camera->recording_memory != NULL) {
+               pthread_mutex_lock(&exynos_camera->recording_mutex);
+
+               // V4L2
+
+               rc = exynos_v4l2_poll(exynos_camera, 2);
+               if (rc < 0) {
+                       LOGE("%s: poll failed!", __func__);
+                       goto error_recording;
+               } else if (rc == 0) {
+                       LOGE("%s: poll timeout!", __func__);
+                       goto error_recording;
+               }
+
+               index = exynos_v4l2_dqbuf_cap(exynos_camera, 2);
+               if (index < 0) {
+                       LOGE("%s: dqbuf failed!", __func__);
+                       goto error_recording;
+               }
+
+               recording_y_addr = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_PADDR_Y, index);
+               if (recording_y_addr == 0xffffffff) {
+                       LOGE("%s: s ctrl failed!", __func__);
+                       goto error_recording;
+               }
+
+               recording_cbcr_addr = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_PADDR_CBCR, index);
+               if (recording_cbcr_addr == 0xffffffff) {
+                       LOGE("%s: s ctrl failed!", __func__);
+                       goto error_recording;
+               }
+
+               addrs = (struct exynos_camera_addrs *) exynos_camera->recording_memory->data;
+
+               addrs[index].type = 0; // kMetadataBufferTypeCameraSource
+               addrs[index].y = recording_y_addr;
+               addrs[index].cbcr = recording_cbcr_addr;
+               addrs[index].index = index;
+               addrs[index].reserved = 0;
+
+               pthread_mutex_unlock(&exynos_camera->recording_mutex);
+
+               if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_VIDEO_FRAME) && EXYNOS_CAMERA_CALLBACK_DEFINED(data_timestamp)) {
+                       exynos_camera->callbacks.data_timestamp(timestamp, CAMERA_MSG_VIDEO_FRAME,
+                               exynos_camera->recording_memory, index, exynos_camera->callbacks.user);
+               } else {
+                       rc = exynos_v4l2_qbuf_cap(exynos_camera, 2, index);
+                       if (rc < 0) {
+                               LOGE("%s: qbuf failed!", __func__);
+                               return -1;
+                       }
+               }
+       }
+
+       return 0;
+
+error_recording:
+       pthread_mutex_lock(&exynos_camera->recording_mutex);
+
+       return -1;
+}
+
+void *exynos_camera_preview_thread(void *data)
+{
+       struct exynos_camera *exynos_camera;
+       int rc;
+
+       if (data == NULL)
+               return NULL;
+
+       exynos_camera = (struct exynos_camera *) data;
+
+       LOGE("%s: Starting thread", __func__);
+       exynos_camera->preview_thread_running = 1;
+
+       if (exynos_camera->preview_window == NULL) {
+               // Lock preview lock mutex
+               pthread_mutex_lock(&exynos_camera->preview_lock_mutex);
+       }
+
+       while (exynos_camera->preview_enabled == 1) {
+               pthread_mutex_lock(&exynos_camera->preview_mutex);
+
+               rc = exynos_camera_preview(exynos_camera);
+               if (rc < 0) {
+                       LOGE("%s: preview failed!", __func__);
+                       exynos_camera->preview_enabled = 0;
+               }
+
+               pthread_mutex_unlock(&exynos_camera->preview_mutex);
+       }
+
+       exynos_camera->preview_thread_running = 0;
+       LOGE("%s: Exiting thread", __func__);
+
+       return NULL;
+}
+
+int exynos_camera_preview_start(struct exynos_camera *exynos_camera)
+{
+       struct v4l2_streamparm streamparm;
+       int width, height, format;
+       float format_bpp;
+       int fps, frame_size;
+       int fd;
+
+       pthread_attr_t thread_attr;
+
+       int rc;
+       int i;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       if (exynos_camera->preview_enabled) {
+               LOGE("Preview was already started!");
+               return 0;
+       }
+
+       // V4L2
+
+       format = exynos_camera->preview_format;
+
+       rc = exynos_v4l2_enum_fmt_cap(exynos_camera, 0, format);
+       if (rc < 0) {
+               LOGE("%s: enum fmt failed!", __func__);
+               return -1;
+       }
+
+       width = exynos_camera->preview_width;
+       height = exynos_camera->preview_height;
+       format_bpp = exynos_camera->preview_format_bpp;
+
+       rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 0, width, height, format, V4L2_PIX_FMT_MODE_PREVIEW);
+       if (rc < 0) {
+               LOGE("%s: s fmt failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CACHEABLE, 1);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       for (i=EXYNOS_CAMERA_MAX_BUFFERS_COUNT ; i >= EXYNOS_CAMERA_MIN_BUFFERS_COUNT ; i--) {
+               rc = exynos_v4l2_reqbufs_cap(exynos_camera, 0, i);
+               if (rc >= 0)
+                       break;
+       }
+
+       if (rc < 0) {
+               LOGE("%s: reqbufs failed!", __func__);
+               return -1;
+       }
+
+       exynos_camera->preview_buffers_count = rc;
+       LOGD("Found %d preview buffers available!", exynos_camera->preview_buffers_count);
+
+       fps = exynos_camera->preview_fps;
+       memset(&streamparm, 0, sizeof(streamparm));
+       streamparm.parm.capture.timeperframe.numerator = 1;
+       streamparm.parm.capture.timeperframe.denominator = fps;
+
+       rc = exynos_v4l2_s_parm_cap(exynos_camera, 0, &streamparm);
+       if (rc < 0) {
+               LOGE("%s: s parm failed!", __func__);
+               return -1;
+       }
+
+       frame_size = (int) ((float) width * (float) height * format_bpp);
+       for (i=0 ; i < exynos_camera->preview_buffers_count ; i++) {
+               rc = exynos_v4l2_querybuf_cap(exynos_camera, 0, i);
+               if (rc < 0) {
+                       LOGE("%s: querybuf failed!", __func__);
+                       return -1;
+               }
+
+               if (rc != frame_size)
+                       LOGE("%s: Frame size mismatch: %d/%d", __func__, frame_size, rc);
+       }
+
+       if (exynos_camera->callbacks.request_memory != NULL) {
+               fd = exynos_v4l2_find_fd(exynos_camera, 0);
+               if (fd < 0) {
+                       LOGE("%s: Unable to find v4l2 fd", __func__);
+                       return -1;
+               }
+
+               if (exynos_camera->preview_memory != NULL && exynos_camera->preview_memory->release != NULL)
+                       exynos_camera->preview_memory->release(exynos_camera->preview_memory);
+
+               exynos_camera->preview_memory =
+                       exynos_camera->callbacks.request_memory(fd,
+                               frame_size, exynos_camera->preview_buffers_count, 0);
+               if (exynos_camera->preview_memory == NULL) {
+                       LOGE("%s: memory request failed!", __func__);
+                       return -1;
+               }
+       } else {
+               LOGE("%s: No memory request function!", __func__);
+               return -1;
+       }
+
+       for (i=0 ; i < exynos_camera->preview_buffers_count ; i++) {
+               rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, i);
+               if (rc < 0) {
+                       LOGE("%s: qbuf failed!", __func__);
+                       return -1;
+               }
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_ROTATION,
+               exynos_camera->camera_rotation);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_HFLIP,
+               exynos_camera->camera_hflip);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_VFLIP,
+               exynos_camera->camera_vflip);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_streamon_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: streamon failed!", __func__);
+               return -1;
+       }
+
+       // Thread
+
+       pthread_mutex_init(&exynos_camera->preview_mutex, NULL);
+       pthread_mutex_init(&exynos_camera->preview_lock_mutex, NULL);
+
+       // Lock preview lock
+       pthread_mutex_lock(&exynos_camera->preview_lock_mutex);
+
+       pthread_attr_init(&thread_attr);
+       pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+
+       exynos_camera->preview_enabled = 1;
+
+       rc = pthread_create(&exynos_camera->preview_thread, &thread_attr,
+               exynos_camera_preview_thread, (void *) exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to create thread", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+void exynos_camera_preview_stop(struct exynos_camera *exynos_camera)
+{
+       int rc;
+       int i;
+
+       if (exynos_camera == NULL)
+               return;
+
+       if (!exynos_camera->preview_enabled) {
+               LOGE("Preview was already stopped!");
+               return;
+       }
+
+       exynos_camera->preview_enabled = 0;
+
+       // Unlock preview lock
+       pthread_mutex_unlock(&exynos_camera->preview_lock_mutex);
+
+       pthread_mutex_lock(&exynos_camera->preview_mutex);
+
+       // Wait for the thread to end
+       for (i=0 ; i < 10 ; i++) {
+               if (!exynos_camera->preview_thread_running)
+                       break;
+
+               usleep(1000);
+       }
+
+       rc = exynos_v4l2_streamoff_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: streamoff failed!", __func__);
+       }
+
+       exynos_camera->preview_params_set = 0;
+
+       if (exynos_camera->preview_memory != NULL && exynos_camera->preview_memory->release != NULL) {
+               exynos_camera->preview_memory->release(exynos_camera->preview_memory);
+               exynos_camera->preview_memory = NULL;
+       }
+
+       exynos_camera->preview_window = NULL;
+
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+
+       pthread_mutex_destroy(&exynos_camera->preview_lock_mutex);
+       pthread_mutex_destroy(&exynos_camera->preview_mutex);
+}
+
+// Recording
+
+void exynos_camera_recording_frame_release(struct exynos_camera *exynos_camera, void *data)
+{
+       struct exynos_camera_addrs *addrs;
+       int rc;
+
+       if (exynos_camera == NULL || data == NULL)
+               return;
+
+       addrs = (struct exynos_camera_addrs *) data;
+       if (addrs->index >= (unsigned int) exynos_camera->recording_buffers_count)
+               return;
+
+       pthread_mutex_lock(&exynos_camera->recording_mutex);
+
+       rc = exynos_v4l2_qbuf_cap(exynos_camera, 2, addrs->index);
+       if (rc < 0) {
+               LOGE("%s: qbuf failed!", __func__);
+               goto error;
+       }
+
+error:
+       pthread_mutex_unlock(&exynos_camera->recording_mutex);
+}
+
+int exynos_camera_recording_start(struct exynos_camera *exynos_camera)
+{
+       int width, height, format;
+       int fd;
+
+       int rc;
+       int i;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       if (exynos_camera->recording_enabled) {
+               LOGE("Recording was already started!");
+               return 0;
+       }
+
+       pthread_mutex_lock(&exynos_camera->preview_mutex);
+
+       // V4L2
+
+       format = exynos_camera->recording_format;
+
+       rc = exynos_v4l2_enum_fmt_cap(exynos_camera, 2, format);
+       if (rc < 0) {
+               LOGE("%s: enum fmt failed!", __func__);
+               goto error;
+       }
+
+       width = exynos_camera->recording_width;
+       height = exynos_camera->recording_height;
+
+       rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 2, width, height, format, V4L2_PIX_FMT_MODE_CAPTURE);
+       if (rc < 0) {
+               LOGE("%s: s fmt failed!", __func__);
+               goto error;
+       }
+
+       for (i=EXYNOS_CAMERA_MAX_BUFFERS_COUNT ; i >= EXYNOS_CAMERA_MIN_BUFFERS_COUNT ; i--) {
+               rc = exynos_v4l2_reqbufs_cap(exynos_camera, 2, i);
+               if (rc >= 0)
+                       break;
+       }
+
+       if (rc < 0) {
+               LOGE("%s: reqbufs failed!", __func__);
+               goto error;
+       }
+
+       exynos_camera->recording_buffers_count = rc;
+       LOGD("Found %d recording buffers available!", exynos_camera->recording_buffers_count);
+
+       for (i=0 ; i < exynos_camera->recording_buffers_count ; i++) {
+               rc = exynos_v4l2_querybuf_cap(exynos_camera, 2, i);
+               if (rc < 0) {
+                       LOGE("%s: querybuf failed!", __func__);
+                       goto error;
+               }
+       }
+
+       if (exynos_camera->callbacks.request_memory != NULL) {
+               if (exynos_camera->recording_memory != NULL && exynos_camera->recording_memory->release != NULL)
+                       exynos_camera->recording_memory->release(exynos_camera->recording_memory);
+
+               exynos_camera->recording_memory =
+                       exynos_camera->callbacks.request_memory(-1, sizeof(struct exynos_camera_addrs),
+                               exynos_camera->recording_buffers_count, 0);
+               if (exynos_camera->recording_memory == NULL) {
+                       LOGE("%s: memory request failed!", __func__);
+                       goto error;
+               }
+       } else {
+               LOGE("%s: No memory request function!", __func__);
+               goto error;
+       }
+
+       for (i=0 ; i < exynos_camera->recording_buffers_count ; i++) {
+               rc = exynos_v4l2_qbuf_cap(exynos_camera, 2, i);
+               if (rc < 0) {
+                       LOGE("%s: qbuf failed!", __func__);
+                       goto error;
+               }
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_ROTATION,
+               exynos_camera->camera_rotation);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               goto error;
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_HFLIP,
+               exynos_camera->camera_hflip);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               goto error;
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 2, V4L2_CID_VFLIP,
+               exynos_camera->camera_vflip);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               goto error;
+       }
+
+       rc = exynos_v4l2_streamon_cap(exynos_camera, 2);
+       if (rc < 0) {
+               LOGE("%s: streamon failed!", __func__);
+               goto error;
+       }
+
+       pthread_mutex_init(&exynos_camera->recording_mutex, NULL);
+
+       exynos_camera->recording_enabled = 1;
+
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+
+       return 0;
+error:
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+
+       return -1;
+}
+
+void exynos_camera_recording_stop(struct exynos_camera *exynos_camera)
+{
+       int rc;
+
+       if (exynos_camera == NULL)
+               return;
+
+       if (!exynos_camera->recording_enabled) {
+               LOGE("Recording was already stopped!");
+               return;
+       }
+
+       exynos_camera->recording_enabled = 0;
+
+       pthread_mutex_lock(&exynos_camera->preview_mutex);
+
+       rc = exynos_v4l2_streamoff_cap(exynos_camera, 2);
+       if (rc < 0) {
+               LOGE("%s: streamoff failed!", __func__);
+       }
+
+       if (exynos_camera->recording_memory != NULL && exynos_camera->recording_memory->release != NULL) {
+               exynos_camera->recording_memory->release(exynos_camera->recording_memory);
+               exynos_camera->recording_memory = NULL;
+       }
+
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+
+       pthread_mutex_destroy(&exynos_camera->recording_mutex);
+}
+
+/*
+ * Exynos Camera OPS
+ */
+
+int exynos_camera_set_preview_window(struct camera_device *dev,
+       struct preview_stream_ops *w)
+{
+       struct exynos_camera *exynos_camera;
+
+       int width, height, format, hal_format;
+
+       buffer_handle_t *buffer;
+       int stride;
+       void *addr = NULL;
+
+       int rc;
+
+       LOGD("%s(%p, %p)", __func__, dev, w);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       if (w == NULL)
+               return 0;
+
+       exynos_camera->preview_window = w;
+
+       if (w->set_buffer_count == NULL || w->set_usage == NULL || w->set_buffers_geometry == NULL)
+               return -EINVAL;
+
+       if (exynos_camera->preview_buffers_count <= 0) {
+               LOGE("%s: Invalid preview buffers count", __func__);
+               exynos_camera->preview_buffers_count = EXYNOS_CAMERA_MAX_BUFFERS_COUNT;
+       }
+
+       rc = w->set_buffer_count(w, exynos_camera->preview_buffers_count);
+       if (rc) {
+               LOGE("%s: Unable to set buffer count (%d)", __func__,
+                       exynos_camera->preview_buffers_count);
+               return -1;
+       }
+
+       rc = w->set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN);
+       if (rc) {
+               LOGE("%s: Unable to set usage", __func__);
+               return -1;
+       }
+
+       width = exynos_camera->preview_width;
+       height = exynos_camera->preview_height;
+       format = exynos_camera->preview_format;
+
+       switch (format) {
+               case V4L2_PIX_FMT_NV21:
+                       hal_format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+                       break;
+               case V4L2_PIX_FMT_YUV420:
+                       hal_format = HAL_PIXEL_FORMAT_YV12;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+                       hal_format = HAL_PIXEL_FORMAT_RGB_565;
+                       break;
+               case V4L2_PIX_FMT_RGB32:
+                       hal_format = HAL_PIXEL_FORMAT_RGBX_8888;
+                       break;
+               default:
+                       hal_format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+                       break;
+       }
+
+       rc = w->set_buffers_geometry(w, width, height, hal_format);
+       if (rc) {
+               LOGE("%s: Unable to set buffers geometry", __func__);
+               return -1;
+       }
+
+       // Unlock preview lock
+       pthread_mutex_unlock(&exynos_camera->preview_lock_mutex);
+
+       return 0;
+}
+
+void exynos_camera_set_callbacks(struct camera_device *dev,
+       camera_notify_callback notify_cb,
+       camera_data_callback data_cb,
+       camera_data_timestamp_callback data_cb_timestamp,
+       camera_request_memory get_memory,
+       void *user)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %p)", __func__, dev, user);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera->callbacks.notify = notify_cb;
+       exynos_camera->callbacks.data = data_cb;
+       exynos_camera->callbacks.data_timestamp = data_cb_timestamp;
+       exynos_camera->callbacks.request_memory = get_memory;
+       exynos_camera->callbacks.user = user;
+}
+
+void exynos_camera_enable_msg_type(struct camera_device *dev, int32_t msg_type)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera->messages_enabled |= msg_type;
+}
+
+void exynos_camera_disable_msg_type(struct camera_device *dev, int32_t msg_type)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera->messages_enabled &= ~msg_type;
+}
+
+int exynos_camera_msg_type_enabled(struct camera_device *dev, int32_t msg_type)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera->messages_enabled & msg_type;
+}
+
+int exynos_camera_start_preview(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera_preview_start(exynos_camera);
+}
+
+void exynos_camera_stop_preview(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera_preview_stop(exynos_camera);
+}
+
+int exynos_camera_preview_enabled(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera->preview_enabled;
+}
+
+int exynos_camera_store_meta_data_in_buffers(struct camera_device *dev,
+       int enable)
+{
+       LOGD("%s(%p, %d)", __func__, dev, enable);
+
+       if (!enable) {
+               LOGE("%s: Cannot disable meta-data in buffers!", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_camera_start_recording(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera_recording_start(exynos_camera);
+}
+
+void exynos_camera_stop_recording(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera_recording_stop(exynos_camera);
+}
+
+int exynos_camera_recording_enabled(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera->recording_enabled;
+}
+
+void exynos_camera_release_recording_frame(struct camera_device *dev,
+       const void *opaque)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGV("%s(%p, %p)", __func__, dev, opaque);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera_recording_frame_release(exynos_camera, (void *) opaque);
+}
+
+int exynos_camera_auto_focus(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera_auto_focus_start(exynos_camera);
+}
+
+int exynos_camera_cancel_auto_focus(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera_auto_focus_stop(exynos_camera);
+
+       return 0;
+}
+
+int exynos_camera_take_picture(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera_picture_start(exynos_camera);
+}
+
+int exynos_camera_cancel_picture(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera_picture_stop(exynos_camera);
+
+       return 0;
+}
+
+int exynos_camera_set_parameters(struct camera_device *dev,
+       const char *params)
+{
+       struct exynos_camera *exynos_camera;
+       int rc;
+
+       LOGD("%s(%p, %s)", __func__, dev, params);
+
+       if (dev == NULL || dev->priv == NULL || params == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       rc = exynos_params_string_set(exynos_camera, (char *) params);
+       if (rc < 0) {
+               LOGE("%s: Unable to set params string", __func__);
+               return -1;
+       }
+
+       rc = exynos_camera_params_apply(exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to apply params", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+char *exynos_camera_get_parameters(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+       char *params;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return NULL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       params = exynos_params_string_get(exynos_camera);
+       if (params == NULL) {
+               LOGE("%s: Couldn't find any param", __func__);
+               return strdup("");
+       }
+
+       return params;
+}
+
+void exynos_camera_put_parameters(struct camera_device *dev, char *params)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       if (params != NULL)
+               free(params);
+}
+
+int exynos_camera_send_command(struct camera_device *dev,
+       int32_t cmd, int32_t arg1, int32_t arg2)
+{
+       LOGD("%s(%p, %d, %d, %d)", __func__, dev, cmd, arg1, arg2);
+
+       return 0;
+}
+
+void exynos_camera_release(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       if (exynos_camera->preview_memory != NULL && exynos_camera->preview_memory->release != NULL) {
+               exynos_camera->preview_memory->release(exynos_camera->preview_memory);
+               exynos_camera->preview_memory = NULL;
+       }
+
+       if (exynos_camera->picture_memory != NULL && exynos_camera->picture_memory->release != NULL) {
+               exynos_camera->picture_memory->release(exynos_camera->picture_memory);
+               exynos_camera->picture_memory = NULL;
+       }
+
+       exynos_camera_deinit(exynos_camera);
+}
+
+int exynos_camera_dump(struct camera_device *dev, int fd)
+{
+       LOGD("%s(%p, %d)", __func__, dev, fd);
+
+       return 0;
+}
+
+/*
+ * Interface
+ */
+
+struct camera_device_ops exynos_camera_ops = {
+       .set_preview_window = exynos_camera_set_preview_window,
+       .set_callbacks = exynos_camera_set_callbacks,
+       .enable_msg_type = exynos_camera_enable_msg_type,
+       .disable_msg_type = exynos_camera_disable_msg_type,
+       .msg_type_enabled = exynos_camera_msg_type_enabled,
+       .start_preview = exynos_camera_start_preview,
+       .stop_preview = exynos_camera_stop_preview,
+       .preview_enabled = exynos_camera_preview_enabled,
+       .store_meta_data_in_buffers = exynos_camera_store_meta_data_in_buffers,
+       .start_recording = exynos_camera_start_recording,
+       .stop_recording = exynos_camera_stop_recording,
+       .recording_enabled = exynos_camera_recording_enabled,
+       .release_recording_frame = exynos_camera_release_recording_frame,
+       .auto_focus = exynos_camera_auto_focus,
+       .cancel_auto_focus = exynos_camera_cancel_auto_focus,
+       .take_picture = exynos_camera_take_picture,
+       .cancel_picture = exynos_camera_cancel_picture,
+       .set_parameters = exynos_camera_set_parameters,
+       .get_parameters = exynos_camera_get_parameters,
+       .put_parameters = exynos_camera_put_parameters,
+       .send_command = exynos_camera_send_command,
+       .release = exynos_camera_release,
+       .dump = exynos_camera_dump,
+};
+
+int exynos_camera_close(hw_device_t *device)
+{
+       struct camera_device *camera_device;
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, device);
+
+       if (device == NULL)
+               return -EINVAL;
+
+       camera_device = (struct camera_device *) device;
+
+       if (camera_device->priv != NULL) {
+               free(camera_device->priv);
+       }
+
+       free(camera_device);
+
+       return 0;
+}
+
+int exynos_camera_open(const struct hw_module_t* module, const char *camera_id,
+       struct hw_device_t** device)
+{
+       struct camera_device *camera_device = NULL;
+       struct exynos_camera *exynos_camera = NULL;
+       int id;
+       int rc;
+
+       LOGD("%s(%p, %s, %p)", __func__, module, camera_id, device);
+
+       if (module == NULL || camera_id == NULL || device == NULL)
+               return -EINVAL;
+
+       id = atoi(camera_id);
+       if (id < 0)
+               return -EINVAL;
+
+       exynos_camera = calloc(1, sizeof(struct exynos_camera));
+       exynos_camera->config = exynos_camera_config;
+
+       if (exynos_camera->config->presets_count > EXYNOS_CAMERA_MAX_PRESETS_COUNT ||
+               exynos_camera->config->v4l2_nodes_count > EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT)
+               goto error_preset;
+
+       if (id >= exynos_camera->config->presets_count)
+               goto error_preset;
+
+       rc = exynos_camera_init(exynos_camera, id);
+       if (rc < 0) {
+               LOGE("%s: Unable to init camera", __func__);
+               goto error;
+       }
+
+       camera_device = calloc(1, sizeof(struct camera_device));
+       camera_device->common.tag = HARDWARE_DEVICE_TAG;
+       camera_device->common.version = 0;
+       camera_device->common.module = (struct hw_module_t *) module;
+       camera_device->common.close = exynos_camera_close;
+
+       camera_device->ops = &exynos_camera_ops;
+       camera_device->priv = exynos_camera;
+
+       *device = (struct hw_device_t *) &(camera_device->common);
+
+       return 0;
+
+error:
+       exynos_camera_deinit(exynos_camera);
+
+error_device:
+       if (camera_device != NULL)
+               free(camera_device);
+
+error_preset:
+       if (exynos_camera != NULL)
+               free(exynos_camera);
+
+       return -1;
+}
+
+int exynos_camera_get_number_of_cameras(void)
+{
+       LOGD("%s()", __func__);
+
+       if (exynos_camera_config == NULL || exynos_camera_config->presets == NULL) {
+               LOGE("%s: Unable to find proper camera config", __func__);
+               return -1;
+       }
+
+       return exynos_camera_config->presets_count;
+}
+
+int exynos_camera_get_camera_info(int id, struct camera_info *info)
+{
+       LOGD("%s(%d, %p)", __func__, id, info);
+
+       if (id < 0 || info == NULL)
+               return -EINVAL;
+
+       if (exynos_camera_config == NULL || exynos_camera_config->presets == NULL) {
+               LOGE("%s: Unable to find proper camera config", __func__);
+               return -1;
+       }
+
+       if (id >= exynos_camera_config->presets_count)
+               return -EINVAL;
+
+       LOGD("Selected camera: %s", exynos_camera_config->presets[id].name);
+
+       info->facing = exynos_camera_config->presets[id].facing;
+       info->orientation = exynos_camera_config->presets[id].orientation;
+
+       return 0;
+}
+
+struct hw_module_methods_t exynos_camera_module_methods = {
+       .open = exynos_camera_open,
+};
+
+struct camera_module HAL_MODULE_INFO_SYM = {
+       .common = {
+               .tag = HARDWARE_MODULE_TAG,
+               .version_major = 1,
+               .version_minor = 0,
+               .id = CAMERA_HARDWARE_MODULE_ID,
+               .name = "Exynos Camera",
+               .author = "Paul Kocialkowski",
+               .methods = &exynos_camera_module_methods,
+       },
+       .get_number_of_cameras = exynos_camera_get_number_of_cameras,
+       .get_camera_info = exynos_camera_get_camera_info,
+};
diff --git a/exynos_camera.h b/exynos_camera.h
new file mode 100644 (file)
index 0000000..94272e9
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <pthread.h>
+
+#include <linux/videodev2.h>
+#include <linux/videodev2_samsung.h>
+
+#include <Exif.h>
+
+#include <hardware/hardware.h>
+#include <hardware/camera.h>
+
+#ifndef _EXYNOS_CAMERA_H_
+#define _EXYNOS_CAMERA_H_
+
+#define EXYNOS_CAMERA_MAX_PRESETS_COUNT                2
+#define EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT     4
+#define EXYNOS_CAMERA_MIN_BUFFERS_COUNT                3
+#define EXYNOS_CAMERA_MAX_BUFFERS_COUNT                8
+
+#define EXYNOS_CAMERA_MSG_ENABLED(msg) \
+       (exynos_camera->messages_enabled & msg)
+#define EXYNOS_CAMERA_CALLBACK_DEFINED(cb) \
+       (exynos_camera->callbacks.cb != NULL)
+
+/*
+ * Structures
+ */
+
+struct list_head {
+       struct list_head *next;
+       struct list_head *prev;
+};
+
+enum exynos_param_type {
+       EXYNOS_PARAM_INT,
+       EXYNOS_PARAM_FLOAT,
+       EXYNOS_PARAM_STRING,
+};
+
+union exynos_param_data {
+       int integer;
+       float floating;
+       char *string;
+};
+
+struct exynos_param {
+       struct list_head list;
+
+       char *key;
+       union exynos_param_data data;
+       enum exynos_param_type type;
+};
+
+struct exynos_camera_params {
+       char *preview_size_values;
+       char *preview_size;
+       char *preview_format_values;
+       char *preview_format;
+       char *preview_frame_rate_values;
+       int preview_frame_rate;
+       char *preview_fps_range_values;
+       char *preview_fps_range;
+
+       char *picture_size_values;
+       char *picture_size;
+       char *picture_format_values;
+       char *picture_format;
+       char *jpeg_thumbnail_size_values;
+       int jpeg_thumbnail_width;
+       int jpeg_thumbnail_height;
+       int jpeg_thumbnail_quality;
+       int jpeg_quality;
+
+       char *recording_size;
+       char *recording_size_values;
+       char *recording_format;
+
+       char *focus_mode;
+       char *focus_mode_values;
+       char *focus_distances;
+       char *focus_areas;
+       int max_num_focus_areas;
+
+       int zoom_supported;
+       int smooth_zoom_supported;
+       char *zoom_ratios;
+       int zoom;
+       int max_zoom;
+
+       char *flash_mode;
+       char *flash_mode_values;
+
+       int exposure_compensation;
+       float exposure_compensation_step;
+       int min_exposure_compensation;
+       int max_exposure_compensation;
+
+       char *whitebalance;
+       char *whitebalance_values;
+
+       char *scene_mode;
+       char *scene_mode_values;
+
+       char *effect;
+       char *effect_values;
+
+       char *iso;
+       char *iso_values;
+};
+
+struct exynos_camera_preset {
+       char *name;
+       int facing;
+       int orientation;
+
+       int rotation;
+       int hflip;
+       int vflip;
+
+       int picture_format;
+
+       float focal_length;
+       float horizontal_view_angle;
+       float vertical_view_angle;
+
+       int metering;
+
+       struct exynos_camera_params params;
+};
+
+struct exynos_v4l2_node {
+       int id;
+       char *node;
+};
+
+struct exynox_camera_config {
+       struct exynos_camera_preset *presets;
+       int presets_count;
+
+       struct exynos_v4l2_node *v4l2_nodes;
+       int v4l2_nodes_count;
+};
+
+struct exynos_camera_callbacks {
+       camera_notify_callback notify;
+       camera_data_callback data;
+       camera_data_timestamp_callback data_timestamp;
+       camera_request_memory request_memory;
+       void *user;
+};
+
+struct exynos_camera {
+       int v4l2_fds[EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT];
+
+       struct exynox_camera_config *config;
+       struct exynos_param *params;
+
+       struct exynos_camera_callbacks callbacks;
+       int messages_enabled;
+
+       gralloc_module_t *gralloc;
+
+       // Picture
+       pthread_t picture_thread;
+       pthread_mutex_t picture_mutex;
+       int picture_thread_running;
+
+       int picture_enabled;
+       camera_memory_t *picture_memory;
+       int picture_buffer_length;
+
+       // Auto-focus
+       pthread_t auto_focus_thread;
+       pthread_mutex_t auto_focus_mutex;
+       int auto_focus_thread_running;
+
+       int auto_focus_enabled;
+
+       // Preview
+       pthread_t preview_thread;
+       pthread_mutex_t preview_mutex;
+       pthread_mutex_t preview_lock_mutex;
+       int preview_thread_running;
+
+       int preview_enabled;
+       struct preview_stream_ops *preview_window;
+       camera_memory_t *preview_memory;
+       int preview_buffers_count;
+       int preview_params_set;
+
+       // Recording
+       pthread_mutex_t recording_mutex;
+
+       int recording_enabled;
+       camera_memory_t *recording_memory;
+       int recording_buffers_count;
+
+       // Camera params
+       int camera_rotation;
+       int camera_hflip;
+       int camera_vflip;
+       int camera_picture_format;
+       int camera_focal_length;
+       int camera_metering;
+
+       int camera_sensor_mode;
+
+       // Params
+       int preview_width;
+       int preview_height;
+       int preview_format;
+       float preview_format_bpp;
+       int preview_fps;
+       int picture_width;
+       int picture_height;
+       int picture_format;
+       int jpeg_thumbnail_width;
+       int jpeg_thumbnail_height;
+       int jpeg_thumbnail_quality;
+       int jpeg_quality;
+       int recording_width;
+       int recording_height;
+       int recording_format;
+       int focus_mode;
+       int focus_x;
+       int focus_y;
+       int zoom;
+       int flash_mode;
+       int exposure_compensation;
+       int whitebalance;
+       int scene_mode;
+       int effect;
+       int iso;
+       int metering;
+};
+
+struct exynos_camera_addrs {
+       unsigned int type;
+       unsigned int y;
+       unsigned int cbcr;
+       unsigned int index;
+       unsigned int reserved;
+};
+
+// This is because the linux header uses anonymous union
+struct exynos_v4l2_ext_control {
+       __u32 id;
+       __u32 size;
+       __u32 reserved2[1];
+       union {
+               __s32 value;
+               __s64 value64;
+               char *string;
+       } data;
+} __attribute__ ((packed));
+
+/*
+ * Camera
+ */
+
+int exynos_camera_params_init(struct exynos_camera *exynos_camera, int id);
+int exynos_camera_params_apply(struct exynos_camera *exynos_camera);
+
+int exynos_camera_auto_focus_start(struct exynos_camera *exynos_camera);
+void exynos_camera_auto_focus_stop(struct exynos_camera *exynos_camera);
+
+int exynos_camera_picture(struct exynos_camera *exynos_camera);
+int exynos_camera_picture_start(struct exynos_camera *exynos_camera);
+
+int exynos_camera_preview(struct exynos_camera *exynos_camera);
+int exynos_camera_preview_start(struct exynos_camera *exynos_camera);
+void exynos_camera_preview_stop(struct exynos_camera *exynos_camera);
+
+/*
+ * EXIF
+ */
+
+int exynos_exif_attributes_create_static(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes);
+int exynos_exif_attributes_create_params(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes);
+
+int exynos_exif_create(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes,
+       camera_memory_t *jpeg_thumbnail_data_memory, int jpeg_thumbnail_size,
+       camera_memory_t **exif_data_memory_p, int *exif_size_p);
+
+/*
+ * Param
+ */
+
+int exynos_param_int_get(struct exynos_camera *exynos_camera,
+       char *key);
+float exynos_param_float_get(struct exynos_camera *exynos_camera,
+       char *key);
+char *exynos_param_string_get(struct exynos_camera *exynos_camera,
+       char *key);
+
+int exynos_param_int_set(struct exynos_camera *exynos_camera,
+       char *key, int integer);
+int exynos_param_float_set(struct exynos_camera *exynos_camera,
+       char *key, float floating);
+int exynos_param_string_set(struct exynos_camera *exynos_camera,
+       char *key, char *string);
+
+char *exynos_params_string_get(struct exynos_camera *exynos_camera);
+int exynos_params_string_set(struct exynos_camera *exynos_camera, char *string);
+
+/*
+ * V4L2
+ */
+
+// Utils
+int exynos_v4l2_find_index(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_find_fd(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+
+// File ops
+int exynos_v4l2_open(struct exynos_camera *exynos_camera, int id);
+void exynos_v4l2_close(struct exynos_camera *exynos_camera, int id);
+int exynos_v4l2_ioctl(struct exynos_camera *exynos_camera, int id, int request, void *data);
+int exynos_v4l2_poll(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+
+// VIDIOC
+int exynos_v4l2_qbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int memory, int index);
+int exynos_v4l2_qbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index);
+int exynos_v4l2_qbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index);
+int exynos_v4l2_dqbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int memory);
+int exynos_v4l2_dqbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_dqbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_reqbufs(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int memory, int count);
+int exynos_v4l2_reqbufs_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int count);
+int exynos_v4l2_reqbufs_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int count);
+int exynos_v4l2_querybuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int memory, int index);
+int exynos_v4l2_querybuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index);
+int exynos_v4l2_querybuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index);
+int exynos_v4l2_querycap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int flags);
+int exynos_v4l2_querycap_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_querycap_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamon(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type);
+int exynos_v4l2_streamon_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamon_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamoff(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type);
+int exynos_v4l2_streamoff_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamoff_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_g_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int *width, int *height, int *fmt);
+int exynos_v4l2_g_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int *width, int *height, int *fmt);
+int exynos_v4l2_g_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int *width, int *height, int *fmt);
+int exynos_v4l2_s_fmt_pix(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int width, int height, int fmt, int priv);
+int exynos_v4l2_s_fmt_pix_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int width, int height, int fmt, int priv);
+int exynos_v4l2_s_fmt_pix_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int width, int height, int fmt, int priv);
+int exynos_v4l2_s_fmt_win(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int left, int top, int width, int height);
+int exynos_v4l2_enum_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int fmt);
+int exynos_v4l2_enum_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int fmt);
+int exynos_v4l2_enum_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int fmt);
+int exynos_v4l2_enum_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id);
+int exynos_v4l2_s_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id);
+int exynos_v4l2_g_ext_ctrls(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_ext_control *control, int count);
+int exynos_v4l2_g_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id, int *value);
+int exynos_v4l2_s_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id, int value);
+int exynos_v4l2_s_parm(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, struct v4l2_streamparm *streamparm);
+int exynos_v4l2_s_parm_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_streamparm *streamparm);
+int exynos_v4l2_s_parm_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_streamparm *streamparm);
+int exynos_v4l2_s_crop(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int left, int top, int width, int height);
+int exynos_v4l2_s_crop_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int left, int top, int width, int height);
+int exynos_v4l2_s_crop_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int left, int top, int width, int height);
+int exynos_v4l2_g_fbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       void **base, int *width, int *height, int *fmt);
+int exynos_v4l2_s_fbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       void *base, int width, int height, int fmt);
+
+#endif
diff --git a/exynos_exif.c b/exynos_exif.c
new file mode 100644 (file)
index 0000000..3bf4298
--- /dev/null
@@ -0,0 +1,797 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * Based on crespo libcamera and exynos4 hal libcamera:
+ * Copyright 2008, The Android Open Source Project
+ * Copyright 2010, Samsung Electronics Co. LTD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <Exif.h>
+
+#define LOG_TAG "exynos_camera"
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include "exynos_camera.h"
+
+/*
+ * FIXME: This EXIF implementation doesn't work very well, it needs to be fixed.
+ */
+
+int exynos_exif_attributes_create_static(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes)
+{
+       unsigned char gps_version[] = { 0x02, 0x02, 0x00, 0x00 };
+       char property[PROPERTY_VALUE_MAX];
+       uint32_t av;
+
+       if (exynos_camera == NULL || exif_attributes == NULL)
+               return -EINVAL;
+
+       // Device
+       property_get("ro.product.brand", property, EXIF_DEF_MAKER);
+       strncpy((char *) exif_attributes->maker, property,
+               sizeof(exif_attributes->maker) - 1);
+       exif_attributes->maker[sizeof(exif_attributes->maker) - 1] = '\0';
+
+       property_get("ro.product.model", property, EXIF_DEF_MODEL);
+       strncpy((char *) exif_attributes->model, property,
+               sizeof(exif_attributes->model) - 1);
+       exif_attributes->model[sizeof(exif_attributes->model) - 1] = '\0';
+
+       property_get("ro.build.id", property, EXIF_DEF_SOFTWARE);
+       strncpy((char *) exif_attributes->software, property,
+               sizeof(exif_attributes->software) - 1);
+       exif_attributes->software[sizeof(exif_attributes->software) - 1] = '\0';
+
+       exif_attributes->ycbcr_positioning = EXIF_DEF_YCBCR_POSITIONING;
+
+       exif_attributes->fnumber.num = EXIF_DEF_FNUMBER_NUM;
+       exif_attributes->fnumber.den = EXIF_DEF_FNUMBER_DEN;
+
+       exif_attributes->exposure_program = EXIF_DEF_EXPOSURE_PROGRAM;
+
+       memcpy(exif_attributes->exif_version, EXIF_DEF_EXIF_VERSION,
+               sizeof(exif_attributes->exif_version));
+
+       av = APEX_FNUM_TO_APERTURE((double) exif_attributes->fnumber.num /
+               exif_attributes->fnumber.den);
+       exif_attributes->aperture.num = av * EXIF_DEF_APEX_DEN;
+       exif_attributes->aperture.den = EXIF_DEF_APEX_DEN;
+       exif_attributes->max_aperture.num = av * EXIF_DEF_APEX_DEN;
+       exif_attributes->max_aperture.den = EXIF_DEF_APEX_DEN;
+
+       strcpy((char *) exif_attributes->user_comment, EXIF_DEF_USERCOMMENTS);
+       exif_attributes->color_space = EXIF_DEF_COLOR_SPACE;
+       exif_attributes->exposure_mode = EXIF_DEF_EXPOSURE_MODE;
+
+       // GPS version
+       memcpy(exif_attributes->gps_version_id, gps_version, sizeof(gps_version));
+
+       exif_attributes->compression_scheme = EXIF_DEF_COMPRESSION;
+       exif_attributes->x_resolution.num = EXIF_DEF_RESOLUTION_NUM;
+       exif_attributes->x_resolution.den = EXIF_DEF_RESOLUTION_DEN;
+       exif_attributes->y_resolution.num = EXIF_DEF_RESOLUTION_NUM;
+       exif_attributes->y_resolution.den = EXIF_DEF_RESOLUTION_DEN;
+       exif_attributes->resolution_unit = EXIF_DEF_RESOLUTION_UNIT;
+
+       return 0;
+}
+
+int exynos_exif_attributes_create_gps(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes)
+{
+       float gps_latitude_float, gps_longitude_float, gps_altitude_float;
+       int gps_timestamp_int;
+       char *gps_processing_method_string;
+       long gps_latitude, gps_longitude;
+       long gps_altitude, gps_timestamp;
+       double gps_latitude_abs, gps_longitude_abs, gps_altitude_abs;
+
+       struct tm time_info;
+
+       if (exynos_camera == NULL || exif_attributes == NULL)
+               return -EINVAL;
+
+       gps_latitude_float = exynos_param_float_get(exynos_camera, "gps-latitude");
+       gps_longitude_float = exynos_param_float_get(exynos_camera, "gps-longitude");
+       gps_altitude_float = exynos_param_float_get(exynos_camera, "gps-altitude");
+       if (gps_altitude_float == -1)
+               gps_altitude_float = (float) exynos_param_int_get(exynos_camera, "gps-altitude");
+       gps_timestamp_int = exynos_param_int_get(exynos_camera, "gps-timestamp");
+       gps_processing_method_string = exynos_param_string_get(exynos_camera, "gps-processing-method");
+
+       if (gps_latitude_float == -1 || gps_longitude_float == -1 ||
+               gps_altitude_float == -1 || gps_timestamp_int <= 0 ||
+               gps_processing_method_string == NULL) {
+               exif_attributes->enableGps = false;
+               return 0;
+       }
+
+       gps_latitude = (long) (gps_latitude_float * 10000) / 1;
+       gps_longitude = (long) (gps_longitude_float * 10000) / 1;
+       gps_altitude = (long) (gps_altitude_float * 100) / 1;
+       gps_timestamp = (long) gps_timestamp_int;
+
+       if (gps_latitude == 0 || gps_longitude == 0) {
+               exif_attributes->enableGps = false;
+               return 0;
+       }
+
+       if (gps_latitude > 0)
+               strcpy((char *) exif_attributes->gps_latitude_ref, "N");
+       else
+               strcpy((char *) exif_attributes->gps_latitude_ref, "S");
+
+       if (gps_longitude > 0)
+               strcpy((char *) exif_attributes->gps_longitude_ref, "E");
+       else
+               strcpy((char *) exif_attributes->gps_longitude_ref, "W");
+
+       if (gps_altitude > 0)
+               exif_attributes->gps_altitude_ref = 0;
+       else
+               exif_attributes->gps_altitude_ref = 1;
+
+
+       gps_latitude_abs = fabs(gps_latitude / 10000.0);
+       gps_longitude_abs = fabs(gps_longitude / 10000.0);
+       gps_altitude_abs = fabs(gps_altitude / 100.0);
+
+       exif_attributes->gps_latitude[0].num = (uint32_t) gps_latitude_abs;
+       exif_attributes->gps_latitude[0].den = 1;
+       exif_attributes->gps_latitude[1].num = 0;
+       exif_attributes->gps_latitude[1].den = 1;
+       exif_attributes->gps_latitude[2].num = 0;
+       exif_attributes->gps_latitude[2].den = 1;
+
+       exif_attributes->gps_longitude[0].num = (uint32_t) gps_longitude_abs;
+       exif_attributes->gps_longitude[0].den = 1;
+       exif_attributes->gps_longitude[1].num = 0;
+       exif_attributes->gps_longitude[1].den = 1;
+       exif_attributes->gps_longitude[2].num = 0;
+       exif_attributes->gps_longitude[2].den = 1;
+
+       exif_attributes->gps_altitude.num = (uint32_t) gps_altitude_abs;
+       exif_attributes->gps_altitude.den = 1;
+
+       gmtime_r(&gps_timestamp, &time_info);
+
+       exif_attributes->gps_timestamp[0].num = time_info.tm_hour;
+       exif_attributes->gps_timestamp[0].den = 1;
+       exif_attributes->gps_timestamp[1].num = time_info.tm_min;
+       exif_attributes->gps_timestamp[1].den = 1;
+       exif_attributes->gps_timestamp[2].num = time_info.tm_sec;
+       exif_attributes->gps_timestamp[2].den = 1;
+       snprintf((char *) exif_attributes->gps_datestamp, sizeof(exif_attributes->gps_datestamp),
+               "%04d:%02d:%02d", time_info.tm_year + 1900, time_info.tm_mon + 1, time_info.tm_mday);
+
+       exif_attributes->enableGps = true;
+
+       return 0;
+}
+
+int exynos_exif_attributes_create_params(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes)
+{
+       uint32_t av, tv, bv, sv, ev;
+       time_t time_data;
+       struct tm *time_info;
+       int rotation;
+       int shutter_speed;
+       int exposure_time;
+       int iso_speed;
+       int exposure;
+
+       int rc;
+
+       if (exynos_camera == NULL || exif_attributes == NULL)
+               return -EINVAL;
+
+       // Picture size
+       exif_attributes->width = exynos_camera->picture_width;
+       exif_attributes->height = exynos_camera->picture_height;
+
+       // Thumbnail
+       exif_attributes->widthThumb = exynos_camera->jpeg_thumbnail_width;
+       exif_attributes->heightThumb = exynos_camera->jpeg_thumbnail_height;
+       exif_attributes->enableThumb = true;
+
+       // Orientation
+       rotation = exynos_param_int_get(exynos_camera, "rotation");
+       switch (rotation) {
+               case 90:
+                       exif_attributes->orientation = EXIF_ORIENTATION_90;
+                       break;
+               case 180:
+                       exif_attributes->orientation = EXIF_ORIENTATION_180;
+                       break;
+               case 270:
+                       exif_attributes->orientation = EXIF_ORIENTATION_270;
+                       break;
+               case 0:
+               default:
+                       exif_attributes->orientation = EXIF_ORIENTATION_UP;
+                       break;
+       }
+
+       // Time
+       time(&time_data);
+       time_info = localtime(&time_data);
+       strftime((char *) exif_attributes->date_time, sizeof(exif_attributes->date_time),
+               "%Y:%m:%d %H:%M:%S", time_info);
+
+       exif_attributes->focal_length.num = exynos_camera->camera_focal_length;
+       exif_attributes->focal_length.den = EXIF_DEF_FOCAL_LEN_DEN;
+
+       shutter_speed = 100;
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_TV,
+               &shutter_speed);
+       if (rc < 0)
+               LOGE("%s: g ctrl failed!", __func__);
+
+       exif_attributes->shutter_speed.num = 1;
+       exif_attributes->shutter_speed.den = shutter_speed;
+
+       exposure_time = shutter_speed;
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EXPTIME,
+               &exposure_time);
+       if (rc < 0)
+               LOGE("%s: g ctrl failed!", __func__);
+
+       exif_attributes->exposure_time.num = 1;
+       exif_attributes->exposure_time.den = exposure_time;
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_ISO,
+               &iso_speed);
+       if (rc < 0)
+               LOGE("%s: g ctrl failed!", __func__);
+
+       exif_attributes->iso_speed_rating = iso_speed;
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_BV,
+               (int *) &bv);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               goto bv_static;
+       }
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EBV,
+               (int *) &ev);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               goto bv_static;
+       }
+
+       goto bv_ioctl;
+
+bv_static:
+       exposure = exynos_param_int_get(exynos_camera, "exposure-compensation");
+       if (exposure < 0)
+               exposure = EV_DEFAULT;
+
+       av = APEX_FNUM_TO_APERTURE((double) exif_attributes->fnumber.num /
+               exif_attributes->fnumber.den);
+       tv = APEX_EXPOSURE_TO_SHUTTER((double) exif_attributes->exposure_time.num /
+               exif_attributes->exposure_time.den);
+       sv = APEX_ISO_TO_FILMSENSITIVITY(iso_speed);
+       bv = av + tv - sv;
+       ev = exposure - EV_DEFAULT;
+
+bv_ioctl:
+       exif_attributes->brightness.num = bv * EXIF_DEF_APEX_DEN;
+       exif_attributes->brightness.den = EXIF_DEF_APEX_DEN;
+
+       if (exynos_camera->scene_mode == SCENE_MODE_BEACH_SNOW) {
+               exif_attributes->exposure_bias.num = EXIF_DEF_APEX_DEN;
+               exif_attributes->exposure_bias.den = EXIF_DEF_APEX_DEN;
+       } else {
+               exif_attributes->exposure_bias.num = ev * EXIF_DEF_APEX_DEN;
+               exif_attributes->exposure_bias.den = EXIF_DEF_APEX_DEN;
+       }
+
+       switch (exynos_camera->camera_metering) {
+               case METERING_CENTER:
+                       exif_attributes->metering_mode = EXIF_METERING_CENTER;
+                       break;
+               case METERING_MATRIX:
+                       exif_attributes->metering_mode = EXIF_METERING_AVERAGE;
+                       break;
+               case METERING_SPOT:
+                       exif_attributes->metering_mode = EXIF_METERING_SPOT;
+                       break;
+               default:
+                       exif_attributes->metering_mode = EXIF_METERING_AVERAGE;
+                       break;
+       }
+
+       if (exynos_camera->flash_mode == FLASH_MODE_BASE)
+               exif_attributes->flash = EXIF_DEF_FLASH;
+       else
+               exif_attributes->flash = exynos_camera->flash_mode;
+
+       if (exynos_camera->whitebalance == WHITE_BALANCE_AUTO ||
+               exynos_camera->whitebalance == WHITE_BALANCE_BASE)
+               exif_attributes->white_balance = EXIF_WB_AUTO;
+       else
+               exif_attributes->white_balance = EXIF_WB_MANUAL;
+
+       switch (exynos_camera->scene_mode) {
+               case SCENE_MODE_PORTRAIT:
+                       exif_attributes->scene_capture_type = EXIF_SCENE_PORTRAIT;
+                       break;
+               case SCENE_MODE_LANDSCAPE:
+                       exif_attributes->scene_capture_type = EXIF_SCENE_LANDSCAPE;
+                       break;
+               case SCENE_MODE_NIGHTSHOT:
+                       exif_attributes->scene_capture_type = EXIF_SCENE_NIGHT;
+                       break;
+               default:
+                       exif_attributes->scene_capture_type = EXIF_SCENE_STANDARD;
+                       break;
+       }
+
+       rc = exynos_exif_attributes_create_gps(exynos_camera, exif_attributes);
+       if (rc < 0) {
+               LOGE("%s: Failed to create GPS attributes", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_exif_write_data(void *exif_data, unsigned short tag,
+       unsigned short type, unsigned int count, int *offset, void *start, 
+       void *data, int length)
+{
+       unsigned char *pointer;
+       int size;
+
+       if (exif_data == NULL || data == NULL || length <= 0)
+               return -EINVAL;
+
+       pointer = (unsigned char *) exif_data;
+
+       memcpy(pointer, &tag, sizeof(tag));
+       pointer += sizeof(tag);
+
+       memcpy(pointer, &type, sizeof(type));
+       pointer += sizeof(type);
+
+       memcpy(pointer, &count, sizeof(count));
+       pointer += sizeof(count);
+
+       if (offset != NULL && start != NULL) {
+               memcpy(pointer, offset, sizeof(*offset));
+               pointer += sizeof(*offset);
+
+               memcpy((void *) ((int) start + *offset), data, count * length);
+               *offset += count * length;              
+       } else {
+               memcpy(pointer, data, count * length);
+               pointer += count * length;
+       }
+
+       size = (int) pointer - (int) exif_data;
+       return size;
+}
+
+int exynos_exif_create(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes,
+       camera_memory_t *jpeg_thumbnail_data_memory, int jpeg_thumbnail_size,
+       camera_memory_t **exif_data_memory_p, int *exif_size_p)
+{
+       // Markers
+       unsigned char exif_app1_marker[] = { 0xff, 0xe1 };
+       unsigned char exif_app1_size[] = { 0x00, 0x00 };
+       unsigned char exif_marker[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
+       unsigned char tiff_marker[] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 };
+
+       unsigned char user_comment_code[] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 };
+       unsigned char exif_ascii_prefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };
+
+       camera_memory_t *exif_data_memory;
+       void *exif_data;
+       int exif_data_size;
+       int exif_size;
+
+       void *exif_ifd_data_start, *exif_ifd_start, *exif_ifd_gps, *exif_ifd_thumb;
+
+       void *exif_thumb_data;
+       unsigned int exif_thumb_size;
+
+       unsigned char *pointer;
+       unsigned int offset;
+       void *data;
+       int count;
+
+       unsigned int value;
+
+       if (exynos_camera == NULL || exif_attributes == NULL ||
+               jpeg_thumbnail_data_memory == NULL || jpeg_thumbnail_size <= 0 ||
+               exif_data_memory_p == NULL || exif_size_p == NULL)
+               return -EINVAL;
+
+       exif_data_size = EXIF_FILE_SIZE + jpeg_thumbnail_size;
+
+       if (exynos_camera->callbacks.request_memory != NULL) {
+               exif_data_memory = exynos_camera->callbacks.request_memory(-1,
+                       exif_data_size, 1, 0);
+               if (exif_data_memory == NULL) {
+                       LOGE("%s: exif memory request failed!", __func__);
+                       goto error;
+               }
+       } else {
+               LOGE("%s: No memory request function!", __func__);
+               goto error;
+       }
+
+       exif_data = exif_data_memory->data;
+       memset(exif_data, 0, exif_data_size);
+
+       pointer = (unsigned char *) exif_data;
+       exif_ifd_data_start = (void *) pointer;
+
+       // Skip 4 bytes for APP1 marker
+       pointer += 4;
+
+       // Copy EXIF marker
+       memcpy(pointer, exif_marker, sizeof(exif_marker));
+       pointer += sizeof(exif_marker);
+
+       // Copy TIFF marker
+       memcpy(pointer, tiff_marker, sizeof(tiff_marker));
+       exif_ifd_start = (void *) pointer;
+       pointer += sizeof(tiff_marker);
+
+       if (exif_attributes->enableGps)
+               value = NUM_0TH_IFD_TIFF;
+       else
+               value = NUM_0TH_IFD_TIFF - 1;
+
+       memcpy(pointer, &value, NUM_SIZE);
+       pointer += NUM_SIZE;
+
+       offset = 8 + NUM_SIZE + value * IFD_SIZE + OFFSET_SIZE;
+
+       // Write EXIF data
+       count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_WIDTH,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->width, sizeof(exif_attributes->width));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_HEIGHT,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->height, sizeof(exif_attributes->height));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_MAKE,
+               EXIF_TYPE_ASCII, strlen((char *) exif_attributes->maker) + 1,
+               &offset, exif_ifd_start, &exif_attributes->maker, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_MODEL,
+               EXIF_TYPE_ASCII, strlen((char *) exif_attributes->model) + 1,
+               &offset, exif_ifd_start, &exif_attributes->model, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_ORIENTATION,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->orientation, sizeof(exif_attributes->orientation));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_SOFTWARE,
+               EXIF_TYPE_ASCII, strlen((char *) exif_attributes->software) + 1,
+               &offset, exif_ifd_start, &exif_attributes->software, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME,
+               EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_YCBCR_POSITIONING,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->ycbcr_positioning, sizeof(exif_attributes->ycbcr_positioning));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXIF_IFD_POINTER,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset));
+       pointer += count;
+
+       if (exif_attributes->enableGps) {
+               exif_ifd_gps = (void *) pointer;
+               pointer += IFD_SIZE;
+       }
+
+       exif_ifd_thumb = (void *) pointer;
+       pointer += OFFSET_SIZE;
+
+       pointer = (unsigned char *) exif_ifd_start;
+       pointer += offset;
+
+       value = NUM_0TH_IFD_EXIF;
+       memcpy(pointer, &value, NUM_SIZE);
+       pointer += NUM_SIZE;
+
+       offset += NUM_SIZE + NUM_0TH_IFD_EXIF * IFD_SIZE + OFFSET_SIZE;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_TIME,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->exposure_time, sizeof(exif_attributes->exposure_time));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_FNUMBER,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->fnumber, sizeof(exif_attributes->fnumber));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_PROGRAM,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->exposure_program, sizeof(exif_attributes->exposure_program));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_ISO_SPEED_RATING,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->iso_speed_rating, sizeof(exif_attributes->iso_speed_rating));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXIF_VERSION,
+               EXIF_TYPE_UNDEFINED, 1, NULL, NULL, &exif_attributes->exif_version, sizeof(exif_attributes->exif_version));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME_ORG,
+               EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME_DIGITIZE,
+               EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_SHUTTER_SPEED,
+               EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->shutter_speed, sizeof(exif_attributes->shutter_speed));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_APERTURE,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->aperture, sizeof(exif_attributes->shutter_speed));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_BRIGHTNESS,
+               EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->brightness, sizeof(exif_attributes->brightness));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_BIAS,
+               EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->exposure_bias, sizeof(exif_attributes->exposure_bias));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_MAX_APERTURE,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->max_aperture, sizeof(exif_attributes->max_aperture));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_METERING_MODE,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->metering_mode, sizeof(exif_attributes->metering_mode));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_FLASH,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->flash, sizeof(exif_attributes->flash));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_FOCAL_LENGTH,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->focal_length, sizeof(exif_attributes->focal_length));
+       pointer += count;
+
+       value = strlen((char *) exif_attributes->user_comment) + 1;
+       memmove(exif_attributes->user_comment + sizeof(user_comment_code), exif_attributes->user_comment, value);
+       memcpy(exif_attributes->user_comment, user_comment_code, sizeof(user_comment_code));
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_USER_COMMENT,
+               EXIF_TYPE_UNDEFINED, value + sizeof(user_comment_code), &offset, exif_ifd_start, &exif_attributes->user_comment, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_COLOR_SPACE,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->color_space, sizeof(exif_attributes->color_space));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_PIXEL_X_DIMENSION,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->width, sizeof(exif_attributes->width));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_PIXEL_Y_DIMENSION,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->height, sizeof(exif_attributes->height));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_MODE,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->exposure_mode, sizeof(exif_attributes->exposure_mode));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_WHITE_BALANCE,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->white_balance, sizeof(exif_attributes->white_balance));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_SCENCE_CAPTURE_TYPE,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->scene_capture_type, sizeof(exif_attributes->scene_capture_type));
+       pointer += count;
+
+       value = 0;
+       memcpy(pointer, &value, OFFSET_SIZE);
+       pointer += OFFSET_SIZE;
+
+       // GPS
+       if (exif_attributes->enableGps) {
+               pointer = (unsigned char *) exif_ifd_gps;
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_IFD_POINTER,
+                       EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset));
+
+               pointer = exif_ifd_start + offset;
+
+               if (exif_attributes->gps_processing_method[0] == 0)
+                       value = NUM_0TH_IFD_GPS - 1;
+               else
+                       value = NUM_0TH_IFD_GPS;
+
+               memcpy(pointer, &value, NUM_SIZE);
+               pointer += NUM_SIZE;
+
+               offset += NUM_SIZE + value * IFD_SIZE + OFFSET_SIZE;
+               
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_VERSION_ID,
+                       EXIF_TYPE_LONG, 4, NULL, NULL, &exif_attributes->gps_version_id, 1);
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE_REF,
+                       EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_latitude_ref, 1);
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE,
+                       EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_latitude, sizeof(exif_attributes->gps_latitude[0]));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LONGITUDE_REF,
+                       EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_longitude_ref, 1);
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LONGITUDE,
+                       EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_longitude, sizeof(exif_attributes->gps_longitude[0]));
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE_REF,
+                       EXIF_TYPE_BYTE, 1, NULL, NULL, &exif_attributes->gps_altitude_ref, 1);
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE,
+                       EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->gps_altitude, sizeof(exif_attributes->gps_altitude));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_TIMESTAMP,
+                       EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_timestamp, sizeof(exif_attributes->gps_timestamp[0]));
+               pointer += count;
+
+               value = strlen((char *) exif_attributes->gps_processing_method);
+               if (value > 0) {
+                       value = value > 100 ? 100 : value;
+
+                       data = calloc(1, value + sizeof(exif_ascii_prefix));
+                       memcpy(data, &exif_ascii_prefix, sizeof(exif_ascii_prefix));
+                       memcpy((void *) ((int) data + (int) sizeof(exif_ascii_prefix)), exif_attributes->gps_processing_method, value);
+
+                       count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_PROCESSING_METHOD,
+                               EXIF_TYPE_UNDEFINED, value + sizeof(exif_ascii_prefix), &offset, exif_ifd_start, data, 1);
+                       pointer += count;
+
+                       free(data);
+               }
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_DATESTAMP,
+                               EXIF_TYPE_ASCII, 11, &offset, exif_ifd_start, &exif_attributes->gps_datestamp, 1);
+               pointer += count;
+
+               value = 0;
+               memcpy(pointer, &value, OFFSET_SIZE);
+               pointer += OFFSET_SIZE;
+       }
+
+       if (exif_attributes->enableThumb && jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_size > 0) {
+               exif_thumb_size = (unsigned int) jpeg_thumbnail_size;
+               exif_thumb_data = (void *) jpeg_thumbnail_data_memory->data;
+
+               value = offset;
+               memcpy(exif_ifd_thumb, &value, OFFSET_SIZE);
+
+               pointer = (unsigned char *) ((int) exif_ifd_start + (int) offset);
+
+               value = NUM_1TH_IFD_TIFF;
+               memcpy(pointer, &value, NUM_SIZE);
+               pointer += NUM_SIZE;
+
+               offset += NUM_SIZE + NUM_1TH_IFD_TIFF * IFD_SIZE + OFFSET_SIZE;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_WIDTH,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->widthThumb, sizeof(exif_attributes->widthThumb));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_HEIGHT,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->heightThumb, sizeof(exif_attributes->heightThumb));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_COMPRESSION_SCHEME,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->compression_scheme, sizeof(exif_attributes->compression_scheme));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_ORIENTATION,
+                               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->orientation, sizeof(exif_attributes->orientation));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_X_RESOLUTION,
+                               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->x_resolution, sizeof(exif_attributes->x_resolution));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_Y_RESOLUTION,
+                               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->y_resolution, sizeof(exif_attributes->y_resolution));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_RESOLUTION_UNIT,
+                               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->resolution_unit, sizeof(exif_attributes->resolution_unit));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_thumb_size, sizeof(exif_thumb_size));
+               pointer += count;
+
+               value = 0;
+               memcpy(pointer, &value, OFFSET_SIZE);
+
+               pointer = (unsigned char *) ((int) exif_ifd_start + (int) offset);
+
+               memcpy(pointer, exif_thumb_data, exif_thumb_size);
+               offset += exif_thumb_size;
+       } else {
+               value = 0;
+               memcpy(exif_ifd_thumb, &value, OFFSET_SIZE);
+               
+       }
+
+       pointer = (unsigned char *) exif_ifd_data_start;
+
+       memcpy(pointer, exif_app1_marker, sizeof(exif_app1_marker));
+       pointer += sizeof(exif_app1_marker);
+
+       exif_size = offset + 10;
+       value = exif_size - 2;
+       exif_app1_size[0] = (value >> 8) & 0xff;
+       exif_app1_size[1] = value & 0xff;
+
+       memcpy(pointer, exif_app1_size, sizeof(exif_app1_size));
+
+       *exif_data_memory_p = exif_data_memory;
+       *exif_size_p = exif_size;
+
+       return 0;
+
+error:
+       if (exif_data_memory != NULL && exif_data_memory->release != NULL)
+               exif_data_memory->release(exif_data_memory);
+
+       *exif_data_memory_p = NULL;
+       *exif_size_p = 0;
+
+       return -1;
+}
diff --git a/exynos_param.c b/exynos_param.c
new file mode 100644 (file)
index 0000000..17b0450
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <malloc.h>
+#include <ctype.h>
+
+#define LOG_TAG "exynos_param"
+#include <utils/Log.h>
+
+#include "exynos_camera.h"
+
+int list_head_insert(struct list_head *list, struct list_head *prev,
+       struct list_head *next)
+{
+       if (list == NULL)
+               return -EINVAL;
+
+       list->prev = prev;
+       list->next = next;
+
+       if(prev != NULL)
+               prev->next = list;
+       if(next != NULL)
+               next->prev = list;
+
+       return 0;
+}
+
+void list_head_remove(struct list_head *list)
+{
+       if(list == NULL)
+               return;
+
+       if(list->next != NULL)
+               list->next->prev = list->prev;
+       if(list->prev != NULL)
+               list->prev->next = list->next;
+}
+
+int exynos_param_register(struct exynos_camera *exynos_camera, char *key,
+       union exynos_param_data data, enum exynos_param_type type)
+{
+       struct list_head *list_end;
+       struct list_head *list;
+       struct exynos_param *param;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       param = (struct exynos_param *) calloc(1, sizeof(struct exynos_param));
+       if (param == NULL)
+               return -ENOMEM;
+
+       param->key = strdup(key);
+       switch (type) {
+               case EXYNOS_PARAM_INT:
+                       param->data.integer = data.integer;
+                       break;
+               case EXYNOS_PARAM_FLOAT:
+                       param->data.floating = data.floating;
+                       break;
+               case EXYNOS_PARAM_STRING:
+                       param->data.string = strdup(data.string);
+                       break;
+               default:
+                       LOGE("%s: Invalid type", __func__);
+                       goto error;
+       }
+       param->type = type;
+
+       list_end = (struct list_head *) exynos_camera->params;
+       while (list_end != NULL && list_end->next != NULL)
+               list_end = list_end->next;
+
+       list = (struct list_head *) param;
+       list_head_insert(list, list_end, NULL);
+
+       if (exynos_camera->params == NULL)
+               exynos_camera->params = param;
+
+       return 0;
+
+error:
+       if (param != NULL) {
+               if (param->key != NULL)
+                       free(param->key);
+
+               free(param);
+       }
+
+       return -1;
+}
+
+void exynos_param_unregister(struct exynos_camera *exynos_camera,
+       struct exynos_param *param)
+{
+       struct list_head *list;
+
+       if (exynos_camera == NULL || param == NULL)
+               return;
+
+       list = (struct list_head *) exynos_camera->params;
+       while (list != NULL) {
+               if ((void *) list == (void *) param) {
+                       list_head_remove(list);
+
+                       if ((void *) list == (void *) exynos_camera->params)
+                               exynos_camera->params = (struct exynos_param *) list->next;
+
+                       if (param->type == EXYNOS_PARAM_STRING && param->data.string != NULL)
+                               free(param->data.string);
+
+                       memset(param, 0, sizeof(struct exynos_param));
+                       free(param);
+
+                       break;
+               }
+
+list_continue:
+               list = list->next;
+       }
+}
+
+struct exynos_param *exynos_param_find_key(struct exynos_camera *exynos_camera,
+       char *key)
+{
+       struct exynos_param *param;
+       struct list_head *list;
+
+       if (exynos_camera == NULL || key == NULL)
+               return NULL;
+
+       list = (struct list_head *) exynos_camera->params;
+       while (list != NULL) {
+               param = (struct exynos_param *) list;
+               if (param->key == NULL)
+                       goto list_continue;
+
+               if (strcmp(param->key, key) == 0)
+                       return param;
+
+list_continue:
+               list = list->next;
+       }
+
+       return NULL;
+}
+
+int exynos_param_data_set(struct exynos_camera *exynos_camera, char *key,
+       union exynos_param_data data, enum exynos_param_type type)
+{
+       struct exynos_param *param;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       if (strchr(key, '=') || strchr(key, ';'))
+               return -EINVAL;
+
+       if (type == EXYNOS_PARAM_STRING && data.string != NULL &&
+               (strchr(data.string, '=') || strchr(data.string, ';')))
+               return -EINVAL;
+
+       param = exynos_param_find_key(exynos_camera, key);
+       if (param == NULL) {
+               // The key isn't in the list yet
+               exynos_param_register(exynos_camera, key, data, type);
+               return 0;
+       }
+
+       if (param->type != type)
+               LOGE("%s: Mismatching types for key %s", __func__, key);
+
+       if (param->type == EXYNOS_PARAM_STRING && param->data.string != NULL)
+               free(param->data.string);
+
+       switch (type) {
+               case EXYNOS_PARAM_INT:
+                       param->data.integer = data.integer;
+                       break;
+               case EXYNOS_PARAM_FLOAT:
+                       param->data.floating = data.floating;
+                       break;
+               case EXYNOS_PARAM_STRING:
+                       param->data.string = strdup(data.string);
+                       break;
+               default:
+                       LOGE("%s: Invalid type", __func__);
+                       return -1;
+       }
+       param->type = type;
+
+       return 0;
+}
+
+int exynos_param_data_get(struct exynos_camera *exynos_camera, char *key,
+       union exynos_param_data *data, enum exynos_param_type type)
+{
+       struct exynos_param *param;
+
+       if (exynos_camera == NULL || key == NULL || data == NULL)
+               return -EINVAL;
+
+       param = exynos_param_find_key(exynos_camera, key);
+       if (param == NULL || param->type != type)
+               return -1;
+
+       memcpy(data, &param->data, sizeof(param->data));
+
+       return 0;
+}
+
+int exynos_param_int_get(struct exynos_camera *exynos_camera,
+       char *key)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_INT);
+       if (rc < 0) {
+               LOGE("%s: Unable to get data for key %s", __func__, key);
+               return -1;
+       }
+
+       return data.integer;
+}
+
+float exynos_param_float_get(struct exynos_camera *exynos_camera,
+       char *key)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_FLOAT);
+       if (rc < 0) {
+               LOGE("%s: Unable to get data for key %s", __func__, key);
+               return -1;
+       }
+
+       return data.floating;
+}
+
+char *exynos_param_string_get(struct exynos_camera *exynos_camera,
+       char *key)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return NULL;
+
+       rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_STRING);
+       if (rc < 0) {
+               LOGE("%s: Unable to get data for key %s", __func__, key);
+               return NULL;
+       }
+
+       return data.string;
+}
+
+int exynos_param_int_set(struct exynos_camera *exynos_camera,
+       char *key, int integer)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       data.integer = integer;
+
+       rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_INT);
+       if (rc < 0) {
+               LOGE("%s: Unable to set data for key %s", __func__, key);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_param_float_set(struct exynos_camera *exynos_camera,
+       char *key, float floating)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       data.floating = floating;
+
+       rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_FLOAT);
+       if (rc < 0) {
+               LOGE("%s: Unable to set data for key %s", __func__, key);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_param_string_set(struct exynos_camera *exynos_camera,
+       char *key, char *string)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL || string == NULL)
+               return -EINVAL;
+
+       data.string = string;
+
+       rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_STRING);
+       if (rc < 0) {
+               LOGE("%s: Unable to set data for key %s", __func__, key);
+               return -1;
+       }
+
+       return 0;
+}
+
+char *exynos_params_string_get(struct exynos_camera *exynos_camera)
+{
+       struct exynos_param *param;
+       struct list_head *list;
+       char *string = NULL;
+       char *s = NULL;
+       int length = 0;
+       int l = 0;
+
+       if (exynos_camera == NULL)
+               return NULL;
+
+       list = (struct list_head *) exynos_camera->params;
+       while (list != NULL) {
+               param = (struct exynos_param *) list;
+               if (param->key == NULL)
+                       goto list_continue_length;
+
+               length += strlen(param->key);
+               length++;
+
+               switch (param->type) {
+                       case EXYNOS_PARAM_INT:
+                       case EXYNOS_PARAM_FLOAT:
+                               length += 16;
+                               break;
+                       case EXYNOS_PARAM_STRING:
+                               length += strlen(param->data.string);
+                               break;
+                       default:
+                               LOGE("%s: Invalid type", __func__);
+                               return NULL;
+               }
+
+               length++;
+
+list_continue_length:
+               list = list->next;
+       }
+
+       if (length == 0)
+               return NULL;
+
+       string = calloc(1, length);
+       s = string;
+
+       list = (struct list_head *) exynos_camera->params;
+       while (list != NULL) {
+               param = (struct exynos_param *) list;
+               if (param->key == NULL)
+                       goto list_continue;
+
+               l = sprintf(s, "%s=", param->key);
+               s += l;
+
+               switch (param->type) {
+                       case EXYNOS_PARAM_INT:
+                               l = snprintf(s, 16, "%d", param->data.integer);
+                               s += l;
+                               break;
+                       case EXYNOS_PARAM_FLOAT:
+                               l = snprintf(s, 16, "%g", param->data.floating);
+                               s += l;
+                               break;
+                       case EXYNOS_PARAM_STRING:
+                               l = sprintf(s, "%s", param->data.string);
+                               s += l;
+                               break;
+                       default:
+                               LOGE("%s: Invalid type", __func__);
+                               return NULL;
+               }
+
+               if (list->next != NULL) {
+                       *s = ';';
+                       s++;
+               } else {
+                       *s = '\0';
+                       break;
+               }
+
+list_continue:
+               list = list->next;
+       }
+
+       return string;
+}
+
+int exynos_params_string_set(struct exynos_camera *exynos_camera, char *string)
+{
+       union exynos_param_data data;
+       enum exynos_param_type type;
+
+       char *d = NULL;
+       char *s = NULL;
+       char *k = NULL;
+       char *v = NULL;
+
+       char *key;
+       char *value;
+
+       int rc;
+       int i;
+
+       if (exynos_camera == NULL || string == NULL)
+               return -1;
+
+       d = strdup(string);
+       s = d;
+
+       while (1) {
+               k = strchr(s, '=');
+               if (k == NULL)
+                       break;
+               *k = '\0';
+               key = s;
+
+               v = strchr(k+1, ';');
+               if (v != NULL)
+                       *v = '\0';
+               value = k+1;
+
+               k = value;
+               if (isdigit(k[0]) || k[0] == '-') {
+                       type = EXYNOS_PARAM_INT;
+
+                       for (i=1 ; k[i] != '\0' ; i++) {
+                               if (k[i] == '.') {
+                                       type = EXYNOS_PARAM_FLOAT;
+                               } else if (!isdigit(k[i])) {
+                                       type = EXYNOS_PARAM_STRING;
+                                       break;
+                               }
+                       }
+               } else {
+                       type = EXYNOS_PARAM_STRING;
+               }
+
+               switch (type) {
+                       case EXYNOS_PARAM_INT:
+                               data.integer = atoi(value);
+                               break;
+                       case EXYNOS_PARAM_FLOAT:
+                               data.floating = atof(value);
+                               break;
+                       case EXYNOS_PARAM_STRING:
+                               data.string = value;
+                               break;
+                       default:
+                               LOGE("%s: Invalid type", __func__);
+                               goto error;
+               }
+
+               rc = exynos_param_data_set(exynos_camera, key, data, type);
+               if (rc < 0) {
+                       LOGE("%s: Unable to set data for key %s", __func__, key);
+                       goto error;
+               }
+
+               if (v == NULL)
+                       break;
+
+               s = v+1;
+       }
+
+       if (d != NULL)
+               free(d);
+
+       return 0;
+
+error:
+       if (d != NULL)
+               free(d);
+
+       return -1;
+}
diff --git a/exynos_v4l2.c b/exynos_v4l2.c
new file mode 100644 (file)
index 0000000..a4ef8d6
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * Based on crespo libcamera and exynos4 hal libcamera:
+ * Copyright 2008, The Android Open Source Project
+ * Copyright 2010, Samsung Electronics Co. LTD
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+#include <poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>
+
+#define LOG_TAG "exynos_v4l2"
+#include <utils/Log.h>
+
+#include "exynos_camera.h"
+
+/*
+ * Utils
+ */
+
+int exynos_v4l2_find_index(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       int index;
+       int i;
+
+       if (exynos_camera == NULL || exynos_camera->config == NULL ||
+               exynos_camera->config->v4l2_nodes == NULL)
+               return -EINVAL;
+
+       if (exynos_v4l2_id > exynos_camera->config->v4l2_nodes_count)
+               return -1;
+
+       index = -1;
+       for (i=0 ; i < exynos_camera->config->v4l2_nodes_count ; i++) {
+               if (exynos_camera->config->v4l2_nodes[i].id == exynos_v4l2_id &&
+                       exynos_camera->config->v4l2_nodes[i].node != NULL) {
+                       index = i;
+               }
+       }
+
+       return index;
+}
+
+int exynos_v4l2_find_fd(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       int index;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+       if (index < 0)
+               return -1;
+
+       return exynos_camera->v4l2_fds[index];
+}
+
+/*
+ * File ops
+ */
+
+int exynos_v4l2_open(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       char *node;
+       int index;
+       int fd;
+
+       if (exynos_camera == NULL || exynos_camera->config == NULL ||
+               exynos_camera->config->v4l2_nodes == NULL)
+               return -EINVAL;
+
+       index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+       if (index < 0) {
+               LOGE("%s: Unable to find v4l2 node #%d", __func__, exynos_v4l2_id);
+               return -1;
+       }
+
+       node = exynos_camera->config->v4l2_nodes[index].node;
+       fd = open(node, O_RDWR);
+       if (fd < 0) {
+               LOGE("%s: Unable to open v4l2 node #%d", __func__, exynos_v4l2_id);
+               return -1;
+       }
+
+       exynos_camera->v4l2_fds[index] = fd;
+
+       return 0;
+}
+
+void exynos_v4l2_close(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       int index;
+
+       if (exynos_camera == NULL || exynos_camera->config == NULL ||
+               exynos_camera->config->v4l2_nodes == NULL)
+               return;
+
+       index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+       if (index < 0) {
+               LOGE("%s: Unable to find v4l2 node #%d", __func__, exynos_v4l2_id);
+               return;
+       }
+
+       if (exynos_camera->v4l2_fds[index] > 0)
+               close(exynos_camera->v4l2_fds[index]);
+
+       exynos_camera->v4l2_fds[index] = -1;
+}
+
+int exynos_v4l2_ioctl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int request, void *data)
+{
+       int fd;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       fd = exynos_v4l2_find_fd(exynos_camera, exynos_v4l2_id);
+       if (fd < 0) {
+               LOGE("%s: Unable to find v4l2 fd #%d", __func__, exynos_v4l2_id);
+               return -1;
+       }
+
+       return ioctl(fd, request, data);
+}
+
+int exynos_v4l2_poll(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       struct pollfd events;
+       int fd;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       fd = exynos_v4l2_find_fd(exynos_camera, exynos_v4l2_id);
+       if (fd < 0) {
+               LOGE("%s: Unable to find v4l2 fd #%d", __func__, exynos_v4l2_id);
+               return -1;
+       }
+
+       memset(&events, 0, sizeof(events));
+       events.fd = fd;
+       events.events = POLLIN | POLLERR;
+
+       rc = poll(&events, 1, 1000);
+       if (rc < 0 || events.revents & POLLERR) {
+               LOGE("%s: poll failed", __func__);
+               return -1;
+       }
+
+       return rc;
+}
+
+/*
+ * VIDIOC
+ */
+
+int exynos_v4l2_qbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int memory, int index)
+{
+       struct v4l2_buffer buffer;
+       int rc;
+
+       if (exynos_camera == NULL || index < 0)
+               return -EINVAL;
+
+       buffer.type = type;
+       buffer.memory = memory;
+       buffer.index = index;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QBUF, &buffer);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_qbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index)
+{
+       return exynos_v4l2_qbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               V4L2_MEMORY_MMAP, index);
+}
+
+int exynos_v4l2_qbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index)
+{
+       return exynos_v4l2_qbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               V4L2_MEMORY_USERPTR, index);
+}
+
+int exynos_v4l2_dqbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int memory)
+{
+       struct v4l2_buffer buffer;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       memset(&buffer, 0, sizeof(buffer));
+       buffer.type = type;
+       buffer.memory = memory;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_DQBUF, &buffer);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return buffer.index;
+}
+
+int exynos_v4l2_dqbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_dqbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               V4L2_MEMORY_MMAP);
+}
+
+int exynos_v4l2_dqbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_dqbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               V4L2_MEMORY_USERPTR);
+}
+
+int exynos_v4l2_reqbufs(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int memory, int count)
+{
+       struct v4l2_requestbuffers requestbuffers;
+       int rc;
+
+       if (exynos_camera == NULL || count < 0)
+               return -EINVAL;
+
+       requestbuffers.type = type;
+       requestbuffers.count = count;
+       requestbuffers.memory = memory;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_REQBUFS, &requestbuffers);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return requestbuffers.count;
+}
+
+int exynos_v4l2_reqbufs_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int count)
+{
+       return exynos_v4l2_reqbufs(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               V4L2_MEMORY_MMAP, count);
+}
+
+int exynos_v4l2_reqbufs_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int count)
+{
+       return exynos_v4l2_reqbufs(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               V4L2_MEMORY_USERPTR, count);
+}
+
+int exynos_v4l2_querybuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int memory, int index)
+{
+       struct v4l2_buffer buffer;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       memset(&buffer, 0, sizeof(buffer));
+       buffer.type = type;
+       buffer.memory = memory;
+       buffer.index = index;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QUERYBUF, &buffer);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return buffer.length;
+}
+
+int exynos_v4l2_querybuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index)
+{
+       return exynos_v4l2_querybuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               V4L2_MEMORY_MMAP, index);
+}
+
+int exynos_v4l2_querybuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index)
+{
+       return exynos_v4l2_querybuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               V4L2_MEMORY_USERPTR, index);
+}
+
+int exynos_v4l2_querycap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int flags)
+{
+       struct v4l2_capability cap;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QUERYCAP, &cap);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (!(cap.capabilities & flags))
+               return -1;
+
+       return 0;
+}
+
+int exynos_v4l2_querycap_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_querycap(exynos_camera, exynos_v4l2_id, V4L2_CAP_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_querycap_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_querycap(exynos_camera, exynos_v4l2_id, V4L2_CAP_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_streamon(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type)
+{
+       enum v4l2_buf_type buf_type;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       buf_type = type;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_STREAMON, &buf_type);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_streamon_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_streamon(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_streamon_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_streamon(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_streamoff(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type)
+{
+       enum v4l2_buf_type buf_type;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       buf_type = type;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_STREAMOFF, &buf_type);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_streamoff_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_streamoff(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_streamoff_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_streamoff(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_g_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int *width, int *height, int *fmt)
+{
+       struct v4l2_format format;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       format.type = type;
+       format.fmt.pix.field = V4L2_FIELD_NONE;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_G_FMT, &format);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (width != NULL)
+               *width = format.fmt.pix.width;
+       if (height != NULL)
+               *height = format.fmt.pix.height;
+       if (fmt != NULL)
+               *fmt = format.fmt.pix.pixelformat;
+
+       return 0;
+}
+
+int exynos_v4l2_g_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int *width, int *height, int *fmt)
+{
+       return exynos_v4l2_g_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               width, height, fmt);
+}
+
+int exynos_v4l2_g_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int *width, int *height, int *fmt)
+{
+       return exynos_v4l2_g_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               width, height, fmt);
+}
+
+int exynos_v4l2_s_fmt_pix(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int width, int height, int fmt, int priv)
+{
+       struct v4l2_format format;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       memset(&format, 0, sizeof(format));
+       format.type = type;
+       format.fmt.pix.width = width;
+       format.fmt.pix.height = height;
+       format.fmt.pix.pixelformat = fmt;
+       format.fmt.pix.field = V4L2_FIELD_NONE;
+       format.fmt.pix.priv = priv;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_FMT, &format);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_s_fmt_pix_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int width, int height, int fmt, int priv)
+{
+       return exynos_v4l2_s_fmt_pix(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               width, height, fmt, priv);
+}
+
+int exynos_v4l2_s_fmt_pix_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int width, int height, int fmt, int priv)
+{
+       return exynos_v4l2_s_fmt_pix(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               width, height, fmt, priv);
+}
+
+int exynos_v4l2_s_fmt_win(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int left, int top, int width, int height)
+{
+       struct v4l2_format format;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       memset(&format, 0, sizeof(format));
+       format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+       format.fmt.win.w.left = left;
+       format.fmt.win.w.top = top;
+       format.fmt.win.w.width = width;
+       format.fmt.win.w.height = height;
+
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_FMT, &format);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_enum_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int fmt)
+{
+       struct v4l2_fmtdesc fmtdesc;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       fmtdesc.type = type;
+       fmtdesc.index = 0;
+
+       do {
+               rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_ENUM_FMT, &fmtdesc);
+               if (rc < 0) {
+                       LOGE("%s: ioctl failed", __func__);
+                       return -1;
+               }
+
+               if (fmtdesc.pixelformat == (unsigned int) fmt)
+                       return 0;
+
+               fmtdesc.index++;
+       } while (rc >= 0);
+
+       return -1;
+}
+
+int exynos_v4l2_enum_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int fmt)
+{
+       return exynos_v4l2_enum_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               fmt);
+}
+
+int exynos_v4l2_enum_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int fmt)
+{
+       return exynos_v4l2_enum_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               fmt);
+}
+
+int exynos_v4l2_enum_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id)
+{
+       struct v4l2_input input;
+       int rc;
+
+       if (exynos_camera == NULL || id < 0)
+               return -EINVAL;
+
+       input.index = id;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_ENUMINPUT, &input);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (input.name[0] == '\0')
+               return -1;
+
+       return 0;
+}
+
+int exynos_v4l2_s_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id)
+{
+       struct v4l2_input input;
+       int rc;
+
+       if (exynos_camera == NULL || id < 0)
+               return -EINVAL;
+
+       input.index = id;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_INPUT, &input);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_g_ext_ctrls(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_ext_control *control, int count)
+{
+       struct v4l2_ext_controls controls;
+       int rc;
+
+       if (exynos_camera == NULL || control == NULL)
+               return -EINVAL;
+
+       memset(&controls, 0, sizeof(controls));
+       controls.ctrl_class = V4L2_CTRL_CLASS_CAMERA;
+       controls.count = count;
+       controls.controls = control;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_G_EXT_CTRLS, &controls);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_g_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id, int *value)
+{
+       struct v4l2_control control;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       control.id = id;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_G_CTRL, &control);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (value != NULL)
+               *value = control.value;
+
+       return 0;
+}
+
+int exynos_v4l2_s_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id, int value)
+{
+       struct v4l2_control control;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       control.id = id;
+       control.value = value;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_CTRL, &control);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return control.value;
+}
+
+int exynos_v4l2_s_parm(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, struct v4l2_streamparm *streamparm)
+{
+       int rc;
+
+       if (exynos_camera == NULL || streamparm == NULL)
+               return -EINVAL;
+
+       streamparm->type = type;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_PARM, streamparm);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_s_parm_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_streamparm *streamparm)
+{
+       return exynos_v4l2_s_parm(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               streamparm);
+}
+
+int exynos_v4l2_s_parm_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_streamparm *streamparm)
+{
+       return exynos_v4l2_s_parm(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               streamparm);
+}
+
+int exynos_v4l2_s_crop(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int left, int top, int width, int height)
+{
+       struct v4l2_crop crop;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       crop.type = type;
+       crop.c.left = left;
+       crop.c.top = top;
+       crop.c.width = width;
+       crop.c.height = height;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_CROP, &crop);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_s_crop_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int left, int top, int width, int height)
+{
+       return exynos_v4l2_s_crop(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               left, top, width, height);
+}
+
+int exynos_v4l2_s_crop_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int left, int top, int width, int height)
+{
+       return exynos_v4l2_s_crop(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               left, top, width, height);
+}
+
+int exynos_v4l2_g_fbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       void **base, int *width, int *height, int *fmt)
+{
+       struct v4l2_framebuffer framebuffer;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_G_FBUF, &framebuffer);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (base != NULL)
+               *base = framebuffer.base;
+       if (width != NULL)
+               *width = framebuffer.fmt.width;
+       if (height != NULL)
+               *height = framebuffer.fmt.height;
+       if (fmt != NULL)
+               *fmt = framebuffer.fmt.pixelformat;
+
+       return 0;
+}
+
+int exynos_v4l2_s_fbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       void *base, int width, int height, int fmt)
+{
+       struct v4l2_framebuffer framebuffer;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       memset(&framebuffer, 0, sizeof(framebuffer));
+       framebuffer.base = base;
+       framebuffer.fmt.width = width;
+       framebuffer.fmt.height = height;
+       framebuffer.fmt.pixelformat = fmt;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_FBUF, &framebuffer);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/include/linux/videodev2_samsung.h b/include/linux/videodev2_samsung.h
new file mode 100644 (file)
index 0000000..43b1668
--- /dev/null
@@ -0,0 +1,1181 @@
+/*
+ * Video for Linux Two header file for samsung
+ *
+ * Copyright (C) 2009, Dongsoo Nathaniel Kim<dongsoo45.kim@samsung.com>
+ *
+ * This header file contains several v4l2 APIs to be proposed to v4l2
+ * community and until bein accepted, will be used restrictly in Samsung's
+ * camera interface driver FIMC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_VIDEODEV2_SAMSUNG_H
+#define __LINUX_VIDEODEV2_SAMSUNG_H
+
+/* Values for 'capabilities' field */
+/* Object detection device */
+#define V4L2_CAP_OBJ_RECOGNITION       0x10000000
+/* strobe control */
+#define V4L2_CAP_STROBE                        0x20000000
+
+#define V4L2_CID_FOCUS_MODE            (V4L2_CID_CAMERA_CLASS_BASE+17)
+/* Focus Methods */
+enum v4l2_focus_mode {
+       V4L2_FOCUS_MODE_AUTO            = 0,
+       V4L2_FOCUS_MODE_MACRO           = 1,
+       V4L2_FOCUS_MODE_MANUAL          = 2,
+       V4L2_FOCUS_MODE_LASTP           = 2,
+};
+
+#define V4L2_CID_ZOOM_MODE             (V4L2_CID_CAMERA_CLASS_BASE+18)
+/* Zoom Methods */
+enum v4l2_zoom_mode {
+       V4L2_ZOOM_MODE_CONTINUOUS       = 0,
+       V4L2_ZOOM_MODE_OPTICAL          = 1,
+       V4L2_ZOOM_MODE_DIGITAL          = 2,
+       V4L2_ZOOM_MODE_LASTP            = 2,
+};
+
+/* Exposure Methods */
+#define V4L2_CID_PHOTOMETRY            (V4L2_CID_CAMERA_CLASS_BASE+19)
+enum v4l2_photometry_mode {
+       V4L2_PHOTOMETRY_MULTISEG        = 0, /*Multi Segment*/
+       V4L2_PHOTOMETRY_CWA             = 1, /*Centre Weighted Average*/
+       V4L2_PHOTOMETRY_SPOT            = 2,
+       V4L2_PHOTOMETRY_AFSPOT          = 3, /*Spot metering on focused point*/
+       V4L2_PHOTOMETRY_LASTP           = V4L2_PHOTOMETRY_AFSPOT,
+};
+
+/* Manual exposure control items menu type: iris, shutter, iso */
+#define V4L2_CID_CAM_APERTURE  (V4L2_CID_CAMERA_CLASS_BASE+20)
+#define V4L2_CID_CAM_SHUTTER   (V4L2_CID_CAMERA_CLASS_BASE+21)
+#define V4L2_CID_CAM_ISO       (V4L2_CID_CAMERA_CLASS_BASE+22)
+
+/* Following CIDs are menu type */
+#define V4L2_CID_SCENEMODE     (V4L2_CID_CAMERA_CLASS_BASE+23)
+#define V4L2_CID_CAM_STABILIZE (V4L2_CID_CAMERA_CLASS_BASE+24)
+#define V4L2_CID_CAM_MULTISHOT (V4L2_CID_CAMERA_CLASS_BASE+25)
+
+/* Control dynamic range */
+#define V4L2_CID_CAM_DR                (V4L2_CID_CAMERA_CLASS_BASE+26)
+
+/* White balance preset control */
+#define V4L2_CID_WHITE_BALANCE_PRESET (V4L2_CID_CAMERA_CLASS_BASE+27)
+#define V4L2_CID_CAM_SENSOR_FW_VER (V4L2_CID_CAMERA_CLASS_BASE + 28)
+#define V4L2_CID_CAM_PHONE_FW_VER (V4L2_CID_CAMERA_CLASS_BASE + 29)
+
+/* CID extensions */
+#define V4L2_CID_ROTATION              (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PADDR_Y               (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PADDR_CB              (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PADDR_CR              (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PADDR_CBCR            (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_OVERLAY_AUTO          (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_OVERLAY_VADDR0                (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_OVERLAY_VADDR1                (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_OVERLAY_VADDR2                (V4L2_CID_PRIVATE_BASE + 8)
+#define V4L2_CID_OVLY_MODE             (V4L2_CID_PRIVATE_BASE + 9)
+#define V4L2_CID_DST_INFO              (V4L2_CID_PRIVATE_BASE + 10)
+/* UMP secure id control */
+#define V4L2_CID_GET_UMP_SECURE_ID     (V4L2_CID_PRIVATE_BASE + 11)
+#define V4L2_CID_GET_PHY_SRC_YADDR     (V4L2_CID_PRIVATE_BASE + 12)
+#define V4L2_CID_GET_PHY_SRC_CADDR     (V4L2_CID_PRIVATE_BASE + 13)
+#define V4L2_CID_IMAGE_EFFECT_FN       (V4L2_CID_PRIVATE_BASE + 16)
+#define V4L2_CID_IMAGE_EFFECT_APPLY    (V4L2_CID_PRIVATE_BASE + 17)
+#define V4L2_CID_IMAGE_EFFECT_CB       (V4L2_CID_PRIVATE_BASE + 18)
+#define V4L2_CID_IMAGE_EFFECT_CR       (V4L2_CID_PRIVATE_BASE + 19)
+#define V4L2_CID_RESERVED_MEM_BASE_ADDR        (V4L2_CID_PRIVATE_BASE + 20)
+#define V4L2_CID_FIMC_VERSION          (V4L2_CID_PRIVATE_BASE + 21)
+
+#define V4L2_CID_CACHE_FLUSH           (V4L2_CID_PRIVATE_BASE + 61)
+#define V4L2_CID_RESERVED_MEM_SIZE     (V4L2_CID_PRIVATE_BASE + 63)
+#define V4L2_CID_STREAM_PAUSE                  (V4L2_CID_PRIVATE_BASE + 53)
+
+/* CID Extensions for camera sensor operations */
+#define V4L2_CID_CAM_PREVIEW_ONOFF             (V4L2_CID_PRIVATE_BASE + 64)
+#define V4L2_CID_CAM_CAPTURE                   (V4L2_CID_PRIVATE_BASE + 65)
+/*#define V4L2_CID_CAM_JPEG_MEMSIZE    (V4L2_CID_PRIVATE_BASE + 66)*/
+
+#define V4L2_CID_CAM_DATE_INFO_YEAR            (V4L2_CID_PRIVATE_BASE + 14)
+#define V4L2_CID_CAM_DATE_INFO_MONTH   (V4L2_CID_PRIVATE_BASE + 15)
+#define V4L2_CID_CAM_DATE_INFO_DATE            (V4L2_CID_PRIVATE_BASE + 22)
+#define V4L2_CID_CAM_SENSOR_VER                        (V4L2_CID_PRIVATE_BASE + 23)
+#define V4L2_CID_CAM_FW_MINOR_VER              (V4L2_CID_PRIVATE_BASE + 24)
+#define V4L2_CID_CAM_FW_MAJOR_VER              (V4L2_CID_PRIVATE_BASE + 25)
+#define V4L2_CID_CAM_PRM_MINOR_VER             (V4L2_CID_PRIVATE_BASE + 26)
+#define V4L2_CID_CAM_PRM_MAJOR_VER             (V4L2_CID_PRIVATE_BASE + 27)
+#define V4L2_CID_CAM_FW_VER                    (V4L2_CID_PRIVATE_BASE + 28)
+#define V4L2_CID_CAM_SET_FW_ADDR               (V4L2_CID_PRIVATE_BASE + 29)
+#define V4L2_CID_CAM_SET_FW_SIZE                (V4L2_CID_PRIVATE_BASE + 30)
+#define V4L2_CID_CAM_UPDATE_FW (V4L2_CID_PRIVATE_BASE + 31)
+enum v4l2_firmware_mode {
+       FW_MODE_NONE,
+       FW_MODE_VERSION,
+       FW_MODE_UPDATE,
+       FW_MODE_DUMP,
+};
+
+#define V4L2_CID_CAM_JPEG_MAIN_SIZE            (V4L2_CID_PRIVATE_BASE + 32)
+#define V4L2_CID_CAM_JPEG_MAIN_OFFSET          (V4L2_CID_PRIVATE_BASE + 33)
+#define V4L2_CID_CAM_JPEG_THUMB_SIZE           (V4L2_CID_PRIVATE_BASE + 34)
+#define V4L2_CID_CAM_JPEG_THUMB_OFFSET         (V4L2_CID_PRIVATE_BASE + 35)
+#define V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET      (V4L2_CID_PRIVATE_BASE + 36)
+#define V4L2_CID_CAM_JPEG_QUALITY      (V4L2_CID_PRIVATE_BASE + 37)
+#define V4L2_CID_CAM_SENSOR_MAKER      (V4L2_CID_PRIVATE_BASE + 38)
+#define V4L2_CID_CAM_SENSOR_OPTICAL    (V4L2_CID_PRIVATE_BASE + 39)
+#define V4L2_CID_CAM_AF_VER_LOW                (V4L2_CID_PRIVATE_BASE + 40)
+#define V4L2_CID_CAM_AF_VER_HIGH       (V4L2_CID_PRIVATE_BASE + 41)
+#define V4L2_CID_CAM_GAMMA_RG_LOW      (V4L2_CID_PRIVATE_BASE + 42)
+#define V4L2_CID_CAM_GAMMA_RG_HIGH     (V4L2_CID_PRIVATE_BASE + 43)
+#define V4L2_CID_CAM_GAMMA_BG_LOW      (V4L2_CID_PRIVATE_BASE + 44)
+#define V4L2_CID_CAM_GAMMA_BG_HIGH     (V4L2_CID_PRIVATE_BASE + 45)
+#define V4L2_CID_CAM_DUMP_FW           (V4L2_CID_PRIVATE_BASE + 46)
+#define V4L2_CID_CAM_GET_DUMP_SIZE  (V4L2_CID_PRIVATE_BASE + 47)
+#define V4L2_CID_CAMERA_VT_MODE                (V4L2_CID_PRIVATE_BASE + 48)
+enum cam_vt_mode {
+       CAM_VT_MODE_NONE ,
+       CAM_VT_MODE_3G ,
+       CAM_VT_MODE_VOIP ,
+};
+
+#define V4L2_CID_CAMERA_VGA_BLUR       (V4L2_CID_PRIVATE_BASE + 49)
+#define V4L2_CID_CAMERA_CAPTURE                (V4L2_CID_PRIVATE_BASE + 50)
+#define V4L2_CID_CAMERA_HDR            (V4L2_CID_PRIVATE_BASE + 51)
+
+#define V4L2_CID_MAIN_SW_DATE_INFO_YEAR                (V4L2_CID_PRIVATE_BASE + 54)
+#define V4L2_CID_MAIN_SW_DATE_INFO_MONTH       (V4L2_CID_PRIVATE_BASE + 55)
+#define V4L2_CID_MAIN_SW_DATE_INFO_DATE                (V4L2_CID_PRIVATE_BASE + 56)
+#define V4L2_CID_MAIN_SW_FW_MINOR_VER          (V4L2_CID_PRIVATE_BASE + 57)
+#define V4L2_CID_MAIN_SW_FW_MAJOR_VER          (V4L2_CID_PRIVATE_BASE + 58)
+#define V4L2_CID_MAIN_SW_PRM_MINOR_VER         (V4L2_CID_PRIVATE_BASE + 59)
+#define V4L2_CID_MAIN_SW_PRM_MAJOR_VER         (V4L2_CID_PRIVATE_BASE + 60)
+
+#define V4L2_CID_FIMC_IS_BASE   (V4L2_CTRL_CLASS_CAMERA | 0x1000)
+
+#define V4L2_CID_IS_LOAD_FW                    (V4L2_CID_FIMC_IS_BASE + 10)
+#define V4L2_CID_IS_INIT_PARAM                 (V4L2_CID_FIMC_IS_BASE + 11)
+#define V4L2_CID_IS_RESET                      (V4L2_CID_FIMC_IS_BASE + 12)
+#define V4L2_CID_IS_S_POWER                    (V4L2_CID_FIMC_IS_BASE + 13)
+enum is_set_power {
+       IS_POWER_OFF,
+       IS_POWER_ON
+};
+
+#define V4L2_CID_IS_S_STREAM                   (V4L2_CID_FIMC_IS_BASE + 14)
+enum is_set_stream {
+       IS_DISABLE_STREAM,
+       IS_ENABLE_STREAM
+};
+
+#define V4L2_CID_IS_S_SCENARIO_MODE            (V4L2_CID_FIMC_IS_BASE + 15)
+#define V4L2_CID_IS_S_FORMAT_SCENARIO          (V4L2_CID_FIMC_IS_BASE + 16)
+enum scenario_mode {
+       IS_MODE_PREVIEW_STILL,
+       IS_MODE_PREVIEW_VIDEO,
+       IS_MODE_CAPTURE_STILL,
+       IS_MODE_CAPTURE_VIDEO,
+       IS_MODE_MAX
+};
+
+/* global */
+#define V4L2_CID_IS_CAMERA_SHOT_MODE_NORMAL    (V4L2_CID_FIMC_IS_BASE + 101)
+/* value : 1 : single shot , >=2 : continuous shot */
+
+#define V4L2_CID_IS_CAMERA_SENSOR_NUM          (V4L2_CID_FIMC_IS_BASE + 201)
+
+#define V4L2_CID_IS_CAMERA_FOCUS_MODE          (V4L2_CID_FIMC_IS_BASE + 401)
+enum is_focus_mode {
+       IS_FOCUS_MODE_AUTO,
+       IS_FOCUS_MODE_MACRO,
+       IS_FOCUS_MODE_INFINITY,
+       IS_FOCUS_MODE_CONTINUOUS,
+       IS_FOCUS_MODE_TOUCH,
+       IS_FOCUS_MODE_FACEDETECT,
+       IS_FOCUS_MODE_MAX,
+};
+
+#define V4L2_CID_IS_CAMERA_FLASH_MODE          (V4L2_CID_FIMC_IS_BASE + 402)
+enum is_flash_mode {
+       IS_FLASH_MODE_OFF,
+       IS_FLASH_MODE_AUTO,
+       IS_FLASH_MODE_AUTO_REDEYE,
+       IS_FLASH_MODE_ON,
+       IS_FLASH_MODE_TORCH,
+       IS_FLASH_MODE_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_AWB_MODE            (V4L2_CID_FIMC_IS_BASE + 403)
+enum is_awb_mode {
+       IS_AWB_AUTO,
+       IS_AWB_DAYLIGHT,
+       IS_AWB_CLOUDY,
+       IS_AWB_TUNGSTEN,
+       IS_AWB_FLUORESCENT,
+       IS_AWB_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_IMAGE_EFFECT                (V4L2_CID_FIMC_IS_BASE + 404)
+enum is_image_effect {
+       IS_IMAGE_EFFECT_DISABLE,
+       IS_IMAGE_EFFECT_MONOCHROME,
+       IS_IMAGE_EFFECT_NEGATIVE_MONO,
+       IS_IMAGE_EFFECT_NEGATIVE_COLOR,
+       IS_IMAGE_EFFECT_SEPIA,
+       IS_IMAGE_EFFECT_SEPIA_CB,
+       IS_IMAGE_EFFECT_SEPIA_CR,
+       IS_IMAGE_EFFECT_NEGATIVE,
+       IS_IMAGE_EFFECT_ARTFREEZE,
+       IS_IMAGE_EFFECT_EMBOSSING,
+       IS_IMAGE_EFFECT_SILHOUETTE,
+       IS_IMAGE_EFFECT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_ISO                 (V4L2_CID_FIMC_IS_BASE + 405)
+enum is_iso {
+       IS_ISO_AUTO,
+       IS_ISO_50,
+       IS_ISO_100,
+       IS_ISO_200,
+       IS_ISO_400,
+       IS_ISO_800,
+       IS_ISO_1600,
+       IS_ISO_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_CONTRAST            (V4L2_CID_FIMC_IS_BASE + 406)
+enum is_contrast {
+       IS_CONTRAST_AUTO,
+       IS_CONTRAST_MINUS_2,
+       IS_CONTRAST_MINUS_1,
+       IS_CONTRAST_DEFAULT,
+       IS_CONTRAST_PLUS_1,
+       IS_CONTRAST_PLUS_2,
+       IS_CONTRAST_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_SATURATION          (V4L2_CID_FIMC_IS_BASE + 407)
+enum is_saturation {
+       IS_SATURATION_MINUS_2,
+       IS_SATURATION_MINUS_1,
+       IS_SATURATION_DEFAULT,
+       IS_SATURATION_PLUS1,
+       IS_SATURATION_PLUS2,
+       IS_SATURATION_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_SHARPNESS           (V4L2_CID_FIMC_IS_BASE + 408)
+enum is_sharpness {
+       IS_SHARPNESS_MINUS_2,
+       IS_SHARPNESS_MINUS_1,
+       IS_SHARPNESS_DEFAULT,
+       IS_SHARPNESS_PLUS1,
+       IS_SHARPNESS_PLUS2,
+       IS_SHARPNESS_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_EXPOSURE            (V4L2_CID_FIMC_IS_BASE + 409)
+enum is_exposure {
+       IS_EXPOSURE_MINUS_2,
+       IS_EXPOSURE_MINUS_1,
+       IS_EXPOSURE_DEFAULT,
+       IS_EXPOSURE_PLUS1,
+       IS_EXPOSURE_PLUS2,
+       IS_EXPOSURE_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_BRIGHTNESS          (V4L2_CID_FIMC_IS_BASE + 410)
+enum is_brightness {
+       IS_BRIGHTNESS_MINUS_2,
+       IS_BRIGHTNESS_MINUS_1,
+       IS_BRIGHTNESS_DEFAULT,
+       IS_BRIGHTNESS_PLUS1,
+       IS_BRIGHTNESS_PLUS2,
+       IS_BRIGHTNESS_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_HUE                 (V4L2_CID_FIMC_IS_BASE + 411)
+enum is_hue {
+       IS_HUE_MINUS_2,
+       IS_HUE_MINUS_1,
+       IS_HUE_DEFAULT,
+       IS_HUE_PLUS1,
+       IS_HUE_PLUS2,
+       IS_HUE_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_METERING            (V4L2_CID_FIMC_IS_BASE + 412)
+enum is_metering {
+       IS_METERING_AVERAGE,
+       IS_METERING_SPOT,
+       IS_METERING_MATRIX,
+       IS_METERING_CENTER,
+       IS_METERING_MAX
+};
+#define V4L2_CID_IS_CAMERA_METERING_POSITION_X (V4L2_CID_FIMC_IS_BASE + 500)
+#define V4L2_CID_IS_CAMERA_METERING_POSITION_Y (V4L2_CID_FIMC_IS_BASE + 501)
+#define V4L2_CID_IS_CAMERA_METERING_WINDOW_X   (V4L2_CID_FIMC_IS_BASE + 502)
+#define V4L2_CID_IS_CAMERA_METERING_WINDOW_Y   (V4L2_CID_FIMC_IS_BASE + 503)
+
+#define V4L2_CID_IS_CAMERA_AFC_MODE            (V4L2_CID_FIMC_IS_BASE + 413)
+enum is_afc_mode {
+       IS_AFC_DISABLE,
+       IS_AFC_AUTO,
+       IS_AFC_MANUAL_50HZ,
+       IS_AFC_MANUAL_60HZ,
+       IS_AFC_MAX
+};
+
+#define V4L2_CID_IS_FD_GET_FACE_COUNT    (V4L2_CID_FIMC_IS_BASE + 600)
+#define V4L2_CID_IS_FD_GET_FACE_FRAME_NUMBER    (V4L2_CID_FIMC_IS_BASE + 601)
+#define V4L2_CID_IS_FD_GET_FACE_CONFIDENCE    (V4L2_CID_FIMC_IS_BASE + 602)
+#define V4L2_CID_IS_FD_GET_FACE_SMILE_LEVEL    (V4L2_CID_FIMC_IS_BASE + 603)
+#define V4L2_CID_IS_FD_GET_FACE_BLINK_LEVEL    (V4L2_CID_FIMC_IS_BASE + 604)
+#define V4L2_CID_IS_FD_GET_FACE_TOPLEFT_X    (V4L2_CID_FIMC_IS_BASE + 605)
+#define V4L2_CID_IS_FD_GET_FACE_TOPLEFT_Y    (V4L2_CID_FIMC_IS_BASE + 606)
+#define V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_X    (V4L2_CID_FIMC_IS_BASE + 607)
+#define V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_Y    (V4L2_CID_FIMC_IS_BASE + 608)
+#define V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_X    (V4L2_CID_FIMC_IS_BASE + 609)
+#define V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_Y    (V4L2_CID_FIMC_IS_BASE + 610)
+#define V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_X  (V4L2_CID_FIMC_IS_BASE + 611)
+#define V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_Y  (V4L2_CID_FIMC_IS_BASE + 612)
+#define V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_X    (V4L2_CID_FIMC_IS_BASE + 613)
+#define V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_Y    (V4L2_CID_FIMC_IS_BASE + 614)
+#define V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_X (V4L2_CID_FIMC_IS_BASE + 615)
+#define V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_Y (V4L2_CID_FIMC_IS_BASE + 616)
+#define V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_X    (V4L2_CID_FIMC_IS_BASE + 617)
+#define V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_Y    (V4L2_CID_FIMC_IS_BASE + 618)
+#define V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_X  (V4L2_CID_FIMC_IS_BASE + 619)
+#define V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_Y  (V4L2_CID_FIMC_IS_BASE + 620)
+#define V4L2_CID_IS_FD_GET_ANGLE    (V4L2_CID_FIMC_IS_BASE + 621)
+#define V4L2_CID_IS_FD_GET_YAW_ANGLE    (V4L2_CID_FIMC_IS_BASE + 622)
+#define V4L2_CID_IS_FD_GET_NEXT    (V4L2_CID_FIMC_IS_BASE + 623)
+#define V4L2_CID_IS_FD_GET_DATA    (V4L2_CID_FIMC_IS_BASE + 624)
+
+#define V4L2_CID_IS_FD_SET_MAX_FACE_NUMBER    (V4L2_CID_FIMC_IS_BASE + 650)
+#define V4L2_CID_IS_FD_SET_ROLL_ANGLE    (V4L2_CID_FIMC_IS_BASE + 651)
+
+enum is_fd_roll_angle {
+       /* 0, 45, 0, -45 */
+       IS_FD_ROLL_ANGLE_BASIC          = 0,
+       /* 0, 30, 0, -30, 0, 45, 0, -45 */
+       IS_FD_ROLL_ANGLE_PRECISE_BASIC  = 1,
+       /* 0, 90, 0, -90 */
+       IS_FD_ROLL_ANGLE_SIDES          = 2,
+       /* 0, 90, 0, -90 0, 45, 0, -45 */
+       IS_FD_ROLL_ANGLE_PRECISE_SIDES  = 3,
+       /* 0, 90, 0, -90, 0, 180 */
+       IS_FD_ROLL_ANGLE_FULL           = 4,
+       /* 0, 90, 0, -90, 0, 180, 0, 135, 0, -135 */
+       IS_FD_ROLL_ANGLE_PRECISE_FULL   = 5,
+};
+
+#define V4L2_CID_IS_FD_SET_YAW_ANGLE   (V4L2_CID_FIMC_IS_BASE + 652)
+enum is_fd_yaw_angle {
+       IS_FD_YAW_ANGLE_0       = 0,
+       IS_FD_YAW_ANGLE_45      = 1,
+       IS_FD_YAW_ANGLE_90      = 2,
+       IS_FD_YAW_ANGLE_45_90   = 3,
+};
+
+#define V4L2_CID_IS_FD_SET_SMILE_MODE  (V4L2_CID_FIMC_IS_BASE + 653)
+enum is_fd_smile_mode {
+       IS_FD_SMILE_MODE_DISABLE        = 0,
+       IS_FD_SMILE_MODE_ENABLE         = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_BLINK_MODE  (V4L2_CID_FIMC_IS_BASE + 654)
+enum is_fd_blink_mode {
+       IS_FD_BLINK_MODE_DISABLE        = 0,
+       IS_FD_BLINK_MODE_ENABLE         = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_EYE_DETECT_MODE     (V4L2_CID_FIMC_IS_BASE + 655)
+enum is_fd_eye_detect_mode {
+       IS_FD_EYE_DETECT_DISABLE        = 0,
+       IS_FD_EYE_DETECT_ENABLE         = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_MOUTH_DETECT_MODE   (V4L2_CID_FIMC_IS_BASE + 656)
+enum is_fd_mouth_detect_mode {
+       IS_FD_MOUTH_DETECT_DISABLE      = 0,
+       IS_FD_MOUTH_DETECT_ENABLE       = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_ORIENTATION_MODE  (V4L2_CID_FIMC_IS_BASE + 657)
+enum is_fd_orientation_mode {
+       IS_FD_ORIENTATION_DISABLE       = 0,
+       IS_FD_ORIENTATION_ENABLE        = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_ORIENTATION (V4L2_CID_FIMC_IS_BASE + 658)
+#define V4L2_CID_IS_FD_SET_DATA_ADDRESS        (V4L2_CID_FIMC_IS_BASE + 659)
+
+#define V4L2_CID_IS_SET_ISP                    (V4L2_CID_FIMC_IS_BASE + 440)
+enum is_isp_bypass_mode {
+       IS_ISP_BYPASS_DISABLE,
+       IS_ISP_BYPASS_ENABLE,
+       IS_ISP_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_DRC                    (V4L2_CID_FIMC_IS_BASE + 441)
+enum is_drc_bypass_mode {
+       IS_DRC_BYPASS_DISABLE,
+       IS_DRC_BYPASS_ENABLE,
+       IS_DRC_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_FD                     (V4L2_CID_FIMC_IS_BASE + 442)
+enum is_fd_bypass_mode {
+       IS_FD_BYPASS_DISABLE,
+       IS_FD_BYPASS_ENABLE,
+       IS_FD_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_ODC                    (V4L2_CID_FIMC_IS_BASE + 443)
+enum is_odc_bypass_mode {
+       IS_ODC_BYPASS_DISABLE,
+       IS_ODC_BYPASS_ENABLE,
+       IS_ODC_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_DIS                    (V4L2_CID_FIMC_IS_BASE + 444)
+enum is_dis_bypass_mode {
+       IS_DIS_BYPASS_DISABLE,
+       IS_DIS_BYPASS_ENABLE,
+       IS_DIS_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_3DNR                   (V4L2_CID_FIMC_IS_BASE + 445)
+enum is_tdnr_bypass_mode {
+       IS_TDNR_BYPASS_DISABLE,
+       IS_TDNR_BYPASS_ENABLE,
+       IS_TDNR_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_SCALERC                        (V4L2_CID_FIMC_IS_BASE + 446)
+enum is_scalerc_bypass_mode {
+       IS_SCALERC_BYPASS_DISABLE,
+       IS_SCALERC_BYPASS_ENABLE,
+       IS_SCALERC_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_SCALERP                        (V4L2_CID_FIMC_IS_BASE + 446)
+enum is_scalerp_bypass_mode {
+       IS_SCALERP_BYPASS_DISABLE,
+       IS_SCALERP_BYPASS_ENABLE,
+       IS_SCALERP_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_ROTATION_MODE              (V4L2_CID_FIMC_IS_BASE + 450)
+enum is_rotation_mode {
+       IS_ROTATION_0,
+       IS_ROTATION_90,
+       IS_ROTATION_180,
+       IS_ROTATION_270,
+       IS_ROTATION_MAX
+};
+
+#define V4L2_CID_IS_3DNR_1ST_FRAME_MODE                (V4L2_CID_FIMC_IS_BASE + 451)
+enum is_tdnr_1st_frame_mode {
+       IS_TDNR_1ST_FRAME_NOPROCESSING,
+       IS_TDNR_1ST_FRAME_2DNR,
+       IS_TDNR_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_OBJECT_POSITION_X   (V4L2_CID_FIMC_IS_BASE + 452)
+#define V4L2_CID_IS_CAMERA_OBJECT_POSITION_Y   (V4L2_CID_FIMC_IS_BASE + 453)
+#define V4L2_CID_IS_CAMERA_WINDOW_SIZE_X       (V4L2_CID_FIMC_IS_BASE + 454)
+#define V4L2_CID_IS_CAMERA_WINDOW_SIZE_Y       (V4L2_CID_FIMC_IS_BASE + 455)
+
+#define V4L2_CID_IS_CAMERA_EXIF_EXPTIME                (V4L2_CID_FIMC_IS_BASE + 456)
+#define V4L2_CID_IS_CAMERA_EXIF_FLASH          (V4L2_CID_FIMC_IS_BASE + 457)
+#define V4L2_CID_IS_CAMERA_EXIF_ISO            (V4L2_CID_FIMC_IS_BASE + 458)
+#define V4L2_CID_IS_CAMERA_EXIF_SHUTTERSPEED   (V4L2_CID_FIMC_IS_BASE + 459)
+#define V4L2_CID_IS_CAMERA_EXIF_BRIGHTNESS     (V4L2_CID_FIMC_IS_BASE + 460)
+
+#define V4L2_CID_IS_CAMERA_ISP_SEL_INPUT       (V4L2_CID_FIMC_IS_BASE + 461)
+enum is_isp_sel_input {
+       IS_ISP_INPUT_OTF,
+       IS_ISP_INPUT_DMA1,
+       IS_ISP_INPUT_DMA2,
+       IS_ISP_INPUT_DMA12,
+       IS_ISP_INPUT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_ISP_SEL_OUTPUT      (V4L2_CID_FIMC_IS_BASE + 462)
+enum is_isp_sel_output {
+       IS_ISP_OUTPUT_OTF,
+       IS_ISP_OUTPUT_DMA1,
+       IS_ISP_OUTPUT_DMA2,
+       IS_ISP_OUTPUT_DMA12,
+       IS_ISP_OUTPUT_OTF_DMA1,
+       IS_ISP_OUTPUT_OTF_DMA2,
+       IS_ISP_OUTPUT_OTF_DMA12,
+       IS_ISP_OUTPUT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_DRC_SEL_INPUT       (V4L2_CID_FIMC_IS_BASE + 463)
+enum is_drc_sel_input {
+       IS_DRC_INPUT_OTF,
+       IS_DRC_INPUT_DMA,
+       IS_DRC_INPUT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_FD_SEL_INPUT                (V4L2_CID_FIMC_IS_BASE + 464)
+enum is_fd_sel_input {
+       IS_FD_INPUT_OTF,
+       IS_FD_INPUT_DMA,
+       IS_FD_INPUT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_INIT_WIDTH          (V4L2_CID_FIMC_IS_BASE + 465)
+#define V4L2_CID_IS_CAMERA_INIT_HEIGHT         (V4L2_CID_FIMC_IS_BASE + 466)
+
+#define V4L2_CID_IS_CMD_ISP                    (V4L2_CID_FIMC_IS_BASE + 467)
+enum is_isp_cmd_mode {
+       IS_ISP_COMMAND_STOP,
+       IS_ISP_COMMAND_START,
+       IS_ISP_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_DRC                    (V4L2_CID_FIMC_IS_BASE + 468)
+enum is_drc_cmd_mode {
+       IS_DRC_COMMAND_STOP,
+       IS_DRC_COMMAND_START,
+       IS_DRC_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_FD                     (V4L2_CID_FIMC_IS_BASE + 469)
+enum is_fd_cmd_mode {
+       IS_FD_COMMAND_STOP,
+       IS_FD_COMMAND_START,
+       IS_FD_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_ODC                    (V4L2_CID_FIMC_IS_BASE + 470)
+enum is_odc_cmd_mode {
+       IS_ODC_COMMAND_STOP,
+       IS_ODC_COMMAND_START,
+       IS_ODC_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_DIS                    (V4L2_CID_FIMC_IS_BASE + 471)
+enum is_dis_cmd_mode {
+       IS_DIS_COMMAND_STOP,
+       IS_DIS_COMMAND_START,
+       IS_DIS_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_TDNR                   (V4L2_CID_FIMC_IS_BASE + 472)
+enum is_tdnr_cmd_mode {
+       IS_TDNR_COMMAND_STOP,
+       IS_TDNR_COMMAND_START,
+       IS_TDNR_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_SCALERC                        (V4L2_CID_FIMC_IS_BASE + 473)
+enum is_scalerc_cmd_mode {
+       IS_SCALERC_COMMAND_STOP,
+       IS_SCALERC_COMMAND_START,
+       IS_SCALERC_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_SCALERP                        (V4L2_CID_FIMC_IS_BASE + 474)
+enum is_scalerp_cmd_mode {
+       IS_SCALERP_COMMAND_STOP,
+       IS_SCALERP_COMMAND_START,
+       IS_SCALERP_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_GET_SENSOR_OFFSET_X                (V4L2_CID_FIMC_IS_BASE + 480)
+#define V4L2_CID_IS_GET_SENSOR_OFFSET_Y                (V4L2_CID_FIMC_IS_BASE + 481)
+#define V4L2_CID_IS_GET_SENSOR_WIDTH           (V4L2_CID_FIMC_IS_BASE + 482)
+#define V4L2_CID_IS_GET_SENSOR_HEIGHT          (V4L2_CID_FIMC_IS_BASE + 483)
+
+#define V4L2_CID_IS_GET_FRAME_VALID            (V4L2_CID_FIMC_IS_BASE + 484)
+#define V4L2_CID_IS_SET_FRAME_VALID            (V4L2_CID_FIMC_IS_BASE + 485)
+#define V4L2_CID_IS_GET_FRAME_BADMARK          (V4L2_CID_FIMC_IS_BASE + 486)
+#define V4L2_CID_IS_SET_FRAME_BADMARK          (V4L2_CID_FIMC_IS_BASE + 487)
+#define V4L2_CID_IS_GET_FRAME_CAPTURED         (V4L2_CID_FIMC_IS_BASE + 488)
+#define V4L2_CID_IS_SET_FRAME_CAPTURED         (V4L2_CID_FIMC_IS_BASE + 489)
+#define V4L2_CID_IS_SET_FRAME_NUMBER           (V4L2_CID_FIMC_IS_BASE + 490)
+#define V4L2_CID_IS_GET_FRAME_NUMBER           (V4L2_CID_FIMC_IS_BASE + 491)
+#define V4L2_CID_IS_CLEAR_FRAME_NUMBER         (V4L2_CID_FIMC_IS_BASE + 492)
+#define V4L2_CID_IS_GET_LOSTED_FRAME_NUMBER    (V4L2_CID_FIMC_IS_BASE + 493)
+#define V4L2_CID_IS_ISP_DMA_BUFFER_NUM         (V4L2_CID_FIMC_IS_BASE + 494)
+#define V4L2_CID_IS_ISP_DMA_BUFFER_ADDRESS     (V4L2_CID_FIMC_IS_BASE + 495)
+
+#define V4L2_CID_IS_ZOOM_STATE                 (V4L2_CID_FIMC_IS_BASE + 660)
+#define V4L2_CID_IS_ZOOM_MAX_LEVEL             (V4L2_CID_FIMC_IS_BASE + 661)
+#define V4L2_CID_IS_ZOOM                       (V4L2_CID_FIMC_IS_BASE + 662)
+
+enum v4l2_blur {
+       BLUR_LEVEL_0 = 0,
+       BLUR_LEVEL_1,
+       BLUR_LEVEL_2,
+       BLUR_LEVEL_3,
+       BLUR_LEVEL_MAX,
+};
+
+#if 1
+#define V4L2_CID_CAMERA_SCENE_MODE             (V4L2_CID_PRIVATE_BASE+70)
+enum v4l2_scene_mode {
+       SCENE_MODE_BASE,
+       SCENE_MODE_NONE,
+       SCENE_MODE_PORTRAIT,
+       SCENE_MODE_NIGHTSHOT,
+       SCENE_MODE_BACK_LIGHT,
+       SCENE_MODE_LANDSCAPE,
+       SCENE_MODE_SPORTS,
+       SCENE_MODE_PARTY_INDOOR,
+       SCENE_MODE_BEACH_SNOW,
+       SCENE_MODE_SUNSET,
+       SCENE_MODE_DUSK_DAWN,
+       SCENE_MODE_FALL_COLOR,
+       SCENE_MODE_FIREWORKS,
+       SCENE_MODE_TEXT,
+       SCENE_MODE_CANDLE_LIGHT,
+       SCENE_MODE_MAX,
+};
+
+#define V4L2_CID_CAMERA_FLASH_MODE             (V4L2_CID_PRIVATE_BASE+71)
+enum v4l2_flash_mode {
+       FLASH_MODE_BASE,
+       FLASH_MODE_OFF,
+       FLASH_MODE_AUTO,
+       FLASH_MODE_ON,
+       FLASH_MODE_TORCH,
+       FLASH_MODE_MAX,
+};
+
+#define V4L2_CID_CAMERA_BRIGHTNESS             (V4L2_CID_PRIVATE_BASE+72)
+enum v4l2_ev_mode {
+       EV_MINUS_4      = -4,
+       EV_MINUS_3      = -3,
+       EV_MINUS_2      = -2,
+       EV_MINUS_1      = -1,
+       EV_DEFAULT      = 0,
+       EV_PLUS_1       = 1,
+       EV_PLUS_2       = 2,
+       EV_PLUS_3       = 3,
+       EV_PLUS_4       = 4,
+       EV_MAX,
+       EV_MAX_V4L2     = EV_MAX,
+};
+
+#define V4L2_CID_CAMERA_WHITE_BALANCE  (V4L2_CID_PRIVATE_BASE+73)
+enum v4l2_wb_mode {
+       WHITE_BALANCE_BASE = 0,
+       WHITE_BALANCE_AUTO,
+       WHITE_BALANCE_SUNNY,
+       WHITE_BALANCE_CLOUDY,
+       WHITE_BALANCE_TUNGSTEN,
+       WHITE_BALANCE_FLUORESCENT,
+       WHITE_BALANCE_MAX,
+};
+
+#define V4L2_CID_CAMERA_EFFECT                 (V4L2_CID_PRIVATE_BASE+74)
+enum v4l2_effect_mode {
+       IMAGE_EFFECT_BASE = 0,
+       IMAGE_EFFECT_NONE,
+       IMAGE_EFFECT_BNW,
+       IMAGE_EFFECT_SEPIA,
+       IMAGE_EFFECT_AQUA,
+       IMAGE_EFFECT_ANTIQUE,
+       IMAGE_EFFECT_NEGATIVE,
+       IMAGE_EFFECT_SHARPEN,
+       IMAGE_EFFECT_MAX,
+};
+
+#define V4L2_CID_CAMERA_ISO            (V4L2_CID_PRIVATE_BASE+75)
+enum v4l2_iso_mode {
+       ISO_AUTO = 0,
+       ISO_50,
+       ISO_100,
+       ISO_200,
+       ISO_400,
+       ISO_800,
+       ISO_1600,
+       ISO_SPORTS,
+       ISO_NIGHT,
+       ISO_MOVIE,
+       ISO_MAX,
+};
+
+#define V4L2_CID_CAMERA_METERING       (V4L2_CID_PRIVATE_BASE+76)
+enum v4l2_metering_mode {
+       METERING_BASE = 0,
+       METERING_MATRIX,
+       METERING_CENTER,
+       METERING_SPOT,
+       METERING_MAX,
+};
+
+#define V4L2_CID_CAMERA_CONTRAST       (V4L2_CID_PRIVATE_BASE+77)
+enum v4l2_contrast_mode {
+       CONTRAST_MINUS_2 = 0,
+       CONTRAST_MINUS_1,
+       CONTRAST_DEFAULT,
+       CONTRAST_PLUS_1,
+       CONTRAST_PLUS_2,
+       CONTRAST_MAX,
+};
+
+#define V4L2_CID_CAMERA_SATURATION             (V4L2_CID_PRIVATE_BASE+78)
+enum v4l2_saturation_mode {
+       SATURATION_MINUS_2 = 0,
+       SATURATION_MINUS_1,
+       SATURATION_DEFAULT,
+       SATURATION_PLUS_1,
+       SATURATION_PLUS_2,
+       SATURATION_MAX,
+};
+
+#define V4L2_CID_CAMERA_SHARPNESS              (V4L2_CID_PRIVATE_BASE+79)
+enum v4l2_sharpness_mode {
+       SHARPNESS_MINUS_2 = 0,
+       SHARPNESS_MINUS_1,
+       SHARPNESS_DEFAULT,
+       SHARPNESS_PLUS_1,
+       SHARPNESS_PLUS_2,
+       SHARPNESS_MAX,
+};
+
+#define V4L2_CID_CAMERA_WDR            (V4L2_CID_PRIVATE_BASE+80)
+enum v4l2_wdr_mode {
+       WDR_OFF,
+       WDR_ON,
+       WDR_MAX,
+};
+
+#define V4L2_CID_CAMERA_ANTI_SHAKE             (V4L2_CID_PRIVATE_BASE+81)
+enum v4l2_anti_shake_mode {
+       ANTI_SHAKE_OFF,
+       ANTI_SHAKE_STILL_ON,
+       ANTI_SHAKE_MOVIE_ON,
+       ANTI_SHAKE_MAX,
+};
+
+#define V4L2_CID_CAMERA_TOUCH_AF_START_STOP (V4L2_CID_PRIVATE_BASE+82)
+enum v4l2_touch_af {
+       TOUCH_AF_STOP = 0,
+       TOUCH_AF_START,
+       TOUCH_AF_MAX,
+};
+
+#define V4L2_CID_CAMERA_SMART_AUTO             (V4L2_CID_PRIVATE_BASE+83)
+enum v4l2_smart_auto {
+       SMART_AUTO_OFF = 0,
+       SMART_AUTO_ON,
+       SMART_AUTO_MAX,
+};
+
+#define V4L2_CID_CAMERA_VINTAGE_MODE           (V4L2_CID_PRIVATE_BASE+84)
+enum v4l2_vintage_mode {
+       VINTAGE_MODE_BASE,
+       VINTAGE_MODE_OFF,
+       VINTAGE_MODE_NORMAL,
+       VINTAGE_MODE_WARM,
+       VINTAGE_MODE_COOL,
+       VINTAGE_MODE_BNW,
+       VINTAGE_MODE_MAX,
+};
+
+#define V4L2_CID_CAMERA_JPEG_QUALITY           (V4L2_CID_PRIVATE_BASE+85)
+#define V4L2_CID_CAMERA_GPS_LATITUDE   (V4L2_CID_CAMERA_CLASS_BASE + 30)
+#define V4L2_CID_CAMERA_GPS_LONGITUDE  (V4L2_CID_CAMERA_CLASS_BASE + 31)
+#define V4L2_CID_CAMERA_GPS_TIMESTAMP  (V4L2_CID_CAMERA_CLASS_BASE + 32)
+#define V4L2_CID_CAMERA_GPS_ALTITUDE   (V4L2_CID_CAMERA_CLASS_BASE + 33)
+#define V4L2_CID_CAMERA_EXIF_TIME_INFO (V4L2_CID_CAMERA_CLASS_BASE + 34)
+#define V4L2_CID_CAMERA_GPS_PROCESSINGMETHOD   (V4L2_CID_CAMERA_CLASS_BASE+35)
+
+#define V4L2_CID_FOCUS_AUTO_MODE               (V4L2_CID_CAMERA_CLASS_BASE+36)
+enum  v4l2_focus_mode_type {
+       V4L2_FOCUS_AUTO_NORMAL = 0,
+       V4L2_FOCUS_AUTO_MACRO = 1,
+       V4L2_FOCUS_AUTO_CONTINUOUS = 2,
+       V4L2_FOCUS_AUTO_FACE_DETECTION = 3,
+       V4L2_FOCUS_AUTO_RECTANGLE = 4
+};
+#define V4L2_CID_FOCUS_AUTO_RECTANGLE_LEFT     (V4L2_CID_CAMERA_CLASS_BASE+37)
+#define V4L2_CID_FOCUS_AUTO_RECTANGLE_TOP      (V4L2_CID_CAMERA_CLASS_BASE+38)
+#define V4L2_CID_FOCUS_AUTO_RECTANGLE_WIDTH    (V4L2_CID_CAMERA_CLASS_BASE+39)
+#define V4L2_CID_FOCUS_AUTO_RECTANGLE_HEIGHT   (V4L2_CID_CAMERA_CLASS_BASE+40)
+
+#define V4L2_CID_CAMERA_ZOOM   (V4L2_CID_PRIVATE_BASE+90)
+enum v4l2_zoom_level {
+       ZOOM_LEVEL_0 = 0,
+       ZOOM_LEVEL_1,
+       ZOOM_LEVEL_2,
+       ZOOM_LEVEL_3,
+       ZOOM_LEVEL_4,
+       ZOOM_LEVEL_5,
+       ZOOM_LEVEL_6,
+       ZOOM_LEVEL_7,
+       ZOOM_LEVEL_8,
+       ZOOM_LEVEL_9,
+       ZOOM_LEVEL_10,
+       ZOOM_LEVEL_11,
+       ZOOM_LEVEL_12,
+       ZOOM_LEVEL_MAX = 31,
+};
+
+#define V4L2_CID_CAMERA_FACE_DETECTION         (V4L2_CID_PRIVATE_BASE+91)
+enum v4l2_face_detection {
+       FACE_DETECTION_OFF = 0,
+       FACE_DETECTION_ON,
+       FACE_DETECTION_NOLINE,
+       FACE_DETECTION_ON_BEAUTY,
+       FACE_DETECTION_MAX,
+};
+
+#define V4L2_CID_CAMERA_SMART_AUTO_STATUS      (V4L2_CID_PRIVATE_BASE+92)
+enum v4l2_smart_auto_status {
+       SMART_AUTO_STATUS_AUTO = 0,
+       SMART_AUTO_STATUS_LANDSCAPE,
+       SMART_AUTO_STATUS_PORTRAIT,
+       SMART_AUTO_STATUS_MACRO,
+       SMART_AUTO_STATUS_NIGHT,
+       SMART_AUTO_STATUS_PORTRAIT_NIGHT,
+       SMART_AUTO_STATUS_BACKLIT,
+       SMART_AUTO_STATUS_PORTRAIT_BACKLIT,
+       SMART_AUTO_STATUS_ANTISHAKE,
+       SMART_AUTO_STATUS_PORTRAIT_ANTISHAKE,
+       SMART_AUTO_STATUS_MAX,
+};
+
+#define V4L2_CID_CAMERA_SET_AUTO_FOCUS         (V4L2_CID_PRIVATE_BASE+93)
+enum v4l2_auto_focus {
+       AUTO_FOCUS_OFF = 0,
+       AUTO_FOCUS_ON,
+       AUTO_FOCUS_MAX,
+};
+
+#define V4L2_CID_CAMERA_BEAUTY_SHOT            (V4L2_CID_PRIVATE_BASE+94)
+enum v4l2_beauty_shot {
+       BEAUTY_SHOT_OFF = 0,
+       BEAUTY_SHOT_ON,
+       BEAUTY_SHOT_MAX,
+};
+
+#define V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK      (V4L2_CID_PRIVATE_BASE+95)
+enum v4l2_ae_awb_lockunlock {
+       AE_UNLOCK_AWB_UNLOCK = 0,
+       AE_LOCK_AWB_UNLOCK,
+       AE_UNLOCK_AWB_LOCK,
+       AE_LOCK_AWB_LOCK,
+       AE_AWB_MAX
+};
+
+#define V4L2_CID_CAMERA_FACEDETECT_LOCKUNLOCK  (V4L2_CID_PRIVATE_BASE+96)
+enum v4l2_face_lock {
+       FACE_LOCK_OFF = 0,
+       FACE_LOCK_ON,
+       FIRST_FACE_TRACKING,
+       FACE_LOCK_MAX,
+};
+
+#define V4L2_CID_CAMERA_OBJECT_POSITION_X      (V4L2_CID_PRIVATE_BASE+97)
+#define V4L2_CID_CAMERA_OBJECT_POSITION_Y      (V4L2_CID_PRIVATE_BASE+98)
+#define V4L2_CID_CAMERA_FOCUS_MODE             (V4L2_CID_PRIVATE_BASE+99)
+enum v4l2_focusmode {
+       FOCUS_MODE_AUTO = 0,
+       FOCUS_MODE_MACRO,
+       FOCUS_MODE_FACEDETECT,
+       FOCUS_MODE_AUTO_DEFAULT,
+       FOCUS_MODE_MACRO_DEFAULT,
+       FOCUS_MODE_FACEDETECT_DEFAULT,
+       FOCUS_MODE_INFINITY,
+       FOCUS_MODE_FIXED,
+       FOCUS_MODE_CONTINOUS,
+       FOCUS_MODE_CONTINOUS_PICTURE,
+       FOCUS_MODE_CONTINOUS_PICTURE_MACRO,
+       FOCUS_MODE_CONTINOUS_VIDEO,
+       FOCUS_MODE_TOUCH,
+       FOCUS_MODE_MAX,
+       FOCUS_MODE_DEFAULT = (1 << 8),
+};
+
+#define V4L2_CID_CAMERA_OBJ_TRACKING_STATUS    (V4L2_CID_PRIVATE_BASE+100)
+enum v4l2_obj_tracking_status {
+       OBJECT_TRACKING_STATUS_BASE,
+       OBJECT_TRACKING_STATUS_PROGRESSING,
+       OBJECT_TRACKING_STATUS_SUCCESS,
+       OBJECT_TRACKING_STATUS_FAIL,
+       OBJECT_TRACKING_STATUS_MISSING,
+       OBJECT_TRACKING_STATUS_MAX,
+};
+
+#define V4L2_CID_CAMERA_OBJ_TRACKING_START_STOP        (V4L2_CID_PRIVATE_BASE+101)
+enum v4l2_ot_start_stop {
+       OT_STOP = 0,
+       OT_START,
+       OT_MAX,
+};
+
+#define V4L2_CID_CAMERA_CAF_START_STOP (V4L2_CID_PRIVATE_BASE+102)
+enum v4l2_caf_start_stop {
+       CAF_STOP = 0,
+       CAF_START,
+       CAF_MAX,
+};
+
+#define V4L2_CID_CAMERA_AUTO_FOCUS_RESULT      (V4L2_CID_PRIVATE_BASE+103)
+enum v4l2_af_status {
+       CAMERA_AF_STATUS_FAIL = 0,
+       CAMERA_AF_STATUS_IN_PROGRESS,
+       CAMERA_AF_STATUS_SUCCESS,
+       CAMERA_AF_STATUS_1ST_SUCCESS,
+       CAMERA_AF_STATUS_MAX
+};
+
+#define V4L2_CID_CAMERA_FRAME_RATE             (V4L2_CID_PRIVATE_BASE+104)
+enum v4l2_frame_rate {
+       FRAME_RATE_AUTO = 0,
+       FRAME_RATE_7 = 7,
+       FRAME_RATE_15 = 15,
+       FRAME_RATE_20 = 20,
+       FRAME_RATE_25 = 25,
+       FRAME_RATE_30 = 30,
+       FRAME_RATE_60 = 60,
+       FRAME_RATE_120 = 120,
+       FRAME_RATE_MAX
+};
+
+#define V4L2_CID_CAMERA_ANTI_BANDING           (V4L2_CID_PRIVATE_BASE+105)
+enum v4l2_anti_banding {
+       ANTI_BANDING_AUTO = 0,
+       ANTI_BANDING_50HZ = 1,
+       ANTI_BANDING_60HZ = 2,
+       ANTI_BANDING_OFF = 3,
+};
+
+#define V4L2_CID_CAMERA_SET_GAMMA      (V4L2_CID_PRIVATE_BASE+106)
+enum v4l2_gamma_mode {
+       GAMMA_OFF = 0,
+       GAMMA_ON = 1,
+       GAMMA_MAX,
+};
+
+#define V4L2_CID_CAMERA_SET_SLOW_AE    (V4L2_CID_PRIVATE_BASE+107)
+enum v4l2_slow_ae_mode {
+       SLOW_AE_OFF,
+       SLOW_AE_ON,
+       SLOW_AE_MAX,
+};
+
+#define V4L2_CID_CAMERA_BATCH_REFLECTION       (V4L2_CID_PRIVATE_BASE+108)
+#define V4L2_CID_CAMERA_EXIF_ORIENTATION       (V4L2_CID_PRIVATE_BASE+109)
+/*s1_camera [ Defense process by ESD input ]*/
+#define V4L2_CID_CAMERA_RESET          (V4L2_CID_PRIVATE_BASE+111)
+#define V4L2_CID_CAMERA_CHECK_DATALINE (V4L2_CID_PRIVATE_BASE+112)
+#define V4L2_CID_CAMERA_CHECK_DATALINE_STOP     (V4L2_CID_PRIVATE_BASE+113)
+
+#endif
+
+#if defined(CONFIG_ARIES_NTT) /*Modify NTTS1*/
+#define V4L2_CID_CAMERA_AE_AWB_DISABLE_LOCK     (V4L2_CID_PRIVATE_BASE+114)
+#endif
+#define V4L2_CID_CAMERA_THUMBNAIL_NULL         (V4L2_CID_PRIVATE_BASE+115)
+#define V4L2_CID_CAMERA_SENSOR_MODE            (V4L2_CID_PRIVATE_BASE+116)
+enum v4l2_sensor_mode {
+       SENSOR_CAMERA,
+       SENSOR_MOVIE,
+};
+
+enum stream_mode_t {
+       STREAM_MODE_CAM_OFF,
+       STREAM_MODE_CAM_ON,
+       STREAM_MODE_MOVIE_OFF,
+       STREAM_MODE_MOVIE_ON,
+};
+
+#define V4L2_CID_CAMERA_EXIF_EXPTIME           (V4L2_CID_PRIVATE_BASE+117)
+#define V4L2_CID_CAMERA_EXIF_FLASH     (V4L2_CID_PRIVATE_BASE+118)
+#define V4L2_CID_CAMERA_EXIF_ISO               (V4L2_CID_PRIVATE_BASE+119)
+#define V4L2_CID_CAMERA_EXIF_TV                (V4L2_CID_PRIVATE_BASE+120)
+#define V4L2_CID_CAMERA_EXIF_BV                (V4L2_CID_PRIVATE_BASE+121)
+#define V4L2_CID_CAMERA_EXIF_EBV               (V4L2_CID_PRIVATE_BASE+122)
+#define V4L2_CID_CAMERA_CHECK_ESD              (V4L2_CID_PRIVATE_BASE+123)
+#define V4L2_CID_CAMERA_APP_CHECK              (V4L2_CID_PRIVATE_BASE+124)
+#define V4L2_CID_CAMERA_CHECK_SENSOR_STATUS    (V4L2_CID_PRIVATE_BASE+150)
+#define V4L2_CID_CAMERA_DEFAULT_FOCUS_POSITION  (V4L2_CID_PRIVATE_BASE+151)
+#define V4L2_CID_CAMERA_BUSFREQ_LOCK           (V4L2_CID_PRIVATE_BASE+125)
+#define V4L2_CID_CAMERA_BUSFREQ_UNLOCK         (V4L2_CID_PRIVATE_BASE+126)
+
+/* If you would like to control AE and AWB lock with signle command,
+ * use V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK above.
+ */
+#define V4L2_CID_CAMERA_AE_LOCK_UNLOCK (V4L2_CID_PRIVATE_BASE + 127)
+enum v4l2_ae_lockunlock {
+       AE_UNLOCK = 0,
+       AE_LOCK,
+       AE_LOCK_MAX
+};
+
+#define V4L2_CID_CAMERA_AWB_LOCK_UNLOCK        (V4L2_CID_PRIVATE_BASE + 128)
+enum v4l2_awb_lockunlock {
+       AWB_UNLOCK = 0,
+       AWB_LOCK,
+       AWB_LOCK_MAX
+};
+
+#define V4L2_CID_CAMERA_SENSOR_OUTPUT_SIZE  (V4L2_CID_PRIVATE_BASE + 129)
+#define V4L2_CID_EMBEDDEDDATA_ENABLE   (V4L2_CID_PRIVATE_BASE + 130)
+#define V4L2_CID_CAMERA_JPEG_RESOLUTION  (V4L2_CID_PRIVATE_BASE + 131)
+#define V4L2_CID_CAMERA_FACE_ZOOM  (V4L2_CID_PRIVATE_BASE + 132)
+enum v4l2_face_zoom {
+       FACE_ZOOM_STOP = 0,
+       FACE_ZOOM_START
+};
+
+/*      Pixel format FOURCC depth  Description  */
+enum v4l2_pix_format_mode {
+       V4L2_PIX_FMT_MODE_PREVIEW,
+       V4L2_PIX_FMT_MODE_CAPTURE,
+       V4L2_PIX_FMT_MODE_HDR,
+       V4L2_PIX_FMT_MODE_VT_MIRROR,
+       V4L2_PIX_FMT_MODE_VT_NONMIRROR,
+};
+
+/* 12  Y/CbCr 4:2:0 64x32 macroblocks */
+#define V4L2_PIX_FMT_NV12T    v4l2_fourcc('T', 'V', '1', '2')
+#define V4L2_PIX_FMT_NV21T    v4l2_fourcc('T', 'V', '2', '1')
+#define V4L2_PIX_FMT_INTERLEAVED    v4l2_fourcc('I', 'T', 'L', 'V')
+
+
+/*
+ *  * V4L2 extention for digital camera
+ *   */
+/* Strobe flash light */
+enum v4l2_strobe_control {
+       /* turn off the flash light */
+       V4L2_STROBE_CONTROL_OFF         = 0,
+       /* turn on the flash light */
+       V4L2_STROBE_CONTROL_ON          = 1,
+       /* act guide light before splash */
+       V4L2_STROBE_CONTROL_AFGUIDE     = 2,
+       /* charge the flash light */
+       V4L2_STROBE_CONTROL_CHARGE      = 3,
+};
+
+enum v4l2_strobe_conf {
+       V4L2_STROBE_OFF                 = 0,    /* Always off */
+       V4L2_STROBE_ON                  = 1,    /* Always splashes */
+       /* Auto control presets */
+       V4L2_STROBE_AUTO                = 2,
+       V4L2_STROBE_REDEYE_REDUCTION    = 3,
+       V4L2_STROBE_SLOW_SYNC           = 4,
+       V4L2_STROBE_FRONT_CURTAIN       = 5,
+       V4L2_STROBE_REAR_CURTAIN        = 6,
+       /* Extra manual control presets */
+       /* keep turned on until turning off */
+       V4L2_STROBE_PERMANENT           = 7,
+       V4L2_STROBE_EXTERNAL            = 8,
+};
+
+enum v4l2_strobe_status {
+       V4L2_STROBE_STATUS_OFF          = 0,
+       /* while processing configurations */
+       V4L2_STROBE_STATUS_BUSY         = 1,
+       V4L2_STROBE_STATUS_ERR          = 2,
+       V4L2_STROBE_STATUS_CHARGING     = 3,
+       V4L2_STROBE_STATUS_CHARGED      = 4,
+};
+
+/* capabilities field */
+/* No strobe supported */
+#define V4L2_STROBE_CAP_NONE           0x0000
+/* Always flash off mode */
+#define V4L2_STROBE_CAP_OFF            0x0001
+/* Always use flash light mode */
+#define V4L2_STROBE_CAP_ON             0x0002
+/* Flashlight works automatic */
+#define V4L2_STROBE_CAP_AUTO           0x0004
+/* Red-eye reduction */
+#define V4L2_STROBE_CAP_REDEYE         0x0008
+/* Slow sync */
+#define V4L2_STROBE_CAP_SLOWSYNC       0x0010
+/* Front curtain */
+#define V4L2_STROBE_CAP_FRONT_CURTAIN  0x0020
+/* Rear curtain */
+#define V4L2_STROBE_CAP_REAR_CURTAIN   0x0040
+/* keep turned on until turning off */
+#define V4L2_STROBE_CAP_PERMANENT      0x0080
+/* use external strobe */
+#define V4L2_STROBE_CAP_EXTERNAL       0x0100
+
+/* Set mode and Get status */
+struct v4l2_strobe {
+       /* off/on/charge:0/1/2 */
+       enum    v4l2_strobe_control control;
+       /* supported strobe capabilities */
+       __u32   capabilities;
+       enum    v4l2_strobe_conf mode;
+       enum    v4l2_strobe_status status;      /* read only */
+/* default is 0 and range of value varies from each models */
+       __u32   flash_ev;
+       __u32   reserved[4];
+};
+
+#define VIDIOC_S_STROBE     _IOWR('V', 83, struct v4l2_strobe)
+#define VIDIOC_G_STROBE     _IOR('V', 84, struct v4l2_strobe)
+
+/* Object recognition and collateral actions */
+enum v4l2_recog_mode {
+       V4L2_RECOGNITION_MODE_OFF       = 0,
+       V4L2_RECOGNITION_MODE_ON        = 1,
+       V4L2_RECOGNITION_MODE_LOCK      = 2,
+};
+
+enum v4l2_recog_action {
+       V4L2_RECOGNITION_ACTION_NONE    = 0,    /* only recognition */
+       V4L2_RECOGNITION_ACTION_BLINK   = 1,    /* Capture on blinking */
+       V4L2_RECOGNITION_ACTION_SMILE   = 2,    /* Capture on smiling */
+};
+
+enum v4l2_recog_pattern {
+       V4L2_RECOG_PATTERN_FACE         = 0, /* Face */
+       V4L2_RECOG_PATTERN_HUMAN        = 1, /* Human */
+       V4L2_RECOG_PATTERN_CHAR         = 2, /* Character */
+};
+
+struct v4l2_recog_rect {
+       enum    v4l2_recog_pattern  p;  /* detected pattern */
+       struct  v4l2_rect  o;   /* detected area */
+       __u32   reserved[4];
+};
+
+struct v4l2_recog_data {
+       __u8    detect_cnt;             /* detected object counter */
+       struct  v4l2_rect       o;      /* detected area */
+       __u32   reserved[4];
+};
+
+struct v4l2_recognition {
+       enum v4l2_recog_mode    mode;
+
+       /* Which pattern to detect */
+       enum v4l2_recog_pattern  pattern;
+
+       /* How many object to detect */
+       __u8    obj_num;
+
+       /* select detected object */
+       __u32   detect_idx;
+
+       /* read only :Get object coordination */
+       struct v4l2_recog_data  data;
+
+       enum v4l2_recog_action  action;
+       __u32   reserved[4];
+};
+
+#define VIDIOC_S_RECOGNITION   _IOWR('V', 85, struct v4l2_recognition)
+#define VIDIOC_G_RECOGNITION   _IOR('V', 86, struct v4l2_recognition)
+
+#endif /* __LINUX_VIDEODEV2_SAMSUNG_H */