r1426 - in developers/seanchiang: . gsm gsm/doc gsm/include gsm/include/common gsm/include/gsmd gsm/include/libgsmd gsm/logs gsm/src gsm/src/gsmd gsm/src/libgsmd gsm/src/util

sean_chiang at sita.openmoko.org sean_chiang at sita.openmoko.org
Tue Mar 20 08:30:35 CET 2007


Author: sean_chiang
Date: 2007-03-20 08:29:51 +0100 (Tue, 20 Mar 2007)
New Revision: 1426

Added:
   developers/seanchiang/gsm/
   developers/seanchiang/gsm/COPYING
   developers/seanchiang/gsm/COPYING.library
   developers/seanchiang/gsm/Makefile.am
   developers/seanchiang/gsm/README.txt
   developers/seanchiang/gsm/autogen.sh
   developers/seanchiang/gsm/configure.ac
   developers/seanchiang/gsm/doc/
   developers/seanchiang/gsm/doc/functions.txt
   developers/seanchiang/gsm/include/
   developers/seanchiang/gsm/include/Makefile.am
   developers/seanchiang/gsm/include/common/
   developers/seanchiang/gsm/include/common/Makefile.am
   developers/seanchiang/gsm/include/common/linux_list.h
   developers/seanchiang/gsm/include/gsmd/
   developers/seanchiang/gsm/include/gsmd/Makefile.am
   developers/seanchiang/gsm/include/gsmd/atcmd.h
   developers/seanchiang/gsm/include/gsmd/event.h
   developers/seanchiang/gsm/include/gsmd/extrsp.h
   developers/seanchiang/gsm/include/gsmd/gsmd.h
   developers/seanchiang/gsm/include/gsmd/select.h
   developers/seanchiang/gsm/include/gsmd/state.h
   developers/seanchiang/gsm/include/gsmd/talloc.h
   developers/seanchiang/gsm/include/gsmd/ts0707.h
   developers/seanchiang/gsm/include/gsmd/unsolicited.h
   developers/seanchiang/gsm/include/gsmd/usock.h
   developers/seanchiang/gsm/include/gsmd/vendorplugin.h
   developers/seanchiang/gsm/include/libgsmd/
   developers/seanchiang/gsm/include/libgsmd/Makefile.am
   developers/seanchiang/gsm/include/libgsmd/event.h
   developers/seanchiang/gsm/include/libgsmd/handset.h
   developers/seanchiang/gsm/include/libgsmd/libgsmd.h
   developers/seanchiang/gsm/include/libgsmd/misc.h
   developers/seanchiang/gsm/include/libgsmd/phonebook.h
   developers/seanchiang/gsm/include/libgsmd/pin.h
   developers/seanchiang/gsm/include/libgsmd/voicecall.h
   developers/seanchiang/gsm/libgsmd.pc.in
   developers/seanchiang/gsm/logs/
   developers/seanchiang/gsm/logs/screenlog.0
   developers/seanchiang/gsm/src/
   developers/seanchiang/gsm/src/Makefile.am
   developers/seanchiang/gsm/src/gsmd/
   developers/seanchiang/gsm/src/gsmd/Makefile.am
   developers/seanchiang/gsm/src/gsmd/atcmd.c
   developers/seanchiang/gsm/src/gsmd/ext_response.c
   developers/seanchiang/gsm/src/gsmd/gsmd.c
   developers/seanchiang/gsm/src/gsmd/gsmd.h
   developers/seanchiang/gsm/src/gsmd/gsmd_event.h
   developers/seanchiang/gsm/src/gsmd/log.c
   developers/seanchiang/gsm/src/gsmd/operator_cache.c
   developers/seanchiang/gsm/src/gsmd/select.c
   developers/seanchiang/gsm/src/gsmd/sms_cb.c
   developers/seanchiang/gsm/src/gsmd/talloc.c
   developers/seanchiang/gsm/src/gsmd/unsolicited.c
   developers/seanchiang/gsm/src/gsmd/usock.c
   developers/seanchiang/gsm/src/gsmd/vendor.c
   developers/seanchiang/gsm/src/gsmd/vendor_ti.c
   developers/seanchiang/gsm/src/gsmd/vendorplugin.h
   developers/seanchiang/gsm/src/libgsmd/
   developers/seanchiang/gsm/src/libgsmd/Makefile.am
   developers/seanchiang/gsm/src/libgsmd/lgsm_internals.h
   developers/seanchiang/gsm/src/libgsmd/libgsmd.c
   developers/seanchiang/gsm/src/libgsmd/libgsmd_event.c
   developers/seanchiang/gsm/src/libgsmd/libgsmd_input.c
   developers/seanchiang/gsm/src/libgsmd/libgsmd_network.c
   developers/seanchiang/gsm/src/libgsmd/libgsmd_passthrough.c
   developers/seanchiang/gsm/src/libgsmd/libgsmd_phone.c
   developers/seanchiang/gsm/src/libgsmd/libgsmd_pin.c
   developers/seanchiang/gsm/src/libgsmd/libgsmd_voicecall.c
   developers/seanchiang/gsm/src/util/
   developers/seanchiang/gsm/src/util/Makefile.am
   developers/seanchiang/gsm/src/util/atcmd.c
   developers/seanchiang/gsm/src/util/atcmd.h
   developers/seanchiang/gsm/src/util/event.c
   developers/seanchiang/gsm/src/util/event.h
   developers/seanchiang/gsm/src/util/libgsmd-tool.c
   developers/seanchiang/gsm/src/util/pin.c
   developers/seanchiang/gsm/src/util/pin.h
   developers/seanchiang/gsm/src/util/shell.c
   developers/seanchiang/gsm/src/util/shell.h
Log:
support phonebook, sms(not fully support yet)

Added: developers/seanchiang/gsm/COPYING
===================================================================
--- developers/seanchiang/gsm/COPYING	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/COPYING	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <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 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

Added: developers/seanchiang/gsm/COPYING.library
===================================================================
--- developers/seanchiang/gsm/COPYING.library	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/COPYING.library	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,510 @@
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+	51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard.  To achieve this, non-free programs must
+be allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at least
+    three years, to give the same user the materials specified in
+    Subsection 6a, above, for a charge no more than the cost of
+    performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James
+  Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+

Added: developers/seanchiang/gsm/Makefile.am
===================================================================
--- developers/seanchiang/gsm/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,15 @@
+AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
+
+SUBDIRS = include src
+#LINKOPTS = -lusb
+
+AM_CFLAGS = -std=gnu99
+
+$(OBJECTS): libtool
+libtool: $(LIBTOOL_DEPS)
+	$(SHELL) ./config.status --recheck
+
+pcdata_DATA= libgsmd.pc
+pcdatadir= $(libdir)/pkgconfig
+
+EXTRA_DIST= $(pcdata_DATA)

Added: developers/seanchiang/gsm/README.txt
===================================================================
--- developers/seanchiang/gsm/README.txt	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/README.txt	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,76 @@
+
+
+1. GSMD api towards libgsmd 
+	- provides api for other processes to interact with GSM subsystem
+	- is not documented and subject to change
+
+2. GSMD api towards vendor-specific plugins
+	- implement vendor-specific AT commands
+	- is not documented and will initially only support TI 
+	- later, a Motorola plugin is planned.
+
+3. libgsmd api towards applications
+	- wraps GSMD-libgsmd api into C functions that can be used by applications
+	- will be documented and is supposed to be stable.
+
+3.1. Events
+
+The application registers callback handlers for events.  libgsmd can call these callback
+handlers at any given time.  Events include "incoming call", "remote end hangup", ...
+
+3.2. Commands
+
+Commands have the form of command-reply.  Usually they will be performed
+synchronously, i.e. the the caller will be blocked until a response to the command has been
+received.
+
+If this behaviour is not desired, a completion handler callback function can be
+registered.  In this case, the function call will return immediately after the
+command has been sent to gsmd.  Further incoming packets on the gsmd socket
+will be handled to libgsmd by calling lgsm_handle_packet().  If one such packet is the
+response to a currently-executing command, the completion handler will be
+called from within lgsm_handle_packet().  Matching of responses to requests is done by 
+assigning a unique id to each request.  gsmd responses will have a matching id.
+
+
+code flow in gsmd:
+
+- select loop detects data has arrived on user socket
+	- gsmd_usock_user_cb()
+		- if this is atcmd passthrough, 
+			- alloc + fill in gsmd_atcmd
+			- atcmd_submit()
+				- append it to pending_atcmds
+				- mark interest of writing to UART
+		- if this is not passthrough
+			- do whatever handling, including enqueueing of atcmds
+- select loop detects UART is marked writable
+	- atcmd_select_cb()
+		- iterate over list of pending_atcmds()
+			- write a particular atcmd to UART
+			- move atcmd to busy_atcmds
+- select loop detects UART is marked readable
+	- atcmd_select_cb()
+		- read up to 1024 bytes into buffer
+		- llparse_string()
+			- llparse_byte()
+				- llparse_append()
+			- llp->cb == ml_parse()
+				- if this is not unsolicited
+					- call cmd->cb() 
+						- alloc + fill ucmd reply
+						- add to finished_ucmds
+						- mark user sock writable
+					- unlink + free atcmd
+				- if this is unsolicited
+					- unsolicited_parse()
+						- usock_evt_send()
+							- alloc + fill ucmd reply
+							- add to finished_ucmds
+							- mark user sock writable
+- select loop detects user sock writeability
+	- gsmd_usock_user_cb()
+		- iterate over finished_ucmds
+			- write ucmd
+			- unlink + free ucmd
+

Added: developers/seanchiang/gsm/autogen.sh
===================================================================
--- developers/seanchiang/gsm/autogen.sh	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/autogen.sh	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,5 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+glib-gettextize --force --copy || exit 1
+./configure --enable-maintainer-mode "$@"
+

Added: developers/seanchiang/gsm/configure.ac
===================================================================
--- developers/seanchiang/gsm/configure.ac	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/configure.ac	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,28 @@
+AC_PREREQ(2.53)
+AC_INIT(gsmd, 0.0.1, http://www.openmoko.org/)
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(src/gsmd/gsmd.c)
+AM_CONFIG_HEADER(config.h)
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_PROG_LIBTOOL
+
+# base deps
+
+# output stuff
+AC_OUTPUT([
+Makefile
+libgsmd.pc
+src/Makefile
+src/gsmd/Makefile
+src/libgsmd/Makefile
+src/util/Makefile
+include/Makefile
+include/gsmd/Makefile
+include/libgsmd/Makefile
+include/common/Makefile
+])
+

Added: developers/seanchiang/gsm/doc/functions.txt
===================================================================
--- developers/seanchiang/gsm/doc/functions.txt	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/doc/functions.txt	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,51 @@
+0. general
+
+commands
+- power up/down phone
+- operator selection
+- get list of operators
+- get operator name / id list
+- get (and edit) preferred operator list
+- get manufacturer/device/serial info
+- get IMSI
+- obtain network registration status
+
+
+events
+- some pin required
+- network registration status
+- time zone update
+
+
+1. voice calls
+
+commands (request/response)
+- dial outgoing call
+- send dtmf digit (during call)
+- hang up (incoming/outgoing)
+- accept currently pending incoming call
+- enable/disable clip
+- enable/disable colp
+- enable/disable clir
+- call forwarding
+- call deflection
+
+events
+- incoming call
+- clip
+- colp
+- call waiting
+- 
+
+2. SMS
+
+commands
+- send outgoing message
+
+3. data calls
+
+TBD
+
+4. GPRS
+
+TBD

Added: developers/seanchiang/gsm/include/Makefile.am
===================================================================
--- developers/seanchiang/gsm/include/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1 @@
+SUBDIRS = libgsmd gsmd common 

Added: developers/seanchiang/gsm/include/common/Makefile.am
===================================================================
--- developers/seanchiang/gsm/include/common/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/common/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,3 @@
+
+noinst_HEADERS = linux_list.h
+

Added: developers/seanchiang/gsm/include/common/linux_list.h
===================================================================
--- developers/seanchiang/gsm/include/common/linux_list.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/common/linux_list.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,364 @@
+#ifndef _LINUX_LLIST_H
+#define _LINUX_LLIST_H
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x)	(sizeof(x) / sizeof((x)[0]))
+#endif
+
+#include <stddef.h>
+
+#ifndef inline
+#define inline __inline__
+#endif
+
+static inline void prefetch(const void *x) {;}
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({			\
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized llist entries.
+ */
+#define LLIST_POISON1  ((void *) 0x00100100)
+#define LLIST_POISON2  ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked llist implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole llists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct llist_head {
+	struct llist_head *next, *prev;
+};
+
+#define LLIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LLIST_HEAD(name) \
+	struct llist_head name = LLIST_HEAD_INIT(name)
+
+#define INIT_LLIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal llist manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __llist_add(struct llist_head *new,
+			      struct llist_head *prev,
+			      struct llist_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * llist_add - add a new entry
+ * @new: new entry to be added
+ * @head: llist head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void llist_add(struct llist_head *new, struct llist_head *head)
+{
+	__llist_add(new, head, head->next);
+}
+
+/**
+ * llist_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: llist head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void llist_add_tail(struct llist_head *new, struct llist_head *head)
+{
+	__llist_add(new, head->prev, head);
+}
+
+/*
+ * Delete a llist entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal llist manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * llist_del - deletes entry from llist.
+ * @entry: the element to delete from the llist.
+ * Note: llist_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void llist_del(struct llist_head *entry)
+{
+	__llist_del(entry->prev, entry->next);
+	entry->next = LLIST_POISON1;
+	entry->prev = LLIST_POISON2;
+}
+
+/**
+ * llist_del_init - deletes entry from llist and reinitialize it.
+ * @entry: the element to delete from the llist.
+ */
+static inline void llist_del_init(struct llist_head *entry)
+{
+	__llist_del(entry->prev, entry->next);
+	INIT_LLIST_HEAD(entry); 
+}
+
+/**
+ * llist_move - delete from one llist and add as another's head
+ * @llist: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void llist_move(struct llist_head *llist, struct llist_head *head)
+{
+        __llist_del(llist->prev, llist->next);
+        llist_add(llist, head);
+}
+
+/**
+ * llist_move_tail - delete from one llist and add as another's tail
+ * @llist: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void llist_move_tail(struct llist_head *llist,
+				  struct llist_head *head)
+{
+        __llist_del(llist->prev, llist->next);
+        llist_add_tail(llist, head);
+}
+
+/**
+ * llist_empty - tests whether a llist is empty
+ * @head: the llist to test.
+ */
+static inline int llist_empty(const struct llist_head *head)
+{
+	return head->next == head;
+}
+
+static inline void __llist_splice(struct llist_head *llist,
+				 struct llist_head *head)
+{
+	struct llist_head *first = llist->next;
+	struct llist_head *last = llist->prev;
+	struct llist_head *at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
+}
+
+/**
+ * llist_splice - join two llists
+ * @llist: the new llist to add.
+ * @head: the place to add it in the first llist.
+ */
+static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
+{
+	if (!llist_empty(llist))
+		__llist_splice(llist, head);
+}
+
+/**
+ * llist_splice_init - join two llists and reinitialise the emptied llist.
+ * @llist: the new llist to add.
+ * @head: the place to add it in the first llist.
+ *
+ * The llist at @llist is reinitialised
+ */
+static inline void llist_splice_init(struct llist_head *llist,
+				    struct llist_head *head)
+{
+	if (!llist_empty(llist)) {
+		__llist_splice(llist, head);
+		INIT_LLIST_HEAD(llist);
+	}
+}
+
+/**
+ * llist_entry - get the struct for this entry
+ * @ptr:	the &struct llist_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * llist_for_each	-	iterate over a llist
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ */
+#define llist_for_each(pos, head) \
+	for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+        	pos = pos->next, prefetch(pos->next))
+
+/**
+ * __llist_for_each	-	iterate over a llist
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ *
+ * This variant differs from llist_for_each() in that it's the
+ * simplest possible llist iteration code, no prefetching is done.
+ * Use this for code that knows the llist to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __llist_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * llist_for_each_prev	-	iterate over a llist backwards
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_prev(pos, head) \
+	for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+        	pos = pos->prev, prefetch(pos->prev))
+        	
+/**
+ * llist_for_each_safe	-	iterate over a llist safe against removal of llist entry
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @n:		another &struct llist_head to use as temporary storage
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * llist_for_each_entry	-	iterate over llist of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry(pos, head, member)				\
+	for (pos = llist_entry((head)->next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head); 					\
+	     pos = llist_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next))
+
+/**
+ * llist_for_each_entry_reverse - iterate backwards over llist of given type.
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_reverse(pos, head, member)			\
+	for (pos = llist_entry((head)->prev, typeof(*pos), member),	\
+		     prefetch(pos->member.prev);			\
+	     &pos->member != (head); 					\
+	     pos = llist_entry(pos->member.prev, typeof(*pos), member),	\
+		     prefetch(pos->member.prev))
+
+/**
+ * llist_for_each_entry_continue -	iterate over llist of given type
+ *			continuing after existing point
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_continue(pos, head, member) 		\
+	for (pos = llist_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head);					\
+	     pos = llist_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next))
+
+/**
+ * llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = llist_entry((head)->next, typeof(*pos), member),	\
+		n = llist_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = llist_entry(n->member.next, typeof(*n), member))
+
+/**
+ * llist_for_each_rcu	-	iterate over an rcu-protected llist
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_rcu(pos, head) \
+	for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+        	pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
+        	
+#define __llist_for_each_rcu(pos, head) \
+	for (pos = (head)->next; pos != (head); \
+        	pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
+        	
+/**
+ * llist_for_each_safe_rcu	-	iterate over an rcu-protected llist safe
+ *					against removal of llist entry
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @n:		another &struct llist_head to use as temporary storage
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_safe_rcu(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
+
+/**
+ * llist_for_each_entry_rcu	-	iterate over rcu llist of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_rcu(pos, head, member)			\
+	for (pos = llist_entry((head)->next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head); 					\
+	     pos = llist_entry(pos->member.next, typeof(*pos), member),	\
+		     ({ smp_read_barrier_depends(); 0;}),		\
+		     prefetch(pos->member.next))
+
+
+/**
+ * llist_for_each_continue_rcu	-	iterate over an rcu-protected llist 
+ *			continuing after existing point.
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_continue_rcu(pos, head) \
+	for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
+        	(pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
+
+
+#endif

Added: developers/seanchiang/gsm/include/gsmd/Makefile.am
===================================================================
--- developers/seanchiang/gsm/include/gsmd/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,4 @@
+
+pkginclude_HEADERS = event.h usock.h
+
+noinst_HEADERS = atcmd.h gsmd.h select.h ts0707.h unsolicited.h usock.h vendorplugin.h

Added: developers/seanchiang/gsm/include/gsmd/atcmd.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/atcmd.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/atcmd.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,17 @@
+#ifndef __GSMD_ATCMD_H
+#define __GSMD_ATCMD_H
+
+#ifdef __GSMD__
+
+#include <gsmd/gsmd.h>
+
+typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp);
+
+extern struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id);
+extern int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd);
+extern int atcmd_init(struct gsmd *g, int sockfd);
+extern void atcmd_drain(int fd);
+
+#endif /* __GSMD__ */
+
+#endif

Added: developers/seanchiang/gsm/include/gsmd/event.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/event.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/event.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,80 @@
+#ifndef _GSMD_EVENT_H
+#define _GSMD_EVENT_H
+
+enum gsmd_events {
+	GSMD_EVT_NONE		= 0,
+	GSMD_EVT_IN_CALL	= 1,	/* Incoming call */
+	GSMD_EVT_IN_SMS		= 2,	/* Incoming SMS */
+	GSMD_EVT_IN_GPRS	= 3,	/* Network initiated GPRS */
+	GSMD_EVT_IN_CLIP	= 4,	/* Incoming CLIP */
+	GSMD_EVT_NETREG		= 5,	/* Network (un)registration event */
+	GSMD_EVT_SIGNAL		= 6,	/* Signal quality event */
+	GSMD_EVT_PIN		= 7, 	/* Modem is waiting for some PIN/PUK */
+	GSMD_EVT_OUT_STATUS	= 8,	/* Outgoing call status */
+	GSMD_EVT_OUT_COLP	= 9,	/* Outgoing COLP */
+	GSMD_EVT_CALL_WAIT	= 10,	/* Call Waiting */
+	GSMD_EVT_TIMEZONE	= 11,	/* Timezone change */
+	GSMD_EVT_SUBSCRIPTIONS	= 12,	/* To which events are we subscribed to */
+	GSMD_EVT_CIPHER		= 13,	/* Chiphering Information */
+	__NUM_GSMD_EVT
+};
+
+/* Chapter 8.3 */
+enum gsmd_pin_type {			/* waiting for ... */
+	GSMD_PIN_NONE		= 0,	/* not for any PIN */
+	GSMD_PIN_SIM_PIN	= 1,	/* SIM PIN */
+	GSMD_PIN_SIM_PUK	= 2,	/* SIM PUK */
+	GSMD_PIN_PH_SIM_PIN	= 3,	/* phone-to-SIM passowrd */
+	GSMD_PIN_PH_FSIM_PIN	= 4,	/* phone-to-very-first SIM password */
+	GSMD_PIN_PH_FSIM_PUK	= 5,	/* phone-to-very-first SIM PUK password */
+	GSMD_PIN_SIM_PIN2	= 6,	/* SIM PIN2 */
+	GSMD_PIN_SIM_PUK2	= 7,	/* SIM PUK2 */
+	GSMD_PIN_PH_NET_PIN	= 8,	/* netwokr personalisation password */
+	GSMD_PIN_PH_NET_PUK	= 9,	/* network personalisation PUK */
+	GSMD_PIN_PH_NETSUB_PIN	= 10, 	/* network subset personalisation PIN */
+	GSMD_PIN_PH_NETSUB_PUK	= 11,	/* network subset personalisation PUK */
+	GSMD_PIN_PH_SP_PIN	= 12,	/* service provider personalisation PIN */
+	GSMD_PIN_PH_SP_PUK	= 13,	/* service provider personalisation PUK */
+	GSMD_PIN_PH_CORP_PIN	= 14,	/* corporate personalisation PIN */
+	GSMD_PIN_PH_CORP_PUK	= 15,	/* corporate personalisation PUK */
+	__NUM_GSMD_PIN
+};
+
+enum gsmd_call_type {
+	GSMD_CALL_NONE		= 0,
+	GSMD_CALL_UNSPEC	= 1,
+	GSMD_CALL_VOICE		= 2,
+	GSMD_CALL_FAX		= 4,
+	GSMD_CALL_DATA_SYNC	= 5,
+	GSMD_CALL_DATA_REL_ASYNC= 6,
+	GSMD_CALL_DATA_REL_SYNC	= 7,
+	__NUM_GSMD_CALL
+};
+
+enum gsmd_netreg_state {
+	GSMD_NETREG_NONE	= 0,
+	__NUM_GSMD_NETREG
+};
+
+enum gsmd_call_progress {
+	GSMD_CALLPROG_SETUP		= 0,
+	GSMD_CALLPROG_DISCONNECT	= 1,
+	GSMD_CALLPROG_ALERT		= 2,
+	GSMD_CALLPROG_CALL_PROCEED	= 3,
+	GSMD_CALLPROG_SYNC		= 4,
+	GSMD_CALLPROG_PROGRESS		= 5,
+	GSMD_CALLPROG_CONNECTED		= 6,
+	GSMD_CALLPROG_RELEASE		= 7,
+	GSMD_CALLPROG_REJECT		= 8,
+	GSMD_CALLPROG_UNKNOWN		= 9,
+	__NUM_GSMD_CALLPROG
+};
+
+enum gsmd_call_direction {
+	GSMD_CALL_DIR_MO		= 0,	/* Mobile Originated (Outgoing) */
+	GSMD_CALL_DIR_MT		= 1,	/* Mobile Terminated (Incoming) */
+	GSMD_CALL_DIR_CCBS		= 2,	/* network initiated MO */
+	GSMD_CALL_DIR_MO_REDIAL		= 3,	/* Mobile Originated Redial */
+};
+
+#endif

Added: developers/seanchiang/gsm/include/gsmd/extrsp.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/extrsp.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/extrsp.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,45 @@
+#ifndef _GSMD_EXTRSP_H
+#define _GSMD_EXTRSP_H
+
+/* how many tokens (CSV items) can an extended response have, max */
+#define GSM_EXTRSP_MAX_TOKENS	16
+
+/* how many individual sub-ranges can one range contain */
+#define GSM_EXTRSP_MAX_RANGES	16
+
+
+struct gsm_extrsp_range_item {
+	int min;
+	int max;
+};
+
+enum gsm_extrsp_tok_type {
+	GSMD_ECMD_RTT_NONE,
+	GSMD_ECMD_RTT_EMPTY,
+	GSMD_ECMD_RTT_NUMERIC,
+	GSMD_ECMD_RTT_STRING,
+	GSMD_ECMD_RTT_RANGE,
+};
+
+struct gsm_extrsp_tok {
+	enum gsm_extrsp_tok_type type;
+	union {
+		struct {
+			struct gsm_extrsp_range_item item[GSM_EXTRSP_MAX_RANGES];
+			int num_items;
+		} range;
+		char string[64];
+		int numeric;
+	} u;
+};
+
+struct gsm_extrsp {
+	unsigned int num_tokens;
+	struct gsm_extrsp_tok tokens[GSM_EXTRSP_MAX_TOKENS];
+};
+
+extern int extrsp_supports(const struct gsm_extrsp *er, int index, int value);
+extern struct gsm_extrsp *extrsp_parse(const void *ctx, const char *input);
+extern void extrsp_dump(const struct gsm_extrsp *er);
+
+#endif

Added: developers/seanchiang/gsm/include/gsmd/gsmd.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/gsmd.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/gsmd.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,100 @@
+#ifndef _GSMD_H
+#define _GSMD_H
+
+#ifdef __GSMD__
+
+#include <sys/types.h>
+
+#include <common/linux_list.h>
+
+#include <gsmd/vendorplugin.h>
+#include <gsmd/select.h>
+#include <gsmd/state.h>
+
+void *gsmd_tallocs;
+
+/* Refer to 3GPP TS 07.07 v 7.8.0, Chapter 4.1 */
+#define LGSM_ATCMD_F_EXTENDED	0x01	/* as opposed to basic */
+#define LGSM_ATCMD_F_PARAM	0x02	/* as opposed to action */
+
+struct gsmd_atcmd {
+	struct llist_head list;
+	void *ctx;
+	int (*cb)(struct gsmd_atcmd *cmd, void *ctx, char *resp);
+	char *resp;
+	int32_t ret;
+	u_int32_t buflen;
+	u_int16_t id;
+	u_int8_t flags;
+	char buf[];
+};
+
+enum llparse_state {
+	LLPARSE_STATE_IDLE,		/* idle, not parsing a response */
+	LLPARSE_STATE_IDLE_CR,		/* CR before response (V1) */
+	LLPARSE_STATE_IDLE_LF,		/* LF before response (V1) */
+	LLPARSE_STATE_RESULT,		/* within result payload */
+	LLPARSE_STATE_RESULT_CR,	/* CR after result */
+	LLPARSE_STATE_ERROR,		/* something went wrong */
+					/* ... idle again */
+};
+
+/* we can't take any _single_ response bigger than this: */
+#define LLPARSE_BUF_SIZE	256
+
+struct llparser {
+	enum llparse_state state;
+	unsigned int len;
+	unsigned int flags;
+	void *ctx;
+	int (*cb)(const char *buf, int len, void *ctx);
+	char *cur;
+	char buf[LLPARSE_BUF_SIZE];
+};
+
+struct gsmd;
+
+#define GSMD_FLAG_V0		0x0001	/* V0 responses to be expected from TA */
+
+struct gsmd {
+	unsigned int flags;
+	struct gsmd_fd gfd_uart;
+	struct gsmd_fd gfd_sock;
+	struct llparser llp;
+	struct llist_head users;
+	struct llist_head pending_atcmds;	/* our busy gsmd_atcmds */
+	struct llist_head busy_atcmds;	/* our busy gsmd_atcmds */
+	struct gsmd_vendor_plugin *vendorpl;
+	struct gsmd_device_state dev_state;
+
+	struct llist_head operators;		/* cached list of operator names */
+};
+
+struct gsmd_user {
+	struct llist_head list;		/* our entry in the global list */
+	struct llist_head finished_ucmds;	/* our busy gsmd_ucmds */
+	struct gsmd *gsmd;
+	struct gsmd_fd gfd;				/* the socket */
+	u_int32_t subscriptions;		/* bitmaks of subscribed event groups */
+};
+
+#define GSMD_DEBUG	1	/* debugging information */
+#define GSMD_INFO	3
+#define GSMD_NOTICE	5	/* abnormal/unexpected condition */
+#define GSMD_ERROR	7	/* error condition, requires user action */
+#define GSMD_FATAL	8	/* fatal, program aborted */
+
+extern int gsmdlog_init(const char *path);
+/* write a message to the daemons' logfile */
+void __gsmd_log(int level, const char *file, int line, const char *function, const char *message, ...);
+/* macro for logging including filename and line number */
+#define gsmd_log(level, format, args ...) \
+	__gsmd_log(level, __FILE__, __LINE__, __FUNCTION__, format, ## args)
+
+#define DEBUGP(x, args ...)	gsmd_log(GSMD_DEBUG, x, ## args)
+
+extern int gsmd_simplecmd(struct gsmd *gsmd, char *cmdtxt);
+
+#endif /* __GSMD__ */
+
+#endif /* _GSMD_H */

Added: developers/seanchiang/gsm/include/gsmd/select.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/select.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/select.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,26 @@
+#ifndef __GSMD_SELECT_H
+#define __GSMD_SELECT_H
+
+#ifdef __GSMD__
+
+#include <common/linux_list.h>
+
+#define GSMD_FD_READ	0x0001
+#define GSMD_FD_WRITE	0x0002
+#define GSMD_FD_EXCEPT	0x0004
+
+struct gsmd_fd {
+	struct llist_head list;
+	int fd;				/* file descriptor */
+	unsigned int when;
+	int (*cb)(int fd, unsigned int what, void *data);
+	void *data;			/* void * to pass to callback */
+};
+
+extern int gsmd_register_fd(struct gsmd_fd *ufd);
+extern void gsmd_unregister_fd(struct gsmd_fd *ufd);
+extern int gsmd_select_main(void);
+
+#endif /* __GSMD__ */
+
+#endif

Added: developers/seanchiang/gsm/include/gsmd/state.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/state.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/state.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,23 @@
+#ifndef _GSMD_STATE_H
+#define _GSMD_STATE_H
+
+#ifdef __GSMD__
+
+#define GSMD_CIPHIND_CAPABLE		0x01
+#define GSMD_CIPHIND_DISABLED_SIM	0x02
+#define GSMD_CIPHIND_ACTIVE		0x04
+
+struct gsmd_device_state {
+	struct {
+		unsigned int flags;
+		unsigned int network_state_gsm;
+		unsigned int network_state_gprs;
+	} ciph_ind;
+
+	unsigned int on;
+	unsigned int registered;
+};
+
+#endif /* __GSMD__ */
+
+#endif /* _GSMD_STATE_H */

Added: developers/seanchiang/gsm/include/gsmd/talloc.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/talloc.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/talloc.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,140 @@
+#ifndef _TALLOC_H_
+#define _TALLOC_H_
+
+
+#ifdef __GSMD__
+/*
+   Unix SMB/CIFS implementation.
+   Samba temporary memory allocation functions
+
+   Copyright (C) Andrew Tridgell 2004-2005
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* nfsim additions */
+#include <stdarg.h>
+#include <stdio.h>
+
+/* this is only needed for compatibility with the old talloc */
+typedef void TALLOC_CTX;
+
+/*
+  this uses a little trick to allow __LINE__ to be stringified
+*/
+#define _STRING_LINE_(s)    #s
+#define _STRING_LINE2_(s)   _STRING_LINE_(s)
+#define __LINESTR__       _STRING_LINE2_(__LINE__)
+#define __location__ __FILE__ ":" __LINESTR__
+
+#ifndef TALLOC_DEPRECATED
+#define TALLOC_DEPRECATED 0
+#endif
+
+/* useful macros for creating type checked pointers */
+#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
+#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
+
+#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
+
+#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
+#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
+
+#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
+#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
+#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
+
+#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
+#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
+
+#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
+
+#define malloc_p(type) (type *)malloc(sizeof(type))
+#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count)
+#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count)
+
+#define data_blob(ptr, size) data_blob_named(ptr, size, "DATA_BLOB: "__location__)
+#define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, "DATA_BLOB: "__location__)
+#define data_blob_dup_talloc(ctx, blob) data_blob_talloc_named(ctx, (blob)->data, (blob)->length, "DATA_BLOB: "__location__)
+
+#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
+#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
+
+
+#if TALLOC_DEPRECATED
+#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
+#define talloc_p(ctx, type) talloc(ctx, type)
+#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
+#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
+#define talloc_destroy(ctx) talloc_free(ctx)
+#endif
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3)
+/** Use gcc attribute to check printf fns.  a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+
+/* The following definitions come from talloc.c  */
+void *_talloc(const void *context, size_t size);
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *));
+void talloc_increase_ref_count(const void *ptr);
+void *talloc_reference(const void *context, const void *ptr);
+int talloc_unlink(const void *context, void *ptr);
+void talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void talloc_set_name_const(const void *ptr, const char *name);
+void *talloc_named(const void *context, size_t size,
+		   const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+void *talloc_named_const(const void *context, size_t size, const char *name);
+const char *talloc_get_name(const void *ptr);
+void *talloc_check_name(const void *ptr, const char *name);
+void talloc_report_depth(const void *ptr, FILE *f, int depth);
+void *talloc_parent(const void *ptr);
+void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
+int talloc_free(void *ptr);
+void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
+void *talloc_steal(const void *new_ctx, const void *ptr);
+off_t talloc_total_size(const void *ptr);
+off_t talloc_total_blocks(const void *ptr);
+void talloc_report_full(const void *ptr, FILE *f);
+void talloc_report(const void *ptr, FILE *f);
+void talloc_enable_null_tracking(void);
+void talloc_enable_leak_report(void);
+void talloc_enable_leak_report_full(void);
+void *_talloc_zero(const void *ctx, size_t size, const char *name);
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
+char *talloc_strdup(const void *t, const char *p);
+char *talloc_strndup(const void *t, const char *p, size_t n);
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
+char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+char *talloc_asprintf_append(char *s,
+			     const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
+void *talloc_autofree_context(void);
+size_t talloc_get_size(const void *ctx);
+
+#endif
+
+#endif

Added: developers/seanchiang/gsm/include/gsmd/ts0707.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/ts0707.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/ts0707.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,45 @@
+#ifndef _GSM_0707_H
+#define _GSM_0707_H
+
+/* Section 9.2.1 */
+enum gsm0707_cme_error {
+	GSM0707_CME_PHONE_FAILURE		= 0,
+	GSM0707_CME_PHONE_NOCONNECT		= 1,
+	GSM0707_CME_PHONE_ADAPT_RESERVED	= 2,
+	GSM0707_CME_OPERATION_NOT_ALLOWED	= 3,
+	GSM0707_CME_OPERATUON_NOT_SUPPORTED	= 4,
+	GSM0707_CME_PH_SIM_PIN_REQUIRED		= 5,
+	GSM0707_CME_PH_FSIM_PIN_REQUIRED	= 6,
+	GSM0707_CME_PH_FSIM_PUK_REQUIRED	= 7,
+	GSM0707_CME_SIM_NOT_INSERTED		= 10,
+	GSM0707_CME_SIM_PIN_REQUIRED		= 11,
+	GSM0707_CME_SIM_PUK_REQUIRED		= 12,
+	GSM0707_CME_SIM_FAILURE			= 13,
+	GSM0707_CME_SIM_BUSY			= 14,
+	GSM0707_CME_SIM_WRONG			= 15,
+	GSM0707_CME_INCORRECT_PASSWORD		= 16,
+	GSM0707_CME_SIM_PIN2_REQUIRED		= 17,
+	GSM0707_CME_SIM_PUK2_REQUIRED		= 18,
+	GSM0707_CME_MEMORY_FULL			= 20,
+	GSM0707_CME_INVALID_INDEX		= 21,
+	GSM0707_CME_NOT_FOUND			= 22,
+	GSM0707_CME_MEMORY_FAILURE		= 23,
+	GSM0707_CME_TEXT_STRING_TOO_LONG	= 24,
+	GSM0707_CME_TEXT_STRING_INVAL_CHARS	= 25,
+	GSM0707_CME_DIAL_STRING_TOO_LONG	= 26,
+	GSM0707_CME_DIAL_STRING_INVAL_CHARS	= 27,
+	GSM0707_CME_NO_NETWORK_SERVICE		= 30,
+	GSM0707_CME_NETWORK_TIMEOUT		= 31,
+	GSM0707_CME_NETWORK_NOT_ALLOWED		= 32,
+	GSM0707_CME_NETPERS_PIN_REQUIRED	= 40,
+	GSM0707_CME_NETPERS_PUK_REQUIRED	= 41,
+	GSM0707_CME_NETSUBSET_PIN_REQUIRED	= 42,
+	GSM0707_CME_NETSUBSET_PUK_REQUIRED	= 43,
+	GSM0707_CME_PROVIDER_PIN_REQUIRED	= 44,
+	GSM0707_CME_PROVIDER_PUK_REQUIRED	= 45,
+	GSM0707_CME_CORPORATE_PIN_REQUIRED	= 46,
+	GSM0707_CME_CORPORATE_PUK_REQUIRED	= 47,
+	GSM0707_CME_UNKNOWN			= 100,
+};
+
+#endif /* _GSM_0707_H */

Added: developers/seanchiang/gsm/include/gsmd/unsolicited.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/unsolicited.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/unsolicited.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,18 @@
+#ifndef __GSMD_UNSOLICITED_H
+#define __GSMD_UNSOLICITED_H
+
+#ifdef __GSMD__
+
+#include <gsmd/gsmd.h>
+
+struct gsmd_unsolicit {
+	const char *prefix;
+	int (*parse)(char *unsol, int len, const char *param, struct gsmd *gsmd);
+};
+
+extern int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param);
+extern int generate_event_from_cme(struct gsmd *g, unsigned int cme_error);
+
+#endif /* __GSMD__ */
+
+#endif

Added: developers/seanchiang/gsm/include/gsmd/usock.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/usock.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/usock.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,266 @@
+#ifndef _GSMD_USOCK_H
+#define _GSMD_USOCK_H
+
+#include <gsmd/event.h>
+
+#define GSMD_UNIX_SOCKET "\0gsmd"
+//#define GSMD_UNIX_SOCKET_TYPE SOCK_SEQPACKET
+#define GSMD_UNIX_SOCKET_TYPE SOCK_STREAM
+
+#define GSMD_PROTO_VERSION	1
+
+#define GSMD_MSGSIZE_MAX	4096
+
+enum gsmd_msg_type {
+	GSMD_MSG_NONE		= 0,
+	GSMD_MSG_EVENT		= 1,
+	GSMD_MSG_PASSTHROUGH	= 2,
+	GSMD_MSG_VOICECALL	= 3,
+	GSMD_MSG_DATACALL	= 4,
+	GSMD_MSG_PHONEBOOK	= 5,
+	GSMD_MSG_NETWORK	= 6,
+	GSMD_MSG_PHONE		= 7,
+	GSMD_MSG_PIN		= 8,
+	GSMD_MSG_SMS		= 9,
+	__NUM_GSMD_MSGS
+};
+
+enum gsmd_passthrough_type {
+	GSMD_PASSTHROUGH_NONE	= 0,
+	GSMD_PASSTHROUGH_REQ	= 1,
+	GSMD_PASSTHROUGH_RESP	= 2,
+};
+
+enum gsmd_msg_voicecall_type {
+	GSMD_VOICECALL_DIAL	= 1,
+	GSMD_VOICECALL_HANGUP	= 2,
+	GSMD_VOICECALL_ANSWER	= 3,
+	GSMD_VOICECALL_DTMF	= 4,
+	GSMD_VOICECALL_VOL_SET	= 5,
+	GSMD_VOICECALL_VOL_GET	= 6,
+};
+
+/* Handset / MT related commands */
+enum gsmd_msg_phone_type {
+	GSMD_PHONE_VOLUME	= 1,
+	GSMD_PHONE_VIBRATOR	= 2,
+};
+
+enum gsmd_msg_pin_type {
+	GSMD_PIN_INPUT		= 1,
+};
+
+enum gsmd_msg_phone {
+	GSMD_PHONE_POWERUP	= 1,
+	GSMD_PHONE_POWERDOWN	= 2,
+};
+
+enum gsmd_msg_network {
+	GSMD_NETWORK_REGISTER	= 1,
+	GSMD_NETWORK_SIGQ_GET	= 2,
+	GSMD_NETWORK_VMAIL_GET	= 3,
+	GSMD_NETWORK_VMAIL_SET	= 4,
+	GSMD_NETWORK_OPER_GET	= 5,
+	GSMD_NETWORK_CIND_GET	= 6,
+};
+
+enum gsmd_msg_sms {
+	GSMD_SMS_LIST		= 1,
+	GSMD_SMS_READ		= 2,
+	GSMD_SMS_SEND		= 3,
+	GSMD_SMS_WRITE		= 4,
+	GSMD_SMS_DELETE		= 5,	
+};
+
+/* SMS stat from 3GPP TS 07.05, Clause 3.1 */
+enum gsmd_msg_sms_type {
+	GSMD_SMS_REC_UNREAD	= 0,
+	GSMD_SMS_REC_READ	= 1,
+	GSMD_SMS_STO_UNSENT	= 2,
+	GSMD_SMS_STO_SENT	= 3,
+	GSMD_SMS_ALL		= 4,
+};
+
+/* SMS format from 3GPP TS 07.05, Clause 3.2.3 */
+enum gsmd_msg_sms_fmt {
+	GSMD_SMS_FMT_PDU	= 0,
+	GSMD_SMS_FMT_TEXT	= 1,
+};
+
+/* SMS delflg from 3GPP TS 07.05, Clause 3.5.4 */
+enum gsmd_msg_sms_delflg {
+	GSMD_SMS_DELFLG_INDEX		= 0,
+	GSMD_SMS_DELFLG_READ		= 1,
+	GSMD_SMS_DELFLG_READ_SENT	= 2,
+	GSMD_SMS_DELFLG_LEAVING_UNREAD	= 3,
+	GSMD_SMS_DELFLG_ALL		= 4,
+};
+
+enum gsmd_msg_phonebook {
+	GSMD_PHONEBOOK_FIND		= 1,
+	GSMD_PHONEBOOK_READ		= 2,
+	GSMD_PHONEBOOK_READRG		= 3,
+	GSMD_PHONEBOOK_WRITE		= 4,
+	GSMD_PHONEBOOK_DELETE		= 5,	
+	GSMD_PHONEBOOK_GET_SUPPORT	= 6,
+};
+
+/* Length from 3GPP TS 04.08, Clause 10.5.4.7 */
+
+#define GSMD_ADDR_MAXLEN	32
+struct gsmd_addr {
+	u_int8_t type;
+	char number[GSMD_ADDR_MAXLEN+1];
+} __attribute__ ((packed));
+
+struct gsmd_dtmf {
+	u_int8_t len;
+	char dtmf[0];
+} __attribute__ ((packed));
+
+struct gsmd_signal_quality {
+	u_int8_t rssi;
+	u_int8_t ber;
+} __attribute__ ((packed));
+
+struct gsmd_voicemail {
+	u_int8_t enable;
+	struct gsmd_addr addr;
+} __attribute__ ((packed));
+
+#define GSMD_PIN_MAXLEN		8
+struct gsmd_pin {
+	enum gsmd_pin_type type;
+	char pin[GSMD_PIN_MAXLEN+1];
+	char newpin[GSMD_PIN_MAXLEN+1];
+} __attribute__ ((packed));
+
+struct gsmd_evt_auxdata {
+	union {
+		struct {
+			enum gsmd_call_type type;
+		} call;
+		struct {
+			struct gsmd_addr addr;
+		} clip;
+		struct {
+			struct gsmd_addr addr;
+		} colp;
+		struct {
+			/* TBD */
+			struct gsmd_addr addr;
+		} sms;
+		struct {
+			enum gsmd_pin_type type;
+		} pin;
+		struct {
+			enum gsmd_netreg_state state;
+			u_int16_t lac;
+			u_int16_t ci;
+		} netreg;
+		struct {
+			u_int8_t tz;
+		} timezone;
+		struct {
+			struct gsmd_signal_quality sigq;
+		} signal;
+		struct {
+			enum gsmd_call_progress prog;
+			struct gsmd_addr addr;
+			u_int8_t ibt:1,
+				 tch:1,
+				 dir:2;
+		} call_status;
+		struct {
+			u_int16_t flags;
+			u_int16_t net_state_gsm;
+			u_int16_t net_state_gprs;
+		} cipher;
+	} u;
+} __attribute__((packed));
+
+/* Refer to GSM 07.05 subclause 3.5.4 */
+struct gsmd_sms_delete {
+	u_int8_t index;
+	u_int8_t delflg;	
+} __attribute__ ((packed));
+
+/* Refer to GSM 03.40 subclause 9.2.2.2 and GSM 07.05 subclause 4.3 */
+#define GSMD_SMS_DATA_MAXLEN	164 
+struct gsmd_sms {
+	u_int8_t length;	
+	char data[GSMD_SMS_DATA_MAXLEN+1];	
+} __attribute__ ((packed));
+
+/* Refer to GSM 07.05 subclause 4.4 */
+struct gsmd_sms_write {
+	u_int8_t stat;
+	struct gsmd_sms sms;	
+} __attribute__ ((packed));
+
+/* Refer to GSM 07.07 subclause 8.12 */
+struct gsmd_phonebook_readrg {
+	u_int8_t index1;
+	u_int8_t index2;	
+} __attribute__ ((packed));
+
+/* Refer to GSM 07.07 subclause 8.14 */
+/* FIXME: the nlength and tlength depend on SIM, use +CPBR=? to get */ 
+#define	GSMD_PB_NUMB_MAXLEN	44
+#define GSMD_PB_TEXT_MAXLEN	14
+struct gsmd_phonebook {
+	u_int8_t index;
+	char numb[GSMD_PB_NUMB_MAXLEN+1];
+	u_int8_t type;
+	char text[GSMD_PB_TEXT_MAXLEN+1];
+} __attribute__ ((packed));
+
+
+/* Refer to GSM 07.07 subclause 8.13 */
+/* FIXME: the tlength depends on SIM, use +CPBR=? to get */ 
+struct gsmd_phonebook_find {	
+	char findtext[GSMD_PB_TEXT_MAXLEN+1];
+} __attribute__ ((packed));
+
+/* Refer to GSM 07.07 subclause 8.12 */
+struct gsmd_phonebook_support {	
+	u_int8_t index;
+	u_int8_t nlength;
+	u_int8_t tlength;
+} __attribute__ ((packed));
+
+struct gsmd_msg_hdr {
+	u_int8_t version;
+	u_int8_t msg_type;
+	u_int8_t msg_subtype;
+	u_int8_t _pad;
+	u_int16_t id;
+	u_int16_t len;
+	u_int8_t data[];
+} __attribute__((packed));
+
+#ifdef __GSMD__
+
+#include <common/linux_list.h>
+
+#include <gsmd/usock.h>
+#include <gsmd/gsmd.h>
+
+struct gsmd_user;
+
+struct gsmd_ucmd {
+	struct llist_head list;
+	struct gsmd_msg_hdr hdr;
+	char buf[];
+} __attribute__ ((packed));
+
+extern struct gsmd_ucmd *ucmd_alloc(int extra_size);
+extern int usock_init(struct gsmd *g);
+extern void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu);
+extern struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len);
+extern int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt);
+
+#endif /* __GSMD__ */
+
+#endif
+

Added: developers/seanchiang/gsm/include/gsmd/vendorplugin.h
===================================================================
--- developers/seanchiang/gsm/include/gsmd/vendorplugin.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/gsmd/vendorplugin.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,27 @@
+#ifndef _GSMD_VENDORPLUGIN_H
+#define _GSMD_VENDORPLUGIN_H
+
+#ifdef __GSMD__
+
+#include <common/linux_list.h>
+#include <gsmd/gsmd.h>
+
+struct gsmd;
+struct gsmd_unsolicit;
+
+struct gsmd_vendor_plugin {
+	struct llist_head list;
+	unsigned char *name;
+	unsigned int num_unsolicit;
+	const struct gsmd_unsolicit *unsolicit;
+	int (*detect)(struct gsmd *g);
+	int (*initsettings)(struct gsmd *g);
+};
+
+extern int gsmd_vendor_plugin_register(struct gsmd_vendor_plugin *pl);
+extern void gsmd_vendor_plugin_unregister(struct gsmd_vendor_plugin *pl);
+extern int gsmd_vendor_plugin_find(struct gsmd *g);
+
+#endif /* __GSMD__ */
+
+#endif

Added: developers/seanchiang/gsm/include/libgsmd/Makefile.am
===================================================================
--- developers/seanchiang/gsm/include/libgsmd/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/libgsmd/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,2 @@
+pkgincludedir = $(includedir)/libgsmd
+pkginclude_HEADERS = event.h handset.h libgsmd.h misc.h phonebook.h voicecall.h

Added: developers/seanchiang/gsm/include/libgsmd/event.h
===================================================================
--- developers/seanchiang/gsm/include/libgsmd/event.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/libgsmd/event.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,18 @@
+#ifndef _LIBGSMD_EVENT_H
+#define _LIBGSMD_EVENT_H
+
+#include <gsmd/event.h>
+
+/* Prototype of libgsmd callback handler function */
+typedef int lgsm_evt_handler(struct lgsm_handle *lh, int evt_type, struct gsmd_evt_auxdata *aux);
+
+/* Register an event callback handler with libgsmd */
+extern int lgsm_evt_handler_register(struct lgsm_handle *lh, int evt_type,
+				     lgsm_evt_handler *handler);
+extern void lgsm_evt_handler_unregister(struct lgsm_handle *lh, int evt_type);
+
+extern int lgsm_evt_init(struct lgsm_handle *lh);
+extern void lgsm_evt_exit(struct lgsm_handle *lh);
+
+
+#endif

Added: developers/seanchiang/gsm/include/libgsmd/handset.h
===================================================================
--- developers/seanchiang/gsm/include/libgsmd/handset.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/libgsmd/handset.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,15 @@
+#ifndef _LIBGSMD_HANDSET_H
+#define _LIBGSMD_HANDSET_H
+
+#include <libgsmd/libgsmd.h>
+/* Set speaker level (Chapter 8.23) */
+extern int lgsm_set_spkr_level(struct lgsm_handle *lh,
+			       u_int32_t level);
+
+/* Mute call during voice call */
+extern int lgsm_mute_set(struct lgsm_handle *lh, u_int8_t on);
+
+/* Get information on whether voice call is muted or not */
+extern int lgsm_mute_get(struct lgsm_handle *lh, u_int8_t *on);
+
+#endif

Added: developers/seanchiang/gsm/include/libgsmd/libgsmd.h
===================================================================
--- developers/seanchiang/gsm/include/libgsmd/libgsmd.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/libgsmd/libgsmd.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,69 @@
+#ifndef _LIBGSMD_H
+#define _LIBGSMD_H
+
+/* libgsmd.h - Library API for gsmd, the GSM Daemon
+ * (C) 2006 by Harald Welte <hwelte at hmw-consulting.de>
+ * Development funded by First International Computers, Inc.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include <gsmd/usock.h>
+
+/* Generic Information
+ *
+ * Return value:
+ * 	< 0	Error, see libgsmd/errno.h and errno.h
+ * 	= 0	Success
+ * 	> 0	Success, number of information elements returned
+ *
+ * Allocation:
+ * 	All data structures are caller-allocated.  The only exception
+ * 	is struct lgsm_handle which is allocatedi in lgsm_init() and 
+ * 	free'd in lgsm_exit()
+ *
+ * References:
+ * 	Recefences to "Chapter X" are referring to 3GPP TS 07.07 version 7.8.0
+ */
+
+/* Opaque data structure, content only known to libgsm implementation */
+struct lgsm_handle;
+
+/* Refer to GSM 04.08 [8] subclause 10.5.4.7 */
+enum lgsm_addr_type {
+	LGSM_ATYPE_ISDN_UNKN		= 161,
+	//LGSM_ATYPE_ISDN_INTL		= ,
+	//LGSM_ATYPE_ISDN_NATIONAL	= ,
+};
+
+#define LGSM_ADDR_MAXLEN	31
+struct lgsm_addr {
+	enum lgsm_addr_type type;
+	char addr[LGSM_ADDR_MAXLEN+1];
+};
+
+typedef int lgsm_msg_handler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh);
+
+#define LGSMD_DEVICE_GSMD	"gsmd"
+
+/* initialize usage of libgsmd, obtain handle for othe API calls */
+extern struct lgsm_handle *lgsm_init(const char *device);
+
+/* Terminate usage of libgsmd */
+extern int lgsm_exit(struct lgsm_handle *lh); 
+
+/* Obtain file descriptor (e.g. for select-loop under app control) */
+extern int lgsm_fd(struct lgsm_handle *lh);
+
+extern int lgsm_register_handler(struct lgsm_handle *lh, int type, lgsm_msg_handler *handler);
+extern void lgsm_unregister_handler(struct lgsm_handle *lh, int type);
+
+extern int lgsm_passthrough_send(struct lgsm_handle *lh, const char *tx);
+extern int lgsm_passthrough(struct lgsm_handle *lh, const char *tx, char *rx, unsigned int *rx_len);
+extern int lgsm_subscriptions(struct lgsm_handle *lh, u_int32_t subscriptions);
+
+extern struct gsmd_msg_hdr *lgsm_gmh_fill(int type, int subtype, int payload_len);
+extern int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh);
+
+#endif

Added: developers/seanchiang/gsm/include/libgsmd/misc.h
===================================================================
--- developers/seanchiang/gsm/include/libgsmd/misc.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/libgsmd/misc.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,76 @@
+#ifndef _LIBGSMD_H
+#define _LIBGSMD_H
+
+/* libgsmd.h - Library API for gsmd, the GSM Daemon
+ * (C) 2006 by Harald Welte <hwelte at hmw-consulting.de>
+ * Development funded by First International Computers, Inc.
+ */
+
+#include <libgsmd/libgsmd.h>
+
+extern int lgsm_phone_power(struct lgsm_handle *lh, int power);
+
+enum lgsm_netreg_state {
+	LGSM_NETREG_ST_NOTREG		= 0,
+	LGSM_NETREG_ST_REG_HOME		= 1,
+	LGSM_NETREG_ST_NOTREG_SEARCH	= 2,
+	LGSM_NETREG_ST_DENIED		= 3,
+	LGSM_NETREG_ST_UNKNOWN		= 4,
+	LGSM_NETREG_ST_REG_ROAMING	= 5,
+};
+
+/* Get the current network registration status */
+extern int lgsm_get_netreg_state(struct lgsm_handle *lh,
+				 enum lgsm_netreg_state *state);
+
+extern int lgsm_netreg_register(struct lgsm_handle *lh, int oper);
+
+enum lgsm_info_type {
+	LGSM_INFO_TYPE_NONE		= 0,
+	LGSM_INFO_TYPE_MANUF		= 1,
+	LGSM_INFO_TYPE_MODEL		= 2,
+	LGSM_INFO_TYPE_REVISION		= 3,
+	LGSM_INFO_TYPE_SERIAL		= 4,
+	LGSM_INFO_TYPE_IMSI		= 5,
+};
+
+/* Get some information about the handset */
+extern int lgsm_get_info(struct lgsm_handle *lh,
+			 enum lgsm_info_type type,
+			 char *ret_string, u_int16_t len);
+
+/* Authenticate to SIM Card using specified null-terminated pin */
+extern int lgsm_pin_auth(struct lgsm_handle *lh, const char *pin);
+
+
+/* General Commands */
+
+/* Get Signal Strehngth (Chapter 8.5) */
+extern int lgsm_get_signal_quality(struct lgsm_handle *h,
+				   unsigned int *rssi);
+
+/* Set voice mail number */
+extern int lgsm_voicemail_set(struct lgsm_handle *lh,
+			      struct lgsm_addr *addr);
+
+/* Get currently configured voice mail number */
+extern int lgsm_voicemail_get(struct lgsm_handle *lh,
+			      struct lgsm_addr *addr);
+
+/* Operator Selection, Network Registration */
+/* TBD */
+
+
+/* CLIP, CLIR, COLP, Call Forwarding, Call Waiting, Call Deflecting */
+/* TBD */
+
+
+/* SMS related functions */
+/* TBD */
+
+
+/* GPRS related functions */
+/* TBD */
+
+
+#endif

Added: developers/seanchiang/gsm/include/libgsmd/phonebook.h
===================================================================
--- developers/seanchiang/gsm/include/libgsmd/phonebook.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/libgsmd/phonebook.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,103 @@
+#ifndef _LIBGSMD_PBOOK_H
+#define _LIBGSMD_PBOOK_H
+
+#include <libgsmd/libgsmd.h>
+
+/* Phonebook */
+
+/* Chapter 8.11 */
+enum lgsm_pbook_type {
+	LGSM_PB_ME_DIALLED		= 1,
+	LGSM_PB_SIM_EMERGENCY		= 2,
+	LGSM_PB_SIM_FIXDIAL		= 3,
+	LGSM_PB_SIM_DIALLED		= 4,
+	LGSM_PB_ME_MISSED		= 5,
+	LGSM_PB_ME_PHONEBOOK		= 6,
+	LGSM_PB_COMB_PHONEBOOK		= 7,
+	LGSM_PB_SIM_OWN_NUMBERS		= 8,
+	LGSM_PB_ME_RECEIVED		= 9,
+	LGSM_PB_SIM_PHONEBOOK		= 10,
+	LGSM_PB_TA_PHONEBOOK		= 11,
+};
+
+/* Refer to GSM 07.07 subclause 8.14 */
+enum lgsm_pb_addr_type {	
+	LGSM_PB_ATYPE_INTL		= 145,
+	LGSM_PB_ATYPE_OTHE		= 129,
+};
+
+/* Refer to GSM 07.07 subclause 8.12 */
+struct lgsm_phonebook_readrg {
+	int index1;
+	int index2;
+};
+
+/* Refer to GSM 07.07 subclause 8.14 */
+/* FIXME: the nlength and tlength depend on SIM, use +CPBR=? to get */ 
+#define	LGSM_PB_NUMB_MAXLEN	44
+#define LGSM_PB_TEXT_MAXLEN	14
+struct lgsm_phonebook {
+	int index;
+	char numb[LGSM_PB_NUMB_MAXLEN+1];
+	enum lgsm_pb_addr_type type;
+	char text[LGSM_PB_TEXT_MAXLEN+1];
+};
+
+/* Refer to GSM 07.07 subclause 8.13 */
+/* FIXME: the tlength depends on SIM, use +CPBR=? to get */ 
+struct lgsm_phonebook_find {	
+	char findtext[LGSM_PB_TEXT_MAXLEN+1];
+};
+
+#if 0
+/* Get a bitmask of supported phonebook types */
+extern int lgsm_pb_get_types(struct lgsm_handle *lh, u_int32 *typemask);
+
+/* Get a range of supported indexes in given phonebook type, Chapter 8.12 */
+extern int lgsm_pb_get_range(struct lgsm_handle *lh,
+			     enum lgsm_pbook_type type,
+			     u_int32_t *from, u_int32_t *to,
+			     u_int32_t *nlength, *u_int32_t tlength);
+
+#define LGSM_PB_TEXT_MAXLEN	31
+
+struct lgsm_pb_entry {
+	struct lgsm_pb_entry	*next;
+	enum lgsm_pbook_type 	type;
+	u_int32_t 		index;
+	char 			text[LGSM_PB_TEXT_MAXLEN+1];
+};
+#endif
+
+/* Get a specific phonebook entry  and store it to 'pb'
+ * pb' is caller-allocated */
+extern int lgsm_pb_get_entry(struct lgsm_handle *lh,
+			     struct lgsm_pb_entry *pb);
+
+/* Store a specific phonebook entry 'pb' into phone */
+extern int lgsm_pb_set_entry(struct lgsm_handle *lh,
+			     struct lgsm_pb_entry *pb);
+
+/* Find phonebook entires which alphanumeric filed start 
+ * with string <findtext> */
+extern int lgsm_pb_find_entry(struct lgsm_handle *lh, 
+		const struct lgsm_phonebook_find *pb_find);
+
+/* Read phonebook entry in location number index */
+extern int lgsm_pb_read_entry(struct lgsm_handle *lh, int index);
+
+/* Read phonebook entries in location number range */
+extern int lgsm_pb_read_entryies(struct lgsm_handle *lh, 
+		const struct lgsm_phonebook_readrg *pb_readrg);
+
+/* Delete phonebook entry in location index */
+extern int lgsmd_pb_del_entry(struct lgsm_handle *lh, int index);
+
+/* Write phonebook entry in location */
+extern int lgsmd_pb_write_entry(struct lgsm_handle *lh, 
+		const struct lgsm_phonebook *pb);
+
+/* Get the location range/nlength/tlength supported */
+extern int lgsm_pb_get_support(struct lgsm_handle *lh);
+
+#endif

Added: developers/seanchiang/gsm/include/libgsmd/pin.h
===================================================================
--- developers/seanchiang/gsm/include/libgsmd/pin.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/libgsmd/pin.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,8 @@
+#ifndef _LGSM_PIN_H
+#define _LGSM_PIN_H
+
+extern const char *lgsm_pin_name(enum gsmd_pin_type ptype);
+
+extern int lgsm_pin(struct lgsm_handle *lh, unsigned int type, char *pin, char *newpin);
+
+#endif

Added: developers/seanchiang/gsm/include/libgsmd/voicecall.h
===================================================================
--- developers/seanchiang/gsm/include/libgsmd/voicecall.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/include/libgsmd/voicecall.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,21 @@
+#ifndef _LIBGSMD_VCALL_H
+#define _LIBGSMD_VCALL_H
+
+#include <libgsmd/libgsmd.h>
+
+/* Voice Calls */
+
+/* Initiate an outgoing voice call */
+extern int lgsm_voice_out_init(struct lgsm_handle *lh, 
+			       const struct lgsm_addr *number);
+
+/* Accept incoming voice call */
+extern int lgsm_voice_in_accept(struct lgsm_handle *lh);
+
+/* Terminate outgoing (or incoming) voice call */
+extern int lgsm_voice_hangup(struct lgsm_handle *lh);
+
+/* Send DTMF character during voice call */
+extern int lgsm_voice_dtmf(struct lgsm_handle *lh, char dtmf_char);
+
+#endif

Added: developers/seanchiang/gsm/libgsmd.pc.in
===================================================================
--- developers/seanchiang/gsm/libgsmd.pc.in	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/libgsmd.pc.in	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: libgsmd
+Description: GSM 07.10 Multiplexer Library
+Version: @VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lgsmd
+Requires:
+

Added: developers/seanchiang/gsm/logs/screenlog.0
===================================================================
--- developers/seanchiang/gsm/logs/screenlog.0	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/logs/screenlog.0	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,500 @@
+ccu -l /dev/ttU yUSB0 -s 15200
+cu: Unsupported baud rate 15200
+%                                                                                                        

laforge at rama%pts/11 (20:27) phone/src/libgsmd/atcmd >  2/1cu -l /dev/ttyUSB0 -s 1520015200
+Connected.
+
+OK
+ATV1
+OK
+AT+COPS=?
+ERROR
+AT+COPS=?
+ERROR
+AT+COPS?
++COPS: 0
+
+OK
+AT+COPS=?
+ERROR
+
+OK
+
+OK
+AT+CRC=1
+OK
+AT+CRC=?
++CRC: (0,1)
+
+OK
+AT+CGMI
+<manufacturer>
+
+OK
+AT+GMM
+<model>
+
+OK
+AT+CGSI
+EXT: I
+
+ERROR
+AT+CGSS
+EXT: I
+
+ERROR
+AT+CGSS=?
+EXT: I
+
+ERROR
+AT+CGSS?
+EXT: I
+
+ERROR
+AT+CGSN
+<serial number>
+
+OK
+AT+CSCS?
++CSCS: "IRA"
+
+OK
+AT+CSCS=?
++CSCS: "GSM","IRA","PCCP437","PCDN","8859-1","HEX","UCS2"
+
+OK
+AT+CIMI?
+ERROR
+AT+CIMI
+262074992516579
+
+OK
+AT+M
+EXT: I
+
+ERROR
+AT+CMUX?
+OK
+AT-Command Interpreter ready
+
+OK
+AT+CMUX=?
++CMUX: (1),(0),(1-5),(10-100),(1-255),(0-100),(2-255),(1-255),(1-7)
+
+OK
+AT-Command Interpreter ready
+AT+CSTA
+ERROR
+AT+CSTA?
++CSTA: 129
+
+OK
+AT+CSTA=?
++CSTA: (129,145)
+
+OK
+AT+CPIN?
++CPIN: SIM PIN
+
+OK
+ATP
+ERROR
+AT+CPIN=9450
+ERROR
+AT+CMOD?
++CMOD: 0
+
+OK
+AT+CMOD=?
++CMOD: (0-3)
+
+OK
+
+OK
+AT+CHUP
+OK
+AT+CBST=?
++CBST: (0-7,12,14,65,66,68,70,71,75),(0),(0-3)
+
+OK
+AT
+ERROR
+AT+CRLP=?
++CRLP: (0-61),(0-61),(39-255),(1-255)
+
+OK
+
+OK
+AT+CR?
++CR: 0
+
+OK
+AT+CR=?
++CR: (0,1)
+
+OK
+AT+CR=1
+OK
+
+OK
+
+OK
+
+OK
+AT+CEER=1
++CEER: 0,1,1,255,no error
+
+OK
+AT+CEER?
+ERROR
+AT+CEER=?
+OK
+
+OK
+AT+CRC=1
+OK
+AT+CRC=?
++CRC: (0,1)
+
+OK
+AT+CSNS=?
+ERROR
+AT+CSNS?
++CSNS: 0
+
+OK
+AT+CSNS=?
++CSNS: (0-7)
+
+OK
+
+OK
+AT+CHVU?
+EXT: I
+
+ERROR
+AT+CVUHU?
+EXT: I
+
+ERROR
+AT+CVHU?
+EXT: I
+
+ERROR
+AT+CVHU=?
+EXT: I
+
+ERROR
+
+OK
+AT+CV120?
+EXT: I
+
+ERROR
+AT+CV120=?
+EXT: I
+
+ERROR
+
+OK
+AT+CNUM?
+ERROR
+AT+CNUM=?
+OK
+AT+CNUM?
+ERROR
+AT+CNUM=?
+OK
+AT+CREG?
++CREG: 0,2
+
+OK
+AT+CREG=?
++CREG: (0-2)
+
+OK
+AT
+ERROR
+ATC
+EXT: I
+
+ERROR
+AT+CREG=2
+OK
+
+OK
+AT+COPS=?
+ERROR
+AT+COPS?
++COPS: 0
+
+OK
+AT+COPS=?
+ERROR
+
+OK
+AT+CLKS=?
+EXT: I
+
+ERROR
+AT+CLCK=?
++CLCK: ("SC","AO","OI","OX","AI","IR","AB","AG","AC","FD","PS","PN","PU","PP","PC","PF","AL")
+
+OK
+
+OK
+AT+CLIP=?
++CLIP: (0,1)
+
+OK
+ATP
+ERROR
+AT+CLIP?
++CLIP: 0,2
+
+OK
+AT+CLIR=?
++CLIR: (0,1,2)
+
+OK
+AT+CLIR?
++CLIR: 0,2
+
+OK
+AT+COPLP+
+EXT: I
+
+ERROR
+AT+COLP?
++COLP: 0,2
+
+OK
+AT+COLP=?
++COLP: (0,1)
+
+OK
+AT+CCFG
+EXT: I
+
+ERROR
+a
+ERROR
+AT+CCFC?
+ERROR
+AT+CCFC=?
++CCFC: (0-5)
+
+OK
+AT+CCWA
+OK
+AT+CCWA?
++CCWA: 0
+
+OK
+AT+CCWA=?
++CCWA: (0,1)
+
+OK
+
+OK
+AT+CCWA=1
+OK
+
+OK
+AT+CTFR=?
+OK
+AT+CTFR?
+ERROR
+
+OK
+AT+CUSD=?
++CUSD: (0,1,2)
+
+OK
+AT+CUSD?
++CUSD: 0
+
+OK
+AT+CUSD=1
+OK
+AT+CCSN?
+EXT: I
+
+ERROR
+AT+CCSN=?
+EXT: I
+
+ERROR
+
+OK
+AT+CCSI?
+EXT: I
+
+ERROR
+AT
+ERROR
+AT+CLCC?
+ERROR
+AT+CLCC=?
+OK
+
+OK
+AT+CPOL?
+ERROR
+AT+CPOL=?
+ERROR
+AT+
+ERROR
+AT+COPN?
+ERROR
+AT+COPN=?
+OK
+
+OK
+AT+CPAS?
+ERROR
+AT+CPAS=?
++CPAS: (0-5)
+
+OK
+AT+CPAS
++CPAS: 0
+
+OK
+
+OK
+AT+CMEC?
+EXT: I
+
+ERROR
+AT+CMEC=?
+EXT: I
+
+ERROR
+AT+CFUN?
++CFUN: 1
+
+OK
+AT+CFUN=?
++CFUN: (0,1,4),(0)
+
+OK
+
+OK
+AT+PIN
+EXT: I
+
+ERROR
+AT+CPIN?
++CPIN: SIM PIN
+
+OK
+AT+CPIN?
++CPIN: SIM PIN
+
+OK
+AT+CPIN=9450
+ERROR
+
++CREG: 2
+
+OK
+AT+CPIN?
++CPIN: READY
+
+OK
+AT+CBC?
+ERROR
+AT+CBC=?
++CBC: (0-3),(0-100)
+
+OK
+AT+CBC
++CBC: 0,0
+
+OK
+AT+CBC
++CBC: 0,0
+
+OK
+AT+CBC
++CBC: 0,0
+
+OK
+AT+CSQ?
+ERROR
+AT+COPS?
++COPS: 0
+
+OK
+AT+COPS=?
AT-Command Interpreter ready
+
+OK
+
+OK
+AT+CPIN
+ERROR
+AT+CPIN?
++CPIN: SIM PIN
+
+OK
+AT+COPS?
++COPS: 0
+
+OK
+AT+COPS?
++COPS: 0
+
+OK
+AT+CPAS?
+ERROR
+AT+CAP
+EXT: I
+
+ERROR
+AT+CPAS
++CPAS: 0
+
+OK
+AT+COPS?
++COPS: 0
+
+OK
+AT+COPS=?
AT-Command Interpreter ready
+AT+CPIN?
++CPIN: READY
+
+OK
+AT+CMEC
+EXT: I
+
+ERROR
+AT+CMEC?
+EXT: I
+
+ERROR
+AT+CDIS?
+EXT: I
+
+ERROR
+AT+CIND?
++CIND: 0,0
+
+OK
+AT+CIND=/?
+OK
+AT+CIND=?
++CIND: ("signal", (0-5)), ("smsfull", (0-1))
+
+OK
+AT+CMER?
++CMER: 0,0,0,0,0
+
+OK
+AT+CMER=?
++CMER: (0-2), (0), (0), (0-2), (0,1)
+
+OK
+cu: Got hangup signal
+
+Disconnected.
+%                                                                                                        

laforge at rama%pts/11 (22:31) phone/src/libgsmd/atcmd >  3/0
\ No newline at end of file

Added: developers/seanchiang/gsm/src/Makefile.am
===================================================================
--- developers/seanchiang/gsm/src/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1 @@
+SUBDIRS = gsmd libgsmd util

Added: developers/seanchiang/gsm/src/gsmd/Makefile.am
===================================================================
--- developers/seanchiang/gsm/src/gsmd/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,11 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS = -std=gnu99
+
+sbin_PROGRAMS = gsmd
+
+gsmd_SOURCES = gsmd.c atcmd.c select.c vendor.c usock.c unsolicited.c log.c \
+	       vendor_ti.c talloc.c operator_cache.c ext_response.c
+#gsmd_LDADD = ../libgsmd/libgsmd.la
+#gsmd_LDFLAGS = -dynamic
+
+noinst_HEADERS = gsmd.h

Added: developers/seanchiang/gsm/src/gsmd/atcmd.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/atcmd.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/atcmd.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,475 @@
+/* gsmd AT command interpreter / parser / constructor
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <termios.h>
+
+#include <sys/types.h>
+
+#include <common/linux_list.h>
+
+#include "gsmd.h"
+
+#include <gsmd/ts0707.h>
+#include <gsmd/gsmd.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/talloc.h>
+#include <gsmd/unsolicited.h>
+
+static void *__atcmd_ctx;
+
+enum final_result_codes {
+	GSMD_RESULT_OK = 0,
+	GSMD_RESULT_ERR = 1,
+	NUM_FINAL_RESULTS,
+};
+
+static const char *final_results[] = {
+	"OK",
+	"ERROR",
+	"+CME ERROR:"
+};
+
+/* we basically implement a parse that can deal with
+ * - receiving and queueing commands from higher level of libgmsd
+ * - optionally combining them into one larger command (; appending)
+ * - sending those commands to the TA, receiving and parsing responses
+ * - calling back application on completion, or waiting synchronously
+ *   for a response
+ * - dealing with intermediate and unsolicited resultcodes by calling
+ *   back into the application / higher levels
+ */
+
+static inline int llparse_append(struct llparser *llp, char byte)
+{
+	if (llp->cur < llp->buf + llp->len) {
+		*(llp->cur++) = byte;
+		return 0;
+	} else {
+		DEBUGP("llp->cur too big!!!\n");
+		return -EFBIG;
+	}
+}
+
+static int llparse_byte(struct llparser *llp, char byte)
+{
+	int ret = 0;
+
+	switch (llp->state) {
+	case LLPARSE_STATE_IDLE:
+		if (llp->flags & LGSM_ATCMD_F_EXTENDED) {
+			if (byte == '\r')
+				llp->state = LLPARSE_STATE_IDLE_CR;
+			else {
+#ifdef STRICT
+				llp->state = LLPARSE_STATE_ERROR;
+#else
+				llp->state = LLPARSE_STATE_RESULT;
+				ret = llparse_append(llp, byte);
+#endif
+			}
+		} else {
+			llp->state = LLPARSE_STATE_RESULT;
+			ret = llparse_append(llp, byte);
+		}
+		break;
+	case LLPARSE_STATE_IDLE_CR:
+		if (byte == '\n')
+			llp->state = LLPARSE_STATE_IDLE_LF;
+		else
+			llp->state = LLPARSE_STATE_ERROR;
+		break;
+	case LLPARSE_STATE_IDLE_LF:
+		/* can we really go directly into result_cr ? */
+		if (byte == '\r')
+			llp->state = LLPARSE_STATE_RESULT_CR;
+		else {
+			llp->state = LLPARSE_STATE_RESULT;
+			ret = llparse_append(llp, byte);
+		}
+		break;
+	case LLPARSE_STATE_RESULT:
+		if (byte == '\r')
+			llp->state = LLPARSE_STATE_RESULT_CR;
+		else
+			ret = llparse_append(llp, byte);
+		break;
+	case LLPARSE_STATE_RESULT_CR:
+		if (byte == '\n') {
+			/* re-set cursor to start of buffer */
+			llp->cur = llp->buf;
+			llp->state = LLPARSE_STATE_IDLE;
+			memset(llp->buf, 0, LLPARSE_BUF_SIZE);
+		}
+		break;
+	case LLPARSE_STATE_ERROR:
+		break;
+	}
+
+	return ret;
+}
+
+static int llparse_string(struct llparser *llp, char *buf, unsigned int len)
+{
+	while (len--) {
+		int rc = llparse_byte(llp, *(buf++));
+		if (rc < 0)
+			return rc;
+
+		/* if _after_ parsing the current byte we have finished,
+		 * let the caller know that there is something to handle */
+		if (llp->state == LLPARSE_STATE_RESULT_CR) {
+			/* FIXME: what to do with return value ? */
+			llp->cb(llp->buf, llp->cur - llp->buf, llp->ctx);
+		}
+	}
+
+	return 0;
+}
+
+static int llparse_init(struct llparser *llp)
+{
+	llp->state = LLPARSE_STATE_IDLE;
+	return 0;
+}
+
+/* mid-level parser */
+
+static int parse_final_result(const char *res)
+{
+	int i;
+	for (i = 0; i < NUM_FINAL_RESULTS; i++) {
+		if (!strcmp(res, final_results[i]))
+			return i;
+	}
+	
+	return -1;
+}
+
+static int ml_parse(const char *buf, int len, void *ctx)
+{
+	struct gsmd *g = ctx;
+	struct gsmd_atcmd *cmd = NULL;
+	int rc = 0, final = 0;
+
+	DEBUGP("buf=`%s'(%d)\n", buf, len);
+
+	/* FIXME: This needs to be part of the vendor plugin. If we receive
+	 * an empty string or that 'ready' string, we need to init the modem */
+	if (strlen(buf) == 0 ||
+	    !strcmp(buf, "AT-Command Interpreter ready")) {
+		gsmd_initsettings(g);
+		return 0;
+	}
+
+	/* responses come in order, so first response has to be for first
+	 * command we sent, i.e. first entry in list */
+	if (!llist_empty(&g->busy_atcmds))
+		cmd = llist_entry(g->busy_atcmds.next,
+				  struct gsmd_atcmd, list);
+
+	/* we have to differentiate between the following cases:
+	 *
+	 * A) an information response ("+whatever: ...")
+	 *    we just pass it up the callback
+	 * B) an unsolicited message ("+whateverelse: ... ")
+	 *    we call the unsolicited.c handlers
+	 * C) a final response ("OK", "+CME ERROR", ...)
+	 *    in this case, we need to check whether we already sent some
+	 *    previous data to the callback (information response).  If yes,
+	 *    we do nothing.  If no, we need to call the callback.
+	 * D) an intermediate response ("CONNECTED", "BUSY", "NO DIALTONE")
+	 *    TBD
+	 */
+
+	if (buf[0] == '+' || buf[0] == '%') {
+		/* an extended response */
+		const char *colon = strchr(buf, ':');
+		if (!colon) {
+			gsmd_log(GSMD_ERROR, "no colon in extd response `%s'\n",
+				buf);
+			return -EINVAL;
+		}
+		if (!strncmp(buf+1, "CME ERROR", 9)) {
+			/* Part of Case 'C' */
+			unsigned long err_nr;
+			err_nr = strtoul(colon+1, NULL, 10);
+			DEBUGP("error number %lu\n", err_nr);
+			if (cmd)
+				cmd->ret = err_nr;
+			final = 1;
+			goto final_cb;
+		}
+
+		if (!cmd || strncmp(buf, &cmd->buf[2], colon-buf)) {
+			/* Assuming Case 'B' */
+			DEBUGP("extd reply `%s' to cmd `%s', must be "
+			       "unsolicited\n", buf, cmd ? &cmd->buf[2] : "NONE");
+			colon++;
+			if (colon > buf+len)
+				colon = NULL;
+			rc = unsolicited_parse(g, buf, len, colon);
+			/* if unsolicited parser didn't handle this 'reply', then we 
+			 * need to continue and try harder and see what it is */
+			if (rc != -ENOENT) {
+				/* Case 'B' finished */
+				return rc;
+			}
+			/* contine, not 'B' */
+		}
+
+		if (cmd) {
+			if (cmd->buf[2] != '+' && cmd->buf[2] != '%') {
+				gsmd_log(GSMD_ERROR, "extd reply to non-extd command?\n");
+				return -EINVAL;
+			}
+
+			/* if we survive till here, it's a valid extd response
+			 * to an extended command and thus Case 'A' */
+	
+			/* FIXME: solve multi-line responses ! */
+			if (cmd->buflen < len)
+				len = cmd->buflen;
+
+			memcpy(cmd->buf, buf, len);
+		}
+	} else {
+		if (!strcmp(buf, "RING")) {
+			/* this is the only non-extended unsolicited return
+			 * code, part of Case 'B' */
+			return unsolicited_parse(g, buf, len, NULL);
+		}
+
+		if (!strcmp(buf, "ERROR") ||
+		    ((g->flags & GSMD_FLAG_V0) && buf[0] == '4')) {
+			/* Part of Case 'C' */
+			DEBUGP("unspecified error\n");
+			if (cmd)
+				cmd->ret = 4;
+			final = 1;
+			goto final_cb;
+		}
+
+		if (!strncmp(buf, "OK", 2)
+		    || ((g->flags & GSMD_FLAG_V0) && buf[0] == '0')) {
+			/* Part of Case 'C' */
+			if (cmd)
+				cmd->ret = 0;
+			final = 1;
+			goto final_cb;
+		}
+
+		/* FIXME: handling of those special commands in response to
+		 * ATD / ATA */
+		if (!strncmp(buf, "NO CARRIER", 11)) {
+			/* Part of Case 'D' */
+			final = 1;
+			goto final_cb;
+		}
+
+		if (!strncmp(buf, "BUSY", 4)) {
+			/* Part of Case 'D' */
+			final = 1;
+			goto final_cb;
+		}
+	}
+
+	/* we reach here, if we are at an information response that needs to be
+	 * passed on */
+
+final_cb:
+	/* if we reach here, the final result code of a command has been reached */
+
+	if (!cmd)
+		return rc;
+
+	if (cmd && cmd->ret != 0)
+		generate_event_from_cme(g, cmd->ret);
+
+	if (!cmd->cb) {
+		gsmd_log(GSMD_NOTICE, "command without cb!!!\n");
+	} else {
+		if (!final || !cmd->resp) {
+			/* if we reach here, we didn't send any information responses yet */
+			DEBUGP("Calling cmd->cb()\n");
+			cmd->resp = buf;
+			rc = cmd->cb(cmd, cmd->ctx, buf);
+		}
+	}
+
+	if (final) {
+		/* remove from list of currently executing cmds */
+		llist_del(&cmd->list);
+		talloc_free(cmd);
+
+		/* if we're finished with current commands, but still have pending
+		 * commands: we want to WRITE again */
+		if (llist_empty(&g->busy_atcmds) && !llist_empty(&g->pending_atcmds))
+			g->gfd_uart.when |= GSMD_FD_WRITE;
+	}
+
+	return rc;
+}	
+
+/* callback to be called if [virtual] UART has some data for us */
+static int atcmd_select_cb(int fd, unsigned int what, void *data)
+{
+	int len, rc;
+	static char rxbuf[1024];
+	struct gsmd *g = data;
+
+	if (what & GSMD_FD_READ) {
+		memset(rxbuf, 0, sizeof(rxbuf));
+		while ((len = read(fd, rxbuf, sizeof(rxbuf)))) {
+			if (len < 0) {
+				if (errno == EAGAIN)
+					return 0;
+				gsmd_log(GSMD_NOTICE, "ERROR reading from fd %u: %d (%s)\n", fd, len,
+					strerror(errno));
+					return len;
+			}
+			rc = llparse_string(&g->llp, rxbuf, len);
+			if (rc < 0) {
+				gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc);
+				return rc;
+			}
+		}
+	}
+
+	/* write pending commands to UART */
+	if (what & GSMD_FD_WRITE) {
+		struct gsmd_atcmd *pos, *pos2;
+		llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) {
+			len = strlen(pos->buf);
+			rc = write(fd, pos->buf, strlen(pos->buf));
+			if (rc == 0) {
+				gsmd_log(GSMD_ERROR, "write returns 0, aborting\n");
+				break;
+			} else if (rc < 0) {
+				gsmd_log(GSMD_ERROR, "error during write to fd %d: %d\n",
+					fd, rc);
+				return rc;
+			}
+			if (rc < len) {
+				gsmd_log(GSMD_FATAL, "short write!!! FIXME!\n");
+				exit(3);
+			}
+			write(fd, "\r", 1);
+			/* success: remove from global list of to-be-sent atcmds */
+			llist_del(&pos->list);
+			/* append to global list of executing atcmds */
+			llist_add_tail(&pos->list, &g->busy_atcmds);
+
+				/* we only send one cmd at the moment */
+				g->gfd_uart.when &= ~GSMD_FD_WRITE;
+				break;
+		}
+	}
+
+#if 0
+	if (llist_empty(&g->pending_atcmds))
+		g->gfd_uart.when &= ~GSMD_FD_WRITE;
+#endif
+		
+
+	return 0;
+}
+
+
+struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen,
+			      atcmd_cb_t cb, void *ctx, u_int16_t id)
+{
+	int buflen = strlen(cmd);
+	struct gsmd_atcmd *atcmd;
+	
+	if (rlen > buflen)
+		buflen = rlen;
+	
+	atcmd = talloc_size(__atcmd_ctx, sizeof(*atcmd)+ buflen);
+	if (!atcmd)
+		return NULL;
+
+	atcmd->ctx = ctx;
+	atcmd->id = id;
+	atcmd->flags = 0;
+	atcmd->ret = -255;
+	atcmd->buflen = buflen;
+	atcmd->buf[buflen-1] = '\0';
+	atcmd->cb = cb;
+	atcmd->resp = NULL;
+	strncpy(atcmd->buf, cmd, buflen-1);
+
+	return atcmd;
+}
+
+/* submit an atcmd in the global queue of pending atcmds */
+int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd)
+{
+	DEBUGP("submitting command `%s'\n", cmd->buf);
+
+	llist_add_tail(&cmd->list, &g->pending_atcmds);
+	g->gfd_uart.when |= GSMD_FD_WRITE;
+
+	return 0;
+}
+
+void atcmd_drain(int fd)
+{
+	int rc;
+	struct termios t;
+	rc = tcflush(fd, TCIOFLUSH);
+	rc = tcgetattr(fd, &t);
+	DEBUGP("c_iflag = 0x%08x, c_oflag = 0x%08x, c_cflag = 0x%08x, c_lflag = 0x%08x\n",
+		t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
+	t.c_iflag = t.c_oflag = 0;
+	cfmakeraw(&t);
+	rc = tcsetattr(fd, TCSANOW, &t);
+}
+
+/* init atcmd parser */
+int atcmd_init(struct gsmd *g, int sockfd)
+{
+	__atcmd_ctx = talloc_named_const(gsmd_tallocs, 1, "atcmds");
+
+	g->gfd_uart.fd = sockfd;
+	g->gfd_uart.when = GSMD_FD_READ;
+	g->gfd_uart.data = g;
+	g->gfd_uart.cb = &atcmd_select_cb;
+
+	INIT_LLIST_HEAD(&g->pending_atcmds);
+	INIT_LLIST_HEAD(&g->busy_atcmds);
+
+	llparse_init (&g->llp);
+
+	g->llp.cur = g->llp.buf;
+	g->llp.len = sizeof(g->llp.buf);
+	g->llp.cb = &ml_parse;
+	g->llp.ctx = g;
+	g->llp.flags = LGSM_ATCMD_F_EXTENDED;
+
+	return gsmd_register_fd(&g->gfd_uart);
+}	
+

Added: developers/seanchiang/gsm/src/gsmd/ext_response.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/ext_response.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/ext_response.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,213 @@
+/* gsmd extended response parser
+ *
+ * (C) 2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/extrsp.h>
+#include <gsmd/talloc.h>
+
+int extrsp_supports(const struct gsm_extrsp *er, int index, int value)
+{
+	int i;
+
+	if (index >= er->num_tokens)
+		return -EINVAL;
+	if (er->tokens[index].type != GSMD_ECMD_RTT_RANGE)
+		return -EINVAL;
+
+	for (i = 0; i < er->tokens[index].u.range.num_items; i++) {
+		struct gsm_extrsp_range_item *ri = 
+			&er->tokens[index].u.range.item[i];
+		if (value >= ri->min && value <= ri->max)
+			return 1;
+	}
+
+	return 0;
+}
+
+enum parser_state {
+	IDLE,
+	TOKEN_STRING,
+	TOKEN_STRING_LASTQUOTE,
+	TOKEN_NUMERIC,
+	TOKEN_RANGE,
+};
+		
+/* parse a comma-separated list, possibly containing quote values */
+struct gsm_extrsp *extrsp_parse(const void *ctx, const char *input)
+{
+	const char *cur = input;
+	struct gsm_extrsp *er;
+	int cur_tok = 0;
+	enum parser_state state = IDLE;
+	char buf[512];
+	char *cur_buf = buf;
+	struct gsm_extrsp_tok *cur_token;
+
+	if (!input || strlen(input) == 0)
+		return NULL;
+
+	er = talloc(ctx, struct gsm_extrsp);
+	if (!er)
+		return NULL;
+	memset(er, 0, sizeof(*er));
+
+	while (*cur) {
+		cur_token = &er->tokens[er->num_tokens];
+
+		switch (state) {
+		case IDLE:
+			memset(buf, 0, sizeof(buf));
+			cur_buf = buf;
+
+			if (isblank(*cur))
+				break;
+			else if (*cur == '"') {
+				cur_token->type = GSMD_ECMD_RTT_STRING;
+				state = TOKEN_STRING;
+			} else if (*cur == '(') {
+				cur_token->type = GSMD_ECMD_RTT_RANGE;
+				state = TOKEN_RANGE;
+			} else if (isdigit(*cur)) {
+				cur_token->type = GSMD_ECMD_RTT_NUMERIC;
+				*cur_buf = *cur;
+				cur_buf++;
+				state = TOKEN_NUMERIC;
+			} else if (*cur == ',') {
+				cur_token->type = GSMD_ECMD_RTT_EMPTY;
+				er->num_tokens++;
+				state = IDLE;
+			}
+			break;
+		case TOKEN_NUMERIC:
+			if (*cur == ',') {
+				/* end of number */
+				cur_token->u.numeric = atoi(buf);
+				er->num_tokens++;
+				state = IDLE;
+			} else if (isdigit(*cur)) {
+				*cur_buf = *cur;
+				cur_buf++;
+			} else {
+				/* ERORR */
+			}
+			break;
+		case TOKEN_STRING:
+			if (*cur == '"') {
+				int len = strlen(buf);
+				if (len > sizeof(cur_token->u.string)-1)
+					len = sizeof(cur_token->u.string)-1;
+
+				/* end of string token */
+				strncpy(cur_token->u.string, buf, len);
+				er->num_tokens++;
+				state = TOKEN_STRING_LASTQUOTE;
+			} else {
+				*cur_buf = *cur;
+				cur_buf++;
+			}
+			break;
+		case TOKEN_STRING_LASTQUOTE:
+			if (*cur == ',')
+				state = IDLE;
+			else {
+				/* ERROR */
+			}
+			break;
+		case TOKEN_RANGE:
+			if (isdigit(*cur)) {
+				*cur_buf = *cur;
+				cur_buf++;
+			} else if (*cur == '-') {
+				/* previous number has completed */
+				cur_token->u.range.item[cur_token->u.range.num_items].min = atoi(buf);
+				memset(buf, 0, sizeof(buf));
+				cur_buf = buf;
+			} else if (*cur == ',') {
+				/* previous number has completed */
+				cur_token->u.range.item[cur_token->u.range.num_items].max = atoi(buf);
+				cur_token->u.range.num_items++;
+			} else if (*cur == ')') {
+				/* previous number has completed */
+				cur_token->u.range.item[cur_token->u.range.num_items].max = atoi(buf);
+				cur_token->u.range.num_items++;
+				state = TOKEN_STRING_LASTQUOTE;
+				er->num_tokens++;
+			} else {
+				/* ERROR */
+			}
+			break;
+		}
+		cur++;
+	}
+
+	//extrsp_dump(er);
+	return er;
+}
+
+static const char *er_tok_names[] = {
+	[GSMD_ECMD_RTT_EMPTY]	= "EMPTY",
+	[GSMD_ECMD_RTT_NUMERIC]	= "NUMERIC",
+	[GSMD_ECMD_RTT_STRING]	= "STRING",
+	[GSMD_ECMD_RTT_RANGE]	= "RANGE",
+};
+
+void extrsp_dump(const struct gsm_extrsp *er)
+{
+	int i;
+
+	DEBUGP("entering(er=%p, num_tokens=%u)\n", er, er->num_tokens);
+	for (i = 0; i < er->num_tokens; i++) {
+		const struct gsm_extrsp_tok *tok = &er->tokens[i];
+		DEBUGP("Token %u: %s: ", i, er_tok_names[tok->type]);
+		switch (tok->type) {
+		case GSMD_ECMD_RTT_EMPTY:
+			DEBUGP("\n");
+			break;
+		case GSMD_ECMD_RTT_NUMERIC:
+			DEBUGP("%d\n", tok->u.numeric);
+			break;
+		case GSMD_ECMD_RTT_STRING:
+			DEBUGP("%s\n", tok->u.string);
+			break;
+		case GSMD_ECMD_RTT_RANGE: {
+			int j;
+			for (j = 0; j < tok->u.range.num_items; j++)
+				DEBUGP("%d-%d, ", tok->u.range.item[j].min,
+					tok->u.range.item[j].max);
+			}
+			
+			break;
+		}
+	}
+
+}

Added: developers/seanchiang/gsm/src/gsmd/gsmd.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/gsmd.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/gsmd.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,307 @@
+/* gsmd core
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/select.h>
+#include <gsmd/usock.h>
+#include <gsmd/vendorplugin.h>
+#include <gsmd/talloc.h>
+
+static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	printf("`%s' returned `%s'\n", cmd->buf, resp);
+	return 0;
+}
+
+int gsmd_simplecmd(struct gsmd *gsmd, char *cmdtxt)
+{
+	struct gsmd_atcmd *cmd;
+	cmd = atcmd_fill(cmdtxt, strlen(cmdtxt)+1, &gsmd_test_atcb, NULL, 0);
+	if (!cmd)
+		return -ENOMEM;
+	
+	return atcmd_submit(gsmd, cmd);
+}
+
+int gsmd_initsettings(struct gsmd *gsmd)
+{
+	int rc;
+	
+	/* echo on, verbose */
+	rc |= gsmd_simplecmd(gsmd, "ATE0V1");
+	/* use +CRING instead of RING */
+	rc |= gsmd_simplecmd(gsmd, "AT+CRC=1");
+	/* enable +CREG: unsolicited response if registration status changes */
+	rc |= gsmd_simplecmd(gsmd, "AT+CREG=2");
+	/* use +CME ERROR: instead of ERROR */
+	rc |= gsmd_simplecmd(gsmd, "AT+CMEE=1");
+	/* use +CLIP: to indicate CLIP */
+	rc |= gsmd_simplecmd(gsmd, "AT+CLIP=1");
+	/* use +COLP: to indicate COLP */
+	rc |= gsmd_simplecmd(gsmd, "AT+COLP=1");
+	/* power on the phone */
+	rc |= gsmd_simplecmd(gsmd, "AT+CFUN=1");
+	/* configure message format as PDU mode*/
+	/* FIXME: TEXT mode support!! */
+	rc |= gsmd_simplecmd(gsmd, "AT+CMGF=0");
+
+	if (gsmd->vendorpl && gsmd->vendorpl->initsettings)
+		return gsmd->vendorpl->initsettings(gsmd);
+	else
+		return rc;
+}
+
+struct bdrt {
+	int bps;
+	u_int32_t b;
+};
+
+static struct bdrt bdrts[] = {
+	{ 0, B0 },
+	{ 9600, B9600 },
+	{ 19200, B19200 },
+	{ 38400, B38400 },
+	{ 57600, B57600 },
+	{ 115200, B115200 },
+};
+
+static int set_baudrate(int fd, int baudrate, int hwflow)
+{
+	int i;
+	u_int32_t bd = 0;
+	struct termios ti;
+
+	for (i = 0; i < ARRAY_SIZE(bdrts); i++) {
+		if (bdrts[i].bps == baudrate)
+			bd = bdrts[i].b;
+	}
+	if (bd == 0)
+		return -EINVAL;
+	
+	i = tcgetattr(fd, &ti);
+	if (i < 0)
+		return i;
+	
+	i = cfsetispeed(&ti, B0);
+	if (i < 0)
+		return i;
+	
+	i = cfsetospeed(&ti, bd);
+	if (i < 0)
+		return i;
+	
+	if (hwflow)
+		ti.c_cflag |= CRTSCTS;
+	else
+		ti.c_cflag &= ~CRTSCTS;
+
+	return tcsetattr(fd, 0, &ti);
+}
+
+
+static struct gsmd g;
+
+static int gsmd_initialize(struct gsmd *g)
+{
+	INIT_LLIST_HEAD(&g->users);
+
+	return 0;
+}
+
+static struct option opts[] = {
+	{ "version", 0, NULL, 'V' },
+	{ "daemon", 0, NULL, 'd' },
+	{ "help", 0, NULL, 'h' },
+	{ "device", 1, NULL, 'p' },
+	{ "speed", 1, NULL, 's' },
+	{ "logfile", 1, NULL, 'l' },
+	{ "hwflow", 0, NULL, 'F' },
+	{ "leak-report", 0, NULL, 'L' },
+	{ 0, 0, 0, 0 }
+};
+
+static void print_help(void)
+{
+	printf("gsmd - (C) 2006 by Harald Welte <laforge at gnumonks.org>\n"
+	       "This program is FREE SOFTWARE under the terms of GNU GPL\n\n"
+	       "Usage:\n"
+	       "\t-v\t--version\tDisplay program version\n"
+	       "\t-d\t--daemon\tDeamonize\n"
+	       "\t-h\t--help\t\tDisplay this help message\n"
+	       "\t-p dev\t--device dev\tSpecify serial device to be used\n"
+	       "\t-s spd\t--speed spd\tSpecify speed in bps (9600,38400,115200,...)\n"
+	       "\t-F\t--hwflow\tHardware Flow Control (RTS/CTS)\n"
+	       "\t-L\t--leak-report\tLeak Report of talloc memory allocator\n"
+	       "\t-l file\t--logfile file\tSpecify a logfile to log to\n"
+	       );
+}
+
+static void sig_handler(int signr)
+{
+	switch (signr) {
+	case SIGTERM:
+	case SIGINT:
+		talloc_report_full(gsmd_tallocs, stderr);
+		exit(0);
+		break;
+	case SIGUSR1:
+		talloc_report_full(gsmd_tallocs, stderr);
+		break;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int fd, argch; 
+
+	int daemonize = 0;
+	int bps = 115200;
+	int hwflow = 0;
+	char *device = "/dev/ttyUSB0";
+	char *logfile = "syslog";
+
+	signal(SIGTERM, sig_handler);
+	signal(SIGINT, sig_handler);
+	signal(SIGSEGV, sig_handler);
+	signal(SIGUSR1, sig_handler);
+	
+	gsmd_tallocs = talloc_named_const(NULL, 1, "GSMD");
+
+	/*FIXME: parse commandline, set daemonize, device, ... */
+	while ((argch = getopt_long(argc, argv, "FVLdhp:s:l:", opts, NULL)) != -1) {
+		switch (argch) {
+		case 'V':
+			/* FIXME */
+			break;
+		case 'L':
+			talloc_enable_leak_report_full();
+			break;
+		case 'F':
+			hwflow = 1;
+			break;
+		case 'd':
+			daemonize = 1;
+			break;
+		case 'h':
+			/* FIXME */
+			print_help();
+			exit(0);
+			break;
+		case 'p':
+			device = optarg;
+			break;
+		case 's':
+			bps = atoi(optarg);
+			break;
+		case 'l':
+			if (gsmdlog_init(optarg)) {
+				fprintf(stderr, "can't open logfile `%s'\n", optarg);
+				exit(2);
+			}
+			break;
+		}
+	}
+
+	/* use direct access to device node ([virtual] tty device) */
+	fd = open(device, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "can't open device `%s': %s\n",
+			device, strerror(errno));
+		exit(1);
+	}
+
+	if (set_baudrate(fd, bps, hwflow) < 0) {
+		fprintf(stderr, "can't set baudrate\n");
+		exit(1);
+	}
+
+	if (gsmd_initialize(&g) < 0) {
+		fprintf(stderr, "internal error\n");
+		exit(1);
+	}
+
+	if (atcmd_init(&g, fd) < 0) {
+		fprintf(stderr, "can't initialize UART device\n");
+		exit(1);
+	}
+	atcmd_drain(fd);
+
+	if (usock_init(&g) < 0) {
+		fprintf(stderr, "can't open unix socket\n");
+		exit(1);
+	}
+
+	if (daemonize) {
+		if (fork()) {
+			exit(0);
+		}
+		fclose(stdout);
+		fclose(stderr);
+		fclose(stdin);
+		setsid();
+	}
+
+	/* FIXME: do this dynamically */
+	ticalypso_init();
+
+	gsmd_vendor_plugin_find(&g);
+
+	gsmd_initsettings(&g);
+
+	gsmd_opname_init(&g);
+
+	while (1) {
+		int ret = gsmd_select_main();
+		if (ret == 0)
+			continue;
+
+		if (ret < 0) {
+			if (errno == -EINTR)
+				continue;
+			else {
+				DEBUGP("select returned error (%s)\n",
+					strerror(errno));
+				break;
+			}
+		}
+	}
+
+	exit(0);
+}

Added: developers/seanchiang/gsm/src/gsmd/gsmd.h
===================================================================
--- developers/seanchiang/gsm/src/gsmd/gsmd.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/gsmd.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,3 @@
+#ifndef __GSMD__
+#define __GSMD__
+#endif

Added: developers/seanchiang/gsm/src/gsmd/gsmd_event.h
===================================================================
--- developers/seanchiang/gsm/src/gsmd/gsmd_event.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/gsmd_event.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,53 @@
+#ifndef __GSMD_EVENT_H
+#define __GSMD_EVENT_H
+
+/* event handling */
+
+enum gsmd_event_type {
+	GSMD_EVTTYPE_NONE,
+	GSMD_EVTTYPE_VOICECALL,
+	GSMD_EVTTYPE_DATACALL,
+	GSMD_EVTTYPE_SMS,
+	GSMD_EVTTYPE_GPRS,
+	GSMD_EVTTYPE_CIPHER_IND,
+};
+
+enum gsmd_event_call {
+	GSMD_EVT_CALL_NONE,
+	GSMD_EVT_CALL_HANGUP,		/* any call: hanged up */
+	GSMD_EVT_CALL_RING,		/* incoming call: we're ringing */ 
+	GSMD_EVT_CALL_BUSY,		/* outgoing call: busy */
+	GSMD_EVT_CALL_RINGING,		/* outgoing call: other end ringing */
+	GSMD_EVT_CALL_ESTABLISHED,	/* any call: now established */
+};
+
+enum gsmd_event_voice {
+	/* all of event_call */
+};
+
+enum gsmd_event_data {
+	/* all of event_call */
+};
+
+enum gsmd_event_sms {
+	GSMD_EVT_SMS_NONE,
+	GSMD_EVT_SMS_RCVD,		/* incoming SMS received */
+	GSMD_EVT_SMS_OVERFLOW,		/* sms memory full, can't receive */
+};
+
+enum gsmd_event_gprs {
+};
+
+enum gsmd_event_cipher {
+	GSMD_EVT_CI_NONE,
+	GSMD_EVT_CI_ENABLED,		/* cipher enabled */
+	GSMD_EVT_CI_DISABLED,		/* cipher disabled */
+};
+
+enum gsmd_event_network {
+	GSMD_EVT_NW_NONE,
+	GSMD_EVT_NW_SIGNAL,		/* signal strength */
+	GSMD_EVT_NW_REG,		/* network registration */
+};
+
+#endif

Added: developers/seanchiang/gsm/src/gsmd/log.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/log.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/log.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,109 @@
+/* gsmd logging functions 
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <sys/types.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+
+static FILE *logfile;
+static FILE syslog_dummy;
+static int loglevel;
+
+static int gsmd2syslog[] = {
+	[GSMD_DEBUG]	= LOG_DEBUG,
+	[GSMD_INFO]	= LOG_INFO,
+	[GSMD_NOTICE]	= LOG_NOTICE,
+	[GSMD_ERROR]	= LOG_ERR,
+	[GSMD_FATAL]	= LOG_CRIT,
+};
+
+static inline int gsmd2syslog_level(int level)
+{
+	if (level >= ARRAY_SIZE(gsmd2syslog))
+		return LOG_ERR;
+
+	return gsmd2syslog[level];
+}
+
+void __gsmd_log(int level, const char *file, int line, const char *function,
+		const char *format, ...)
+{
+	char *timestr;
+	va_list ap;
+	time_t tm;
+	FILE *outfd;
+
+	if (level < loglevel)
+		return;
+	
+	if (logfile == &syslog_dummy) {
+		va_start(ap, format);
+		vsyslog(gsmd2syslog_level(level), format, ap);
+		va_end(ap);
+	} else {
+		if (logfile)
+			outfd = logfile;
+		else
+			outfd = stderr;
+
+		tm = time(NULL);
+		timestr = ctime(&tm);
+		timestr[strlen(timestr)-1] = '\0';
+		fprintf(outfd, "%s <%1.1d> %s:%d:%s() ", timestr, level, file, 
+			line, function);
+
+		va_start(ap, format);
+		vfprintf(outfd, format, ap);
+		va_end(ap);
+
+		fflush(outfd);
+	}
+}
+
+int gsmdlog_init(const char *path)
+{
+	
+	if (!strcmp(path, "syslog")) {
+		logfile = &syslog_dummy;
+		openlog("gsmd", 0, LOG_DAEMON);
+	} else {
+		logfile = fopen(path, "a+");
+	}
+
+	if (logfile == NULL)
+		return -1;
+	
+	gsmd_log(LOG_INFO, "logfile successfully opened\n");
+
+	return 0;
+}

Added: developers/seanchiang/gsm/src/gsmd/operator_cache.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/operator_cache.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/operator_cache.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,99 @@
+/* gsmd cache of operator names
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "gsmd.h"
+
+#include <common/linux_list.h>
+#include <gsmd/gsmd.h>
+#include <gsmd/talloc.h>
+
+static void *__opc_ctx;
+
+struct opname {
+	struct llist_head list;
+	struct {
+		u_int16_t mcc;	/* mobile country code */
+		u_int8_t mnc;	/* mobile network code */
+	} numeric;
+	char alnum_long[16+1];
+	//char alnum_short[8+1];
+};
+
+/* add an entry to the operator name list, overwrite existing entries for
+ * same mcc/mnc */
+static int _opname_add(struct gsmd *g, struct opname *op)
+{
+	struct opname *cur, *cur2;
+
+	llist_for_each_entry_safe(cur, cur2, &g->operators, list) {
+		if (op->numeric.mcc == cur->numeric.mcc &&
+		    op->numeric.mnc == cur->numeric.mnc) {
+			llist_del(&cur->list);
+			talloc_free(cur);
+		}
+	}
+	llist_add_tail(&op->list, &g->operators);
+
+	return 0;
+}
+
+int gsmd_opname_add(struct gsmd *g, const char *numeric_bcd_string,
+		    const char *alnum_long)
+{
+	struct opname *op;
+	char mcc[3+1];
+	char mnc[2+1];
+
+	if (strlen(numeric_bcd_string) != 5)
+		return -EINVAL;
+
+	op = talloc(__opc_ctx, struct opname);
+	if (!op)
+		return -ENOMEM;
+	
+	memset(mcc, 0, sizeof(mcc));
+	memset(mnc, 0, sizeof(mnc));
+
+	strncpy(mcc, numeric_bcd_string, 3);
+	strncpy(mnc, numeric_bcd_string+3, 2);
+
+	strncpy(op->alnum_long, alnum_long, sizeof(op->alnum_long-1));
+	op->numeric.mcc = atoi(mcc);
+	op->numeric.mnc = atoi(mnc);
+
+	return _opname_add(g, op);
+}
+
+int gsmd_opname_init(struct gsmd *g)
+{
+	INIT_LLIST_HEAD(&g->operators);
+
+	__opc_ctx = talloc_named_const(gsmd_tallocs, 1, "operator_cache");
+
+	return 0;
+}

Added: developers/seanchiang/gsm/src/gsmd/select.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/select.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/select.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,101 @@
+/* select() FD handling for GSM Daemon.
+ * (C) 2000-2006 by Harald Welte <laforge at gnumonks.org>
+ *
+ * Based on code originally written by myself for ulogd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <fcntl.h>
+#include <common/linux_list.h>
+
+#include "gsmd.h"
+
+#include <gsmd/select.h>
+
+static int maxfd = 0;
+static LLIST_HEAD(gsmd_fds);
+
+int gsmd_register_fd(struct gsmd_fd *fd)
+{
+	int flags;
+
+	/* make FD nonblocking */
+	flags = fcntl(fd->fd, F_GETFL);
+	if (flags < 0)
+		return -1;
+	flags |= O_NONBLOCK;
+	flags = fcntl(fd->fd, F_SETFL, flags);
+	if (flags < 0)
+		return -1;
+
+	/* Register FD */
+	if (fd->fd > maxfd)
+		maxfd = fd->fd;
+
+	llist_add_tail(&fd->list, &gsmd_fds);
+
+	return 0;
+}
+
+void gsmd_unregister_fd(struct gsmd_fd *fd)
+{
+	llist_del(&fd->list);
+}
+
+int gsmd_select_main()
+{
+	struct gsmd_fd *ufd, *ufd2;
+	fd_set readset, writeset, exceptset;
+	int i;
+
+	FD_ZERO(&readset);
+	FD_ZERO(&writeset);
+	FD_ZERO(&exceptset);
+
+	/* prepare read and write fdsets */
+	llist_for_each_entry(ufd, &gsmd_fds, list) {
+		if (ufd->when & GSMD_FD_READ)
+			FD_SET(ufd->fd, &readset);
+
+		if (ufd->when & GSMD_FD_WRITE)
+			FD_SET(ufd->fd, &writeset);
+
+		if (ufd->when & GSMD_FD_EXCEPT)
+			FD_SET(ufd->fd, &exceptset);
+	}
+
+	i = select(maxfd+1, &readset, &writeset, &exceptset, NULL);
+	if (i > 0) {
+		/* call registered callback functions */
+		llist_for_each_entry_safe(ufd, ufd2, &gsmd_fds, list) {
+			int flags = 0;
+
+			if (FD_ISSET(ufd->fd, &readset))
+				flags |= GSMD_FD_READ;
+
+			if (FD_ISSET(ufd->fd, &writeset))
+				flags |= GSMD_FD_WRITE;
+
+			if (FD_ISSET(ufd->fd, &exceptset))
+				flags |= GSMD_FD_EXCEPT;
+
+			if (flags)
+				ufd->cb(ufd->fd, flags, ufd->data);
+		}
+	}
+	return i;
+}

Added: developers/seanchiang/gsm/src/gsmd/sms_cb.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/sms_cb.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/sms_cb.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,203 @@
+/* gsmd SMS functions
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/usock.h>
+#include <gsmd/select.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/usock.h>
+
+enum ts0705_mem_type {
+	GSM0705_MEMTYPE_NONE,
+	GSM0705_MEMTYPE_BROADCAST,
+	GSM0705_MEMTYPE_BROADCAST,
+	GSM0705_MEMTYPE_ME_MESSAGE,
+	GSM0705_MEMTYPE_MT,
+	GSM0705_MEMTYPE_SIM,
+	GSM0705_MEMTYPE_TA,
+	GSM0705_MEMTYPE_SR,
+};
+
+static const char *ts0705_memtype_name = {
+	[GSM0705_MEMTYPE_NONE]		= "NONE",
+	[GSM0705_MEMTYPE_BROADCAST]	= "BM",
+	[GSM0705_MEMTYPE_ME_MESSAGE]	= "ME",
+	[GSM0705_MEMTYPE_MT]		= "MT",
+	[GSM0705_MEMTYPE_SIM]		= "SM",
+	[GSM0705_MEMTYPE_TA]		= "TA",
+	[GSM0705_MEMTYPE_SR]		= "SR",
+};
+
+static inline int parse_memtype(char *memtype)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ts0705_memtype_name); i++) {
+		if (!strcmp(ts0705_memtype_name[i], memtype))
+			return i;
+	}
+
+	return GSM0705_MEMTYPE_NONE;
+}
+
+struct __gsmd_sms_storage {
+	u_int8 memtype;
+	u_int8_t pad[3]
+	u_int16_t used;
+	u_int16_t total;
+} __attribute__ ((packed));
+
+struct gsmd_sms_storage {
+	struct __gsmd_sms_storage mem[3];
+} __attribute__ ((packed));
+
+static int usock_cpms_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;
+	struct gsmd_ucmd *ucmd = ucmd_alloc(sizeof(struct gsmd_sms_storage));
+
+	DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu);
+
+	if (!ucmd)
+		return -ENOMEM;
+
+
+	
+	
+	ucmd->hdr.version = GSMD_PROTO_VERSION;
+	ucmd->hdr.msg_type = GSMD_MSG_SMS;
+	ucmd->hdr.msg_subtype = GSMD_SMS_GETMSG_STORAGE;
+	ucmd->hdr.len = ...;
+	ucmd->hdr.id = cmd->id;
+	
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+/* main unix socket SMS receiver */
+static int usock_rcv_sms(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,
+			 int len)
+{
+	struct gsmd_atcmd *cmd;
+
+	switch (gph->msg_subtype) {
+	case GSMD_SMS_GET_SERVICE_CENTRE:
+		
+		break;
+	case GSMD_SMS_SET_SERVICE_CENTRE:
+		break;
+	case GSMD_SMS_SET_MSG_STORAGE:
+		break;
+	case GSMD_SMS_GET_MSG_STORAGE:
+		cmd = atcmd_fill("AT+CPMS?", 8, ...);
+		break;
+	}
+
+	return atcmd_submit(gu->gsmd, cmd);
+}
+
+/* main unix socket Cell Broadcast receiver */
+static int usock_rcv_cb(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,
+			int len)
+{
+
+	switch (gph->msg_subtype) {
+	case GSMD_CB_SUBSCRIBE:
+		break;
+	case GSMD_CB_UNSUBSCRIBE:
+		break;
+	}
+
+	return 
+}
+
+
+/* Unsolicited messages related to SMS / CB */
+static int cmti_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+}
+
+static int cmt_parse(char *buf, int len, const char *param,
+		     struct gsmd *gsmd)
+{
+}
+
+static int cbmi_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+}
+
+static int cbm_parse(char *buf, int len, const char *param,
+		     struct gsmd *gsmd)
+{
+}
+
+static int cdsi_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+}
+
+static int cds_parse(char *buf, int len, const char *param,
+		     struct gsmd *gsmd)
+{
+}
+
+
+static const struct gsmd_unsolocit gsm0705_unsolicit[] = {
+	{ "+CMTI",	&cmti_parse },	/* SMS Deliver Index (stored in ME/TA) */
+	{ "+CMT",	&cmt_parse },	/* SMS Deliver to TE */
+	{ "+CBMI",	&cbmi_parse },	/* Cell Broadcast Message Index */
+	{ "+CBM",	&cbm_parse },	/* Cell Broadcast Message */
+	{ "+CDSI",	&cdsi_parse },	/* SMS Status Report */
+	{ "+CDS",	&cds_parse },	/* SMS Status Index (stored in ME/TA) */
+};
+
+
+int sms_cb_init(struct gsmd *gsmd)
+{
+	struct gsmd_atcmd *atcmd;
+
+	atcmd = atcmd_fill("AT+CSMS=0", NULL, gu, 0);
+	if (!atcmd)
+		return -ENOMEM;
+	atcmd_submit(gsmd, atcmd);
+
+	/* Switch into "text mode" (Section 3.2.3) */
+	atcdm = atcmd_fill("AT+CMGF=1", 9, &sms_cb_init_cb, gu, 0);
+	if (!atcmd)
+		return -ENOMEM;
+
+	return atcmd_submit(gsmd, atcmd);
+}

Added: developers/seanchiang/gsm/src/gsmd/talloc.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/talloc.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/talloc.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,1133 @@
+/*
+   Samba Unix SMB/CIFS implementation.
+
+   Samba trivial allocation library - new interface
+
+   NOTE: Please read talloc_guide.txt for full documentation
+
+   Copyright (C) Andrew Tridgell 2004
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+  inspired by http://swapped.cc/halloc/
+*/
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if 1
+/* nfsim additions */
+//#define HAVE_SYS_TYPES_H
+//#define HAVE_UNISTD_H
+#define HAVE_STDARG_H
+//#define HAVE_STDINT_H
+#define HAVE_VA_COPY
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include "gsmd.h"
+#include <gsmd/talloc.h>
+
+/* use this to force every realloc to change the pointer, to stress test
+   code that might not cope */
+#define ALWAYS_REALLOC 0
+
+
+#define MAX_TALLOC_SIZE 0x10000000
+#define TALLOC_MAGIC 0xe814ec4f
+#define TALLOC_MAGIC_FREE 0x7faebef3
+#define TALLOC_MAGIC_REFERENCE ((const char *)1)
+
+/* by default we abort when given a bad pointer (such as when talloc_free() is
+ * called on a pointer that came from malloc() */
+#ifndef TALLOC_ABORT
+#define TALLOC_ABORT(reason) abort()
+#endif
+
+#ifndef discard_const_p
+#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
+# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
+#else
+# define discard_const_p(type, ptr) ((type *)(ptr))
+#endif
+#endif
+
+/* this null_context is only used if talloc_enable_leak_report() or
+   talloc_enable_leak_report_full() is called, otherwise it remains
+   NULL
+*/
+static const void *null_context;
+static void *cleanup_context;
+
+
+struct talloc_reference_handle {
+	struct talloc_reference_handle *next, *prev;
+	void *ptr;
+};
+
+typedef int (*talloc_destructor_t)(void *);
+
+struct talloc_chunk {
+	struct talloc_chunk *next, *prev;
+	struct talloc_chunk *parent, *child;
+	struct talloc_reference_handle *refs;
+	size_t size;
+	talloc_destructor_t destructor;
+	const char *name;
+	union {
+		unsigned magic;
+		double align_dummy;
+	} u;
+};
+
+/* panic if we get a bad magic value */
+static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
+{
+	struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1;
+	if (tc->u.magic != TALLOC_MAGIC) {
+		if (tc->u.magic == TALLOC_MAGIC_FREE) {
+			TALLOC_ABORT("Bad talloc magic value - double free");
+		} else {
+			TALLOC_ABORT("Bad talloc magic value - unknown value");
+		}
+	}
+
+	return tc;
+}
+
+/* hook into the front of the list */
+#define _TLIST_ADD(list, p) \
+do { \
+        if (!(list)) { \
+		(list) = (p); \
+		(p)->next = (p)->prev = NULL; \
+	} else { \
+		(list)->prev = (p); \
+		(p)->next = (list); \
+		(p)->prev = NULL; \
+		(list) = (p); \
+	}\
+} while (0)
+
+/* remove an element from a list - element doesn't have to be in list. */
+#define _TLIST_REMOVE(list, p) \
+do { \
+	if ((p) == (list)) { \
+		(list) = (p)->next; \
+		if (list) (list)->prev = NULL; \
+	} else { \
+		if ((p)->prev) (p)->prev->next = (p)->next; \
+		if ((p)->next) (p)->next->prev = (p)->prev; \
+	} \
+	if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
+} while (0)
+
+
+/*
+  return the parent chunk of a pointer
+*/
+static struct talloc_chunk *talloc_parent_chunk(const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	while (tc->prev) tc=tc->prev;
+	return tc->parent;
+}
+
+void *talloc_parent(const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_parent_chunk(ptr);
+	return (void *)(tc+1);
+}
+
+/*
+   Allocate a bit of memory as a child of an existing pointer
+*/
+void *_talloc(const void *context, size_t size)
+{
+	struct talloc_chunk *tc;
+
+	if (context == NULL) {
+		context = null_context;
+	}
+
+	if (size >= MAX_TALLOC_SIZE) {
+		return NULL;
+	}
+
+	tc = malloc(sizeof(*tc)+size);
+	if (tc == NULL) return NULL;
+
+	tc->size = size;
+	tc->u.magic = TALLOC_MAGIC;
+	tc->destructor = NULL;
+	tc->child = NULL;
+	tc->name = NULL;
+	tc->refs = NULL;
+
+	if (context) {
+		struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
+
+		tc->parent = parent;
+
+		if (parent->child) {
+			parent->child->parent = NULL;
+		}
+
+		_TLIST_ADD(parent->child, tc);
+	} else {
+		tc->next = tc->prev = tc->parent = NULL;
+	}
+
+	return (void *)(tc+1);
+}
+
+
+/*
+  setup a destructor to be called on free of a pointer
+  the destructor should return 0 on success, or -1 on failure.
+  if the destructor fails then the free is failed, and the memory can
+  be continued to be used
+*/
+void talloc_set_destructor(const void *ptr, int (*destructor)(void *))
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	tc->destructor = destructor;
+}
+
+/*
+  increase the reference count on a piece of memory.
+*/
+void talloc_increase_ref_count(const void *ptr)
+{
+	talloc_reference(null_context, ptr);
+}
+
+/*
+  helper for talloc_reference()
+*/
+static int talloc_reference_destructor(void *ptr)
+{
+	struct talloc_reference_handle *handle = ptr;
+	struct talloc_chunk *tc1 = talloc_chunk_from_ptr(ptr);
+	struct talloc_chunk *tc2 = talloc_chunk_from_ptr(handle->ptr);
+	if (tc1->destructor != (talloc_destructor_t)-1) {
+		tc1->destructor = NULL;
+	}
+	_TLIST_REMOVE(tc2->refs, handle);
+	talloc_free(handle);
+	return 0;
+}
+
+/*
+  make a secondary reference to a pointer, hanging off the given context.
+  the pointer remains valid until both the original caller and this given
+  context are freed.
+
+  the major use for this is when two different structures need to reference the
+  same underlying data, and you want to be able to free the two instances
+  separately, and in either order
+*/
+void *talloc_reference(const void *context, const void *ptr)
+{
+	struct talloc_chunk *tc;
+	struct talloc_reference_handle *handle;
+	if (ptr == NULL) return NULL;
+
+	tc = talloc_chunk_from_ptr(ptr);
+	handle = talloc_named_const(context, sizeof(*handle),
+			TALLOC_MAGIC_REFERENCE);
+
+	if (handle == NULL) return NULL;
+
+	/* note that we hang the destructor off the handle, not the
+	   main context as that allows the caller to still setup their
+	   own destructor on the context if they want to */
+	talloc_set_destructor(handle, talloc_reference_destructor);
+	handle->ptr = discard_const_p(void, ptr);
+	_TLIST_ADD(tc->refs, handle);
+	return handle->ptr;
+}
+
+/*
+  remove a secondary reference to a pointer. This undo's what
+  talloc_reference() has done. The context and pointer arguments
+  must match those given to a talloc_reference()
+*/
+static int talloc_unreference(const void *context, const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	struct talloc_reference_handle *h;
+
+	if (context == NULL) {
+		context = null_context;
+	}
+
+	for (h=tc->refs;h;h=h->next) {
+		struct talloc_chunk *p = talloc_parent_chunk(h);
+		if ((p==NULL && context==NULL) || p+1 == context) break;
+	}
+	if (h == NULL) {
+		return -1;
+	}
+
+	talloc_set_destructor(h, NULL);
+	_TLIST_REMOVE(tc->refs, h);
+	talloc_free(h);
+	return 0;
+}
+
+/*
+  remove a specific parent context from a pointer. This is a more
+  controlled varient of talloc_free()
+*/
+int talloc_unlink(const void *context, void *ptr)
+{
+	struct talloc_chunk *tc_p, *new_p;
+	void *new_parent;
+
+	if (ptr == NULL) {
+		return -1;
+	}
+
+	if (context == NULL) {
+		context = null_context;
+	}
+
+	if (talloc_unreference(context, ptr) == 0) {
+		return 0;
+	}
+
+	if (context == NULL) {
+		if (talloc_parent_chunk(ptr) != NULL) {
+			return -1;
+		}
+	} else {
+		if (talloc_chunk_from_ptr(context)
+				!= talloc_parent_chunk(ptr)) {
+			return -1;
+		}
+	}
+
+	tc_p = talloc_chunk_from_ptr(ptr);
+
+	if (tc_p->refs == NULL) {
+		return talloc_free(ptr);
+	}
+
+	new_p = talloc_parent_chunk(tc_p->refs);
+	if (new_p) {
+		new_parent = new_p+1;
+	} else {
+		new_parent = NULL;
+	}
+
+	if (talloc_unreference(new_parent, ptr) != 0) {
+		return -1;
+	}
+
+	talloc_steal(new_parent, ptr);
+
+	return 0;
+}
+
+/*
+  add a name to an existing pointer - va_list version
+*/
+static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
+	PRINTF_ATTRIBUTE(2,0);
+
+static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	tc->name = talloc_vasprintf(ptr, fmt, ap);
+	if (tc->name) {
+		talloc_set_name_const(tc->name, ".name");
+	}
+}
+
+/*
+  add a name to an existing pointer
+*/
+void talloc_set_name(const void *ptr, const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	talloc_set_name_v(ptr, fmt, ap);
+	va_end(ap);
+}
+
+/*
+   more efficient way to add a name to a pointer - the name must point to a
+   true string constant
+*/
+void talloc_set_name_const(const void *ptr, const char *name)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	tc->name = name;
+}
+
+/*
+  create a named talloc pointer. Any talloc pointer can be named, and
+  talloc_named() operates just like talloc() except that it allows you
+  to name the pointer.
+*/
+void *talloc_named(const void *context, size_t size, const char *fmt, ...)
+{
+	va_list ap;
+	void *ptr;
+
+	ptr = _talloc(context, size);
+	if (ptr == NULL) return NULL;
+
+	va_start(ap, fmt);
+	talloc_set_name_v(ptr, fmt, ap);
+	va_end(ap);
+
+	return ptr;
+}
+
+/*
+  create a named talloc pointer. Any talloc pointer can be named, and
+  talloc_named() operates just like talloc() except that it allows you
+  to name the pointer.
+*/
+void *talloc_named_const(const void *context, size_t size, const char *name)
+{
+	void *ptr;
+
+	ptr = _talloc(context, size);
+	if (ptr == NULL) {
+		return NULL;
+	}
+
+	talloc_set_name_const(ptr, name);
+
+	return ptr;
+}
+
+/*
+  return the name of a talloc ptr, or "UNNAMED"
+*/
+const char *talloc_get_name(const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	if (tc->name == TALLOC_MAGIC_REFERENCE) {
+		return ".reference";
+	}
+	if (tc->name) {
+		return tc->name;
+	}
+	return "UNNAMED";
+}
+
+
+/*
+  check if a pointer has the given name. If it does, return the pointer,
+  otherwise return NULL
+*/
+void *talloc_check_name(const void *ptr, const char *name)
+{
+	const char *pname;
+	if (ptr == NULL) return NULL;
+	pname = talloc_get_name(ptr);
+	if (pname == name || strcmp(pname, name) == 0) {
+		return discard_const_p(void, ptr);
+	}
+	return NULL;
+}
+
+
+/*
+  this is for compatibility with older versions of talloc
+*/
+void *talloc_init(const char *fmt, ...)
+{
+	va_list ap;
+	void *ptr;
+
+	ptr = _talloc(NULL, 0);
+	if (ptr == NULL) return NULL;
+
+	va_start(ap, fmt);
+	talloc_set_name_v(ptr, fmt, ap);
+	va_end(ap);
+
+	return ptr;
+}
+
+/*
+  this is a replacement for the Samba3 talloc_destroy_pool functionality. It
+  should probably not be used in new code. It's in here to keep the talloc
+  code consistent across Samba 3 and 4.
+*/
+static void talloc_free_children(void *ptr)
+{
+	struct talloc_chunk *tc;
+
+	if (ptr == NULL) {
+		return;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	while (tc->child) {
+		/* we need to work out who will own an abandoned child
+		   if it cannot be freed. In priority order, the first
+		   choice is owner of any remaining reference to this
+		   pointer, the second choice is our parent, and the
+		   final choice is the null context. */
+		void *child = tc->child+1;
+		const void *new_parent = null_context;
+		if (tc->child->refs) {
+			struct talloc_chunk *p =
+				talloc_parent_chunk(tc->child->refs);
+			if (p) new_parent = p+1;
+		}
+		if (talloc_free(child) == -1) {
+			if (new_parent == null_context) {
+				struct talloc_chunk *p =
+					talloc_parent_chunk(ptr);
+				if (p) new_parent = p+1;
+			}
+			talloc_steal(new_parent, child);
+		}
+	}
+}
+
+/*
+   free a talloc pointer. This also frees all child pointers of this
+   pointer recursively
+
+   return 0 if the memory is actually freed, otherwise -1. The memory
+   will not be freed if the ref_count is > 1 or the destructor (if
+   any) returns non-zero
+*/
+int talloc_free(void *ptr)
+{
+	struct talloc_chunk *tc;
+
+	if (ptr == NULL) {
+		return -1;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (tc->refs) {
+		talloc_reference_destructor(tc->refs);
+		return -1;
+	}
+
+	if (tc->destructor) {
+		talloc_destructor_t d = tc->destructor;
+		if (d == (talloc_destructor_t)-1) {
+			return -1;
+		}
+		tc->destructor = (talloc_destructor_t)-1;
+		if (d(ptr) == -1) {
+			tc->destructor = d;
+			return -1;
+		}
+		tc->destructor = NULL;
+	}
+
+	talloc_free_children(ptr);
+
+	if (tc->parent) {
+		_TLIST_REMOVE(tc->parent->child, tc);
+		if (tc->parent->child) {
+			tc->parent->child->parent = tc->parent;
+		}
+	} else {
+		if (tc->prev) tc->prev->next = tc->next;
+		if (tc->next) tc->next->prev = tc->prev;
+	}
+
+	tc->u.magic = TALLOC_MAGIC_FREE;
+
+	free(tc);
+	return 0;
+}
+
+
+
+/*
+  A talloc version of realloc. The context argument is only used if
+  ptr is NULL
+*/
+void *_talloc_realloc(const void *context, void *ptr, size_t size,
+		const char *name)
+{
+	struct talloc_chunk *tc;
+	void *new_ptr;
+
+	/* size zero is equivalent to free() */
+	if (size == 0) {
+		talloc_free(ptr);
+		return NULL;
+	}
+
+	if (size >= MAX_TALLOC_SIZE) {
+		return NULL;
+	}
+
+	/* realloc(NULL) is equavalent to malloc() */
+	if (ptr == NULL) {
+		return talloc_named_const(context, size, name);
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	/* don't allow realloc on referenced pointers */
+	if (tc->refs) {
+		return NULL;
+	}
+
+	/* by resetting magic we catch users of the old memory */
+	tc->u.magic = TALLOC_MAGIC_FREE;
+
+#if ALWAYS_REALLOC
+	new_ptr = malloc(size + sizeof(*tc));
+	if (new_ptr) {
+		memcpy(new_ptr, tc, tc->size + sizeof(*tc));
+		free(tc);
+	}
+#else
+	new_ptr = realloc(tc, size + sizeof(*tc));
+#endif
+	if (!new_ptr) {
+		tc->u.magic = TALLOC_MAGIC;
+		return NULL;
+	}
+
+	tc = new_ptr;
+	tc->u.magic = TALLOC_MAGIC;
+	if (tc->parent) {
+		tc->parent->child = new_ptr;
+	}
+	if (tc->child) {
+		tc->child->parent = new_ptr;
+	}
+
+	if (tc->prev) {
+		tc->prev->next = tc;
+	}
+	if (tc->next) {
+		tc->next->prev = tc;
+	}
+
+	tc->size = size;
+	talloc_set_name_const(tc+1, name);
+
+	return (void *)(tc+1);
+}
+
+/*
+   move a lump of memory from one talloc context to another return the
+   ptr on success, or NULL if it could not be transferred.
+   passing NULL as ptr will always return NULL with no side effects.
+*/
+void *talloc_steal(const void *new_ctx, const void *ptr)
+{
+	struct talloc_chunk *tc, *new_tc;
+
+	if (!ptr) {
+		return NULL;
+	}
+
+	if (new_ctx == NULL) {
+		new_ctx = null_context;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	if (new_ctx == NULL) {
+		if (tc->parent) {
+			_TLIST_REMOVE(tc->parent->child, tc);
+			if (tc->parent->child) {
+				tc->parent->child->parent = tc->parent;
+			}
+		} else {
+			if (tc->prev) tc->prev->next = tc->next;
+			if (tc->next) tc->next->prev = tc->prev;
+		}
+
+		tc->parent = tc->next = tc->prev = NULL;
+		return discard_const_p(void, ptr);
+	}
+
+	new_tc = talloc_chunk_from_ptr(new_ctx);
+
+	if (tc == new_tc) {
+		return discard_const_p(void, ptr);
+	}
+
+	if (tc->parent) {
+		_TLIST_REMOVE(tc->parent->child, tc);
+		if (tc->parent->child) {
+			tc->parent->child->parent = tc->parent;
+		}
+	} else {
+		if (tc->prev) tc->prev->next = tc->next;
+		if (tc->next) tc->next->prev = tc->prev;
+	}
+
+	tc->parent = new_tc;
+	if (new_tc->child) new_tc->child->parent = NULL;
+	_TLIST_ADD(new_tc->child, tc);
+
+	return discard_const_p(void, ptr);
+}
+
+/*
+  return the total size of a talloc pool (subtree)
+*/
+off_t talloc_total_size(const void *ptr)
+{
+	off_t total = 0;
+	struct talloc_chunk *c, *tc;
+
+	if (ptr == NULL) {
+		ptr = null_context;
+	}
+	if (ptr == NULL) {
+		return 0;
+	}
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	total = tc->size;
+	for (c=tc->child;c;c=c->next) {
+		total += talloc_total_size(c+1);
+	}
+	return total;
+}
+
+/*
+  return the total number of blocks in a talloc pool (subtree)
+*/
+off_t talloc_total_blocks(const void *ptr)
+{
+	off_t total = 0;
+	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+
+	total++;
+	for (c=tc->child;c;c=c->next) {
+		total += talloc_total_blocks(c+1);
+	}
+	return total;
+}
+
+/*
+  return the number of external references to a pointer
+*/
+static int talloc_reference_count(const void *ptr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
+	struct talloc_reference_handle *h;
+	int ret = 0;
+
+	for (h=tc->refs;h;h=h->next) {
+		ret++;
+	}
+	return ret;
+}
+
+/*
+  report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_depth(const void *ptr, FILE *f, int depth)
+{
+	struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+
+	for (c=tc->child;c;c=c->next) {
+		if (c->name == TALLOC_MAGIC_REFERENCE) {
+			struct talloc_reference_handle *handle = (void *)(c+1);
+			const char *name2 = talloc_get_name(handle->ptr);
+			fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
+		} else {
+			const char *name = talloc_get_name(c+1);
+			fprintf(f, "%*s%-30s contains %6lu bytes "
+					"in %3lu blocks (ref %d)\n",
+				depth * 4, "", name,
+				(unsigned long)talloc_total_size(c+1),
+				(unsigned long)talloc_total_blocks(c+1),
+				talloc_reference_count(c+1));
+			talloc_report_depth(c+1, f, depth+1);
+		}
+	}
+
+}
+
+/*
+  report on memory usage by all children of a pointer, giving a full tree view
+*/
+void talloc_report_full(const void *ptr, FILE *f)
+{
+	if (ptr == NULL) {
+		ptr = null_context;
+	}
+	if (ptr == NULL) return;
+
+	fprintf(f, "full talloc report on '%s' "
+			"(total %lu bytes in %lu blocks)\n",
+		talloc_get_name(ptr),
+		(unsigned long)talloc_total_size(ptr),
+		(unsigned long)talloc_total_blocks(ptr));
+
+	talloc_report_depth(ptr, f, 1);
+	fflush(f);
+}
+
+/*
+  report on memory usage by all children of a pointer
+*/
+void talloc_report(const void *ptr, FILE *f)
+{
+	struct talloc_chunk *c, *tc;
+
+	if (ptr == NULL) {
+		ptr = null_context;
+	}
+	if (ptr == NULL) return;
+
+	fprintf(f, "talloc report on '%s' (total %lu bytes in %lu blocks)\n",
+		talloc_get_name(ptr),
+		(unsigned long)talloc_total_size(ptr),
+		(unsigned long)talloc_total_blocks(ptr));
+
+	tc = talloc_chunk_from_ptr(ptr);
+
+	for (c=tc->child;c;c=c->next) {
+		fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n",
+			talloc_get_name(c+1),
+			(unsigned long)talloc_total_size(c+1),
+			(unsigned long)talloc_total_blocks(c+1));
+	}
+	fflush(f);
+}
+
+/*
+  report on any memory hanging off the null context
+*/
+static void talloc_report_null(void)
+{
+	if (talloc_total_size(null_context) != 0) {
+		talloc_report(null_context, stderr);
+	}
+}
+
+/*
+  report on any memory hanging off the null context
+*/
+static void talloc_report_null_full(void)
+{
+	if (talloc_total_size(null_context) != 0) {
+		talloc_report_full(null_context, stderr);
+	}
+}
+
+/*
+  enable tracking of the NULL context
+*/
+void talloc_enable_null_tracking(void)
+{
+	if (null_context == NULL) {
+		null_context = talloc_named_const(NULL, 0, "null_context");
+	}
+}
+
+/*
+  enable leak reporting on exit
+*/
+void talloc_enable_leak_report(void)
+{
+	talloc_enable_null_tracking();
+	atexit(talloc_report_null);
+}
+
+/*
+  enable full leak reporting on exit
+*/
+void talloc_enable_leak_report_full(void)
+{
+	talloc_enable_null_tracking();
+	atexit(talloc_report_null_full);
+}
+
+/*
+   talloc and zero memory.
+*/
+void *_talloc_zero(const void *ctx, size_t size, const char *name)
+{
+	void *p = talloc_named_const(ctx, size, name);
+
+	if (p) {
+		memset(p, '\0', size);
+	}
+
+	return p;
+}
+
+
+/*
+  memdup with a talloc.
+*/
+void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
+{
+	void *newp = talloc_named_const(t, size, name);
+
+	if (newp) {
+		memcpy(newp, p, size);
+	}
+
+	return newp;
+}
+
+/*
+  strdup with a talloc
+*/
+char *talloc_strdup(const void *t, const char *p)
+{
+	char *ret;
+	if (!p) {
+		return NULL;
+	}
+	ret = talloc_memdup(t, p, strlen(p) + 1);
+	if (ret) {
+		talloc_set_name_const(ret, ret);
+	}
+	return ret;
+}
+
+/*
+  strndup with a talloc
+*/
+char *talloc_strndup(const void *t, const char *p, size_t n)
+{
+	size_t len;
+	char *ret;
+
+	for (len=0; len<n && p[len]; len++) ;
+
+	ret = _talloc(t, len + 1);
+	if (!ret) { return NULL; }
+	memcpy(ret, p, len);
+	ret[len] = 0;
+	talloc_set_name_const(ret, ret);
+	return ret;
+}
+
+#ifndef VA_COPY
+#ifdef HAVE_VA_COPY
+#define VA_COPY(dest, src) va_copy(dest, src)
+#elif defined(HAVE___VA_COPY)
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#else
+#define VA_COPY(dest, src) (dest) = (src)
+#endif
+#endif
+
+char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
+{
+	int len;
+	char *ret;
+	va_list ap2;
+
+	VA_COPY(ap2, ap);
+
+	len = vsnprintf(NULL, 0, fmt, ap2);
+
+	ret = _talloc(t, len+1);
+	if (ret) {
+		VA_COPY(ap2, ap);
+		vsnprintf(ret, len+1, fmt, ap2);
+		talloc_set_name_const(ret, ret);
+	}
+
+	return ret;
+}
+
+
+/*
+  Perform string formatting, and return a pointer to newly allocated
+  memory holding the result, inside a memory pool.
+ */
+char *talloc_asprintf(const void *t, const char *fmt, ...)
+{
+	va_list ap;
+	char *ret;
+
+	va_start(ap, fmt);
+	ret = talloc_vasprintf(t, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+
+
+/**
+ * Realloc @p s to append the formatted result of @p fmt and @p ap,
+ * and return @p s, which may have moved.  Good for gradually
+ * accumulating output into a string buffer.
+ **/
+
+static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+	PRINTF_ATTRIBUTE(2,0);
+
+static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
+{
+	struct talloc_chunk *tc;
+	int len, s_len;
+	va_list ap2;
+
+	if (s == NULL) {
+		return talloc_vasprintf(NULL, fmt, ap);
+	}
+
+	tc = talloc_chunk_from_ptr(s);
+
+	VA_COPY(ap2, ap);
+
+	s_len = tc->size - 1;
+	len = vsnprintf(NULL, 0, fmt, ap2);
+
+	s = talloc_realloc(NULL, s, char, s_len + len+1);
+	if (!s) return NULL;
+
+	VA_COPY(ap2, ap);
+
+	vsnprintf(s+s_len, len+1, fmt, ap2);
+	talloc_set_name_const(s, s);
+
+	return s;
+}
+
+/*
+  Realloc @p s to append the formatted result of @p fmt and return @p
+  s, which may have moved.  Good for gradually accumulating output
+  into a string buffer.
+ */
+char *talloc_asprintf_append(char *s, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	s = talloc_vasprintf_append(s, fmt, ap);
+	va_end(ap);
+	return s;
+}
+
+/*
+  alloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_array(const void *ctx, size_t el_size, unsigned count,
+		const char *name)
+{
+	if (count >= MAX_TALLOC_SIZE/el_size) {
+		return NULL;
+	}
+	return talloc_named_const(ctx, el_size * count, name);
+}
+
+/*
+  alloc an zero array, checking for integer overflow in the array size
+*/
+void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count,
+		const char *name)
+{
+	if (count >= MAX_TALLOC_SIZE/el_size) {
+		return NULL;
+	}
+	return _talloc_zero(ctx, el_size * count, name);
+}
+
+
+/*
+  realloc an array, checking for integer overflow in the array size
+*/
+void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size,
+		unsigned count, const char *name)
+{
+	if (count >= MAX_TALLOC_SIZE/el_size) {
+		return NULL;
+	}
+	return _talloc_realloc(ctx, ptr, el_size * count, name);
+}
+
+/*
+  a function version of talloc_realloc(), so it can be passed as a function
+  pointer to libraries that want a realloc function (a realloc function
+  encapsulates all the basic capabilities of an allocation library, which is
+  why this is useful)
+*/
+void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
+{
+	return _talloc_realloc(context, ptr, size, NULL);
+}
+
+
+static void talloc_autofree(void)
+{
+	talloc_free(cleanup_context);
+	cleanup_context = NULL;
+}
+
+/*
+  return a context which will be auto-freed on exit
+  this is useful for reducing the noise in leak reports
+*/
+void *talloc_autofree_context(void)
+{
+	if (cleanup_context == NULL) {
+		cleanup_context = talloc_named_const(NULL, 0,
+				"autofree_context");
+		atexit(talloc_autofree);
+	}
+	return cleanup_context;
+}
+
+size_t talloc_get_size(const void *context)
+{
+	struct talloc_chunk *tc;
+
+	if (context == NULL)
+		return 0;
+
+	tc = talloc_chunk_from_ptr(context);
+
+	return tc->size;
+}

Added: developers/seanchiang/gsm/src/gsmd/unsolicited.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/unsolicited.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/unsolicited.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,525 @@
+/* gsmd unsolicited message handling
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "gsmd.h"
+
+#include <gsmd/usock.h>
+#include <gsmd/event.h>
+#include <gsmd/extrsp.h>
+#include <gsmd/ts0707.h>
+#include <gsmd/unsolicited.h>
+#include <gsmd/talloc.h>
+
+struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len)
+{
+	struct gsmd_ucmd *ucmd = ucmd_alloc(len);
+
+	if (!ucmd)
+		return NULL;
+
+	ucmd->hdr.version = GSMD_PROTO_VERSION;
+	ucmd->hdr.msg_type = type;
+	ucmd->hdr.msg_subtype = subtype;
+	ucmd->hdr.len = len;
+
+	return ucmd;
+}
+
+static struct gsmd_ucmd *ucmd_copy(const struct gsmd_ucmd *orig)
+{
+	struct gsmd_ucmd *copy = ucmd_alloc(orig->hdr.len);
+
+	if (copy)
+		memcpy(copy, orig, orig->hdr.len);
+
+	return copy;
+}
+
+int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt)
+{
+	struct gsmd_user *gu;
+	int num_sent = 0;
+
+	DEBUGP("entering evt=%u\n", evt);
+
+	llist_for_each_entry(gu, &gsmd->users, list) {
+		if (gu->subscriptions & (1 << evt)) {
+			if (num_sent == 0)
+				usock_cmd_enqueue(ucmd, gu);
+			else {
+				struct gsmd_ucmd *cpy = ucmd_copy(ucmd);
+				if (!cpy) {
+					fprintf(stderr, 
+						"can't allocate memory for "
+						"copy of ucmd\n");
+					return num_sent;
+				}
+				usock_cmd_enqueue(cpy, gu);
+			}
+			num_sent++;
+		}
+	}
+
+	if (num_sent == 0)
+		talloc_free(ucmd);
+
+	return num_sent;
+}
+
+static int ring_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	/* FIXME: generate ring event */
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL,
+					     sizeof(struct gsmd_evt_auxdata));	
+	struct gsmd_evt_auxdata *aux;
+	if (!ucmd)
+		return -ENOMEM;
+
+	aux = (struct gsmd_evt_auxdata *)ucmd->buf;
+
+	aux->u.call.type = GSMD_CALL_UNSPEC;
+
+	return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_CALL);
+}
+
+static int cring_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
+{
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL,
+					     sizeof(struct gsmd_evt_auxdata));
+	struct gsmd_evt_auxdata *aux;
+	if (!ucmd)
+		return -ENOMEM;
+
+	aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+	if (!strcmp(param, "VOICE")) {
+		/* incoming voice call */
+		aux->u.call.type = GSMD_CALL_VOICE;
+	} else if (!strcmp(param, "SYNC")) {
+		aux->u.call.type = GSMD_CALL_DATA_SYNC;
+	} else if (!strcmp(param, "REL ASYNC")) {
+		aux->u.call.type = GSMD_CALL_DATA_REL_ASYNC;
+	} else if (!strcmp(param, "REL SYNC")) {
+		aux->u.call.type = GSMD_CALL_DATA_REL_SYNC;
+	} else if (!strcmp(param, "FAX")) {
+		aux->u.call.type = GSMD_CALL_FAX;
+	} else if (!strncmp(param, "GPRS ", 5)) {
+		/* FIXME: change event type to GPRS */
+		talloc_free(ucmd);
+		return 0;
+	}
+	/* FIXME: parse all the ALT* profiles, Chapter 6.11 */
+
+	return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_CALL);
+}
+
+/* Chapter 7.2, network registration */
+static int creg_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	const char *comma = strchr(param, ',');
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_NETREG,
+					     sizeof(struct gsmd_evt_auxdata));
+	struct gsmd_evt_auxdata *aux;
+	if (!ucmd)
+		return -ENOMEM;
+	aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+	aux->u.netreg.state = atoi(param);
+	if (comma) {
+		/* we also have location area code and cell id to parse (hex) */
+		aux->u.netreg.lac = strtoul(comma+2, NULL, 16);
+		comma = strchr(comma+1, ',');
+		if (!comma)
+			return -EINVAL;
+		aux->u.netreg.ci = strtoul(comma+2, NULL, 16);
+	}
+
+	return usock_evt_send(gsmd, ucmd, GSMD_EVT_NETREG);
+}
+
+/* Chapter 7.11, call waiting */
+static int ccwa_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	const char *token;
+	unsigned int type;
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_CALL_WAIT,
+					     sizeof(struct gsmd_addr));
+	struct gsmd_addr *gaddr;
+
+	if (!ucmd)
+		return -ENOMEM;
+
+	gaddr = (struct gsmd_addr *) ucmd->buf;
+	memset(gaddr, 0, sizeof(*gaddr));
+
+	/* parse address (phone number) */
+	token = strtok(buf, ",");
+	if (!token)
+		return -EINVAL;
+	strncpy(gaddr->number, token, GSMD_ADDR_MAXLEN);
+
+	/* parse type */
+	token = strtok(NULL, ",");
+	if (!token)
+		return -EINVAL;
+	type = atoi(token) & 0xff;
+	gaddr->type = type;
+
+	/* FIXME: parse class */
+	token = strtok(NULL, ",");
+
+	return usock_evt_send(gsmd, ucmd, GSMD_EVT_CALL_WAIT);
+}
+
+/* Chapter 7.14, unstructured supplementary service data */
+static int cusd_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	/* FIXME: parse */
+	return 0;
+}
+
+/* Chapter 7.15, advise of charge */
+static int cccm_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	/* FIXME: parse */
+	return 0;
+}
+
+/* Chapter 10.1.13, GPRS event reporting */
+static int cgev_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	/* FIXME: parse */
+	return 0;
+}
+
+/* Chapter 10.1.14, GPRS network registration status */
+static int cgreg_parse(char *buf, int len, const char *param,
+		       struct gsmd *gsmd)
+{
+	/* FIXME: parse */
+	return 0;
+}
+
+/* Chapter 7.6, calling line identification presentation */
+static int clip_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CLIP,
+					     sizeof(struct gsmd_evt_auxdata));
+	struct gsmd_evt_auxdata *aux;
+	const char *comma = strchr(param, ',');
+
+	if (!ucmd)
+		return -ENOMEM;
+	
+	aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+	if (!comma)
+		return -EINVAL;
+
+	
+	if (comma - param > GSMD_ADDR_MAXLEN)
+		return -EINVAL;
+
+	memcpy(aux->u.clip.addr.number, param, comma-param);
+	/* FIXME: parse of subaddr, etc. */
+
+	return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_CLIP);
+}
+
+/* Chapter 7.9, calling line identification presentation */
+static int colp_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_OUT_COLP,
+					     sizeof(struct gsmd_evt_auxdata));
+	struct gsmd_evt_auxdata *aux;
+	const char *comma = strchr(param, ',');
+
+	if (!ucmd)
+		return -ENOMEM;
+	
+	aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+	if (!comma)
+		return -EINVAL;
+	
+	if (comma - param > GSMD_ADDR_MAXLEN)
+		return -EINVAL;
+
+	memcpy(aux->u.colp.addr.number, param, comma-param);
+	/* FIXME: parse of subaddr, etc. */
+
+	return usock_evt_send(gsmd, ucmd, GSMD_EVT_OUT_COLP);
+}
+
+static int ctzv_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_TIMEZONE,
+					     sizeof(struct gsmd_evt_auxdata));
+	struct gsmd_evt_auxdata *aux;
+	int tz;
+
+	if (!ucmd)
+		return -ENOMEM;
+	
+	aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+	/* timezones are expressed in quarters of hours +/- GMT (-48...+48) */
+	tz = atoi(param);
+
+	if (tz < -48  || tz > 48)
+		return -EINVAL;
+	
+	aux->u.timezone.tz = tz;
+
+	return usock_evt_send(gsmd, ucmd, GSMD_EVT_TIMEZONE);
+}
+
+static int copn_parse(char *buf, int len, const char *param,
+		      struct gsmd *gsmd)
+{
+	struct gsm_extrsp *er = extrsp_parse(gsmd_tallocs, param);
+	int rc = 0;
+
+	if (!er)
+		return -ENOMEM;
+
+	extrsp_dump(er);
+
+	if (er->num_tokens == 2 &&
+	    er->tokens[0].type == GSMD_ECMD_RTT_STRING &&
+	    er->tokens[1].type == GSMD_ECMD_RTT_STRING)
+		rc = gsmd_opname_add(gsmd, er->tokens[0].u.string,
+				     er->tokens[1].u.string);
+
+	talloc_free(er);
+
+	return rc;
+}
+
+static const struct gsmd_unsolicit gsm0707_unsolicit[] = {
+	{ "RING",	&ring_parse },
+	{ "+CRING", 	&cring_parse },
+	{ "+CREG",	&creg_parse },	/* Network registration */
+	{ "+CCWA",	&ccwa_parse },	/* Call waiting */
+	{ "+CUSD",	&cusd_parse },	/* Unstructured supplementary data */
+	{ "+CCCM",	&cccm_parse },	/* Advice of Charge */
+	{ "+CGEV",	&cgev_parse },	/* GPRS Event */
+	{ "+CGREG",	&cgreg_parse },	/* GPRS Registration */
+	{ "+CLIP",	&clip_parse },
+	{ "+COLP",	&colp_parse },
+	{ "+CTZV",	&ctzv_parse },	/* Timezone */
+	{ "+COPN",	&copn_parse },  /* operator names, treat as unsolicited */
+	/*
+	{ "+CKEV",	&ckev_parse },
+	{ "+CDEV",	&cdev_parse },
+	{ "+CIEV",	&ciev_parse },
+	{ "+CLAV",	&clav_parse },
+	{ "+CCWV",	&ccwv_parse },
+	{ "+CLAV",	&clav_parse },
+	{ "+CSSU",	&cssu_parse },
+	*/
+};
+
+/* called by midlevel parser if a response seems unsolicited */
+int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param)
+{
+	int i, rc;
+	struct gsmd_vendor_plugin *vpl = g->vendorpl;
+
+	/* call vendor-specific unsolicited code parser */
+	if (vpl && vpl->num_unsolicit) {
+		for (i = 0; i < vpl->num_unsolicit; i++) {
+			const char *colon;
+			if (strncmp(buf, vpl->unsolicit[i].prefix,
+				     strlen(vpl->unsolicit[i].prefix)))
+				continue;
+
+			colon = strchr(buf, ':') + 2;
+			if (colon > buf+len)
+				colon = NULL;
+
+			rc = vpl->unsolicit[i].parse(buf, len, colon, g);
+			if (rc < 0) 
+				gsmd_log(GSMD_ERROR, "error %d during parse of "
+					 "vendor unsolicied response `%s'\n",
+					 rc, buf);
+			return rc;
+		}
+	}
+
+	/* call generic unsolicited code parser */
+	for (i = 0; i < ARRAY_SIZE(gsm0707_unsolicit); i++) {
+		const char *colon;
+		if (strncmp(buf, gsm0707_unsolicit[i].prefix,
+			     strlen(gsm0707_unsolicit[i].prefix)))
+			continue;
+		
+		colon = strchr(buf, ':') + 2;
+		if (colon > buf+len)
+			colon = NULL;
+
+		rc = gsm0707_unsolicit[i].parse(buf, len, colon, g);
+		if (rc < 0) 
+			gsmd_log(GSMD_ERROR, "error %d during parse of "
+				 "unsolicied response `%s'\n", rc, buf);
+		return rc;
+	}
+
+	gsmd_log(GSMD_NOTICE, "no parser for unsolicited response `%s'\n", buf);
+
+	return -ENOENT;
+}
+
+static unsigned int errors_creating_events[] = {
+	GSM0707_CME_PHONE_FAILURE,
+	GSM0707_CME_PHONE_NOCONNECT,
+	GSM0707_CME_PHONE_ADAPT_RESERVED,
+	GSM0707_CME_PH_SIM_PIN_REQUIRED,
+	GSM0707_CME_PH_FSIM_PIN_REQUIRED,
+	GSM0707_CME_PH_FSIM_PUK_REQUIRED,
+	GSM0707_CME_SIM_NOT_INSERTED,
+	GSM0707_CME_SIM_PIN_REQUIRED,
+	GSM0707_CME_SIM_PUK_REQUIRED,
+	GSM0707_CME_SIM_FAILURE,
+	GSM0707_CME_SIM_BUSY,
+	GSM0707_CME_SIM_WRONG,
+	GSM0707_CME_SIM_PIN2_REQUIRED,
+	GSM0707_CME_SIM_PUK2_REQUIRED,
+	GSM0707_CME_MEMORY_FULL,
+	GSM0707_CME_MEMORY_FAILURE,
+	GSM0707_CME_NETPERS_PIN_REQUIRED,
+	GSM0707_CME_NETPERS_PUK_REQUIRED,
+	GSM0707_CME_NETSUBSET_PIN_REQUIRED,
+	GSM0707_CME_NETSUBSET_PUK_REQUIRED,
+	GSM0707_CME_PROVIDER_PIN_REQUIRED,
+	GSM0707_CME_PROVIDER_PUK_REQUIRED,
+	GSM0707_CME_CORPORATE_PIN_REQUIRED,
+	GSM0707_CME_CORPORATE_PUK_REQUIRED,
+};
+
+static int is_in_array(unsigned int val, unsigned int *arr, unsigned int arr_len)
+{
+	unsigned int i;
+
+	for (i = 0; i < arr_len; i++) {
+		if (arr[i] == val)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+int generate_event_from_cme(struct gsmd *g, unsigned int cme_error)
+{
+	struct gsmd_ucmd *gu;
+	struct gsmd_evt_auxdata *eaux;
+	if (!is_in_array(cme_error, errors_creating_events,
+			 ARRAY_SIZE(errors_creating_events)))
+		return 0;
+	
+	gu = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_PIN, sizeof(*eaux));
+	if (!gu)
+		return -1;
+	eaux = ((void *)gu) + sizeof(*gu);
+
+	switch (cme_error) {
+	case GSM0707_CME_PH_SIM_PIN_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_SIM_PIN;
+		break;
+	case GSM0707_CME_PH_FSIM_PIN_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_FSIM_PIN;
+		break;
+	case GSM0707_CME_PH_FSIM_PUK_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_FSIM_PUK;
+		break;
+	case GSM0707_CME_SIM_PIN_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_SIM_PIN;
+		break;
+	case GSM0707_CME_SIM_PUK_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_SIM_PUK;
+		break;
+	case GSM0707_CME_SIM_PIN2_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_SIM_PIN2;
+		break;
+	case GSM0707_CME_SIM_PUK2_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_SIM_PUK2;
+		break;
+	case GSM0707_CME_NETPERS_PIN_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_NET_PIN;
+		break;
+	case GSM0707_CME_NETPERS_PUK_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_NET_PUK;
+		break;
+	case GSM0707_CME_NETSUBSET_PIN_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_NETSUB_PIN;
+		break;
+	case GSM0707_CME_NETSUBSET_PUK_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_NETSUB_PUK;
+		break;
+	case GSM0707_CME_PROVIDER_PIN_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_SP_PIN;
+		break;
+	case GSM0707_CME_PROVIDER_PUK_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_SP_PUK;
+		break;
+	case GSM0707_CME_CORPORATE_PIN_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_CORP_PIN;
+		break;
+	case GSM0707_CME_CORPORATE_PUK_REQUIRED:
+		eaux->u.pin.type = GSMD_PIN_PH_CORP_PUK;
+		break;
+
+	case GSM0707_CME_SIM_FAILURE:
+	case GSM0707_CME_SIM_BUSY:
+	case GSM0707_CME_SIM_WRONG:
+	case GSM0707_CME_MEMORY_FULL:
+	case GSM0707_CME_MEMORY_FAILURE:
+	case GSM0707_CME_PHONE_FAILURE:
+	case GSM0707_CME_PHONE_NOCONNECT:
+	case GSM0707_CME_PHONE_ADAPT_RESERVED:
+	case GSM0707_CME_SIM_NOT_INSERTED:
+		/* FIXME */
+		return 0;
+		break;
+	default:
+		return 0;
+		break;
+	}
+	return usock_evt_send(g, gu, GSMD_EVT_PIN);
+}

Added: developers/seanchiang/gsm/src/gsmd/usock.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/usock.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/usock.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,1006 @@
+/* gsmd unix domain socket handling
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/usock.h>
+#include <gsmd/select.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/usock.h>
+#include <gsmd/talloc.h>
+#include <gsmd/ts0707.h>
+
+static void *__ucmd_ctx, *__gu_ctx;
+
+struct gsmd_ucmd *ucmd_alloc(int extra_size)
+{
+	return talloc_size(__ucmd_ctx, 
+			   sizeof(struct gsmd_ucmd) + extra_size);
+}
+
+void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu)
+{
+	DEBUGP("enqueueing usock cmd %p for user %p\n", ucmd, gu);
+
+	/* add to per-user list of finished cmds */
+	llist_add_tail(&ucmd->list, &gu->finished_ucmds);
+
+	/* mark socket of user as we-want-to-write */
+	gu->gfd.when |= GSMD_FD_WRITE;
+}
+
+/* callback for completed passthrough gsmd_atcmd's */
+static int usock_cmd_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;
+	int rlen = strlen(resp)+1;
+	struct gsmd_ucmd *ucmd = ucmd_alloc(rlen);
+
+	DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu);
+
+	if (!ucmd)
+		return -ENOMEM;
+	
+	/* FIXME: pass error values back somehow */
+	ucmd->hdr.version = GSMD_PROTO_VERSION;
+	ucmd->hdr.msg_type = GSMD_MSG_PASSTHROUGH;
+	ucmd->hdr.msg_subtype = GSMD_PASSTHROUGH_RESP;
+	ucmd->hdr.len = strlen(resp)+1;
+	ucmd->hdr.id = cmd->id;
+	memcpy(ucmd->buf, resp, ucmd->hdr.len);
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+typedef int usock_msg_handler(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len);
+
+static int usock_rcv_passthrough(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len)
+{
+	struct gsmd_atcmd *cmd;
+	cmd = atcmd_fill((char *)gph+sizeof(*gph), gph->len, &usock_cmd_cb, gu, gph->id);
+	if (!cmd)
+		return -ENOMEM;
+
+	DEBUGP("submitting cmd=%p, gu=%p\n", cmd, gu);
+
+	return atcmd_submit(gu->gsmd, cmd);
+}
+
+static int usock_rcv_event(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len)
+{
+	u_int32_t *evtmask = (u_int32_t *) ((char *)gph + sizeof(*gph), gph->id);
+
+	if (len < sizeof(*gph) + sizeof(u_int32_t))
+		return -EINVAL;
+
+	if (gph->msg_subtype != GSMD_EVT_SUBSCRIPTIONS)
+		return -EINVAL;
+
+	gu->subscriptions = *evtmask;
+}
+
+static int usock_rcv_voicecall(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,
+				int len)
+{
+	struct gsmd_atcmd *cmd = NULL;
+	struct gsmd_addr *ga;
+	struct gsmd_dtmf *gd;
+	int atcmd_len;
+
+	switch (gph->msg_subtype) {
+	case GSMD_VOICECALL_DIAL:
+		if (len < sizeof(*gph) + sizeof(*ga))
+			return -EINVAL;
+		ga = (struct gsmd_addr *) ((void *)gph + sizeof(*gph));
+		ga->number[GSMD_ADDR_MAXLEN] = '\0';
+		cmd = atcmd_fill("ATD", 5 + strlen(ga->number),
+				 &usock_cmd_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "ATD%s;", ga->number);
+		/* FIXME: number type! */
+		break;
+	case GSMD_VOICECALL_HANGUP:
+		cmd = atcmd_fill("ATH0", 5, &usock_cmd_cb, gu, gph->id);
+		break;
+	case GSMD_VOICECALL_ANSWER:
+		cmd = atcmd_fill("ATA", 4, &usock_cmd_cb, gu, gph->id);
+		break;
+	case GSMD_VOICECALL_DTMF:
+		if (len < sizeof(*gph) + sizeof(*gd))
+			return -EINVAL;
+
+		gd = (struct gsmd_dtmf *) ((void *)gph + sizeof(*gph));
+		if (len < sizeof(*gph) + sizeof(*gd) + gd->len)
+			return -EINVAL;
+
+		/* FIXME: we don't yet support DTMF of multiple digits */
+		if (gd->len != 1)
+			return -EINVAL;
+
+		atcmd_len = 1 + strlen("AT+VTS=") + (gd->len * 2);
+		cmd = atcmd_fill("AT+VTS=", atcmd_len, &usock_cmd_cb,
+				 gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+
+		sprintf(cmd->buf, "AT+VTS=%c;", gd->dtmf[0]);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (cmd)
+		return atcmd_submit(gu->gsmd, cmd);
+	else
+		return 0;
+}
+
+static int null_cmd_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	gsmd_log(GSMD_DEBUG, "null cmd cb\n");
+	return 0;
+}
+
+/* PIN command callback. Gets called for response to AT+CPIN cmcd */
+static int pin_cmd_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	gsmd_log(GSMD_DEBUG, "pin cmd cb\n");
+
+	/* We need to verify if there is some error */
+	switch (cmd->ret) {
+	case 0:
+		break;
+	case GSM0707_CME_INCORRECT_PASSWORD:
+		/* prompt for pin again */
+		break;
+	default:	
+		/* something went wrong */
+		break;
+	}
+	return 0;
+}
+
+static int usock_rcv_pin(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, 
+			 int len)
+{
+	struct gsmd_pin *gp = (struct gsmd_pin *) ((void *)gph + sizeof(*gph));
+	struct gsmd_atcmd *cmd;
+
+	if (gph->len < sizeof(*gp) || len < sizeof(*gp)+sizeof(*gph))
+		return -EINVAL;
+
+	gsmd_log(GSMD_DEBUG, "pin type=%u, pin='%s', newpin='%s'\n",
+		 gp->type, gp->pin, gp->newpin);
+
+	switch (gph->msg_subtype) {
+	case GSMD_PIN_INPUT:
+		/* FIXME */
+		break;
+	default:
+		gsmd_log(GSMD_ERROR, "unknown pin type %u\n",
+			 gph->msg_subtype);
+		return -EINVAL;
+	}
+
+	cmd = atcmd_fill("AT+CPIN=\"", 9+GSMD_PIN_MAXLEN+3+GSMD_PIN_MAXLEN+2,
+			 &pin_cmd_cb, gu, 0);
+	if (!cmd)
+		return -ENOMEM;
+
+	strcat(cmd->buf, gp->pin);
+
+	switch (gp->type) {
+	case GSMD_PIN_SIM_PUK:
+	case GSMD_PIN_SIM_PUK2:
+		strcat(cmd->buf, "\",\"");
+		strcat(cmd->buf, gp->newpin);
+		break;
+	default:
+		break;
+	}
+
+	strcat(cmd->buf, "\"");
+
+	return atcmd_submit(gu->gsmd, cmd);
+}
+
+static int usock_rcv_phone(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, 
+			   int len)
+{
+	struct gsmd_atcmd *cmd;
+
+	switch (gph->msg_subtype) {
+	case GSMD_PHONE_POWERUP:
+		cmd = atcmd_fill("AT+CFUN=1", 9+1,
+				 &null_cmd_cb, gu, 0);
+		gu->gsmd->dev_state.on = 1;
+		break;
+
+	case GSMD_PHONE_POWERDOWN:
+		cmd = atcmd_fill("AT+CFUN=0", 9+1,
+				 &null_cmd_cb, gu, 0);
+		gu->gsmd->dev_state.on = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (!cmd)
+		return -ENOMEM;
+
+	return atcmd_submit(gu->gsmd, cmd);
+}
+
+static int network_vmail_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;
+	struct gsmd_voicemail *vmail;
+	struct gsmd_ucmd *ucmd;
+	char *comma;
+
+	DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu);
+
+	ucmd = ucmd_alloc(sizeof(*vmail));
+	if (!ucmd)
+		return -ENOMEM;
+	
+	/* FIXME: pass error values back somehow */
+	ucmd->hdr.version = GSMD_PROTO_VERSION;
+	ucmd->hdr.msg_type = GSMD_MSG_NETWORK;
+	ucmd->hdr.len = sizeof(*vmail);
+	ucmd->hdr.id = cmd->id;
+
+	if (cmd->buf[7] == '=') {
+		/* response to set command */
+		ucmd->hdr.msg_subtype = GSMD_NETWORK_VMAIL_SET;
+		/* FIXME: */
+		return 0;
+	} else {
+		/* response to get command */
+		char *tok = strtok(resp, ",");
+		if (!tok)
+			goto out_free_einval;
+		ucmd->hdr.msg_subtype = GSMD_NETWORK_VMAIL_GET;
+		vmail->enable = atoi(tok);
+
+		tok = strtok(NULL, ",");
+		if (!tok)
+			goto out_free_einval;
+		strncpy(vmail->addr.number, tok, GSMD_ADDR_MAXLEN);
+		vmail->addr.number[GSMD_ADDR_MAXLEN] = '\0';
+
+		tok = strtok(NULL, ",");
+		if (!tok)
+			goto out_free_einval;
+		vmail->addr.type = atoi(tok);
+	}
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+
+out_free_einval:
+	gsmd_log(GSMD_ERROR, "can't understand voicemail response\n");
+	talloc_free(ucmd);
+	return -EINVAL;
+}
+
+static struct gsmd_ucmd *gsmd_ucmd_fill(int len, u_int8_t msg_type, u_int8_t msg_subtype,
+					u_int16_t id)
+{
+	struct gsmd_ucmd *ucmd;
+
+	ucmd = ucmd_alloc(len);
+	if (!ucmd)
+		return NULL;
+	
+	ucmd->hdr.version = GSMD_PROTO_VERSION;
+	ucmd->hdr.msg_type = msg_type;
+	ucmd->hdr.msg_subtype = msg_subtype;
+	ucmd->hdr.len = len;
+	ucmd->hdr.id = id;
+
+	return ucmd;
+}
+
+static int network_sigq_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;
+	struct gsmd_signal_quality *gsq;
+	struct gsmd_ucmd *ucmd;
+	char *comma;
+	
+	ucmd = gsmd_ucmd_fill(sizeof(*gsq), GSMD_MSG_NETWORK,
+			      GSMD_NETWORK_SIGQ_GET, 0);
+	if (!ucmd)
+		return -ENOMEM;
+	
+	gsq = (struct gsmd_signal_quality *) ucmd->buf;
+	gsq->rssi = atoi(resp);
+	comma = strchr(resp, ',');
+	if (!comma) {
+		talloc_free(ucmd);
+		return -EIO;
+	}
+	gsq->ber = atoi(comma+1);
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int network_oper_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;
+	struct gsmd_signal_quality *gsq;
+	struct gsmd_ucmd *ucmd;
+	char *comma;
+	
+	ucmd = gsmd_ucmd_fill(sizeof(*gsq), GSMD_MSG_NETWORK,
+			      GSMD_NETWORK_OPER_GET, 0);
+	if (!ucmd)
+		return -ENOMEM;
+
+	/* FIXME: implementation */
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int usock_rcv_network(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, 
+			     int len)
+{
+	struct gsmd_atcmd *cmd;
+	struct gsmd_voicemail *vmail = (struct gsmd_voicemail *) gph->data;
+
+	switch (gph->msg_subtype) {
+	case GSMD_NETWORK_REGISTER:
+		cmd = atcmd_fill("AT+COPS", 9+1,
+				 &null_cmd_cb, gu, 0);
+		break;
+	case GSMD_NETWORK_VMAIL_GET:
+		cmd = atcmd_fill("AT+CSVM?", 8+1, &network_vmail_cb, gu, 0);
+		break;
+	case GSMD_NETWORK_VMAIL_SET:
+		cmd = atcmd_fill("AT+CSVM=", 8+1, &network_vmail_cb, gu, 0);
+		break;
+	case GSMD_NETWORK_SIGQ_GET:
+		cmd = atcmd_fill("AT+CSQ", 6+1, &network_sigq_cb, gu, 0);
+		break;
+	case GSMD_NETWORK_OPER_GET:
+		cmd = atcmd_fill("AT+COPS?", 8+1, &network_oper_cb, gu, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (!cmd)
+		return -ENOMEM;
+
+	return atcmd_submit(gu->gsmd, cmd);
+}
+
+static int sms_list_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;	
+	struct gsmd_ucmd *ucmd;	
+#if 1
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
+			      GSMD_SMS_LIST, 0);
+	if (!ucmd)
+		return -ENOMEM;
+
+	/* FIXME: implementation */
+	strcpy(ucmd->buf, resp);
+	
+	usock_cmd_enqueue(ucmd, gu);
+#endif
+	return 0;
+}
+
+static int sms_read_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;	
+	struct gsmd_ucmd *ucmd;	
+
+	/* FIXME: implementation */
+
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
+			      GSMD_SMS_READ, 0);
+	if (!ucmd)
+		return -ENOMEM;
+
+	strcpy(ucmd->buf, resp);	
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int sms_send_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;	
+	struct gsmd_ucmd *ucmd;	
+	
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
+			      GSMD_SMS_SEND, 0);
+	if (!ucmd)
+		return -ENOMEM;
+	
+	strcpy(ucmd->buf, resp);
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int sms_write_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;	
+	struct gsmd_ucmd *ucmd;	
+	
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
+			      GSMD_SMS_WRITE, 0);
+	if (!ucmd)
+		return -ENOMEM;	
+
+	strcpy(ucmd->buf, resp);
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int sms_delete_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;	
+	struct gsmd_ucmd *ucmd;	
+
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
+			      GSMD_SMS_DELETE, 0);
+	if (!ucmd)
+		return -ENOMEM;	
+
+	strcpy(ucmd->buf, resp);
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int usock_rcv_sms(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, 
+			 int len)
+{
+	/* FIXME: TEXT mode support!!  */
+	struct gsmd_atcmd *cmd = NULL;
+	struct gsmd_sms_delete *gsd;
+	struct gsmd_sms *gs;
+	struct gsmd_sms_write *gsw;
+	int *stat, *index;
+	int atcmd_len;
+	char buf[1024];
+	
+	switch (gph->msg_subtype) {
+	case GSMD_SMS_LIST:
+		/* FIXME: only support PDU mode!! */
+		if(len < sizeof(*gph) + sizeof(int))
+			return -EINVAL;
+		stat = (int *) ((void *)gph + sizeof(*gph));	
+
+		sprintf(buf, "%d", *stat);	
+				
+		atcmd_len = 1 + strlen("AT+CMGL=") + strlen(buf);
+		cmd = atcmd_fill("AT+CMGL=", atcmd_len,
+				 &sms_list_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CMGL=%s", buf);
+		break;
+	case GSMD_SMS_READ:
+		/* FIXME: only support PDU mode!! */
+		if(len < sizeof(*gph) + sizeof(int))
+			return -EINVAL;
+		index = (int *) ((void *)gph + sizeof(*gph));
+
+		sprintf(buf, "%d", *index);
+		
+		atcmd_len = 1 + strlen("AT+CMGR=") + strlen(buf);
+		cmd = atcmd_fill("AT+CMGR=", atcmd_len,
+				 &sms_read_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CMGR=%s", buf);
+		break;
+#if 0
+	case GSMD_SMS_SEND:
+		/* FIXME: only support PDU mode!! */
+		if(len < sizeof(*gph) + sizeof(*gs))
+			return -EINVAL;
+		gs = (struct gsmd_sms *) ((void *)gph + sizeof(*gph));
+
+		sprintf(buf, "%d", *index);
+		
+		atcmd_len = 1 + strlen("AT+CMGR=") + 1;
+		cmd = atcmd_fill("AT+CMGR=", atcmd_len,
+				 &sms_send_cb, gu, gph->id);
+		if (!cmd)GSMD_SMS_WRITE
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CMGR=%d", index);
+		break;
+	case GSMD_SMS_WRITE:
+		/* FIXME: only support PDU mode!! */
+		if(len < sizeof(*gph) + sizeof(*gsw))
+			return -EINVAL;
+		&index = (int *) ((void *)gph + sizeof(*gph));
+		
+		atcmd_len = 1 + strlen("AT+CMGR=") + 1;
+		cmd = atcmd_fill("AT+CMGR=", atcmd_len,
+				 &sms_write_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CMGR=%d", index);
+		break;
+#endif
+	case GSMD_SMS_DELETE:		
+		if(len < sizeof(*gph) + sizeof(*gsd))
+			return -EINVAL;
+		gsd = (struct gsmd_sms_delete *) ((void *)gph + sizeof(*gph));
+	    
+		sprintf(buf, "%d,%d", gsd->index, gsd->delflg);
+	
+		atcmd_len = 1 + strlen("AT+CMGR=") + strlen(buf);
+		cmd = atcmd_fill("AT+CMGD=", atcmd_len,
+				 &sms_delete_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CMGD=%s", buf);		
+		break;	
+	default:
+		return -EINVAL;
+	}
+		
+#if 1
+	printf("%s\n",cmd->buf);
+	if (cmd)
+		return atcmd_submit(gu->gsmd, cmd);
+	else
+		return 0;
+#endif
+}
+
+static int phonebook_find_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;	
+	struct gsmd_ucmd *ucmd;			
+	
+	/* FIXME: implementation */
+#if 1
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
+			      GSMD_PHONEBOOK_FIND, 0);
+	if (!ucmd)
+		return -ENOMEM;	
+
+	strcpy(ucmd->buf, resp);
+
+	usock_cmd_enqueue(ucmd, gu);
+#endif
+	return 0;
+}
+
+static int phonebook_read_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;
+	struct gsmd_phonebook *gp;
+	struct gsmd_ucmd *ucmd;
+	char *fcomma, *lcomma;
+	char *ptr;
+	/* FIXME: We should check this case "When the entry is empty" */
+	ucmd = gsmd_ucmd_fill(sizeof(*gp), GSMD_MSG_PHONEBOOK,
+			      GSMD_PHONEBOOK_READ, 0);	
+
+	if (!ucmd)
+		return -ENOMEM;	
+	gp = (struct gsmd_phonebook *) ucmd->buf;
+	
+	ptr = strchr(resp, ' ');	
+	gp->index = atoi(ptr+1);		
+	
+	fcomma = strchr(resp, '"');
+	lcomma = strchr(fcomma+1, '"');		
+	strncpy(gp->numb, fcomma+1, (lcomma-fcomma-1));	
+	gp->numb[(lcomma-fcomma)-1] = '\0';			
+		
+	gp->type = atoi(lcomma+2);		
+
+	ptr = strrchr(resp, ',');
+	fcomma = ptr+1;
+	lcomma = strchr(fcomma+1, '"');
+	strncpy(gp->text, fcomma+1, (lcomma-fcomma-1));
+	gp->text[(lcomma-fcomma)-1] = '\0';
+			
+	usock_cmd_enqueue(ucmd, gu);
+	
+	return 0;
+}
+
+static int phonebook_readrg_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;
+	struct gsmd_ucmd *ucmd;	
+	
+	/* FIXME: implementation */
+	
+#if 1
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
+			      GSMD_PHONEBOOK_READRG, 0);
+	if (!ucmd)
+		return -ENOMEM;	
+
+	strcpy(ucmd->buf, resp);
+
+	usock_cmd_enqueue(ucmd, gu);
+#endif
+
+	return 0;
+}
+
+static int phonebook_write_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;	
+	struct gsmd_ucmd *ucmd;	
+		
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
+			      GSMD_PHONEBOOK_WRITE, 0);
+	if (!ucmd)
+		return -ENOMEM;
+
+	strcpy(ucmd->buf, resp);
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int phonebook_delete_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;		
+	struct gsmd_ucmd *ucmd;		
+		
+	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
+			      GSMD_PHONEBOOK_DELETE, 0);
+	if (!ucmd)
+		return -ENOMEM;	
+
+	strcpy(ucmd->buf, resp);
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int phonebook_support_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd_user *gu = ctx;
+	struct gsmd_phonebook_support *gps;
+	struct gsmd_ucmd *ucmd;
+	char *fcomma, *lcomma;
+	char *dash;
+	
+	ucmd = gsmd_ucmd_fill(sizeof(*gps), GSMD_MSG_PHONEBOOK,
+			      GSMD_PHONEBOOK_GET_SUPPORT, 0);
+	if (!ucmd)
+		return -ENOMEM;
+	
+	gps = (struct gsmd_phonebook_support *) ucmd->buf;
+		
+	dash = strchr(resp, '-');
+	if (!dash) {
+		talloc_free(ucmd);
+		return -EIO;
+	}	
+	gps->index = atoi(dash+1);
+
+	fcomma = strchr(resp, ',');
+	if (!fcomma) {
+		talloc_free(ucmd);
+		return -EIO;
+	}
+	gps->nlength = atoi(fcomma+1);
+	
+	lcomma = strrchr(resp, ',');
+	if (!lcomma) {
+		talloc_free(ucmd);
+		return -EIO;
+	}	
+	gps->tlength = atoi(lcomma+1);	
+
+	usock_cmd_enqueue(ucmd, gu);
+	return 0;
+}
+
+static int usock_rcv_phonebook(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, 
+			 int len)
+{	
+	struct gsmd_atcmd *cmd = NULL;
+	struct gsmd_phonebook_readrg *gpr;
+	struct gsmd_phonebook *gp;
+	struct gsmd_phonebook_find *gpf;
+	int *index;
+	int atcmd_len;
+	char buf[1024];
+	
+	switch (gph->msg_subtype) {
+	case GSMD_PHONEBOOK_FIND:
+		if(len < sizeof(*gph) + sizeof(*gpf))
+			return -EINVAL;
+		gpf = (struct gsmd_phonebook_find *) ((void *)gph + sizeof(*gph));		
+				
+		atcmd_len = 1 + strlen("AT+CPBF=\"") + strlen(gpf->findtext) + strlen("\"");
+		cmd = atcmd_fill("AT+CPBF=\"", atcmd_len,
+				 &phonebook_find_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CPBF=\"%s\"", gpf->findtext);
+		break;
+	case GSMD_PHONEBOOK_READ:
+		if(len < sizeof(*gph) + sizeof(int))
+			return -EINVAL;
+		index = (int *) ((void *)gph + sizeof(*gph));
+		
+		sprintf(buf, "%d", *index);		
+
+		atcmd_len = 1 + strlen("AT+CPBR=") + strlen(buf);
+		cmd = atcmd_fill("AT+CPBR=", atcmd_len,
+				 &phonebook_read_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CPBR=%d", *index);
+		break;
+	case GSMD_PHONEBOOK_READRG:		
+		if(len < sizeof(*gph) + sizeof(*gpr))
+			return -EINVAL;
+		gpr = (struct gsmd_phonebook_readrg *) ((void *)gph + sizeof(*gph));
+
+		sprintf(buf, "%d,%d", gpr->index1, gpr->index2);		
+
+		atcmd_len = 1 + strlen("AT+CPBR=") + strlen(buf);
+		cmd = atcmd_fill("AT+CPBR=", atcmd_len,
+				 &phonebook_readrg_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CPBR=%s", buf);
+		break;
+	case GSMD_PHONEBOOK_WRITE:
+		if(len < sizeof(*gph) + sizeof(*gp))
+			return -EINVAL;
+		gp = (struct gsmd_phonebook *) ((void *)gph + sizeof(*gph));
+
+		sprintf(buf, "%d,\"%s\",%d,\"%s\"", gp->index, gp->numb, gp->type, gp->text);
+		
+		atcmd_len = 1 + strlen("AT+CPBW=") + strlen(buf);
+		cmd = atcmd_fill("AT+CPBW=", atcmd_len,
+				 &phonebook_write_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CPBW=%s", buf);
+		break;
+	case GSMD_PHONEBOOK_DELETE:
+		if(len < sizeof(*gph) + sizeof(int))
+			return -EINVAL;
+		index = (int *) ((void *)gph + sizeof(*gph));
+	    	
+		sprintf(buf, "%d", *index);
+		
+		atcmd_len = 1 + strlen("AT+CPBW=") + strlen(buf);
+		cmd = atcmd_fill("AT+CPBW=", atcmd_len,
+				 &phonebook_delete_cb, gu, gph->id);
+		if (!cmd)
+			return -ENOMEM;
+		sprintf(cmd->buf, "AT+CPBW=%s", buf);
+		break;	
+	case GSMD_PHONEBOOK_GET_SUPPORT:
+		cmd = atcmd_fill("AT+CPBR=?", 9+1,
+				 &phonebook_support_cb, gu, gph->id);
+		break;
+	default:
+		return -EINVAL;
+	}	
+#if 1	
+	printf("%s\n", cmd->buf);
+	if (cmd)
+		return atcmd_submit(gu->gsmd, cmd);
+	else
+		return 0;
+#endif
+}
+
+static usock_msg_handler *pcmd_type_handlers[__NUM_GSMD_MSGS] = {
+	[GSMD_MSG_PASSTHROUGH]	= &usock_rcv_passthrough,
+	[GSMD_MSG_EVENT]	= &usock_rcv_event,
+	[GSMD_MSG_VOICECALL]	= &usock_rcv_voicecall,
+	[GSMD_MSG_PIN]		= &usock_rcv_pin,
+	[GSMD_MSG_PHONE]	= &usock_rcv_phone,
+	[GSMD_MSG_NETWORK]	= &usock_rcv_network,
+	[GSMD_MSG_SMS]		= &usock_rcv_sms,	
+	[GSMD_MSG_PHONEBOOK]	= &usock_rcv_phonebook,
+};
+
+static int usock_rcv_pcmd(struct gsmd_user *gu, char *buf, int len)
+{
+	struct gsmd_msg_hdr *gph = (struct gsmd_msg_hdr *)buf;
+	usock_msg_handler *umh;
+
+	if (gph->version != GSMD_PROTO_VERSION)
+		return -EINVAL;
+
+	if (gph->msg_type >= __NUM_GSMD_MSGS)
+		return -EINVAL;
+	
+	umh = pcmd_type_handlers[gph->msg_type];
+	if (!umh)
+		return -EINVAL;
+
+	return umh(gu, gph, len);
+}
+
+/* callback for read/write on client (libgsmd) socket */
+static int gsmd_usock_user_cb(int fd, unsigned int what, void *data)
+{
+	struct gsmd_user *gu = data;
+
+	/* FIXME: check some kind of backlog and limit it */
+
+	if (what & GSMD_FD_READ) {
+		char buf[1024];
+		int rcvlen;
+		/* read data from socket, determine what he wants */
+		rcvlen = read(fd, buf, sizeof(buf));
+		if (rcvlen == 0) {
+			DEBUGP("EOF, this client has just vanished\n");
+			/* EOF, this client has just vanished */
+			gsmd_unregister_fd(&gu->gfd);
+			close(fd);
+			/* destroy whole user structure */
+			llist_del(&gu->list);
+			/* FIXME: delete busy ucmds from finished_ucmds */
+			talloc_free(gu);
+			return 0;
+		} else if (rcvlen < 0)
+			return rcvlen;
+		else
+			return usock_rcv_pcmd(gu, buf, rcvlen);
+	}
+
+	if (what & GSMD_FD_WRITE) {
+		/* write data from pending replies to socket */
+		struct gsmd_ucmd *ucmd, *uctmp;
+		llist_for_each_entry_safe(ucmd, uctmp, &gu->finished_ucmds,
+					  list) {
+			int rc;
+
+			rc = write(fd, &ucmd->hdr, sizeof(ucmd->hdr) + ucmd->hdr.len);
+			if (rc < 0) {
+				DEBUGP("write return %d\n", rc);
+				return rc;
+			}
+			if (rc == 0) {
+				DEBUGP("write returns zero!!\n");
+				break;
+			}
+			if (rc != sizeof(ucmd->hdr) + ucmd->hdr.len) {
+				DEBUGP("short write\n");
+				break;
+			}
+
+			DEBUGP("successfully sent cmd %p to user %p, freeing\n", ucmd, gu);
+			llist_del(&ucmd->list);
+			talloc_free(ucmd);
+		}
+		if (llist_empty(&gu->finished_ucmds))
+			gu->gfd.when &= ~GSMD_FD_WRITE;
+	}
+
+	return 0;
+}
+
+/* callback for read on master-listen-socket */
+static int gsmd_usock_cb(int fd, unsigned int what, void *data)
+{
+	struct gsmd *g = data;
+	struct gsmd_user *newuser;
+
+	/* FIXME: implement this */
+	if (what & GSMD_FD_READ) {
+		/* new incoming connection */
+		newuser = talloc(__gu_ctx, struct gsmd_user);
+		if (!newuser)
+			return -ENOMEM;
+		
+		newuser->gfd.fd = accept(fd, NULL, 0);
+		if (newuser->gfd.fd < 0) {
+			DEBUGP("error accepting incoming conn: `%s'\n",
+				strerror(errno));
+			talloc_free(newuser);
+		}
+		newuser->gfd.when = GSMD_FD_READ;
+		newuser->gfd.data = newuser;
+		newuser->gfd.cb = &gsmd_usock_user_cb;
+		newuser->gsmd = g;
+		newuser->subscriptions = 0xffffffff;
+		INIT_LLIST_HEAD(&newuser->finished_ucmds);
+
+		llist_add(&newuser->list, &g->users);
+		gsmd_register_fd(&newuser->gfd);
+	}
+
+	return 0;
+}
+
+/* handling of socket with incoming client connections */
+int usock_init(struct gsmd *g)
+{
+	struct sockaddr_un sun;
+	int fd, rc;
+
+	__ucmd_ctx = talloc_named_const(gsmd_tallocs, 1, "ucmd");
+	__gu_ctx = talloc_named_const(gsmd_tallocs, 1, "gsmd_user");
+
+	fd = socket(PF_UNIX, GSMD_UNIX_SOCKET_TYPE, 0);
+	if (fd < 0)
+		return fd;
+	
+	memset(&sun, 0, sizeof(sun));
+	sun.sun_family = AF_UNIX;
+	memcpy(sun.sun_path, GSMD_UNIX_SOCKET, sizeof(GSMD_UNIX_SOCKET));
+
+	rc = bind(fd, (struct sockaddr *)&sun, sizeof(sun));
+	if (rc < 0) {
+		close(fd);
+		return rc;
+	}
+
+	rc = listen(fd, 10);
+	if (rc < 0) {
+		close(fd);
+		return rc;
+	}
+
+	g->gfd_sock.fd = fd;
+	g->gfd_sock.when = GSMD_FD_READ | GSMD_FD_EXCEPT;
+	g->gfd_sock.data = g;
+	g->gfd_sock.cb = &gsmd_usock_cb;
+
+	return gsmd_register_fd(&g->gfd_sock);
+}

Added: developers/seanchiang/gsm/src/gsmd/vendor.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/vendor.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/vendor.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,61 @@
+/* gsmd vendor plugin core
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <errno.h>
+
+#include <common/linux_list.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/vendorplugin.h>
+
+static LLIST_HEAD(vendorpl_list);
+
+int gsmd_vendor_plugin_register(struct gsmd_vendor_plugin *pl)
+{
+	llist_add(&pl->list, &vendorpl_list);
+
+	return 0;
+}
+
+void gsmd_vendor_plugin_unregister(struct gsmd_vendor_plugin *pl)
+{
+	llist_del(&pl->list);
+}
+
+int gsmd_vendor_plugin_find(struct gsmd *g)
+{
+	struct gsmd_vendor_plugin *pl;
+
+	if (g->vendorpl)
+		return -EEXIST;
+	
+	llist_for_each_entry(pl, &vendorpl_list, list) {
+		if (pl->detect(g) == 1) {
+			g->vendorpl = pl;
+			return 1;
+		}
+	}
+
+	return 0;
+}

Added: developers/seanchiang/gsm/src/gsmd/vendor_ti.c
===================================================================
--- developers/seanchiang/gsm/src/gsmd/vendor_ti.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/vendor_ti.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,317 @@
+/* TI [Calypso] compatible gsmd plugin
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/usock.h>
+#include <gsmd/event.h>
+#include <gsmd/talloc.h>
+#include <gsmd/extrsp.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/vendorplugin.h>
+#include <gsmd/unsolicited.h>
+
+#if 0
+#include "vendorplugin.h"
+
+static int 
+ti_getopt(struct gsmd *gh, int optname, void *optval, int *optlen)
+{
+	switch (optname) {
+	case GSMD_OPT_CIPHER_IND:
+		/* FIXME: send AT%CPRI=? */
+		break;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int 
+ti_setopt(struct gsmd *gh, int optname, const void *optval, int optlen)
+{
+	switch (optname) {
+	case GSMD_OPT_CIPHER_IND:
+		/* FIXME: send AT%CPRI= */
+		break;
+	default:
+		return -EINVAL;
+	}
+}
+
+#endif
+
+
+static int csq_parse(char *buf, int len, const char *param,
+		     struct gsmd *gsmd)
+{
+	char *tok;
+	struct gsmd_evt_auxdata *aux;
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_SIGNAL,
+					     sizeof(*aux));
+
+	DEBUGP("entering csq_parse param=`%s'\n", param);
+	if (!ucmd)
+		return -EINVAL;
+	
+	
+	aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+	tok = strtok(buf, ",");
+	if (!tok)
+		goto out_free_io;
+	
+	aux->u.signal.sigq.rssi = atoi(tok);
+
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto out_free_io;
+
+	aux->u.signal.sigq.ber = atoi(tok);
+
+	DEBUGP("sending EVT_SIGNAL\n");
+	usock_evt_send(gsmd, ucmd, GSMD_EVT_SIGNAL);
+
+	return 0;
+
+out_free_io:
+	free(ucmd);
+	return -EIO;
+}
+
+static int cpri_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
+{
+	char *tok1, *tok2;
+
+	tok1 = strtok(buf, ",");
+	if (!tok1)
+		return -EIO;
+	
+	tok2 = strtok(NULL, ",");
+	if (!tok2) {
+		switch (atoi(tok1)) {
+		case 0:
+			gsmd->dev_state.ciph_ind.flags &= ~GSMD_CIPHIND_ACTIVE;
+			break;
+		case 1:
+			gsmd->dev_state.ciph_ind.flags |= GSMD_CIPHIND_ACTIVE;
+			break;
+		case 2:
+			gsmd->dev_state.ciph_ind.flags |= GSMD_CIPHIND_DISABLED_SIM;
+			break;
+		}
+	} else {
+		struct gsmd_evt_auxdata *aux;
+		struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT,
+							   GSMD_EVT_CIPHER,
+							   sizeof(*aux));
+		if (!ucmd)
+			return -ENOMEM;
+
+		aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+		aux->u.cipher.net_state_gsm = atoi(tok1);
+		aux->u.cipher.net_state_gsm = atoi(tok2);
+
+		usock_evt_send(gsmd, ucmd, GSMD_EVT_CIPHER);
+	}
+
+	return 0;
+}
+
+static int ctzv_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
+{
+	/* FIXME: decide what to do with it.  send as event to clients? or keep
+	 * locally? Offer option to sync system RTC? */
+	return 0;
+}
+
+/* Call Progress Information */
+static int cpi_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
+{
+	char *tok;
+	struct gsmd_evt_auxdata *aux;
+	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT,
+						   GSMD_EVT_OUT_STATUS,
+						   sizeof(*aux));
+	
+	DEBUGP("entering cpi_parse param=`%s'\n", param);
+	if (!ucmd)
+		return -EINVAL;
+	
+	aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+	/* Format: cId, msgType, ibt, tch, dir,[mode],[number],[type],[alpha],[cause],line */
+
+	/* call ID */
+	tok = strtok(buf, ",");
+	if (!tok)
+		goto out_free_io;
+
+	/* message type (layer 3) */
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto out_free_io;
+	aux->u.call_status.prog = atoi(tok);
+
+	/* in-band tones */
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto out_free_io;
+
+	if (*tok == '1')
+		aux->u.call_status.ibt = 1;
+	else
+		aux->u.call_status.ibt = 0;
+	
+	/* TCH allocated */
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto out_free_io;
+
+	if (*tok == '1')
+		aux->u.call_status.tch = 1;
+	else
+		aux->u.call_status.tch = 0;
+	
+	/* direction */
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto out_send;
+	
+	switch (*tok) {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+		aux->u.call_status.dir = (*tok - '0');
+		break;
+	default:
+		break;
+	}
+
+	/* mode */
+	tok = strtok(NULL, ",");
+	if (!tok)
+		goto out_send;
+	
+out_send:
+	usock_evt_send(gsmd, ucmd, GSMD_EVT_OUT_STATUS);
+
+	return 0;
+
+out_free_io:
+	talloc_free(ucmd);
+	return -EIO;
+}
+
+static const struct gsmd_unsolicit ticalypso_unsolicit[] = {
+	{ "%CSQ",	&csq_parse },	/* Signal Quality */
+	{ "%CPRI",	&cpri_parse },	/* Ciphering Indication */
+	{ "%CPI",	&cpi_parse },	/* Call Progress Information */
+	{ "%CTZV",	&ctzv_parse },	/* network time and data */
+
+	/* FIXME: parse all the below and generate the respective events */
+
+	/* %CPROAM: CPHS Home Country Roaming Indicator */
+	/* %CPVWI: CPHS Voice Message Waiting */
+	/* %CGREG: reports extended information about GPRS registration state */
+	/* %CNIV: reports network name information */
+	/* %CPKY: Press Key */
+	/* %CMGRS: Message Retransmission Service */
+	/* %CGEV: reports GPRS network events */
+};
+
+static int cpi_detect_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+{
+	struct gsmd *g = ctx;
+	struct gsm_extrsp *er;
+
+	if (strncmp(resp, "%CPI: ", 6))
+		return -EINVAL;
+	resp += 6;
+	
+	er = extrsp_parse(cmd, resp);
+	if (!er)
+		return -EINVAL;
+
+	if (extrsp_supports(er, 0, 3))
+		return gsmd_simplecmd(g, "AT%CPI=3");
+	else if (extrsp_supports(er, 0, 2))
+		return gsmd_simplecmd(g, "AT%CPI=2");
+	else
+		DEBUGP("Call Progress Indication mode 2 or 3 not supported!!\n");
+
+	talloc_free(er);
+	return 0;
+}
+
+static int ticalypso_detect(struct gsmd *g)
+{
+	/* FIXME: do actual detection of vendor if we have multiple vendors */
+	return 1;
+}
+
+static int ticalypso_initsettings(struct gsmd *g)
+{
+	int rc;
+	struct gsmd_atcmd *cmd;
+
+	/* use +CTZR: to report time zone changes */
+	rc |= gsmd_simplecmd(g, "AT+CTZR=1");
+	/* use %CTZV: Report time and date */
+	rc |= gsmd_simplecmd(g, "AT%CTZV=1");
+	/* use %CGREG */
+	//rc |= gsmd_simplecmd(g, "AT%CGREG=3");
+	/* enable %CPRI: ciphering indications */
+	rc |= gsmd_simplecmd(g, "AT%CPRI=1");
+	/* enable %CSQ: signal quality reports */
+	rc |= gsmd_simplecmd(g, "AT%CSQ=1");
+	/* send unsolicited commands at any time */
+	rc |= gsmd_simplecmd(g, "AT%CUNS=0");
+
+	/* enable %CPI: call progress indication */
+	cmd = atcmd_fill("AT%CPI=?", 9, &cpi_detect_cb, g, 0);
+	if (cmd)
+		atcmd_submit(g, cmd);
+
+	return rc;
+}
+
+static struct gsmd_vendor_plugin plugin_ticalypso = {
+	.name = "TI Calypso",
+	.num_unsolicit = ARRAY_SIZE(ticalypso_unsolicit),
+	.unsolicit = ticalypso_unsolicit,
+	.detect = &ticalypso_detect,
+	.initsettings = &ticalypso_initsettings,
+};
+ 
+/* FIXME: this will be _init() when we make this a plugin */
+int ticalypso_init(void)
+{
+	return gsmd_vendor_plugin_register(&plugin_ticalypso);
+}

Added: developers/seanchiang/gsm/src/gsmd/vendorplugin.h
===================================================================
--- developers/seanchiang/gsm/src/gsmd/vendorplugin.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/gsmd/vendorplugin.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,33 @@
+#ifndef __GSMD_VENDORPLUG_H
+#define __GSMD_VENDORPLUG_H
+
+#ifdef __GSMD__
+
+#include "gsmd.h"
+
+/* gsmd vendor-specific plugin */
+
+enum gsmd_options {
+	GSMD_OPT_NONE,
+	GSMD_OPT_CIPHER_IND,
+};
+
+/* CIPHER_IND */
+enum gsmd_cipher_ind {
+	GSMD_CIPHER_IND_OFF,
+	GSMD_CIPHER_IND_ON,
+	GSMD_CIPHER_IND_SIM_FORBID,
+};
+
+struct gsmd_vendorspecific {
+	/* callback function to parse unknown unsolicited responses */	
+	int (*parse_unsolicit)(void);
+	int (*getopt)(struct gsmd *gh, int optname, void *optval, int *optlen);
+	int (*setopt)(struct gsmd *gh, int optname, const void *optval, int optlen);
+};
+
+/* ciphering indications */
+
+#endif /* __GSMD__ */
+
+#endif

Added: developers/seanchiang/gsm/src/libgsmd/Makefile.am
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,10 @@
+LIBVERSION= 0:0:0
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS = -std=gnu99
+
+lib_LTLIBRARIES = libgsmd.la
+
+libgsmd_la_LDFLAGS = -Wc,-nostartfiles -version-info $(LIBVERSION)
+libgsmd_la_SOURCES = libgsmd.c libgsmd_input.c libgsmd_voicecall.c libgsmd_passthrough.c libgsmd_event.c libgsmd_phone.c libgsmd_network.c libgsmd_pin.c libgsmd_sms.c libgsmd_phonebook.c
+
+noinst_HEADERS = lgsm_internals.h

Added: developers/seanchiang/gsm/src/libgsmd/lgsm_internals.h
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/lgsm_internals.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/lgsm_internals.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,15 @@
+#ifndef _LGSM_INTERNALS_H
+#define _LGSM_INTERNALS_H
+
+#include <gsmd/usock.h>
+
+struct lgsm_handle {
+	int fd;
+	lgsm_msg_handler *handler[__NUM_GSMD_MSGS];
+};
+
+int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh);
+struct gsmd_msg_hdr *lgsm_gmh_fill(int type, int subtype, int payload_len);
+#define lgsm_gmh_free(x)	free(x)
+
+#endif /* _LGSM_INTERNALS_H */

Added: developers/seanchiang/gsm/src/libgsmd/libgsmd.c
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/libgsmd.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/libgsmd.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,187 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <gsmd/usock.h>
+#include <libgsmd/libgsmd.h>
+
+#include "lgsm_internals.h"
+
+static int lgsm_get_packet(struct lgsm_handle *lh)
+{
+	static char buf[GSMD_MSGSIZE_MAX];
+	struct gsmd_msg_hdr *hdr = (struct gsmd_msg_hdr *) buf;
+	int rc = read(lh->fd, buf, sizeof(buf));
+	if (rc <= 0)
+		return rc;
+
+	if (hdr->version != GSMD_PROTO_VERSION)
+		return -EINVAL;
+	
+	switch (hdr->msg_type) {
+	case GSMD_MSG_PASSTHROUGH:
+		
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int lgsm_open_backend(struct lgsm_handle *lh, const char *device)
+{
+	int rc;
+
+	if (!strcmp(device, LGSMD_DEVICE_GSMD)) {
+		struct sockaddr_un sun;
+		
+		/* use unix domain socket to gsm daemon */
+		lh->fd = socket(PF_UNIX, GSMD_UNIX_SOCKET_TYPE, 0);
+		if (lh->fd < 0)
+			return lh->fd;
+		
+		memset(&sun, 0, sizeof(sun));
+		sun.sun_family = AF_UNIX;
+		memcpy(sun.sun_path, GSMD_UNIX_SOCKET, sizeof(GSMD_UNIX_SOCKET));
+
+		rc = connect(lh->fd, (struct sockaddr *)&sun, sizeof(sun));
+		if (rc < 0) {
+			close(lh->fd);
+			lh->fd = -1;
+			return rc;
+		}
+	} else 	
+		return -EINVAL;
+
+	return 0;
+}
+
+/* handle a packet that was received on the gsmd socket */
+int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len)
+{
+	struct gsmd_msg_hdr *gmh = (struct gsmd_msg_hdr *)buf;
+	lgsm_msg_handler *handler; 
+	
+	if (len < sizeof(*gmh))
+		return -EINVAL;
+	
+	if (len - sizeof(*gmh) < gmh->len)
+		return -EINVAL;
+	
+	if (gmh->msg_type >= __NUM_GSMD_MSGS)
+		return -EINVAL;
+	
+	handler = lh->handler[gmh->msg_type];
+	
+	if (handler)
+		return handler(lh, gmh);
+	else {
+		fprintf(stderr, "unable to handle packet type=%u\n", gmh->msg_type);
+		return 0;
+	}
+}
+
+int lgsm_register_handler(struct lgsm_handle *lh, int type, lgsm_msg_handler *handler)
+{
+	if (type >= __NUM_GSMD_MSGS)
+		return -EINVAL;
+
+	lh->handler[type] = handler;
+
+	return 0;
+}
+
+void lgsm_unregister_handler(struct lgsm_handle *lh, int type)
+{
+	if (type < __NUM_GSMD_MSGS)
+		lh->handler[type] = NULL;
+}
+
+/* blocking read and processing of packets until packet matching 'id' is found */
+int lgsm_blocking_wait_packet(struct lgsm_handle *lh, u_int16_t id, 
+			      struct gsmd_msg_hdr *gmh, int rlen)
+{
+	int rc;
+	fd_set readset;
+
+	FD_ZERO(&readset);
+
+	while (1) {
+		FD_SET(lh->fd, &readset);
+		rc = select(lh->fd+1, &readset, NULL, NULL, NULL);
+		if (rc <= 0)
+			return rc;
+
+		rc = read(lh->fd, (char *)gmh, rlen);
+		if (rc <= 0)
+			return rc;
+
+		if (gmh->id == id) {
+			/* we've found the matching packet, return to calling function */
+			return rc;
+		} else
+			rc = lgsm_handle_packet(lh, (char *)gmh, rc);
+	}
+}
+
+int lgsm_fd(struct lgsm_handle *lh)
+{
+	return lh->fd;
+}
+
+struct lgsm_handle *lgsm_init(const char *device)
+{
+	struct lgsm_handle *lh = malloc(sizeof(*lh));
+
+	memset(lh, 0, sizeof(*lh));
+	lh->fd = -1;
+
+	if (lgsm_open_backend(lh, device) < 0) {
+		free(lh);
+		return NULL;
+	}
+
+	lgsm_evt_init(lh);
+
+	return lh;
+}
+
+int lgsm_exit(struct lgsm_handle *lh)
+{
+	free(lh);
+
+	return 0;
+}
+
+
+static u_int16_t next_msg_id;
+
+int lgsm_send(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+	gmh->id = next_msg_id++;
+	return send(lh->fd, (char *) gmh, sizeof(*gmh) + gmh->len, 0);
+}
+
+struct gsmd_msg_hdr *lgsm_gmh_fill(int type, int subtype, int payload_len)
+{
+	struct gsmd_msg_hdr *gmh = malloc(sizeof(*gmh)+payload_len);
+	if (!gmh)
+		return NULL;
+
+	memset(gmh, 0, sizeof(*gmh)+payload_len);
+
+	gmh->version = GSMD_PROTO_VERSION;
+	gmh->msg_type = type;
+	gmh->msg_subtype = subtype;
+	gmh->len = payload_len;
+
+	return gmh;
+}
+

Added: developers/seanchiang/gsm/src/libgsmd/libgsmd_event.c
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/libgsmd_event.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/libgsmd_event.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,80 @@
+/* libgsmd event demultiplexer handler 
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */ 
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <libgsmd/voicecall.h>
+#include <libgsmd/event.h>
+
+#include <gsmd/usock.h>
+#include <gsmd/event.h>
+
+#include "lgsm_internals.h"
+
+static lgsm_evt_handler *evt_handlers[__NUM_GSMD_EVT];
+
+int lgsm_evt_handler_register(struct lgsm_handle *lh, int evt_type,
+			      lgsm_evt_handler *handler)
+{
+	if (evt_type >= __NUM_GSMD_EVT)
+		return -EINVAL;
+
+	evt_handlers[evt_type] = handler;
+
+	return 0;
+}
+
+void lgsm_evt_handler_unregister(struct lgsm_handle *lh, int evt_type)
+{
+	if (evt_type < __NUM_GSMD_EVT)
+		evt_handlers[evt_type] = NULL;
+}
+
+
+static int evt_demux_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+	struct gsmd_evt_auxdata *aux = gmh->data;
+
+	if (gmh->len < sizeof(*aux))
+		return -EIO;
+	
+	if (gmh->msg_type != GSMD_MSG_EVENT || 
+	    gmh->msg_subtype >= __NUM_GSMD_EVT)
+		return -EINVAL;
+
+	if (evt_handlers[gmh->msg_subtype])
+		return evt_handlers[gmh->msg_subtype](lh, gmh->msg_subtype, aux);
+	else
+		return 0;
+}
+
+int lgsm_evt_init(struct lgsm_handle *lh)
+{
+	return lgsm_register_handler(lh, GSMD_MSG_EVENT, &evt_demux_msghandler);
+}
+
+void lgsm_evt_exit(struct lgsm_handle *lh)
+{
+	lgsm_unregister_handler(lh, GSMD_MSG_EVENT);
+}

Added: developers/seanchiang/gsm/src/libgsmd/libgsmd_input.c
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/libgsmd_input.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/libgsmd_input.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,35 @@
+/* libgsmd core
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */ 
+
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#include <libgsmd/libgsmd.h>
+
+#include "lgsm_internals.h"
+
+

Added: developers/seanchiang/gsm/src/libgsmd/libgsmd_network.c
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/libgsmd_network.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/libgsmd_network.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,49 @@
+/* libgsmd network related functions
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */ 
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <libgsmd/libgsmd.h>
+#include <libgsmd/misc.h>
+
+#include <gsmd/usock.h>
+#include <gsmd/event.h>
+
+#include "lgsm_internals.h"
+
+int lgsm_netreg_register(struct lgsm_handle *lh, int oper)
+{
+	/* FIXME: implement oper selection */
+	return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_REGISTER);
+}
+
+int lgsm_signal_quality(struct lgsm_handle *lh)
+{
+	return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_SIGQ_GET);
+}
+
+int lgsmd_operator_name(struct lgsm_handle *lh)
+{
+	return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_OPER_GET);
+}

Added: developers/seanchiang/gsm/src/libgsmd/libgsmd_passthrough.c
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/libgsmd_passthrough.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/libgsmd_passthrough.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,91 @@
+/* libgsmd passthrough
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */ 
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <gsmd/usock.h>
+#include <libgsmd/libgsmd.h>
+
+#include "lgsm_internals.h"
+
+#define PT_BUF_SIZE	1024
+static char passthrough_buf[sizeof(struct gsmd_msg_hdr)+PT_BUF_SIZE];
+static char passthrough_rbuf[sizeof(struct gsmd_msg_hdr)+PT_BUF_SIZE];
+
+int lgsm_passthrough_send(struct lgsm_handle *lh, const char *tx)
+{
+	struct gsmd_msg_hdr *gmh = (struct gsmd_msg_hdr *)passthrough_buf;
+	char *tx_buf = (char *)gmh + sizeof(*gmh);
+	int len = strlen(tx);
+
+	if (len > PT_BUF_SIZE)
+		return -EINVAL;
+
+	gmh->version = GSMD_PROTO_VERSION;
+	gmh->msg_type = GSMD_MSG_PASSTHROUGH;
+	gmh->msg_subtype = GSMD_PASSTHROUGH_REQ;
+	gmh->len = len+1;
+	strcpy(tx_buf, tx);
+
+	if (lgsm_send(lh, gmh) < len+sizeof(*gmh))
+		return -EIO;
+
+	return gmh->id;
+}
+
+int lgsm_passthrough(struct lgsm_handle *lh, const char *tx, char *rx, unsigned int *rx_len)
+{
+	struct gsmd_msg_hdr *rgmh = (struct gsmd_msg_hdr *)passthrough_rbuf;
+	char *rx_buf = (char *)rgmh + sizeof(*rgmh);
+	int rc;
+
+	rc = lgsm_passthrough_send(lh, tx);
+	if (rc < 0)
+		return rc;
+
+	/* since we synchronously want to wait for a response, we need to
+	 * _internally_ loop over incoming packets and call the callbacks for
+	 * intermediate messages (if applicable) */
+	rc = lgsm_blocking_wait_packet(lh, rc, passthrough_rbuf, 
+					sizeof(passthrough_rbuf));
+	if (rc <= 0)
+		return rc;
+
+	if (rc < sizeof(*rgmh))
+		return -EINVAL;
+
+	if (rc < sizeof(*rgmh) + rgmh->len)
+		return -EINVAL;
+	
+	/* FIXME: make sure rx_buf is zero-terminated */
+	strcpy(rx, rx_buf);
+	*rx_len = rgmh->len;
+
+	return rx_len;
+}

Added: developers/seanchiang/gsm/src/libgsmd/libgsmd_phone.c
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/libgsmd_phone.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/libgsmd_phone.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,46 @@
+/* libgsmd phone related functions
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */ 
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <libgsmd/libgsmd.h>
+#include <libgsmd/misc.h>
+
+#include <gsmd/usock.h>
+#include <gsmd/event.h>
+
+#include "lgsm_internals.h"
+
+int lgsm_phone_power(struct lgsm_handle *lh, int power)
+{
+	int type;
+
+	if (power)
+		type = GSMD_PHONE_POWERUP;
+	else
+		type = GSMD_PHONE_POWERDOWN;
+		
+	return lgsm_send_simple(lh, GSMD_MSG_PHONE, type);
+}

Added: developers/seanchiang/gsm/src/libgsmd/libgsmd_pin.c
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/libgsmd_pin.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/libgsmd_pin.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <gsmd/event.h>
+#include <libgsmd/libgsmd.h>
+
+static const char *pin_type_names[__NUM_GSMD_PIN] = {
+	[GSMD_PIN_NONE]		= "NONE",
+	[GSMD_PIN_SIM_PIN]	= "SIM PIN",
+	[GSMD_PIN_SIM_PUK]	= "SIM PUK",
+	[GSMD_PIN_PH_SIM_PIN]	= "Phone-to-SIM PIN",
+	[GSMD_PIN_PH_FSIM_PIN]	= "Phone-to-very-first SIM PIN",
+	[GSMD_PIN_PH_FSIM_PUK]	= "Phone-to-very-first SIM PUK",
+	[GSMD_PIN_SIM_PIN2]	= "SIM PIN2",
+	[GSMD_PIN_SIM_PUK2]	= "SIM PUK2",
+	[GSMD_PIN_PH_NET_PIN]	= "Network personalization PIN",
+	[GSMD_PIN_PH_NET_PUK]	= "Network personalizaiton PUK",
+	[GSMD_PIN_PH_NETSUB_PIN]= "Network subset personalisation PIN",
+	[GSMD_PIN_PH_NETSUB_PUK]= "Network subset personalisation PUK",
+	[GSMD_PIN_PH_SP_PIN]	= "Service provider personalisation PIN",
+	[GSMD_PIN_PH_SP_PUK]	= "Service provider personalisation PUK",
+	[GSMD_PIN_PH_CORP_PIN]	= "Corporate personalisation PIN",
+	[GSMD_PIN_PH_CORP_PUK]	= "Corporate personalisation PUK",
+};
+
+const char *lgsm_pin_name(enum gsmd_pin_type ptype)
+{
+	if (ptype >= __NUM_GSMD_PIN)
+		return "unknown";
+
+	return pin_type_names[ptype];
+}
+
+int lgsm_pin(struct lgsm_handle *lh, unsigned int type, char *pin, char *newpin)
+{
+	int rc;
+	struct {
+		struct gsmd_msg_hdr gmh;
+		struct gsmd_pin gp;
+	} __attribute__ ((packed)) *gm;
+
+	if (strlen(pin) > GSMD_PIN_MAXLEN || 
+	    (newpin && strlen(newpin) > GSMD_PIN_MAXLEN) ||
+	    type >= __NUM_GSMD_PIN)
+		return -EINVAL;
+
+	gm = (void *) lgsm_gmh_fill(GSMD_MSG_PIN, GSMD_PIN_INPUT,
+				    sizeof(struct gsmd_pin));
+	if (!gm)
+		return -ENOMEM;
+
+	gm->gp.type = type;
+
+	gm->gp.pin[0] = '\0';
+	strcat(gm->gp.pin, pin);
+
+	switch (type) {
+	case GSMD_PIN_SIM_PUK:
+	case GSMD_PIN_SIM_PUK2:
+		/* GSM 07.07 explicitly states that only those two PUK types
+		 * require a new pin to be specified! Don't know if this is a
+		 * bug or a feature. */
+		if (!newpin)
+			return -EINVAL;
+		gm->gp.newpin[0] = '\0';
+		strcat(gm->gp.newpin, newpin);
+		break;
+	default:
+		break;
+	}
+	printf("sending pin='%s', newpin='%s'\n", gm->gp.pin, gm->gp.newpin);
+	rc = lgsm_send(lh, &gm->gmh);
+	free(gm);
+
+	return rc;
+}

Added: developers/seanchiang/gsm/src/libgsmd/libgsmd_voicecall.c
===================================================================
--- developers/seanchiang/gsm/src/libgsmd/libgsmd_voicecall.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/libgsmd/libgsmd_voicecall.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,115 @@
+/* libgsmd voice call support
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */ 
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <libgsmd/voicecall.h>
+
+#include "lgsm_internals.h"
+
+int lgsm_send_simple(struct lgsm_handle *lh, int type, int sub_type)
+{
+	struct gsmd_msg_hdr *gmh;
+	int rc;
+
+	gmh = lgsm_gmh_fill(type, sub_type, 0);
+	if (!gmh)
+		return -ENOMEM;
+	rc = lgsm_send(lh, gmh);
+	if (rc < gmh->len + sizeof(*gmh)) {
+		lgsm_gmh_free(gmh);
+		return -EIO;
+	}
+	lgsm_gmh_free(gmh);
+
+	return 0;
+}
+
+int lgsm_voice_out_init(struct lgsm_handle *lh,
+			const struct lgsm_addr *number)
+{
+	struct gsmd_msg_hdr *gmh;
+	struct gsmd_addr *ga;
+	int rc;
+
+	gmh = lgsm_gmh_fill(GSMD_MSG_VOICECALL,
+			    GSMD_VOICECALL_DIAL, sizeof(*ga));
+	if (!gmh)
+		return -ENOMEM;
+	ga = (struct gsmd_addr *) gmh->data;
+	ga->type = number->type;	/* FIXME: is this correct? */
+	memcpy(ga->number, number->addr, sizeof(ga->number));
+	ga->number[sizeof(ga->number)-1] = '\0';
+
+	rc = lgsm_send(lh, gmh);
+	if (rc < gmh->len + sizeof(*gmh)) {
+		lgsm_gmh_free(gmh);
+		return -EIO;
+	}
+
+	lgsm_gmh_free(gmh);
+
+	return 0;
+}
+
+int lgsm_voice_dtmf(struct lgsm_handle *lh, char dtmf_char)
+{
+	struct gsmd_msg_hdr *gmh;
+	struct gsmd_dtmf *gd;
+	int rc;
+
+	gmh = lgsm_gmh_fill(GSMD_MSG_VOICECALL,
+			    GSMD_VOICECALL_DTMF, sizeof(*gd)+1);
+	if (!gmh)
+		return -ENOMEM;
+	gd = (struct gsmd_dtmf *) gmh->data;
+	gd->len = 1;
+	gd->dtmf[0] = dtmf_char;
+
+	rc = lgsm_send(lh, gmh);
+	if (rc < gmh->len + sizeof(*gd)+1) {
+		lgsm_gmh_free(gmh);;
+		return -EIO;
+	}
+
+	lgsm_gmh_free(gmh);
+
+	return 0;
+}
+
+int lgsm_voice_in_accept(struct lgsm_handle *lh)
+{
+	return lgsm_send_simple(lh, GSMD_MSG_VOICECALL, GSMD_VOICECALL_ANSWER);
+}
+
+int lgsm_voice_hangup(struct lgsm_handle *lh)
+{
+	return lgsm_send_simple(lh, GSMD_MSG_VOICECALL, GSMD_VOICECALL_HANGUP);
+}
+
+int lgsm_voice_volume_set(struct lgsm_handle *lh, int volume)
+{
+	/* FIXME: we need to pass along the parameter */
+	return lgsm_send_simple(lh, GSMD_MSG_VOICECALL, GSMD_VOICECALL_VOL_SET);
+}

Added: developers/seanchiang/gsm/src/util/Makefile.am
===================================================================
--- developers/seanchiang/gsm/src/util/Makefile.am	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/Makefile.am	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,10 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS = -std=gnu99
+
+bin_PROGRAMS = libgsmd-tool
+
+libgsmd_tool_SOURCES = libgsmd-tool.c shell.c event.c pin.c atcmd.c
+libgsmd_tool_LDADD = ../libgsmd/libgsmd.la
+libgsmd_tool_LDFLAGS = -dynamic
+
+noinst_HEADERS = atcmd.h event.h pin.h shell.h

Added: developers/seanchiang/gsm/src/util/atcmd.c
===================================================================
--- developers/seanchiang/gsm/src/util/atcmd.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/atcmd.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,99 @@
+/* libgsmd tool
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <libgsmd/libgsmd.h>
+
+#define STDIN_BUF_SIZE	1024
+
+/* this is the handler for receiving passthrough responses */
+static int pt_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+	char *payload = (char *)gmh + sizeof(*gmh);
+	printf("RSTR=`%s'\n", payload);
+}
+
+int atcmd_main(struct lgsm_handle *lgsmh)
+{
+	int rc;
+	char buf[STDIN_BUF_SIZE+1];
+	char rbuf[STDIN_BUF_SIZE+1];
+	int rlen = sizeof(rbuf);
+	fd_set readset;
+
+	lgsm_register_handler(lgsmh, GSMD_MSG_PASSTHROUGH, &pt_msghandler);
+
+#if 1
+	fcntl(0, F_SETFD, O_NONBLOCK);
+	fcntl(1, F_SETFD, O_NONBLOCK);
+	fcntl(2, F_SETFD, O_NONBLOCK);
+	fcntl(lgsm_fd(lgsmh), F_SETFD, O_NONBLOCK);
+#endif
+
+	FD_ZERO(&readset);
+
+	while (1) {
+		fd_set readset;
+		int gsm_fd = lgsm_fd(lgsmh);
+
+		FD_SET(0, &readset);
+		FD_SET(gsm_fd, &readset);
+
+		rc = select(gsm_fd+1, &readset, NULL, NULL, NULL);
+		if (rc <= 0)	
+			break;
+		if (FD_ISSET(gsm_fd, &readset)) {
+			/* we've received something on the gsmd socket, pass it
+			 * on to the library */
+			rc = read(gsm_fd, buf, sizeof(buf));
+			if (rc <= 0) {
+				printf("ERROR reding from gsm_fd\n");
+				break;
+			}
+			rc = lgsm_handle_packet(lgsmh, buf, rc);
+			if (rc < 0)
+				printf("ERROR processing packet: %d(%s)\n", rc, strerror(rc));
+		}
+		if (FD_ISSET(0, &readset)) {
+			/* we've received something on stdin.  send it as passthrough
+			 * to gsmd */
+			rc = fscanf(stdin, "%s", buf);
+			if (rc == EOF) {
+				printf("EOF\n");
+				return -1;
+			}
+			if (rc <= 0) {
+				printf("NULL\n");
+				continue;
+			}
+			printf("STR=`%s'\n", buf);
+		}
+		/* this is a synchronous call for a passthrough command */
+		lgsm_passthrough(lgsmh, buf, rbuf, &rlen);
+		printf("RSTR=`%s'\n", rbuf);
+	}
+}

Added: developers/seanchiang/gsm/src/util/atcmd.h
===================================================================
--- developers/seanchiang/gsm/src/util/atcmd.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/atcmd.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,2 @@
+
+extern int atcmd_main(struct lgsm_handle *lgsmh);

Added: developers/seanchiang/gsm/src/util/event.c
===================================================================
--- developers/seanchiang/gsm/src/util/event.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/event.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,141 @@
+/* libgsmd tool
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdio.h>
+#include <string.h>
+
+#include <common/linux_list.h>
+#include <libgsmd/libgsmd.h>
+#include <libgsmd/event.h>
+
+static int incall_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	printf("EVENT: Incoming call type = %u\n", aux->u.call.type);
+
+	return 0;
+}
+
+static int clip_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	printf("EVENT: Incoming call clip = %s\n", aux->u.clip.addr.number);
+
+	return 0;
+}
+
+static int colp_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	printf("EVENT: Outgoing call colp = %s\n", aux->u.colp.addr.number);
+
+	return 0;
+}
+
+static int netreg_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	printf("EVENT: Netreg ");
+
+	switch (aux->u.netreg.state) {
+	case 0:
+		printf("not searching for network ");
+		break;
+	case 1:
+		printf("registered (home network) ");
+		break;
+	case 2:
+		printf("searching for network ");
+		break;
+	case 3:
+		printf("registration denied ");
+		break;
+	case 5:
+		printf("registered (roaming) ");
+		break;
+	}
+
+	if (aux->u.netreg.lac)
+		printf("LocationAreaCode = 0x%04X ", aux->u.netreg.lac);
+	if (aux->u.netreg.ci)
+		printf("CellID = 0x%04X ", aux->u.netreg.ci);
+	
+	printf("\n");
+
+	return 0;
+}
+
+static int sigq_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	printf("EVENT: Signal Quality: %u\n", aux->u.signal.sigq.rssi);
+	return 0;
+}
+
+static const char *cprog_names[] = {
+	[GSMD_CALLPROG_SETUP]		= "SETUP",
+	[GSMD_CALLPROG_DISCONNECT]	= "DISCONNECT",
+	[GSMD_CALLPROG_ALERT]		= "ALERT",
+	[GSMD_CALLPROG_CALL_PROCEED]	= "PROCEED",
+	[GSMD_CALLPROG_SYNC]		= "SYNC",
+	[GSMD_CALLPROG_PROGRESS]	= "PROGRESS",
+	[GSMD_CALLPROG_CONNECTED]	= "CONNECTED",
+	[GSMD_CALLPROG_RELEASE]		= "RELEASE",
+	[GSMD_CALLPROG_REJECT]		= "REJECT",
+	[GSMD_CALLPROG_UNKNOWN]		= "UNKNOWN",
+};
+
+static const char *cdir_names[] = {
+	[GSMD_CALL_DIR_MO]		= "Outgoing",
+	[GSMD_CALL_DIR_MT]		= "Incoming",
+	[GSMD_CALL_DIR_CCBS]		= "CCBS",
+	[GSMD_CALL_DIR_MO_REDIAL]	= "Outgoing Redial",
+};
+
+static int cprog_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	const char *name, *dir;
+
+	if (aux->u.call_status.prog >= ARRAY_SIZE(cprog_names))
+		name = "UNDEFINED";
+	else
+		name = cprog_names[aux->u.call_status.prog];
+
+	if (aux->u.call_status.dir >= ARRAY_SIZE(cdir_names))
+		dir = "";
+	else
+		dir = cdir_names[aux->u.call_status.dir];
+
+	printf("EVENT: %s Call Progress: %s\n", dir, name);
+
+	return 0;
+}
+
+int event_init(struct lgsm_handle *lh)
+{
+	int rc;
+
+	rc  = lgsm_evt_handler_register(lh, GSMD_EVT_IN_CALL, &incall_handler);
+	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_CLIP, &clip_handler);
+	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_OUT_COLP, &colp_handler);
+	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_NETREG, &netreg_handler);
+	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_SIGNAL, &sigq_handler);
+	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_OUT_STATUS, &cprog_handler);
+
+	return rc;
+}
+

Added: developers/seanchiang/gsm/src/util/event.h
===================================================================
--- developers/seanchiang/gsm/src/util/event.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/event.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,2 @@
+
+extern int event_init(struct lgsm_handle *lh);

Added: developers/seanchiang/gsm/src/util/libgsmd-tool.c
===================================================================
--- developers/seanchiang/gsm/src/util/libgsmd-tool.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/libgsmd-tool.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,147 @@
+/* libgsmd tool
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <libgsmd/libgsmd.h>
+
+#include "pin.h"
+#include "event.h"
+#include "shell.h"
+#include "atcmd.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+static struct lgsm_handle *lgsmh;
+static int verbose = 0;
+
+enum mode_enum {
+	MODE_NONE,
+	MODE_SHELL,
+	MODE_EVENTLOG,
+	MODE_ATCMD,
+};
+
+static char *modes[] = {
+	[MODE_NONE]	= "",
+	[MODE_SHELL]	= "shell",
+	[MODE_EVENTLOG]	= "eventlog",
+	[MODE_ATCMD]	= "atcmd",
+};
+
+static int parse_mode(char *modestr)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(modes); i++) {
+		if (!strcmp(modes[i], modestr))
+			return i;
+	}
+
+	return -1;
+}
+
+static struct option opts[] = {
+	{ "help", 0, 0, 'h' },
+	{ "version", 0, 0, 'V' },
+	{ "verbose", 0, 0, 'v' },
+	{ "mode", 1, 0, 'm' },
+	{ "pin", 1, 0, 'p' },
+	{ 0, 0, 0, 0 }
+};
+
+static void help(void)
+{
+	printf("Usage:\n"
+		"\t-h\t--help\tPrint this Help message\n"
+		"\t-V\t--version\tPrint version number\n"
+		"\t-v\t--verbose\tBe more verbose\n"
+		"\t-m\t--mode\tSet mode {shell,eventlog,atcmd}\n"
+		);
+}
+
+int main(int argc, char **argv)
+{
+	char *pin = NULL;
+	int rc, i, mode;
+
+	printf("libgsm-tool - (C) 2006 by Harald Welte\n"
+		"This program is Free Software and has ABSOLUTELY NO WARRANTY\n\n");
+
+	while (1) {
+		int c, option_index = 0;
+		c = getopt_long(argc, argv, "vVhm:p:", opts, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'v':
+			verbose = 1;
+			break;
+		case 'V':
+			/* FIXME */
+			break;
+		case 'h':
+			help();
+			exit(0);
+			break;
+		case 'm':
+			mode = parse_mode(optarg);
+			if (mode < 0) {
+				fprintf(stderr, "unknown/unsupported mode `%s'\n", optarg);
+				exit(2);
+			}
+			break;
+		case 'p':
+			pin = optarg;
+			break;
+		}
+	}
+
+	lgsmh = lgsm_init(LGSMD_DEVICE_GSMD);
+	if (!lgsmh) {
+		fprintf(stderr, "Can't connect to gsmd\n");
+		exit(1);
+	}
+
+	pin_init(lgsmh, pin);
+	event_init(lgsmh);
+
+	switch (mode) {
+	case MODE_ATCMD:
+		atcmd_main(lgsmh);
+		break;
+	case MODE_SHELL:
+		shell_main(lgsmh);
+		break;
+	}
+
+	exit(0);
+}

Added: developers/seanchiang/gsm/src/util/pin.c
===================================================================
--- developers/seanchiang/gsm/src/util/pin.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/pin.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,78 @@
+/* libgsmd tool
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdio.h>
+#include <string.h>
+
+#include <libgsmd/libgsmd.h>
+#include <libgsmd/event.h>
+#include <libgsmd/pin.h>
+
+#define PIN_SIZE 8
+
+static char *pin;
+static char pinbuf[PIN_SIZE+1];
+static char pinbuf2[PIN_SIZE+1];
+
+static int pin_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	int rc;
+	int type = aux->u.pin.type;
+	char *newpin = NULL;
+
+	printf("EVENT: PIN request (type='%s') ", lgsm_pin_name(aux->u.pin.type));
+
+	/* FIXME: read pin from STDIN and send it back via lgsm_pin */
+	if (type == 1 && pin) {
+		printf("Auto-responding with pin `%s'\n", pin);
+		lgsm_pin(lh, type, pin, NULL);
+	} else {
+		do {
+			printf("Please enter %s: ", lgsm_pin_name(type));
+			rc = fscanf(stdin, "%8s", &pinbuf);
+		} while (rc < 1);
+
+		switch (type) {
+		case GSMD_PIN_SIM_PUK:
+		case GSMD_PIN_SIM_PUK2:
+			do {
+				printf("Please enter new PIN: ");
+				rc = fscanf(stdin, "%8s", &pinbuf2);
+				newpin = pinbuf2;
+			} while (rc < 1);
+			break;
+		default:
+			break;
+		}
+
+		return lgsm_pin(lh, type, pinbuf, newpin);
+	}
+
+	return 0;
+}
+
+int pin_init(struct lgsm_handle *lh, const char *pin_preset)
+{
+	pin = pin_preset;
+	return lgsm_evt_handler_register(lh, GSMD_EVT_PIN, &pin_handler);
+}
+

Added: developers/seanchiang/gsm/src/util/pin.h
===================================================================
--- developers/seanchiang/gsm/src/util/pin.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/pin.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,2 @@
+
+extern int pin_init(struct lgsm_handle *lh, const char *pin_preset);

Added: developers/seanchiang/gsm/src/util/shell.c
===================================================================
--- developers/seanchiang/gsm/src/util/shell.c	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/shell.c	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,307 @@
+/* libgsmd tool
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */ 
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <libgsmd/libgsmd.h>
+#include <libgsmd/voicecall.h>
+#include <libgsmd/misc.h>
+#include <libgsmd/phonebook.h>
+#include <libgsmd/sms.h>
+#include <gsmd/usock.h>
+
+#define STDIN_BUF_SIZE	1024
+
+/* this is the handler for receiving passthrough responses */
+static int pt_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+	char *payload = (char *)gmh + sizeof(*gmh);
+	printf("RSTR=`%s'\n", payload);
+}
+
+/* this is the handler for receiving phonebook responses */
+static int pb_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{
+	struct gsmd_phonebook *gp;
+	struct gsmd_phonebook_support *gps;
+	char *payload;
+
+	switch (gmh->msg_subtype) {
+	case GSMD_PHONEBOOK_FIND:		
+		break;
+	case GSMD_PHONEBOOK_READRG:
+		payload = (char *)gmh + sizeof(*gmh);
+		printf("%s\n", payload);	
+		break;
+	case GSMD_PHONEBOOK_READ:
+		gp = (struct gsmd_phonebook *) ((char *)gmh + sizeof(*gmh));
+		printf("%d, %s, %d, %s\n", gp->index, gp->numb, gp->type, gp->text);
+		break;
+	case GSMD_PHONEBOOK_WRITE:			
+	case GSMD_PHONEBOOK_DELETE:
+		payload = (char *)gmh + sizeof(*gmh);
+		printf("%s\n", payload);		
+		break;
+	case GSMD_PHONEBOOK_GET_SUPPORT:
+		gps = (struct gsmd_phonebook_support *) ((char *)gmh + sizeof(*gmh));
+		printf("(1-%d), %d, %d\n", gps->index, gps->nlength, gps->tlength);
+		break;
+	default:
+		return -EINVAL;
+	}	
+}
+
+/* this is the handler for receiving sms responses */
+static int sms_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
+{	
+	char *payload;
+
+	switch (gmh->msg_subtype) {
+	case GSMD_SMS_LIST:
+		break;	
+	case GSMD_SMS_READ:		
+	case GSMD_SMS_SEND:		
+	case GSMD_SMS_WRITE:			
+	case GSMD_SMS_DELETE:
+		payload = (char *)gmh + sizeof(*gmh);
+		printf("%s\n", payload);		
+		break;	
+	default:
+		return -EINVAL;
+	}	
+}
+
+static int shell_help(void)
+{
+	printf( "\tA\tAnswer incoming call\n"
+		"\tD\tDial outgoing number\n"
+		"\tH\tHangup call\n"
+		"\tO\tPower On\n"
+		"\to\tPower Off\n"
+		"\tR\tRegister Netowrk\n"
+		"\tT\tSend DTMF Tone\n"
+		"\tpd\tPB Delete (pb=index)\n"
+		"\tpr\tPB Read (pr=index)\n"
+		"\tprr\tPB Read Range (prr=index1,index2)\n"
+		"\tpf\tPB Find (pff=indtext)\n"
+		"\tpw\tPB Write (pw=index,number,text)\n"
+		"\tps\tPB Support\n"
+		"\tsd\tSMS Delete (sd=index,delflg)\n"
+		"\tsl\tSMS List (sl=stat)\n"
+		"\tsr\tSMS Read (sr=index)\n"
+		"\tss\tSMS Send (ss=number,text)\n"
+		"\tsw\tSMS Write (sw=stat,number,text)\n"
+		"\tq\tQuit\n"
+		);
+}
+
+int shell_main(struct lgsm_handle *lgsmh)
+{
+	int rc;
+	char buf[STDIN_BUF_SIZE+1];
+	char rbuf[STDIN_BUF_SIZE+1];
+	int rlen = sizeof(rbuf);
+	fd_set readset;
+	char *ptr, *fcomma, *lcomma;
+
+	lgsm_register_handler(lgsmh, GSMD_MSG_PASSTHROUGH, &pt_msghandler);
+	lgsm_register_handler(lgsmh, GSMD_MSG_PHONEBOOK, &pb_msghandler);
+	lgsm_register_handler(lgsmh, GSMD_MSG_SMS, &sms_msghandler);
+
+	fcntl(0, F_SETFD, O_NONBLOCK);
+	fcntl(lgsm_fd(lgsmh), F_SETFD, O_NONBLOCK);
+
+	FD_ZERO(&readset);
+
+	printf("# ");
+
+	while (1) {
+		fd_set readset;
+		int gsm_fd = lgsm_fd(lgsmh);
+		FD_SET(0, &readset);
+		FD_SET(gsm_fd, &readset);
+
+		rc = select(gsm_fd+1, &readset, NULL, NULL, NULL);
+		if (rc <= 0)	
+			break;
+		if (FD_ISSET(gsm_fd, &readset)) {
+			/* we've received something on the gsmd socket, pass it
+			 * on to the library */
+			rc = read(gsm_fd, buf, sizeof(buf));
+			if (rc <= 0) {
+				printf("ERROR reding from gsm_fd\n");
+				break;
+			}
+			rc = lgsm_handle_packet(lgsmh, buf, rc);
+		}
+		if (FD_ISSET(0, &readset)) {
+			/* we've received something on stdin.  */
+			printf("# ");
+			rc = fscanf(stdin, "%s", buf);			
+			if (rc == EOF) {
+				printf("EOF\n");
+				return -1;
+			}
+			if (rc <= 0) {
+				printf("NULL\n");
+				continue;
+			}
+			if (!strcmp(buf, "h")) {
+				shell_help();
+			} else if (!strcmp(buf, "?")) {
+				shell_help();
+			} else if (!strcmp(buf, "H")) {
+				printf("Hangup\n");
+				lgsm_voice_hangup(lgsmh);
+			} else if (buf[0] == 'D') {
+				struct lgsm_addr addr;
+				if (strlen(buf) < 2)
+					continue;
+				printf("Dial %s\n", buf+1);
+				addr.type = 129;
+				strncpy(addr.addr, buf+1, sizeof(addr.addr)-1);
+				addr.addr[sizeof(addr.addr)-1] = '\0';
+				lgsm_voice_out_init(lgsmh, &addr);
+			} else if (!strcmp(buf, "A")) {
+				printf("Answer\n");
+				lgsm_voice_in_accept(lgsmh);
+			} else if (!strcmp(buf, "O")) {
+				printf("Power-On\n");
+				lgsm_phone_power(lgsmh, 1);
+			} else if (!strcmp(buf, "o")) {
+				printf("Power-Off\n");
+				lgsm_phone_power(lgsmh, 0);
+			} else if (!strcmp(buf, "R")) {
+				printf("Register\n");
+				lgsm_netreg_register(lgsmh, 0);
+			} else if (!strcmp(buf, "q")) {
+				exit(0);
+			} else if (buf[0] == 'T') {
+				if (strlen(buf) < 2)
+					continue;
+				printf("DTMF: %c\n", buf[1]);
+				lgsm_voice_dtmf(lgsmh, buf[1]);
+			} else if ( !strncmp(buf, "pd", 2)) {
+				printf("Delete Phonebook Entry\n");				
+				ptr = strchr(buf, '=');
+				lgsmd_pb_del_entry(lgsmh, atoi(ptr+1));				
+			} else if ( !strncmp(buf, "prr", 3)) {	
+				printf("Read Phonebook Entries\n");
+				struct lgsm_phonebook_readrg pb_readrg;
+
+				ptr = strchr(buf, '=');
+				pb_readrg.index1 = atoi(ptr+1);				
+				ptr = strchr(buf, ',');
+				pb_readrg.index2 = atoi(ptr+1);	
+
+				lgsm_pb_read_entryies(lgsmh, &pb_readrg);
+			} else if ( !strncmp(buf, "pr", 2)) {	
+				printf("Read Phonebook Entry\n");
+				ptr = strchr(buf, '=');				
+				lgsm_pb_read_entry(lgsmh, atoi(ptr+1));	
+			} else if ( !strncmp(buf, "pf", 2)) {
+				printf("Find Phonebook Entry\n");
+				struct lgsm_phonebook_find pb_find;
+
+				ptr = strchr(buf, '=');
+				strncpy(pb_find.findtext, ptr+1, sizeof(pb_find.findtext)-1);
+				pb_find.findtext[strlen(ptr+1)] = '\0';	
+			
+				lgsm_pb_find_entry(lgsmh, &pb_find);
+			} else if ( !strncmp(buf, "pw", 2)) {
+				printf("Write Phonebook Entry\n");
+				struct lgsm_phonebook pb;
+
+				ptr = strchr(buf, '=');
+				pb.index = atoi(ptr+1);
+
+				fcomma = strchr(buf, ',');
+				lcomma = strrchr(buf, ',');
+				strncpy(pb.numb, fcomma+1, (lcomma-fcomma-1));
+				pb.numb[(lcomma-fcomma-1)] = '\0';				
+				if ( '+' == pb.numb[0] )
+					pb.type = LGSM_PB_ATYPE_INTL;
+				else 
+					pb.type = LGSM_PB_ATYPE_OTHE;				
+				strncpy(pb.text, lcomma+1, strlen(lcomma+1));
+				pb.text[strlen(lcomma+1)] = '\0';
+				
+				lgsmd_pb_write_entry(lgsmh, &pb);
+			} else if ( !strncmp(buf, "ps", 2)) {	
+				printf("Get Phonebook Support\n");
+				lgsm_pb_get_support(lgsmh);				
+			} else if ( !strncmp(buf, "sd", 2)) {		
+				printf("Delete SMS\n");			
+				struct lgsm_sms_delete sms_del;
+
+				ptr = strchr(buf, '=');
+				sms_del.index = atoi(ptr+1);
+				ptr = strchr(buf, ',');
+				sms_del.delflg = atoi(ptr+1);	
+			
+				lgsmd_sms_delete(lgsmh, &sms_del);				
+			} else if ( !strncmp(buf, "sl", 2)) {		
+				printf("List SMS\n");	
+				ptr = strchr(buf, '=');	
+					
+				lgsm_sms_list(lgsmh, atoi(ptr+1));			
+			} else if ( !strncmp(buf, "sr", 2)) {				
+				printf("Read SMS\n");	
+				ptr = strchr(buf, '=');	
+					
+				lgsm_sms_read(lgsmh, atoi(ptr+1));				
+			} else if ( !strncmp(buf, "ss", 2)) {
+				printf("Send SMS\n");		
+				struct lgsm_sms sms;
+
+				ptr = strchr(buf, '=');
+				fcomma = strchr(buf, ',');
+				strncpy(sms.addr, ptr+1, (fcomma-ptr-1));
+				sms.addr[fcomma-ptr-1] = '\0';
+				strncpy(sms.data, fcomma+1, strlen(fcomma+1));
+				sms.data[strlen(fcomma+1)] = '\0';
+						
+				lgsmd_sms_send(lgsmh, &sms);			
+			} else if ( !strncmp(buf, "sw", 2)) {	
+				printf("Write SMS\n");				
+				struct lgsm_sms_write sms_write;
+
+				ptr = strchr(buf, '=');
+				sms_write.stat = atoi(ptr+1);				
+				fcomma = strchr(buf, ',');
+				lcomma = strrchr(buf, ',');
+				strncpy(sms_write.sms.addr, fcomma+1, (lcomma-fcomma-1));
+				sms_write.sms.addr[lcomma-fcomma-1] = '\0';
+				strncpy(sms_write.sms.data, lcomma+1, strlen(lcomma+1));
+				sms_write.sms.data[strlen(lcomma+1)] = '\0';	
+				
+				lgsmd_sms_write(lgsmh, &sms_write);
+			} else {
+				printf("Unknown command `%s'\n", buf);
+			}
+		}
+	}
+}

Added: developers/seanchiang/gsm/src/util/shell.h
===================================================================
--- developers/seanchiang/gsm/src/util/shell.h	2007-03-20 07:24:45 UTC (rev 1425)
+++ developers/seanchiang/gsm/src/util/shell.h	2007-03-20 07:29:51 UTC (rev 1426)
@@ -0,0 +1,2 @@
+
+extern int shell_main(struct lgsm_handle *lgsmh);





More information about the commitlog mailing list