Android-x86
Fork
Donation

  • R/O
  • HTTP
  • SSH
  • HTTPS

hardware-ril: 提交

hardware/ril


Commit MetaInfo

修订版9c7019fc06d30ac1ce6083e1d71e072293e4c018 (tree)
时间2012-04-30 02:58:05
作者Chih-Wei Huang <cwhuang@linu...>
CommiterChih-Wei Huang

Log Message

add huaweigeneric-ril

Originates from https://github.com/DerArtem/huaweigeneric-ril
and a modified version in wetab tree.

更改概述

差异

--- /dev/null
+++ b/huaweigeneric-ril/Android.mk
@@ -0,0 +1,35 @@
1+# Copyright 2012 The Android-x86 Open Source Project
2+
3+LOCAL_PATH := $(call my-dir)
4+include $(CLEAR_VARS)
5+
6+LOCAL_SRC_FILES := \
7+ at_tok.c \
8+ atchannel.c \
9+ audiochannel.cpp \
10+ fcp_parser.c \
11+ gsm.c \
12+ huaweigeneric-ril.c \
13+ misc.c \
14+ requestdatahandler.c \
15+ sms.c \
16+ sms_gsm.c \
17+
18+LOCAL_SHARED_LIBRARIES := \
19+ libcutils \
20+ libutils \
21+ libril \
22+ libmedia
23+
24+# for asprinf
25+LOCAL_CFLAGS := -D_GNU_SOURCE
26+#build shared library
27+LOCAL_CFLAGS += -DRIL_SHLIB
28+
29+LOCAL_C_INCLUDES := \
30+ hardware/ril/libril \
31+
32+LOCAL_MODULE:= libhuaweigeneric-ril
33+LOCAL_MODULE_TAGS := optional
34+
35+include $(BUILD_SHARED_LIBRARY)
--- /dev/null
+++ b/huaweigeneric-ril/NOTICE
@@ -0,0 +1,189 @@
1+
2+ Copyright (c) 2005-2008, The Android Open Source Project
3+
4+ Licensed under the Apache License, Version 2.0 (the "License");
5+ you may not use this file except in compliance with the License.
6+
7+ Unless required by applicable law or agreed to in writing, software
8+ distributed under the License is distributed on an "AS IS" BASIS,
9+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+ See the License for the specific language governing permissions and
11+ limitations under the License.
12+
13+
14+ Apache License
15+ Version 2.0, January 2004
16+ http://www.apache.org/licenses/
17+
18+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
19+
20+ 1. Definitions.
21+
22+ "License" shall mean the terms and conditions for use, reproduction,
23+ and distribution as defined by Sections 1 through 9 of this document.
24+
25+ "Licensor" shall mean the copyright owner or entity authorized by
26+ the copyright owner that is granting the License.
27+
28+ "Legal Entity" shall mean the union of the acting entity and all
29+ other entities that control, are controlled by, or are under common
30+ control with that entity. For the purposes of this definition,
31+ "control" means (i) the power, direct or indirect, to cause the
32+ direction or management of such entity, whether by contract or
33+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
34+ outstanding shares, or (iii) beneficial ownership of such entity.
35+
36+ "You" (or "Your") shall mean an individual or Legal Entity
37+ exercising permissions granted by this License.
38+
39+ "Source" form shall mean the preferred form for making modifications,
40+ including but not limited to software source code, documentation
41+ source, and configuration files.
42+
43+ "Object" form shall mean any form resulting from mechanical
44+ transformation or translation of a Source form, including but
45+ not limited to compiled object code, generated documentation,
46+ and conversions to other media types.
47+
48+ "Work" shall mean the work of authorship, whether in Source or
49+ Object form, made available under the License, as indicated by a
50+ copyright notice that is included in or attached to the work
51+ (an example is provided in the Appendix below).
52+
53+ "Derivative Works" shall mean any work, whether in Source or Object
54+ form, that is based on (or derived from) the Work and for which the
55+ editorial revisions, annotations, elaborations, or other modifications
56+ represent, as a whole, an original work of authorship. For the purposes
57+ of this License, Derivative Works shall not include works that remain
58+ separable from, or merely link (or bind by name) to the interfaces of,
59+ the Work and Derivative Works thereof.
60+
61+ "Contribution" shall mean any work of authorship, including
62+ the original version of the Work and any modifications or additions
63+ to that Work or Derivative Works thereof, that is intentionally
64+ submitted to Licensor for inclusion in the Work by the copyright owner
65+ or by an individual or Legal Entity authorized to submit on behalf of
66+ the copyright owner. For the purposes of this definition, "submitted"
67+ means any form of electronic, verbal, or written communication sent
68+ to the Licensor or its representatives, including but not limited to
69+ communication on electronic mailing lists, source code control systems,
70+ and issue tracking systems that are managed by, or on behalf of, the
71+ Licensor for the purpose of discussing and improving the Work, but
72+ excluding communication that is conspicuously marked or otherwise
73+ designated in writing by the copyright owner as "Not a Contribution."
74+
75+ "Contributor" shall mean Licensor and any individual or Legal Entity
76+ on behalf of whom a Contribution has been received by Licensor and
77+ subsequently incorporated within the Work.
78+
79+ 2. Grant of Copyright License. Subject to the terms and conditions of
80+ this License, each Contributor hereby grants to You a perpetual,
81+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
82+ copyright license to reproduce, prepare Derivative Works of,
83+ publicly display, publicly perform, sublicense, and distribute the
84+ Work and such Derivative Works in Source or Object form.
85+
86+ 3. Grant of Patent License. Subject to the terms and conditions of
87+ this License, each Contributor hereby grants to You a perpetual,
88+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
89+ (except as stated in this section) patent license to make, have made,
90+ use, offer to sell, sell, import, and otherwise transfer the Work,
91+ where such license applies only to those patent claims licensable
92+ by such Contributor that are necessarily infringed by their
93+ Contribution(s) alone or by combination of their Contribution(s)
94+ with the Work to which such Contribution(s) was submitted. If You
95+ institute patent litigation against any entity (including a
96+ cross-claim or counterclaim in a lawsuit) alleging that the Work
97+ or a Contribution incorporated within the Work constitutes direct
98+ or contributory patent infringement, then any patent licenses
99+ granted to You under this License for that Work shall terminate
100+ as of the date such litigation is filed.
101+
102+ 4. Redistribution. You may reproduce and distribute copies of the
103+ Work or Derivative Works thereof in any medium, with or without
104+ modifications, and in Source or Object form, provided that You
105+ meet the following conditions:
106+
107+ (a) You must give any other recipients of the Work or
108+ Derivative Works a copy of this License; and
109+
110+ (b) You must cause any modified files to carry prominent notices
111+ stating that You changed the files; and
112+
113+ (c) You must retain, in the Source form of any Derivative Works
114+ that You distribute, all copyright, patent, trademark, and
115+ attribution notices from the Source form of the Work,
116+ excluding those notices that do not pertain to any part of
117+ the Derivative Works; and
118+
119+ (d) If the Work includes a "NOTICE" text file as part of its
120+ distribution, then any Derivative Works that You distribute must
121+ include a readable copy of the attribution notices contained
122+ within such NOTICE file, excluding those notices that do not
123+ pertain to any part of the Derivative Works, in at least one
124+ of the following places: within a NOTICE text file distributed
125+ as part of the Derivative Works; within the Source form or
126+ documentation, if provided along with the Derivative Works; or,
127+ within a display generated by the Derivative Works, if and
128+ wherever such third-party notices normally appear. The contents
129+ of the NOTICE file are for informational purposes only and
130+ do not modify the License. You may add Your own attribution
131+ notices within Derivative Works that You distribute, alongside
132+ or as an addendum to the NOTICE text from the Work, provided
133+ that such additional attribution notices cannot be construed
134+ as modifying the License.
135+
136+ You may add Your own copyright statement to Your modifications and
137+ may provide additional or different license terms and conditions
138+ for use, reproduction, or distribution of Your modifications, or
139+ for any such Derivative Works as a whole, provided Your use,
140+ reproduction, and distribution of the Work otherwise complies with
141+ the conditions stated in this License.
142+
143+ 5. Submission of Contributions. Unless You explicitly state otherwise,
144+ any Contribution intentionally submitted for inclusion in the Work
145+ by You to the Licensor shall be under the terms and conditions of
146+ this License, without any additional terms or conditions.
147+ Notwithstanding the above, nothing herein shall supersede or modify
148+ the terms of any separate license agreement you may have executed
149+ with Licensor regarding such Contributions.
150+
151+ 6. Trademarks. This License does not grant permission to use the trade
152+ names, trademarks, service marks, or product names of the Licensor,
153+ except as required for reasonable and customary use in describing the
154+ origin of the Work and reproducing the content of the NOTICE file.
155+
156+ 7. Disclaimer of Warranty. Unless required by applicable law or
157+ agreed to in writing, Licensor provides the Work (and each
158+ Contributor provides its Contributions) on an "AS IS" BASIS,
159+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
160+ implied, including, without limitation, any warranties or conditions
161+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
162+ PARTICULAR PURPOSE. You are solely responsible for determining the
163+ appropriateness of using or redistributing the Work and assume any
164+ risks associated with Your exercise of permissions under this License.
165+
166+ 8. Limitation of Liability. In no event and under no legal theory,
167+ whether in tort (including negligence), contract, or otherwise,
168+ unless required by applicable law (such as deliberate and grossly
169+ negligent acts) or agreed to in writing, shall any Contributor be
170+ liable to You for damages, including any direct, indirect, special,
171+ incidental, or consequential damages of any character arising as a
172+ result of this License or out of the use or inability to use the
173+ Work (including but not limited to damages for loss of goodwill,
174+ work stoppage, computer failure or malfunction, or any and all
175+ other commercial damages or losses), even if such Contributor
176+ has been advised of the possibility of such damages.
177+
178+ 9. Accepting Warranty or Additional Liability. While redistributing
179+ the Work or Derivative Works thereof, You may choose to offer,
180+ and charge a fee for, acceptance of support, warranty, indemnity,
181+ or other liability obligations and/or rights consistent with this
182+ License. However, in accepting such obligations, You may act only
183+ on Your own behalf and on Your sole responsibility, not on behalf
184+ of any other Contributor, and only if You agree to indemnify,
185+ defend, and hold each Contributor harmless for any liability
186+ incurred by, or claims asserted against, such Contributor by reason
187+ of your accepting any such warranty or additional liability.
188+
189+ END OF TERMS AND CONDITIONS
--- /dev/null
+++ b/huaweigeneric-ril/README
@@ -0,0 +1,36 @@
1+
2+The modules has still a few problems:
3+
4+* required modify init.rc add:
5+ on device-added-/dev/ttyUSB0
6+ chmod 0777 /dev/ttyUSB0
7+ on device-added-/dev/ttyUSB1
8+ chmod 0777 /dev/ttyUSB1
9+ on device-added-/dev/ttyUSB2
10+ chmod 0777 /dev/ttyUSB2
11+ on device-added-/dev/ttyUSB3
12+ chmod 0777 /dev/ttyUSB3
13+ on device-added-/dev/ttyUSB4
14+ chmod 0777 /dev/ttyUSB4
15+ on device-added-/dev/ttyUSB5
16+ chmod 0777 /dev/ttyUSB5
17+
18+
19+ on boot
20+ service ril-daemon /system/bin/rild
21+ socket rild stream 660 root radio
22+ socket rild-debug stream 660 radio system
23+ user root
24+ group radio cache inet misc audio
25+
26+
27+* Edit system/build.prop ,add:
28+ # for 3g
29+ rild.libpath=/system/lib/libhuaweigeneric-ril.so
30+ rild.libargs=-d /dev/ttyUSB2 -v /dev/ttyUSB1
31+ keyguard.no_require_sim=1
32+
33+
34+----
35+
36+ pppd must be suid ROOT, and kernel must include ppp support compiled in
--- /dev/null
+++ b/huaweigeneric-ril/at_error.h
@@ -0,0 +1,236 @@
1+#ifndef ATERROR_H
2+#define ATERROR_H 1
3+
4+#define mbm_error \
5+ at_error \
6+ cme_error \
7+ cms_error \
8+ generic_error \
9+
10+#define at_error \
11+ aterror(AT, NOERROR, 0) \
12+ aterror(AT, ERROR_GENERIC, 1) \
13+ aterror(AT, ERROR_COMMAND_PENDING, 2) \
14+ aterror(AT, ERROR_CHANNEL_CLOSED, 3) \
15+ aterror(AT, ERROR_TIMEOUT, 4) \
16+ aterror(AT, ERROR_INVALID_THREAD, 5) \
17+ aterror(AT, ERROR_INVALID_RESPONSE, 6) \
18+ aterror(AT, ERROR_MEMORY_ALLOCATION, 7) \
19+ aterror(AT, ERROR_STRING_CREATION, 8) \
20+
21+#define cme_error \
22+ aterror(CME, MODULE_FAILURE, 0) \
23+ aterror(CME, NO_MODULE_CONNECTION, 1) \
24+ aterror(CME, PHONE_ADAPTER_RESERVED, 2) \
25+ aterror(CME, OPERATION_NOT_ALLOWED, 3) \
26+ aterror(CME, OPERATION_NOT_SUPPORTED, 4) \
27+ aterror(CME, PH_SIM_PIN, 5) \
28+ aterror(CME, PH_FSIM_PIN, 6) \
29+ aterror(CME, PH_FSIM_PUK, 7) \
30+ aterror(CME, SIM_NOT_INSERTED, 10) \
31+ aterror(CME, SIM_PIN_REQUIRED, 11) \
32+ aterror(CME, SIM_PUK_REQUIRED, 12) \
33+ aterror(CME, FAILURE, 13) \
34+ aterror(CME, SIM_BUSY, 14) \
35+ aterror(CME, SIM_WRONG, 15) \
36+ aterror(CME, INCORRECT_PASSWORD, 16) \
37+ aterror(CME, SIM_PIN2_REQUIRED, 17) \
38+ aterror(CME, SIM_PUK2_REQUIRED, 18) \
39+ aterror(CME, MEMORY_FULL, 20) \
40+ aterror(CME, INVALID_INDEX, 21) \
41+ aterror(CME, NOT_FOUND, 22) \
42+ aterror(CME, MEMORY_FAILURE, 23) \
43+ aterror(CME, STRING_TO_LONG, 24) \
44+ aterror(CME, INVALID_CHAR, 25) \
45+ aterror(CME, DIALSTR_TO_LONG, 26) \
46+ aterror(CME, INVALID_DIALCHAR, 27) \
47+ aterror(CME, NO_NETWORK_SERVICE, 30) \
48+ aterror(CME, NETWORK_TIMEOUT, 31) \
49+ aterror(CME, NETWORK_NOT_ALLOWED, 32) \
50+ aterror(CME, NETWORK_PERSONALIZATION_PIN_REQUIRED, 40) \
51+ aterror(CME, NETWORK_PERSONALIZATION_PUK_REQUIRED, 41) \
52+ aterror(CME, NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED, 42) \
53+ aterror(CME, NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED, 43) \
54+ aterror(CME, SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED, 44) \
55+ aterror(CME, SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED, 45) \
56+ aterror(CME, CORPORATE_PERSONALIZATION_PIN_REQUIRED, 46) \
57+ aterror(CME, CORPORATE_PERSONALIZATION_PUK_REQUIRED, 47) \
58+ aterror(CME, HIDDEN_KEY, 48) \
59+ aterror(CME, EAP_NOT_SUPORTED, 49) \
60+ aterror(CME, INCORRECT_PARAMETERS, 50) \
61+ aterror(CME, UNKNOWN, 100) \
62+ aterror(CME, ILLEGAL_MS, 103) \
63+ aterror(CME, ILLEGAL_ME, 106) \
64+ aterror(CME, PLMN_NOT_ALLOWED, 111) \
65+ aterror(CME, LOCATION_AREA_NOT_ALLOWED, 112) \
66+ aterror(CME, ROAMING_AREA_NOT_ALLOWED, 113) \
67+ aterror(CME, SERVICE_NOT_SUPPORTED, 132) \
68+ aterror(CME, SERVICE_NOT_SUBSCRIBED, 133) \
69+ aterror(CME, SERVICE_TEMPORARILY_OUT, 134) \
70+ aterror(CME, UNSPECIFIED_GPRS_ERROR, 148) \
71+ aterror(CME, PDP_AUTH_FAILURE, 149) \
72+ aterror(CME, INVALID_MOBILE_CLASS, 150) \
73+ aterror(CME, PH_SIMLOCK_PIN_REQUIRED, 200) \
74+ aterror(CME, SYNTAX_ERROR, 257) \
75+ aterror(CME, INVALID_PARAMETER, 258) \
76+ aterror(CME, LENGTH_ERROR, 259) \
77+ aterror(CME, SIM_AUTH_FAILURE, 260) \
78+ aterror(CME, SIM_FILE_ERROR, 261) \
79+ aterror(CME, FILE_SYSTEM_ERROR, 262) \
80+ aterror(CME, SERVICE_UNAVIABLE, 263) \
81+ aterror(CME, PHONEBOOK_NOT_READY, 264) \
82+ aterror(CME, PHONEBOOK_NOT_SUPPORTED, 265) \
83+ aterror(CME, COMMAND_TO_LONG, 266) \
84+ aterror(CME, PARAMETER_OUT_OF_RANGE, 267) \
85+ aterror(CME, BAND_NOT_ALLOWED, 268) \
86+ aterror(CME, SUPPLEMENTARY_SERIVEC_FAILURE, 269) \
87+ aterror(CME, COMMAND_ABORTED, 270) \
88+ aterror(CME, ACTION_ALREADY_IN_PROGRESS, 271) \
89+ aterror(CME, WAN_DISABLED, 272) \
90+ aterror(CME, GPS_DISABLE_DUE_TO_TEMP, 273) \
91+ aterror(CME, RADIO_NOT_ACTIVATED, 274) \
92+ aterror(CME, USB_NOT_CONFIGURED, 275) \
93+ aterror(CME, NOT_CONNECTED, 276) \
94+ aterror(CME, NOT_DISCONNECTED, 277) \
95+ aterror(CME, TOO_MANY_CONNECTIONS, 278) \
96+ aterror(CME, TOO_MANY_USERS, 279) \
97+ aterror(CME, FDN_RESTRICITONS, 280) \
98+
99+#define cms_error \
100+ aterror(CMS, UNASSIGNED_NUMBER, 1) \
101+ aterror(CMS, BARRING, 8) \
102+ aterror(CMS, CALL_BARRED, 10) \
103+ aterror(CMS, SHORT_MESSAGE_REJECTED, 21) \
104+ aterror(CMS, DESTINATION_OUT_OF_SERVICE, 27) \
105+ aterror(CMS, UNIDENTIFIED_SUBSCRIBER, 28) \
106+ aterror(CMS, FACILITY_REJECTED, 29) \
107+ aterror(CMS, UNKNOWN_SUBSCRIBER, 30) \
108+ aterror(CMS, NETWORK_OUT_OF_ORDER, 38) \
109+ aterror(CMS, TEMP_FAILURE, 41) \
110+ aterror(CMS, SMS_CONGESTION, 42) \
111+ aterror(CMS, RESOURCE_UNAVAIBLE, 47) \
112+ aterror(CMS, REQUESTED_FACILITY_NOT_SUBSCRIBED, 50) \
113+ aterror(CMS, REQUESTED_FACILITY_NOT_IMPLEMENTED, 69) \
114+ aterror(CMS, INVALID_SMS_REF, 81) \
115+ aterror(CMS, INVALID_MESSAGE, 95) \
116+ aterror(CMS, INVALID_MANDATORY_INFORMATION, 96) \
117+ aterror(CMS, MESSAGE_TYPE_NOT_IMPLEMENTED, 97) \
118+ aterror(CMS, MESSAGE_NOT_COMPATIBLE, 98) \
119+ aterror(CMS, INFORMATION_ELEMENT_NOT_IMPLEMENTED, 99) \
120+ aterror(CMS, PROTOCOL_ERROR, 111) \
121+ aterror(CMS, INTERWORKING_UNSPECIFIED, 127) \
122+ aterror(CMS, TELEMATIC_INTERWORKING_NOT_SUPPORTED, 128) \
123+ aterror(CMS, SHORT_MESSAGE_TYPE_0_NOT_SUPPORTED, 129) \
124+ aterror(CMS, CANNOT_REPLACE_SHORT_MESSAGE, 130) \
125+ aterror(CMS, UNSPECIFIED_TP_PID_ERROR, 143) \
126+ aterror(CMS, DATA_SCHEME_NOT_SUPPORTED, 144) \
127+ aterror(CMS, MESSAGE_CLASS_NOT_SUPPORTED, 145) \
128+ aterror(CMS, UNSPECIFIED_TP_DCS_ERROR, 159) \
129+ aterror(CMS, COMMAND_CANT_BE_ACTIONED, 160) \
130+ aterror(CMS, COMMAND_UNSUPPORTED, 161) \
131+ aterror(CMS, UNSPECIFIED_TP_COMMAND, 175) \
132+ aterror(CMS, TPDU_NOT_SUPPORTED, 176) \
133+ aterror(CMS, SC_BUSY, 192) \
134+ aterror(CMS, NO_SC_SUBSCRIPTINO, 193) \
135+ aterror(CMS, SC_FAILURE, 194) \
136+ aterror(CMS, INVALID_SME_ADDRESS, 195) \
137+ aterror(CMS, SME_BARRIED, 196) \
138+ aterror(CMS, SM_DUPLICATE_REJECTED, 197) \
139+ aterror(CMS, TP_VPF_NOT_SUPPORTED, 198) \
140+ aterror(CMS, TP_VP_NOT_SUPPORTED, 199) \
141+ aterror(CMS, SIM_SMS_FULL, 208) \
142+ aterror(CMS, NO_SMS_STORAGE_CAPABILITY, 209) \
143+ aterror(CMS, ERROR_IN_MS, 210) \
144+ aterror(CMS, MEMORY_CAPACITY_EXCEEDED, 211) \
145+ aterror(CMS, STK_BUSY, 212) \
146+ aterror(CMS, UNSPECIFIED_ERROR, 255) \
147+ aterror(CMS, ME_FAILURE, 300) \
148+ aterror(CMS, SMS_OF_ME_RESERVED, 301) \
149+ aterror(CMS, SERVICE_OPERATION_NOT_ALLOWED, 302) \
150+ aterror(CMS, SERVICE_OPERATION_NOT_SUPPORTED, 303) \
151+ aterror(CMS, INVALID_PDU_PARAMETER, 304) \
152+ aterror(CMS, INVALID_TEXT_PARAMETER, 305) \
153+ aterror(CMS, SERVICE_SIM_NOT_INSERTED, 310) \
154+ aterror(CMS, SERVICE_SIM_PIN_REQUIRED, 311) \
155+ aterror(CMS, PH_SIM_PIN_REQUIRED, 312) \
156+ aterror(CMS, SIM_FAILURE, 313) \
157+ aterror(CMS, SERVICE_SIM_BUSY, 314) \
158+ aterror(CMS, SERVICE_SIM_WRONG, 315) \
159+ aterror(CMS, SIM_PUK_REQUIRED, 316) \
160+ aterror(CMS, SERVICE_SIM_PIN2_REQUIRED, 317) \
161+ aterror(CMS, SERVICE_SIM_PUK2_REQUIRED, 318) \
162+ aterror(CMS, SERVICE_MEMORY_FAILURE, 320) \
163+ aterror(CMS, INVALID_MEMORY_INDEX, 321) \
164+ aterror(CMS, SERVICE_MEMORY_FULL, 322) \
165+ aterror(CMS, SMSC_ADDR_UNKNOWN, 330) \
166+ aterror(CMS, NO_NETWORK_SERVICE, 331) \
167+ aterror(CMS, NETWORK_TIMEOUT, 332) \
168+ aterror(CMS, NO_CNMA, 340) \
169+ aterror(CMS, UNKNOWN_ERROR, 500) \
170+
171+#define generic_error \
172+ aterror(GENERIC, ERROR_RESPONSE, 1) \
173+ aterror(GENERIC, NO_CARRIER_RESPONSE, 2) \
174+ aterror(GENERIC, NO_ANSWER_RESPONSE, 3) \
175+ aterror(GENERIC, NO_DIALTONE_RESPONSE, 4) \
176+ aterror(GENERIC, ERROR_UNSPECIFIED, 5) \
177+
178+#define aterror(group, name, num) group(name, num)
179+
180+typedef enum {
181+ CME_ERROR_NON_CME = -1,
182+#define CME(name, num) CME_ ## name = num,
183+ cme_error
184+#undef CME
185+} AT_CME_Error;
186+
187+typedef enum {
188+ CMS_ERROR_NON_CMS = -1,
189+#define CMS(name, num) CMS_ ## name = num,
190+ cms_error
191+#undef CMS
192+} AT_CMS_Error;
193+
194+typedef enum {
195+ GENERIC_ERROR_NON_GENERIC = -1,
196+#define GENERIC(name, num) GENERIC_ ## name = num,
197+ generic_error
198+#undef GENERIC
199+} AT_Generic_Error;
200+
201+typedef enum {
202+ AT_ERROR_NON_AT = -1,
203+ /* AT ERRORS are enumerated by MBM_Error below */
204+} AT_Error;
205+
206+#define AT_ERROR_BASE 0 /* see also _TOP */
207+#define CME_ERROR_BASE 1000 /* see also _TOP */
208+#define CMS_ERROR_BASE 2000 /* see also _TOP */
209+#define GENERIC_ERROR_BASE 3000 /* see also _TOP */
210+
211+#define AT_ERROR_TOP (CME_ERROR_BASE - 1) /* see also _BASE */
212+#define CME_ERROR_TOP (CMS_ERROR_BASE - 1) /* see also _BASE */
213+#define CMS_ERROR_TOP (GENERIC_ERROR_BASE - 1) /* see also _BASE */
214+#define GENERIC_ERROR_TOP (GENERIC_ERROR_BASE + 999) /* see also _BASE */
215+
216+typedef enum {
217+#define AT(name, num) AT_ ## name = num + AT_ERROR_BASE,
218+#define CME(name, num) AT_CME_ ## name = num + CME_ERROR_BASE,
219+#define CMS(name, num) AT_CMS_ ## name = num + CMS_ERROR_BASE,
220+#define GENERIC(name, num) AT_GENERIC_ ## name = num + GENERIC_ERROR_BASE,
221+ mbm_error
222+#undef CME
223+#undef CMS
224+#undef GENERIC
225+#undef AT
226+} MBM_Error;
227+
228+typedef enum {
229+ NONE_ERROR,
230+ AT_ERROR,
231+ CME_ERROR,
232+ CMS_ERROR,
233+ GENERIC_ERROR,
234+ UNKNOWN_ERROR,
235+} AT_Error_type;
236+#endif
--- /dev/null
+++ b/huaweigeneric-ril/at_tok.c
@@ -0,0 +1,252 @@
1+/* //device/system/reference-ril/at_tok.c
2+**
3+** Copyright 2006, The Android Open Source Project
4+**
5+** Licensed under the Apache License, Version 2.0 (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** http://www.apache.org/licenses/LICENSE-2.0
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+*/
17+
18+#include "at_tok.h"
19+#include <string.h>
20+#include <ctype.h>
21+#include <stdlib.h>
22+
23+/**
24+ * Starts tokenizing an AT response string.
25+ * Returns -1 if this is not a valid response string, 0 on success.
26+ * Updates *p_cur with current position.
27+ */
28+int at_tok_start(char **p_cur)
29+{
30+ if (*p_cur == NULL)
31+ return -1;
32+
33+ /* Skip prefix,
34+ consume "^[^:]:". */
35+
36+ *p_cur = strchr(*p_cur, ':');
37+
38+ if (*p_cur == NULL)
39+ return -1;
40+
41+ (*p_cur)++;
42+
43+ return 0;
44+}
45+
46+static void skipWhiteSpace(char **p_cur)
47+{
48+ if (*p_cur == NULL)
49+ return;
50+
51+ while (**p_cur != '\0' && isspace(**p_cur))
52+ (*p_cur)++;
53+ }
54+
55+static void skipNextComma(char **p_cur)
56+{
57+ if (*p_cur == NULL)
58+ return;
59+
60+ while (**p_cur != '\0' && **p_cur != ',')
61+ (*p_cur)++;
62+
63+ if (**p_cur == ',')
64+ (*p_cur)++;
65+ }
66+
67+/**
68+ * If the first none space character is a quotation mark, returns the string
69+ * between two quotation marks, else returns the content before the first comma.
70+ * Updates *p_cur.
71+ */
72+static char * nextTok(char **p_cur)
73+{
74+ char *ret = NULL;
75+
76+ skipWhiteSpace(p_cur);
77+
78+ if (*p_cur == NULL) {
79+ ret = NULL;
80+ } else if (**p_cur == '"') {
81+ enum State {END, NORMAL, ESCAPE} state = NORMAL;
82+
83+ (*p_cur)++;
84+ ret = *p_cur;
85+
86+ while (state != END) {
87+ switch (state) {
88+ case NORMAL:
89+ switch (**p_cur) {
90+ case '\\':
91+ state = ESCAPE;
92+ break;
93+ case '"':
94+ state = END;
95+ break;
96+ case '\0':
97+ /*
98+ * Error case, parsing string is not quoted by ending
99+ * double quote, e.g. "bla bla, this function expects input
100+ * string to be NULL terminated, so that the loop can exit.
101+ */
102+ ret = NULL;
103+ goto exit;
104+ default:
105+ /* Stays in normal case. */
106+ break;
107+ }
108+ break;
109+
110+ case ESCAPE:
111+ state = NORMAL;
112+ break;
113+
114+ default:
115+ /* This should never happen. */
116+ break;
117+ }
118+
119+ if (state == END) {
120+ **p_cur = '\0';
121+ }
122+
123+ (*p_cur)++;
124+ }
125+ skipNextComma(p_cur);
126+ } else {
127+ ret = strsep(p_cur, ",");
128+ }
129+exit:
130+ return ret;
131+}
132+
133+/**
134+ * Parses the next integer in the AT response line and places it in *p_out.
135+ * Returns 0 on success and -1 on fail.
136+ * Updates *p_cur.
137+ * "base" is the same as the base param in strtol.
138+ */
139+static int at_tok_nextint_base(char **p_cur, int *p_out, int base, int uns)
140+{
141+ char *ret;
142+
143+ if (*p_cur == NULL)
144+ return -1;
145+
146+ if (p_out == NULL)
147+ return -1;
148+
149+ ret = nextTok(p_cur);
150+
151+ if (ret == NULL)
152+ return -1;
153+ else {
154+ long l;
155+ char *end;
156+
157+ if (uns)
158+ l = strtoul(ret, &end, base);
159+ else
160+ l = strtol(ret, &end, base);
161+
162+ *p_out = (int)l;
163+
164+ if (end == ret)
165+ return -1;
166+ }
167+
168+ return 0;
169+}
170+
171+/**
172+ * Parses the next base 10 integer in the AT response line
173+ * and places it in *p_out.
174+ * Returns 0 on success and -1 on fail.
175+ * Updates *p_cur.
176+ */
177+int at_tok_nextint(char **p_cur, int *p_out)
178+{
179+ return at_tok_nextint_base(p_cur, p_out, 10, 0);
180+}
181+
182+/**
183+ * Parses the next base 16 integer in the AT response line
184+ * and places it in *p_out.
185+ * Returns 0 on success and -1 on fail.
186+ * Updates *p_cur.
187+ */
188+int at_tok_nexthexint(char **p_cur, int *p_out)
189+{
190+ return at_tok_nextint_base(p_cur, p_out, 16, 1);
191+}
192+
193+int at_tok_nextbool(char **p_cur, char *p_out)
194+{
195+ int ret;
196+ int result;
197+
198+ ret = at_tok_nextint(p_cur, &result);
199+
200+ if (ret < 0)
201+ return -1;
202+
203+ /* Booleans should be 0 or 1. */
204+ if (!(result == 0 || result == 1))
205+ return -1;
206+
207+ if (p_out != NULL)
208+ *p_out = (char)result;
209+ else
210+ return -1;
211+
212+ return ret;
213+}
214+
215+int at_tok_nextstr(char **p_cur, char **p_out)
216+{
217+ if (*p_cur == NULL)
218+ return -1;
219+
220+ *p_out = nextTok(p_cur);
221+ if (*p_out == NULL)
222+ return -1;
223+
224+ return 0;
225+}
226+
227+/** Returns 1 on "has more tokens" and 0 if not. */
228+int at_tok_hasmore(char **p_cur)
229+{
230+ return ! (*p_cur == NULL || **p_cur == '\0');
231+}
232+
233+/** *p_out returns count of given character (needle) in given string (p_in). */
234+int at_tok_charcounter(char *p_in, char needle, int *p_out)
235+{
236+ char *p_cur = p_in;
237+ int num_found = 0;
238+
239+ if (p_in == NULL)
240+ return -1;
241+
242+ while (*p_cur != '\0') {
243+ if (*p_cur == needle) {
244+ num_found++;
245+ }
246+
247+ p_cur++;
248+ }
249+
250+ *p_out = num_found;
251+ return 0;
252+}
--- /dev/null
+++ b/huaweigeneric-ril/at_tok.h
@@ -0,0 +1,31 @@
1+/* //device/system/reference-ril/at_tok.h
2+**
3+** Copyright 2006, The Android Open Source Project
4+**
5+** Licensed under the Apache License, Version 2.0 (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** http://www.apache.org/licenses/LICENSE-2.0
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+*/
17+
18+#ifndef AT_TOK_H
19+#define AT_TOK_H 1
20+
21+int at_tok_start(char **p_cur);
22+int at_tok_nextint(char **p_cur, int *p_out);
23+int at_tok_nexthexint(char **p_cur, int *p_out);
24+
25+int at_tok_nextbool(char **p_cur, char *p_out);
26+int at_tok_nextstr(char **p_cur, char **out);
27+
28+int at_tok_hasmore(char **p_cur);
29+
30+int at_tok_charcounter(char *p_in, char needle, int *p_out);
31+#endif
--- /dev/null
+++ b/huaweigeneric-ril/atchannel.c
@@ -0,0 +1,1377 @@
1+/* //device/system/reference-ril/atchannel.c
2+**
3+** Copyright 2006, The Android Open Source Project
4+**
5+** Licensed under the Apache License, Version 2.0 (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** http://www.apache.org/licenses/LICENSE-2.0
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+*/
17+
18+#include "atchannel.h"
19+#include "at_tok.h"
20+
21+#include <stdio.h>
22+#include <string.h>
23+#include <pthread.h>
24+#include <ctype.h>
25+#include <stdlib.h>
26+#include <errno.h>
27+#include <fcntl.h>
28+#include <sys/time.h>
29+#include <time.h>
30+#include <unistd.h>
31+#include <stdarg.h>
32+
33+#include <poll.h>
34+
35+#define LOG_NDEBUG 0
36+#define LOG_TAG "AT"
37+#include <utils/Log.h>
38+
39+#ifdef HAVE_ANDROID_OS
40+/* For IOCTL's */
41+#include <linux/omap_csmi.h>
42+#endif /*HAVE_ANDROID_OS*/
43+
44+#include "misc.h"
45+
46+#define MAX_AT_RESPONSE (8 * 1024)
47+#define HANDSHAKE_RETRY_COUNT 8
48+#define HANDSHAKE_TIMEOUT_MSEC 250
49+#define DEFAULT_AT_TIMEOUT_MSEC (3 * 60 * 1000)
50+#define BUFFSIZE 512
51+
52+struct atcontext {
53+ pthread_t tid_reader;
54+ int fd; /* fd of the AT channel. */
55+ int readerCmdFds[2];
56+ int isInitialized;
57+ ATUnsolHandler unsolHandler;
58+
59+ /* For input buffering. */
60+ char ATBuffer[MAX_AT_RESPONSE+1];
61+ char *ATBufferCur;
62+
63+ int readCount;
64+
65+ /*
66+ * For current pending command, these are protected by commandmutex.
67+ *
68+ * The mutex and cond struct is memset in the getAtChannel() function,
69+ * so no initializer should be needed.
70+ */
71+ pthread_mutex_t requestmutex;
72+ pthread_mutex_t commandmutex;
73+ pthread_cond_t requestcond;
74+ pthread_cond_t commandcond;
75+
76+ ATCommandType type;
77+ const char *responsePrefix;
78+ const char *smsPDU;
79+ ATResponse *response;
80+
81+ void (*onTimeout)(void);
82+ void (*onReaderClosed)(void);
83+ int readerClosed;
84+
85+ int timeoutMsec;
86+};
87+
88+static struct atcontext *s_defaultAtContext = NULL;
89+static va_list empty = {0};
90+
91+static pthread_key_t key;
92+static pthread_once_t key_once = PTHREAD_ONCE_INIT;
93+
94+static int writeCtrlZ (const char *s);
95+static int writeline (const char *s);
96+static void onReaderClosed(void);
97+
98+static void make_key(void)
99+{
100+ (void) pthread_key_create(&key, NULL);
101+}
102+
103+/**
104+ * Set the atcontext pointer. Useful for sub-threads that needs to hold
105+ * the same state information.
106+ *
107+ * The caller IS responsible for freeing any memory already allocated
108+ * for any previous atcontexts.
109+ */
110+static void setAtContext(struct atcontext *ac)
111+{
112+ (void) pthread_once(&key_once, make_key);
113+ (void) pthread_setspecific(key, ac);
114+}
115+
116+static void ac_free(void)
117+{
118+ struct atcontext *ac = NULL;
119+ (void) pthread_once(&key_once, make_key);
120+ if ((ac = (struct atcontext *) pthread_getspecific(key)) != NULL) {
121+ free(ac);
122+ LOGD("%s() freed current thread AT context", __func__);
123+ } else {
124+ LOGW("%s() No AT context exist for current thread, cannot free it",
125+ __func__);
126+ }
127+}
128+
129+static int initializeAtContext(void)
130+{
131+ struct atcontext *ac = NULL;
132+
133+ if (pthread_once(&key_once, make_key)) {
134+ LOGE("%s() Pthread_once failed!", __func__);
135+ goto error;
136+ }
137+
138+ ac = (struct atcontext *)pthread_getspecific(key);
139+
140+ if (ac == NULL) {
141+ ac = (struct atcontext *) malloc(sizeof(struct atcontext));
142+ if (ac == NULL) {
143+ LOGE("%s() Failed to allocate memory", __func__);
144+ goto error;
145+ }
146+
147+ memset(ac, 0, sizeof(struct atcontext));
148+
149+ ac->fd = -1;
150+ ac->readerCmdFds[0] = -1;
151+ ac->readerCmdFds[1] = -1;
152+ ac->ATBufferCur = ac->ATBuffer;
153+
154+ if (pipe(ac->readerCmdFds)) {
155+ LOGE("%s() Failed to create pipe: %s", __func__, strerror(errno));
156+ goto error;
157+ }
158+
159+ pthread_mutex_init(&ac->commandmutex, NULL);
160+ pthread_mutex_init(&ac->requestmutex, NULL);
161+ pthread_cond_init(&ac->requestcond, NULL);
162+ pthread_cond_init(&ac->commandcond, NULL);
163+
164+ ac->timeoutMsec = DEFAULT_AT_TIMEOUT_MSEC;
165+
166+ if (pthread_setspecific(key, ac)) {
167+ LOGE("%s() Calling pthread_setspecific failed!", __func__);
168+ goto error;
169+ }
170+ }
171+
172+ LOGI("Initialized new AT Context!");
173+
174+ return 0;
175+
176+error:
177+ LOGE("%s() Failed initializing new AT Context!", __func__);
178+ free(ac);
179+ return -1;
180+}
181+
182+static struct atcontext *getAtContext(void)
183+{
184+ struct atcontext *ac = NULL;
185+
186+ (void) pthread_once(&key_once, make_key);
187+
188+ if ((ac = (struct atcontext *) pthread_getspecific(key)) == NULL) {
189+ if (s_defaultAtContext) {
190+ LOGW("WARNING! external thread use default AT Context");
191+ ac = s_defaultAtContext;
192+ } else {
193+ LOGE("WARNING! %s() called from external thread with "
194+ "no defaultAtContext set!! This IS a bug! "
195+ "A crash is probably nearby!", __func__);
196+ }
197+ }
198+
199+ return ac;
200+}
201+
202+/**
203+ * This function will make the current at thread the default channel,
204+ * meaning that calls from a thread that is not a queuerunner will
205+ * be executed in this context.
206+ */
207+void at_make_default_channel(void)
208+{
209+ struct atcontext *ac = getAtContext();
210+
211+ if (ac->isInitialized)
212+ s_defaultAtContext = ac;
213+}
214+
215+#if AT_DEBUG
216+void AT_DUMP(const char* prefix, const char* buff, int len)
217+{
218+ if (len < 0)
219+ len = strlen(buff);
220+ LOGD("%.*s", len, buff);
221+}
222+#endif
223+
224+#ifndef HAVE_ANDROID_OS
225+int pthread_cond_timeout_np(pthread_cond_t *cond,
226+ pthread_mutex_t * mutex,
227+ unsigned msecs)
228+{
229+ struct timespec ts;
230+ clock_gettime(CLOCK_REALTIME, &ts);
231+
232+ ts.tv_sec += msecs / 1000;
233+ ts.tv_nsec += (msecs % 1000) * 1000000;
234+ return pthread_cond_timedwait(cond, mutex, &ts);
235+}
236+#endif /*HAVE_ANDROID_OS*/
237+
238+static void sleepMsec(long long msec)
239+{
240+ struct timespec ts;
241+ int err;
242+
243+ ts.tv_sec = (msec / 1000);
244+ ts.tv_nsec = (msec % 1000) * 1000 * 1000;
245+
246+ do {
247+ err = nanosleep (&ts, &ts);
248+ } while (err < 0 && errno == EINTR);
249+}
250+
251+
252+
253+/** Add an intermediate response to sp_response. */
254+static void addIntermediate(const char *line)
255+{
256+ ATLine *p_new;
257+ struct atcontext *ac = getAtContext();
258+
259+ p_new = (ATLine *) malloc(sizeof(ATLine));
260+
261+ p_new->line = strdup(line);
262+
263+ /* Note: This adds to the head of the list, so the list will
264+ be in reverse order of lines received. the order is flipped
265+ again before passing on to the command issuer. */
266+ p_new->p_next = ac->response->p_intermediates;
267+ ac->response->p_intermediates = p_new;
268+}
269+
270+
271+/**
272+ * Returns 1 if line is a final response indicating error.
273+ * See 27.007 annex B.
274+ * WARNING: NO CARRIER and others are sometimes unsolicited.
275+ */
276+static const char * s_finalResponsesError[] = {
277+ "ERROR",
278+ "+CMS ERROR:",
279+ "+CME ERROR:",
280+ "NO CARRIER", /* Sometimes! */
281+ "NO ANSWER",
282+ "NO DIALTONE",
283+};
284+
285+static int isFinalResponseError(const char *line)
286+{
287+ size_t i;
288+
289+ for (i = 0 ; i < NUM_ELEMS(s_finalResponsesError) ; i++) {
290+ if (strStartsWith(line, s_finalResponsesError[i])) {
291+ return 1;
292+ }
293+ }
294+
295+ return 0;
296+}
297+
298+/**
299+ * Returns 1 if line is a final response indicating success.
300+ * See 27.007 annex B.
301+ * WARNING: NO CARRIER and others are sometimes unsolicited.
302+ */
303+static const char * s_finalResponsesSuccess[] = {
304+ "OK",
305+ "CONNECT" /* Some stacks start up data on another channel. */
306+};
307+static int isFinalResponseSuccess(const char *line)
308+{
309+ size_t i;
310+
311+ for (i = 0 ; i < NUM_ELEMS(s_finalResponsesSuccess) ; i++) {
312+ if (strStartsWith(line, s_finalResponsesSuccess[i])) {
313+ return 1;
314+ }
315+ }
316+
317+ return 0;
318+}
319+
320+/**
321+ * Returns 1 if line is the first line in (what will be) a two-line
322+ * SMS unsolicited response.
323+ */
324+static const char * s_smsUnsoliciteds[] = {
325+ "+CMT:",
326+ "+CDS:",
327+ "+CBM:"
328+};
329+static int isSMSUnsolicited(const char *line)
330+{
331+ size_t i;
332+
333+ for (i = 0 ; i < NUM_ELEMS(s_smsUnsoliciteds) ; i++) {
334+ if (strStartsWith(line, s_smsUnsoliciteds[i])) {
335+ return 1;
336+ }
337+ }
338+
339+ return 0;
340+}
341+
342+
343+/** Assumes s_commandmutex is held. */
344+static void handleFinalResponse(const char *line)
345+{
346+ struct atcontext *ac = getAtContext();
347+
348+ ac->response->finalResponse = strdup(line);
349+
350+ pthread_cond_signal(&ac->commandcond);
351+}
352+
353+static void handleUnsolicited(const char *line)
354+{
355+ struct atcontext *ac = getAtContext();
356+
357+ if (ac->unsolHandler != NULL) {
358+ ac->unsolHandler(line, NULL);
359+ }
360+}
361+
362+static void processLine(const char *line)
363+{
364+ struct atcontext *ac = getAtContext();
365+ pthread_mutex_lock(&ac->commandmutex);
366+
367+ if (ac->response == NULL) {
368+ /* No command pending. */
369+ handleUnsolicited(line);
370+ } else if (isFinalResponseSuccess(line)) {
371+ ac->response->success = 1;
372+ handleFinalResponse(line);
373+ } else if (isFinalResponseError(line)) {
374+ ac->response->success = 0;
375+ handleFinalResponse(line);
376+ } else if (ac->smsPDU != NULL && 0 == strcmp(line, "> ")) {
377+ /* See eg. TS 27.005 4.3.
378+ Commands like AT+CMGS have a "> " prompt. */
379+ writeCtrlZ(ac->smsPDU);
380+ ac->smsPDU = NULL;
381+ } else switch (ac->type) {
382+ case NO_RESULT:
383+ handleUnsolicited(line);
384+ break;
385+ case NUMERIC:
386+ if (ac->response->p_intermediates == NULL
387+ && isdigit(line[0])) {
388+ addIntermediate(line);
389+ } else {
390+ /* Either we already have an intermediate response or
391+ the line doesn't begin with a digit. */
392+ handleUnsolicited(line);
393+ }
394+ break;
395+ case SINGLELINE:
396+ if (ac->response->p_intermediates == NULL
397+ && strStartsWith (line, ac->responsePrefix)) {
398+ addIntermediate(line);
399+ } else {
400+ /* We already have an intermediate response. */
401+ handleUnsolicited(line);
402+ }
403+ break;
404+ case MULTILINE:
405+ if (strStartsWith (line, ac->responsePrefix)) {
406+ addIntermediate(line);
407+ } else {
408+ handleUnsolicited(line);
409+ }
410+ break;
411+
412+ default: /* This should never be reached */
413+ LOGE("%s() Unsupported AT command type %d", __func__, ac->type);
414+ handleUnsolicited(line);
415+ break;
416+ }
417+
418+ pthread_mutex_unlock(&ac->commandmutex);
419+}
420+
421+
422+/**
423+ * Returns a pointer to the end of the next line,
424+ * special-cases the "> " SMS prompt.
425+ *
426+ * returns NULL if there is no complete line.
427+ */
428+static char * findNextEOL(char *cur)
429+{
430+ if (cur[0] == '>' && cur[1] == ' ' && cur[2] == '\0') {
431+ /* SMS prompt character...not \r terminated */
432+ return cur+2;
433+ }
434+
435+ /* Find next newline */
436+ while (*cur != '\0' && *cur != '\r' && *cur != '\n') cur++;
437+
438+ return *cur == '\0' ? NULL : cur;
439+}
440+
441+
442+/**
443+ * Reads a line from the AT channel, returns NULL on timeout.
444+ * Assumes it has exclusive read access to the FD.
445+ *
446+ * This line is valid only until the next call to readline.
447+ *
448+ * This function exists because as of writing, android libc does not
449+ * have buffered stdio.
450+ */
451+
452+static const char *readline(void)
453+{
454+ ssize_t count;
455+
456+ char *p_read = NULL;
457+ char *p_eol = NULL;
458+ char *ret = NULL;
459+
460+ struct atcontext *ac = getAtContext();
461+ read(ac->fd,NULL,0);
462+
463+ /* This is a little odd. I use *s_ATBufferCur == 0 to mean
464+ * "buffer consumed completely". If it points to a character,
465+ * then the buffer continues until a \0.
466+ */
467+ if (*ac->ATBufferCur == '\0') {
468+ /* Empty buffer. */
469+ ac->ATBufferCur = ac->ATBuffer;
470+ *ac->ATBufferCur = '\0';
471+ p_read = ac->ATBuffer;
472+ } else { /* *s_ATBufferCur != '\0' */
473+ /* There's data in the buffer from the last read. */
474+
475+ /* skip over leading newlines */
476+ while (*ac->ATBufferCur == '\r' || *ac->ATBufferCur == '\n')
477+ ac->ATBufferCur++;
478+
479+ p_eol = findNextEOL(ac->ATBufferCur);
480+
481+ if (p_eol == NULL) {
482+ /* A partial line. Move it up and prepare to read more. */
483+ size_t len;
484+
485+ len = strlen(ac->ATBufferCur);
486+
487+ memmove(ac->ATBuffer, ac->ATBufferCur, len + 1);
488+ p_read = ac->ATBuffer + len;
489+ ac->ATBufferCur = ac->ATBuffer;
490+ }
491+ /* Otherwise, (p_eol !- NULL) there is a complete line
492+ that will be returned from the while () loop below. */
493+ }
494+
495+ while (p_eol == NULL) {
496+ int err;
497+ struct pollfd pfds[2];
498+
499+ /* This condition should be synchronized with the read function call
500+ * size argument below.
501+ */
502+ if (0 >= MAX_AT_RESPONSE - (p_read - ac->ATBuffer) - 2) {
503+ LOGE("%s() ERROR: Input line exceeded buffer", __func__);
504+ /* Ditch buffer and start over again. */
505+ ac->ATBufferCur = ac->ATBuffer;
506+ *ac->ATBufferCur = '\0';
507+ p_read = ac->ATBuffer;
508+ }
509+
510+ /* If our fd is invalid, we are probably closed. Return. */
511+ if (ac->fd < 0)
512+ return NULL;
513+
514+ pfds[0].fd = ac->fd;
515+ pfds[0].events = POLLIN | POLLERR;
516+
517+ pfds[1].fd = ac->readerCmdFds[0];
518+ pfds[1].events = POLLIN;
519+
520+ err = poll(pfds, 2, -1);
521+
522+ if (err < 0) {
523+ LOGE("%s() poll: error: %s", __func__, strerror(errno));
524+ return NULL;
525+ }
526+
527+ if (pfds[1].revents & POLLIN) {
528+ char buf[10];
529+
530+ /* Just drain it. We don't care, this is just for waking up. */
531+ read(pfds[1].fd, &buf, 1);
532+ continue;
533+ }
534+
535+ if (pfds[0].revents & POLLERR) {
536+ LOGE("%s() POLLERR event! Returning...", __func__);
537+ return NULL;
538+ }
539+
540+ if (!(pfds[0].revents & POLLIN))
541+ continue;
542+
543+ do
544+ /* The size argument should be synchronized to the ditch buffer
545+ * condition above.
546+ */
547+ count = read(ac->fd, p_read,
548+ MAX_AT_RESPONSE - (p_read - ac->ATBuffer) - 2);
549+
550+ while (count < 0 && errno == EINTR);
551+
552+ if (count > 0) {
553+ AT_DUMP( "<< ", p_read, count );
554+ ac->readCount += count;
555+
556+ /* Implementation requires extra EOS or EOL to get it right if
557+ * there are no trailing newlines in the read buffer. Adding extra
558+ * EOS does not harm even if there actually were trailing EOLs.
559+ */
560+ p_read[count] = '\0';
561+ p_read[count+1] = '\0';
562+
563+ /* Skip over leading newlines. */
564+ while (*ac->ATBufferCur == '\r' || *ac->ATBufferCur == '\n')
565+ ac->ATBufferCur++;
566+
567+ p_eol = findNextEOL(ac->ATBufferCur);
568+ p_read += count;
569+ } else if (count <= 0) {
570+ /* Read error encountered or EOF reached. */
571+ if (count == 0)
572+ LOGD("%s() atchannel: EOF reached.", __func__);
573+ else
574+ LOGD("%s() atchannel: read error %s", __func__, strerror(errno));
575+
576+ return NULL;
577+ }
578+ }
579+
580+ /* A full line in the buffer. Place a \0 over the \r and return. */
581+
582+ ret = ac->ATBufferCur;
583+ *p_eol = '\0';
584+
585+ /* The extra EOS added after read takes care of the case when there is no
586+ * valid data after p_eol.
587+ */
588+ ac->ATBufferCur = p_eol + 1; /* This will always be <= p_read,
589+ and there will be a \0 at *p_read. */
590+
591+ LOGI("AT(%d)< %s", ac->fd, ret);
592+ return ret;
593+}
594+
595+static void onReaderClosed(void)
596+{
597+ struct atcontext *ac = getAtContext();
598+ if (ac->onReaderClosed != NULL && ac->readerClosed == 0) {
599+
600+ pthread_mutex_lock(&ac->commandmutex);
601+
602+ ac->readerClosed = 1;
603+
604+ pthread_cond_signal(&ac->commandcond);
605+
606+ pthread_mutex_unlock(&ac->commandmutex);
607+
608+ ac->onReaderClosed();
609+ }
610+}
611+
612+static void *readerLoop(void *arg)
613+{
614+ struct atcontext *ac = NULL;
615+
616+ LOGI("Entering readerloop!");
617+
618+ setAtContext((struct atcontext *) arg);
619+ ac = getAtContext();
620+
621+ for (;;) {
622+ const char * line;
623+
624+ line = readline();
625+
626+ if (line == NULL)
627+ break;
628+
629+ if(isSMSUnsolicited(line)) {
630+ char *line1;
631+ const char *line2;
632+
633+ /* The scope of string returned by 'readline()' is valid only
634+ until next call to 'readline()' hence making a copy of line
635+ before calling readline again. */
636+ line1 = strdup(line);
637+ line2 = readline();
638+
639+ if (line2 == NULL) {
640+ free(line1);
641+ break;
642+ }
643+
644+ if (ac->unsolHandler != NULL)
645+ ac->unsolHandler(line1, line2);
646+
647+ free(line1);
648+ } else
649+ processLine(line);
650+ }
651+
652+ onReaderClosed();
653+ LOGI("Exiting readerloop!");
654+ return NULL;
655+}
656+
657+/**
658+ * Sends string s to the radio with a \r appended.
659+ * Returns AT_ERROR_* on error, 0 on success.
660+ *
661+ * This function exists because as of writing, android libc does not
662+ * have buffered stdio.
663+ */
664+static int writeline (const char *s)
665+{
666+ size_t cur = 0;
667+ size_t len = strlen(s);
668+ ssize_t written;
669+
670+ struct atcontext *ac = getAtContext();
671+
672+ if (ac->fd < 0 || ac->readerClosed > 0) {
673+ return AT_ERROR_CHANNEL_CLOSED;
674+ }
675+
676+ LOGD("AT(%d)> %s", ac->fd, s);
677+
678+ AT_DUMP( ">> ", s, strlen(s) );
679+
680+ /* The main string. */
681+ while (cur < len) {
682+ do {
683+ written = write (ac->fd, s + cur, len - cur);
684+ } while (written < 0 && errno == EINTR);
685+
686+ if (written < 0) {
687+ return AT_ERROR_GENERIC;
688+ }
689+
690+ cur += written;
691+ }
692+
693+ /* The \r */
694+
695+ do {
696+ written = write (ac->fd, "\r" , 1);
697+ } while ((written < 0 && errno == EINTR) || (written == 0));
698+
699+ if (written < 0) {
700+ return AT_ERROR_GENERIC;
701+ }
702+
703+ return 0;
704+}
705+
706+static int writeCtrlZ (const char *s)
707+{
708+ size_t cur = 0;
709+ size_t len = strlen(s);
710+ ssize_t written;
711+
712+ struct atcontext *ac = getAtContext();
713+
714+ if (ac->fd < 0 || ac->readerClosed > 0)
715+ return AT_ERROR_CHANNEL_CLOSED;
716+
717+ LOGD("AT> %s^Z\n", s);
718+
719+ AT_DUMP( ">* ", s, strlen(s) );
720+
721+ /* The main string. */
722+ while (cur < len) {
723+ do {
724+ written = write (ac->fd, s + cur, len - cur);
725+ } while (written < 0 && errno == EINTR);
726+
727+ if (written < 0)
728+ return AT_ERROR_GENERIC;
729+
730+ cur += written;
731+ }
732+
733+ /* the ^Z */
734+ do {
735+ written = write (ac->fd, "\032" , 1);
736+ } while ((written < 0 && errno == EINTR) || (written == 0));
737+
738+ if (written < 0)
739+ return AT_ERROR_GENERIC;
740+
741+ return 0;
742+}
743+
744+static void clearPendingCommand(void)
745+{
746+ struct atcontext *ac = getAtContext();
747+
748+ if (ac->response != NULL)
749+ at_response_free(ac->response);
750+
751+ ac->response = NULL;
752+ ac->responsePrefix = NULL;
753+ ac->smsPDU = NULL;
754+ }
755+
756+static AT_Error merror(int type, int error)
757+{
758+ switch(type) {
759+ case AT_ERROR :
760+ return (AT_Error)(AT_ERROR_BASE + error);
761+ case CME_ERROR :
762+ return (AT_Error)(CME_ERROR_BASE + error);
763+ case CMS_ERROR:
764+ return (AT_Error)(CMS_ERROR_BASE + error);
765+ case GENERIC_ERROR:
766+ return (AT_Error)(GENERIC_ERROR_BASE + error);
767+ default:
768+ return (AT_Error)(GENERIC_ERROR_UNSPECIFIED);
769+ }
770+}
771+
772+static AT_Error at_get_error(const ATResponse *p_response)
773+{
774+ int ret;
775+ int err;
776+ char *p_cur;
777+
778+ if (p_response == NULL)
779+ return merror(GENERIC_ERROR, GENERIC_ERROR_UNSPECIFIED);
780+
781+ if (p_response->success > 0)
782+ return AT_NOERROR;
783+
784+ if (p_response->finalResponse == NULL)
785+ return AT_ERROR_INVALID_RESPONSE;
786+
787+ if (isFinalResponseSuccess(p_response->finalResponse))
788+ return AT_NOERROR;
789+
790+ p_cur = p_response->finalResponse;
791+ err = at_tok_start(&p_cur);
792+ if (err < 0)
793+ return merror(GENERIC_ERROR, GENERIC_ERROR_UNSPECIFIED);
794+
795+ err = at_tok_nextint(&p_cur, &ret);
796+ if (err < 0)
797+ return merror(GENERIC_ERROR, GENERIC_ERROR_UNSPECIFIED);
798+
799+ if(strStartsWith(p_response->finalResponse, "+CME ERROR:"))
800+ return merror(CME_ERROR, ret);
801+ else if (strStartsWith(p_response->finalResponse, "+CMS ERROR:"))
802+ return merror(CMS_ERROR, ret);
803+ else if (strStartsWith(p_response->finalResponse, "ERROR:"))
804+ return merror(GENERIC_ERROR, GENERIC_ERROR_RESPONSE);
805+ else if (strStartsWith(p_response->finalResponse, "+NO CARRIER:"))
806+ return merror(GENERIC_ERROR, GENERIC_NO_CARRIER_RESPONSE);
807+ else if (strStartsWith(p_response->finalResponse, "+NO ANSWER:"))
808+ return merror(GENERIC_ERROR, GENERIC_NO_ANSWER_RESPONSE);
809+ else if (strStartsWith(p_response->finalResponse, "+NO DIALTONE:"))
810+ return merror(GENERIC_ERROR, GENERIC_NO_DIALTONE_RESPONSE);
811+ else
812+ return merror(GENERIC_ERROR, GENERIC_ERROR_UNSPECIFIED);
813+}
814+
815+/**
816+ * Starts AT handler on stream "fd'.
817+ * returns 0 on success, -1 on error.
818+ */
819+int at_open(int fd, ATUnsolHandler h)
820+{
821+ int ret;
822+ pthread_attr_t attr;
823+
824+ struct atcontext *ac = NULL;
825+
826+ if (initializeAtContext()) {
827+ LOGE("%s() InitializeAtContext failed!", __func__);
828+ goto error;
829+ }
830+
831+ ac = getAtContext();
832+
833+ ac->fd = fd;
834+ ac->isInitialized = 1;
835+ ac->unsolHandler = h;
836+ ac->readerClosed = 0;
837+
838+ ac->responsePrefix = NULL;
839+ ac->smsPDU = NULL;
840+ ac->response = NULL;
841+
842+ pthread_attr_init (&attr);
843+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
844+
845+ ret = pthread_create(&ac->tid_reader, &attr, readerLoop, ac);
846+
847+ if (ret < 0) {
848+ perror ("pthread_create");
849+ goto error;
850+ }
851+
852+
853+ return 0;
854+error:
855+ ac_free();
856+ return -1;
857+}
858+
859+/* FIXME is it ok to call this from the reader and the command thread? */
860+void at_close(void)
861+{
862+ struct atcontext *ac = getAtContext();
863+
864+ if (ac->fd >= 0) {
865+ if (close(ac->fd) != 0)
866+ LOGE("%s() FAILED to close fd %d!", __func__, ac->fd);
867+ }
868+ ac->fd = -1;
869+
870+ pthread_mutex_lock(&ac->commandmutex);
871+
872+ ac->readerClosed = 1;
873+
874+ pthread_cond_signal(&ac->commandcond);
875+
876+ pthread_mutex_unlock(&ac->commandmutex);
877+
878+ /* Kick readerloop. */
879+ write(ac->readerCmdFds[1], "x", 1);
880+}
881+
882+static ATResponse *at_response_new(void)
883+{
884+ return (ATResponse *) calloc(1, sizeof(ATResponse));
885+}
886+
887+void at_response_free(ATResponse *p_response)
888+{
889+ ATLine *p_line;
890+
891+ if (p_response == NULL) return;
892+
893+ p_line = p_response->p_intermediates;
894+
895+ while (p_line != NULL) {
896+ ATLine *p_toFree;
897+
898+ p_toFree = p_line;
899+ p_line = p_line->p_next;
900+
901+ free(p_toFree->line);
902+ free(p_toFree);
903+ }
904+
905+ free (p_response->finalResponse);
906+ free (p_response);
907+}
908+
909+/**
910+ * The line reader places the intermediate responses in reverse order,
911+ * here we flip them back.
912+ */
913+static void reverseIntermediates(ATResponse *p_response)
914+{
915+ ATLine *pcur,*pnext;
916+
917+ pcur = p_response->p_intermediates;
918+ p_response->p_intermediates = NULL;
919+
920+ while (pcur != NULL) {
921+ pnext = pcur->p_next;
922+ pcur->p_next = p_response->p_intermediates;
923+ p_response->p_intermediates = pcur;
924+ pcur = pnext;
925+ }
926+}
927+
928+/**
929+ * Internal send_command implementation.
930+ * Doesn't lock or call the timeout callback.
931+ *
932+ * timeoutMsec == 0 means infinite timeout.
933+ */
934+static int at_send_command_full_nolock (const char *command, ATCommandType type,
935+ const char *responsePrefix, const char *smspdu,
936+ long long timeoutMsec, ATResponse **pp_outResponse)
937+{
938+ int err = AT_NOERROR;
939+
940+ struct atcontext *ac = getAtContext();
941+
942+ /* Default to NULL, to allow caller to free securely even if
943+ * no response will be set below */
944+ if (pp_outResponse != NULL)
945+ *pp_outResponse = NULL;
946+
947+ /* FIXME This is to prevent future problems due to calls from other threads; should be revised. */
948+ while (pthread_mutex_trylock(&ac->requestmutex) == EBUSY)
949+ pthread_cond_wait(&ac->requestcond, &ac->commandmutex);
950+
951+ if(ac->response != NULL) {
952+ err = AT_ERROR_COMMAND_PENDING;
953+ goto finally;
954+ }
955+
956+ ac->type = type;
957+ ac->responsePrefix = responsePrefix;
958+ ac->smsPDU = smspdu;
959+ ac->response = at_response_new();
960+ if (ac->response == NULL) {
961+ err = AT_ERROR_MEMORY_ALLOCATION;
962+ goto finally;
963+ }
964+
965+ err = writeline (command);
966+
967+ if (err != AT_NOERROR)
968+ goto finally;
969+
970+ while (ac->response->finalResponse == NULL && ac->readerClosed == 0) {
971+ if (timeoutMsec != 0)
972+ err = pthread_cond_timeout_np(&ac->commandcond, &ac->commandmutex, timeoutMsec);
973+ else
974+ err = pthread_cond_wait(&ac->commandcond, &ac->commandmutex);
975+
976+ if (err == ETIMEDOUT) {
977+ err = AT_ERROR_TIMEOUT;
978+ goto finally;
979+ }
980+ }
981+
982+ if (ac->response->success == 0) {
983+ err = at_get_error(ac->response);
984+ }
985+
986+ if (pp_outResponse == NULL)
987+ at_response_free(ac->response);
988+ else {
989+ /* Line reader stores intermediate responses in reverse order. */
990+ reverseIntermediates(ac->response);
991+ *pp_outResponse = ac->response;
992+ }
993+
994+ ac->response = NULL;
995+
996+ if(ac->readerClosed > 0) {
997+ err = AT_ERROR_CHANNEL_CLOSED;
998+ goto finally;
999+ }
1000+
1001+finally:
1002+ clearPendingCommand();
1003+
1004+ pthread_cond_broadcast(&ac->requestcond);
1005+ pthread_mutex_unlock(&ac->requestmutex);
1006+
1007+ return err;
1008+}
1009+
1010+/**
1011+ * Internal send_command implementation.
1012+ *
1013+ * timeoutMsec == 0 means infinite timeout.
1014+ */
1015+static int at_send_command_full (const char *command, ATCommandType type,
1016+ const char *responsePrefix, const char *smspdu,
1017+ long long timeoutMsec, ATResponse **pp_outResponse, int useap, va_list ap)
1018+{
1019+ int err;
1020+
1021+ struct atcontext *ac = getAtContext();
1022+ static char strbuf[BUFFSIZE];
1023+ const char *ptr;
1024+
1025+ if (0 != pthread_equal(ac->tid_reader, pthread_self()))
1026+ /* Cannot be called from reader thread. */
1027+ return AT_ERROR_INVALID_THREAD;
1028+
1029+ pthread_mutex_lock(&ac->commandmutex);
1030+ if (useap) {
1031+ if (!vsnprintf(strbuf, BUFFSIZE, command, ap)) {
1032+ pthread_mutex_unlock(&ac->commandmutex);
1033+ return AT_ERROR_STRING_CREATION;
1034+ }
1035+ ptr = strbuf;
1036+ } else
1037+ ptr = command;
1038+
1039+ err = at_send_command_full_nolock(ptr, type,
1040+ responsePrefix, smspdu,
1041+ timeoutMsec, pp_outResponse);
1042+
1043+ pthread_mutex_unlock(&ac->commandmutex);
1044+
1045+ if (err == AT_ERROR_TIMEOUT && ac->onTimeout != NULL)
1046+ ac->onTimeout();
1047+
1048+ return err;
1049+}
1050+
1051+/* Only call this from onTimeout, since we're not locking or anything. */
1052+void at_send_escape (void)
1053+{
1054+ struct atcontext *ac = getAtContext();
1055+ int written;
1056+
1057+ do
1058+ written = write (ac->fd, "\033" , 1);
1059+ while ((written < 0 && errno == EINTR) || (written == 0));
1060+}
1061+
1062+/**
1063+ * Issue a single normal AT command with no intermediate response expected.
1064+ *
1065+ * "command" should not include \r.
1066+ */
1067+int at_send_command (const char *command, ...)
1068+{
1069+ int err;
1070+
1071+ struct atcontext *ac = getAtContext();
1072+ va_list ap;
1073+ va_start(ap, command);
1074+
1075+ err = at_send_command_full (command, NO_RESULT, NULL,
1076+ NULL, ac->timeoutMsec, NULL, 1, ap);
1077+ va_end(ap);
1078+
1079+ if (err != AT_NOERROR)
1080+ LOGI(" --- %s", at_str_err(-err));
1081+
1082+ return -err;
1083+}
1084+
1085+int at_send_command_raw (const char *command, ATResponse **pp_outResponse)
1086+{
1087+ struct atcontext *ac = getAtContext();
1088+ int err;
1089+
1090+ err = at_send_command_full (command, MULTILINE, "",
1091+ NULL, ac->timeoutMsec, pp_outResponse, 0, empty);
1092+
1093+ /* Don't check for intermediate responses as it is unknown if any
1094+ * intermediate responses are expected. Don't free the response, instead,
1095+ * let calling function free the allocated response.
1096+ */
1097+
1098+ if (err != AT_NOERROR)
1099+ LOGI(" --- %s", at_str_err(-err));
1100+
1101+ return -err;
1102+}
1103+
1104+int at_send_command_singleline (const char *command,
1105+ const char *responsePrefix,
1106+ ATResponse **pp_outResponse, ...)
1107+{
1108+ int err;
1109+
1110+ struct atcontext *ac = getAtContext();
1111+ va_list ap;
1112+ va_start(ap, pp_outResponse);
1113+
1114+ err = at_send_command_full (command, SINGLELINE, responsePrefix,
1115+ NULL, ac->timeoutMsec, pp_outResponse, 1, ap);
1116+
1117+ if (err == AT_NOERROR && pp_outResponse != NULL
1118+ && (*pp_outResponse) != NULL
1119+ && (*pp_outResponse)->p_intermediates == NULL)
1120+ /* Command with pp_outResponse must have an intermediate response */
1121+ err = AT_ERROR_INVALID_RESPONSE;
1122+
1123+ /* Free response in case of error */
1124+ if (err != AT_NOERROR && pp_outResponse != NULL
1125+ && (*pp_outResponse) != NULL) {
1126+ at_response_free(*pp_outResponse);
1127+ *pp_outResponse = NULL;
1128+ }
1129+
1130+ va_end(ap);
1131+
1132+ if (err != AT_NOERROR)
1133+ LOGI(" --- %s", at_str_err(-err));
1134+
1135+ return -err;
1136+}
1137+
1138+int at_send_command_numeric (const char *command,
1139+ ATResponse **pp_outResponse)
1140+{
1141+ int err;
1142+
1143+ struct atcontext *ac = getAtContext();
1144+
1145+ err = at_send_command_full (command, NUMERIC, NULL,
1146+ NULL, ac->timeoutMsec, pp_outResponse, 0, empty);
1147+
1148+ if (err == AT_NOERROR && pp_outResponse != NULL
1149+ && (*pp_outResponse) != NULL
1150+ && (*pp_outResponse)->p_intermediates == NULL)
1151+ /* Command with pp_outResponse must have an intermediate response */
1152+ err = AT_ERROR_INVALID_RESPONSE;
1153+
1154+ /* Free response in case of error */
1155+ if (err != AT_NOERROR && pp_outResponse != NULL
1156+ && (*pp_outResponse) != NULL) {
1157+ at_response_free(*pp_outResponse);
1158+ *pp_outResponse = NULL;
1159+ }
1160+
1161+ if (err != AT_NOERROR)
1162+ LOGI(" --- %s", at_str_err(-err));
1163+
1164+ return -err;
1165+}
1166+
1167+
1168+int at_send_command_sms (const char *command,
1169+ const char *pdu,
1170+ const char *responsePrefix,
1171+ ATResponse **pp_outResponse)
1172+{
1173+ int err;
1174+
1175+ struct atcontext *ac = getAtContext();
1176+
1177+ err = at_send_command_full (command, SINGLELINE, responsePrefix,
1178+ pdu, ac->timeoutMsec, pp_outResponse, 0, empty);
1179+
1180+ if (err == AT_NOERROR && pp_outResponse != NULL
1181+ && (*pp_outResponse) != NULL
1182+ && (*pp_outResponse)->p_intermediates == NULL)
1183+ /* Command with pp_outResponse must have an intermediate response */
1184+ err = AT_ERROR_INVALID_RESPONSE;
1185+
1186+ /* Free response in case of error */
1187+ if (err != AT_NOERROR && pp_outResponse != NULL
1188+ && (*pp_outResponse) != NULL) {
1189+ at_response_free(*pp_outResponse);
1190+ *pp_outResponse = NULL;
1191+ }
1192+
1193+ if (err != AT_NOERROR)
1194+ LOGI(" --- %s", at_str_err(-err));
1195+
1196+ return -err;
1197+}
1198+
1199+
1200+int at_send_command_multiline (const char *command,
1201+ const char *responsePrefix,
1202+ ATResponse **pp_outResponse, ...)
1203+{
1204+ int err;
1205+
1206+ struct atcontext *ac = getAtContext();
1207+ va_list ap;
1208+ va_start(ap, pp_outResponse);
1209+
1210+ err = at_send_command_full (command, MULTILINE, responsePrefix,
1211+ NULL, ac->timeoutMsec, pp_outResponse, 1, ap);
1212+ va_end(ap);
1213+
1214+ /* Free response in case of error */
1215+ if (err != AT_NOERROR && pp_outResponse != NULL
1216+ && (*pp_outResponse) != NULL) {
1217+ at_response_free(*pp_outResponse);
1218+ *pp_outResponse = NULL;
1219+ }
1220+
1221+ if (err != AT_NOERROR)
1222+ LOGI(" --- %s", at_str_err(-err));
1223+
1224+ return -err;
1225+}
1226+
1227+/**
1228+ * Set the default timeout. Let it be reasonably high, some commands
1229+ * take their time. Default is 10 minutes.
1230+ */
1231+void at_set_timeout_msec(int timeout)
1232+{
1233+ struct atcontext *ac = getAtContext();
1234+
1235+ ac->timeoutMsec = timeout;
1236+}
1237+
1238+/** This callback is invoked on the command thread. */
1239+void at_set_on_timeout(void (*onTimeout)(void))
1240+{
1241+ struct atcontext *ac = getAtContext();
1242+
1243+ ac->onTimeout = onTimeout;
1244+}
1245+
1246+
1247+/*
1248+ * This callback is invoked on the reader thread (like ATUnsolHandler), when the
1249+ * input stream closes before you call at_close (not when you call at_close()).
1250+ * You should still call at_close(). It may also be invoked immediately from the
1251+ * current thread if the read channel is already closed.
1252+ */
1253+void at_set_on_reader_closed(void (*onClose)(void))
1254+{
1255+ struct atcontext *ac = getAtContext();
1256+
1257+ ac->onReaderClosed = onClose;
1258+}
1259+
1260+
1261+/**
1262+ * Periodically issue an AT command and wait for a response.
1263+ * Used to ensure channel has start up and is active.
1264+ */
1265+int at_handshake(void)
1266+{
1267+ int i;
1268+ int err = 0;
1269+
1270+ struct atcontext *ac = getAtContext();
1271+
1272+ if (0 != pthread_equal(ac->tid_reader, pthread_self()))
1273+ /* Cannot be called from reader thread. */
1274+ return AT_ERROR_INVALID_THREAD;
1275+
1276+ pthread_mutex_lock(&ac->commandmutex);
1277+
1278+ for (i = 0 ; i < HANDSHAKE_RETRY_COUNT ; i++) {
1279+ /* Some stacks start with verbose off. */
1280+ err = at_send_command_full_nolock ("ATE0Q0V1", NO_RESULT,
1281+ NULL, NULL, HANDSHAKE_TIMEOUT_MSEC, NULL);
1282+
1283+ if (err == 0)
1284+ break;
1285+ }
1286+
1287+ if (err == 0) {
1288+ /* Pause for a bit to let the input buffer drain any unmatched OK's
1289+ (they will appear as extraneous unsolicited responses). */
1290+ LOGD("%s() pausing %d ms to drain unmatched OK's...",
1291+ __func__, HANDSHAKE_TIMEOUT_MSEC);
1292+ sleepMsec(HANDSHAKE_TIMEOUT_MSEC);
1293+ }
1294+
1295+ pthread_mutex_unlock(&ac->commandmutex);
1296+
1297+ return err;
1298+}
1299+
1300+AT_Error at_get_at_error(int error)
1301+{
1302+ error = -error;
1303+ if (error >= AT_ERROR_BASE && error < AT_ERROR_TOP)
1304+ return (AT_Error)(error - AT_ERROR_BASE);
1305+ else
1306+ return AT_ERROR_NON_AT;
1307+ }
1308+
1309+AT_CME_Error at_get_cme_error(int error)
1310+{
1311+ error = -error;
1312+ if (error >= CME_ERROR_BASE && error < CME_ERROR_TOP)
1313+ return (AT_CME_Error)(error - CME_ERROR_BASE);
1314+ else
1315+ return CME_ERROR_NON_CME;
1316+ }
1317+
1318+AT_CMS_Error at_get_cms_error(int error)
1319+{
1320+ error = -error;
1321+ if (error >= CMS_ERROR_BASE && error < CMS_ERROR_TOP)
1322+ return (AT_CMS_Error)(error - CMS_ERROR_BASE);
1323+ else
1324+ return CMS_ERROR_NON_CMS;
1325+}
1326+
1327+AT_Generic_Error at_get_generic_error(int error)
1328+{
1329+ error = -error;
1330+ if (error >= GENERIC_ERROR_BASE && error < GENERIC_ERROR_TOP)
1331+ return (AT_Generic_Error)(error - GENERIC_ERROR_BASE);
1332+ else
1333+ return GENERIC_ERROR_NON_GENERIC;
1334+ }
1335+
1336+AT_Error_type at_get_error_type(int error)
1337+{
1338+ error = -error;
1339+ if (error == AT_NOERROR)
1340+ return NONE_ERROR;
1341+
1342+ if (error > AT_ERROR_BASE && error <= AT_ERROR_TOP)
1343+ return AT_ERROR;
1344+
1345+ if (error >= CME_ERROR_BASE && error <= CME_ERROR_TOP)
1346+ return CME_ERROR;
1347+
1348+ if (error >= CMS_ERROR_BASE && error <= CMS_ERROR_TOP)
1349+ return CMS_ERROR;
1350+
1351+ if (error >= GENERIC_ERROR_BASE && error <= GENERIC_ERROR_TOP)
1352+ return GENERIC_ERROR;
1353+
1354+ return UNKNOWN_ERROR;
1355+ }
1356+
1357+#define quote(x) #x
1358+
1359+const char *at_str_err(int error)
1360+{
1361+ const char *s = "--UNKNOWN--";
1362+
1363+ error = -error;
1364+ switch(error) {
1365+#define AT(name, num) case num + AT_ERROR_BASE: s = quote(AT_##name); break;
1366+#define CME(name, num) case num + CME_ERROR_BASE: s = quote(CME_##name); break;
1367+#define CMS(name, num) case num + CMS_ERROR_BASE: s = quote(CMS_##name); break;
1368+#define GENERIC(name, num) case num + GENERIC_ERROR_BASE: s = quote(GENERIC_##name); break;
1369+ mbm_error
1370+#undef AT
1371+#undef CME
1372+#undef CMS
1373+#undef GENERIC
1374+}
1375+
1376+ return s;
1377+}
--- /dev/null
+++ b/huaweigeneric-ril/atchannel.h
@@ -0,0 +1,141 @@
1+/* //device/system/reference-ril/atchannel.h
2+**
3+** Copyright 2006, The Android Open Source Project
4+**
5+** Licensed under the Apache License, Version 2.0 (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** http://www.apache.org/licenses/LICENSE-2.0
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+*/
17+
18+#ifndef ATCHANNEL_H
19+#define ATCHANNEL_H 1
20+#include "at_error.h"
21+
22+/* Define AT_DEBUG to send AT traffic to "/tmp/radio-at.log" */
23+#define AT_DEBUG 0
24+
25+#if AT_DEBUG
26+extern void AT_DUMP(const char* prefix, const char* buff, int len);
27+#else
28+#define AT_DUMP(prefix,buff,len) do{}while(0)
29+#endif
30+
31+typedef enum {
32+ DEFAULT_VALUE = -1,
33+ GENERAL = 0,
34+ AUTHENTICATION_FAILURE = 1,
35+ IMSI_UNKNOWN_IN_HLR = 2,
36+ ILLEGAL_MS = 3,
37+ ILLEGAL_ME = 4,
38+ PLMN_NOT_ALLOWED = 5,
39+ LOCATION_AREA_NOT_ALLOWED = 6,
40+ ROAMING_NOT_ALLOWED = 7,
41+ NO_SUITABLE_CELL_IN_LOCATION_AREA = 8,
42+ NETWORK_FAILURE = 9,
43+ PERSISTEN_LOCATION_UPDATE_REJECT = 10
44+} Reg_Deny_DetailReason;
45+
46+typedef enum {
47+ NO_RESULT, /* No intermediate response expected. */
48+ NUMERIC, /* A single intermediate response starting with a 0-9. */
49+ SINGLELINE, /* A single intermediate response starting with a prefix. */
50+ MULTILINE /* Multiple line intermediate response
51+ starting with a prefix. */
52+} ATCommandType;
53+
54+/** A singly-linked list of intermediate responses. */
55+typedef struct ATLine {
56+ struct ATLine *p_next;
57+ char *line;
58+} ATLine;
59+
60+/** Free this with at_response_free(). */
61+typedef struct {
62+ int success; /* True if final response indicates
63+ success (eg "OK"). */
64+ char *finalResponse; /* Eg OK, ERROR */
65+ ATLine *p_intermediates; /* Any intermediate responses. */
66+} ATResponse;
67+
68+/**
69+ * A user-provided unsolicited response handler function.
70+ * This will be called from the reader thread, so do not block.
71+ * "s" is the line, and "sms_pdu" is either NULL or the PDU response
72+ * for multi-line TS 27.005 SMS PDU responses (eg +CMT:).
73+ */
74+typedef void (*ATUnsolHandler)(const char *s, const char *sms_pdu);
75+
76+int at_open(int fd, ATUnsolHandler h);
77+void at_close(void);
78+
79+/*
80+ * Set default timeout for at commands. Let it be reasonable high
81+ * since some commands take their time. Default is 10 minutes.
82+ */
83+void at_set_timeout_msec(int timeout);
84+
85+/*
86+ * This callback is invoked on the command thread.
87+ * You should reset or handshake here to avoid getting out of sync.
88+ */
89+void at_set_on_timeout(void (*onTimeout)(void));
90+
91+/*
92+ * This callback is invoked on the reader thread (like ATUnsolHandler), when the
93+ * input stream closes before you call at_close (not when you call at_close()).
94+ * You should still call at_close(). It may also be invoked immediately from the
95+ * current thread if the read channel is already closed.
96+ */
97+void at_set_on_reader_closed(void (*onClose)(void));
98+
99+void at_send_escape(void);
100+
101+int at_send_command_singleline (const char *command,
102+ const char *responsePrefix,
103+ ATResponse **pp_outResponse,
104+ ...);
105+
106+int at_send_command_numeric (const char *command,
107+ ATResponse **pp_outResponse);
108+
109+int at_send_command_multiline (const char *command,
110+ const char *responsePrefix,
111+ ATResponse **pp_outResponse,
112+ ...);
113+
114+
115+int at_handshake(void);
116+
117+int at_send_command (const char *command, ...);
118+
119+/* at_send_command_raw do allow missing intermediate response(s) without an
120+ * error code in the return value. Besides that, the response is not freed.
121+ * This requires the caller to handle freeing of the response, even in the
122+ * case that there was an error.
123+ */
124+int at_send_command_raw (const char *command, ATResponse **pp_outResponse);
125+
126+int at_send_command_sms (const char *command, const char *pdu,
127+ const char *responsePrefix,
128+ ATResponse **pp_outResponse);
129+
130+void at_response_free(ATResponse *p_response);
131+
132+void at_make_default_channel(void);
133+
134+AT_Error get_at_error(int error);
135+AT_CME_Error at_get_cme_error(int error);
136+AT_CMS_Error at_get_cms_error(int error);
137+AT_Generic_Error at_get_generic_error(int error);
138+AT_Error_type at_get_error_type(int error);
139+const char *at_str_err(int error);
140+
141+#endif
--- /dev/null
+++ b/huaweigeneric-ril/audiochannel.cpp
@@ -0,0 +1,481 @@
1+/**
2+ * Copyright (C) 2010 Eduardo José Tagle <ejtagle@tutopia.com>
3+ *
4+ * Since deeply inspired from portaudio dev port:
5+ * Copyright (C) 2009-2010 r3gis (http://www.r3gis.fr)
6+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
7+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
8+ *
9+ * Licensed under the Apache License, Version 2.0 (the "License");
10+ * you may not use this file except in compliance with the License.
11+ * You may obtain a copy of the License at
12+ *
13+ * http://www.apache.org/licenses/LICENSE-2.0
14+ *
15+ * Unless required by applicable law or agreed to in writing, software
16+ * distributed under the License is distributed on an "AS IS" BASIS,
17+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+ * See the License for the specific language governing permissions and
19+ * limitations under the License.
20+ */
21+
22+
23+#include <termios.h>
24+#include <stdio.h>
25+#include <stdlib.h>
26+#include <unistd.h>
27+#include <fcntl.h>
28+#include <sys/types.h>
29+#include "audiochannel.h"
30+
31+#define LOG_NDEBUG 0
32+#define LOG_TAG "RILAudioCh"
33+#include <utils/Log.h>
34+
35+#include <system/audio.h>
36+#include <media/AudioRecord.h>
37+#include <media/AudioSystem.h>
38+#include <media/AudioTrack.h>
39+
40+// ---- Android sound streaming ----
41+
42+/* modemAudioOut:
43+ Output an audio frame (160 samples) to the 3G audio port of the cell modem
44+
45+ data = Pointer to audio data to write
46+
47+*/
48+static int modemAudioOut(struct GsmAudioTunnel* ctx,const void* data)
49+{
50+ if (ctx->fd == -1)
51+ return 0;
52+
53+ // Write audio to the 3G modem audio port in 320 bytes chunks... This is
54+ // required by huawei modems...
55+
56+ // Write audio chunk
57+ int res = write(ctx->fd, data, ctx->frame_size * (ctx->bits_per_sample/8));
58+ if (res < 0)
59+ return -1;
60+
61+ // Write a 0 length frame to post data
62+ res = write(ctx->fd, data, 0);
63+ if (res < 0)
64+ return -1;
65+
66+ return 0;
67+}
68+
69+/* modemAudioIn:
70+ Input an audio frame (160 samples) from the 3G audio port of the cell modem
71+
72+ data = Pointer to buffer where data must be stored
73+*/
74+static int modemAudioIn(struct GsmAudioTunnel* ctx, void* data)
75+{
76+ int res = 0;
77+ if (ctx->fd == -1)
78+ return 0;
79+
80+
81+ while (1) {
82+ res = read(ctx->fd, data, ctx->frame_size * (ctx->bits_per_sample/8));
83+ if (res == -1) {
84+
85+ if (errno != EAGAIN && errno != EINTR) {
86+ // A real error, not something that trying again will fix
87+ break;
88+ }
89+ } else {
90+ break;
91+ }
92+ }
93+
94+ /* Failure means 0 bytes */
95+ if (res < 0)
96+ res = 0;
97+
98+ /* If some samples missing, complete them with silence */
99+ if (res < (int) (ctx->frame_size * (ctx->bits_per_sample/8) )) {
100+
101+ /* Output silence */
102+ memset( (char*)data + res, 0, (ctx->frame_size * (ctx->bits_per_sample/8) - res));
103+ }
104+
105+ return 0;
106+}
107+
108+static void AndroidRecorderCallback(int event, void* userData, void* info)
109+{
110+ struct GsmAudioTunnel *ctx = (struct GsmAudioTunnel*) userData;
111+ android::AudioRecord::Buffer* uinfo = (android::AudioRecord::Buffer*) info;
112+ unsigned nsamples;
113+ void *input;
114+
115+ if(!ctx || !uinfo)
116+ return;
117+
118+ if (ctx->quit_flag)
119+ goto on_break;
120+
121+ input = (void *) uinfo->raw;
122+
123+ // Calculate number of total samples we've got
124+ nsamples = uinfo->frameCount + ctx->rec_buf_count;
125+
126+ if (nsamples >= ctx->frame_size) {
127+
128+ /* If buffer is not empty, combine the buffer with the just incoming
129+ * samples, then call put_frame.
130+ */
131+ if (ctx->rec_buf_count) {
132+
133+ unsigned chunk_count = ctx->frame_size - ctx->rec_buf_count;
134+ memcpy( (char*)ctx->rec_buf + ctx->rec_buf_count * (ctx->bits_per_sample/8), input, chunk_count * (ctx->bits_per_sample/8));
135+
136+ /* Send the audio to the modem */
137+ modemAudioOut(ctx, ctx->rec_buf);
138+
139+ input = (char*) input + chunk_count * (ctx->bits_per_sample/8);
140+ nsamples -= ctx->frame_size;
141+ ctx->rec_buf_count = 0;
142+ }
143+
144+ // Give all frames we have
145+ while (nsamples >= ctx->frame_size) {
146+
147+ /* Send the audio to the modem */
148+ modemAudioOut(ctx, input);
149+
150+ input = (char*) input + ctx->frame_size * (ctx->bits_per_sample/8);
151+ nsamples -= ctx->frame_size;
152+ }
153+
154+ // Store the remaining samples into the buffer
155+ if (nsamples) {
156+ ctx->rec_buf_count = nsamples;
157+ memcpy(ctx->rec_buf, input, nsamples * (ctx->bits_per_sample/8));
158+ }
159+
160+ } else {
161+ // Not enough samples, let's just store them in the buffer
162+ memcpy((char*)ctx->rec_buf + ctx->rec_buf_count * (ctx->bits_per_sample/8), input, uinfo->frameCount * (ctx->bits_per_sample/8));
163+ ctx->rec_buf_count += uinfo->frameCount;
164+ }
165+
166+ return;
167+
168+on_break:
169+ LOGD("Record thread stopped");
170+ ctx->rec_thread_exited = 1;
171+ return;
172+}
173+
174+static void AndroidPlayerCallback( int event, void* userData, void* info)
175+{
176+ unsigned nsamples_req;
177+ void *output;
178+ struct GsmAudioTunnel *ctx = (struct GsmAudioTunnel*) userData;
179+ android::AudioTrack::Buffer* uinfo = (android::AudioTrack::Buffer*) info;
180+
181+ if (!ctx || !uinfo)
182+ return;
183+
184+ if (ctx->quit_flag)
185+ goto on_break;
186+
187+ nsamples_req = uinfo->frameCount;
188+ output = (void*) uinfo->raw;
189+
190+ // Check if any buffered samples
191+ if (ctx->play_buf_count) {
192+
193+ // samples buffered >= requested by sound device
194+ if (ctx->play_buf_count >= nsamples_req) {
195+
196+ memcpy(output, ctx->play_buf, nsamples_req * (ctx->bits_per_sample/8));
197+ ctx->play_buf_count -= nsamples_req;
198+
199+ memmove(ctx->play_buf,
200+ (char*)ctx->play_buf + nsamples_req * (ctx->bits_per_sample/8), ctx->play_buf_count * (ctx->bits_per_sample/8));
201+ nsamples_req = 0;
202+ return;
203+ }
204+
205+ // samples buffered < requested by sound device
206+ memcpy(output, ctx->play_buf,
207+ ctx->play_buf_count * (ctx->bits_per_sample/8));
208+ nsamples_req -= ctx->play_buf_count;
209+ output = (char*)output + ctx->play_buf_count * (ctx->bits_per_sample/8);
210+ ctx->play_buf_count = 0;
211+ }
212+
213+ // Fill output buffer as requested in chunks
214+ while (nsamples_req) {
215+ if (nsamples_req >= ctx->frame_size) {
216+
217+ /* get a frame from the modem */
218+ modemAudioIn(ctx, output);
219+
220+ nsamples_req -= ctx->frame_size;
221+ output = (char*)output + ctx->frame_size * (ctx->bits_per_sample/8);
222+
223+ } else {
224+
225+ /* get a frame from the modem */
226+ modemAudioIn(ctx, ctx->play_buf);
227+
228+ memcpy(output, ctx->play_buf,
229+ nsamples_req * (ctx->bits_per_sample/8));
230+ ctx->play_buf_count = ctx->frame_size - nsamples_req;
231+ memmove(ctx->play_buf,
232+ (char*)ctx->play_buf + nsamples_req * (ctx->bits_per_sample/8),
233+ ctx->play_buf_count * (ctx->bits_per_sample/8));
234+ nsamples_req = 0;
235+ }
236+ }
237+
238+ return;
239+
240+on_break:
241+ LOGD("Play thread stopped");
242+ ctx->play_thread_exited = 1;
243+ return;
244+}
245+
246+ //AT^DDSETEX=2
247+
248+int gsm_audio_tunnel_start(struct GsmAudioTunnel *ctx,const char* gsmvoicechannel,unsigned int sampling_rate,unsigned int frame_size,unsigned int bits_per_sample)
249+{
250+ struct termios newtio;
251+ int format = (bits_per_sample > 8)
252+ ? AUDIO_FORMAT_PCM_16_BIT
253+ : AUDIO_FORMAT_PCM_8_BIT;
254+
255+ /* If already running, dont do it again */
256+ if (ctx->running)
257+ return 0;
258+
259+ memset(ctx,0,sizeof(struct GsmAudioTunnel));
260+
261+ ctx->sampling_rate = sampling_rate;
262+ ctx->frame_size = frame_size;
263+ ctx->bits_per_sample = bits_per_sample;
264+
265+ LOGD("Opening GSM voice channel '%s', sampling_rate:%u hz, frame_size:%u, bits_per_sample:%u ...",
266+ gsmvoicechannel,sampling_rate,frame_size,bits_per_sample);
267+
268+ // Open the device(com port) to be non-blocking (read will return immediately)
269+ ctx->fd = open(gsmvoicechannel, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
270+ if (ctx->fd < 0) {
271+ LOGE("Could not open '%s'",gsmvoicechannel);
272+ return -1;
273+ }
274+
275+ // Configure it to get data as raw as possible
276+ tcgetattr(ctx->fd, &newtio );
277+ newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
278+ newtio.c_iflag = IGNPAR | IGNBRK | IGNCR | IXOFF;
279+ newtio.c_oflag = 0;
280+ newtio.c_lflag = 0;
281+ newtio.c_cc[VMIN]=0;
282+ newtio.c_cc[VTIME]=5; // You may want to tweak this; 5 = 1/2 second, 10 = 1 second
283+ tcsetattr(ctx->fd,TCSANOW, &newtio);
284+
285+ LOGD("Creating streams....");
286+ ctx->rec_buf = malloc(ctx->frame_size * (ctx->bits_per_sample/8));
287+ if (!ctx->rec_buf) {
288+ close(ctx->fd);
289+ return -1;
290+ }
291+
292+ ctx->play_buf = malloc(ctx->frame_size * (ctx->bits_per_sample/8));
293+ if (!ctx->play_buf) {
294+ free(ctx->rec_buf);
295+ close(ctx->fd);
296+ return -1;
297+ }
298+
299+ // Compute buffer size
300+ size_t inputBuffSize = 0;
301+ android::AudioSystem::getInputBufferSize(
302+ ctx->sampling_rate, // Samples per second
303+ format,
304+ AUDIO_CHANNEL_IN_MONO,
305+ &inputBuffSize);
306+
307+ // We use 2* size of input buffer for ping pong use of record buffer.
308+ inputBuffSize = 2 * inputBuffSize;
309+
310+ // Create audio record channel
311+ ctx->rec_strm = new android::AudioRecord();
312+ if(!ctx->rec_strm) {
313+ LOGE("fail to create audio record");
314+ free(ctx->play_buf);
315+ free(ctx->rec_buf);
316+ close(ctx->fd);
317+ return -1;
318+ }
319+
320+ // Unmute microphone
321+ // android::AudioSystem::muteMicrophone(false);
322+ int create_result = ((android::AudioRecord*)ctx->rec_strm)->set(
323+ AUDIO_SOURCE_MIC,
324+ ctx->sampling_rate,
325+ format,
326+ AUDIO_CHANNEL_IN_MONO,
327+ inputBuffSize,
328+ 0, //flags
329+ &AndroidRecorderCallback,
330+ (void *) ctx,
331+ (inputBuffSize / 2), // Notification frames
332+ false,
333+ 0);
334+
335+ if(create_result != android::NO_ERROR){
336+ LOGE("fail to check audio record : error code %d", create_result);
337+ delete ((android::AudioRecord*)ctx->rec_strm);
338+ free(ctx->play_buf);
339+ free(ctx->rec_buf);
340+ close(ctx->fd);
341+ return -1;
342+ }
343+
344+ if(((android::AudioRecord*)ctx->rec_strm)->initCheck() != android::NO_ERROR) {
345+ LOGE("fail to check audio record : buffer size is : %d, error code : %d", inputBuffSize, ((android::AudioRecord*)ctx->rec_strm)->initCheck() );
346+ delete ((android::AudioRecord*)ctx->rec_strm);
347+ free(ctx->play_buf);
348+ free(ctx->rec_buf);
349+ close(ctx->fd);
350+ return -1;
351+ }
352+
353+ // Create audio playback channel
354+ ctx->play_strm = new android::AudioTrack();
355+ if(!ctx->play_strm) {
356+ LOGE("Failed to create AudioTrack");
357+ delete ((android::AudioRecord*)ctx->rec_strm);
358+ free(ctx->play_buf);
359+ free(ctx->rec_buf);
360+ close(ctx->fd);
361+ return -1;
362+ }
363+
364+ // android::AudioSystem::setMasterMute(false);
365+ create_result = ((android::AudioTrack*)ctx->play_strm)->set(
366+ AUDIO_STREAM_VOICE_CALL,
367+ ctx->sampling_rate, //this is sample rate in Hz (16000 Hz for example)
368+ format,
369+ AUDIO_CHANNEL_OUT_MONO, //For now this is mono (we expect 1)
370+ inputBuffSize,
371+ 0, //flags
372+ &AndroidPlayerCallback,
373+ (void *) ctx,
374+ (inputBuffSize / 2),
375+ 0,
376+ false,
377+ 0);
378+
379+ if(create_result != android::NO_ERROR){
380+ LOGE("fail to check audio record : error code %d", create_result);
381+ delete ((android::AudioTrack*)ctx->play_strm);
382+ delete ((android::AudioRecord*)ctx->rec_strm);
383+ free(ctx->play_buf);
384+ free(ctx->rec_buf);
385+ close(ctx->fd);
386+ return -1;
387+ }
388+
389+ if(((android::AudioTrack*)ctx->play_strm)->initCheck() != android::NO_ERROR) {
390+ LOGE("fail to check audio playback : buffer size is : %d, error code : %d", inputBuffSize, ((android::AudioTrack*)ctx->play_strm)->initCheck() );
391+ delete ((android::AudioTrack*)ctx->play_strm);
392+ delete ((android::AudioRecord*)ctx->rec_strm);
393+ free(ctx->play_buf);
394+ free(ctx->rec_buf);
395+ close(ctx->fd);
396+ return -1;
397+ }
398+
399+ /* Save the current audio routing setting, then switch it to earpiece. */
400+ // android::AudioSystem::getMode(&ctx->saved_audio_mode);
401+ // android::AudioSystem::getRouting(ctx->saved_audio_mode, &ctx->saved_audio_routing);
402+ // android::AudioSystem::setRouting(ctx->saved_audio_mode,
403+ // android::AudioSystem::ROUTE_EARPIECE,
404+ // android::AudioSystem::ROUTE_ALL);
405+
406+ LOGD("Starting streaming...");
407+
408+ if (ctx->play_strm) {
409+ ((android::AudioTrack*)ctx->play_strm)->start();
410+ }
411+
412+ if (ctx->rec_strm) {
413+ ((android::AudioRecord*)ctx->rec_strm)->start();
414+ }
415+
416+ LOGD("Done");
417+
418+ ctx->running = 1;
419+
420+ // OK, done
421+ return 0;
422+}
423+
424+/* API: destroy ctx. */
425+int gsm_audio_tunnel_stop(struct GsmAudioTunnel *ctx)
426+{
427+ int i = 0;
428+
429+ /* If not running, dont do it again */
430+ if (!ctx->running)
431+ return 0;
432+
433+
434+ LOGD("Will Stop ctx, wait for all audio callback clean");
435+ ctx->quit_flag = 1;
436+ for (i=0; !ctx->rec_thread_exited && i<100; ++i){
437+ usleep(100000);
438+ }
439+ for (i=0; !ctx->play_thread_exited && i<100; ++i){
440+ usleep(100000);
441+ }
442+
443+ // After all sleep for 0.1 seconds since android device can be slow
444+ usleep(100000);
445+
446+ LOGD("Stopping ctx..");
447+ if (ctx->rec_strm) {
448+ ((android::AudioRecord*)ctx->rec_strm)->stop();
449+ }
450+
451+ if (ctx->play_strm) {
452+ ((android::AudioTrack*)ctx->play_strm)->stop();
453+ }
454+
455+ // Restore the audio routing setting
456+ // android::AudioSystem::setRouting(ctx->saved_audio_mode,
457+ // ctx->saved_audio_routing,
458+ // android::AudioSystem::ROUTE_ALL);
459+
460+
461+ LOGD("Closing streaming");
462+
463+ if (ctx->play_strm) {
464+ delete ((android::AudioTrack*)ctx->play_strm);
465+ ctx->play_strm = NULL;
466+ }
467+
468+ if (ctx->rec_strm) {
469+ delete ((android::AudioRecord*)ctx->rec_strm);
470+ ctx->rec_strm = NULL;
471+ }
472+
473+ free(ctx->play_buf);
474+ free(ctx->rec_buf);
475+
476+ close(ctx->fd);
477+ memset(ctx,0,sizeof(struct GsmAudioTunnel));
478+
479+ LOGD("Done");
480+ return 0;
481+}
--- /dev/null
+++ b/huaweigeneric-ril/audiochannel.h
@@ -0,0 +1,65 @@
1+/*
2+**
3+** Copyright (C) 2010 Eduardo José Tagle <ejtagle@tutopia.com>
4+**
5+** Licensed under the Apache License, Version 2.0 (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** http://www.apache.org/licenses/LICENSE-2.0
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+**
17+** Author: Christian Bejram <christian.bejram@stericsson.com>
18+*/
19+#ifndef _AUDIOCHANNEL_H
20+#define _AUDIOCHANNEL_H 1
21+
22+struct GsmAudioTunnel {
23+ int running; // If running
24+
25+ // 3G voice modem
26+ int fd; // Voice data serial port handler
27+
28+ // Common properties
29+ volatile int quit_flag; // If threads should quit
30+ unsigned int frame_size; // Frame size
31+ unsigned int sampling_rate; // Sampling rate
32+ unsigned int bits_per_sample; // Bits per sample. valid values = 16/8
33+
34+ // Playback
35+ void* play_strm; // Playback stream
36+ volatile int play_thread_exited;// If play thread has exited
37+ void* play_buf; // Pointer to the playback buffer
38+ unsigned int play_buf_count; // Count of already stored samples in the playback buffer
39+
40+ // Record
41+ void* rec_strm; // Record stream
42+ volatile int rec_thread_exited; // If record thread has exited
43+ void* rec_buf; // Pointer to the recording buffer
44+ unsigned int rec_buf_count; // Count of already stored samples in the recording buffer
45+};
46+
47+#define GSM_AUDIO_CHANNEL_STATIC_INIT { 0, 0, 0,0,0,0, 0,0,0,0 ,0,0,0,0 }
48+
49+#ifdef __cplusplus
50+extern "C" {
51+#endif
52+
53+int gsm_audio_tunnel_start(struct GsmAudioTunnel *stream,
54+ const char* gsmvoicechannel,
55+ unsigned int sampling_rate,
56+ unsigned int frame_size,
57+ unsigned int bits_per_sample);
58+
59+int gsm_audio_tunnel_stop(struct GsmAudioTunnel *stream);
60+
61+#ifdef __cplusplus
62+}
63+#endif
64+
65+#endif
--- /dev/null
+++ b/huaweigeneric-ril/fcp_parser.c
@@ -0,0 +1,129 @@
1+/*
2+**
3+** Copyright (C) ST-Ericsson AB 2008-2010
4+** Copyright 2006, The Android Open Source Project
5+**
6+** Licensed under the Apache License, Version 2.0 (the "License");
7+** you may not use this file except in compliance with the License.
8+** You may obtain a copy of the License at
9+**
10+** http://www.apache.org/licenses/LICENSE-2.0
11+**
12+** Unless required by applicable law or agreed to in writing, software
13+** distributed under the License is distributed on an "AS IS" BASIS,
14+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+** See the License for the specific language governing permissions and
16+** limitations under the License.
17+**
18+** Based on reference-ril by The Android Open Source Project.
19+**
20+** Heavily modified for ST-Ericsson U300 modems.
21+** Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
22+*/
23+
24+#include <memory.h>
25+#include <errno.h>
26+#include <stdio.h>
27+
28+#define LOG_TAG "RILV"
29+#include <utils/Log.h>
30+
31+#include "fcp_parser.h"
32+#include "misc.h"
33+
34+int fcp_to_ts_51011(/*in*/ const char *stream, /*in*/ size_t len,
35+ /*out*/ struct ts_51011_921_resp *out)
36+{
37+ const char *end = &stream[len];
38+ struct tlv fcp;
39+ int ret = parseTlv(stream, end, &fcp);
40+ const char *what = NULL;
41+#define FCP_CVT_THROW(_ret, _what) \
42+ do { \
43+ ret = _ret; \
44+ what = _what; \
45+ goto except; \
46+ } while (0)
47+
48+ if (ret < 0)
49+ FCP_CVT_THROW(ret, "ETSI TS 102 221, 11.1.1.3: FCP template TLV structure");
50+ if (fcp.tag != 0x62)
51+ FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.3: FCP template tag");
52+
53+ /*
54+ * NOTE: Following fields do not exist in FCP template:
55+ * - file_acc
56+ * - file_status
57+ */
58+
59+ memset(out, 0, sizeof(*out));
60+ while (fcp.data < fcp.end) {
61+ unsigned char fdbyte;
62+ size_t property_size;
63+ struct tlv tlv;
64+ ret = parseTlv(fcp.data, end, &tlv);
65+ if (ret < 0)
66+ FCP_CVT_THROW(ret, "ETSI TS 102 221, 11.1.1.3: FCP property TLV structure");
67+ property_size = (tlv.end - tlv.data) / 2;
68+
69+ switch (tlv.tag) {
70+ case 0x80: /* File size, ETSI TS 102 221, 11.1.1.4.1 */
71+ /* File size > 0xFFFF is not supported by ts_51011 */
72+ if (property_size != 2)
73+ FCP_CVT_THROW(-ENOTSUP, "3GPP TS 51 011, 9.2.1: Unsupported file size");
74+ /* be16 on both sides */
75+ ((char*)&out->file_size)[0] = TLV_DATA(tlv, 0);
76+ ((char*)&out->file_size)[1] = TLV_DATA(tlv, 1);
77+ break;
78+ case 0x83: /* File identifier, ETSI TS 102 221, 11.1.1.4.4 */
79+ /* Sanity check */
80+ if (property_size != 2)
81+ FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.4.4: Invalid file identifier");
82+ /* be16 on both sides */
83+ ((char*)&out->file_id)[0] = TLV_DATA(tlv, 0);
84+ ((char*)&out->file_id)[1] = TLV_DATA(tlv, 1);
85+ break;
86+ case 0x82: /* File descriptior, ETSI TS 102 221, 11.1.1.4.3 */
87+ /* Sanity check */
88+ if (property_size < 2)
89+ FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.4.3: Invalid file descriptor");
90+ fdbyte = TLV_DATA(tlv, 0);
91+ /* ETSI TS 102 221, Table 11.5 for FCP fields */
92+ /* 3GPP TS 51 011, 9.2.1 and 9.3 for 'out' fields */
93+ if ((fdbyte & 0xBF) == 0x38) {
94+ out->file_type = 2; /* DF of ADF */
95+ } else if ((fdbyte & 0xB0) == 0x00) {
96+ out->file_type = 4; /* EF */
97+ out->file_status = 1; /* Not invalidated */
98+ ++out->data_size; /* file_structure field is valid */
99+ if ((fdbyte & 0x07) == 0x01) {
100+ out->file_structure = 0; /* Transparent */
101+ } else {
102+ if (property_size < 5)
103+ FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.4.3: Invalid non-transparent file descriptor");
104+ ++out->data_size; /* record_size field is valid */
105+ out->record_size = TLV_DATA(tlv, 3);
106+ if ((fdbyte & 0x07) == 0x06) {
107+ out->file_structure = 3; /* Cyclic */
108+ } else if ((fdbyte & 0x07) == 0x02) {
109+ out->file_structure = 1; /* Linear fixed */
110+ } else {
111+ FCP_CVT_THROW(-EINVAL, "ETSI TS 102 221, 11.1.1.4.3: Invalid file structure");
112+ }
113+ }
114+ } else {
115+ out->file_type = 0; /* RFU */
116+ }
117+ break;
118+ }
119+ fcp.data = tlv.end;
120+ }
121+
122+ finally:
123+ return ret;
124+
125+ except:
126+ #undef FCP_CVT_THROW
127+ LOGE("%s() FCP to TS 510 11: Specification violation: %s.", __func__, what);
128+ goto finally;
129+}
--- /dev/null
+++ b/huaweigeneric-ril/fcp_parser.h
@@ -0,0 +1,47 @@
1+/* ST-Ericsson U300 RIL
2+**
3+** Copyright (C) ST-Ericsson AB 2008-2010
4+** Copyright 2006, The Android Open Source Project
5+**
6+** Licensed under the Apache License, Version 2.0 (the "License");
7+** you may not use this file except in compliance with the License.
8+** You may obtain a copy of the License at
9+**
10+** http://www.apache.org/licenses/LICENSE-2.0
11+**
12+** Unless required by applicable law or agreed to in writing, software
13+** distributed under the License is distributed on an "AS IS" BASIS,
14+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+** See the License for the specific language governing permissions and
16+** limitations under the License.
17+**
18+** Based on reference-ril by The Android Open Source Project.
19+**
20+** Heavily modified for ST-Ericsson U300 modems.
21+** Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
22+*/
23+
24+#ifndef FCP_PARSER_H
25+#define FCP_PARSER_H
26+
27+#include <stdint.h>
28+#include <endian.h>
29+
30+struct ts_51011_921_resp {
31+ uint8_t rfu_1[2];
32+ uint16_t file_size; /* be16 */
33+ uint16_t file_id; /* be16 */
34+ uint8_t file_type;
35+ uint8_t rfu_2;
36+ uint8_t file_acc[3];
37+ uint8_t file_status;
38+ uint8_t data_size;
39+ uint8_t file_structure;
40+ uint8_t record_size;
41+} __attribute__((packed));
42+
43+int fcp_to_ts_51011(/*in*/ const char *stream,
44+ /*in*/ size_t len,
45+ /*out*/ struct ts_51011_921_resp *out);
46+
47+#endif
--- /dev/null
+++ b/huaweigeneric-ril/gsm.c
@@ -0,0 +1,1153 @@
1+#include "gsm.h"
2+#include <stdlib.h>
3+
4+/** UTILITIES
5+ **/
6+byte_t
7+gsm_int_to_bcdi( int value )
8+{
9+ return (byte_t)((value / 10) | ((value % 10) << 4));
10+}
11+
12+int
13+gsm_int_from_bcdi( byte_t val )
14+{
15+ int ret = 0;
16+
17+ if ((val & 0xf0) <= 0x90)
18+ ret = (val >> 4);
19+
20+ if ((val & 0x0f) <= 0x90)
21+ ret |= (val % 0xf)*10;
22+
23+ return ret;
24+}
25+
26+
27+static int
28+gsm_bcdi_to_ascii( cbytes_t bcd, int bcdlen, bytes_t dst )
29+{
30+ static byte_t bcdichars[14] = "0123456789*#,N";
31+
32+ int result = 0;
33+ int shift = 0;
34+
35+ while (bcdlen > 0) {
36+ int c = (bcd[0] >> shift) & 0xf;
37+
38+ if (c == 0xf && bcdlen == 1)
39+ break;
40+
41+ if (c < 14) {
42+ if (dst) dst[result] = bcdichars[c];
43+ result += 1;
44+ }
45+ bcdlen --;
46+ shift += 4;
47+ if (shift == 8) {
48+ bcd++;
49+ shift = 0;
50+ }
51+ }
52+ return result;
53+}
54+
55+
56+static int
57+gsm_bcdi_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst )
58+{
59+ cbytes_t end = ascii + asciilen;
60+ int result = 0;
61+ int phase = 0x01;
62+
63+ while (ascii < end) {
64+ int c = *ascii++;
65+ int d;
66+
67+ if (c == '*')
68+ c = 11;
69+ else if (c == '#')
70+ c = 12;
71+ else if (c == ',')
72+ c = 13;
73+ else if (c == 'N')
74+ c = 14;
75+ else {
76+ c -= '0';
77+ if ((unsigned)c >= 10)
78+ break;
79+ }
80+ phase = (phase << 4) | c;
81+ if (phase & 0x100) {
82+ if (dst) dst[result] = (byte_t) phase;
83+ result += 1;
84+ phase = 0x01;
85+ }
86+ }
87+ if (phase != 0x01) {
88+ if (dst) dst[result] = (byte_t)( phase | 0xf0 );
89+ result += 1;
90+ }
91+ return result;
92+}
93+
94+
95+int
96+gsm_hexchar_to_int( char c )
97+{
98+ if ((unsigned)(c - '0') < 10)
99+ return c - '0';
100+ if ((unsigned)(c - 'a') < 6)
101+ return 10 + (c - 'a');
102+ if ((unsigned)(c - 'A') < 6)
103+ return 10 + (c - 'A');
104+ return -1;
105+}
106+
107+int
108+gsm_hexchar_to_int0( char c )
109+{
110+ int ret = gsm_hexchar_to_int(c);
111+
112+ return (ret < 0) ? 0 : ret;
113+}
114+
115+int
116+gsm_hex2_to_byte( const char* hex )
117+{
118+ int hi = gsm_hexchar_to_int(hex[0]);
119+ int lo = gsm_hexchar_to_int(hex[1]);
120+
121+ if (hi < 0 || lo < 0)
122+ return -1;
123+
124+ return ( (hi << 4) | lo );
125+}
126+
127+int
128+gsm_hex4_to_short( const char* hex )
129+{
130+ int hi = gsm_hex2_to_byte(hex);
131+ int lo = gsm_hex2_to_byte(hex+2);
132+
133+ if (hi < 0 || lo < 0)
134+ return -1;
135+
136+ return ((hi << 8) | lo);
137+}
138+
139+int
140+gsm_hex2_to_byte0( const char* hex )
141+{
142+ int hi = gsm_hexchar_to_int0(hex[0]);
143+ int lo = gsm_hexchar_to_int0(hex[1]);
144+
145+ return (byte_t)( (hi << 4) | lo );
146+}
147+
148+void
149+gsm_hex_from_byte( char* hex, int val )
150+{
151+ static const char hexdigits[] = "0123456789ABCDEF";
152+
153+ hex[0] = hexdigits[(val >> 4) & 15];
154+ hex[1] = hexdigits[val & 15];
155+}
156+
157+void
158+gsm_hex_from_short( char* hex, int val )
159+{
160+ gsm_hex_from_byte( hex, (val >> 8) );
161+ gsm_hex_from_byte( hex+2, val );
162+}
163+
164+
165+
166+/** HEX
167+ **/
168+void
169+gsm_hex_to_bytes( cbytes_t hex, int hexlen, bytes_t dst )
170+{
171+ int nn;
172+
173+ for (nn = 0; nn < hexlen/2; nn++ ) {
174+ dst[nn] = (byte_t) gsm_hex2_to_byte0( hex+2*nn );
175+ }
176+ if (hexlen & 1) {
177+ dst[nn] = gsm_hexchar_to_int0( hex[2*nn] ) << 4;
178+ }
179+}
180+
181+void
182+gsm_hex_from_bytes( char* hex, cbytes_t src, int srclen )
183+{
184+ int nn;
185+
186+ for (nn = 0; nn < srclen; nn++) {
187+ gsm_hex_from_byte( hex + 2*nn, src[nn] );
188+ }
189+}
190+
191+/** ROPES
192+ **/
193+
194+void
195+gsm_rope_init( GsmRope rope )
196+{
197+ rope->data = NULL;
198+ rope->pos = 0;
199+ rope->max = 0;
200+ rope->error = 0;
201+}
202+
203+void
204+gsm_rope_init_alloc( GsmRope rope, int count )
205+{
206+ rope->data = rope->data0;
207+ rope->pos = 0;
208+ rope->max = sizeof(rope->data0);
209+ rope->error = 0;
210+
211+ if (count > 0) {
212+ rope->data = calloc( count, 1 );
213+ rope->max = count;
214+
215+ if (rope->data == NULL) {
216+ rope->error = 1;
217+ rope->max = 0;
218+ }
219+ }
220+}
221+
222+int
223+gsm_rope_done( GsmRope rope )
224+{
225+ int result = rope->error;
226+
227+ if (rope->data && rope->data != rope->data0)
228+ free(rope->data);
229+
230+ rope->data = NULL;
231+ rope->pos = 0;
232+ rope->max = 0;
233+ rope->error = 0;
234+
235+ return result;
236+}
237+
238+
239+bytes_t
240+gsm_rope_done_acquire( GsmRope rope, int *psize )
241+{
242+ bytes_t result = rope->data;
243+
244+ *psize = rope->pos;
245+ if (result == rope->data0) {
246+ result = malloc( rope->pos );
247+ if (result != NULL)
248+ memcpy( result, rope->data, rope->pos );
249+ }
250+ return result;
251+}
252+
253+
254+int
255+gsm_rope_ensure( GsmRope rope, int new_count )
256+{
257+ if (rope->data != NULL) {
258+ int old_max = rope->max;
259+ bytes_t old_data = rope->data == rope->data0 ? NULL : rope->data;
260+ int new_max = old_max;
261+ bytes_t new_data;
262+
263+ while (new_max < new_count) {
264+ new_max += (new_max >> 1) + 4;
265+ }
266+ new_data = realloc( old_data, new_max );
267+ if (new_data == NULL) {
268+ rope->error = 1;
269+ return -1;
270+ }
271+ rope->data = new_data;
272+ rope->max = new_max;
273+ } else {
274+ rope->max = new_count;
275+ }
276+ return 0;
277+}
278+
279+static int
280+gsm_rope_can_grow( GsmRope rope, int count )
281+{
282+ if (!rope->data || rope->error)
283+ return 0;
284+
285+ if (rope->pos + count > rope->max) {
286+ if (rope->data == NULL)
287+ rope->max = rope->pos + count;
288+
289+ else if (rope->error ||
290+ gsm_rope_ensure( rope, rope->pos + count ) < 0)
291+ return 0;
292+ }
293+ return 1;
294+}
295+
296+void
297+gsm_rope_add_c( GsmRope rope, char c )
298+{
299+ if (gsm_rope_can_grow(rope, 1)) {
300+ rope->data[ rope->pos ] = (byte_t) c;
301+ }
302+ rope->pos += 1;
303+}
304+
305+void
306+gsm_rope_add( GsmRope rope, const void* buf, int buflen )
307+{
308+ if (gsm_rope_can_grow(rope, buflen)) {
309+ memcpy( rope->data + rope->pos, (const char*)buf, buflen );
310+ }
311+ rope->pos += buflen;
312+}
313+
314+void*
315+gsm_rope_reserve( GsmRope rope, int count )
316+{
317+ void* result = NULL;
318+
319+ if (gsm_rope_can_grow(rope, count)) {
320+ if (rope->data != NULL)
321+ result = rope->data + rope->pos;
322+ }
323+ rope->pos += count;
324+
325+ return result;
326+}
327+
328+/* skip a given number of Unicode characters in a utf-8 byte string */
329+cbytes_t
330+utf8_skip( cbytes_t utf8,
331+ cbytes_t utf8end,
332+ int count)
333+{
334+ cbytes_t p = utf8;
335+ cbytes_t end = utf8end;
336+
337+ for ( ; count > 0; count-- ) {
338+ int c;
339+
340+ if (p > end)
341+ break;
342+
343+ c = *p++;
344+ if (c > 128) {
345+ while (p < end && (p[0] & 0xc0) == 0x80)
346+ p++;
347+ }
348+ }
349+ return p;
350+}
351+
352+static __inline__ int
353+utf8_next( cbytes_t *pp, cbytes_t end )
354+{
355+ cbytes_t p = *pp;
356+ int result = -1;
357+
358+ if (p < end) {
359+ int c= *p++;
360+ if (c >= 128) {
361+ if ((c & 0xe0) == 0xc0)
362+ c &= 0x1f;
363+ else if ((c & 0xf0) == 0xe0)
364+ c &= 0x0f;
365+ else
366+ c &= 0x07;
367+
368+ while (p < end && (p[0] & 0xc0) == 0x80) {
369+ c = (c << 6) | (p[0] & 0x3f);
370+ }
371+ }
372+ result = c;
373+ *pp = p;
374+ }
375+Exit:
376+ return result;
377+}
378+
379+
380+__inline__ int
381+utf8_write( bytes_t utf8, int offset, int v )
382+{
383+ int result;
384+
385+ if (v < 128) {
386+ result = 1;
387+ if (utf8)
388+ utf8[offset] = (byte_t) v;
389+ } else if (v < 0x800) {
390+ result = 2;
391+ if (utf8) {
392+ utf8[offset+0] = (byte_t)( 0xc0 | (v >> 6) );
393+ utf8[offset+1] = (byte_t)( 0x80 | (v & 0x3f) );
394+ }
395+ } else if (v < 0x10000) {
396+ result = 3;
397+ if (utf8) {
398+ utf8[offset+0] = (byte_t)( 0xe0 | (v >> 12) );
399+ utf8[offset+1] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) );
400+ utf8[offset+2] = (byte_t)( 0x80 | (v & 0x3f) );
401+ }
402+ } else {
403+ result = 4;
404+ if (utf8) {
405+ utf8[offset+0] = (byte_t)( 0xf0 | ((v >> 18) & 0x7) );
406+ utf8[offset+1] = (byte_t)( 0x80 | ((v >> 12) & 0x3f) );
407+ utf8[offset+2] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) );
408+ utf8[offset+3] = (byte_t)( 0x80 | (v & 0x3f) );
409+ }
410+ }
411+ return result;
412+}
413+
414+static __inline__ int
415+ucs2_write( bytes_t ucs2, int offset, int v )
416+{
417+ if (ucs2) {
418+ ucs2[offset+0] = (byte_t) (v >> 8);
419+ ucs2[offset+1] = (byte_t) (v);
420+ }
421+ return 2;
422+}
423+
424+int
425+utf8_check( cbytes_t p, int utf8len )
426+{
427+ cbytes_t end = p + utf8len;
428+ int result = 0;
429+
430+ if (p) {
431+ while (p < end) {
432+ int c = *p++;
433+ if (c >= 128) {
434+ int len;
435+ if ((c & 0xe0) == 0xc0) {
436+ len = 1;
437+ }
438+ else if ((c & 0xf0) == 0xe0) {
439+ len = 2;
440+ }
441+ else if ((c & 0xf8) == 0xf0) {
442+ len = 3;
443+ }
444+ else
445+ goto Exit; /* malformed utf-8 */
446+
447+ if (p+len > end) /* string too short */
448+ goto Exit;
449+
450+ for ( ; len > 0; len--, p++ ) {
451+ if ((p[0] & 0xc0) != 0x80)
452+ goto Exit;
453+ }
454+ }
455+ }
456+ result = 1;
457+ }
458+Exit:
459+ return result;
460+}
461+
462+/** UCS2 to UTF8
463+ **/
464+
465+/* convert a UCS2 string into a UTF8 byte string, assumes 'buf' is correctly sized */
466+int
467+ucs2_to_utf8( cbytes_t ucs2,
468+ int ucs2len,
469+ bytes_t buf )
470+{
471+ int nn;
472+ int result = 0;
473+
474+ for (nn = 0; nn < ucs2len; ucs2 += 2, nn++) {
475+ int c= (ucs2[0] << 8) | ucs2[1];
476+ result += utf8_write(buf, result, c);
477+ }
478+ return result;
479+}
480+
481+/* count the number of UCS2 chars contained in a utf8 byte string */
482+int
483+utf8_to_ucs2( cbytes_t utf8,
484+ int utf8len,
485+ bytes_t ucs2 )
486+{
487+ cbytes_t p = utf8;
488+ cbytes_t end = p + utf8len;
489+ int result = 0;
490+
491+ while (p < end) {
492+ int c = utf8_next(&p, end);
493+
494+ if (c < 0)
495+ break;
496+
497+ result += ucs2_write(ucs2, result, c);
498+ }
499+ return result/2;
500+}
501+
502+
503+
504+/** GSM ALPHABET
505+ **/
506+
507+#define GSM_7BITS_ESCAPE 0x1b
508+#define GSM_7BITS_UNKNOWN 0
509+
510+static const unsigned short gsm7bits_to_unicode[128] = {
511+ '@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
512+0x394, '_',0x3a6,0x393,0x39b,0x3a9,0x3a0,0x3a8,0x3a3,0x398,0x39e, 0, 0xc6, 0xe6, 0xdf, 0xc9,
513+ ' ', '!', '"', '#', 0xa4, '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
514+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
515+ 0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
516+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0xc4, 0xd6,0x147, 0xdc, 0xa7,
517+ 0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
518+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0,
519+};
520+
521+static const unsigned short gsm7bits_extend_to_unicode[128] = {
522+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\f', 0, 0, 0, 0, 0,
523+ 0, 0, 0, 0, '^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
524+ 0, 0, 0, 0, 0, 0, 0, 0, '{', '}', 0, 0, 0, 0, 0,'\\',
525+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[', '~', ']', 0,
526+ '|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
527+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
528+ 0, 0, 0, 0, 0,0x20ac, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
529+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
530+};
531+
532+
533+static int
534+unichar_to_gsm7( int unicode )
535+{
536+ int nn;
537+ for (nn = 0; nn < 128; nn++) {
538+ if (gsm7bits_to_unicode[nn] == unicode) {
539+ return nn;
540+ }
541+ }
542+ return -1;
543+}
544+
545+static int
546+unichar_to_gsm7_extend( int unichar )
547+{
548+ int nn;
549+ for (nn = 0; nn < 128; nn++) {
550+ if (gsm7bits_extend_to_unicode[nn] == unichar) {
551+ return nn;
552+ }
553+ }
554+ return -1;
555+}
556+
557+
558+/* return the number of septets needed to encode a unicode charcode */
559+static int
560+unichar_to_gsm7_count( int unicode )
561+{
562+ int nn;
563+
564+ nn = unichar_to_gsm7(unicode);
565+ if (nn >= 0)
566+ return 1;
567+
568+ nn = unichar_to_gsm7_extend(unicode);
569+ if (nn >= 0)
570+ return 2;
571+
572+ return 0;
573+}
574+
575+
576+int
577+utf8_check_gsm7( cbytes_t utf8,
578+ int utf8len )
579+{
580+ cbytes_t utf8end = utf8 + utf8len;
581+
582+ while (utf8 < utf8end) {
583+ int c = utf8_next( &utf8, utf8end );
584+ if (unichar_to_gsm7_count(c) == 0)
585+ return 0;
586+ }
587+ return 1;
588+}
589+
590+
591+int
592+utf8_from_gsm7( cbytes_t src,
593+ int septet_offset,
594+ int septet_count,
595+ bytes_t utf8 )
596+{
597+ int shift = (septet_offset & 7);
598+ int escaped = 0;
599+ int result = 0;
600+
601+ src += (septet_offset >> 3);
602+ for ( ; septet_count > 0; septet_count-- ) {
603+ int c = (src[0] >> shift) & 0x7f;
604+ int v;
605+
606+ if (shift > 1) {
607+ c = ((src[1] << (8-shift)) | c) & 0x7f;
608+ }
609+
610+ if (escaped) {
611+ v = gsm7bits_extend_to_unicode[c];
612+ } else if (c == GSM_7BITS_ESCAPE) {
613+ escaped = 1;
614+ goto NextSeptet;
615+ } else {
616+ v = gsm7bits_to_unicode[c];
617+ }
618+
619+ result += utf8_write( utf8, result, v );
620+
621+ NextSeptet:
622+ shift += 7;
623+ if (shift >= 8) {
624+ shift -= 8;
625+ src += 1;
626+ }
627+ }
628+ return result;
629+}
630+
631+
632+int
633+utf8_from_gsm8( cbytes_t src, int count, bytes_t utf8 )
634+{
635+ int result = 0;
636+ int escaped = 0;
637+
638+
639+ for ( ; count > 0; count-- ) {
640+ int c = *src++;
641+ int v;
642+
643+ if (c == 0xff)
644+ break;
645+
646+ if (c == GSM_7BITS_ESCAPE) {
647+ if (escaped) { /* two escape characters => one space */
648+ c = 0x20;
649+ escaped = 0;
650+ } else {
651+ escaped = 1;
652+ continue;
653+ }
654+ } else {
655+ if (c >= 0x80) {
656+ c = 0x20;
657+ escaped = 0;
658+ } else if (escaped) {
659+ c = gsm7bits_extend_to_unicode[c];
660+ } else
661+ c = gsm7bits_to_unicode[c];
662+ }
663+
664+ result += utf8_write( utf8, result, c );
665+ }
666+ return result;
667+}
668+
669+/* convert a GSM 7-bit message into a unicode character array
670+ * the 'dst' array must contain at least 160 chars. the function
671+ * returns the number of characters decoded
672+ *
673+ * assumes the 'dst' array has at least septet_count items, returns the
674+ * number of unichars really written
675+ */
676+int
677+ucs2_from_gsm7( bytes_t ucs2,
678+ cbytes_t src,
679+ int septet_offset,
680+ int septet_count )
681+{
682+ const unsigned char* p = src + (septet_offset >> 3);
683+ int shift = (septet_offset & 7);
684+ int escaped = 0;
685+ int result = 0;
686+
687+ for ( ; septet_count > 0; septet_count-- ) {
688+ unsigned val = (p[0] >> shift) & 0x7f;
689+
690+ if (shift > 1)
691+ val = (val | (p[1] << (8-shift))) & 0x7f;
692+
693+ if (escaped) {
694+ int c = gsm7bits_to_unicode[val];
695+
696+ result += ucs2_write(ucs2, result, c);
697+ escaped = 0;
698+ } else if (val == GSM_7BITS_ESCAPE) {
699+ escaped = 1;
700+ } else {
701+ val = gsm7bits_extend_to_unicode[val];
702+ if (val == 0)
703+ val = 0x20;
704+
705+ result += ucs2_write( ucs2, result, val );
706+ }
707+ }
708+ return result/2;
709+}
710+
711+
712+/* count the number of septets required to write a utf8 string */
713+static int
714+utf8_to_gsm7_count( cbytes_t utf8, int utf8len )
715+{
716+ cbytes_t utf8end = utf8 + utf8len;
717+ int result = 0;
718+
719+ while ( utf8 < utf8end ) {
720+ int len;
721+ int c = utf8_next( &utf8, utf8end );
722+
723+ if (c < 0)
724+ break;
725+
726+ len = unichar_to_gsm7_count(c);
727+ if (len == 0) /* replace non-representables with space */
728+ len = 1;
729+
730+ result += len;
731+ }
732+ return result;
733+}
734+
735+typedef struct {
736+ bytes_t dst;
737+ unsigned pad;
738+ int bits;
739+ int offset;
740+} BWriterRec, *BWriter;
741+
742+static void
743+bwriter_init( BWriter writer, bytes_t dst, int start )
744+{
745+ int shift = start & 7;
746+
747+ writer->dst = dst + (start >> 3);
748+ writer->pad = 0;
749+ writer->bits = shift;
750+ writer->offset = start;
751+
752+ if (shift > 0) {
753+ writer->pad = writer->dst[0] & ~(0xFF << shift);
754+ }
755+}
756+
757+static void
758+bwriter_add7( BWriter writer, unsigned value )
759+{
760+ writer->pad |= (unsigned)(value << writer->bits);
761+ writer->bits += 7;
762+ if (writer->bits >= 8) {
763+ writer->dst[0] = (byte_t)writer->pad;
764+ writer->bits -= 8;
765+ writer->pad >>= 8;
766+ writer->dst += 1;
767+ }
768+ writer->offset += 7;
769+}
770+
771+static int
772+bwriter_done( BWriter writer )
773+{
774+ if (writer->bits > 0) {
775+ writer->dst[0] = (byte_t)writer->pad;
776+ writer->pad = 0;
777+ writer->bits = 0;
778+ writer->dst += 1;
779+ }
780+ return writer->offset;
781+}
782+
783+/* convert a utf8 string to a gsm7 byte string - return the number of septets written */
784+int
785+utf8_to_gsm7( cbytes_t utf8, int utf8len, bytes_t dst, int offset )
786+{
787+ const unsigned char* utf8end = utf8 + utf8len;
788+ BWriterRec writer[1];
789+
790+ if (dst == NULL)
791+ return utf8_to_gsm7_count(utf8, utf8len);
792+
793+ bwriter_init( writer, dst, offset );
794+ while ( utf8 < utf8end ) {
795+ int c = utf8_next( &utf8, utf8end );
796+ int nn;
797+
798+ if (c < 0)
799+ break;
800+
801+ nn = unichar_to_gsm7(c);
802+ if (nn >= 0) {
803+ bwriter_add7( writer, nn );
804+ continue;
805+ }
806+
807+ nn = unichar_to_gsm7_extend(c);
808+ if (nn >= 0) {
809+ bwriter_add7( writer, GSM_7BITS_ESCAPE );
810+ bwriter_add7( writer, nn );
811+ continue;
812+ }
813+
814+ /* unknown => replaced by space */
815+ bwriter_add7( writer, 0x20 );
816+ }
817+ return bwriter_done( writer );
818+}
819+
820+
821+int
822+utf8_to_gsm8( cbytes_t utf8, int utf8len, bytes_t dst )
823+{
824+ const unsigned char* utf8end = utf8 + utf8len;
825+ int result = 0;
826+
827+ while ( utf8 < utf8end ) {
828+ int c = utf8_next( &utf8, utf8end );
829+ int nn;
830+
831+ if (c < 0)
832+ break;
833+
834+ nn = unichar_to_gsm7(c);
835+ if (nn >= 0) {
836+ if (dst)
837+ dst[result] = (byte_t)nn;
838+ result += 1;
839+ continue;
840+ }
841+
842+ nn = unichar_to_gsm7_extend(c);
843+ if (nn >= 0) {
844+ if (dst) {
845+ dst[result+0] = (byte_t) GSM_7BITS_ESCAPE;
846+ dst[result+1] = (byte_t) nn;
847+ }
848+ result += 2;
849+ continue;
850+ }
851+
852+ /* unknown => space */
853+ if (dst)
854+ dst[result] = 0x20;
855+ result += 1;
856+ }
857+ return result;
858+}
859+
860+
861+int
862+ucs2_to_gsm7( cbytes_t ucs2, int ucs2len, bytes_t dst, int offset )
863+{
864+ const unsigned char* ucs2end = ucs2 + ucs2len*2;
865+ BWriterRec writer[1];
866+
867+ bwriter_init( writer, dst, offset );
868+ while ( ucs2 < ucs2end ) {
869+ int c = *ucs2++;
870+ int nn;
871+
872+ for (nn = 0; nn < 128; nn++) {
873+ if ( gsm7bits_to_unicode[nn] == c ) {
874+ bwriter_add7( writer, nn );
875+ goto NextUnicode;
876+ }
877+ }
878+ for (nn = 0; nn < 128; nn++) {
879+ if ( gsm7bits_extend_to_unicode[nn] == c ) {
880+ bwriter_add7( writer, GSM_7BITS_ESCAPE );
881+ bwriter_add7( writer, nn );
882+ goto NextUnicode;
883+ }
884+ }
885+
886+ /* unknown */
887+ bwriter_add7( writer, 0x20 );
888+
889+ NextUnicode:
890+ ;
891+ }
892+ return bwriter_done( writer );
893+}
894+
895+
896+int
897+ucs2_to_gsm8( cbytes_t ucs2, int ucs2len, bytes_t dst )
898+{
899+ const unsigned char* ucs2end = ucs2 + ucs2len*2;
900+ bytes_t dst0 = dst;
901+
902+ while ( ucs2 < ucs2end ) {
903+ int c = *ucs2++;
904+ int nn;
905+
906+ for (nn = 0; nn < 128; nn++) {
907+ if ( gsm7bits_to_unicode[nn] == c ) {
908+ *dst++ = (byte_t)nn;
909+ goto NextUnicode;
910+ }
911+ }
912+ for (nn = 0; nn < 128; nn++) {
913+ if ( gsm7bits_extend_to_unicode[nn] == c ) {
914+ dst[0] = (byte_t) GSM_7BITS_ESCAPE;
915+ dst[1] = (byte_t) nn;
916+ dst += 2;
917+ goto NextUnicode;
918+ }
919+ }
920+
921+ /* unknown */
922+ *dst++ = 0x20;
923+
924+ NextUnicode:
925+ ;
926+ }
927+ return (dst - dst0);
928+}
929+
930+int
931+gsm_bcdnum_to_ascii( cbytes_t bcd, int count, bytes_t dst )
932+{
933+ int result = 0;
934+ int shift = 0;
935+
936+ while (count > 0) {
937+ int c = (bcd[0] >> shift) & 0xf;
938+
939+ if (c == 15 && count == 1) /* ignore trailing 0xf */
940+ break;
941+
942+ if (c >= 14)
943+ c = 0;
944+
945+ if (dst) dst[result] = "0123456789*#,N"[c];
946+ result += 1;
947+
948+ shift += 4;
949+ if (shift == 8) {
950+ shift = 0;
951+ bcd += 1;
952+ }
953+ }
954+ return result;
955+}
956+
957+
958+int
959+gsm_bcdnum_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst )
960+{
961+ cbytes_t end = ascii + asciilen;
962+ int result = 0;
963+ int phase = 0x01;
964+
965+ while (ascii < end) {
966+ int c = *ascii++;
967+
968+ if (c == '*')
969+ c = 10;
970+ else if (c == '#')
971+ c = 11;
972+ else if (c == ',')
973+ c = 12;
974+ else if (c == 'N')
975+ c = 13;
976+ else {
977+ c -= '0';
978+ if ((unsigned)c >= 10U)
979+ return -1;
980+ }
981+ phase = (phase << 4) | c;
982+ result += 1;
983+ if (phase & 0x100) {
984+ if (dst) dst[result/2] = (byte_t) phase;
985+ phase = 0x01;
986+ }
987+ }
988+
989+ if (result & 1) {
990+ if (dst) dst[result/2] = (byte_t)(phase | 0xf0);
991+ }
992+ return result;
993+}
994+
995+/** ADN: Abbreviated Dialing Number
996+ **/
997+
998+#define ADN_FOOTER_SIZE 14
999+#define ADN_OFFSET_NUMBER_LENGTH 0
1000+#define ADN_OFFSET_TON_NPI 1
1001+#define ADN_OFFSET_NUMBER_START 2
1002+#define ADN_OFFSET_NUMBER_END 11
1003+#define ADN_OFFSET_CAPABILITY_ID 12
1004+#define ADN_OFFSET_EXTENSION_ID 13
1005+
1006+/* see 10.5.1 of 3GPP 51.011 */
1007+static int
1008+sim_adn_alpha_to_utf8( cbytes_t alpha, cbytes_t end, bytes_t dst )
1009+{
1010+ int result = 0;
1011+ int c, is_ucs2 = 0;
1012+
1013+ /* ignore trailing 0xff */
1014+ while (alpha < end && end[-1] == 0xff)
1015+ end--;
1016+
1017+ if (alpha >= end)
1018+ return 0;
1019+
1020+ if (alpha[0] == 0x80) { /* UCS/2 source encoding */
1021+ int count, len;
1022+
1023+ alpha += 1;
1024+ result = ucs2_to_utf8( alpha, (end-alpha)/2, dst );
1025+ } else {
1026+ int is_ucs2 = 0;
1027+ int len = 0, base = 0;
1028+
1029+ if (alpha+3 <= end && alpha[0] == 0x81) {
1030+ is_ucs2 = 1;
1031+ len = alpha[1];
1032+ base = alpha[2] << 7;
1033+ alpha += 3;
1034+ if (len > end-alpha)
1035+ len = end-alpha;
1036+ } else if (alpha+4 <= end && alpha[0] == 0x82) {
1037+ is_ucs2 = 1;
1038+ len = alpha[1];
1039+ base = (alpha[2] << 8) | alpha[3];
1040+ alpha += 4;
1041+ if (len > end-alpha)
1042+ len = end-alpha;
1043+ }
1044+
1045+ if (is_ucs2) {
1046+ end = alpha + len;
1047+ while (alpha < end) {
1048+ int c = alpha[0];
1049+ if (c >= 0x80) {
1050+ result += utf8_write(dst, result, base + (c & 0x7f));
1051+ alpha += 1;
1052+ } else {
1053+ /* GSM character set */
1054+ int count;
1055+ for (count = 0; alpha+count < end && alpha[count] < 128; count++)
1056+ ;
1057+ result += utf8_from_gsm8(alpha, count, (dst ? dst+result : NULL));
1058+ alpha += count;
1059+ }
1060+ }
1061+ } else {
1062+ result = utf8_from_gsm8(alpha, end-alpha, dst);
1063+ }
1064+ }
1065+ return result;
1066+}
1067+
1068+static int
1069+sim_adn_alpha_from_utf8( cbytes_t utf8, int utf8len, bytes_t dst )
1070+{
1071+ int result = 0;
1072+
1073+ if (utf8_check_gsm7(utf8, utf8len)) {
1074+ /* GSM 7-bit compatible, encode directly as 8-bit string */
1075+ result = utf8_to_gsm8(utf8, utf8len, dst);
1076+ } else {
1077+ /* otherwise, simply try UCS-2 encoding, nothing more serious at the moment */
1078+ if (dst) {
1079+ dst[0] = 0x80;
1080+ }
1081+ result = 1 + utf8_to_ucs2(utf8, utf8len, dst ? (dst+1) : NULL)*2;
1082+ }
1083+ return result;
1084+}
1085+
1086+int
1087+sim_adn_record_from_bytes( SimAdnRecord rec, cbytes_t data, int len )
1088+{
1089+ cbytes_t end = data + len;
1090+ cbytes_t footer = end - ADN_FOOTER_SIZE;
1091+ int num_len;
1092+
1093+ rec->adn.alpha[0] = 0;
1094+ rec->adn.number[0] = 0;
1095+ rec->ext_record = 0xff;
1096+
1097+ if (len < ADN_FOOTER_SIZE)
1098+ return -1;
1099+
1100+ /* alpha is optional */
1101+ if (len > ADN_FOOTER_SIZE) {
1102+ cbytes_t dataend = data + len - ADN_FOOTER_SIZE;
1103+ int count = sim_adn_alpha_to_utf8(data, dataend, NULL);
1104+
1105+ if (count > sizeof(rec->adn.alpha)-1) /* too long */
1106+ return -1;
1107+
1108+ sim_adn_alpha_to_utf8(data, dataend, rec->adn.alpha);
1109+ rec->adn.alpha[count] = 0;
1110+ }
1111+
1112+ num_len = footer[ADN_OFFSET_NUMBER_LENGTH];
1113+ if (num_len > 11)
1114+ return -1;
1115+
1116+ /* decode TON and number to ASCII, NOTE: this is lossy !! */
1117+ {
1118+ int ton = footer[ADN_OFFSET_TON_NPI];
1119+ bytes_t number = rec->adn.number;
1120+ int len = sizeof(rec->adn.number)-1;
1121+ int count;
1122+
1123+ if (ton != 0x81 && ton != 0x91)
1124+ return -1;
1125+
1126+ if (ton == 0x91) {
1127+ *number++ = '+';
1128+ len -= 1;
1129+ }
1130+
1131+ count = gsm_bcdnum_to_ascii( footer + ADN_OFFSET_NUMBER_START,
1132+ num_len*2, number );
1133+ number[count] = 0;
1134+ }
1135+ return 0;
1136+}
1137+
1138+int
1139+sim_adn_record_to_bytes( SimAdnRecord rec, bytes_t data, int datalen )
1140+{
1141+ bytes_t end = data + datalen;
1142+ bytes_t footer = end - ADN_FOOTER_SIZE;
1143+ int ton = 0x81;
1144+ cbytes_t number = rec->adn.number;
1145+ int len;
1146+
1147+ if (number[0] == '+') {
1148+ ton = 0x91;
1149+ number += 1;
1150+ }
1151+ footer[0] = (strlen(number)+1)/2 + 1;
1152+ return 0;
1153+}
--- /dev/null
+++ b/huaweigeneric-ril/gsm.h
@@ -0,0 +1,177 @@
1+#ifndef _android_gsm_h
2+#define _android_gsm_h
3+
4+/** USEFUL TYPES
5+ **/
6+
7+typedef unsigned char byte_t;
8+typedef byte_t* bytes_t;
9+typedef const byte_t* cbytes_t;
10+
11+/** BCD
12+ **/
13+
14+/* convert a 8-bit value into the corresponding nibble-bcd byte */
15+extern byte_t gsm_int_to_bcdi( int value );
16+
17+/* convert a nibble-bcd byte into an int, invalid nibbles are silently converted to 0 */
18+extern int gsm_int_from_bcdi( byte_t value );
19+
20+/** HEX
21+ **/
22+
23+/* convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even */
24+extern void gsm_hex_to_bytes ( cbytes_t hex, int hexlen, bytes_t dst );
25+
26+/* convert a byte string into a hex string, assumes 'hex' is properly sized */
27+extern void gsm_hex_from_bytes( char* hex, cbytes_t src, int srclen );
28+
29+/* convert a hexchar to an int, returns -1 on error */
30+extern int gsm_hexchar_to_int( char c );
31+
32+/* convert a hexchar to an int, returns 0 on error */
33+extern int gsm_hexchar_to_int0( char c );
34+
35+/* convert a 2-char hex value into an int, returns -1 on error */
36+extern int gsm_hex2_to_byte( const char* hex );
37+
38+/* convert a 2-char hex value into an int, returns 0 on error */
39+extern int gsm_hex2_to_byte0( const char* hex );
40+
41+/* convert a 4-char hex value into an int, returns -1 on error */
42+extern int gsm_hex4_to_short( const char* hex );
43+
44+/* convert a 4-char hex value into an int, returns 0 on error */
45+extern int gsm_hex4_to_short0( const char* hex );
46+
47+/* write a byte to a 2-byte hex string */
48+extern void gsm_hex_from_byte( char* hex, int val );
49+
50+extern void gsm_hex_from_short( char* hex, int val );
51+
52+/** UTF-8 and GSM Alphabet
53+ **/
54+
55+/* check that a given utf8 string is well-formed, returns 1 on success, 0 otherwise */
56+extern int utf8_check( cbytes_t utf8, int utf8len );
57+
58+/* check that all characters in a given utf8 string can be encoded into the GSM alphabet.
59+ returns 1 if TRUE, 0 otherwise */
60+extern int utf8_check_gsm7( cbytes_t utf8, int utf8len );
61+
62+/* convert a utf-8 string into a GSM septet string, assumes 'dst' is NULL or is properly sized,
63+ and that all characters are representable. 'offset' is the starting bit offset in 'dst'.
64+ non-representable characters are replaced by spaces.
65+ returns the number of septets, */
66+extern int utf8_to_gsm7( cbytes_t utf8, int utf8len, bytes_t dst, int offset );
67+
68+/* convert a utf8 string into an array of 8-bit unpacked GSM septets,
69+ * assumes 'dst' is NULL or is properly sized, returns the number of GSM bytes */
70+extern int utf8_to_gsm8( cbytes_t utf8, int utf8len, bytes_t dst );
71+
72+/* convert a GSM septets string into a utf-8 byte string. assumes that 'utf8' is NULL or properly
73+ sized. 'offset' is the starting bit offset in 'src', 'count' is the number of input septets.
74+ return the number of utf8 bytes. */
75+extern int utf8_from_gsm7( cbytes_t src, int offset, int count, bytes_t utf8 );
76+
77+/* convert an unpacked 8-bit GSM septets string into a utf-8 byte string. assumes that 'utf8'
78+ is NULL or properly sized. 'count' is the number of input bytes.
79+ returns the number of utf8 bytes */
80+extern int utf8_from_gsm8( cbytes_t src, int count, bytes_t utf8 );
81+
82+
83+/** UCS-2 and GSM Alphabet
84+ **
85+ ** Note that here, 'ucs2' really refers to non-aligned UCS2-BE, as used by the GSM standard
86+ **/
87+
88+/* check that all characters in a given ucs2 string can be encoded into the GSM alphabet.
89+ returns 1 if TRUE, 0 otherwise */
90+extern int ucs2_check_gsm7( cbytes_t ucs2, int ucs2len );
91+
92+/* convert a ucs2 string into a GSM septet string, assumes 'dst' is NULL or properly sized,
93+ 'offset' is the starting bit offset in 'dst'. non-representable characters are replaced
94+ by spaces. returns the number of septets */
95+extern int ucs2_to_gsm7( cbytes_t ucs2, int ucs2len, bytes_t dst, int offset );
96+
97+/* convert a ucs2 string into a GSM septet string, assumes 'dst' is NULL or properly sized,
98+ non-representable characters are replaced by spaces. returns the number of bytes */
99+extern int ucs2_to_gsm8( cbytes_t ucs2, int ucs2len, bytes_t dst );
100+
101+/* convert a GSM septets string into a ucs2 string. assumes that 'ucs2' is NULL or
102+ properly sized. 'offset' is the starting bit offset in 'src', 'count' is the number
103+ of input septets. return the number of ucs2 characters (not bytes) */
104+extern int ucs2_from_gsm7( bytes_t ucs2, cbytes_t src, int offset, int count );
105+
106+/* convert an 8-bit unpacked GSM septets string into a ucs2 string. assumes that 'ucs2'
107+ is NULL or properly sized. 'count' is the number of input septets. return the number
108+ of ucs2 characters (not bytes) */
109+extern int ucs2_from_gsm8( bytes_t ucs2, cbytes_t src, int count );
110+
111+
112+/** UCS2 to/from UTF8
113+ **/
114+
115+/* convert a ucs2 string into a utf8 byte string, assumes 'utf8' NULL or properly sized.
116+ returns the number of utf8 bytes*/
117+extern int ucs2_to_utf8( cbytes_t ucs2, int ucs2len, bytes_t utf8 );
118+
119+/* convert a utf8 byte string into a ucs2 string, assumes 'ucs2' NULL or properly sized.
120+ returns the number of ucs2 chars */
121+extern int utf8_to_ucs2( cbytes_t utf8, int utf8len, bytes_t ucs2 );
122+
123+/* try to skip a given number of characters in a utf-8 byte string, return new position */
124+extern cbytes_t utf8_skip( cbytes_t utf8, cbytes_t utf8end, int count);
125+
126+/** Dial Numbers: TON byte + 'count' bcd numbers
127+ **/
128+
129+/* convert a bcd-coded GSM dial number into an ASCII string (not zero-terminated)
130+ assumes 'dst' is NULL or properly sized, returns 0 in case of success, -1 in case of error.
131+ 'num_digits' is the number of digits, not input bytes. a trailing 0xf0 is ignored automatically
132+ return the number of ASCII chars */
133+extern int gsm_bcdnum_to_ascii ( cbytes_t bcd, int num_digits, bytes_t dst );
134+
135+/* convert an ASCII dial-number into a bcd-coded string, returns the number of 4-bit nibbles written, */
136+extern int gsm_bcdnum_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst );
137+
138+/** ADN: Abbreviated Dialing Numbers
139+ **/
140+#define SIM_ADN_MAX_ALPHA 20 /* maximum number of characters in ADN alpha tag */
141+#define SIM_ADN_MAX_NUMBER 20 /* maximum digits in ADN number */
142+
143+typedef struct {
144+ byte_t alpha [ SIM_ADN_MAX_ALPHA*3+1 ]; /* alpha tag in zero-terminated utf-8 */
145+ char number[ SIM_ADN_MAX_NUMBER+1 ]; /* dialing number in zero-terminated ASCII */
146+}
147+SimAdnRec, *SimAdn;
148+
149+typedef struct {
150+ SimAdnRec adn;
151+ byte_t ext_record; /* 0 or 0xFF means no extension */
152+}
153+SimAdnRecordRec, *SimAdnRecord;
154+
155+extern int sim_adn_record_from_bytes( SimAdnRecord rec, cbytes_t data, int datalen );
156+extern int sim_adn_record_to_bytes ( SimAdnRecord rec, bytes_t data, int datalen );
157+
158+/** ROPES
159+ **/
160+
161+typedef struct {
162+ bytes_t data;
163+ int max;
164+ int pos;
165+ int error;
166+ unsigned char data0[16];
167+} GsmRopeRec, *GsmRope;
168+
169+extern void gsm_rope_init( GsmRope rope );
170+extern void gsm_rope_init_alloc( GsmRope rope, int alloc );
171+extern int gsm_rope_done( GsmRope rope );
172+extern bytes_t gsm_rope_done_acquire( GsmRope rope, int *psize );
173+extern void gsm_rope_add_c( GsmRope rope, char c );
174+extern void gsm_rope_add( GsmRope rope, const void* str, int len );
175+extern void* gsm_rope_reserve( GsmRope rope, int len );
176+
177+#endif /* _android_gsm_h */
--- /dev/null
+++ b/huaweigeneric-ril/huaweigeneric-ril.c
@@ -0,0 +1,6564 @@
1+/* //device/system/htcgeneric-ril/htcgeneric-ril.c
2+ **
3+ ** Copyright 2006, The Android Open Source Project
4+ ** Copyright 2012 Eduardo Jos[e Tagle <ejtagle@tutopia.com>
5+ **
6+ ** Licensed under the Apache License, Version 2.0 (the "License");
7+ ** you may not use this file except in compliance with the License.
8+ ** You may obtain a copy of the License at
9+ **
10+ ** http://www.apache.org/licenses/LICENSE-2.0
11+ **
12+ ** Unless required by applicable law or agreed to in writing, software
13+ ** distributed under the License is distributed on an "AS IS" BASIS,
14+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+ ** See the License for the specific language governing permissions and
16+ ** limitations under the License.
17+ */
18+
19+/*
20+AT^CURC=0
21+ATQ0V1
22+
23+^MODE:
24+^RSSI:
25+^SRVST:
26++CCCM:
27+^CONN:
28+^CEND:
29++CDSI:
30+^SMMEMFULL:
31++CSSU:
32+^DCONN
33+^DEND
34+^SIMST ¡
35++CRING:
36+AT^SYSCFG=2,3,%s,1,2
37+^RSSI
38+^SMMEMFULL
39+*/
40+
41+/*
42+AT^SYSCFG=2,1,3FFFFFFF,1,2 for GPRS/EDGE Preferred
43+AT^SYSCFG=2,2,3FFFFFFF,1,2 for 3G Preferred
44+AT^SYSCFG=13,1,3FFFFFFF,1,2 for GPRS/EDGE Only
45+AT^SYSCFG=14,2,3FFFFFFF,1,2 for 3G Only
46+
47+The third parameter, 0x3FFFFFFF tells the card to use all bands. A value of 0x400380 here means GSM900/1800/WCDMA2100 only and a value of 0x200000 here means GSM1900 only.
48+
49+I don't know what the final "1,2" parameter is for. But for some it has to be "2,4" instead for some reason.
50+
51+The status updates from the second port are prefixed with a caret and are of these forms:
52+
53+^MODE:3,2 indicates GPRS
54+^MODE:3,3 indicates EDGE
55+^MODE:5,4 indicates 3G
56+^MODE:5,5 indicates HSDPA
57+
58+^DSFLOWRPT:n,n,n,n,n,n,n
59+n1 is the duration of the connection in seconds
60+n2 is transmit (upload) speed in bytes per second (n2 *8 / 1000 will give you kbps)
61+n3 is receive (download) speed in bytes per second (n3 *8 / 1000 will give you kbps)
62+n4 is the total bytes transmitted during this session
63+n5 is the total bytes transmitted during this session
64+n6 no idea, but I always get 0x1F40 (8000) here
65+n7 no idea, but I always get 0x7530 (30000) here
66+
67+You can reset the connection statistics by sending AT^DSFLOWCLR.
68+
69+---
70+If anyone is interested, sending DTMF signals in modem-mode (+FCLASS=0) is possible. But it is device-dependent feature.
71+For Huawei E1550 it is AT^DTMF=<n> command.
72+
73+----
74+
75+AT^CVOICE=0 Enable Voice
76+AT^CVOICE=1 Disable Voice
77+AT^CVOICE=? Check status
78+
79+AT^CVOICE? [len=10]
80+ [len=0]
81+ <LF>^CVOICE:0,8000,16,20 [len=21] This answer tells you voice parameters (8 khz,16 bits, 20 ms)
82+ <LF>
83+
84+----
85+That need to be tested but voice activation should work with:
86+AT^U2DIAG=5
87+
88+then the modem become 0x12d1:0x140c a flash drive.
89+
90+then I plug in on my Linux Ubuntu computer, use minicom and type AT^U2DIAG=0 to deactivate the damn flash drive.
91+
92+Maybe it's better to first type AT^U2DIAG=0 and then AT^U2DIAG=5 ...
93+
94+Regards, Phil.
95+*/
96+
97+#define LOG_NDEBUG 0
98+#define LOG_TAG "RIL"
99+#include <utils/Log.h>
100+
101+#include <telephony/ril.h>
102+#include <stdio.h>
103+#include <assert.h>
104+#include <string.h>
105+#include <errno.h>
106+#include <unistd.h>
107+#include <sys/types.h>
108+#include <sys/stat.h>
109+#include <fcntl.h>
110+#include <pthread.h>
111+#include <alloca.h>
112+#include "atchannel.h"
113+#include "at_tok.h"
114+#include "misc.h"
115+#include "gsm.h"
116+#include "requestdatahandler.h"
117+#include "fcp_parser.h"
118+#include "audiochannel.h"
119+#include <getopt.h>
120+#include <sys/socket.h>
121+#include <cutils/sockets.h>
122+#include <termios.h>
123+#include <cutils/properties.h>
124+#include <stdbool.h>
125+
126+#define D LOGI
127+
128+#define RIL_VERSION_STRING "Huawei-ril 1.0.0.0"
129+
130+#define timespec_cmp(a, b, op) \
131+ ((a).tv_sec == (b).tv_sec \
132+ ? (a).tv_nsec op (b).tv_nsec \
133+ : (a).tv_sec op (b).tv_sec)
134+
135+#define TIMEOUT_SEARCH_FOR_TTY 5 /* Poll every Xs for the port*/
136+#define TIMEOUT_EMRDY 10 /* Module should respond at least within 10s */
137+#define MAX_BUF 1024
138+
139+/* pathname returned from RIL_REQUEST_SETUP_DATA_CALL / RIL_REQUEST_SETUP_DEFAULT_PDP */
140+#define PPP_TTY_PATH "ppp0"
141+
142+
143+/** declarations */
144+static const char *getVersion();
145+static void signalCloseQueues(void);
146+static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
147+static int onSupports (int requestCode);
148+static void onCancel (RIL_Token t);
149+extern const char *requestToString(int request);
150+
151+static RIL_RadioState getRadioState();
152+static int isRadioOn();
153+static int getCardStatus(RIL_CardStatus_v6 **pp_card_status);
154+static void freeCardStatus(RIL_CardStatus_v6 *p_card_status);
155+static void onDataCallListChanged(void *param);
156+static int killConn(const char * cid);
157+static int wait_for_property(const char *name, const char *desired_value, int maxwait);
158+static void checkMessageStorageReady(void *p);
159+static void onSIMReady(void *p);
160+static void pollSIMState(void *param);
161+static void checkMessageStorageReady(void *p);
162+
163+extern const char * requestToString(int request);
164+
165+/*** Static Variables ***/
166+static const RIL_RadioFunctions s_callbacks = {
167+ RIL_VERSION,
168+ onRequest,
169+ getRadioState,
170+ onSupports,
171+ onCancel,
172+ getVersion
173+};
174+
175+static RIL_RadioState sState = RADIO_STATE_UNAVAILABLE;
176+static pthread_mutex_t s_state_mutex = PTHREAD_MUTEX_INITIALIZER;
177+static const struct timespec TIMEVAL_SIMPOLL = {1,0};
178+
179+
180+#ifdef RIL_SHLIB
181+static const struct RIL_Env *s_rilenv;
182+#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
183+#define RIL_onUnsolicitedResponse(a,b,c) s_rilenv->OnUnsolicitedResponse(a,b,c)
184+#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
185+#endif
186+
187+typedef struct RILRequest {
188+ int request;
189+ void *data;
190+ size_t datalen;
191+ RIL_Token token;
192+ struct RILRequest *next;
193+} RILRequest;
194+
195+typedef struct RILEvent {
196+ void (*eventCallback) (void *param);
197+ void *param;
198+ struct timespec abstime;
199+ struct RILEvent *next;
200+ struct RILEvent *prev;
201+} RILEvent;
202+
203+typedef struct RequestQueue {
204+ pthread_mutex_t queueMutex;
205+ pthread_cond_t cond;
206+ RILRequest *requestList;
207+ RILEvent *eventList;
208+ char enabled;
209+ char closed;
210+} RequestQueue;
211+
212+static RequestQueue s_requestQueue = {
213+ PTHREAD_MUTEX_INITIALIZER,
214+ PTHREAD_COND_INITIALIZER,
215+ NULL,
216+ NULL,
217+ 1,
218+ 1
219+};
220+
221+static RequestQueue *s_requestQueues[] = {
222+ &s_requestQueue
223+};
224+
225+/* The Audio channel */
226+static struct GsmAudioTunnel sAudioChannel = GSM_AUDIO_CHANNEL_STATIC_INIT;
227+static char sAudioDevice[64] = {0};
228+
229+/* Starts the audio tunnel channel */
230+static void startAudioTunnel(void)
231+{
232+ ATResponse *atResponse = NULL;
233+ int err;
234+ char *line;
235+ int voice_disabled = 0, sampling_rate = 8000,
236+ bits_per_sample = 16, framesize_ms = 20;
237+
238+ if (sAudioChannel.running)
239+ return;
240+
241+ // Enable voice function
242+ err = at_send_command("AT^CVOICE=0");
243+ if (err != AT_NOERROR)
244+ goto error;
245+
246+ // Check status.
247+ err = at_send_command_singleline("AT^CVOICE=?", "^CVOICE:", &atResponse);
248+ if (err != AT_NOERROR)
249+ goto error;
250+
251+ line = atResponse->p_intermediates->line;
252+ err = at_tok_start(&line);
253+ if (err < 0) goto error;
254+
255+ err = at_tok_nextint(&line, &voice_disabled);
256+ if (err < 0) goto error;
257+
258+ err = at_tok_nextint(&line, &sampling_rate);
259+ if (err < 0) goto error;
260+
261+ err = at_tok_nextint(&line, &bits_per_sample);
262+ if (err < 0) goto error;
263+
264+ err = at_tok_nextint(&line, &framesize_ms);
265+ if (err < 0) goto error;
266+
267+ /* Switch to audio from USB1 */
268+ err = at_send_command("AT^DDSETEX=2");
269+ if (err != AT_NOERROR)
270+ goto error;
271+
272+ /* Start the audio channel */
273+ err = gsm_audio_tunnel_start(&sAudioChannel,sAudioDevice,
274+ sampling_rate, (sampling_rate * framesize_ms) / 1000, bits_per_sample );
275+ if (err)
276+ goto error;
277+
278+ LOGE("Audio Tunnel enabled");
279+ at_response_free(atResponse);
280+ return;
281+
282+error:
283+ LOGE("Failed to start audio tunnel");
284+
285+ at_response_free(atResponse);
286+ return;
287+}
288+
289+/* Stops the audio tunnel channel */
290+static void stopAudioTunnel(void)
291+{
292+ if (!sAudioChannel.running)
293+ return;
294+
295+ // Stop the audio tunnel
296+ gsm_audio_tunnel_stop(&sAudioChannel);
297+
298+ D("Audio Tunnel disabled");
299+}
300+
301+/**
302+ * Enqueue a RILEvent to the request queue.
303+ */
304+static void enqueueRILEvent(void (*callback) (void *param),
305+ void *param, const struct timespec *relativeTime)
306+{
307+ int err;
308+ struct timespec ts;
309+ char done = 0;
310+ RequestQueue *q = NULL;
311+
312+ RILEvent *e = (RILEvent *) malloc(sizeof(RILEvent));
313+ memset(e, 0, sizeof(RILEvent));
314+
315+ e->eventCallback = callback;
316+ e->param = param;
317+
318+ if (relativeTime == NULL) {
319+ relativeTime = (const struct timespec *) alloca(sizeof(struct timespec));
320+ memset((struct timespec *) relativeTime, 0, sizeof(struct timespec));
321+ }
322+
323+ clock_gettime(CLOCK_MONOTONIC, &ts);
324+
325+ e->abstime.tv_sec = ts.tv_sec + relativeTime->tv_sec;
326+ e->abstime.tv_nsec = ts.tv_nsec + relativeTime->tv_nsec;
327+
328+ if (e->abstime.tv_nsec > 1000000000) {
329+ e->abstime.tv_sec++;
330+ e->abstime.tv_nsec -= 1000000000;
331+ }
332+
333+ q = &s_requestQueue;
334+
335+again:
336+ if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
337+ LOGE("%s() failed to take queue mutex: %s!", __func__, strerror(err));
338+
339+ if (q->eventList == NULL) {
340+ q->eventList = e;
341+ } else {
342+ if (timespec_cmp(q->eventList->abstime, e->abstime, > )) {
343+ e->next = q->eventList;
344+ q->eventList->prev = e;
345+ q->eventList = e;
346+ } else {
347+ RILEvent *tmp = q->eventList;
348+ do {
349+ if (timespec_cmp(tmp->abstime, e->abstime, > )) {
350+ tmp->prev->next = e;
351+ e->prev = tmp->prev;
352+ tmp->prev = e;
353+ e->next = tmp;
354+ break;
355+ } else if (tmp->next == NULL) {
356+ tmp->next = e;
357+ e->prev = tmp;
358+ break;
359+ }
360+ tmp = tmp->next;
361+ } while (tmp);
362+ }
363+ }
364+
365+ if ((err = pthread_cond_broadcast(&q->cond)) != 0)
366+ LOGE("%s() failed to take broadcast queue update: %s!",
367+ __func__, strerror(err));
368+
369+ if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
370+ LOGE("%s() failed to release queue mutex: %s!",
371+ __func__, strerror(err));
372+
373+}
374+
375+/** returns 1 if on, 0 if off, and -1 on error */
376+static int isRadioOn()
377+{
378+ ATResponse *atResponse = NULL;
379+ int err,ison;
380+ char *line;
381+ char ret1,ret2;
382+
383+ err = at_send_command_singleline("AT^RFSWITCH?", "^RFSWITCH:", &atResponse);
384+
385+ if (err != AT_NOERROR) {
386+ // assume radio is off
387+ goto error;
388+ }
389+
390+ line = atResponse->p_intermediates->line;
391+
392+ err = at_tok_start(&line);
393+ if (err < 0) goto error;
394+
395+ err = at_tok_nextbool(&line, &ret1);
396+ if (err < 0) goto error;
397+
398+ err = at_tok_nextbool(&line, &ret2);
399+ if (err < 0) goto error;
400+
401+ at_response_free(atResponse);
402+
403+ /* 1 is ON, 0 is OFF */
404+ ison = (ret1 == 1 && ret2 == 1);
405+
406+ LOGD("Radio is %s", ison ? "On" : "Off");
407+
408+ return ison;
409+
410+error:
411+
412+ at_response_free(atResponse);
413+ return -1;
414+}
415+
416+
417+static const char *radioStateToString(RIL_RadioState radioState)
418+{
419+ const char *state;
420+
421+ switch (radioState) {
422+ case RADIO_STATE_OFF:
423+ state = "RADIO_STATE_OFF";
424+ break;
425+ case RADIO_STATE_UNAVAILABLE:
426+ state = "RADIO_STATE_UNAVAILABLE";
427+ break;
428+ case RADIO_STATE_SIM_NOT_READY:
429+ state = "RADIO_STATE_SIM_NOT_READY";
430+ break;
431+ case RADIO_STATE_SIM_LOCKED_OR_ABSENT:
432+ state = "RADIO_STATE_SIM_LOCKED_OR_ABSENT";
433+ break;
434+ case RADIO_STATE_SIM_READY:
435+ state = "RADIO_STATE_SIM_READY";
436+ break;
437+ case RADIO_STATE_RUIM_NOT_READY:
438+ state = "RADIO_STATE_RUIM_NOT_READY";
439+ break;
440+ case RADIO_STATE_RUIM_READY:
441+ state = "RADIO_STATE_RUIM_READY";
442+ break;
443+ case RADIO_STATE_RUIM_LOCKED_OR_ABSENT:
444+ state = "RADIO_STATE_RUIM_READY";
445+ break;
446+ case RADIO_STATE_NV_NOT_READY:
447+ state = "RADIO_STATE_NV_NOT_READY";
448+ break;
449+ case RADIO_STATE_NV_READY:
450+ state = "RADIO_STATE_NV_READY";
451+ break;
452+ default:
453+ state = "RADIO_STATE_<> Unknown!";
454+ break;
455+ }
456+
457+ return state;
458+}
459+
460+
461+/**
462+ * Synchronous call from the RIL to us to return current radio state.
463+ * RADIO_STATE_UNAVAILABLE should be the initial state.
464+ */
465+static RIL_RadioState getRadioState()
466+{
467+ return sState;
468+}
469+
470+
471+static void setRadioState(RIL_RadioState newState)
472+{
473+ RIL_RadioState oldState;
474+ int err;
475+
476+ if ((err = pthread_mutex_lock(&s_state_mutex)) != 0)
477+ LOGE("%s() failed to take state mutex: %s!", __func__, strerror(err));
478+
479+ oldState = sState;
480+
481+ LOGI("%s() oldState=%s newState=%s", __func__, radioStateToString(oldState),
482+ radioStateToString(newState));
483+
484+ sState = newState;
485+
486+ if ((err = pthread_mutex_unlock(&s_state_mutex)) != 0)
487+ LOGE("%s() failed to release state mutex: %s!", __func__, strerror(err));
488+
489+ /* Do these outside of the mutex. */
490+ if (sState != oldState || sState == RADIO_STATE_SIM_LOCKED_OR_ABSENT) {
491+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED,
492+ NULL, 0);
493+
494+ if (sState == RADIO_STATE_SIM_READY) {
495+ enqueueRILEvent(checkMessageStorageReady, NULL, NULL);
496+ enqueueRILEvent(onSIMReady, NULL, NULL);
497+ } else if (sState == RADIO_STATE_SIM_NOT_READY)
498+ enqueueRILEvent(pollSIMState, NULL, NULL);
499+ }
500+}
501+
502+typedef enum {
503+ SIM_ABSENT = 0, /* SIM card is not inserted */
504+ SIM_NOT_READY = 1, /* SIM card is not ready */
505+ SIM_READY = 2, /* radiostate = RADIO_STATE_SIM_READY */
506+ SIM_PIN = 3, /* SIM PIN code lock */
507+ SIM_PUK = 4, /* SIM PUK code lock */
508+ SIM_NETWORK_PERSO = 5, /* Network Personalization lock */
509+ SIM_PIN2 = 6, /* SIM PIN2 lock */
510+ SIM_PUK2 = 7, /* SIM PUK2 lock */
511+ SIM_NETWORK_SUBSET_PERSO = 8, /* Network Subset Personalization */
512+ SIM_SERVICE_PROVIDER_PERSO = 9, /* Service Provider Personalization */
513+ SIM_CORPORATE_PERSO = 10, /* Corporate Personalization */
514+ SIM_SIM_PERSO = 11, /* SIM/USIM Personalization */
515+ SIM_STERICSSON_LOCK = 12, /* ST-Ericsson Extended SIM */
516+ SIM_BLOCKED = 13, /* SIM card is blocked */
517+ SIM_PERM_BLOCKED = 14, /* SIM card is permanently blocked */
518+ SIM_NETWORK_PERSO_PUK = 15, /* Network Personalization PUK */
519+ SIM_NETWORK_SUBSET_PERSO_PUK = 16, /* Network Subset Perso. PUK */
520+ SIM_SERVICE_PROVIDER_PERSO_PUK = 17,/* Service Provider Perso. PUK */
521+ SIM_CORPORATE_PERSO_PUK = 18, /* Corporate Personalization PUK */
522+ SIM_SIM_PERSO_PUK = 19, /* SIM Personalization PUK (unused) */
523+ SIM_PUK2_PERM_BLOCKED = 20 /* PUK2 is permanently blocked */
524+} SIM_Status;
525+
526+typedef enum {
527+ UICC_TYPE_UNKNOWN,
528+ UICC_TYPE_SIM,
529+ UICC_TYPE_USIM,
530+ UICC_TYPE_UIM,
531+} UICC_Type;
532+
533+/** Returns one of SIM_*. Returns SIM_NOT_READY on error. */
534+static SIM_Status getSIMStatus(void)
535+{
536+ ATResponse *atResponse = NULL;
537+ int err;
538+ SIM_Status ret = SIM_ABSENT;
539+ char *cpinLine;
540+ char *cpinResult;
541+
542+ if (getRadioState() == RADIO_STATE_OFF ||
543+ getRadioState() == RADIO_STATE_UNAVAILABLE) {
544+ return SIM_NOT_READY;
545+ }
546+
547+ err = at_send_command_singleline("AT+CPIN?", "+CPIN:", &atResponse);
548+
549+ if (err != AT_NOERROR) {
550+ if (at_get_error_type(err) == AT_ERROR) {
551+ ret = SIM_NOT_READY;
552+ goto done;
553+ }
554+
555+ switch (at_get_cme_error(err)) {
556+ case CME_SIM_NOT_INSERTED:
557+ ret = SIM_ABSENT;
558+ break;
559+ case CME_SIM_PIN_REQUIRED:
560+ ret = SIM_PIN;
561+ break;
562+ case CME_SIM_PUK_REQUIRED:
563+ ret = SIM_PUK;
564+ break;
565+ case CME_SIM_PIN2_REQUIRED:
566+ ret = SIM_PIN2;
567+ break;
568+ case CME_SIM_PUK2_REQUIRED:
569+ ret = SIM_PUK2;
570+ break;
571+ case CME_NETWORK_PERSONALIZATION_PIN_REQUIRED:
572+ ret = SIM_NETWORK_PERSO;
573+ break;
574+ case CME_NETWORK_PERSONALIZATION_PUK_REQUIRED:
575+ ret = SIM_NETWORK_PERSO_PUK;
576+ break;
577+ case CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED:
578+ ret = SIM_NETWORK_SUBSET_PERSO;
579+ break;
580+ case CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED:
581+ ret = SIM_NETWORK_SUBSET_PERSO_PUK;
582+ break;
583+ case CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED:
584+ ret = SIM_SERVICE_PROVIDER_PERSO;
585+ break;
586+ case CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED:
587+ ret = SIM_SERVICE_PROVIDER_PERSO_PUK;
588+ break;
589+ case CME_PH_SIMLOCK_PIN_REQUIRED: /* PUK not in use by modem */
590+ ret = SIM_SIM_PERSO;
591+ break;
592+ case CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED:
593+ ret = SIM_CORPORATE_PERSO;
594+ break;
595+ case CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED:
596+ ret = SIM_CORPORATE_PERSO_PUK;
597+ break;
598+ default:
599+ ret = SIM_NOT_READY;
600+ break;
601+ }
602+ return ret;
603+ }
604+
605+ /* CPIN? has succeeded, now look at the result. */
606+
607+ cpinLine = atResponse->p_intermediates->line;
608+ err = at_tok_start(&cpinLine);
609+
610+ if (err < 0) {
611+ ret = SIM_NOT_READY;
612+ goto done;
613+ }
614+
615+ err = at_tok_nextstr(&cpinLine, &cpinResult);
616+
617+ if (err < 0) {
618+ ret = SIM_NOT_READY;
619+ goto done;
620+ }
621+
622+ if (0 == strcmp(cpinResult, "READY")) {
623+ ret = SIM_READY;
624+ } else if (0 == strcmp(cpinResult, "SIM PIN")) {
625+ ret = SIM_PIN;
626+ } else if (0 == strcmp(cpinResult, "SIM PUK")) {
627+ ret = SIM_PUK;
628+ } else if (0 == strcmp(cpinResult, "SIM PIN2")) {
629+ ret = SIM_PIN2;
630+ } else if (0 == strcmp(cpinResult, "SIM PUK2")) {
631+ ret = SIM_PUK2;
632+ } else if (0 == strcmp(cpinResult, "PH-NET PIN")) {
633+ ret = SIM_NETWORK_PERSO;
634+ } else if (0 == strcmp(cpinResult, "PH-NETSUB PIN")) {
635+ ret = SIM_NETWORK_SUBSET_PERSO;
636+ } else if (0 == strcmp(cpinResult, "PH-SP PIN")) {
637+ ret = SIM_SERVICE_PROVIDER_PERSO;
638+ } else if (0 == strcmp(cpinResult, "PH-CORP PIN")) {
639+ ret = SIM_CORPORATE_PERSO;
640+ } else if (0 == strcmp(cpinResult, "PH-SIMLOCK PIN")) {
641+ ret = SIM_SIM_PERSO;
642+ } else if (0 == strcmp(cpinResult, "PH-ESL PIN")) {
643+ ret = SIM_STERICSSON_LOCK;
644+ } else if (0 == strcmp(cpinResult, "BLOCKED")) {
645+ int numRetries = 3;
646+ if (numRetries == -1 || numRetries == 0)
647+ ret = SIM_PERM_BLOCKED;
648+ else
649+ ret = SIM_PUK2_PERM_BLOCKED;
650+ } else if (0 == strcmp(cpinResult, "PH-SIM PIN")) {
651+ /*
652+ * Should not happen since lock must first be set from the phone.
653+ * Setting this lock is not supported by Android.
654+ */
655+ ret = SIM_BLOCKED;
656+ } else {
657+ /* Unknown locks should not exist. Defaulting to "sim absent" */
658+ ret = SIM_ABSENT;
659+ }
660+done:
661+ at_response_free(atResponse);
662+ return ret;
663+}
664+
665+
666+/**
667+ * SIM ready means any commands that access the SIM will work, including:
668+ * AT+CPIN, AT+CSMS, AT+CNMI, AT+CRSM
669+ * (all SMS-related commands).
670+ */
671+static void pollSIMState(void *param)
672+{
673+ if (((int) param) != 1 &&
674+ getRadioState() != RADIO_STATE_SIM_NOT_READY &&
675+ getRadioState() != RADIO_STATE_SIM_LOCKED_OR_ABSENT)
676+ /* No longer valid to poll. */
677+ return;
678+
679+ switch (getSIMStatus()) {
680+ case SIM_NOT_READY:
681+ LOGI("SIM_NOT_READY, poll for sim state.");
682+ enqueueRILEvent(pollSIMState, NULL, &TIMEVAL_SIMPOLL);
683+ return;
684+
685+ case SIM_PIN2:
686+ case SIM_PUK2:
687+ case SIM_PUK2_PERM_BLOCKED:
688+ case SIM_READY:
689+ setRadioState(RADIO_STATE_SIM_READY);
690+ return;
691+ case SIM_ABSENT:
692+ case SIM_PIN:
693+ case SIM_PUK:
694+ case SIM_NETWORK_PERSO:
695+ case SIM_NETWORK_SUBSET_PERSO:
696+ case SIM_SERVICE_PROVIDER_PERSO:
697+ case SIM_CORPORATE_PERSO:
698+ case SIM_SIM_PERSO:
699+ case SIM_STERICSSON_LOCK:
700+ case SIM_BLOCKED:
701+ case SIM_PERM_BLOCKED:
702+ case SIM_NETWORK_PERSO_PUK:
703+ case SIM_NETWORK_SUBSET_PERSO_PUK:
704+ case SIM_SERVICE_PROVIDER_PERSO_PUK:
705+ case SIM_CORPORATE_PERSO_PUK:
706+ /* pass through, do not break */
707+ default:
708+ setRadioState(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
709+ return;
710+ }
711+}
712+
713+
714+
715+static void sendCallStateChanged(void *param)
716+{
717+ RIL_onUnsolicitedResponse (
718+ RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
719+ NULL, 0);
720+}
721+
722+
723+static int clccStateToRILState(int state, RIL_CallState *p_state)
724+
725+{
726+ switch(state) {
727+ case 0: *p_state = RIL_CALL_ACTIVE; return 0;
728+ case 1: *p_state = RIL_CALL_HOLDING; return 0;
729+ case 2: *p_state = RIL_CALL_DIALING; return 0;
730+ case 3: *p_state = RIL_CALL_ALERTING; return 0;
731+ case 4: *p_state = RIL_CALL_INCOMING; return 0;
732+ case 5: *p_state = RIL_CALL_WAITING; return 0;
733+ default:
734+ LOGE("Unsupported call state: %d\n",state);
735+ return -1;
736+ }
737+}
738+
739+/**
740+ * Note: directly modified line and has *p_call point directly into
741+ * modified line
742+ */
743+static int callFromCLCCLine(char *line, RIL_Call *p_call)
744+{
745+ //+CLCC: 1,0,2,0,0,\"+18005551212\",145
746+ // index,isMT,state,mode,isMpty(,number,TOA)?
747+
748+ int err;
749+ int state;
750+ int mode;
751+
752+ err = at_tok_start(&line);
753+ if (err < 0) goto error;
754+
755+ err = at_tok_nextint(&line, &(p_call->index));
756+ if (err < 0) goto error;
757+
758+ err = at_tok_nextbool(&line, &(p_call->isMT));
759+ if (err < 0) goto error;
760+
761+ err = at_tok_nextint(&line, &state);
762+ if (err < 0) goto error;
763+
764+ err = clccStateToRILState(state, &(p_call->state));
765+ if (err < 0) goto error;
766+
767+ err = at_tok_nextint(&line, &mode);
768+ if (err < 0) goto error;
769+
770+ p_call->isVoice = (mode == 0);
771+
772+ err = at_tok_nextbool(&line, &(p_call->isMpty));
773+ if (err < 0) goto error;
774+
775+ if (at_tok_hasmore(&line)) {
776+ err = at_tok_nextstr(&line, &(p_call->number));
777+
778+ /* tolerate null here */
779+ if (err < 0) return 0;
780+
781+ // Some lame implementations return strings
782+ // like "NOT AVAILABLE" in the CLCC line
783+ if (p_call->number != NULL
784+ && 0 == strspn(p_call->number, "+0123456789")
785+ ) {
786+ p_call->number = NULL;
787+ }
788+
789+ err = at_tok_nextint(&line, &p_call->toa);
790+ if (err < 0) goto error;
791+ }
792+
793+ return 0;
794+
795+error:
796+ LOGE("invalid CLCC line\n");
797+ return -1;
798+}
799+
800+static const struct timespec TIMEVAL_CALLSTATEPOLL = {0,500000};
801+
802+static void requestGetCurrentCalls(void *data, size_t datalen, RIL_Token t)
803+{
804+ int err,fd;
805+ ATResponse *atResponse;
806+ ATLine *p_cur;
807+ int countCalls;
808+ RIL_Call *p_calls;
809+ RIL_Call **pp_calls;
810+ int i;
811+ char status[1];
812+ int needRepoll = 0;
813+ int countValidCalls=0;
814+
815+
816+ if(getRadioState() != RADIO_STATE_SIM_READY){
817+ /* Might be waiting for SIM PIN */
818+ RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
819+ }
820+
821+ err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &atResponse);
822+ if (err != AT_NOERROR) {
823+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
824+ at_response_free(atResponse);
825+ return;
826+ }
827+
828+ /* count the calls */
829+ for (countCalls = 0, p_cur = atResponse->p_intermediates
830+ ; p_cur != NULL
831+ ; p_cur = p_cur->p_next
832+ ) {
833+ countCalls++;
834+ }
835+
836+ /* yes, there's an array of pointers and then an array of structures */
837+ pp_calls = (RIL_Call **)alloca(countCalls * sizeof(RIL_Call *));
838+ p_calls = (RIL_Call *)alloca(countCalls * sizeof(RIL_Call));
839+ memset (p_calls, 0, countCalls * sizeof(RIL_Call));
840+
841+ /* init the pointer array */
842+ for(i = 0; i < countCalls ; i++) {
843+ pp_calls[i] = &(p_calls[i]);
844+ }
845+
846+ for (countValidCalls = 0, p_cur = atResponse->p_intermediates
847+ ; p_cur != NULL
848+ ; p_cur = p_cur->p_next
849+ ) {
850+ err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
851+
852+ if (err != 0) {
853+ continue;
854+ }
855+
856+ if (p_calls[countValidCalls].state != RIL_CALL_ACTIVE
857+ && p_calls[countValidCalls].state != RIL_CALL_HOLDING
858+ ) {
859+ needRepoll = 1;
860+ }
861+ if(p_calls[countValidCalls].isVoice) // only count voice calls
862+ countValidCalls++;
863+ }
864+
865+ LOGI("Calls=%d,Valid=%d\n",countCalls,countValidCalls);
866+
867+ /* If some voice calls are active, enable audio tunnel */
868+ if (countValidCalls) {
869+ startAudioTunnel();
870+ } else {
871+ stopAudioTunnel();
872+ }
873+
874+ RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls,
875+ countValidCalls * sizeof (RIL_Call *));
876+
877+ at_response_free(atResponse);
878+
879+ if (needRepoll) {
880+ enqueueRILEvent(sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
881+ }
882+ return;
883+
884+error:
885+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
886+ at_response_free(atResponse);
887+}
888+
889+static void requestScreenState(void *data, size_t datalen, RIL_Token t)
890+{
891+ int err, screenState;
892+
893+ assert (datalen >= sizeof(int *));
894+ screenState = ((int*)data)[0];
895+
896+ if (screenState == 1) {
897+ /* Screen is on - be sure to enable all unsolicited notifications again */
898+
899+ /* Enable proactive network registration notifications */
900+ err = at_send_command("AT+CREG=2");
901+ if (err != AT_NOERROR) goto error;
902+
903+ /* Enable proactive network registration notifications */
904+ err = at_send_command("AT+CGREG=2");
905+ if (err != AT_NOERROR) goto error;
906+
907+ /* Enable unsolicited reports */
908+ err = at_send_command("AT^CURC=1");
909+ if (err != AT_NOERROR) goto error;
910+
911+ /* Enable GPRS reporting */
912+ err = at_send_command("AT+CGEREP=1,0");
913+ if (err != AT_NOERROR) goto error;
914+
915+
916+
917+ } else if (screenState == 0) {
918+
919+ /* Screen is off - disable all unsolicited notifications */
920+ err = at_send_command("AT+CREG=0");
921+ if (err != AT_NOERROR) goto error;
922+ err = at_send_command("AT+CGREG=0");
923+ if (err != AT_NOERROR) goto error;
924+ err = at_send_command("AT^CURC=0");
925+ if (err != AT_NOERROR) goto error;
926+ err = at_send_command("AT+CGEREP=0,0");
927+ if (err != AT_NOERROR) goto error;
928+
929+
930+ } else {
931+ /* Not a defined value - error */
932+ goto error;
933+ }
934+
935+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
936+ return;
937+
938+error:
939+ LOGE("ERROR: requestScreenState failed");
940+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
941+}
942+
943+
944+/* wait for a propertyvalue change */
945+static int wait_for_property(const char *name, const char *desired_value, int maxwait)
946+{
947+ char value[PROPERTY_VALUE_MAX] = {'\0'};
948+ int maxnaps = maxwait / 1;
949+
950+ if (maxnaps < 1) {
951+ maxnaps = 1;
952+ }
953+
954+ while (maxnaps-- > 0) {
955+ usleep(1000000);
956+ if (property_get(name, value, NULL)) {
957+ if (desired_value == NULL ||
958+ strcmp(value, desired_value) == 0) {
959+ return 0;
960+ }
961+ }
962+ }
963+ return -1; /* failure */
964+}
965+
966+static int killConn(const char * cid)
967+{
968+ int err;
969+ int fd;
970+ int i=0;
971+
972+ D("killConn");
973+
974+#if 0
975+ while ((fd = open("/sys/class/net/ppp0/ifindex",O_RDONLY)) > 0)
976+ {
977+ if(i%5 == 0)
978+ system("killall pppd");
979+ if(i>25)
980+ goto error;
981+ i++;
982+ close(fd);
983+ sleep(2);
984+ }
985+#elif 0
986+ // Requires root access...
987+ property_set("ctl.stop", "pppd_gprs");
988+ if (wait_for_property("init.svc.pppd_gprs", "stopped", 10) < 0) {
989+ goto error;
990+ }
991+#endif
992+
993+ D("killall pppd finished");
994+
995+ err = at_send_command("AT+CGACT=0,%s", cid);
996+ if (err != AT_NOERROR)
997+ goto error;
998+
999+ at_send_command("ATH");
1000+ return 0;
1001+
1002+error:
1003+ return -1;
1004+}
1005+
1006+
1007+//static char userPassStatic[512] = "preload";
1008+
1009+static void requestSetupDefaultPDP(void *data, size_t datalen, RIL_Token t)
1010+{
1011+ const char *apn;
1012+ const char *user = NULL;
1013+ const char *pass = NULL;
1014+ char pppdcmd[512] = "/system/bin/pppd ";
1015+ int err;
1016+ int fd, pppstatus,i;
1017+ FILE *pppconfig;
1018+ size_t cur = 0;
1019+ ssize_t written, rlen;
1020+ char status[32] = {0};
1021+ char *buffer;
1022+ long buffSize, len;
1023+ int retry = 10;
1024+
1025+ int n = 1;
1026+ RIL_Data_Call_Response_v6 responses;
1027+ char ppp_dnses[(PROPERTY_VALUE_MAX * 2) + 3] = {'\0'};
1028+ char ppp_local_ip[PROPERTY_VALUE_MAX] = {'\0'};
1029+ char ppp_dns1[PROPERTY_VALUE_MAX] = {'\0'};
1030+ char ppp_dns2[PROPERTY_VALUE_MAX] = {'\0'};
1031+ char ppp_gw[PROPERTY_VALUE_MAX] = {'\0'};
1032+
1033+ apn = ((const char **)data)[2];
1034+ user = ((char **)data)[3];
1035+ if (user == NULL || strlen(user) < 2) {
1036+ user = "dummy";
1037+ }
1038+
1039+ pass = ((char **)data)[4];
1040+ if (pass == NULL || strlen(pass) < 2) {
1041+ pass = "dummy";
1042+ }
1043+
1044+ D("requesting data connection to APN '%s'\n", apn);
1045+
1046+ // Make sure there is no existing connection or pppd instance running
1047+ if (killConn("1") < 0) {
1048+ LOGE("killConn Error!\n");
1049+ goto error;
1050+ }
1051+
1052+ /* Switch radio ON */
1053+ err = at_send_command("AT^RFSWITCH=1");
1054+ err = at_send_command("AT+CFUN=1");
1055+
1056+ /* Define the PDP context */
1057+ err = at_send_command("AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);
1058+
1059+ /* Set required QoS params to default */
1060+ err = at_send_command("AT+CGQREQ=1");
1061+
1062+ /* Set minimum QoS params to default */
1063+ err = at_send_command("AT+CGQMIN=1");
1064+
1065+ /* packet-domain event reporting */
1066+ err = at_send_command("AT+CGEREP=1,0");
1067+
1068+ /* Hangup anything that's happening there now */
1069+ err = at_send_command("AT+CGACT=0,1");
1070+
1071+ /* Start data on PDP context 1 */
1072+ err = at_send_command("ATD*99***1#");
1073+// if (err != AT_NOERROR) {
1074+// goto error;
1075+// }
1076+ sleep(2); //Wait for the modem to finish
1077+
1078+ // set up the pap/chap secrets file
1079+// sprintf(userpass, "%s * %s", user, pass);
1080+
1081+ /* start the gprs pppd */
1082+#if 1
1083+ property_get("rild.ppp.tty", pppdcmd + strlen(pppdcmd), "/dev/ttyUSB0");
1084+ strcat(pppdcmd, " call gprs");
1085+ system(pppdcmd);
1086+#else
1087+ // Requires root access...
1088+ property_set("ctl.start", "ppp");
1089+ if (wait_for_property("init.svc.ppp", "running", 10) < 0) {
1090+ LOGE("Timeout waiting init.svc.ppp - giving up!\n");
1091+ goto error;
1092+ }
1093+#endif
1094+
1095+ sleep(10); // Allow time for ip-up to complete
1096+
1097+ if (wait_for_property("net.ppp0.local-ip", NULL, 10) < 0) {
1098+ LOGE("Timeout waiting net.ppp0.local-ip - giving up!\n");
1099+ goto error;
1100+ }
1101+
1102+ property_get("net.ppp0.local-ip", ppp_local_ip, NULL);
1103+ property_get("net.dns1", ppp_dns1, NULL);
1104+ property_get("net.dns2", ppp_dns2, NULL);
1105+ property_get("net.ppp0.gw", ppp_gw, NULL);
1106+ sprintf(ppp_dnses, "%s %s", ppp_dns1, ppp_dns2);
1107+
1108+ LOGI("Got net.ppp0.local-ip: %s\n", ppp_local_ip);
1109+
1110+ responses.status = 0;
1111+ responses.suggestedRetryTime = -1;
1112+ responses.cid = 1;
1113+ responses.active = 2;
1114+ responses.type = (char*)"PPP";
1115+ responses.ifname = (char*)PPP_TTY_PATH;
1116+ responses.addresses = ppp_local_ip;
1117+ responses.dnses = ppp_dnses;
1118+ responses.gateways = ppp_gw;
1119+
1120+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &responses, sizeof(RIL_Data_Call_Response_v6));
1121+ return;
1122+
1123+error:
1124+ LOGE("Unable to setup PDP\n");
1125+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1126+
1127+}
1128+
1129+/* CHECK There are several error cases if PDP deactivation fails
1130+ * 24.008: 8, 25, 36, 38, 39, 112
1131+ */
1132+static void requestDeactivateDefaultPDP(void *data, size_t datalen, RIL_Token t)
1133+{
1134+ char * cid;
1135+
1136+ D("requestDeactivateDefaultPDP()");
1137+
1138+ cid = ((char **)data)[0];
1139+ if (killConn(cid) < 0)
1140+ goto error;
1141+
1142+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1143+ return;
1144+
1145+error:
1146+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1147+}
1148+
1149+/**
1150+ * RIL_REQUEST_LAST_PDP_FAIL_CAUSE
1151+ *
1152+ * Requests the failure cause code for the most recently failed PDP
1153+ * context activate.
1154+ *
1155+ * See also: RIL_REQUEST_LAST_CALL_FAIL_CAUSE.
1156+ *
1157+ */
1158+
1159+/* Last pdp fail cause */
1160+static int s_lastPdpFailCause = PDP_FAIL_ERROR_UNSPECIFIED;
1161+static void requestLastPDPFailCause(RIL_Token t)
1162+{
1163+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &s_lastPdpFailCause, sizeof(int));
1164+}
1165+
1166+static void requestOrSendPDPContextList(RIL_Token *t)
1167+{
1168+ ATResponse *atResponse = NULL;
1169+ ATLine *p_cur;
1170+ RIL_Data_Call_Response_v6 *responses = NULL;
1171+
1172+ int err;
1173+ int fd;
1174+ char *line, *out;
1175+ int i,n = 0;
1176+
1177+ err = at_send_command_multiline ("AT+CGACT?", "+CGACT:", &atResponse);
1178+ if (err != AT_NOERROR) {
1179+ if (t != NULL)
1180+ RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
1181+ else
1182+ RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED, NULL, 0);
1183+
1184+ at_response_free(atResponse);
1185+ return;
1186+ }
1187+
1188+ for (p_cur = atResponse->p_intermediates; p_cur != NULL;
1189+ p_cur = p_cur->p_next)
1190+ n++;
1191+
1192+ responses = (RIL_Data_Call_Response_v6*)
1193+ alloca(n * sizeof(RIL_Data_Call_Response_v6));
1194+
1195+ for (i = 0; i < n; i++) {
1196+ responses[i].status = -1;
1197+ responses[i].suggestedRetryTime = -1;
1198+ responses[i].cid = -1;
1199+ responses[i].active = -1;
1200+ responses[i].type = (char*)"";
1201+ responses[i].ifname = (char*)PPP_TTY_PATH;
1202+ responses[i].addresses = (char*)"";
1203+ responses[i].dnses = (char*)"";
1204+ responses[i].gateways = (char*)"";
1205+ }
1206+
1207+ RIL_Data_Call_Response_v6 *response = responses;
1208+ for (p_cur = atResponse->p_intermediates; p_cur != NULL;
1209+ p_cur = p_cur->p_next) {
1210+
1211+ char *line = p_cur->line;
1212+
1213+ err = at_tok_start(&line);
1214+ if (err < 0)
1215+ goto error;
1216+
1217+ err = at_tok_nextint(&line, &response->cid);
1218+ if (err < 0)
1219+ goto error;
1220+
1221+ err = at_tok_nextint(&line, &response->active);
1222+ if (err < 0)
1223+ goto error;
1224+
1225+ response++;
1226+ }
1227+
1228+ at_response_free(atResponse);
1229+
1230+ err = at_send_command_multiline("AT+CGDCONT?", "+CGDCONT:", &atResponse);
1231+ if (err != AT_NOERROR)
1232+ goto error;
1233+
1234+ for (p_cur = atResponse->p_intermediates; p_cur != NULL;
1235+ p_cur = p_cur->p_next) {
1236+
1237+ char *line = p_cur->line;
1238+ int cid;
1239+
1240+ err = at_tok_start(&line);
1241+ if (err < 0)
1242+ goto error;
1243+
1244+ err = at_tok_nextint(&line, &cid);
1245+ if (err < 0)
1246+ goto error;
1247+
1248+ for (i = 0; i < n; i++) {
1249+ if (responses[i].cid == cid)
1250+ break;
1251+ }
1252+
1253+ if (i >= n) {
1254+ /* details for a context we didn't hear about in the last request */
1255+ continue;
1256+ }
1257+
1258+ // Assume no error
1259+ responses[i].status = 0;
1260+
1261+ // type
1262+ err = at_tok_nextstr(&line, &out);
1263+ if (err < 0)
1264+ goto error;
1265+
1266+ responses[i].type = (char*)alloca(strlen(out) + 1);
1267+ strcpy(responses[i].type, out);
1268+
1269+ // APN ignored for v5
1270+ err = at_tok_nextstr(&line, &out);
1271+ if (err < 0)
1272+ goto error;
1273+
1274+ responses[i].ifname = (char*)PPP_TTY_PATH;
1275+
1276+ err = at_tok_nextstr(&line, &out);
1277+ if (err < 0)
1278+ goto error;
1279+
1280+ responses[i].addresses = (char*)alloca(strlen(out) + 1);
1281+ strcpy(responses[i].addresses, out);
1282+ }
1283+
1284+
1285+ at_response_free(atResponse);
1286+ atResponse = NULL;
1287+
1288+ if (t != NULL)
1289+ RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
1290+ n * sizeof(RIL_Data_Call_Response_v6));
1291+ else
1292+ RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED, &response,
1293+ sizeof(RIL_Data_Call_Response_v6));
1294+
1295+ return;
1296+
1297+error:
1298+ if (t != NULL)
1299+ RIL_onRequestComplete(*t, RIL_E_GENERIC_FAILURE, NULL, 0);
1300+ else
1301+ RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED, NULL, 0);
1302+
1303+ at_response_free(atResponse);
1304+}
1305+
1306+/**
1307+ * RIL_REQUEST_PDP_CONTEXT_LIST
1308+ *
1309+ * Queries the status of PDP contexts, returning for each
1310+ * its CID, whether or not it is active, and its PDP type,
1311+ * APN, and PDP adddress.
1312+ */
1313+static void requestPDPContextList(RIL_Token t)
1314+{
1315+ requestOrSendPDPContextList(&t);
1316+}
1317+
1318+static void onDataCallListChanged(void *param)
1319+{
1320+ requestOrSendPDPContextList(NULL);
1321+}
1322+
1323+/*
1324+ * Configure preferred message storage
1325+ * mem1 = SM, mem2 = SM
1326+ */
1327+static int setPreferredMessageStorage(void)
1328+{
1329+ ATResponse *atResponse = NULL;
1330+ char *tok = NULL;
1331+ int used1, total1;
1332+ int err;
1333+ int return_value;
1334+
1335+ err = at_send_command_singleline("AT+CPMS=\"SM\",\"SM\"","+CPMS: ", &atResponse);
1336+ if (err != AT_NOERROR) {
1337+ LOGE("%s() Unable to set preferred message storage", __func__);
1338+ goto error;
1339+ }
1340+
1341+ /*
1342+ * Depending on the host boot time the indication that message storage
1343+ * on SIM is full (+CIEV: 10,1) may be sent before the RIL is started.
1344+ * The RIL will explicitly check status of SIM messages storage using
1345+ * +CPMS intermediate response and inform Android if storage is full.
1346+ * +CPMS: <used1>,<total1>,<used2>,<total2>,<used3>,<total3>
1347+ */
1348+ tok = atResponse->p_intermediates->line;
1349+
1350+ err = at_tok_start(&tok);
1351+ if (err < 0)
1352+ goto error;
1353+
1354+ err = at_tok_nextint(&tok, &used1);
1355+ if (err < 0)
1356+ goto error;
1357+
1358+ err = at_tok_nextint(&tok, &total1);
1359+ if (err < 0)
1360+ goto error;
1361+
1362+ if (used1 >= total1)
1363+ RIL_onUnsolicitedResponse(RIL_UNSOL_SIM_SMS_STORAGE_FULL,NULL, 0);
1364+
1365+ return_value = 0;
1366+
1367+ goto exit;
1368+
1369+error:
1370+ LOGE("%s() Failed during AT+CPMS sending/handling!", __func__);
1371+ return_value = 1;
1372+
1373+exit:
1374+ at_response_free(atResponse);
1375+ return return_value;
1376+}
1377+
1378+static char s_outstanding_acknowledge = 0;
1379+
1380+#define OUTSTANDING_SMS 0
1381+#define OUTSTANDING_STATUS 1
1382+#define OUTSTANDING_CB 2
1383+
1384+#define MESSAGE_STORAGE_READY_TIMER 3
1385+
1386+#define BSM_LENGTH 88
1387+
1388+/* Check if ME is ready to set preferred message storage */
1389+static void checkMessageStorageReady(void *p)
1390+{
1391+ int err;
1392+ struct timespec trigger_time;
1393+ (void) p;
1394+
1395+ err = at_send_command_singleline("AT+CPMS?","+CPMS: ", NULL);
1396+ if (err == AT_NOERROR) {
1397+ if (setPreferredMessageStorage() == 0) {
1398+ LOGI("Message storage is ready");
1399+ return;
1400+ }
1401+ }
1402+
1403+ LOGE("%s() Message storage is not ready"
1404+ "A new attempt will be done in %d seconds",
1405+ __func__, MESSAGE_STORAGE_READY_TIMER);
1406+
1407+ trigger_time.tv_sec = MESSAGE_STORAGE_READY_TIMER;
1408+ trigger_time.tv_nsec = 0;
1409+
1410+ enqueueRILEvent(checkMessageStorageReady, NULL, &trigger_time);
1411+}
1412+
1413+struct held_pdu {
1414+ char type;
1415+ char *sms_pdu;
1416+ struct held_pdu *next;
1417+};
1418+
1419+static pthread_mutex_t s_held_pdus_mutex = PTHREAD_MUTEX_INITIALIZER;
1420+static struct held_pdu *s_held_pdus = NULL;
1421+
1422+static struct held_pdu *dequeue_held_pdu(void)
1423+{
1424+ struct held_pdu *hpdu = NULL;
1425+
1426+ if (s_held_pdus != NULL) {
1427+ hpdu = s_held_pdus;
1428+ s_held_pdus = hpdu->next;
1429+ hpdu->next = NULL;
1430+ }
1431+
1432+ return hpdu;
1433+}
1434+
1435+static void enqueue_held_pdu(char type, const char *sms_pdu)
1436+{
1437+ struct held_pdu *hpdu = (struct held_pdu *) malloc(sizeof(*hpdu));
1438+ if (hpdu == NULL) {
1439+ LOGE("%s() failed to allocate memory!", __func__);
1440+ return;
1441+ }
1442+
1443+ memset(hpdu, 0, sizeof(*hpdu));
1444+ hpdu->type = type;
1445+ hpdu->sms_pdu = strdup(sms_pdu);
1446+ if (NULL == hpdu->sms_pdu) {
1447+ LOGE("%s() failed to allocate memory!", __func__);
1448+ return;
1449+ }
1450+
1451+ if (s_held_pdus == NULL)
1452+ s_held_pdus = hpdu;
1453+ else {
1454+ struct held_pdu *p = s_held_pdus;
1455+ while (p->next != NULL)
1456+ p = p->next;
1457+
1458+ p->next = hpdu;
1459+ }
1460+}
1461+
1462+void isSimSmsStorageFull(void *p)
1463+{
1464+ ATResponse *atResponse = NULL;
1465+ char *tok = NULL;
1466+ char* storage_area = NULL;
1467+ int used1, total1;
1468+ int err;
1469+ (void) p;
1470+
1471+ err = at_send_command_singleline("AT+CPMS?", "+CPMS: ", &atResponse);
1472+ if (err != AT_NOERROR)
1473+ goto error;
1474+
1475+ tok = atResponse->p_intermediates->line;
1476+
1477+ err = at_tok_start(&tok);
1478+ if (err < 0)
1479+ goto error;
1480+
1481+ err = at_tok_nextstr(&tok, &storage_area);
1482+ if (err < 0)
1483+ goto error;
1484+
1485+ err = at_tok_nextint(&tok, &used1);
1486+ if (err < 0)
1487+ goto error;
1488+
1489+ err = at_tok_nextint(&tok, &total1);
1490+ if (err < 0)
1491+ goto error;
1492+
1493+ if (used1 >= total1)
1494+ RIL_onUnsolicitedResponse(RIL_UNSOL_SIM_SMS_STORAGE_FULL, NULL, 0);
1495+
1496+ goto exit;
1497+
1498+error:
1499+ LOGE("%s() failed during AT+CPMS sending/handling!", __func__);
1500+exit:
1501+ at_response_free(atResponse);
1502+ return;
1503+}
1504+
1505+/**
1506+ * RIL_UNSOL_SIM_SMS_STORAGE_FULL
1507+ *
1508+ * SIM SMS storage area is full, cannot receive
1509+ * more messages until memory freed
1510+ */
1511+void onNewSmsIndication(void)
1512+{
1513+ enqueueRILEvent(isSimSmsStorageFull, NULL, NULL);
1514+}
1515+
1516+void onNewSms(const char *sms_pdu)
1517+{
1518+ pthread_mutex_lock(&s_held_pdus_mutex);
1519+
1520+ /* No RIL_UNSOL_RESPONSE_NEW_SMS or RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT
1521+ * messages should be sent until a RIL_REQUEST_SMS_ACKNOWLEDGE has been received for
1522+ * previous new SMS.
1523+ */
1524+ if (s_outstanding_acknowledge) {
1525+ LOGI("Waiting for ack for previous sms, enqueueing PDU");
1526+ enqueue_held_pdu(OUTSTANDING_SMS, sms_pdu);
1527+ } else {
1528+ s_outstanding_acknowledge = 1;
1529+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS,
1530+ sms_pdu, strlen(sms_pdu));
1531+ }
1532+
1533+ pthread_mutex_unlock(&s_held_pdus_mutex);
1534+}
1535+
1536+void onNewStatusReport(const char *sms_pdu)
1537+{
1538+ char *response = NULL;
1539+ int err;
1540+
1541+ /* Baseband will not prepend SMSC addr, but Android expects it. */
1542+ err = asprintf(&response, "%s%s", "00", sms_pdu);
1543+ if (err == -1) {
1544+ D("%s() Error allocating memory!", __func__);
1545+ return;
1546+ }
1547+
1548+ pthread_mutex_lock(&s_held_pdus_mutex);
1549+
1550+ /* No RIL_UNSOL_RESPONSE_NEW_SMS or RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT
1551+ * messages should be sent until a RIL_REQUEST_SMS_ACKNOWLEDGE has been received for
1552+ * previous new SMS.
1553+ */
1554+ if (s_outstanding_acknowledge) {
1555+ LOGE("%s() Waiting for previous ack, enqueueing PDU..", __func__);
1556+ enqueue_held_pdu(OUTSTANDING_STATUS, response);
1557+ } else {
1558+ s_outstanding_acknowledge = 1;
1559+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
1560+ response, strlen(response));
1561+ }
1562+ free(response);
1563+ pthread_mutex_unlock(&s_held_pdus_mutex);
1564+}
1565+
1566+void onNewBroadcastSms(const char *pdu)
1567+{
1568+ char *message = NULL;
1569+ D("%s() Length : %d", __func__, strlen(pdu));
1570+
1571+ if (strlen(pdu) != (2 * BSM_LENGTH)) {
1572+ LOGE("%s() Broadcast Message length error! Discarding!", __func__);
1573+ goto error;
1574+ }
1575+ D("%s() PDU: %176s", __func__, pdu);
1576+
1577+ message = (char*) alloca(BSM_LENGTH);
1578+ if (!message) {
1579+ LOGE("%s() error allocating memory for message! Discarding!", __func__);
1580+ goto error;
1581+ }
1582+
1583+ stringToBinary(pdu, 2*BSM_LENGTH, (unsigned char *)message);
1584+ D("%s() Message: %88s", __func__, message);
1585+
1586+ pthread_mutex_lock(&s_held_pdus_mutex);
1587+
1588+ /* No RIL_UNSOL_RESPONSE_NEW_SMS or RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT
1589+ * or RIL_UNSOL_RESPONSE_NEW_CB
1590+ * messages should be sent until a RIL_REQUEST_SMS_ACKNOWLEDGE has been received for
1591+ * previous new SMS.
1592+ */
1593+ if (s_outstanding_acknowledge) {
1594+ LOGE("%s() Waiting for previous ack, enqueueing PDU..", __func__);
1595+ enqueue_held_pdu(OUTSTANDING_CB, message);
1596+ } else {
1597+ s_outstanding_acknowledge = 1;
1598+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS,
1599+ message, BSM_LENGTH);
1600+ }
1601+
1602+ pthread_mutex_unlock(&s_held_pdus_mutex);
1603+
1604+error:
1605+ return;
1606+}
1607+
1608+void onNewSmsOnSIM(const char *s)
1609+{
1610+ char *line;
1611+ char *mem;
1612+ char *tok;
1613+ int err = 0;
1614+ int index = -1;
1615+
1616+ tok = line = strdup(s);
1617+
1618+ err = at_tok_start(&tok);
1619+ if (err < 0)
1620+ goto error;
1621+
1622+ err = at_tok_nextstr(&tok, &mem);
1623+ if (err < 0)
1624+ goto error;
1625+
1626+ if (strncmp(mem, "SM", 2) != 0)
1627+ goto error;
1628+
1629+ err = at_tok_nextint(&tok, &index);
1630+ if (err < 0)
1631+ goto error;
1632+
1633+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM,
1634+ &index, sizeof(int *));
1635+
1636+finally:
1637+ free(line);
1638+ return;
1639+
1640+error:
1641+ LOGE("%s() Failed to parse +CMTI.", __func__);
1642+ goto finally;
1643+}
1644+
1645+
1646+/**
1647+ * RIL_REQUEST_SEND_SMS
1648+ *
1649+ * Sends an SMS message.
1650+*/
1651+static void requestSendSMS(void *data, size_t datalen, RIL_Token t)
1652+{
1653+ (void) datalen;
1654+ int err, aterr = 0;
1655+ const char *testSmsc;
1656+ char smsc[30];
1657+ const char *pdu;
1658+ char *line;
1659+ int tpLayerLength;
1660+ char *cmd1, *cmd2;
1661+ RIL_SMS_Response response;
1662+ RIL_Errno ret = RIL_E_SUCCESS;
1663+ ATResponse *atResponse = NULL;
1664+
1665+ testSmsc = ((const char **) data)[0];
1666+ pdu = ((const char **) data)[1];
1667+
1668+ tpLayerLength = strlen(pdu) / 2;
1669+
1670+ /* NULL for default SMSC. */
1671+ if (testSmsc == NULL) {
1672+ char* temp;
1673+ int tosca;
1674+ int plus = 0;
1675+ int length = 0;
1676+ int i,curChar = 0;
1677+
1678+ err = at_send_command_singleline("AT+CSCA?", "+CSCA:", &atResponse);
1679+ if (err != AT_NOERROR)
1680+ goto error;
1681+
1682+ line = atResponse->p_intermediates->line;
1683+
1684+ err = at_tok_start(&line);
1685+ if (err < 0) goto error;
1686+
1687+ err = at_tok_nextstr(&line, &temp);
1688+ if (err < 0) goto error;
1689+
1690+ err = at_tok_nextint(&line, &tosca);
1691+ if (err < 0) goto error;
1692+
1693+ if(temp[0]=='+')
1694+ plus = 1;
1695+
1696+ length = strlen(temp) - plus;
1697+ sprintf(smsc,"%.2x%.2x",(length + 1) / 2 + 1, tosca);
1698+
1699+ for (i = 0; curChar < length - 1; i+=2 ) {
1700+ smsc[5+i] = temp[plus+curChar++];
1701+ smsc[4+i] = temp[plus+curChar++];
1702+ }
1703+
1704+ if ( length % 2) { // One extra number
1705+ smsc[4+length] = temp[curChar];
1706+ smsc[3+length]='F';
1707+ smsc[5+length]='\0';
1708+ } else {
1709+ smsc[4+length] = '\0';
1710+ }
1711+ at_response_free(atResponse);
1712+ }
1713+ else
1714+ strcpy(smsc,testSmsc);
1715+
1716+ asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength);
1717+ asprintf(&cmd2, "%s%s", smsc, pdu);
1718+ aterr = at_send_command_sms(cmd1, cmd2, "+CMGS:", &atResponse);
1719+ free(cmd1);
1720+ free(cmd2);
1721+
1722+ if (aterr != AT_NOERROR)
1723+ goto error;
1724+
1725+ memset(&response, 0, sizeof(response));
1726+
1727+ /* Set errorCode to -1 if unknown or not applicable
1728+ * See 3GPP 27.005, 3.2.5 for GSM/UMTS
1729+ */
1730+ response.errorCode = -1;
1731+
1732+ line = atResponse->p_intermediates->line;
1733+
1734+ err = at_tok_start(&line);
1735+ if (err < 0)
1736+ goto error;
1737+
1738+ err = at_tok_nextint(&line, &response.messageRef);
1739+ if (err < 0)
1740+ goto error;
1741+
1742+ /* No support for ackPDU. Do we need it? */
1743+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
1744+
1745+finally:
1746+ at_response_free(atResponse);
1747+ return;
1748+
1749+error:
1750+ switch (at_get_cms_error(aterr)) {
1751+ case CMS_NO_NETWORK_SERVICE:
1752+ case CMS_NETWORK_TIMEOUT:
1753+ ret = RIL_E_SMS_SEND_FAIL_RETRY;
1754+ break;
1755+ default:
1756+ ret = RIL_E_GENERIC_FAILURE;
1757+ break;
1758+ }
1759+ RIL_onRequestComplete(t, ret, NULL, 0);
1760+ goto finally;
1761+}
1762+
1763+
1764+/**
1765+ * RIL_REQUEST_SEND_SMS_EXPECT_MORE
1766+ *
1767+ * Send an SMS message. Identical to RIL_REQUEST_SEND_SMS,
1768+ * except that more messages are expected to be sent soon. If possible,
1769+ * keep SMS relay protocol link open (eg TS 27.005 AT+CMMS command).
1770+*/
1771+static void requestSendSMSExpectMore(void *data, size_t datalen, RIL_Token t)
1772+{
1773+ /* Throw the command on the channel and ignore any errors, since we
1774+ need to send the SMS anyway and subsequent SMSes will be sent anyway. */
1775+ at_send_command("AT+CMMS=1");
1776+
1777+ requestSendSMS(data, datalen, t);
1778+}
1779+
1780+
1781+/**
1782+ * RIL_REQUEST_WRITE_SMS_TO_SIM
1783+ *
1784+ * Stores a SMS message to SIM memory.
1785+*/
1786+void requestWriteSmsToSim(void *data, size_t datalen, RIL_Token t)
1787+{
1788+ RIL_SMS_WriteArgs *args;
1789+ char *cmd;
1790+ char *pdu;
1791+ char *line;
1792+ int length;
1793+ int index;
1794+ int err;
1795+ ATResponse *atResponse = NULL;
1796+
1797+ (void) datalen;
1798+
1799+ args = (RIL_SMS_WriteArgs *) data;
1800+
1801+ length = strlen(args->pdu) / 2;
1802+
1803+ asprintf(&cmd, "AT+CMGW=%d,%d", length, args->status);
1804+ asprintf(&pdu, "%s%s", (args->smsc ? args->smsc : "00"), args->pdu);
1805+ err = at_send_command_sms(cmd, pdu, "+CMGW:", &atResponse);
1806+ free(cmd);
1807+ free(pdu);
1808+
1809+ if (err != AT_NOERROR)
1810+ goto error;
1811+
1812+ line = atResponse->p_intermediates->line;
1813+
1814+ err = at_tok_start(&line);
1815+ if (err < 0)
1816+ goto error;
1817+
1818+ err = at_tok_nextint(&line, &index);
1819+ if (err < 0)
1820+ goto error;
1821+
1822+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &index, sizeof(int *));
1823+
1824+finally:
1825+ at_response_free(atResponse);
1826+ return;
1827+
1828+error:
1829+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1830+ goto finally;
1831+}
1832+
1833+/**
1834+ * RIL_REQUEST_DELETE_SMS_ON_SIM
1835+ *
1836+ * Deletes a SMS message from SIM memory.
1837+ */
1838+static void requestDeleteSmsOnSim(void *data, size_t datalen, RIL_Token t)
1839+{
1840+ int err;
1841+
1842+ err = at_send_command("AT+CMGD=%d", ((int *) data)[0]);
1843+ if (err != AT_NOERROR)
1844+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1845+ else
1846+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1847+}
1848+
1849+/**
1850+ * RIL_REQUEST_GET_SMSC_ADDRESS
1851+ */
1852+static void requestGetSMSCAddress(RIL_Token t)
1853+{
1854+ ATResponse *atResponse = NULL;
1855+ int err;
1856+ char *line;
1857+ char *response;
1858+
1859+ err = at_send_command_singleline("AT+CSCA?", "+CSCA:", &atResponse);
1860+
1861+ if (err != AT_NOERROR)
1862+ goto error;
1863+
1864+ line = atResponse->p_intermediates->line;
1865+
1866+ err = at_tok_start(&line);
1867+ if (err < 0)
1868+ goto error;
1869+
1870+ err = at_tok_nextstr(&line, &response);
1871+ if (err < 0)
1872+ goto error;
1873+
1874+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(char *));
1875+
1876+finally:
1877+ at_response_free(atResponse);
1878+ return;
1879+
1880+error:
1881+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1882+ goto finally;
1883+}
1884+
1885+
1886+
1887+/**
1888+ * RIL_REQUEST_SET_SMSC_ADDRESS
1889+ */
1890+static void requestSetSMSCAddress(void *data, size_t datalen, RIL_Token t)
1891+{
1892+ (void) datalen;
1893+ int err;
1894+ const char *smsc = (const char *)data;
1895+
1896+ err = at_send_command("AT+CSCA=\"%s\"", smsc);
1897+ if (err != AT_NOERROR)
1898+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1899+ else
1900+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1901+}
1902+
1903+
1904+/**
1905+ * RIL_REQUEST_REPORT_SMS_MEMORY_STATUS
1906+ */
1907+static void requestSmsStorageFull(void *data, size_t datalen, RIL_Token t)
1908+{
1909+ int ack;
1910+
1911+ ack = ((int *) data)[0];
1912+
1913+ /* Android will call RIL_REQUEST_REPORT_SMS_MEMORY_STATUS in case of:
1914+ * 0. memory is full
1915+ * 1. memory was full and been cleaned up, inform modem memory is available now.
1916+ */
1917+ switch (ack) {
1918+ case 0:
1919+ /* Android will handle this, no need to inform modem. always return success. */
1920+ LOGI("SMS storage full");
1921+ break;
1922+
1923+ case 1:
1924+ /* Since we are not using +CNMA command. It's fine to return without informing network */
1925+ LOGI("Failed to inform network for Message Cleanup. Need cmd : ESMSMEMAVAIL");
1926+ break;
1927+
1928+ default:
1929+ LOGE("%s() Invalid parameter", __func__);
1930+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1931+ return;
1932+ }
1933+
1934+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1935+}
1936+
1937+
1938+/**
1939+ * RIL_REQUEST_SMS_ACKNOWLEDGE
1940+ *
1941+ * Acknowledge successful or failed receipt of SMS previously indicated
1942+ * via RIL_UNSOL_RESPONSE_NEW_SMS .
1943+*/
1944+static void requestSMSAcknowledge(void *data, size_t datalen, RIL_Token t)
1945+{
1946+ int ackSuccess;
1947+ int err;
1948+ struct held_pdu *hpdu;
1949+
1950+ ackSuccess = ((int *)data)[0];
1951+
1952+ if (ackSuccess == 1) {
1953+ err = at_send_command("AT+CNMA=1");
1954+ } else if (ackSuccess == 0) {
1955+ err = at_send_command("AT+CNMA=2");
1956+ } else {
1957+ LOGE("unsupported arg to RIL_REQUEST_SMS_ACKNOWLEDGE\n");
1958+ goto error;
1959+ }
1960+
1961+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
1962+
1963+ pthread_mutex_lock(&s_held_pdus_mutex);
1964+ hpdu = dequeue_held_pdu();
1965+
1966+ if (hpdu != NULL) {
1967+ LOGE("%s() Outstanding requests in queue, dequeueing and sending.",
1968+ __func__);
1969+ int unsolResponse = 0;
1970+
1971+ if (hpdu->type == OUTSTANDING_SMS)
1972+ unsolResponse = RIL_UNSOL_RESPONSE_NEW_SMS;
1973+ else if (hpdu->type == OUTSTANDING_CB)
1974+ unsolResponse = RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS;
1975+ else
1976+ unsolResponse = RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT;
1977+
1978+ RIL_onUnsolicitedResponse(unsolResponse, hpdu->sms_pdu,
1979+ strlen(hpdu->sms_pdu));
1980+
1981+ free(hpdu->sms_pdu);
1982+ free(hpdu);
1983+ } else
1984+ s_outstanding_acknowledge = 0;
1985+
1986+ pthread_mutex_unlock(&s_held_pdus_mutex);
1987+
1988+ return;
1989+
1990+error:
1991+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
1992+
1993+}
1994+
1995+
1996+
1997+
1998+#define BROADCAST_MAX_RANGES_SUPPORTED 10
1999+
2000+/**
2001+ * RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG
2002+ */
2003+static void requestGSMGetBroadcastSMSConfig(RIL_Token t)
2004+{
2005+ ATResponse *atResponse = NULL;
2006+ int mode, err = 0;
2007+ unsigned int i, count = 0;
2008+ char *mids;
2009+ char *range;
2010+ char *trange;
2011+ char *tok = NULL;
2012+
2013+ RIL_GSM_BroadcastSmsConfigInfo *configInfo[BROADCAST_MAX_RANGES_SUPPORTED];
2014+
2015+ err = at_send_command_singleline("AT+CSCB?", "+CSCB:", &atResponse);
2016+
2017+ if (err != AT_NOERROR)
2018+ goto error;
2019+
2020+ tok = atResponse->p_intermediates->line;
2021+
2022+ err = at_tok_start(&tok);
2023+ if (err < 0)
2024+ goto error;
2025+
2026+ err = at_tok_nextint(&tok, &mode);
2027+ if (err < 0)
2028+ goto error;
2029+
2030+ /**
2031+ * Get the string that yields the service ids (mids). AT+CSCB <mids>
2032+ * parameter may contain a mix of single service ids (,%d,) and service id
2033+ * ranges (,%d-%d,).
2034+ */
2035+ err = at_tok_nextstr(&tok, &mids);
2036+ if (err < 0)
2037+ goto error;
2038+
2039+ while (at_tok_nextstr(&mids, &range) == 0) {
2040+ /**
2041+ * Replace any '-' sign with ',' sign to allow for at_tok_nextint
2042+ * for both fromServiceId and toServiceId below.
2043+ */
2044+ trange = range;
2045+ while ((NULL != trange) && ('\0' != *trange)) {
2046+ if ('-' == *trange)
2047+ *trange = ',';
2048+ trange++;
2049+ }
2050+ if (count < BROADCAST_MAX_RANGES_SUPPORTED) {
2051+ configInfo[count] = (RIL_GSM_BroadcastSmsConfigInfo*) calloc(1,
2052+ sizeof(RIL_GSM_BroadcastSmsConfigInfo));
2053+ if (NULL == configInfo[count])
2054+ goto error;
2055+
2056+ /* No support for "Not accepted mids", selected is always 1 */
2057+ configInfo[count]->selected = 1;
2058+
2059+ /* Fetch fromServiceId value */
2060+ err = at_tok_nextint(&range, &(configInfo[count]->fromServiceId));
2061+ if (err < 0)
2062+ goto error;
2063+ /* Try to fetch toServiceId value if it exist */
2064+ err = at_tok_nextint(&range, &(configInfo[count]->toServiceId));
2065+ if (err < 0)
2066+ configInfo[count]->toServiceId =
2067+ configInfo[count]->fromServiceId;
2068+
2069+ count++;
2070+ } else {
2071+ LOGW("%s() Max limit (%d) passed, can not send all ranges "
2072+ "reported by modem.", __func__,
2073+ BROADCAST_MAX_RANGES_SUPPORTED);
2074+ break;
2075+ }
2076+ }
2077+
2078+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &configInfo,
2079+ sizeof(RIL_GSM_BroadcastSmsConfigInfo *) * count);
2080+
2081+ goto exit;
2082+
2083+error:
2084+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2085+
2086+exit:
2087+ at_response_free(atResponse);
2088+ for (i = 0; i < count; i++)
2089+ free(configInfo[i]);
2090+}
2091+
2092+
2093+
2094+/**
2095+ * RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG
2096+ */
2097+static void requestGSMSetBroadcastSMSConfig(void *data, size_t datalen,
2098+ RIL_Token t)
2099+{
2100+ int err, count, i;
2101+ char *tmp, *mids = NULL;
2102+ RIL_GSM_BroadcastSmsConfigInfo **configInfoArray =
2103+ (RIL_GSM_BroadcastSmsConfigInfo **) data;
2104+ RIL_GSM_BroadcastSmsConfigInfo *configInfo = NULL;
2105+
2106+ count = datalen / sizeof(RIL_GSM_BroadcastSmsConfigInfo *);
2107+ LOGI("Number of MID ranges in BROADCAST_SMS_CONFIG: %d", count);
2108+
2109+ for (i = 0; i < count; i++) {
2110+ configInfo = configInfoArray[i];
2111+ /* No support for "Not accepted mids" in AT */
2112+ if (configInfo->selected) {
2113+ tmp = mids;
2114+ asprintf(&mids, "%s%d-%d%s", (tmp ? tmp : ""),
2115+ configInfo->fromServiceId, configInfo->toServiceId,
2116+ (i == (count - 1) ? "" : ",")); /* Last one? Skip comma */
2117+ free(tmp);
2118+ }
2119+ }
2120+
2121+ if (mids == NULL) {
2122+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2123+ return;
2124+ }
2125+
2126+ err = at_send_command("AT+CSCB=0,\"%s\"", mids);
2127+ free(mids);
2128+
2129+ if (err != AT_NOERROR) {
2130+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2131+ return;
2132+ }
2133+
2134+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2135+}
2136+
2137+
2138+/**
2139+ * RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION
2140+ */
2141+static void requestGSMSMSBroadcastActivation(void *data, size_t datalen,
2142+ RIL_Token t)
2143+{
2144+ ATResponse *atResponse = NULL;
2145+ int mode, mt, bm, ds, bfr, skip;
2146+ int activation;
2147+ char *tok;
2148+ int err;
2149+
2150+ (void) datalen;
2151+
2152+ /* AT+CNMI=[<mode>[,<mt>[,<bm>[,<ds>[,<bfr>]]]]] */
2153+ err = at_send_command_singleline("AT+CNMI?", "+CNMI:", &atResponse);
2154+ if (err != AT_NOERROR)
2155+ goto error;
2156+
2157+ tok = atResponse->p_intermediates->line;
2158+
2159+ err = at_tok_start(&tok);
2160+ if (err < 0)
2161+ goto error;
2162+ err = at_tok_nextint(&tok, &mode);
2163+ if (err < 0)
2164+ goto error;
2165+ err = at_tok_nextint(&tok, &mt);
2166+ if (err < 0)
2167+ goto error;
2168+ err = at_tok_nextint(&tok, &skip);
2169+ if (err < 0)
2170+ goto error;
2171+ err = at_tok_nextint(&tok, &ds);
2172+ if (err < 0)
2173+ goto error;
2174+ err = at_tok_nextint(&tok, &bfr);
2175+ if (err < 0)
2176+ goto error;
2177+
2178+ /* 0 - Activate, 1 - Turn off */
2179+ activation = *((const int *)data);
2180+ if (activation == 0)
2181+ bm = 2;
2182+ else
2183+ bm = 0;
2184+
2185+ err = at_send_command("AT+CNMI=%d,%d,%d,%d,%d", mode, mt, bm, ds, bfr);
2186+
2187+ if (err != AT_NOERROR)
2188+ goto error;
2189+
2190+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
2191+
2192+finally:
2193+ at_response_free(atResponse);
2194+ return;
2195+
2196+error:
2197+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2198+ goto finally;
2199+}
2200+
2201+/**
2202+ * Fetch information about UICC card type (SIM/USIM)
2203+ *
2204+ * \return UICC_Type: type of UICC card.
2205+ */
2206+static UICC_Type getUICCType(void)
2207+{
2208+ ATResponse *atResponse = NULL;
2209+ char* line;
2210+ static UICC_Type UiccType = UICC_TYPE_UNKNOWN;
2211+ int err,type;
2212+
2213+ if (getRadioState() == RADIO_STATE_OFF ||
2214+ getRadioState() == RADIO_STATE_UNAVAILABLE) {
2215+ return UICC_TYPE_UNKNOWN;
2216+ }
2217+
2218+ /* Only if card type is not known yet ... */
2219+ if (UiccType == UICC_TYPE_UNKNOWN) {
2220+
2221+ /* Get the card type */
2222+ err = at_send_command_singleline("AT^CARDMODE", "^CARDMODE:", &atResponse);
2223+ if (err != AT_NOERROR)
2224+ goto error;
2225+
2226+ line = atResponse->p_intermediates->line;
2227+
2228+ err = at_tok_start(&line);
2229+
2230+ if (err < 0)
2231+ goto error;
2232+
2233+ err = at_tok_nextint(&line, &type);
2234+ if (err < 0)
2235+ goto error;
2236+
2237+
2238+ UiccType = (type == 0) ? UICC_TYPE_SIM :
2239+ ((type == 1) ? UICC_TYPE_USIM :
2240+ ((type == 2) ? UICC_TYPE_UIM : UICC_TYPE_UNKNOWN));
2241+
2242+ }
2243+
2244+ LOGI("Detected card type :%d", UiccType);
2245+
2246+error:
2247+ at_response_free(atResponse);
2248+
2249+ return UiccType;
2250+}
2251+
2252+/**
2253+ * RIL_REQUEST_SIM_IO
2254+ *
2255+ * Request SIM I/O operation.
2256+ * This is similar to the TS 27.007 "restricted SIM" operation
2257+ * where it assumes all of the EF selection will be done by the
2258+ * callee.
2259+ */
2260+
2261+
2262+/* All files listed under ADF_USIM in 3GPP TS 31.102 */
2263+static const int ef_usim_files[] = {
2264+ 0x6F05, 0x6F06, 0x6F07, 0x6F08, 0x6F09,
2265+ 0x6F2C, 0x6F31, 0x6F32, 0x6F37, 0x6F38,
2266+ 0x6F39, 0x6F3B, 0x6F3C, 0x6F3E, 0x6F3F,
2267+ 0x6F40, 0x6F41, 0x6F42, 0x6F43, 0x6F45,
2268+ 0x6F46, 0x6F47, 0x6F48, 0x6F49, 0x6F4B,
2269+ 0x6F4C, 0x6F4D, 0x6F4E, 0x6F4F, 0x6F50,
2270+ 0x6F55, 0x6F56, 0x6F57, 0x6F58, 0x6F5B,
2271+ 0x6F5C, 0x6F60, 0x6F61, 0x6F62, 0x6F73,
2272+ 0x6F78, 0x6F7B, 0x6F7E, 0x6F80, 0x6F81,
2273+ 0x6F82, 0x6F83, 0x6FAD, 0x6FB1, 0x6FB2,
2274+ 0x6FB3, 0x6FB4, 0x6FB5, 0x6FB6, 0x6FB7,
2275+ 0x6FC3, 0x6FC4, 0x6FC5, 0x6FC6, 0x6FC7,
2276+ 0x6FC8, 0x6FC9, 0x6FCA, 0x6FCB, 0x6FCC,
2277+ 0x6FCD, 0x6FCE, 0x6FCF, 0x6FD0, 0x6FD1,
2278+ 0x6FD2, 0x6FD3, 0x6FD4, 0x6FD5, 0x6FD6,
2279+ 0x6FD7, 0x6FD8, 0x6FD9, 0x6FDA, 0x6FDB,
2280+};
2281+
2282+static const int ef_telecom_files[] = {
2283+ 0x6F3A, 0x6F3D, 0x6F44, 0x6F4A, 0x6F54,
2284+};
2285+
2286+#define PATH_ADF_USIM_DIRECTORY "3F007FFF"
2287+#define PATH_ADF_TELECOM_DIRECTORY "3F007F10"
2288+
2289+/* RID: A000000087 = 3GPP, PIX: 1002 = 3GPP USIM */
2290+#define USIM_APPLICATION_ID "A0000000871002"
2291+
2292+static int sendSimIOCmdICC(const RIL_SIM_IO_v6 *ioargs, ATResponse **atResponse, RIL_SIM_IO_Response *sr)
2293+{
2294+ int err;
2295+ char *fmt;
2296+ char *arg6;
2297+ char *arg7;
2298+ char *line;
2299+
2300+ /* FIXME Handle pin2. */
2301+ memset(sr, 0, sizeof(*sr));
2302+
2303+ arg6 = ioargs->data;
2304+ arg7 = ioargs->path;
2305+
2306+ if (arg7 && arg6) {
2307+ fmt = "AT+CRSM=%d,%d,%d,%d,%d,\"%s\",\"%s\"";
2308+ } else if (arg7) {
2309+ fmt = "AT+CRSM=%d,%d,%d,%d,%d,,\"%s\"";
2310+ arg6 = arg7;
2311+ } else if (arg6) {
2312+ fmt = "AT+CRSM=%d,%d,%d,%d,%d,\"%s\"";
2313+ } else {
2314+ fmt = "AT+CRSM=%d,%d,%d,%d,%d";
2315+ }
2316+
2317+ err = at_send_command_singleline(fmt, "+CRSM:", atResponse,ioargs->command,
2318+ ioargs->fileid, ioargs->p1,
2319+ ioargs->p2, ioargs->p3,
2320+ arg6, arg7);
2321+
2322+ if (err != AT_NOERROR)
2323+ return err;
2324+
2325+ line = (*atResponse)->p_intermediates->line;
2326+
2327+ err = at_tok_start(&line);
2328+ if (err < 0)
2329+ goto finally;
2330+
2331+ err = at_tok_nextint(&line, &(sr->sw1));
2332+ if (err < 0)
2333+ goto finally;
2334+
2335+ err = at_tok_nextint(&line, &(sr->sw2));
2336+ if (err < 0)
2337+ goto finally;
2338+
2339+ if (at_tok_hasmore(&line)) {
2340+ err = at_tok_nextstr(&line, &(sr->simResponse));
2341+ if (err < 0)
2342+ goto finally;
2343+ }
2344+
2345+finally:
2346+ return err;
2347+}
2348+
2349+static int convertSimIoFcp(RIL_SIM_IO_Response *sr, char **cvt)
2350+{
2351+ int err;
2352+ /* size_t pos; */
2353+ size_t fcplen;
2354+ struct ts_51011_921_resp resp;
2355+ void *cvt_buf = NULL;
2356+
2357+ if (!sr->simResponse || !cvt) {
2358+ err = -EINVAL;
2359+ goto error;
2360+ }
2361+
2362+ fcplen = strlen(sr->simResponse);
2363+ if ((fcplen == 0) || (fcplen & 1)) {
2364+ err = -EINVAL;
2365+ goto error;
2366+ }
2367+
2368+ err = fcp_to_ts_51011(sr->simResponse, fcplen, &resp);
2369+ if (err < 0)
2370+ goto error;
2371+
2372+ cvt_buf = malloc(sizeof(resp) * 2 + 1);
2373+ if (!cvt_buf) {
2374+ err = -ENOMEM;
2375+ goto error;
2376+ }
2377+
2378+ err = binaryToString((unsigned char*)(&resp),
2379+ sizeof(resp), cvt_buf);
2380+ if (err < 0)
2381+ goto error;
2382+
2383+ /* cvt_buf ownership is moved to the caller */
2384+ *cvt = cvt_buf;
2385+ cvt_buf = NULL;
2386+
2387+finally:
2388+ return err;
2389+
2390+error:
2391+ free(cvt_buf);
2392+ goto finally;
2393+}
2394+
2395+/**
2396+ * RIL_REQUEST_SIM_IO
2397+ *
2398+ * Request SIM I/O operation.
2399+ * This is similar to the TS 27.007 "restricted SIM" operation
2400+ * where it assumes all of the EF selection will be done by the
2401+ * callee.
2402+ */
2403+static void requestSIM_IO(void *data, size_t datalen, RIL_Token t)
2404+{
2405+ (void) datalen;
2406+ ATResponse *atResponse = NULL;
2407+ RIL_SIM_IO_Response sr;
2408+ int cvt_done = 0;
2409+ int err;
2410+ UICC_Type UiccType = getUICCType();
2411+
2412+ int pathReplaced = 0;
2413+ RIL_SIM_IO_v6 ioargsDup;
2414+
2415+ /*
2416+ * Android telephony framework does not support USIM cards properly,
2417+ * send GSM filepath where as active cardtype is USIM.
2418+ * Android RIL needs to change the file path of files listed under ADF-USIM
2419+ * if current active cardtype is USIM
2420+ */
2421+ memcpy(&ioargsDup, data, sizeof(RIL_SIM_IO_v6));
2422+ if (UICC_TYPE_USIM == UiccType) {
2423+ unsigned int i;
2424+ int err;
2425+ unsigned int count = sizeof(ef_usim_files) / sizeof(int);
2426+
2427+ for (i = 0; i < count; i++) {
2428+ if (ef_usim_files[i] == ioargsDup.fileid) {
2429+ err = asprintf(&ioargsDup.path, PATH_ADF_USIM_DIRECTORY);
2430+ if (err < 0)
2431+ goto error;
2432+ pathReplaced = 1;
2433+ LOGD("%s() Path replaced for USIM: %d", __func__, ioargsDup.fileid);
2434+ break;
2435+ }
2436+ }
2437+ if(!pathReplaced){
2438+ unsigned int count2 = sizeof(ef_telecom_files) / sizeof(int);
2439+ for (i = 0; i < count2; i++) {
2440+ if (ef_telecom_files[i] == ioargsDup.fileid) {
2441+ err = asprintf(&ioargsDup.path, PATH_ADF_TELECOM_DIRECTORY);
2442+ if (err < 0)
2443+ goto error;
2444+ pathReplaced = 1;
2445+ LOGD("%s() Path replaced for telecom: %d", __func__, ioargsDup.fileid);
2446+ break;
2447+ }
2448+ }
2449+ }
2450+ }
2451+
2452+ memset(&sr, 0, sizeof(sr));
2453+
2454+ err = sendSimIOCmdICC(&ioargsDup, &atResponse, &sr);
2455+
2456+ if (err < 0)
2457+ goto error;
2458+
2459+ /*
2460+ * In case the command is GET_RESPONSE and cardtype is 3G SIM
2461+ * convert to 2G FCP
2462+ */
2463+ if (ioargsDup.command == 0xC0 && UiccType != UICC_TYPE_SIM) {
2464+ err = convertSimIoFcp(&sr, &sr.simResponse);
2465+ if (err < 0)
2466+ goto error;
2467+ cvt_done = 1; /* sr.simResponse needs to be freed */
2468+ }
2469+
2470+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
2471+
2472+finally:
2473+ at_response_free(atResponse);
2474+ if (cvt_done)
2475+ free(sr.simResponse);
2476+
2477+ if (pathReplaced)
2478+ free(ioargsDup.path);
2479+ return;
2480+
2481+error:
2482+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2483+ goto finally;
2484+}
2485+
2486+
2487+/*
2488+ * The following list contains values for the structure "RIL_AppStatus" to be
2489+ * sent to Android on a given SIM state. It is indexed by the SIM_Status above.
2490+ */
2491+static const RIL_AppStatus app_status_array[] = {
2492+ /*
2493+ * RIL_AppType, RIL_AppState,
2494+ * RIL_PersoSubstate,
2495+ * Aid pointer, App Label pointer, PIN1 replaced,
2496+ * RIL_PinState (PIN1),
2497+ * RIL_PinState (PIN2)
2498+ */
2499+ /* SIM_ABSENT = 0 */
2500+ {
2501+ RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN,
2502+ RIL_PERSOSUBSTATE_UNKNOWN,
2503+ NULL, NULL, 0,
2504+ RIL_PINSTATE_UNKNOWN,
2505+ RIL_PINSTATE_UNKNOWN
2506+ },
2507+ /* SIM_NOT_READY = 1 */
2508+ {
2509+ RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED,
2510+ RIL_PERSOSUBSTATE_UNKNOWN,
2511+ NULL, NULL, 0,
2512+ RIL_PINSTATE_UNKNOWN,
2513+ RIL_PINSTATE_UNKNOWN
2514+ },
2515+ /* SIM_READY = 2 */
2516+ {
2517+ RIL_APPTYPE_SIM, RIL_APPSTATE_READY,
2518+ RIL_PERSOSUBSTATE_READY,
2519+ NULL, NULL, 0,
2520+ RIL_PINSTATE_UNKNOWN,
2521+ RIL_PINSTATE_UNKNOWN
2522+ },
2523+ /* SIM_PIN = 3 */
2524+ {
2525+ RIL_APPTYPE_SIM, RIL_APPSTATE_PIN,
2526+ RIL_PERSOSUBSTATE_UNKNOWN,
2527+ NULL, NULL, 0,
2528+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2529+ RIL_PINSTATE_UNKNOWN
2530+ },
2531+ /* SIM_PUK = 4 */
2532+ {
2533+ RIL_APPTYPE_SIM, RIL_APPSTATE_PUK,
2534+ RIL_PERSOSUBSTATE_UNKNOWN,
2535+ NULL, NULL, 0,
2536+ RIL_PINSTATE_ENABLED_BLOCKED,
2537+ RIL_PINSTATE_UNKNOWN
2538+ },
2539+ /* SIM_NETWORK_PERSO = 5 */
2540+ {
2541+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2542+ RIL_PERSOSUBSTATE_SIM_NETWORK,
2543+ NULL, NULL, 0,
2544+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2545+ RIL_PINSTATE_UNKNOWN
2546+ },
2547+ /* SIM_PIN2 = 6 */
2548+ {
2549+ RIL_APPTYPE_SIM, RIL_APPSTATE_READY,
2550+ RIL_PERSOSUBSTATE_UNKNOWN,
2551+ NULL, NULL, 0,
2552+ RIL_PINSTATE_UNKNOWN,
2553+ RIL_PINSTATE_ENABLED_NOT_VERIFIED
2554+ },
2555+ /* SIM_PUK2 = 7 */
2556+ {
2557+ RIL_APPTYPE_SIM, RIL_APPSTATE_READY,
2558+ RIL_PERSOSUBSTATE_UNKNOWN,
2559+ NULL, NULL, 0,
2560+ RIL_PINSTATE_UNKNOWN,
2561+ RIL_PINSTATE_ENABLED_BLOCKED
2562+ },
2563+ /* SIM_NETWORK_SUBSET_PERSO = 8 */
2564+ {
2565+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2566+ RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET,
2567+ NULL, NULL, 0,
2568+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2569+ RIL_PINSTATE_UNKNOWN
2570+ },
2571+ /* SIM_SERVICE_PROVIDER_PERSO = 9 */
2572+ {
2573+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2574+ RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER,
2575+ NULL, NULL, 0,
2576+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2577+ RIL_PINSTATE_UNKNOWN
2578+ },
2579+ /* SIM_CORPORATE_PERSO = 10 */
2580+ {
2581+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2582+ RIL_PERSOSUBSTATE_SIM_CORPORATE,
2583+ NULL, NULL, 0,
2584+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2585+ RIL_PINSTATE_UNKNOWN
2586+ },
2587+ /* SIM_SIM_PERSO = 11 */
2588+ {
2589+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2590+ RIL_PERSOSUBSTATE_SIM_SIM,
2591+ NULL, NULL, 0,
2592+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2593+ RIL_PINSTATE_UNKNOWN
2594+ },
2595+ /* SIM_STERICSSON_LOCK = 12 */
2596+ {
2597+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2598+ RIL_PERSOSUBSTATE_UNKNOWN, /* API (ril.h) does not have this lock */
2599+ NULL, NULL, 0,
2600+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2601+ RIL_PINSTATE_UNKNOWN
2602+ },
2603+ /* SIM_BLOCKED = 13 */
2604+ {
2605+ RIL_APPTYPE_SIM, RIL_APPSTATE_UNKNOWN,
2606+ RIL_PERSOSUBSTATE_UNKNOWN,
2607+ NULL, NULL, 0,
2608+ RIL_PINSTATE_ENABLED_BLOCKED,
2609+ RIL_PINSTATE_UNKNOWN
2610+ },
2611+ /* SIM_PERM_BLOCKED = 14 */
2612+ {
2613+ RIL_APPTYPE_SIM, RIL_APPSTATE_UNKNOWN,
2614+ RIL_PERSOSUBSTATE_UNKNOWN,
2615+ NULL, NULL, 0,
2616+ RIL_PINSTATE_ENABLED_PERM_BLOCKED,
2617+ RIL_PINSTATE_UNKNOWN
2618+ },
2619+ /* SIM_NETWORK_PERSO_PUK = 15 */
2620+ {
2621+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2622+ RIL_PERSOSUBSTATE_SIM_NETWORK_PUK,
2623+ NULL, NULL, 0,
2624+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2625+ RIL_PINSTATE_UNKNOWN
2626+ },
2627+ /* SIM_NETWORK_SUBSET_PERSO_PUK = 16 */
2628+ {
2629+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2630+ RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK,
2631+ NULL, NULL, 0,
2632+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2633+ RIL_PINSTATE_UNKNOWN
2634+ },
2635+ /* SIM_SERVICE_PROVIDER_PERSO_PUK = 17 */
2636+ {
2637+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2638+ RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK,
2639+ NULL, NULL, 0,
2640+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2641+ RIL_PINSTATE_UNKNOWN
2642+ },
2643+ /* SIM_CORPORATE_PERSO_PUK = 18 */
2644+ {
2645+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2646+ RIL_PERSOSUBSTATE_SIM_CORPORATE_PUK,
2647+ NULL, NULL, 0,
2648+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2649+ RIL_PINSTATE_UNKNOWN
2650+ },
2651+ /* SIM_SIM_PERSO_PUK = 19 */
2652+ {
2653+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO,
2654+ RIL_PERSOSUBSTATE_SIM_SIM_PUK,
2655+ NULL, NULL, 0,
2656+ RIL_PINSTATE_ENABLED_NOT_VERIFIED,
2657+ RIL_PINSTATE_UNKNOWN
2658+ },
2659+ /* SIM_PUK2_PERM_BLOCKED = 20 */
2660+ {
2661+ RIL_APPTYPE_SIM, RIL_APPSTATE_UNKNOWN,
2662+ RIL_PERSOSUBSTATE_UNKNOWN,
2663+ NULL, NULL, 0,
2664+ RIL_PINSTATE_UNKNOWN,
2665+ RIL_PINSTATE_ENABLED_PERM_BLOCKED
2666+ }
2667+};
2668+
2669+
2670+/**
2671+ * Get the current card status.
2672+ *
2673+ * This must be freed using freeCardStatus.
2674+ * @return: On success returns RIL_E_SUCCESS.
2675+ */
2676+static int getCardStatus(RIL_CardStatus_v6 **pp_card_status)
2677+{
2678+ RIL_CardState card_state;
2679+ int num_apps;
2680+
2681+ SIM_Status sim_status = getSIMStatus();
2682+ if (sim_status == SIM_ABSENT) {
2683+ card_state = RIL_CARDSTATE_ABSENT;
2684+ num_apps = 0;
2685+ } else {
2686+ card_state = RIL_CARDSTATE_PRESENT;
2687+ num_apps = 1;
2688+ }
2689+
2690+ /* Allocate and initialize base card status. */
2691+ RIL_CardStatus_v6 *p_card_status = (RIL_CardStatus_v6 *) malloc(sizeof(RIL_CardStatus_v6));
2692+ p_card_status->card_state = card_state;
2693+ p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
2694+ p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
2695+ p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
2696+ p_card_status->ims_subscription_app_index = RIL_CARD_MAX_APPS;
2697+ p_card_status->num_applications = num_apps;
2698+
2699+ /* Initialize application status. */
2700+ int i;
2701+ for (i = 0; i < RIL_CARD_MAX_APPS; i++)
2702+ p_card_status->applications[i] = app_status_array[SIM_ABSENT];
2703+
2704+ /* Pickup the appropriate application status
2705+ that reflects sim_status for gsm. */
2706+ if (num_apps != 0) {
2707+ UICC_Type uicc_type = getUICCType();
2708+
2709+ /* Only support one app, gsm/wcdma. */
2710+ p_card_status->num_applications = 1;
2711+ p_card_status->gsm_umts_subscription_app_index = 0;
2712+
2713+ /* Get the correct app status. */
2714+ p_card_status->applications[0] = app_status_array[sim_status];
2715+ if (uicc_type == UICC_TYPE_SIM)
2716+ LOGI("[Card type discovery]: Legacy SIM");
2717+ else { /* defaulting to USIM */
2718+ LOGI("[Card type discovery]: USIM");
2719+ p_card_status->applications[0].app_type = RIL_APPTYPE_USIM;
2720+ }
2721+ }
2722+
2723+ *pp_card_status = p_card_status;
2724+ return RIL_E_SUCCESS;
2725+}
2726+
2727+/**
2728+ * Free the card status returned by getCardStatus.
2729+ */
2730+static void freeCardStatus(RIL_CardStatus_v6 *p_card_status) {
2731+ free(p_card_status);
2732+}
2733+
2734+/**
2735+ * RIL_REQUEST_GET_SIM_STATUS
2736+ *
2737+ * Requests status of the SIM interface and the SIM card.
2738+ *
2739+ * Valid errors:
2740+ * Must never fail.
2741+ */
2742+static void requestGetSimStatus(RIL_Token t)
2743+{
2744+ RIL_CardStatus_v6* p_card_status = NULL;
2745+
2746+ if (getCardStatus(&p_card_status) != RIL_E_SUCCESS)
2747+ goto error;
2748+
2749+ RIL_onRequestComplete(t, RIL_E_SUCCESS, (char*)p_card_status, sizeof(*p_card_status));
2750+
2751+finally:
2752+ if (p_card_status != NULL)
2753+ freeCardStatus(p_card_status);
2754+ return;
2755+
2756+error:
2757+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2758+ goto finally;
2759+}
2760+
2761+
2762+
2763+/**
2764+ * RIL_REQUEST_CHANGE_SIM_PIN
2765+ * RIL_REQUEST_CHANGE_SIM_PIN2
2766+*/
2767+static void requestChangePassword(void *data, size_t datalen, RIL_Token t,
2768+ const char *facility, int request)
2769+{
2770+ int err = 0;
2771+ char *oldPassword = NULL;
2772+ char *newPassword = NULL;
2773+ int num_retries = -1;
2774+
2775+ if (datalen != 3 * sizeof(char *) || strlen(facility) != 2)
2776+ goto error;
2777+
2778+
2779+ oldPassword = ((char **) data)[0];
2780+ newPassword = ((char **) data)[1];
2781+
2782+ err = at_send_command("AT+CPWD=\"%s\",\"%s\",\"%s\"", facility,
2783+ oldPassword, newPassword);
2784+ if (err != AT_NOERROR)
2785+ goto error;
2786+
2787+ num_retries = 3;
2788+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &num_retries, sizeof(int *));
2789+
2790+ return;
2791+
2792+error:
2793+ if (at_get_cme_error(err) == CME_INCORRECT_PASSWORD) {
2794+ num_retries = 3;
2795+ RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &num_retries, sizeof(int *));
2796+ } else {
2797+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2798+ }
2799+}
2800+
2801+
2802+/**
2803+ * RIL_REQUEST_QUERY_FACILITY_LOCK
2804+ *
2805+ * Query the status of a facility lock state.
2806+ */
2807+static void requestQueryFacilityLock(void *data, size_t datalen, RIL_Token t)
2808+{
2809+ int err, response;
2810+ ATResponse *atResponse = NULL;
2811+ char *line = NULL;
2812+ char *facility_string = NULL;
2813+ char *facility_password = NULL;
2814+ char *facility_class = NULL;
2815+
2816+ (void) datalen;
2817+
2818+ if (datalen < 3 * sizeof(char **)) {
2819+ LOGE("%s() bad data length!", __func__);
2820+ goto error;
2821+ }
2822+
2823+ facility_string = ((char **) data)[0];
2824+ facility_password = ((char **) data)[1];
2825+ facility_class = ((char **) data)[2];
2826+
2827+ err = at_send_command_singleline("AT+CLCK=\"%s\",2,%s,%s", "+CLCK:", &atResponse,
2828+ facility_string, facility_password, facility_class);
2829+ if (err != AT_NOERROR)
2830+ goto error;
2831+
2832+ line = atResponse->p_intermediates->line;
2833+
2834+ err = at_tok_start(&line);
2835+
2836+ if (err < 0)
2837+ goto error;
2838+
2839+ err = at_tok_nextint(&line, &response);
2840+
2841+ if (err < 0)
2842+ goto error;
2843+
2844+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
2845+ at_response_free(atResponse);
2846+ return;
2847+
2848+error:
2849+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
2850+ at_response_free(atResponse);
2851+}
2852+
2853+
2854+/**
2855+ * RIL_REQUEST_SET_FACILITY_LOCK
2856+ *
2857+ * Enable/disable one facility lock.
2858+ */
2859+static void requestSetFacilityLock(void *data, size_t datalen, RIL_Token t)
2860+{
2861+ int err;
2862+ char *facility_string = NULL;
2863+ int facility_mode = -1;
2864+ char *facility_mode_str = NULL;
2865+ char *facility_password = NULL;
2866+ char *facility_class = NULL;
2867+ int num_retries = -1;
2868+ RIL_Errno errorril = RIL_E_GENERIC_FAILURE;
2869+ (void) datalen;
2870+
2871+ if (datalen < 4 * sizeof(char **)) {
2872+ LOGE("%s() bad data length!", __func__);
2873+ goto exit;
2874+ }
2875+
2876+ facility_string = ((char **) data)[0];
2877+ facility_mode_str = ((char **) data)[1];
2878+ facility_password = ((char **) data)[2];
2879+ facility_class = ((char **) data)[3];
2880+
2881+ if (*facility_mode_str != '0' && *facility_mode_str != '1') {
2882+ LOGE("%s() bad facility mode!", __func__);
2883+ goto exit;
2884+ }
2885+
2886+ facility_mode = atoi(facility_mode_str);
2887+
2888+ /*
2889+ * Skip adding facility_password to AT command parameters if it is NULL,
2890+ * printing NULL with %s will give string "(null)".
2891+ */
2892+ err = at_send_command("AT+CLCK=\"%s\",%d,\"%s\",%s", facility_string,
2893+ facility_mode, facility_password, facility_class);
2894+
2895+ if (at_get_error_type(err) == AT_ERROR)
2896+ goto exit;
2897+ if (err != AT_NOERROR) {
2898+ switch (at_get_cme_error(err)) {
2899+ /* CME ERROR 11: "SIM PIN required" happens when PIN is wrong */
2900+ case CME_SIM_PIN_REQUIRED:
2901+ LOGI("Wrong PIN");
2902+ errorril = RIL_E_PASSWORD_INCORRECT;
2903+ break;
2904+ /*
2905+ * CME ERROR 12: "SIM PUK required" happens when wrong PIN is used
2906+ * 3 times in a row
2907+ */
2908+ case CME_SIM_PUK_REQUIRED:
2909+ LOGI("PIN locked, change PIN with PUK");
2910+ num_retries = 0;/* PUK required */
2911+ errorril = RIL_E_PASSWORD_INCORRECT;
2912+ break;
2913+ /* CME ERROR 16: "Incorrect password" happens when PIN is wrong */
2914+ case CME_INCORRECT_PASSWORD:
2915+ LOGI("Incorrect password, Facility: %s", facility_string);
2916+ errorril = RIL_E_PASSWORD_INCORRECT;
2917+ break;
2918+ /* CME ERROR 17: "SIM PIN2 required" happens when PIN2 is wrong */
2919+ case CME_SIM_PIN2_REQUIRED:
2920+ LOGI("Wrong PIN2");
2921+ errorril = RIL_E_PASSWORD_INCORRECT;
2922+ break;
2923+ /*
2924+ * CME ERROR 18: "SIM PUK2 required" happens when wrong PIN2 is used
2925+ * 3 times in a row
2926+ */
2927+ case CME_SIM_PUK2_REQUIRED:
2928+ LOGI("PIN2 locked, change PIN2 with PUK2");
2929+ num_retries = 0;/* PUK2 required */
2930+ errorril = RIL_E_SIM_PUK2;
2931+ break;
2932+ default: /* some other error */
2933+ num_retries = -1;
2934+ break;
2935+ }
2936+ goto finally;
2937+ }
2938+
2939+ errorril = RIL_E_SUCCESS;
2940+
2941+finally:
2942+ if (strncmp(facility_string, "SC", 2) == 0)
2943+ num_retries = 1;
2944+ else if (strncmp(facility_string, "FD", 2) == 0)
2945+ num_retries = 1;
2946+exit:
2947+ RIL_onRequestComplete(t, errorril, &num_retries, sizeof(int *));
2948+}
2949+
2950+
2951+
2952+/**
2953+ * Enter SIM PIN, might be PIN, PIN2, PUK, PUK2, etc.
2954+ *
2955+ * Data can hold pointers to one or two strings, depending on what we
2956+ * want to enter. (PUK requires new PIN, etc.).
2957+ *
2958+ * FIXME: Do we need to return remaining tries left on error as well?
2959+ * Also applies to the rest of the requests that got the retries
2960+ * in later commits to ril.h.
2961+ */
2962+static void requestEnterSimPin(void *data, size_t datalen, RIL_Token t, int request)
2963+{
2964+ int err = 0;
2965+ int cme_err;
2966+ const char **strings = (const char **) data;
2967+ int num_retries = -1;
2968+
2969+ if (datalen == sizeof(char *)) {
2970+ err = at_send_command("AT+CPIN=\"%s\"", strings[0]);
2971+ } else if (datalen == 2 * sizeof(char *)) {
2972+ if (!strings[1]){
2973+ err = at_send_command("AT+CPIN=\"%s\"", strings[0]);
2974+ } else {
2975+ err = at_send_command("AT+CPIN=\"%s\",\"%s\"", strings[0], strings[1]);
2976+ }
2977+ } else if (datalen == 3 * sizeof(char *)) {
2978+ err = at_send_command("AT+CPIN=\"%s\",\"%s\"", strings[0], strings[1]);
2979+ } else {
2980+ goto error;
2981+ }
2982+
2983+ cme_err = at_get_cme_error(err);
2984+
2985+ if (cme_err != CME_ERROR_NON_CME && err != AT_NOERROR) {
2986+ switch (cme_err) {
2987+ case CME_SIM_PIN_REQUIRED:
2988+ case CME_SIM_PUK_REQUIRED:
2989+ case CME_INCORRECT_PASSWORD:
2990+ case CME_SIM_PIN2_REQUIRED:
2991+ case CME_SIM_PUK2_REQUIRED:
2992+ num_retries = 1;
2993+ RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, &num_retries, sizeof(int *));
2994+ break;
2995+ default:
2996+ goto error;
2997+ }
2998+ } else {
2999+ /*
3000+ * Got OK, return success and wait for *EPEV to trigger poll
3001+ * of SIM state.
3002+ */
3003+
3004+ num_retries = 1;
3005+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &num_retries, sizeof(int *));
3006+ }
3007+ return;
3008+error:
3009+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3010+}
3011+
3012+
3013+/**
3014+ * RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE
3015+ *
3016+ * Query current network selectin mode.
3017+ */
3018+static void requestQueryNetworkSelectionMode(RIL_Token t)
3019+{
3020+ int err;
3021+ ATResponse *atResponse = NULL;
3022+ int response = 0;
3023+ char *line;
3024+
3025+ err = at_send_command_singleline("AT+COPS?", "+COPS:", &atResponse);
3026+
3027+ if (err != AT_NOERROR)
3028+ goto error;
3029+
3030+ line = atResponse->p_intermediates->line;
3031+
3032+ err = at_tok_start(&line);
3033+
3034+ if (err < 0)
3035+ goto error;
3036+
3037+ err = at_tok_nextint(&line, &response);
3038+
3039+ if (err < 0)
3040+ goto error;
3041+
3042+ /*
3043+ * Android accepts 0(automatic) and 1(manual).
3044+ * Modem may return mode 4(Manual/automatic).
3045+ * Convert it to 1(Manual) as android expects.
3046+ */
3047+ if (response == 4)
3048+ response = 1;
3049+
3050+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
3051+
3052+finally:
3053+ at_response_free(atResponse);
3054+ return;
3055+
3056+error:
3057+ LOGE("%s() Must never return error when radio is on", __func__);
3058+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3059+ goto finally;
3060+}
3061+
3062+
3063+struct operatorPollParams {
3064+ RIL_Token t;
3065+ int loopcount;
3066+};
3067+
3068+
3069+#define REPOLL_OPERATOR_SELECTED 30 /* 30 * 2 = 1M = ok? */
3070+static const struct timespec TIMEVAL_OPERATOR_SELECT_POLL = { 2, 0 };
3071+
3072+/*
3073+ * s_registrationDeniedReason is used to keep track of registration deny
3074+ * reason for which is called by pollOperatorSelected from
3075+ * RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, so that in case
3076+ * of invalid SIM/ME, Android will not continuously poll for operator.
3077+ *
3078+ */
3079+static Reg_Deny_DetailReason s_registrationDeniedReason = DEFAULT_VALUE;
3080+
3081+
3082+/**
3083+ * Poll +COPS? and return a success, or if the loop counter reaches
3084+ * REPOLL_OPERATOR_SELECTED, return generic failure.
3085+ */
3086+static void pollOperatorSelected(void *params)
3087+{
3088+ int err = 0;
3089+ int response = 0;
3090+ char *line = NULL;
3091+ ATResponse *atResponse = NULL;
3092+ struct operatorPollParams *poll_params;
3093+ RIL_Token t;
3094+
3095+ assert(params != NULL);
3096+
3097+ poll_params = (struct operatorPollParams *) params;
3098+ t = poll_params->t;
3099+
3100+ if (poll_params->loopcount >= REPOLL_OPERATOR_SELECTED)
3101+ goto error;
3102+
3103+ err = at_send_command_singleline("AT+COPS?", "+COPS:", &atResponse);
3104+ if (err != AT_NOERROR)
3105+ goto error;
3106+
3107+ line = atResponse->p_intermediates->line;
3108+
3109+ err = at_tok_start(&line);
3110+ if (err < 0)
3111+ goto error;
3112+
3113+ err = at_tok_nextint(&line, &response);
3114+ if (err < 0)
3115+ goto error;
3116+
3117+ /* If we don't get more than the COPS: {0-4} we are not registered.
3118+ Loop and try again. */
3119+ if (!at_tok_hasmore(&line)) {
3120+ switch (s_registrationDeniedReason) {
3121+ case IMSI_UNKNOWN_IN_HLR: /* fall through */
3122+ case ILLEGAL_ME:
3123+ RIL_onRequestComplete(t, RIL_E_ILLEGAL_SIM_OR_ME, NULL, 0);
3124+ free(poll_params);
3125+ break;
3126+ default:
3127+ poll_params->loopcount++;
3128+ enqueueRILEvent(pollOperatorSelected,
3129+ poll_params, &TIMEVAL_OPERATOR_SELECT_POLL);
3130+ }
3131+ } else {
3132+ /* We got operator, throw a success! */
3133+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
3134+ free(poll_params);
3135+ }
3136+
3137+ at_response_free(atResponse);
3138+ return;
3139+
3140+error:
3141+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3142+ free(poll_params);
3143+ at_response_free(atResponse);
3144+ return;
3145+}
3146+
3147+/**
3148+ * RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC
3149+ *
3150+ * Specify that the network should be selected automatically.
3151+*/
3152+static void requestSetNetworkSelectionAutomatic(RIL_Token t)
3153+{
3154+ int err = 0;
3155+ ATResponse *atResponse = NULL;
3156+ int mode = 0;
3157+ int skip;
3158+ char *line;
3159+ char *netOperator = NULL;
3160+ struct operatorPollParams *poll_params = NULL;
3161+
3162+ poll_params = (struct operatorPollParams*)
3163+ malloc(sizeof(struct operatorPollParams));
3164+ if (NULL == poll_params)
3165+ goto error;
3166+
3167+ /* First check if we are already scanning or in manual mode */
3168+ err = at_send_command_singleline("AT+COPS=3,2;+COPS?", "+COPS:", &atResponse);
3169+ if (err != AT_NOERROR)
3170+ goto error;
3171+
3172+ line = atResponse->p_intermediates->line;
3173+
3174+ err = at_tok_start(&line);
3175+ if (err < 0)
3176+ goto error;
3177+
3178+ /* Read network selection mode */
3179+ err = at_tok_nextint(&line, &mode);
3180+ if (err < 0)
3181+ goto error;
3182+
3183+ /* If we're unregistered, we may just get
3184+ a "+COPS: 0" response. */
3185+ if (!at_tok_hasmore(&line)) {
3186+ if (mode == 1) {
3187+ D("%s() Changing manual to automatic network mode", __func__);
3188+ goto do_auto;
3189+ } else
3190+ goto check_reg;
3191+ }
3192+
3193+ err = at_tok_nextint(&line, &skip);
3194+ if (err < 0)
3195+ goto error;
3196+
3197+ /* A "+COPS: 0, n" response is also possible. */
3198+ if (!at_tok_hasmore(&line)) {
3199+ if (mode == 1) {
3200+ D("%s() Changing manual to automatic network mode", __func__);
3201+ goto do_auto;
3202+ } else
3203+ goto check_reg;
3204+ }
3205+
3206+ /* Read numeric operator */
3207+ err = at_tok_nextstr(&line, &netOperator);
3208+ if (err < 0)
3209+ goto error;
3210+
3211+ /* If operator is found then do a new scan,
3212+ else let it continue the already pending scan */
3213+ if (netOperator && strlen(netOperator) == 0) {
3214+ if (mode == 1) {
3215+ D("%s() Changing manual to automatic network mode", __func__);
3216+ goto do_auto;
3217+ } else
3218+ goto check_reg;
3219+ }
3220+
3221+ /* Operator found */
3222+ if (mode == 1) {
3223+ D("%s() Changing manual to automatic network mode", __func__);
3224+ goto do_auto;
3225+ } else {
3226+ D("%s() Already in automatic mode with known operator, trigger a new network scan",
3227+ __func__);
3228+ goto do_auto;
3229+ }
3230+
3231+ /* Check if module is scanning,
3232+ if not then trigger a rescan */
3233+check_reg:
3234+ at_response_free(atResponse);
3235+ atResponse = NULL;
3236+
3237+ /* Check CS domain first */
3238+ err = at_send_command_singleline("AT+CREG?", "+CREG:", &atResponse);
3239+ if (err != AT_NOERROR)
3240+ goto error;
3241+
3242+ line = atResponse->p_intermediates->line;
3243+
3244+ err = at_tok_start(&line);
3245+ if (err < 0)
3246+ goto error;
3247+
3248+ /* Read registration unsolicited mode */
3249+ err = at_tok_nextint(&line, &mode);
3250+ if (err < 0)
3251+ goto error;
3252+
3253+ /* Read registration status */
3254+ err = at_tok_nextint(&line, &mode);
3255+ if (err < 0)
3256+ goto error;
3257+
3258+ /* If scanning has stopped, then perform a new scan */
3259+ if (mode == 0) {
3260+ D("%s() Already in automatic mode, but not currently scanning on CS,"
3261+ "trigger a new network scan", __func__);
3262+ goto do_auto;
3263+ }
3264+
3265+ /* Now check PS domain */
3266+ at_response_free(atResponse);
3267+ atResponse = NULL;
3268+ err = at_send_command_singleline("AT+CGREG?", "+CGREG:", &atResponse);
3269+ if (err != AT_NOERROR)
3270+ goto error;
3271+
3272+ line = atResponse->p_intermediates->line;
3273+
3274+ err = at_tok_start(&line);
3275+ if (err < 0)
3276+ goto error;
3277+
3278+ /* Read registration unsolicited mode */
3279+ err = at_tok_nextint(&line, &mode);
3280+ if (err < 0)
3281+ goto error;
3282+
3283+ /* Read registration status */
3284+ err = at_tok_nextint(&line, &mode);
3285+ if (err < 0)
3286+ goto error;
3287+
3288+ /* If scanning has stopped, then perform a new scan */
3289+ if (mode == 0) {
3290+ D("%s() Already in automatic mode, but not currently scanning on PS,"
3291+ "trigger a new network scan", __func__);
3292+ goto do_auto;
3293+ } else {
3294+ D("%s() Already in automatic mode and scanning", __func__);
3295+ goto finish_scan;
3296+ }
3297+
3298+do_auto:
3299+ at_response_free(atResponse);
3300+ atResponse = NULL;
3301+
3302+ /* This command does two things, one it sets automatic mode,
3303+ two it starts a new network scan! */
3304+ err = at_send_command("AT+COPS=0");
3305+ if (err != AT_NOERROR)
3306+ goto error;
3307+
3308+finish_scan:
3309+
3310+ at_response_free(atResponse);
3311+ atResponse = NULL;
3312+
3313+ poll_params->loopcount = 0;
3314+ poll_params->t = t;
3315+
3316+ enqueueRILEvent(pollOperatorSelected,
3317+ poll_params, &TIMEVAL_OPERATOR_SELECT_POLL);
3318+
3319+ return;
3320+
3321+error:
3322+ free(poll_params);
3323+ at_response_free(atResponse);
3324+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3325+ return;
3326+}
3327+
3328+
3329+/**
3330+ * RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL
3331+ *
3332+ * Manually select a specified network.
3333+ *
3334+ * The radio baseband/RIL implementation is expected to fall back to
3335+ * automatic selection mode if the manually selected network should go
3336+ * out of range in the future.
3337+ */
3338+void requestSetNetworkSelectionManual(void *data, size_t datalen,
3339+ RIL_Token t)
3340+{
3341+ /*
3342+ * AT+COPS=[<mode>[,<format>[,<oper>[,<AcT>]]]]
3343+ * <mode> = 4 = Manual (<oper> field shall be present and AcT optionally) with fallback to automatic if manual fails.
3344+ * <format> = 2 = Numeric <oper>, the number has structure:
3345+ * (country code digit 3)(country code digit 2)(country code digit 1)
3346+ * (network code digit 2)(network code digit 1)
3347+ */
3348+
3349+ (void) datalen;
3350+ int err = 0;
3351+ const char *mccMnc = (const char *) data;
3352+
3353+ /* Check inparameter. */
3354+ if (mccMnc == NULL)
3355+ goto error;
3356+
3357+ /* Build and send command. */
3358+ err = at_send_command("AT+COPS=1,2,\"%s\"", mccMnc);
3359+ if (err != AT_NOERROR) {
3360+ err = at_send_command("AT+COPS=0");
3361+ if(err != AT_NOERROR)
3362+ goto error;
3363+ }
3364+
3365+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
3366+ return;
3367+
3368+error:
3369+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3370+}
3371+
3372+
3373+
3374+/**
3375+ * RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
3376+ *
3377+ * Scans for available networks.
3378+*/
3379+static void requestQueryAvailableNetworks(RIL_Token t)
3380+{
3381+ #define QUERY_NW_NUM_PARAMS 4
3382+
3383+ /*
3384+ * AT+COPS=?
3385+ * +COPS: [list of supported (<stat>,long alphanumeric <oper>
3386+ * ,short alphanumeric <oper>,numeric <oper>[,<AcT>])s]
3387+ * [,,(list of supported <mode>s),(list of supported <format>s)]
3388+ *
3389+ * <stat>
3390+ * 0 = unknown
3391+ * 1 = available
3392+ * 2 = current
3393+ * 3 = forbidden
3394+ */
3395+ int err = 0;
3396+ ATResponse *atResponse = NULL;
3397+ const char *statusTable[] =
3398+ { "unknown", "available", "current", "forbidden" };
3399+ char **responseArray = NULL;
3400+ char *p;
3401+ int n = 0;
3402+ int i = 0;
3403+
3404+ err = at_send_command_multiline("AT+COPS=?", "+COPS:", &atResponse);
3405+ if (err != AT_NOERROR || atResponse->p_intermediates == NULL) {
3406+ LOGE("Failed to get operator responses: err:%d, intermediates: %p",err,atResponse->p_intermediates);
3407+ goto error;
3408+ }
3409+
3410+ p = atResponse->p_intermediates->line;
3411+ LOGD("Got line '%s'",p);
3412+
3413+ /* count number of '('. */
3414+ err = at_tok_charcounter(p, '(', &n);
3415+ if (err < 0) goto error;
3416+
3417+ /* We don't want to process the list of supported modes and the list of supported
3418+ commands, so just skip them */
3419+ if (n < 2) n = 0;
3420+ else n -= 2;
3421+
3422+ /* Allocate array of strings, blocks of 4 strings. */
3423+ responseArray = (char **)alloca(n * QUERY_NW_NUM_PARAMS * sizeof(char *));
3424+
3425+ /* Loop and collect response information into the response array. */
3426+ for (i = 0; i < n; i++) {
3427+ int status = 0;
3428+ char *line = NULL;
3429+ char *s = NULL;
3430+ char *longAlphaNumeric = NULL;
3431+ char *shortAlphaNumeric = NULL;
3432+ char *numeric = NULL;
3433+ char *remaining = NULL;
3434+
3435+ s = line = getFirstElementValue(p, "(", ")", &remaining);
3436+ p = remaining;
3437+
3438+ if (line == NULL) {
3439+ LOGE("%s() Null pointer while parsing COPS response."
3440+ "This should not happen.", __func__);
3441+ break;
3442+ }
3443+
3444+ LOGD("%d operator: '%s'",i,line);
3445+
3446+ /* <stat> */
3447+ err = at_tok_nextint(&line, &status);
3448+ if (err < 0) {
3449+error2:
3450+ free(s);
3451+ goto error;
3452+ }
3453+
3454+ /* long alphanumeric <oper> */
3455+ err = at_tok_nextstr(&line, &longAlphaNumeric);
3456+ if (err < 0)
3457+ goto error2;
3458+
3459+ /* short alphanumeric <oper> */
3460+ err = at_tok_nextstr(&line, &shortAlphaNumeric);
3461+ if (err < 0)
3462+ goto error2;
3463+
3464+ /* numeric <oper> */
3465+ err = at_tok_nextstr(&line, &numeric);
3466+ if (err < 0)
3467+ goto error2;
3468+
3469+ responseArray[i * QUERY_NW_NUM_PARAMS + 0] = (char*) alloca(strlen(longAlphaNumeric) + 1);
3470+ strcpy(responseArray[i * QUERY_NW_NUM_PARAMS + 0], longAlphaNumeric);
3471+
3472+ responseArray[i * QUERY_NW_NUM_PARAMS + 1] = (char*) alloca(strlen(shortAlphaNumeric) + 1);
3473+ strcpy(responseArray[i * QUERY_NW_NUM_PARAMS + 1], shortAlphaNumeric);
3474+
3475+ responseArray[i * QUERY_NW_NUM_PARAMS + 2] = (char*) alloca(strlen(numeric) + 1);
3476+ strcpy(responseArray[i * QUERY_NW_NUM_PARAMS + 2], numeric);
3477+
3478+ free(s);
3479+
3480+ /*
3481+ * Check if modem returned an empty string, and fill it with MNC/MMC
3482+ * if that's the case.
3483+ */
3484+ if (responseArray[i * QUERY_NW_NUM_PARAMS + 0] && strlen(responseArray[i * QUERY_NW_NUM_PARAMS + 0]) == 0) {
3485+ responseArray[i * QUERY_NW_NUM_PARAMS + 0] = (char*) alloca(strlen(responseArray[i * QUERY_NW_NUM_PARAMS + 2]) + 1);
3486+ strcpy(responseArray[i * QUERY_NW_NUM_PARAMS + 0], responseArray[i * QUERY_NW_NUM_PARAMS + 2]);
3487+ }
3488+
3489+ if (responseArray[i * QUERY_NW_NUM_PARAMS + 1] && strlen(responseArray[i * QUERY_NW_NUM_PARAMS + 1]) == 0) {
3490+ responseArray[i * QUERY_NW_NUM_PARAMS + 1] = (char*) alloca(strlen(responseArray[i * QUERY_NW_NUM_PARAMS + 2]) + 1);
3491+ strcpy(responseArray[i * QUERY_NW_NUM_PARAMS + 1], responseArray[i * QUERY_NW_NUM_PARAMS + 2]);
3492+ }
3493+
3494+ /* Add status */
3495+ responseArray[i * QUERY_NW_NUM_PARAMS + 3] = (char*) alloca(strlen(statusTable[status])+1);
3496+ strcpy(responseArray[i * QUERY_NW_NUM_PARAMS + 3],statusTable[status]);
3497+ }
3498+
3499+ RIL_onRequestComplete(t, RIL_E_SUCCESS, responseArray,
3500+ i * QUERY_NW_NUM_PARAMS * sizeof(char *));
3501+
3502+finally:
3503+ at_response_free(atResponse);
3504+ return;
3505+
3506+error:
3507+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3508+ goto finally;
3509+}
3510+
3511+
3512+/**
3513+ * RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
3514+ *
3515+ * Requests to set the preferred network type for searching and registering
3516+ * (CS/PS domain, RAT, and operation mode).
3517+ */
3518+static void requestSetPreferredNetworkType(void *data, size_t datalen, RIL_Token t)
3519+{
3520+ int rat,err;
3521+ const char* cmd;
3522+
3523+ assert (datalen >= sizeof(int *));
3524+ rat = ((int *)data)[0];
3525+
3526+ /* Huawei specific
3527+ AT^SYSCFG=2,1,3FFFFFFF,2,4 for GPRS/EDGE Preferred
3528+ AT^SYSCFG=2,2,3FFFFFFF,2,4 for 3G Preferred
3529+ AT^SYSCFG=13,1,3FFFFFFF,2,4 for GPRS/EDGE Only
3530+ AT^SYSCFG=14,2,3FFFFFFF,2,4 for 3G Only
3531+
3532+ The third parameter, 0x3FFFFFFF tells the card to use all bands.
3533+ A value of 0x400380 here means GSM900/1800/WCDMA2100 only and a
3534+ value of 0x200000 here means GSM1900 only.
3535+
3536+ */
3537+
3538+ switch (rat) {
3539+ case PREF_NET_TYPE_GSM_ONLY: /* GSM only */
3540+ cmd = "AT^SYSCFG=13,1,3FFFFFFF,2,4"; /* for GPRS/EDGE Only */
3541+ break;
3542+ case PREF_NET_TYPE_GSM_WCDMA: /* WCDMA only */
3543+ cmd = "AT^SYSCFG=14,2,3FFFFFFF,2,4"; /* for 3G Only */
3544+ break;
3545+ case PREF_NET_TYPE_GSM_WCDMA_AUTO:
3546+ default: /* Dual Mode - WCDMA preferred*/
3547+ cmd = "AT^SYSCFG=2,2,3FFFFFFF,2,4"; /* for 3G Preferred */
3548+ break;
3549+ }
3550+
3551+ /* Set mode */
3552+ err = at_send_command(cmd);
3553+ if (err != AT_NOERROR)
3554+ goto error;
3555+
3556+
3557+ /* Trigger autoregister */
3558+ err = at_send_command("AT+COPS=0");
3559+ if (err != AT_NOERROR)
3560+ goto error;
3561+
3562+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, sizeof(int));
3563+ return;
3564+
3565+error:
3566+ LOGE("ERROR: requestSetPreferredNetworkType() failed\n");
3567+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3568+}
3569+
3570+
3571+/**
3572+ * RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE
3573+ *
3574+ * Query the preferred network type (CS/PS domain, RAT, and operation mode)
3575+ * for searching and registering.
3576+ */
3577+static void requestGetPreferredNetworkType(RIL_Token t)
3578+{
3579+ /*
3580+ AT^SYSCFG=2,1,3FFFFFFF,1,2 for GPRS/EDGE Preferred
3581+ AT^SYSCFG=2,2,3FFFFFFF,1,2 for 3G Preferred
3582+ AT^SYSCFG=13,1,3FFFFFFF,1,2 for GPRS/EDGE Only
3583+ AT^SYSCFG=14,2,3FFFFFFF,1,2 for 3G Only
3584+ */
3585+
3586+ ATResponse *atResponse = NULL;
3587+ int err;
3588+ char *line;
3589+ int ret1,ret2;
3590+ int response = PREF_NET_TYPE_GSM_WCDMA_AUTO;
3591+
3592+ err = at_send_command_singleline("AT^SYSCFG?", "^SYSCFG:", &atResponse);
3593+
3594+ if (err != AT_NOERROR) {
3595+ // assume radio is off
3596+ goto error;
3597+ }
3598+
3599+ line = atResponse->p_intermediates->line;
3600+
3601+ err = at_tok_start(&line);
3602+ if (err < 0) goto error;
3603+
3604+ err = at_tok_nextint(&line, &ret1);
3605+ if (err < 0) goto error;
3606+
3607+ err = at_tok_nextint(&line, &ret2);
3608+ if (err < 0) goto error;
3609+
3610+ /* Based on reported syscfg */
3611+ if (ret1 == 13) {
3612+ response = PREF_NET_TYPE_GSM_ONLY; /* GSM only */
3613+ } else if (ret1 == 14) {
3614+ response = PREF_NET_TYPE_GSM_WCDMA; /* WCDMA only */
3615+ } else {
3616+ response = PREF_NET_TYPE_GSM_WCDMA_AUTO; /* for 3G Preferred */
3617+ }
3618+
3619+ D("requestGetPreferredNetworkType() mode:%d\n",response);
3620+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
3621+ at_response_free(atResponse);
3622+ return;
3623+
3624+error:
3625+ LOGE("ERROR: requestGetPreferredNetworkType() failed - modem does not support command\n");
3626+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3627+ at_response_free(atResponse);
3628+}
3629+
3630+/* +CGREG AcT values */
3631+enum CREG_AcT {
3632+ CGREG_ACT_GSM = 0,
3633+ CGREG_ACT_GSM_COMPACT = 1, /* Not Supported */
3634+ CGREG_ACT_UTRAN = 2,
3635+ CGREG_ACT_GSM_EGPRS = 3,
3636+ CGREG_ACT_UTRAN_HSDPA = 4,
3637+ CGREG_ACT_UTRAN_HSUPA = 5,
3638+ CGREG_ACT_UTRAN_HSUPA_HSDPA = 6
3639+};
3640+
3641+/* +CGREG stat values */
3642+enum CREG_stat {
3643+ CGREG_STAT_NOT_REG = 0,
3644+ CGREG_STAT_REG_HOME_NET = 1,
3645+ CGREG_STAT_NOT_REG_SEARCHING = 2,
3646+ CGREG_STAT_REG_DENIED = 3,
3647+ CGREG_STAT_UKNOWN = 4,
3648+ CGREG_STAT_ROAMING = 5
3649+};
3650+
3651+
3652+/**
3653+ * RIL_REQUEST_VOICE_REGISTRATION_STATE
3654+ *
3655+ * Request current registration state.
3656+ */
3657+static void requestRegistrationState(RIL_Token t)
3658+{
3659+ int err = 0;
3660+ const char resp_size = 15;
3661+ int response[15];
3662+ char *responseStr[15] = {0};
3663+ ATResponse *cgreg_resp = NULL;
3664+ char *line;
3665+ int commas = 0;
3666+ int skip, cs_status = 0;
3667+ int i;
3668+
3669+ /* Setting default values in case values are not returned by AT command */
3670+ for (i = 0; i < resp_size; i++)
3671+ responseStr[i] = NULL;
3672+
3673+ memset(response, 0, sizeof(response));
3674+
3675+ err = at_send_command_singleline("AT+CREG?", "+CREG:", &cgreg_resp);
3676+ if (err != AT_NOERROR)
3677+ goto error;
3678+
3679+ line = cgreg_resp->p_intermediates->line;
3680+
3681+ err = at_tok_start(&line);
3682+ if (err < 0)
3683+ goto error;
3684+
3685+ /*
3686+ * The solicited version of the CREG response is
3687+ * +CREG: n, stat, [lac, cid]
3688+ * and the unsolicited version is
3689+ * +CREG: stat, [lac, cid]
3690+ * The <n> parameter is basically "is unsolicited creg on?"
3691+ * which it should always be.
3692+ *
3693+ * Now we should normally get the solicited version here,
3694+ * but the unsolicited version could have snuck in
3695+ * so we have to handle both.
3696+ *
3697+ * Also since the LAC and CID are only reported when registered,
3698+ * we can have 1, 2, 3, or 4 arguments here.
3699+ *
3700+ * finally, a +CGREG: answer may have a fifth value that corresponds
3701+ * to the network type, as in;
3702+ *
3703+ * +CGREG: n, stat [,lac, cid [,networkType]]
3704+ */
3705+
3706+ /* Count number of commas */
3707+ err = at_tok_charcounter(line, ',', &commas);
3708+
3709+ if (err < 0)
3710+ goto error;
3711+
3712+ switch (commas) {
3713+ case 0: /* +CREG: <stat> */
3714+ err = at_tok_nextint(&line, &response[0]);
3715+ if (err < 0)
3716+ goto error;
3717+
3718+ response[1] = -1;
3719+ response[2] = -1;
3720+ break;
3721+
3722+ case 1: /* +CREG: <n>, <stat> */
3723+ err = at_tok_nextint(&line, &skip);
3724+ if (err < 0)
3725+ goto error;
3726+
3727+ err = at_tok_nextint(&line, &response[0]);
3728+ if (err < 0)
3729+ goto error;
3730+
3731+ response[1] = -1;
3732+ response[2] = -1;
3733+ if (err < 0)
3734+ goto error;
3735+ break;
3736+ case 2: /* +CREG: <stat>, <lac>, <cid> */
3737+ err = at_tok_nextint(&line, &response[0]);
3738+ if (err < 0)
3739+ goto error;
3740+
3741+ err = at_tok_nexthexint(&line, &response[1]);
3742+ if (err < 0)
3743+ goto error;
3744+
3745+ err = at_tok_nexthexint(&line, &response[2]);
3746+ if (err < 0)
3747+ goto error;
3748+ break;
3749+ case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
3750+ case 4: /* +CREG: <n>, <stat>, <lac>, <cid>, <?> */
3751+ err = at_tok_nextint(&line, &skip);
3752+ if (err < 0)
3753+ goto error;
3754+
3755+ err = at_tok_nextint(&line, &response[0]);
3756+ if (err < 0)
3757+ goto error;
3758+
3759+ err = at_tok_nexthexint(&line, &response[1]);
3760+ if (err < 0)
3761+ goto error;
3762+
3763+ err = at_tok_nexthexint(&line, &response[2]);
3764+ if (err < 0)
3765+ goto error;
3766+ break;
3767+ default:
3768+ goto error;
3769+ }
3770+
3771+
3772+ asprintf(&responseStr[0], "%d", response[0]);
3773+
3774+ if (response[1] > 0)
3775+ asprintf(&responseStr[1], "%04x", response[1]);
3776+ if (response[2] > 0)
3777+ asprintf(&responseStr[2], "%08x", response[2]);
3778+
3779+ if (response[0] == CGREG_STAT_REG_HOME_NET ||
3780+ response[0] == CGREG_STAT_ROAMING)
3781+ responseStr[3] = (0);
3782+
3783+ RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr,
3784+ resp_size * sizeof(char *));
3785+
3786+finally:
3787+
3788+ for (i = 0; i < resp_size; i++)
3789+ free(responseStr[i]);
3790+
3791+ at_response_free(cgreg_resp);
3792+ return;
3793+
3794+error:
3795+ LOGE("%s() Must never return an error when radio is on", __func__);
3796+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3797+ goto finally;
3798+}
3799+
3800+
3801+/**
3802+ * RIL_REQUEST_DATA_REGISTRATION_STATE
3803+ *
3804+ * Request current GPRS registration state.
3805+ */
3806+static void requestGprsRegistrationState(RIL_Token t)
3807+{
3808+ int err = 0;
3809+ const char resp_size = 6;
3810+ int response[resp_size];
3811+ char *responseStr[resp_size];
3812+ ATResponse *atResponse = NULL;
3813+ char *line, *p;
3814+ int commas = 0;
3815+ int skip, tmp;
3816+ int count = 3;
3817+
3818+ memset(responseStr, 0, sizeof(responseStr));
3819+ memset(response, 0, sizeof(response));
3820+ response[1] = -1;
3821+ response[2] = -1;
3822+
3823+ err = at_send_command_singleline("AT+CGREG?", "+CGREG: ", &atResponse);
3824+ if (err != AT_NOERROR)
3825+ goto error;
3826+
3827+ line = atResponse->p_intermediates->line;
3828+ err = at_tok_start(&line);
3829+ if (err < 0)
3830+ goto error;
3831+ /*
3832+ * The solicited version of the +CGREG response is
3833+ * +CGREG: n, stat, [lac, cid [,<AcT>]]
3834+ * and the unsolicited version is
3835+ * +CGREG: stat, [lac, cid [,<AcT>]]
3836+ * The <n> parameter is basically "is unsolicited creg on?"
3837+ * which it should always be.
3838+ *
3839+ * Now we should normally get the solicited version here,
3840+ * but the unsolicited version could have snuck in
3841+ * so we have to handle both.
3842+ *
3843+ * Also since the LAC, CID and AcT are only reported when registered,
3844+ * we can have 1, 2, 3, 4 or 5 arguments here.
3845+ */
3846+ /* Count number of commas */
3847+ p = line;
3848+ err = at_tok_charcounter(line, ',', &commas);
3849+ if (err < 0) {
3850+ LOGE("%s() at_tok_charcounter failed", __func__);
3851+ goto error;
3852+ }
3853+
3854+ switch (commas) {
3855+ case 0: /* +CGREG: <stat> */
3856+ err = at_tok_nextint(&line, &response[0]);
3857+ if (err < 0) goto error;
3858+ break;
3859+
3860+ case 1: /* +CGREG: <n>, <stat> */
3861+ err = at_tok_nextint(&line, &skip);
3862+ if (err < 0) goto error;
3863+ err = at_tok_nextint(&line, &response[0]);
3864+ if (err < 0) goto error;
3865+ break;
3866+
3867+ case 2: /* +CGREG: <stat>, <lac>, <cid> */
3868+ err = at_tok_nextint(&line, &response[0]);
3869+ if (err < 0) goto error;
3870+ err = at_tok_nexthexint(&line, &response[1]);
3871+ if (err < 0) goto error;
3872+ err = at_tok_nexthexint(&line, &response[2]);
3873+ if (err < 0) goto error;
3874+ break;
3875+
3876+ case 3: /* +CGREG: <n>, <stat>, <lac>, <cid> */
3877+ /* +CGREG: <stat>, <lac>, <cid>, <AcT> */
3878+ err = at_tok_nextint(&line, &tmp);
3879+ if (err < 0) goto error;
3880+
3881+ /* We need to check if the second parameter is <lac> */
3882+ if (*(line) == '"') {
3883+ response[0] = tmp; /* <stat> */
3884+ err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
3885+ if (err < 0) goto error;
3886+ err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
3887+ if (err < 0) goto error;
3888+ err = at_tok_nextint(&line, &response[3]); /* <AcT> */
3889+ if (err < 0) goto error;
3890+ count = 4;
3891+ } else {
3892+ err = at_tok_nextint(&line, &response[0]); /* <stat> */
3893+ if (err < 0) goto error;
3894+ err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
3895+ if (err < 0) goto error;
3896+ err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
3897+ if (err < 0) goto error;
3898+ }
3899+ break;
3900+
3901+ case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <AcT> */
3902+ err = at_tok_nextint(&line, &skip); /* <n> */
3903+ if (err < 0) goto error;
3904+ err = at_tok_nextint(&line, &response[0]); /* <stat> */
3905+ if (err < 0) goto error;
3906+ err = at_tok_nexthexint(&line, &response[1]); /* <lac> */
3907+ if (err < 0) goto error;
3908+ err = at_tok_nexthexint(&line, &response[2]); /* <cid> */
3909+ if (err < 0) goto error;
3910+ err = at_tok_nextint(&line, &response[3]); /* <AcT> */
3911+ if (err < 0) goto error;
3912+ count = 4;
3913+ break;
3914+
3915+ default:
3916+ LOGE("%s() Invalid input", __func__);
3917+ goto error;
3918+ }
3919+
3920+ /* Converting to stringlist for Android */
3921+
3922+ asprintf(&responseStr[0], "%d", response[0]); /* state */
3923+
3924+ if (response[1] >= 0)
3925+ asprintf(&responseStr[1], "%04x", response[1]); /* LAC */
3926+ else
3927+ responseStr[1] = NULL;
3928+
3929+ if (response[2] >= 0)
3930+ asprintf(&responseStr[2], "%08x", response[2]); /* CID */
3931+ else
3932+ responseStr[2] = NULL;
3933+
3934+ if (response[0] == CGREG_STAT_REG_HOME_NET ||
3935+ response[0] == CGREG_STAT_ROAMING)
3936+ asprintf(&responseStr[3], "%d",response[3]);
3937+ else
3938+ responseStr[3] = NULL;
3939+
3940+ responseStr[5] = (char*) "1";
3941+
3942+ RIL_onRequestComplete(t, RIL_E_SUCCESS, responseStr, resp_size * sizeof(char *));
3943+
3944+finally:
3945+
3946+ if (responseStr[0])
3947+ free(responseStr[0]);
3948+ if (responseStr[1])
3949+ free(responseStr[1]);
3950+ if (responseStr[2])
3951+ free(responseStr[2]);
3952+ if (responseStr[3])
3953+ free(responseStr[3]);
3954+
3955+ at_response_free(atResponse);
3956+ return;
3957+
3958+error:
3959+ LOGE("%s Must never return an error when radio is on", __func__);
3960+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
3961+ goto finally;
3962+}
3963+
3964+
3965+/**
3966+ * RIL_REQUEST_OEM_HOOK_RAW
3967+ *
3968+ * This request reserved for OEM-specific uses. It passes raw byte arrays
3969+ * back and forth.
3970+*/
3971+static void requestOEMHookRaw(void *data, size_t datalen, RIL_Token t)
3972+{
3973+ RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
3974+ return;
3975+}
3976+
3977+
3978+/**
3979+ * RIL_REQUEST_OEM_HOOK_STRINGS
3980+ *
3981+ * This request reserved for OEM-specific uses. It passes strings
3982+ * back and forth.
3983+ */
3984+static void requestOEMHookStrings(void * data, size_t datalen, RIL_Token t)
3985+{
3986+ int i;
3987+ const char **cur;
3988+ ATResponse *atResponse = NULL;
3989+ ATLine *atline;
3990+ int linecount;
3991+ int err;
3992+
3993+ D("%s() got OEM_HOOK_STRINGS: %8p %lu", __func__, data, (long) datalen);
3994+
3995+ for (i = (datalen / sizeof(char *)), cur = (const char **) data;
3996+ i > 0; cur++, i--) {
3997+ D("%s(): String: %s", __func__, *cur);
3998+ }
3999+
4000+ /* Only take the first string in the array for now */
4001+ cur = (const char **) data;
4002+ err = at_send_command_raw(*cur, &atResponse);
4003+
4004+ if ((err != AT_NOERROR && at_get_error_type(err) == AT_ERROR)
4005+ || atResponse == NULL || atResponse->finalResponse == NULL)
4006+ goto error;
4007+
4008+ /* Count number of lines including prefix, intermediate and final response */
4009+ linecount = 0;
4010+ atline = atResponse->p_intermediates;
4011+ while (atline != NULL && atline->line != NULL) {
4012+ linecount++;
4013+ atline = atline->p_next;
4014+ }
4015+ linecount++; /* for finalResponse */
4016+
4017+ /* Create RIL response */
4018+ if (linecount > 0) {
4019+ cur = (const char **) alloca(linecount * sizeof (char *));
4020+ if (cur != NULL) {
4021+ linecount = 0;
4022+ atline = atResponse->p_intermediates;
4023+ while (atline != NULL && atline->line != NULL) {
4024+ cur[linecount++] = atline->line;
4025+ atline = atline->p_next;
4026+ }
4027+ cur[linecount++] = atResponse->finalResponse;
4028+ } else
4029+ goto error;
4030+ }
4031+
4032+ RIL_onRequestComplete(t, RIL_E_SUCCESS, cur, linecount * sizeof(char *));
4033+ at_response_free(atResponse);
4034+ return;
4035+
4036+error:
4037+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4038+ at_response_free(atResponse);
4039+}
4040+
4041+
4042+static void unsolicitedNitzTime(const char * s)
4043+{
4044+ int err;
4045+ char * response = NULL;
4046+ char * line = NULL;
4047+ char * p = NULL;
4048+ char * tz = NULL; /* Timezone */
4049+ static char sNITZtime[64] = {0};
4050+
4051+ line = strdup(s);
4052+
4053+ /* Higher layers expect a NITZ string in this format:
4054+ * 08/10/28,19:08:37-20,1 (yy/mm/dd,hh:mm:ss(+/-)tz,dst)
4055+ */
4056+
4057+ if (strStartsWith(s,"+CTZV:")){
4058+
4059+ /* Get Time and Timezone data and store in static variable.
4060+ * Wait until DST is received to send response to upper layers
4061+ */
4062+ at_tok_start(&line);
4063+
4064+ err = at_tok_nextstr(&line, &tz);
4065+ if (err < 0) goto error;
4066+
4067+ err = at_tok_nextstr(&line, &response);
4068+ if (err < 0) goto error;
4069+
4070+ strcpy(sNITZtime,response);
4071+ strcat(sNITZtime,tz);
4072+
4073+ free(line);
4074+ return;
4075+
4076+ } else if (strStartsWith(s,"+CTZDST:")){
4077+
4078+ /* We got DST, now assemble the response and send to upper layers */
4079+ at_tok_start(&line);
4080+
4081+ err = at_tok_nextstr(&line, &tz);
4082+ if (err < 0) goto error;
4083+
4084+ asprintf(&response, "%s,%s", sNITZtime, tz);
4085+ RIL_onUnsolicitedResponse(RIL_UNSOL_NITZ_TIME_RECEIVED, response, strlen(response));
4086+ free(response);
4087+
4088+ free(line);
4089+ return;
4090+
4091+ }
4092+
4093+error:
4094+ LOGE("Invalid NITZ line %s\n", s);
4095+}
4096+
4097+static void unsolicitedRSSI(const char * s)
4098+{
4099+ int err;
4100+ int rssi;
4101+ RIL_SignalStrength_v6 signalStrength;
4102+ char * line = NULL;
4103+
4104+ line = strdup(s);
4105+
4106+ err = at_tok_start(&line);
4107+ if (err < 0) goto error;
4108+
4109+ err = at_tok_nextint(&line, &rssi);
4110+ if (err < 0) goto error;
4111+
4112+ signalStrength.GW_SignalStrength.signalStrength = rssi;
4113+ signalStrength.GW_SignalStrength.bitErrorRate = 99;
4114+ signalStrength.CDMA_SignalStrength.dbm = 0;
4115+ signalStrength.CDMA_SignalStrength.ecio = 0;
4116+ signalStrength.EVDO_SignalStrength.dbm = 0;
4117+ signalStrength.EVDO_SignalStrength.ecio = 0;
4118+ signalStrength.EVDO_SignalStrength.signalNoiseRatio = 0;
4119+ signalStrength.LTE_SignalStrength.signalStrength = 0;
4120+ signalStrength.LTE_SignalStrength.rsrp = 0;
4121+ signalStrength.LTE_SignalStrength.rsrq = 0;
4122+ signalStrength.LTE_SignalStrength.rssnr = 0;
4123+ signalStrength.LTE_SignalStrength.cqi = 0;
4124+
4125+ LOGI("Signal Strength %d", rssi);
4126+
4127+ RIL_onUnsolicitedResponse(RIL_UNSOL_SIGNAL_STRENGTH, &signalStrength, sizeof(signalStrength));
4128+ free(line);
4129+ return;
4130+
4131+error:
4132+ /* The notification was for a battery event - do not send a msg to upper layers */
4133+ LOGI("Error getting Signal Strength");
4134+ free(line);
4135+ return;
4136+}
4137+
4138+static void unsolicitedMode(const char * s)
4139+{
4140+ int err;
4141+ int mode1;
4142+ int mode2;
4143+ char * line = NULL;
4144+
4145+ /*
4146+ ^MODE:3,2 indicates GPRS
4147+ ^MODE:3,3 indicates EDGE
4148+ ^MODE:5,4 indicates 3G
4149+ ^MODE:5,5 indicates HSDPA
4150+ */
4151+
4152+ line = strdup(s);
4153+
4154+ err = at_tok_start(&line);
4155+ if (err < 0) goto error;
4156+
4157+ err = at_tok_nextint(&line, &mode1);
4158+ if (err < 0) goto error;
4159+
4160+ err = at_tok_nextint(&line, &mode2);
4161+ if (err < 0) goto error;
4162+
4163+ free(line);
4164+ return;
4165+
4166+error:
4167+ LOGI("Error getting mode");
4168+ free(line);
4169+ return;
4170+}
4171+
4172+
4173+/**
4174+ * RIL_REQUEST_SIGNAL_STRENGTH
4175+ *
4176+ * Requests current signal strength and bit error rate.
4177+ *
4178+ * Must succeed if radio is on.
4179+ */
4180+static void requestSignalStrength(RIL_Token t)
4181+{
4182+ RIL_SignalStrength_v6 signalStrength;
4183+ ATResponse *atResponse = NULL;
4184+ int err;
4185+ char *line;
4186+ int ber;
4187+ int rssi;
4188+
4189+ memset(&signalStrength, 0, sizeof(RIL_SignalStrength_v6));
4190+
4191+ signalStrength.LTE_SignalStrength.signalStrength = 0x7FFFFFFF;
4192+ signalStrength.LTE_SignalStrength.rsrp = 0x7FFFFFFF;
4193+ signalStrength.LTE_SignalStrength.rsrq = 0x7FFFFFFF;
4194+ signalStrength.LTE_SignalStrength.rssnr = 0x7FFFFFFF;
4195+ signalStrength.LTE_SignalStrength.cqi = 0x7FFFFFFF;
4196+
4197+ err = at_send_command_singleline("AT+CSQ", "+CSQ:", &atResponse);
4198+ if (err != AT_NOERROR)
4199+ goto error;
4200+
4201+ line = atResponse->p_intermediates->line;
4202+
4203+ err = at_tok_start(&line);
4204+ if (err < 0) goto error;
4205+
4206+ err = at_tok_nextint(&line,&rssi);
4207+ if (err < 0) goto error;
4208+
4209+ signalStrength.GW_SignalStrength.signalStrength = rssi;
4210+
4211+ err = at_tok_nextint(&line, &ber);
4212+ if (err < 0)
4213+ goto error;
4214+
4215+ signalStrength.GW_SignalStrength.bitErrorRate = ber;
4216+
4217+ signalStrength.CDMA_SignalStrength.dbm = 0;
4218+ signalStrength.CDMA_SignalStrength.ecio = 0;
4219+ signalStrength.EVDO_SignalStrength.dbm = 0;
4220+ signalStrength.EVDO_SignalStrength.ecio = 0;
4221+ signalStrength.EVDO_SignalStrength.signalNoiseRatio = 0;
4222+ signalStrength.LTE_SignalStrength.signalStrength = 0;
4223+ signalStrength.LTE_SignalStrength.rsrp = 0;
4224+ signalStrength.LTE_SignalStrength.rsrq = 0;
4225+ signalStrength.LTE_SignalStrength.rssnr = 0;
4226+ signalStrength.LTE_SignalStrength.cqi = 0;
4227+
4228+ LOGI("SignalStrength %d BER: %d", rssi, ber);
4229+
4230+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &signalStrength,
4231+ sizeof(RIL_SignalStrength_v6));
4232+
4233+ at_response_free(atResponse);
4234+ atResponse = NULL;
4235+ return;
4236+
4237+error:
4238+ LOGE("%s() Must never return an error when radio is on", __func__);
4239+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4240+ at_response_free(atResponse);
4241+ return;
4242+}
4243+
4244+
4245+
4246+/**
4247+ * RIL_REQUEST_OPERATOR
4248+ *
4249+ * Request current operator ONS or EONS.
4250+ */
4251+static void requestOperator(RIL_Token t)
4252+{
4253+ int err;
4254+ int i;
4255+ int skip;
4256+ ATLine *cursor;
4257+ static const int num_resp_lines = 3;
4258+ char *response[num_resp_lines];
4259+ ATResponse *atResponse = NULL;
4260+
4261+ memset(response, 0, sizeof(response));
4262+
4263+ err = at_send_command_multiline
4264+ ("AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", "+COPS:",
4265+ &atResponse);
4266+
4267+ if (err != AT_NOERROR)
4268+ goto error;
4269+
4270+ /* We expect 3 lines here:
4271+ * +COPS: 0,0,"T - Mobile"
4272+ * +COPS: 0,1,"TMO"
4273+ * +COPS: 0,2,"310170"
4274+ */
4275+ for (i = 0, cursor = atResponse->p_intermediates;
4276+ cursor != NULL && i < num_resp_lines;
4277+ cursor = cursor->p_next, i++) {
4278+ char *line = cursor->line;
4279+
4280+ err = at_tok_start(&line);
4281+
4282+ if (err < 0)
4283+ goto error;
4284+
4285+ err = at_tok_nextint(&line, &skip);
4286+
4287+ if (err < 0)
4288+ goto error;
4289+
4290+ /* If we're unregistered, we may just get
4291+ a "+COPS: 0" response. */
4292+ if (!at_tok_hasmore(&line)) {
4293+ response[i] = NULL;
4294+ continue;
4295+ }
4296+
4297+ err = at_tok_nextint(&line, &skip);
4298+
4299+ if (err < 0)
4300+ goto error;
4301+
4302+ /* A "+COPS: 0, n" response is also possible. */
4303+ if (!at_tok_hasmore(&line)) {
4304+ response[i] = NULL;
4305+ continue;
4306+ }
4307+
4308+ err = at_tok_nextstr(&line, &(response[i]));
4309+
4310+ if (err < 0)
4311+ goto error;
4312+ }
4313+
4314+ if (i != num_resp_lines)
4315+ goto error;
4316+
4317+ /*
4318+ * Check if modem returned an empty string, and fill it with MNC/MMC
4319+ * if that's the case.
4320+ */
4321+ if (response[2] && response[0] && strlen(response[0]) == 0) {
4322+ response[0] = (char*) alloca(strlen(response[2]) + 1);
4323+ strcpy(response[0], response[2]);
4324+ }
4325+
4326+ if (response[2] && response[1] && strlen(response[1]) == 0) {
4327+ response[1] = (char*) alloca(strlen(response[2]) + 1);
4328+ strcpy(response[1], response[2]);
4329+ }
4330+
4331+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
4332+
4333+finally:
4334+ at_response_free(atResponse);
4335+ return;
4336+
4337+error:
4338+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4339+ goto finally;
4340+}
4341+
4342+
4343+/**
4344+ * RIL_REQUEST_RADIO_POWER
4345+ *
4346+ * Toggle radio on and off (for "airplane" mode).
4347+*/
4348+static void requestRadioPower(void *data, size_t datalen, RIL_Token t)
4349+{
4350+ int onOff;
4351+ int err;
4352+ int restricted;
4353+
4354+ if (datalen < sizeof(int *)) {
4355+ LOGE("%s() bad data length!", __func__);
4356+ goto error;
4357+ }
4358+
4359+ onOff = ((int *)data)[0];
4360+
4361+ if (onOff == 0 && getRadioState() != RADIO_STATE_OFF) {
4362+ char value[PROPERTY_VALUE_MAX];
4363+
4364+ /* Switch RF OFF */
4365+ err = at_send_command("AT^RFSWITCH=0");
4366+ if (err != AT_NOERROR)
4367+ goto error;
4368+
4369+ if (property_get("sys.shutdown.requested", value, NULL)) {
4370+ setRadioState(RADIO_STATE_UNAVAILABLE);
4371+ } else
4372+ setRadioState(RADIO_STATE_OFF);
4373+
4374+ } else if (onOff > 0 && getRadioState() == RADIO_STATE_OFF) {
4375+
4376+ /* Switch RF ON */
4377+ err = at_send_command("AT^RFSWITCH=1");
4378+ if (err != AT_NOERROR)
4379+ goto error;
4380+
4381+ if (err != AT_NOERROR) {
4382+ // Some stacks return an error when there is no SIM,
4383+ // but they really turn the RF portion on
4384+ // So, if we get an error, let's check to see if it
4385+ // turned on anyway
4386+
4387+ if (isRadioOn() != 1) {
4388+ goto error;
4389+ }
4390+ }
4391+ setRadioState(RADIO_STATE_SIM_NOT_READY);
4392+ }
4393+
4394+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4395+
4396+ restricted = RIL_RESTRICTED_STATE_NONE;
4397+ RIL_onUnsolicitedResponse(RIL_UNSOL_RESTRICTED_STATE_CHANGED,
4398+ &restricted, sizeof(int *));
4399+
4400+ return;
4401+
4402+error:
4403+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4404+}
4405+
4406+
4407+/**
4408+ * RIL_REQUEST_GET_IMSI
4409+*/
4410+static void requestGetIMSI(RIL_Token t)
4411+{
4412+ ATResponse *atResponse = NULL;
4413+ int err;
4414+
4415+ err = at_send_command_numeric("AT+CIMI", &atResponse);
4416+
4417+ if (err != AT_NOERROR)
4418+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4419+ else {
4420+ RIL_onRequestComplete(t, RIL_E_SUCCESS,
4421+ atResponse->p_intermediates->line,
4422+ sizeof(char *));
4423+ }
4424+ at_response_free(atResponse);
4425+}
4426+
4427+
4428+
4429+/**
4430+ * RIL_REQUEST_GET_IMEISV
4431+ *
4432+ * Get the device IMEISV, which should be two decimal digits.
4433+*/
4434+static void requestGetIMEISV(RIL_Token t)
4435+{
4436+ RIL_onRequestComplete(t, RIL_E_SUCCESS, (void*)"01", sizeof(char *));
4437+}
4438+
4439+
4440+
4441+/* RIL_REQUEST_DEVICE_IDENTITY
4442+ *
4443+ * Request the device ESN / MEID / IMEI / IMEISV.
4444+ *
4445+ */
4446+static void requestDeviceIdentity(RIL_Token t)
4447+{
4448+ ATResponse *atResponse = NULL;
4449+ char* response[4];
4450+ int err;
4451+
4452+ /* IMEI */
4453+ err = at_send_command_numeric("AT+CGSN", &atResponse);
4454+
4455+ if (err != AT_NOERROR)
4456+ goto error;
4457+
4458+ response[0] = atResponse->p_intermediates->line;
4459+
4460+ /* IMEISVN */
4461+ response[1] = (char*) "01";
4462+
4463+ /* CDMA not supported */
4464+ response[2] = (char*) "";
4465+ response[3] = (char*) "";
4466+
4467+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
4468+
4469+ at_response_free(atResponse);
4470+ return;
4471+
4472+error:
4473+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4474+ at_response_free(atResponse);
4475+}
4476+
4477+
4478+
4479+/**
4480+ * RIL_REQUEST_BASEBAND_VERSION
4481+ *
4482+ * Return string value indicating baseband version, eg
4483+ * response from AT+CGMR.
4484+*/
4485+static void requestBasebandVersion(RIL_Token t)
4486+{
4487+ int err;
4488+ ATResponse *atResponse = NULL;
4489+ char *line;
4490+
4491+ err = at_send_command_singleline("AT+CGMR", "\0", &atResponse);
4492+
4493+ if (err != AT_NOERROR) {
4494+ LOGE("%s() Error reading Base Band Version", __func__);
4495+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4496+ return;
4497+ }
4498+
4499+ line = atResponse->p_intermediates->line;
4500+
4501+ RIL_onRequestComplete(t, RIL_E_SUCCESS, line, sizeof(char *));
4502+
4503+ at_response_free(atResponse);
4504+}
4505+
4506+
4507+/**
4508+ * RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE
4509+ *
4510+ * Requests to send a terminal response to SIM for a received
4511+ * proactive command.
4512+ */
4513+static void requestStkSendTerminalResponse(void * data, size_t datalen, RIL_Token t)
4514+{
4515+ (void)datalen;
4516+ const char *stkResponse = (const char *) data;
4517+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4518+}
4519+
4520+
4521+/**
4522+ * RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND
4523+ *
4524+ * Requests to send a SAT/USAT envelope command to SIM.
4525+ * The SAT/USAT envelope command refers to 3GPP TS 11.14 and 3GPP TS 31.111.
4526+ */
4527+static void requestStkSendEnvelopeCommand(void * data, size_t datalen, RIL_Token t)
4528+{
4529+ const char *ec = (const char *) data;
4530+ (void)datalen;
4531+ RIL_onRequestComplete(t, RIL_E_SUCCESS, (void*)"ok", sizeof(char *));
4532+}
4533+
4534+
4535+/**
4536+ * RIL_REQUEST_STK_GET_PROFILE
4537+ *
4538+ * Requests the profile of SIM tool kit.
4539+ * The profile indicates the SAT/USAT features supported by ME.
4540+ * The SAT/USAT features refer to 3GPP TS 11.14 and 3GPP TS 31.111.
4541+ */
4542+static void requestStkGetProfile(RIL_Token t)
4543+{
4544+ RIL_onRequestComplete(t, RIL_E_SUCCESS, (void*)"default", sizeof(char *));
4545+}
4546+
4547+
4548+/**
4549+ * RIL_REQUEST_STK_SET_PROFILE
4550+ *
4551+ * Download the STK terminal profile as part of SIM initialization
4552+ * procedure.
4553+ */
4554+static void requestStkSetProfile(void * data, size_t datalen, RIL_Token t)
4555+{
4556+ int err = 0;
4557+ int length = 0;
4558+ char *profile = NULL;
4559+
4560+ profile = (char *)data;
4561+ length = strlen(profile);
4562+
4563+ // Accept everyrhing
4564+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4565+}
4566+
4567+
4568+/**
4569+ * RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING
4570+ *
4571+ * Turn on STK unsol commands.
4572+ */
4573+void requestReportStkServiceIsRunning(RIL_Token t)
4574+{
4575+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4576+}
4577+
4578+
4579+static void requestDial(void *data, size_t datalen, RIL_Token t)
4580+{
4581+ RIL_Dial *p_dial;
4582+ const char *clir;
4583+ int ret;
4584+
4585+ p_dial = (RIL_Dial *)data;
4586+
4587+ switch (p_dial->clir) {
4588+ case 1: clir = "I"; break; /*invocation*/
4589+ case 2: clir = "i"; break; /*suppression*/
4590+ default:
4591+ case 0: clir = ""; break; /*subscription default*/
4592+ }
4593+
4594+ /* Originate call */
4595+ ret = at_send_command("ATD%s%s;", p_dial->address, clir);
4596+
4597+ /* success or failure is ignored by the upper layer here.
4598+ it will call GET_CURRENT_CALLS and determine success that way */
4599+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4600+}
4601+
4602+
4603+static void requestHangup(void *data, size_t datalen, RIL_Token t)
4604+{
4605+ int *p_line;
4606+
4607+ int ret;
4608+
4609+ p_line = (int *)data;
4610+
4611+ // 3GPP 22.030 6.5.5
4612+ // "Releases a specific active call X"
4613+ ret = at_send_command("AT+CHLD=1%d", p_line[0]);
4614+
4615+ /* success or failure is ignored by the upper layer here.
4616+ it will call GET_CURRENT_CALLS and determine success that way */
4617+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4618+}
4619+
4620+static void requestHangupWaitingOrBackground(RIL_Token t)
4621+{
4622+ // 3GPP 22.030 6.5.5
4623+ // "Releases all held calls or sets User Determined User Busy
4624+ // (UDUB) for a waiting call."
4625+ at_send_command("AT+CHLD=0");
4626+
4627+ /* success or failure is ignored by the upper layer here.
4628+ it will call GET_CURRENT_CALLS and determine success that way */
4629+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4630+}
4631+
4632+
4633+static void requestHangupForegroundResumeBackground(RIL_Token t)
4634+{
4635+ // 3GPP 22.030 6.5.5
4636+ // "Releases all active calls (if any exist) and accepts
4637+ // the other (held or waiting) call."
4638+ at_send_command("AT+CHLD=1");
4639+
4640+ /* success or failure is ignored by the upper layer here.
4641+ it will call GET_CURRENT_CALLS and determine success that way */
4642+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4643+}
4644+
4645+
4646+static void requestSwitchWaitingOrHoldingAndActive(RIL_Token t)
4647+{
4648+ // 3GPP 22.030 6.5.5
4649+ // "Places all active calls (if any exist) on hold and accepts
4650+ // the other (held or waiting) call."
4651+ at_send_command("AT+CHLD=2");
4652+
4653+ /* success or failure is ignored by the upper layer here.
4654+ it will call GET_CURRENT_CALLS and determine success that way */
4655+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4656+}
4657+
4658+
4659+static void requestAnswer(RIL_Token t)
4660+{
4661+ at_send_command("ATA");
4662+
4663+ /* success or failure is ignored by the upper layer here.
4664+ it will call GET_CURRENT_CALLS and determine success that way */
4665+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4666+}
4667+
4668+
4669+static void requestConference(RIL_Token t)
4670+{
4671+ // 3GPP 22.030 6.5.5
4672+ // "Adds a held call to the conversation"
4673+ at_send_command("AT+CHLD=3");
4674+
4675+ /* success or failure is ignored by the upper layer here.
4676+ it will call GET_CURRENT_CALLS and determine success that way */
4677+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4678+}
4679+
4680+
4681+static void requestUDUB(RIL_Token t)
4682+{
4683+ /* user determined user busy */
4684+ /* sometimes used: ATH */
4685+ at_send_command("ATH");
4686+
4687+ /* success or failure is ignored by the upper layer here.
4688+ it will call GET_CURRENT_CALLS and determine success that way */
4689+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4690+
4691+}
4692+
4693+
4694+static void requestSeparateConnection(void * data, size_t datalen, RIL_Token t)
4695+{
4696+ int party = ((int*)data)[0];
4697+
4698+ // Make sure that party is in a valid range.
4699+ // (Note: The Telephony middle layer imposes a range of 1 to 7.
4700+ // It's sufficient for us to just make sure it's single digit.)
4701+ if (party > 0 && party < 10) {
4702+ at_send_command("AT+CHLD=2%d", party);
4703+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4704+ } else {
4705+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4706+ }
4707+}
4708+
4709+
4710+static void requestSetMute(void *data, size_t datalen, RIL_Token t)
4711+{
4712+ int err;
4713+ assert (datalen >= sizeof(int *));
4714+
4715+ /* mute */
4716+ err = at_send_command("AT+CMUT=%d", ((int*)data)[0]);
4717+ if (err != AT_NOERROR)
4718+ goto error;
4719+
4720+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4721+ return;
4722+
4723+error:
4724+ LOGE("ERROR: requestSetMute failed");
4725+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4726+
4727+}
4728+
4729+
4730+static void requestGetMute(RIL_Token t)
4731+{
4732+ int err;
4733+ ATResponse *atResponse = NULL;
4734+ int response[1];
4735+ char *line;
4736+
4737+ err = at_send_command_singleline("AT+CMUT?", "+CMUT:", &atResponse);
4738+
4739+ if (err != AT_NOERROR)
4740+ goto error;
4741+
4742+ line = atResponse->p_intermediates->line;
4743+
4744+ err = at_tok_start(&line);
4745+ if (err < 0) goto error;
4746+
4747+ err = at_tok_nextint(&line, &response[0]);
4748+ if (err < 0) goto error;
4749+
4750+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(char*));
4751+ at_response_free(atResponse);
4752+
4753+ return;
4754+
4755+error:
4756+ LOGE("ERROR: requestGetMute failed");
4757+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4758+ at_response_free(atResponse);
4759+}
4760+
4761+
4762+static void requestDTMF(void * data, size_t datalen, RIL_Token t)
4763+{
4764+ int err = 0;
4765+ char c = ((char *)data)[0];
4766+
4767+ err = at_send_command("AT+VTS=%c", (int)c);
4768+ if (err != AT_NOERROR) {
4769+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4770+ } else {
4771+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4772+ }
4773+
4774+}
4775+
4776+
4777+static void requestDtmfStop(RIL_Token t)
4778+{
4779+ int err;
4780+
4781+ /* Send a command to cancel the DTMF tone*/
4782+ err = at_send_command("AT");
4783+ if (err != AT_NOERROR)
4784+ goto error;
4785+
4786+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4787+ return;
4788+
4789+error:
4790+ LOGE("ERROR: requestDtmfStop failed");
4791+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4792+
4793+}
4794+
4795+
4796+static void requestDtmfStart(void *data, size_t datalen, RIL_Token t)
4797+{
4798+ int err;
4799+ char c;
4800+
4801+ assert (datalen >= sizeof(char *));
4802+
4803+ c = ((char *)data)[0];
4804+
4805+ /* Start DTMF generation fro 250ms */
4806+ err = at_send_command("AT^DTMF=0,%c", (int)c);
4807+ if (err != AT_NOERROR)
4808+ goto error;
4809+
4810+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4811+ return;
4812+
4813+error:
4814+ LOGE("ERROR: requestDtmfStart failed");
4815+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4816+
4817+}
4818+
4819+static void unsolicitedUSSD(const char *s)
4820+{
4821+ char *line, *linestart;
4822+ int typeCode, count, err, len;
4823+ char *message;
4824+ char *outputmessage;
4825+ char *responseStr[2] = {0,0};
4826+
4827+ D("unsolicitedUSSD %s\n",s);
4828+
4829+ linestart=line=strdup(s);
4830+ err = at_tok_start(&line);
4831+ if (err < 0) goto error;
4832+
4833+ err = at_tok_nextint(&line, &typeCode);
4834+ if (err < 0) goto error;
4835+
4836+ if (at_tok_hasmore(&line)) {
4837+ err = at_tok_nextstr(&line, &message);
4838+ if(err < 0) goto error;
4839+
4840+ outputmessage = (char*) malloc(strlen(message)*2+1);
4841+ gsm_hex_to_bytes((cbytes_t)message,strlen(message),(bytes_t)outputmessage);
4842+
4843+ responseStr[1] = (char*) malloc(strlen(outputmessage)*2+1);
4844+
4845+ len = utf8_from_gsm8((cbytes_t)outputmessage,strlen(outputmessage),(bytes_t)responseStr[1]);
4846+
4847+ responseStr[1][strlen(message)/2]='\0';
4848+ free(outputmessage);
4849+
4850+ count = 2;
4851+ } else {
4852+ responseStr[1]=NULL;
4853+ count = 1;
4854+ }
4855+ free(linestart);
4856+ asprintf(&responseStr[0], "%d", typeCode);
4857+
4858+ RIL_onUnsolicitedResponse (RIL_UNSOL_ON_USSD, responseStr, count*sizeof(char*));
4859+ if (responseStr[0])
4860+ free(responseStr[0]);
4861+ if (responseStr[1])
4862+ free(responseStr[1]);
4863+
4864+ return;
4865+
4866+error:
4867+ LOGE("unexpectedUSSD error\n");
4868+ free(linestart);
4869+}
4870+
4871+
4872+static void requestCancelUSSD(RIL_Token t)
4873+{
4874+ int err = 0;
4875+ ATResponse *atResponse = NULL;
4876+
4877+ err = at_send_command_numeric("AT+CUSD=2", &atResponse);
4878+
4879+ if (err != AT_NOERROR) {
4880+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4881+ } else {
4882+ RIL_onRequestComplete(t, RIL_E_SUCCESS,
4883+ atResponse->p_intermediates->line, sizeof(char *));
4884+ }
4885+
4886+ at_response_free(atResponse);
4887+ return;
4888+}
4889+
4890+
4891+static void requestQueryCallWaiting(void *data, size_t datalen, RIL_Token t)
4892+{
4893+ ATResponse *atResponse = NULL;
4894+ int err;
4895+ char *line;
4896+ int aclass;
4897+ int response[2];
4898+
4899+ aclass = ((int *)data)[0];
4900+
4901+ err = at_send_command_singleline("AT+CCWA=1,2,%d", "+CCWA:", &atResponse, aclass);
4902+ if (err != AT_NOERROR)
4903+ goto error;
4904+
4905+ line = atResponse->p_intermediates->line;
4906+
4907+ err = at_tok_start(&line);
4908+ if (err < 0) goto error;
4909+
4910+ err = at_tok_nextint(&line, &(response[0]));
4911+ if (err < 0) goto error;
4912+
4913+ if (at_tok_hasmore(&line)) {
4914+ err = at_tok_nextint(&line, &(response[1]));
4915+ if (err < 0) goto error;
4916+ }
4917+
4918+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
4919+ at_response_free(atResponse);
4920+ return;
4921+
4922+error:
4923+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4924+ at_response_free(atResponse);
4925+}
4926+
4927+static void requestSetCallWaiting(void *data, size_t datalen, RIL_Token t)
4928+{
4929+ ATResponse *atResponse = NULL;
4930+ int err;
4931+ int enabled, aclass;
4932+
4933+ if((datalen<2)||(data==NULL)) goto error;
4934+
4935+ enabled = ((int *)data)[0];
4936+ aclass = ((int *)data)[1];
4937+
4938+ err = at_send_command("AT+CCWA=0,%d,%d",enabled,aclass);
4939+ if (err != AT_NOERROR)
4940+ goto error;
4941+
4942+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
4943+ at_response_free(atResponse);
4944+ return;
4945+
4946+error:
4947+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
4948+ at_response_free(atResponse);
4949+}
4950+
4951+
4952+static void requestQueryCallForwardStatus(RIL_Token t)
4953+{
4954+ int err = 0;
4955+ int i = 0;
4956+ int n = 0;
4957+ int tmp = 0;
4958+ ATResponse *atResponse = NULL;
4959+ ATLine *p_cur;
4960+ RIL_CallForwardInfo **responses = NULL;
4961+
4962+ err = at_send_command_multiline("AT+CCFC=0,2", "+CCFC:", &atResponse);
4963+
4964+ if (err != AT_NOERROR)
4965+ goto error;
4966+
4967+ for (p_cur = atResponse->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)
4968+ n++;
4969+
4970+ responses = (RIL_CallForwardInfo **) alloca(n * sizeof(RIL_CallForwardInfo *));
4971+
4972+ for (i = 0; i < n; i++) {
4973+ responses[i] = (RIL_CallForwardInfo*)alloca(sizeof(RIL_CallForwardInfo));
4974+ responses[i]->status = 0;
4975+ responses[i]->reason = 0;
4976+ responses[i]->serviceClass = 0;
4977+ responses[i]->toa = 0;
4978+ responses[i]->number = (char*)"";
4979+ responses[i]->timeSeconds = 0;
4980+ }
4981+
4982+ for (i = 0,p_cur = atResponse->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next, i++) {
4983+ char *line = p_cur->line;
4984+
4985+ err = at_tok_start(&line);
4986+ if (err < 0) goto error;
4987+
4988+ err = at_tok_nextint(&line, &(responses[i]->status));
4989+ if (err < 0) goto error;
4990+
4991+ err = at_tok_nextint(&line, &(responses[i]->serviceClass));
4992+ if (err < 0) goto error;
4993+
4994+ if(!at_tok_hasmore(&line)) continue;
4995+
4996+ err = at_tok_nextstr(&line, &(responses[i]->number));
4997+ if (err < 0) goto error;
4998+
4999+ if(!at_tok_hasmore(&line)) continue;
5000+
5001+ err = at_tok_nextint(&line, &(responses[i]->toa));
5002+ if (err < 0) goto error;
5003+
5004+ if(!at_tok_hasmore(&line)) continue;
5005+ at_tok_nextint(&line,&tmp);
5006+
5007+ if(!at_tok_hasmore(&line)) continue;
5008+ at_tok_nextint(&line,&tmp);
5009+
5010+ if(!at_tok_hasmore(&line)) continue;
5011+ err = at_tok_nextint(&line, &(responses[i]->timeSeconds));
5012+ if (err < 0) goto error;
5013+
5014+ }
5015+
5016+ RIL_onRequestComplete(t, RIL_E_SUCCESS, responses, sizeof(RIL_CallForwardInfo **));
5017+ at_response_free(atResponse);
5018+
5019+ return;
5020+
5021+error:
5022+ at_response_free(atResponse);
5023+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5024+}
5025+
5026+
5027+static void requestSetCallForward(void *data, RIL_Token t)
5028+{
5029+ int err = 0;
5030+ RIL_CallForwardInfo *info = NULL;
5031+
5032+ info = ((RIL_CallForwardInfo *) data);
5033+
5034+ if(data == NULL)
5035+ goto error;
5036+
5037+ err = at_send_command("AT+CCFC = %d, %d, \"%s\"",
5038+ info->reason, info->status,
5039+ info->number);
5040+ if (err != AT_NOERROR)
5041+ goto error;
5042+
5043+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5044+ return;
5045+
5046+error:
5047+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5048+}
5049+
5050+
5051+static void requestGetCLIR(void *data, size_t datalen, RIL_Token t)
5052+{
5053+ /* Even though data and datalen must be NULL and 0 respectively this
5054+ * condition is not verified
5055+ */
5056+ ATResponse *atResponse = NULL;
5057+ int response[2];
5058+ char *line = NULL;
5059+ int err = 0;
5060+
5061+ err = at_send_command_singleline("AT+CLIR?", "+CLIR:", &atResponse);
5062+ if (err != AT_NOERROR)
5063+ goto error;
5064+
5065+
5066+ line = atResponse->p_intermediates->line;
5067+ err = at_tok_start(&line);
5068+ if (err < 0) goto error;
5069+
5070+ err = at_tok_nextint(&line, &(response[0]));
5071+ if (err < 0) goto error;
5072+
5073+ err = at_tok_nextint(&line, &(response[1]));
5074+ if (err < 0) goto error;
5075+
5076+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
5077+ at_response_free(atResponse);
5078+ return;
5079+
5080+error:
5081+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5082+ at_response_free(atResponse);
5083+}
5084+
5085+
5086+static void requestSetCLIR(void *data, size_t datalen, RIL_Token t)
5087+{
5088+ int err = 0;
5089+ err = at_send_command("AT+CLIR=%d", ((int *)data)[0]);
5090+ if (err < 0)
5091+ RIL_onRequestComplete(t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
5092+ else
5093+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5094+}
5095+
5096+
5097+static void requestSendUSSD(void *data, size_t datalen, RIL_Token t)
5098+{
5099+ int err = 0;
5100+ int len;
5101+ cbytes_t ussdRequest;
5102+ bytes_t temp;
5103+ char *newUSSDRequest;
5104+ ussdRequest = (cbytes_t)(data);
5105+
5106+ temp = (bytes_t) malloc(strlen((char *)ussdRequest)*sizeof(char)+1);
5107+ len = utf8_to_gsm8(ussdRequest,strlen((char *)ussdRequest),temp);
5108+ newUSSDRequest = (char*) malloc(2*len*sizeof(char)+1);
5109+ gsm_hex_from_bytes(newUSSDRequest,temp, len);
5110+ newUSSDRequest[2*len]='\0';
5111+ free(temp);
5112+
5113+ err = at_send_command("AT+CUSD=1,\"%s\",15", newUSSDRequest);
5114+ free(newUSSDRequest);
5115+ if (err != AT_NOERROR)
5116+ goto error;
5117+
5118+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5119+ return;
5120+
5121+error:
5122+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5123+}
5124+
5125+
5126+static void requestChangeBarringPassword(void *data, size_t datalen, RIL_Token t)
5127+{
5128+ int err = 0;
5129+ char *string = NULL;
5130+ char *old_password = NULL;
5131+ char *new_password = NULL;
5132+
5133+ assert (datalen >= (3 * sizeof(char **)));
5134+
5135+ string = ((char **)data)[0];
5136+ old_password = ((char **)data)[1];
5137+ new_password = ((char **)data)[2];
5138+
5139+ err = at_send_command("AT+CPWD=\"%s\",\"%s\",\"%s\"", string, old_password, new_password);
5140+ if (err != AT_NOERROR)
5141+ goto error;
5142+
5143+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5144+ return;
5145+
5146+error:
5147+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5148+}
5149+
5150+
5151+static void requestQueryCLIP(RIL_Token t)
5152+{
5153+ ATResponse *atResponse = NULL;
5154+ int err;
5155+ char *line;
5156+ int response;
5157+
5158+ err = at_send_command_singleline("AT+CLIP?","+CLIP:",&atResponse);
5159+ if (err != AT_NOERROR)
5160+ goto error;
5161+
5162+ line = atResponse->p_intermediates->line;
5163+ err = at_tok_start(&line);
5164+ if (err < 0) goto error;
5165+
5166+ /* The first number is discarded */
5167+ err = at_tok_nextint(&line, &response);
5168+ if (err < 0) goto error;
5169+
5170+ err = at_tok_nextint(&line, &response);
5171+ if (err < 0) goto error;
5172+
5173+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
5174+ at_response_free(atResponse);
5175+ return;
5176+
5177+error:
5178+ at_response_free(atResponse);
5179+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5180+}
5181+
5182+static void requestResetRadio(RIL_Token t)
5183+{
5184+ int err = 0;
5185+
5186+ /* Reset MS */
5187+ err = at_send_command("AT+CFUN=6");
5188+ if (err != AT_NOERROR)
5189+ goto error;
5190+
5191+ /* Go online */
5192+ err = at_send_command("AT^RFSWITCH=1");
5193+ err = at_send_command("AT+CFUN=1");
5194+ if (err != AT_NOERROR)
5195+ goto error;
5196+
5197+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5198+ return;
5199+
5200+error:
5201+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5202+ return;
5203+}
5204+
5205+static void requestSetSuppSVCNotification(void *data, size_t datalen, RIL_Token t)
5206+{
5207+ int err = 0;
5208+ int enabled = 0;
5209+ enabled = ((int *)data)[0];
5210+
5211+ err = at_send_command("AT+CSSN=%d,%d", enabled, enabled);
5212+ if (err != AT_NOERROR)
5213+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5214+ else
5215+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5216+}
5217+
5218+
5219+static void requestExplicitCallTransfer(RIL_Token t)
5220+{
5221+ int err = 0;
5222+ err = at_send_command("AT+CHLD=4");
5223+ if (err != AT_NOERROR)
5224+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5225+ else
5226+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5227+}
5228+
5229+
5230+static void requestSetLocationUpdates(void *data, size_t datalen, RIL_Token t)
5231+{
5232+ int err = 0;
5233+ int updates = 0;
5234+ ATResponse *atResponse = NULL;
5235+
5236+ updates = ((int *)data)[0] == 1? 2 : 1;
5237+
5238+ err = at_send_command_singleline("AT+CREG=%d","+CLIP:",&atResponse, updates);
5239+ if (err != AT_NOERROR)
5240+ goto error;
5241+
5242+ at_response_free(atResponse);
5243+
5244+ //Always return success for CDMA (for now)
5245+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5246+ return;
5247+
5248+error:
5249+ at_response_free(atResponse);
5250+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5251+}
5252+
5253+static void requestLastFailCause(RIL_Token t)
5254+{
5255+ ATResponse *atResponse = NULL;
5256+ int err = 0;
5257+ int response = 0;
5258+ char *tmp = NULL;
5259+ char *line = NULL;
5260+
5261+ err = at_send_command_singleline("AT+CEER", "+CEER:", &atResponse);
5262+ if(err != AT_NOERROR)
5263+ goto error;
5264+
5265+ line = atResponse->p_intermediates->line;
5266+ err = at_tok_start(&line);
5267+ if(err < 0) goto error;
5268+
5269+ err = at_tok_nextstr(&line, &tmp);
5270+ if(err < 0) goto error;
5271+
5272+ err = at_tok_nextint(&line, &response);
5273+ if(err < 0) goto error;
5274+
5275+ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(int));
5276+ at_response_free(atResponse);
5277+ return;
5278+
5279+error:
5280+ at_response_free(atResponse);
5281+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5282+
5283+}
5284+
5285+/*
5286+ * "data" is int *
5287+ * ((int *)data)[0] is == 0 from RUIM/SIM (default)
5288+ * ((int *)data)[0] is == 1 from NV
5289+ */
5290+static void requestCdmaSubscription(void * data, size_t datalen, RIL_Token t)
5291+{
5292+
5293+ /*
5294+ * "data" is int *
5295+ * ((int *)data)[0] is == 0 from RUIM/SIM (default)
5296+ * ((int *)data)[0] is == 1 from NV
5297+ */
5298+
5299+ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
5300+}
5301+
5302+
5303+/*
5304+ * RIL_REQUEST_GET_NEIGHBORING_CELL_IDS
5305+ */
5306+static void requestNeighboringCellIds(void * data, size_t datalen, RIL_Token t)
5307+{
5308+ int err;
5309+ ATResponse *atResponse = NULL;
5310+ char *line, *p;
5311+ int commas;
5312+ int skip;
5313+ int lac = 0,cid = 0;
5314+ int count = 3;
5315+ int ber;
5316+ int rssi;
5317+
5318+ RIL_NeighboringCell **pp_cellIds;
5319+ RIL_NeighboringCell *p_cellIds;
5320+
5321+ pp_cellIds = (RIL_NeighboringCell **)alloca(sizeof(RIL_NeighboringCell *));
5322+ p_cellIds = (RIL_NeighboringCell *)alloca(sizeof(RIL_NeighboringCell));
5323+ pp_cellIds[0]=p_cellIds;
5324+
5325+ err = at_send_command_singleline("AT+CREG?", "+CREG:", &atResponse);
5326+ if (err != AT_NOERROR)
5327+ goto error;
5328+
5329+ line = atResponse->p_intermediates->line;
5330+
5331+ err = at_tok_start(&line);
5332+ if (err < 0) goto error;
5333+
5334+ /* Ok you have to be careful here
5335+ * The solicited version of the CREG response is
5336+ * +CREG: n, stat, [lac, cid]
5337+ * and the unsolicited version is
5338+ * +CREG: stat, [lac, cid]
5339+ * The <n> parameter is basically "is unsolicited creg on?"
5340+ * which it should always be
5341+ *
5342+ * Now we should normally get the solicited version here,
5343+ * but the unsolicited version could have snuck in
5344+ * so we have to handle both
5345+ *
5346+ * Also since the LAC and CID are only reported when registered,
5347+ * we can have 1, 2, 3, or 4 arguments here
5348+ *
5349+ * finally, a +CGREG: answer may have a fifth value that corresponds
5350+ * to the network type, as in;
5351+ *
5352+ * +CGREG: n, stat [,lac, cid [,networkType]]
5353+ */
5354+
5355+ /* count number of commas */
5356+ commas = 0;
5357+ for (p = line ; *p != '\0' ;p++) {
5358+ if (*p == ',') commas++;
5359+ }
5360+ switch (commas) {
5361+ case 0: /* +CREG: <stat> */
5362+ case 1: /* +CREG: <n>, <stat> */
5363+ goto error;
5364+
5365+ case 2: /* +CREG: <stat>, <lac>, <cid> */
5366+ err = at_tok_nextint(&line, &skip);
5367+ if (err < 0) goto error;
5368+ err = at_tok_nexthexint(&line, &lac);
5369+ if (err < 0) goto error;
5370+ err = at_tok_nexthexint(&line, &cid);
5371+ if (err < 0) goto error;
5372+ break;
5373+ case 3: /* +CREG: <n>, <stat>, <lac>, <cid> */
5374+ err = at_tok_nextint(&line, &skip);
5375+ if (err < 0) goto error;
5376+ err = at_tok_nextint(&line, &skip);
5377+ if (err < 0) goto error;
5378+ err = at_tok_nexthexint(&line, &lac);
5379+ if (err < 0) goto error;
5380+ err = at_tok_nexthexint(&line, &cid);
5381+ if (err < 0) goto error;
5382+ break;
5383+ case 4: /* +CGREG: <n>, <stat>, <lac>, <cid>, <networkType> */
5384+ err = at_tok_nextint(&line, &skip);
5385+ if (err < 0) goto error;
5386+ err = at_tok_nextint(&line, &skip);
5387+ if (err < 0) goto error;
5388+ err = at_tok_nexthexint(&line, &lac);
5389+ if (err < 0) goto error;
5390+ err = at_tok_nexthexint(&line, &cid);
5391+ if (err < 0) goto error;
5392+ err = at_tok_nexthexint(&line, &skip);
5393+ if (err < 0) goto error;
5394+ count = 4;
5395+ break;
5396+ default:
5397+ goto error;
5398+ }
5399+
5400+
5401+ at_response_free(atResponse);
5402+
5403+ err = at_send_command_singleline("AT+CSQ", "+CSQ:", &atResponse);
5404+ if (err != AT_NOERROR)
5405+ goto error;
5406+
5407+ line = atResponse->p_intermediates->line;
5408+
5409+ err = at_tok_start(&line);
5410+ if (err < 0) goto error;
5411+
5412+ err = at_tok_nextint(&line,&rssi);
5413+ if (err < 0) goto error;
5414+
5415+ err = at_tok_nextint(&line, &ber);
5416+ if (err < 0)
5417+ goto error;
5418+
5419+ /* Dump the current cell information */
5420+ p_cellIds[0].cid = (char*) alloca(16);
5421+ sprintf(p_cellIds[0].cid, "%04x%04x", lac & 0xFFFF, cid & 0xFFFF );
5422+ p_cellIds[0].rssi = rssi;
5423+
5424+ RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_cellIds, sizeof(pp_cellIds));
5425+ at_response_free(atResponse);
5426+ return;
5427+
5428+error:
5429+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5430+ at_response_free(atResponse);
5431+}
5432+
5433+static pthread_t s_tid_queueRunner;
5434+
5435+
5436+/** Do post- SIM ready initialization. */
5437+static void onSIMReady(void *p)
5438+{
5439+ int err = 0;
5440+ (void) p;
5441+
5442+ /* Check if ME is ready to set preferred message storage */
5443+ checkMessageStorageReady(NULL);
5444+
5445+ /* Select message service */
5446+ at_send_command("AT+CSMS=0");
5447+
5448+ /*
5449+ * Always send SMS messages directly to the TE
5450+ *
5451+ * mode = 1 // discard when link is reserved (link should never be
5452+ * reserved)
5453+ * mt = 2 // most messages routed to TE
5454+ * bm = 2 // new cell BM's routed to TE
5455+ * ds = 1 // Status reports routed to TE
5456+ * bfr = 1 // flush buffer
5457+ */
5458+ at_send_command("AT+CNMI=1,2,2,1,1");
5459+
5460+ /* Select cell broadcast messages: Do not accept messages */
5461+ at_send_command("AT+CSCB=1");
5462+
5463+ /* Enable automatic timezone update */
5464+ at_send_command("AT+CTZU=1");
5465+
5466+ /* Enable timezone change reporting */
5467+ at_send_command("AT+CTZR=1");
5468+
5469+ /* Subscribe to network registration events.
5470+ * n = 2 - Enable network registration and location information
5471+ * unsolicited result code +CREG: <stat>[,<lac>,<ci>]
5472+ */
5473+ err = at_send_command("AT+CREG=2");
5474+ if (err != AT_NOERROR) {
5475+ /* Some handsets -- in tethered mode -- don't support CREG=2. */
5476+ at_send_command("AT+CREG=1");
5477+ }
5478+
5479+ /* Configure Short Message (SMS) Format
5480+ * mode = 0 - PDU mode.
5481+ */
5482+ at_send_command("AT+CMGF=0");
5483+
5484+ /* Enable unsolicited RSSI reporting */
5485+ at_send_command("AT^CURC=1");
5486+
5487+ /* Enable GPRS reporting */
5488+ at_send_command("AT+CGEREP=1,0");
5489+
5490+
5491+ /* Select SMS type */
5492+ at_send_command_singleline("AT+CSMS=1", "+CSMS:", NULL);
5493+}
5494+
5495+
5496+
5497+static void requestNotSupported(RIL_Token t, int request)
5498+{
5499+ D("Request %d is unsupported", request);
5500+ RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
5501+ return;
5502+}
5503+
5504+
5505+/*** Callback methods from the RIL library to us ***/
5506+
5507+static void processRequest (int request, void *data, size_t datalen, RIL_Token t)
5508+{
5509+ D("%s() %s", __func__, requestToString(request));
5510+
5511+ /*
5512+ * These commands won't accept RADIO_NOT_AVAILABLE, so we just return
5513+ * GENERIC_FAILURE if we're not in SIM_STATE_READY.
5514+ */
5515+ RIL_RadioState radio_state = getRadioState();
5516+
5517+ if (radio_state != RADIO_STATE_SIM_READY &&
5518+ (request == RIL_REQUEST_WRITE_SMS_TO_SIM ||
5519+ request == RIL_REQUEST_DELETE_SMS_ON_SIM)) {
5520+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5521+ return;
5522+ }
5523+
5524+ /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
5525+ * when RADIO_STATE_UNAVAILABLE.
5526+ */
5527+ if (radio_state == RADIO_STATE_UNAVAILABLE
5528+ && request != RIL_REQUEST_GET_SIM_STATUS) {
5529+ RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
5530+ return;
5531+ }
5532+
5533+ /* Ignore all non-power requests when RADIO_STATE_OFF
5534+ * (except RIL_REQUEST_GET_SIM_STATUS and a few more).
5535+ */
5536+ if ((radio_state == RADIO_STATE_OFF || radio_state == RADIO_STATE_SIM_NOT_READY) &&
5537+ !(request == RIL_REQUEST_RADIO_POWER ||
5538+ request == RIL_REQUEST_GET_SIM_STATUS ||
5539+ request == RIL_REQUEST_STK_GET_PROFILE ||
5540+ request == RIL_REQUEST_STK_SET_PROFILE ||
5541+ request == RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING ||
5542+ request == RIL_REQUEST_GET_IMEISV ||
5543+ request == RIL_REQUEST_GET_IMEI ||
5544+ request == RIL_REQUEST_BASEBAND_VERSION ||
5545+ request == RIL_REQUEST_SCREEN_STATE)) {
5546+ RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
5547+ return;
5548+ }
5549+
5550+ /* Don't allow radio operations when sim is absent or locked! */
5551+ if (radio_state == RADIO_STATE_SIM_LOCKED_OR_ABSENT &&
5552+ !(request == RIL_REQUEST_ENTER_SIM_PIN ||
5553+ request == RIL_REQUEST_ENTER_SIM_PUK ||
5554+ request == RIL_REQUEST_ENTER_SIM_PIN2 ||
5555+ request == RIL_REQUEST_ENTER_SIM_PUK2 ||
5556+ request == RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION ||
5557+ request == RIL_REQUEST_GET_SIM_STATUS ||
5558+ request == RIL_REQUEST_RADIO_POWER ||
5559+ request == RIL_REQUEST_GET_IMEISV ||
5560+ request == RIL_REQUEST_GET_IMEI ||
5561+ request == RIL_REQUEST_BASEBAND_VERSION ||
5562+ request == RIL_REQUEST_GET_CURRENT_CALLS)) {
5563+ RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
5564+ return;
5565+ }
5566+
5567+
5568+ switch (request) {
5569+ case RIL_REQUEST_GET_CURRENT_CALLS:
5570+ if (radio_state == RADIO_STATE_SIM_LOCKED_OR_ABSENT)
5571+ RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
5572+ else
5573+ requestGetCurrentCalls(data, datalen, t);
5574+ break;
5575+
5576+ case RIL_REQUEST_SCREEN_STATE:
5577+ requestScreenState(data, datalen, t);
5578+ /* Trigger a rehash of network values, just to be sure. */
5579+ if (((int *)data)[0] == 1)
5580+ RIL_onUnsolicitedResponse(
5581+ RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
5582+ NULL, 0);
5583+ break;
5584+
5585+ /* Data Call Requests */
5586+ case RIL_REQUEST_SETUP_DATA_CALL:
5587+ requestSetupDefaultPDP(data, datalen, t);
5588+ break;
5589+ case RIL_REQUEST_DEACTIVATE_DATA_CALL:
5590+ requestDeactivateDefaultPDP(data, datalen, t);
5591+ break;
5592+ case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE:
5593+ requestLastPDPFailCause(t);
5594+ break;
5595+ case RIL_REQUEST_DATA_CALL_LIST:
5596+ requestPDPContextList(t);
5597+ break;
5598+
5599+ /* SMS Requests */
5600+ case RIL_REQUEST_SEND_SMS:
5601+ requestSendSMS(data, datalen, t);
5602+ break;
5603+ case RIL_REQUEST_SEND_SMS_EXPECT_MORE:
5604+ requestSendSMSExpectMore(data, datalen, t);
5605+ break;
5606+ case RIL_REQUEST_WRITE_SMS_TO_SIM:
5607+ requestWriteSmsToSim(data, datalen, t);
5608+ break;
5609+ case RIL_REQUEST_DELETE_SMS_ON_SIM:
5610+ requestDeleteSmsOnSim(data, datalen, t);
5611+ break;
5612+ case RIL_REQUEST_GET_SMSC_ADDRESS:
5613+ requestGetSMSCAddress(t);
5614+ break;
5615+ case RIL_REQUEST_SET_SMSC_ADDRESS:
5616+ requestSetSMSCAddress(data, datalen, t);
5617+ break;
5618+ case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS:
5619+ requestSmsStorageFull(data, datalen, t);
5620+ break;
5621+ case RIL_REQUEST_SMS_ACKNOWLEDGE:
5622+ requestSMSAcknowledge(data, datalen, t);
5623+ break;
5624+ case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
5625+ requestGSMGetBroadcastSMSConfig(t);
5626+ break;
5627+ case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
5628+ requestGSMSetBroadcastSMSConfig(data, datalen, t);
5629+ break;
5630+ case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:
5631+ requestGSMSMSBroadcastActivation(data, datalen, t);
5632+ break;
5633+
5634+ /* SIM Handling Requests */
5635+ case RIL_REQUEST_SIM_IO:
5636+ requestSIM_IO(data, datalen, t);
5637+ break;
5638+ case RIL_REQUEST_GET_SIM_STATUS:
5639+ requestGetSimStatus(t);
5640+ break;
5641+ case RIL_REQUEST_ENTER_SIM_PIN:
5642+ case RIL_REQUEST_ENTER_SIM_PUK:
5643+ case RIL_REQUEST_ENTER_SIM_PIN2:
5644+ case RIL_REQUEST_ENTER_SIM_PUK2:
5645+ requestEnterSimPin(data, datalen, t, request);
5646+ break;
5647+ case RIL_REQUEST_CHANGE_SIM_PIN:
5648+ requestChangePassword(data, datalen, t, "SC", request);
5649+ break;
5650+ case RIL_REQUEST_CHANGE_SIM_PIN2:
5651+ requestChangePassword(data, datalen, t, "P2", request);
5652+ break;
5653+ case RIL_REQUEST_QUERY_FACILITY_LOCK:
5654+ requestQueryFacilityLock(data, datalen, t);
5655+ break;
5656+ case RIL_REQUEST_SET_FACILITY_LOCK:
5657+ requestSetFacilityLock(data, datalen, t);
5658+ break;
5659+
5660+ /* Network Requests */
5661+ case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
5662+ requestEnterSimPin(data, datalen, t, request);
5663+ break;
5664+ case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
5665+ requestQueryNetworkSelectionMode(t);
5666+ break;
5667+ case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
5668+ requestSetNetworkSelectionAutomatic(t);
5669+ break;
5670+ case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL:
5671+ requestSetNetworkSelectionManual(data, datalen, t);
5672+ break;
5673+ case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS:
5674+ requestQueryAvailableNetworks(t);
5675+ break;
5676+ case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
5677+ requestSetPreferredNetworkType(data, datalen, t);
5678+ break;
5679+ case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
5680+ requestGetPreferredNetworkType(t);
5681+ break;
5682+ case RIL_REQUEST_VOICE_REGISTRATION_STATE:
5683+ requestRegistrationState(t);
5684+ break;
5685+ case RIL_REQUEST_DATA_REGISTRATION_STATE:
5686+ requestGprsRegistrationState(t);
5687+ break;
5688+
5689+ /* OEM */
5690+ case RIL_REQUEST_OEM_HOOK_RAW:
5691+ // echo back data
5692+ requestOEMHookRaw(data, datalen, t);
5693+ break;
5694+ case RIL_REQUEST_OEM_HOOK_STRINGS:
5695+ requestOEMHookStrings(data, datalen, t);
5696+ break;
5697+
5698+ /* Misc */
5699+ case RIL_REQUEST_SIGNAL_STRENGTH:
5700+ requestSignalStrength(t);
5701+ break;
5702+ case RIL_REQUEST_OPERATOR:
5703+ requestOperator(t);
5704+ break;
5705+ case RIL_REQUEST_RADIO_POWER:
5706+ requestRadioPower(data, datalen, t);
5707+ break;
5708+ case RIL_REQUEST_GET_IMSI:
5709+ requestGetIMSI(t);
5710+ break;
5711+ case RIL_REQUEST_GET_IMEI:
5712+ requestGetIMEISV(t);
5713+ break;
5714+ case RIL_REQUEST_GET_IMEISV:
5715+ requestGetIMEISV(t);
5716+ break;
5717+ case RIL_REQUEST_DEVICE_IDENTITY:
5718+ requestDeviceIdentity(t);
5719+ break;
5720+ case RIL_REQUEST_BASEBAND_VERSION:
5721+ requestBasebandVersion(t);
5722+ break;
5723+
5724+ /* SIM Application Toolkit */
5725+ case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE:
5726+ requestStkSendTerminalResponse(data, datalen, t);
5727+ break;
5728+ case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND:
5729+ requestStkSendEnvelopeCommand(data, datalen, t);
5730+ break;
5731+ case RIL_REQUEST_STK_GET_PROFILE:
5732+ requestStkGetProfile(t);
5733+ break;
5734+ case RIL_REQUEST_STK_SET_PROFILE:
5735+ requestStkSetProfile(data, datalen, t);
5736+ break;
5737+ case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING:
5738+ requestReportStkServiceIsRunning(t);
5739+ break;
5740+
5741+ /* Misc ops */
5742+ case RIL_REQUEST_DIAL:
5743+ requestDial(data, datalen, t);
5744+ break;
5745+ case RIL_REQUEST_HANGUP:
5746+ requestHangup(data, datalen, t);
5747+ break;
5748+ case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
5749+ requestHangupWaitingOrBackground(t);
5750+ break;
5751+ case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
5752+ requestHangupForegroundResumeBackground(t);
5753+ break;
5754+ case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
5755+ requestSwitchWaitingOrHoldingAndActive(t);
5756+ break;
5757+ case RIL_REQUEST_ANSWER:
5758+ requestAnswer(t);
5759+ break;
5760+ case RIL_REQUEST_CONFERENCE:
5761+ requestConference(t);
5762+ break;
5763+ case RIL_REQUEST_UDUB:
5764+ requestUDUB(t);
5765+ break;
5766+ case RIL_REQUEST_SEPARATE_CONNECTION:
5767+ requestSeparateConnection(data, datalen, t);
5768+ break;
5769+ case RIL_REQUEST_SET_MUTE:
5770+ requestSetMute(data, datalen, t);
5771+ break;
5772+ case RIL_REQUEST_GET_MUTE:
5773+ requestGetMute(t);
5774+ break;
5775+ case RIL_REQUEST_DTMF:
5776+ requestDTMF(data, datalen, t);
5777+ break;
5778+ case RIL_REQUEST_DTMF_STOP:
5779+ requestDtmfStop(t);
5780+ break;
5781+ case RIL_REQUEST_DTMF_START:
5782+ requestDtmfStart(data, datalen, t);
5783+ break;
5784+ case RIL_REQUEST_CANCEL_USSD:
5785+ requestCancelUSSD(t);
5786+ break;
5787+ case RIL_REQUEST_QUERY_CALL_WAITING:
5788+ requestQueryCallWaiting(data, datalen, t);
5789+ break;
5790+ case RIL_REQUEST_SET_CALL_WAITING:
5791+ requestSetCallWaiting(data, datalen, t);
5792+ break;
5793+ case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS:
5794+ requestQueryCallForwardStatus(t);
5795+ break;
5796+ case RIL_REQUEST_SET_CALL_FORWARD:
5797+ requestSetCallForward(data, t);
5798+ break;
5799+ case RIL_REQUEST_GET_CLIR:
5800+ requestGetCLIR(data, datalen, t);
5801+ break;
5802+ case RIL_REQUEST_SET_CLIR:
5803+ requestSetCLIR(data, datalen, t);
5804+ break;
5805+ case RIL_REQUEST_SEND_USSD:
5806+ requestSendUSSD(data, datalen, t);
5807+ break;
5808+ case RIL_REQUEST_CHANGE_BARRING_PASSWORD:
5809+ requestChangeBarringPassword(data, datalen, t);
5810+ break;
5811+ case RIL_REQUEST_QUERY_CLIP:
5812+ requestQueryCLIP(t);
5813+ break;
5814+ case RIL_REQUEST_RESET_RADIO:
5815+ requestResetRadio(t);
5816+ break;
5817+ case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
5818+ requestSetSuppSVCNotification(data, datalen, t);
5819+ break;
5820+ case RIL_REQUEST_EXPLICIT_CALL_TRANSFER:
5821+ requestExplicitCallTransfer(t);
5822+ break;
5823+ case RIL_REQUEST_SET_LOCATION_UPDATES:
5824+ requestSetLocationUpdates(data, datalen, t);
5825+ break;
5826+ case RIL_REQUEST_LAST_CALL_FAIL_CAUSE:
5827+ requestLastFailCause(t);
5828+ break;
5829+ case 503: //GET_SIM_TYPES
5830+ RIL_onRequestComplete(t, RIL_E_SUCCESS, 0, sizeof(int));
5831+ break;
5832+ case 504: //GET_PB_ENTRIES_LENGTH
5833+ {
5834+ int response[6];
5835+ response[0]=1;
5836+ response[1]=0;
5837+ response[2]=0;
5838+ response[3]=0;
5839+ response[4]=0;
5840+ response[5]=0;
5841+ RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
5842+ }
5843+ break;
5844+
5845+ case 525: //GET_SUBSCRIBER_NUMBER
5846+ break;
5847+
5848+ case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
5849+ requestCdmaSubscription(data, datalen, t);
5850+ break;
5851+
5852+ case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
5853+ requestNeighboringCellIds(data, datalen, t);
5854+ break;
5855+
5856+ default:
5857+ LOGW("FIXME: Unsupported request logged: %s",
5858+ requestToString(request));
5859+ requestNotSupported(t, request);
5860+ break;
5861+ }
5862+}
5863+
5864+/**
5865+ * Call from RIL to us to make a RIL_REQUEST
5866+ *
5867+ * Must be completed with a call to RIL_onRequestComplete()
5868+ *
5869+ * RIL_onRequestComplete() may be called from any thread, before or after
5870+ * this function returns.
5871+ *
5872+ * Will always be called from the same thread, so returning here implies
5873+ * that the radio is ready to process another command (whether or not
5874+ * the previous command has completed).
5875+ */
5876+
5877+/**
5878+ * Call from RIL to us to make a RIL_REQUEST.
5879+ *
5880+ * Must be completed with a call to RIL_onRequestComplete().
5881+ */
5882+static void onRequest(int request, void *data, size_t datalen, RIL_Token t)
5883+{
5884+ RILRequest *r;
5885+ RequestQueue *q = &s_requestQueue;
5886+ int err;
5887+
5888+ r = (RILRequest *) malloc(sizeof(RILRequest));
5889+ memset(r, 0, sizeof(RILRequest));
5890+
5891+ /* Formulate a RILRequest and put it in the queue. */
5892+ r->request = request;
5893+ r->data = dupRequestData(request, data, datalen);
5894+ r->datalen = datalen;
5895+ r->token = t;
5896+
5897+ if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
5898+ LOGE("%s() failed to take queue mutex: %s!", __func__, strerror(err));
5899+
5900+ /* Queue empty, just throw r on top. */
5901+ if (q->requestList == NULL) {
5902+ q->requestList = r;
5903+ } else {
5904+ RILRequest *l = q->requestList;
5905+ while (l->next != NULL)
5906+ l = l->next;
5907+
5908+ l->next = r;
5909+ }
5910+
5911+ if ((err = pthread_cond_broadcast(&q->cond)) != 0)
5912+ LOGE("%s() failed to broadcast queue update: %s!",
5913+ __func__, strerror(err));
5914+
5915+ if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
5916+ LOGE("%s() failed to release queue mutex: %s!",
5917+ __func__, strerror(err));
5918+}
5919+
5920+/**
5921+ * Call from RIL to us to find out whether a specific request code
5922+ * is supported by this implementation.
5923+ *
5924+ * Return 1 for "supported" and 0 for "unsupported".
5925+ *
5926+ * Currently just stubbed with the default value of one. This is currently
5927+ * not used by android, and therefore not implemented here. We return
5928+ * RIL_E_REQUEST_NOT_SUPPORTED when we encounter unsupported requests.
5929+ */
5930+static int onSupports(int requestCode)
5931+{
5932+ (void) requestCode;
5933+ LOGI("onSupports() called!");
5934+
5935+ return 1;
5936+}
5937+
5938+/**
5939+ * onCancel() is currently stubbed, because android doesn't use it and
5940+ * our implementation will depend on how a cancellation is handled in
5941+ * the upper layers.
5942+ */
5943+static void onCancel(RIL_Token t)
5944+{
5945+ (void) t;
5946+ LOGI("onCancel() called!");
5947+}
5948+
5949+static const char * getVersion(void)
5950+{
5951+ return RIL_VERSION_STRING;
5952+}
5953+
5954+static void sendTime(void *p)
5955+{
5956+ time_t t;
5957+ struct tm tm;
5958+ char str[20];
5959+ char tz[6];
5960+ int num[4];
5961+ int tzi;
5962+ int i;
5963+ (void) p;
5964+
5965+ tzset();
5966+ t = time(NULL);
5967+
5968+ if (!(localtime_r(&t, &tm)))
5969+ return;
5970+ if (!(strftime(tz, 12, "%z", &tm)))
5971+ return;
5972+
5973+ for (i = 0; i < 4; i++)
5974+ num[i] = tz[i+1] - '0';
5975+
5976+ /* convert timezone hours to timezone quarters of hours */
5977+ tzi = (num[0] * 10 + num[1]) * 4 + (num[2] * 10 + num[3]) / 15;
5978+ strftime(str, 20, "%y/%m/%d,%T", &tm);
5979+ at_send_command("AT+CCLK=\"%s%c%02d\"", str, tz[0], tzi);
5980+}
5981+
5982+
5983+static char initializeCommon(void)
5984+{
5985+ int err = 0;
5986+ unsigned int i;
5987+ static const char* const initcmd[] = {
5988+
5989+ /* Reset the MS*/
5990+ "AT+CFUN=6",
5991+
5992+ /* atchannel is tolerant of echo but it must */
5993+ /* reset and have verbose result codes */
5994+ "ATZV1",
5995+
5996+ /* echo off */
5997+ "ATE0",
5998+
5999+ /* No auto-answer */
6000+ "ATS0=0",
6001+
6002+ /* No auto-answer */
6003+ "AT%AUTOANSWER=0",
6004+
6005+ /* send results */
6006+ "ATQ0",
6007+
6008+ /* check for busy, don't check for dialone */
6009+ "ATX3",
6010+
6011+ /* set DCD depending on service */
6012+ "AT&C1",
6013+
6014+ /* set DTR according to service */
6015+ "AT&D1",
6016+
6017+ /* Extended errors without textual decriptions */
6018+ "AT+CMEE=1",
6019+
6020+ /* detailed rings, unknown */
6021+ "AT+CRC=1;+CR=1",
6022+
6023+ /* caller id = yes */
6024+ "AT+CLIP=1",
6025+
6026+ /* don't hide outgoing callerID */
6027+ "AT+CLIR=0",
6028+
6029+ /* Call Waiting notifications */
6030+ "AT+CCWA=1",
6031+
6032+ /* No connected line identification */
6033+ "AT+COLP=0",
6034+
6035+ /* USSD unsolicited */
6036+ "AT+CUSD=1",
6037+
6038+ /* SMS PDU mode */
6039+ "AT+CMGF=0",
6040+
6041+ //"AT+GTKC=2",
6042+
6043+ /* +CSSU unsolicited supp service notifications */
6044+ "AT+CSSN=0,1",
6045+
6046+ /* HEX character set */
6047+ //"AT+CSCS=\"HEX\"",
6048+ "AT+CSCS=\"IRA\"",
6049+
6050+ /* Modem mode */
6051+ "AT+FCLASS=0",
6052+
6053+ "AT+CNMI=1,2,2,2,0",
6054+ //"AT+CPPP=1",
6055+
6056+
6057+ "AT"
6058+ };
6059+
6060+ if (at_handshake() < 0) {
6061+ LOG_FATAL("Handshake failed!");
6062+ return 1;
6063+ }
6064+
6065+
6066+ for (i=0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) {
6067+ err = at_send_command(initcmd[i]);
6068+ if (err != AT_NOERROR) {
6069+ LOGE("Failed sending command '%s'",initcmd[i]);
6070+ }
6071+ }
6072+
6073+ /* Send the current time of the OS to the module */
6074+ sendTime(NULL);
6075+
6076+ return 0;
6077+}
6078+
6079+/**
6080+ * Initialize everything
6081+ */
6082+static char initializeChannel(void)
6083+{
6084+ int err = 0;
6085+ unsigned int i;
6086+ static const char* const initcmd[] = {
6087+
6088+ /* Configure Packet Domain Network Registration Status events
6089+ * 2 = Enable network registration and location information
6090+ * unsolicited result code
6091+ */
6092+
6093+ /* Alternating voice/data off */
6094+ "AT+CMOD=0",
6095+
6096+ /* Not muted */
6097+ "AT+CMUT=0",
6098+
6099+ /* Network registration events */
6100+ "AT+CREG=2",
6101+
6102+ /* GPRS registration events */
6103+ "AT+CGREG=2",
6104+
6105+ "AT+CGEQREQ=1,4,0,0,0,0,2,0,\"0E0\",\"0E0\",3,0,0",
6106+
6107+ /* Enable unsolicited reports */
6108+ "AT^CURC=1",
6109+
6110+ /* Enable GPRS reporting */
6111+ "AT+CGEREP=1,0",
6112+
6113+ /* for 3G Preferred */
6114+ "AT^SYSCFG=2,2,3FFFFFFF,1,2",
6115+
6116+ /* Disable RF */
6117+ "AT^RFSWITCH=0"
6118+ };
6119+
6120+ D("%s()", __func__);
6121+
6122+ setRadioState(RADIO_STATE_OFF);
6123+
6124+ for (i=0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) {
6125+ err = at_send_command(initcmd[i]);
6126+ if (err != AT_NOERROR) {
6127+ LOGE("Failed sending command '%s'",initcmd[i]);
6128+ }
6129+ }
6130+
6131+ /* Assume radio is off on error. */
6132+ if (isRadioOn() > 0)
6133+ setRadioState(RADIO_STATE_SIM_NOT_READY);
6134+
6135+ return 0;
6136+}
6137+
6138+/**
6139+ * Called by atchannel when an unsolicited line appears
6140+ * This is called on atchannel's reader thread. AT commands may
6141+ * not be issued here
6142+ */
6143+static void onUnsolicited (const char *s, const char *sms_pdu)
6144+{
6145+ /* Ignore unsolicited responses until we're initialized.
6146+ This is OK because the RIL library will poll for initial state. */
6147+ if (getRadioState() == RADIO_STATE_UNAVAILABLE)
6148+ return;
6149+
6150+ if (strStartsWith(s, "%CTZV:")
6151+ || strStartsWith(s,"+CTZV:")
6152+ || strStartsWith(s,"+CTZDST:")
6153+ || strStartsWith(s,"+HTCCTZV:")) {
6154+ unsolicitedNitzTime(s);
6155+ } else if (strStartsWith(s,"+CRING:")
6156+ || strStartsWith(s,"RING")
6157+ || strStartsWith(s,"NO CARRIER")
6158+ || strStartsWith(s,"+CCWA")
6159+ ) {
6160+ RIL_onUnsolicitedResponse (
6161+ RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
6162+ NULL, 0);
6163+ enqueueRILEvent(onDataCallListChanged, NULL, NULL);
6164+ } else if (strStartsWith(s,"^RSSI:") ||
6165+ strStartsWith(s,"%RSSI:")) {
6166+ unsolicitedRSSI(s);
6167+ } else if (strStartsWith(s,"^MODE:")) {
6168+ unsolicitedMode(s);
6169+ } else if (strStartsWith(s,"+CREG:")
6170+ || strStartsWith(s,"+CGREG:")) {
6171+ RIL_onUnsolicitedResponse (
6172+ RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
6173+ NULL, 0);
6174+ enqueueRILEvent(onDataCallListChanged, NULL, NULL);
6175+ } else if (strStartsWith(s, "+CMT:")) {
6176+ onNewSms(sms_pdu);
6177+ } else if (strStartsWith(s, "+CBM:")) {
6178+ onNewBroadcastSms(sms_pdu);
6179+ } else if (strStartsWith(s, "+CMTI:")) {
6180+ onNewSmsOnSIM(s);
6181+ } else if (strStartsWith(s, "+CDS:")) {
6182+ onNewStatusReport(sms_pdu);
6183+ } else if (strStartsWith(s, "+CGEV:")) {
6184+ /* Really, we can ignore NW CLASS and ME CLASS events here,
6185+ * but right now we don't since extranous
6186+ * RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
6187+ */
6188+ /* can't issue AT commands here -- call on main thread */
6189+ enqueueRILEvent(onDataCallListChanged, NULL, NULL);
6190+ } else if (strStartsWith(s, "+CUSD:")) {
6191+ unsolicitedUSSD(s);
6192+ } else if (strStartsWith(s, "+CIEV: 7") ||
6193+ strStartsWith(s, "Received SMS:")) {
6194+ onNewSmsIndication();
6195+ }
6196+}
6197+
6198+static void signalCloseQueues(void)
6199+{
6200+ unsigned int i;
6201+ for (i = 0; i < (sizeof(s_requestQueues) / sizeof(RequestQueue *)); i++) {
6202+ int err;
6203+ RequestQueue *q = s_requestQueues[i];
6204+ if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
6205+ LOGE("%s() failed to take queue mutex: %s",
6206+ __func__, strerror(err));
6207+
6208+ q->closed = 1;
6209+ if ((err = pthread_cond_signal(&q->cond)) != 0)
6210+ LOGE("%s() failed to broadcast queue update: %s",
6211+ __func__, strerror(err));
6212+
6213+ if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
6214+ LOGE("%s() failed to take queue mutex: %s", __func__,
6215+ strerror(err));
6216+ }
6217+}
6218+
6219+
6220+/* Called on command or reader thread */
6221+static void onATReaderClosed()
6222+{
6223+ LOGI("AT channel closed\n");
6224+
6225+ setRadioState (RADIO_STATE_UNAVAILABLE);
6226+ signalCloseQueues();
6227+ at_close();
6228+}
6229+
6230+/* Called on command thread */
6231+static void onATTimeout()
6232+{
6233+ LOGI("AT channel timeout; restarting..");
6234+ /* Last resort, throw escape on the line, close the channel
6235+ and hope for the best. */
6236+ at_send_escape();
6237+
6238+ setRadioState(RADIO_STATE_UNAVAILABLE);
6239+ signalCloseQueues();
6240+
6241+ /* TODO We may cause a radio reset here. */
6242+}
6243+
6244+static void usage(char *s)
6245+{
6246+#ifdef RIL_SHLIB
6247+ fprintf(stderr, "htcgeneric-ril requires: -p <tcp port> or -d /dev/tty_device\n");
6248+#else
6249+ fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device] [-v /dev/tty_device]\n", s);
6250+ exit(-1);
6251+#endif
6252+}
6253+
6254+struct queueArgs {
6255+ int port;
6256+ char * loophost;
6257+ const char *device_path;
6258+};
6259+
6260+static int safe_read(int fd, char *buf, int count)
6261+{
6262+ int n;
6263+ int i = 0;
6264+
6265+ while (i < count) {
6266+ n = read(fd, buf + i, count - i);
6267+ if (n > 0)
6268+ i += n;
6269+ else if (!(n < 0 && errno == EINTR))
6270+ return -1;
6271+ }
6272+
6273+ return count;
6274+}
6275+
6276+static void *queueRunner(void *param)
6277+{
6278+ int fd = -1;
6279+ int ret = 0;
6280+ int n;
6281+ fd_set input;
6282+ struct timespec timeout;
6283+ int max_fd = -1;
6284+ char start[MAX_BUF];
6285+ struct queueArgs *queueArgs = (struct queueArgs *) param;
6286+ struct RequestQueue *q = NULL;
6287+
6288+ LOGI("%s() starting!", __func__);
6289+
6290+ for (;;) {
6291+ fd = -1;
6292+ max_fd = -1;
6293+ while (fd < 0) {
6294+ if (queueArgs->port > 0) {
6295+ if (queueArgs->loophost)
6296+ fd = socket_network_client(queueArgs->loophost, queueArgs->port, SOCK_STREAM);
6297+ else
6298+ fd = socket_loopback_client(queueArgs->port, SOCK_STREAM);
6299+ } else if (queueArgs->device_path != NULL) {
6300+
6301+ fd = open (queueArgs->device_path, O_RDWR);
6302+ if ( fd >= 0 && !memcmp( queueArgs->device_path, "/dev/ttyUSB", 11 ) ) {
6303+
6304+ /* disable echo on serial ports */
6305+ struct termios ios;
6306+ tcgetattr( fd, &ios );
6307+ ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
6308+ tcsetattr( fd, TCSANOW, &ios );
6309+ }
6310+ }
6311+
6312+ if (fd < 0) {
6313+ LOGE("%s() Failed to open AT channel %s (%s), retrying in %d.",
6314+ __func__, queueArgs->device_path,
6315+ strerror(errno), TIMEOUT_SEARCH_FOR_TTY);
6316+ sleep(TIMEOUT_SEARCH_FOR_TTY);
6317+ /* Never returns. */
6318+ }
6319+ }
6320+
6321+ ret = at_open(fd, onUnsolicited);
6322+
6323+ if (ret < 0) {
6324+ LOGE("%s() AT error %d on at_open", __func__, ret);
6325+ at_close();
6326+ continue;
6327+ }
6328+
6329+ at_set_on_reader_closed(onATReaderClosed);
6330+ at_set_on_timeout(onATTimeout);
6331+
6332+ q = &s_requestQueue;
6333+
6334+ if (initializeCommon()) {
6335+ LOGE("%s() Failed to initialize channel!", __func__);
6336+ at_close();
6337+ continue;
6338+ }
6339+
6340+ q->closed = 0;
6341+ if (initializeChannel()) {
6342+ LOGE("%s() Failed to initialize channel!", __func__);
6343+ at_close();
6344+ continue;
6345+ }
6346+
6347+ at_make_default_channel();
6348+
6349+ LOGE("%s() Looping the requestQueue!", __func__);
6350+ for (;;) {
6351+ RILRequest *r;
6352+ RILEvent *e;
6353+ struct timespec ts;
6354+ int err;
6355+
6356+ memset(&ts, 0, sizeof(ts));
6357+
6358+ if ((err = pthread_mutex_lock(&q->queueMutex)) != 0)
6359+ LOGE("%s() failed to take queue mutex: %s!",
6360+ __func__, strerror(err));
6361+
6362+ if (q->closed != 0) {
6363+ LOGW("%s() AT Channel error, attempting to recover..", __func__);
6364+ if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
6365+ LOGE("Failed to release queue mutex: %s!", strerror(err));
6366+ break;
6367+ }
6368+
6369+ while (q->closed == 0 && q->requestList == NULL &&
6370+ q->eventList == NULL) {
6371+ if ((err = pthread_cond_wait(&q->cond, &q->queueMutex)) != 0)
6372+ LOGE("%s() failed broadcast queue cond: %s!",
6373+ __func__, strerror(err));
6374+ }
6375+
6376+ /* eventList is prioritized, smallest abstime first. */
6377+ if (q->closed == 0 && q->requestList == NULL && q->eventList) {
6378+ int err = 0;
6379+ err = pthread_cond_timedwait(&q->cond, &q->queueMutex, &q->eventList->abstime);
6380+ if (err && err != ETIMEDOUT)
6381+ LOGE("%s() timedwait returned unexpected error: %s",
6382+ __func__, strerror(err));
6383+ }
6384+
6385+ if (q->closed != 0) {
6386+ if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
6387+ LOGE("%s(): Failed to release queue mutex: %s!",
6388+ __func__, strerror(err));
6389+ continue; /* Catch the closed bit at the top of the loop. */
6390+ }
6391+
6392+ e = NULL;
6393+ r = NULL;
6394+
6395+ clock_gettime(CLOCK_MONOTONIC, &ts);
6396+
6397+ if (q->eventList != NULL &&
6398+ timespec_cmp(q->eventList->abstime, ts, < )) {
6399+ e = q->eventList;
6400+ q->eventList = e->next;
6401+ }
6402+
6403+ if (q->requestList != NULL) {
6404+ r = q->requestList;
6405+ q->requestList = r->next;
6406+ }
6407+
6408+ if ((err = pthread_mutex_unlock(&q->queueMutex)) != 0)
6409+ LOGE("%s(): Failed to release queue mutex: %s!",
6410+ __func__, strerror(err));
6411+
6412+ if (e) {
6413+ e->eventCallback(e->param);
6414+ free(e);
6415+ }
6416+
6417+ if (r) {
6418+ processRequest(r->request, r->data, r->datalen, r->token);
6419+ freeRequestData(r->request, r->data, r->datalen);
6420+ free(r);
6421+ }
6422+ }
6423+
6424+ at_close();
6425+ LOGE("%s() Re-opening after close", __func__);
6426+ }
6427+ return NULL;
6428+}
6429+
6430+#ifdef RIL_SHLIB
6431+const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc,
6432+ char **argv)
6433+{
6434+ int opt;
6435+ int port = -1;
6436+ char *loophost = NULL;
6437+ const char *device_path = NULL;
6438+ struct queueArgs *queueArgs;
6439+ pthread_attr_t attr;
6440+
6441+ s_rilenv = env;
6442+
6443+ /* By default, use USB1 as audio channel */
6444+ strcpy(sAudioDevice,"/dev/ttyUSB1");
6445+
6446+ D("%s() entering...", __func__);
6447+
6448+ while (-1 != (opt = getopt(argc, argv, "z:p:d:v:"))) {
6449+ switch (opt) {
6450+ case 'z':
6451+ loophost = optarg;
6452+ D("%s() Using loopback host %s..", __func__, loophost);
6453+ break;
6454+
6455+ case 'p':
6456+ port = atoi(optarg);
6457+ if (port == 0) {
6458+ usage(argv[0]);
6459+ return NULL;
6460+ }
6461+ D("%s() Opening loopback port %d", __func__, port);
6462+ break;
6463+
6464+ case 'd':
6465+ device_path = optarg;
6466+ D("%s() Opening tty device %s", __func__, device_path);
6467+ break;
6468+
6469+ case 'v':
6470+ strcpy(sAudioDevice,optarg);
6471+ D("%s() Opening voice tty device %s", __func__, sAudioDevice);
6472+ break;
6473+
6474+ default:
6475+ usage(argv[0]);
6476+ return NULL;
6477+ }
6478+ }
6479+
6480+ if (port < 0 && device_path == NULL) {
6481+ usage(argv[0]);
6482+ return NULL;
6483+ }
6484+
6485+ queueArgs = (struct queueArgs*) malloc(sizeof(struct queueArgs));
6486+ memset(queueArgs, 0, sizeof(struct queueArgs));
6487+
6488+ queueArgs->device_path = device_path;
6489+ queueArgs->port = port;
6490+ queueArgs->loophost = loophost;
6491+
6492+ pthread_attr_init(&attr);
6493+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
6494+
6495+ pthread_create(&s_tid_queueRunner, &attr, queueRunner, queueArgs);
6496+
6497+ return &s_callbacks;
6498+}
6499+
6500+#else /* RIL_SHLIB */
6501+int main (int argc, char **argv)
6502+{
6503+ int opt;
6504+ int port = -1;
6505+ char *loophost = NULL;
6506+ const char *device_path = NULL;
6507+ struct queueArgs *queueArgs;
6508+
6509+ /* By default, use USB1 as audio channel */
6510+ strcpy(sAudioDevice,"/dev/ttyUSB1");
6511+
6512+ D("%s() entering...", __func__);
6513+
6514+ while (-1 != (opt = getopt(argc, argv, "z:p:d:v:"))) {
6515+ switch (opt) {
6516+ case 'z':
6517+ loophost = optarg;
6518+ D("%s() Using loopback host %s..", __func__, loophost);
6519+ break;
6520+
6521+ case 'p':
6522+ port = atoi(optarg);
6523+ if (port == 0) {
6524+ usage(argv[0]);
6525+ return 0;
6526+ }
6527+ D("%s() Opening loopback port %d", __func__, port);
6528+ break;
6529+
6530+ case 'd':
6531+ device_path = optarg;
6532+ D("%s() Opening tty device %s", __func__, device_path);
6533+ break;
6534+
6535+ case 'v':
6536+ strcpy(sAudioDevice,optarg);
6537+ D("%s() Opening voice tty device %s", __func__, sAudioDevice);
6538+ break;
6539+
6540+ default:
6541+ usage(argv[0]);
6542+ return 0;
6543+ }
6544+ }
6545+
6546+ if (port < 0 && device_path == NULL) {
6547+ usage(argv[0]);
6548+ return 0;
6549+ }
6550+
6551+ queueArgs = (struct queueArgs*) malloc(sizeof(struct queueArgs));
6552+ memset(queueArgs, 0, sizeof(struct queueArgs));
6553+
6554+ queueArgs->device_path = device_path;
6555+ queueArgs->port = port;
6556+ queueArgs->loophost = loophost;
6557+
6558+ RIL_register(&s_callbacks);
6559+
6560+ queueRunner(queueArgs);
6561+
6562+ return 0;
6563+}
6564+#endif
--- /dev/null
+++ b/huaweigeneric-ril/misc.c
@@ -0,0 +1,169 @@
1+/*
2+**
3+** Copyright 2006, The Android Open Source Project
4+**
5+** Licensed under the Apache License, Version 2.0 (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** http://www.apache.org/licenses/LICENSE-2.0
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+*/
17+
18+#include <string.h>
19+#include <errno.h>
20+
21+#include "misc.h"
22+
23+/** Returns 1 if line starts with prefix, 0 if it does not. */
24+int strStartsWith(const char *line, const char *prefix)
25+{
26+ for (; *line != '\0' && *prefix != '\0'; line++, prefix++)
27+ if (*line != *prefix)
28+ return 0;
29+
30+ return *prefix == '\0';
31+}
32+
33+/**
34+ * Very simple function that extract and returns whats between ElementBeginTag
35+ * and ElementEndTag.
36+ *
37+ * Optional ppszRemainingDocument that can return a pointer to the remaining
38+ * of the document to be "scanned". This can be used if subsequent
39+ * scanning/searching is desired.
40+ *
41+ * This function is used to extract the parameters from the XML result
42+ * returned by U3xx during a PDP Context setup, and used to parse the
43+ * tuples of operators returned from AT+COPS.
44+ *
45+ * const char* document - Document to be scanned
46+ * const char* elementBeginTag - Begin tag to scan for, return whats
47+ * between begin/end tags
48+ * const char* elementEndTag - End tag to scan for, return whats
49+ * between begin/end tags
50+ * char** remainingDocumen t - Can return the a pointer to the remaining
51+ * of pszDocument, this parameter is optional
52+ *
53+ * return char* containing whats between begin/end tags, allocated on the
54+ * heap, need to free this.
55+ * return NULL if nothing is found.
56+ */
57+char *getFirstElementValue(const char* document,
58+ const char* elementBeginTag,
59+ const char* elementEndTag,
60+ char** remainingDocument)
61+{
62+ char* value = NULL;
63+ char* start = NULL;
64+ char* end = NULL;
65+
66+ if (document != NULL && elementBeginTag != NULL && elementEndTag != NULL) {
67+ start = strstr(document, elementBeginTag);
68+ if (start != NULL) {
69+ end = strstr(start, elementEndTag);
70+ if (end != NULL) {
71+ int n = strlen(elementBeginTag);
72+ int m = end - (start + n);
73+ value = (char*) malloc((m + 1) * sizeof(char));
74+ strncpy(value, (start + n), m);
75+ value[m] = (char) 0;
76+
77+ /* Optional, return a pointer to the remaining document,
78+ to be used when document contains many tags with same name. */
79+ if (remainingDocument != NULL)
80+ *remainingDocument = end + strlen(elementEndTag);
81+ }
82+ }
83+ }
84+ return value;
85+}
86+
87+char char2nib(char c)
88+{
89+ if (c >= 0x30 && c <= 0x39)
90+ return c - 0x30;
91+
92+ if (c >= 0x41 && c <= 0x46)
93+ return c - 0x41 + 0xA;
94+
95+ if (c >= 0x61 && c <= 0x66)
96+ return c - 0x61 + 0xA;
97+
98+ return 0;
99+}
100+
101+int stringToBinary(/*in*/ const char *string,
102+ /*in*/ size_t len,
103+ /*out*/ unsigned char *binary)
104+{
105+ int pos;
106+ const char *it;
107+ const char *end = &string[len];
108+
109+ if (end < string)
110+ return -EINVAL;
111+
112+ if (len & 1)
113+ return -EINVAL;
114+
115+ for (pos = 0, it = string; it != end; ++pos, it += 2) {
116+ binary[pos] = char2nib(it[0]) << 4 | char2nib(it[1]);
117+ }
118+ return 0;
119+}
120+
121+int binaryToString(/*in*/ const unsigned char *binary,
122+ /*in*/ size_t len,
123+ /*out*/ char *string)
124+{
125+ int pos;
126+ const unsigned char *it;
127+ const unsigned char *end = &binary[len];
128+ static const char nibbles[] =
129+ {'0', '1', '2', '3', '4', '5', '6', '7',
130+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
131+
132+ if (end < binary)
133+ return -EINVAL;
134+
135+ for (pos = 0, it = binary; it != end; ++it, pos += 2) {
136+ string[pos + 0] = nibbles[*it >> 4];
137+ string[pos + 1] = nibbles[*it & 0x0f];
138+ }
139+ string[pos] = 0;
140+ return 0;
141+}
142+
143+int parseTlv(/*in*/ const char *stream,
144+ /*in*/ const char *end,
145+ /*out*/ struct tlv *tlv)
146+{
147+#define TLV_STREAM_GET(stream, end, p) \
148+ do { \
149+ if (stream + 1 >= end) \
150+ goto underflow; \
151+ p = ((unsigned)char2nib(stream[0]) << 4) \
152+ | ((unsigned)char2nib(stream[1]) << 0); \
153+ stream += 2; \
154+ } while (0)
155+
156+ size_t size;
157+
158+ TLV_STREAM_GET(stream, end, tlv->tag);
159+ TLV_STREAM_GET(stream, end, size);
160+ if (stream + size * 2 > end)
161+ goto underflow;
162+ tlv->data = &stream[0];
163+ tlv->end = &stream[size * 2];
164+ return 0;
165+
166+underflow:
167+ return -EINVAL;
168+#undef TLV_STREAM_GET
169+}
--- /dev/null
+++ b/huaweigeneric-ril/misc.h
@@ -0,0 +1,53 @@
1+/* //device/system/reference-ril/misc.h
2+**
3+** Copyright 2006, The Android Open Source Project
4+**
5+** Licensed under the Apache License, Version 2.0 (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** http://www.apache.org/licenses/LICENSE-2.0
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+*/
17+
18+#ifndef _MISC_H
19+#define _MISC_H 1
20+
21+struct tlv {
22+ unsigned tag;
23+ const char *data;
24+ const char *end;
25+};
26+
27+/** Returns 1 if line starts with prefix, 0 if it does not. */
28+int strStartsWith(const char *line, const char *prefix);
29+
30+char *getFirstElementValue(const char* document,
31+ const char* elementBeginTag,
32+ const char* elementEndTag,
33+ char** remainingDocument);
34+
35+char char2nib(char c);
36+
37+int stringToBinary(/*in*/ const char *string,
38+ /*in*/ size_t len,
39+ /*out*/ unsigned char *binary);
40+
41+int binaryToString(/*in*/ const unsigned char *binary,
42+ /*in*/ size_t len,
43+ /*out*/ char *string);
44+
45+int parseTlv(/*in*/ const char *stream,
46+ /*in*/ const char *end,
47+ /*out*/ struct tlv *tlv);
48+#define TLV_DATA(tlv, pos) (((unsigned)char2nib(tlv.data[(pos) * 2 + 0]) << 4) | \
49+ ((unsigned)char2nib(tlv.data[(pos) * 2 + 1]) << 0))
50+
51+#define NUM_ELEMS(x) (sizeof(x) / sizeof(x[0]))
52+
53+#endif
--- /dev/null
+++ b/huaweigeneric-ril/requestdatahandler.c
@@ -0,0 +1,340 @@
1+/*
2+**
3+** Copyright (C) ST-Ericsson AB 2008-2009
4+** Copyright 2006, The Android Open Source Project
5+**
6+** Licensed under the Apache License, Version 2.0 (the "License");
7+** you may not use this file except in compliance with the License.
8+** You may obtain a copy of the License at
9+**
10+** http://www.apache.org/licenses/LICENSE-2.0
11+**
12+** Unless required by applicable law or agreed to in writing, software
13+** distributed under the License is distributed on an "AS IS" BASIS,
14+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+** See the License for the specific language governing permissions and
16+** limitations under the License.
17+**
18+** Based on the Android ril daemon and reference RIL by
19+** The Android Open Source Project.
20+**
21+** Heavily modified for ST-Ericsson U300 modems.
22+** Author: Christian Bejram <christian.bejram@stericsson.com>
23+*/
24+
25+#include <stdlib.h>
26+#include <telephony/ril.h>
27+#include <assert.h>
28+
29+#define LOG_TAG "RIL"
30+#include <utils/Log.h>
31+
32+/* Handler functions. The names are because we cheat by including
33+ * ril_commands.h from rild. In here we generate local allocations
34+ * of the data representations, as well as free:ing them after
35+ * they've been handled.
36+ *
37+ * This design might not be ideal, but considering the alternatives,
38+ * it's good enough.
39+ */
40+static void *dummyDispatch(void *data, size_t datalen);
41+
42+#define dispatchCdmaSms dummyDispatch
43+#define dispatchCdmaSmsAck dummyDispatch
44+#define dispatchCdmaBrSmsCnf dummyDispatch
45+#define dispatchRilCdmaSmsWriteArgs dummyDispatch
46+
47+static void *dispatchCallForward(void *data, size_t datalen);
48+static void *dispatchDial(void *data, size_t datalen);
49+static void *dispatchSIM_IO(void *data, size_t datalen);
50+static void *dispatchSmsWrite(void *data, size_t datalen);
51+static void *dispatchString(void *data, size_t datalen);
52+static void *dispatchStrings(void *data, size_t datalen);
53+static void *dispatchRaw(void *data, size_t datalen);
54+static void *dispatchVoid(void *data, size_t datalen);
55+static void *dispatchGsmBrSmsCnf(void *data, size_t datalen);
56+
57+#define dispatchInts dispatchRaw
58+
59+static void dummyResponse(void);
60+
61+#define responseCallForwards dummyResponse
62+#define responseCallList dummyResponse
63+#define responseCellList dummyResponse
64+#define responseContexts dummyResponse
65+#define responseInts dummyResponse
66+#define responseRaw dummyResponse
67+#define responseSIM_IO dummyResponse
68+#define responseSMS dummyResponse
69+#define responseString dummyResponse
70+#define responseStrings dummyResponse
71+#define responseVoid dummyResponse
72+
73+#define responseSimStatus dummyResponse
74+#define responseRilSignalStrength dummyResponse
75+#define responseDataCallList dummyResponse
76+#define responseGsmBrSmsCnf dummyResponse
77+#define responseCdmaBrSmsCnf dummyResponse
78+
79+#define dispatchDataCall dispatchStrings
80+#define responseSetupDataCall responseStrings
81+
82+/*
83+should be looked into how dispatchDataCall and others really should be handled,
84+not just use dispatchStrings but it seems to work. This feature
85+was added in android 3.0, might be just be a nicer way handling
86+things seperatly. This has no impact on older versions and should
87+work as it is on both (hence we can't really remove code from
88+dispatchStrings if it should be in distpatchDataCall).
89+
90+static void *dispatchDataCall(void *data, size_t datalen){
91+...
92+} */
93+
94+typedef struct CommandInfo {
95+ int requestId;
96+ void *(*dispatchFunction) (void *data, size_t datalen);
97+ void (*responseFunction) (void);
98+} CommandInfo;
99+
100+/* RILD made me do it! */
101+static CommandInfo s_commandInfo[] = {
102+#include <ril_commands.h>
103+};
104+
105+static void *dummyDispatch(void *data, size_t datalen)
106+{
107+ (void) data; (void) datalen;
108+ return 0;
109+}
110+
111+static void dummyResponse(void)
112+{
113+ return;
114+}
115+
116+/**
117+ * dupRequestData will copy the data pointed to by *data, returning a pointer
118+ * to a freshly allocated representation of the data.
119+ */
120+void *dupRequestData(int requestId, void *data, size_t datalen)
121+{
122+ CommandInfo *ci = &s_commandInfo[requestId];
123+
124+ return ci->dispatchFunction(data, datalen);
125+}
126+
127+static void *dispatchCallForward(void *data, size_t datalen)
128+{
129+ RIL_CallForwardInfo *ret = dispatchRaw(data, datalen);
130+
131+ if (ret->number)
132+ ret->number = strdup(ret->number);
133+
134+ return ret;
135+}
136+
137+static void *dispatchDial(void *data, size_t datalen)
138+{
139+ RIL_Dial *ret = dispatchRaw(data, datalen);
140+
141+ if (ret->address)
142+ ret->address = strdup(ret->address);
143+
144+ return ret;
145+}
146+
147+static void *dispatchSIM_IO(void *data, size_t datalen)
148+{
149+ RIL_SIM_IO_v6 *ret = dispatchRaw(data, datalen);
150+
151+ if (ret->path)
152+ ret->path = strdup(ret->path);
153+ if (ret->data)
154+ ret->data = strdup(ret->data);
155+ if (ret->pin2)
156+ ret->pin2 = strdup(ret->pin2);
157+ if (ret->aidPtr)
158+ ret->aidPtr = strdup(ret->aidPtr);
159+
160+ return ret;
161+}
162+
163+static void *dispatchSmsWrite(void *data, size_t datalen)
164+{
165+ RIL_SMS_WriteArgs *ret = dispatchRaw(data, datalen);
166+
167+ if (ret->pdu)
168+ ret->pdu = strdup(ret->pdu);
169+
170+ if (ret->smsc)
171+ ret->smsc = strdup(ret->smsc);
172+
173+ return ret;
174+}
175+
176+static void *dispatchString(void *data, size_t datalen)
177+{
178+ (void) data; (void) datalen;
179+ assert(datalen == sizeof(char *));
180+
181+ if (data)
182+ return strdup((char *) data);
183+
184+ return NULL;
185+}
186+
187+static void *dispatchStrings(void *data, size_t datalen)
188+{
189+ char **a = (char **)data;
190+ char **ret;
191+ int strCount = datalen / sizeof(char *);
192+ int i;
193+
194+ assert((datalen % sizeof(char *)) == 0);
195+
196+ ret = malloc(strCount * sizeof(char *));
197+ memset(ret, 0, sizeof(char *) * strCount);
198+
199+ for (i = 0; i < strCount; i++) {
200+ if (a[i])
201+ ret[i] = strdup(a[i]);
202+ }
203+
204+ return (void *) ret;
205+}
206+
207+static void *dispatchGsmBrSmsCnf(void *data, size_t datalen)
208+{
209+ RIL_GSM_BroadcastSmsConfigInfo **a =
210+ (RIL_GSM_BroadcastSmsConfigInfo **) data;
211+ int count;
212+ void **ret;
213+ int i;
214+
215+ count = datalen / sizeof(RIL_GSM_BroadcastSmsConfigInfo *);
216+
217+ ret = malloc(count * sizeof(RIL_GSM_BroadcastSmsConfigInfo *));
218+ memset(ret, 0, sizeof(*ret));
219+
220+ for (i = 0; i < count; i++) {
221+ if (a[i])
222+ ret[i] = dispatchRaw(a[i], sizeof(RIL_GSM_BroadcastSmsConfigInfo));
223+ }
224+
225+ return ret;
226+}
227+
228+static void *dispatchRaw(void *data, size_t datalen)
229+{
230+ void *ret = malloc(datalen);
231+ memcpy(ret, data, datalen);
232+
233+ return (void *) ret;
234+}
235+
236+static void *dispatchVoid(void *data, size_t datalen)
237+{
238+ (void) data; (void) datalen;
239+ return NULL;
240+}
241+
242+static void freeDial(void *data)
243+{
244+ RIL_Dial *d = data;
245+
246+ if (d->address)
247+ free(d->address);
248+
249+ free(d);
250+}
251+
252+static void freeStrings(void *data, size_t datalen)
253+{
254+ int count = datalen / sizeof(char *);
255+ int i;
256+
257+ for (i = 0; i < count; i++) {
258+ if (((char **) data)[i])
259+ free(((char **) data)[i]);
260+ }
261+
262+ free(data);
263+}
264+
265+static void freeGsmBrSmsCnf(void *data, size_t datalen)
266+{
267+ int count = datalen / sizeof(RIL_GSM_BroadcastSmsConfigInfo);
268+ int i;
269+
270+ for (i = 0; i < count; i++) {
271+ if (((RIL_GSM_BroadcastSmsConfigInfo **) data)[i])
272+ free(((RIL_GSM_BroadcastSmsConfigInfo **) data)[i]);
273+ }
274+
275+ free(data);
276+}
277+
278+static void freeSIM_IO(void *data)
279+{
280+ RIL_SIM_IO_v6 *sio = data;
281+
282+ if (sio->path)
283+ free(sio->path);
284+ if (sio->data)
285+ free(sio->data);
286+ if (sio->pin2)
287+ free(sio->pin2);
288+ if (sio->aidPtr)
289+ free(sio->aidPtr);
290+
291+ free(sio);
292+}
293+
294+static void freeSmsWrite(void *data)
295+{
296+ RIL_SMS_WriteArgs *args = data;
297+
298+ if (args->pdu)
299+ free(args->pdu);
300+
301+ if (args->smsc)
302+ free(args->smsc);
303+
304+ free(args);
305+}
306+
307+static void freeCallForward(void *data)
308+{
309+ RIL_CallForwardInfo *cff = data;
310+
311+ if (cff->number)
312+ free(cff->number);
313+
314+ free(cff);
315+}
316+
317+void freeRequestData(int requestId, void *data, size_t datalen)
318+{
319+ CommandInfo *ci = &s_commandInfo[requestId];
320+
321+ if (ci->dispatchFunction == dispatchInts ||
322+ ci->dispatchFunction == dispatchRaw ||
323+ ci->dispatchFunction == dispatchString) {
324+ if (data)
325+ free(data);
326+ } else if (ci->dispatchFunction == dispatchStrings) {
327+ freeStrings(data, datalen);
328+ } else if (ci->dispatchFunction == dispatchSIM_IO) {
329+ freeSIM_IO(data);
330+ } else if (ci->dispatchFunction == dispatchDial) {
331+ freeDial(data);
332+ } else if (ci->dispatchFunction == dispatchVoid) {
333+ } else if (ci->dispatchFunction == dispatchCallForward) {
334+ freeCallForward(data);
335+ } else if (ci->dispatchFunction == dispatchSmsWrite) {
336+ freeSmsWrite(data);
337+ } else if (ci->dispatchFunction == dispatchGsmBrSmsCnf) {
338+ freeGsmBrSmsCnf(data, datalen);
339+ }
340+}
--- /dev/null
+++ b/huaweigeneric-ril/requestdatahandler.h
@@ -0,0 +1,25 @@
1+/*
2+**
3+** Copyright (C) ST-Ericsson AB 2009
4+**
5+** Licensed under the Apache License, Version 2.0 (the "License");
6+** you may not use this file except in compliance with the License.
7+** You may obtain a copy of the License at
8+**
9+** http://www.apache.org/licenses/LICENSE-2.0
10+**
11+** Unless required by applicable law or agreed to in writing, software
12+** distributed under the License is distributed on an "AS IS" BASIS,
13+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+** See the License for the specific language governing permissions and
15+** limitations under the License.
16+**
17+** Author: Christian Bejram <christian.bejram@stericsson.com>
18+*/
19+#ifndef _REQUESTDATAHANDLER_H
20+#define _REQUESTDATAHANDLER_H 1
21+
22+void *dupRequestData(int requestId, void *data, size_t datalen);
23+void freeRequestData(int requestId, void *data, size_t datalen);
24+
25+#endif
--- /dev/null
+++ b/huaweigeneric-ril/sms.c
@@ -0,0 +1,285 @@
1+//
2+// Convert CDMA SMS to GSM and vice versa.
3+// By Martin Johnson <M.J.Johnson@massey.ac.nz>
4+// GPL
5+//
6+#include <stdio.h>
7+#include <string.h>
8+#include "sms_gsm.h"
9+
10+#ifndef nodroid
11+#define LOG_TAG "SMS_RIL"
12+#include <utils/Log.h>
13+#else
14+#define LOGD printf
15+#define LOGE printf
16+#define LOGI printf
17+#endif
18+
19+int hex2int(char c)
20+{
21+ if (c>'9') return c-'A'+10;
22+ return c-'0';
23+}
24+
25+int getbit(char *s,int b)
26+{
27+ int byte=b/4;
28+ int bit=b%4;
29+
30+ int data=hex2int(s[byte]);
31+ if (data&(1<<(3-bit))) return 1;
32+ else return 0;
33+}
34+
35+const char hextable[17]="0123456789ABCDEF";
36+
37+void setbit(char *s,int b, int val)
38+{
39+ int byte=b/4;
40+ int bit=b%4;
41+
42+ s[byte]=hextable[hex2int(s[byte]) | (val<<(3-bit))] ;
43+}
44+
45+int getbits(char *s,int startbit,int nbits)
46+{
47+ int val=0;
48+ int i;
49+
50+ for (i=0;i<nbits;i++)
51+ val = val | (getbit(s,startbit+i)<<(nbits-i-1));
52+ return val;
53+}
54+
55+void setbits(char *s,int startbit,int nbits,int val)
56+{
57+ int i;
58+
59+ for (i=0;i<nbits;i++)
60+ setbit(s,startbit+i,(val>>(nbits-i-1))&1);
61+}
62+
63+const char decode_table[17]=".1234567890*#...";
64+
65+void decode_number(char *msg, int length, char *no)
66+{
67+
68+ int ndigits=getbits(msg,2,8);
69+ int j,digit;
70+
71+ for (j=0;j<ndigits;j++)
72+ *no++=decode_table[getbits(msg,10+j*4,4)];
73+ *no=0;
74+}
75+
76+int encode_digit(int d)
77+{
78+ int i;
79+ for (i=0;i<16;i++)
80+ if (decode_table[i]==d)
81+ return i;
82+ return 0;
83+}
84+
85+int encode_number(char *msg, char *no)
86+{
87+ unsigned int i;
88+ int digit;
89+
90+ setbits(msg, 0, 2, 0);
91+ setbits(msg, 2, 8, strlen(no));
92+ for (i=0;i<strlen(no);i++)
93+ setbits(msg,10+i*4, 4, encode_digit(no[i]));
94+ return (10+i*4+7)/8;
95+}
96+
97+void get_code_and_length(char *msg, int *code, int *length)
98+{
99+ *code=hex2int(msg[0])*16+hex2int(msg[1]);
100+ *length=hex2int(msg[2])*16+hex2int(msg[3]);
101+}
102+
103+void decode_bearer_data(char *msg, int length, char *message, int *is_vm)
104+{
105+ int i=0,j;
106+ int code,sublength;
107+
108+ while (i<length) {
109+ get_code_and_length(msg+i*2,&code,&sublength);
110+ if (code==1) {
111+ int encoding=getbits(msg+i*2+4,0,5);
112+ int nchars=getbits(msg+i*2+4,5,8);
113+ if (encoding==2 || encoding==3) {
114+ for (j=0;j<nchars;j++)
115+ *message++=getbits(msg+i*2+4,13+7*j,7);
116+ } else if (encoding==8 || encoding==0) {
117+ for (j=0;j<nchars;j++)
118+ *message++=getbits(msg+i*2+4,13+8*j,8);
119+ } else if (encoding==4) {
120+ for (j=0;j<nchars;j++)
121+ *message++=getbits(msg+i*2+6,13+16*j,8);
122+ } else {
123+ strcpy(message,"bad SMS encoding");
124+ LOGE("Bad encoding: %d",encoding);
125+ message+=16;
126+ }
127+ *message=0;
128+ } else if (code == 11 && sublength == 1) {
129+ int msgs;
130+ if (is_vm) {
131+ *is_vm = 1;
132+ msgs = hex2int(msg[i*2+4])+16*hex2int(msg[i*2+5]);
133+ if (msgs)
134+ *is_vm |= 0x10;
135+ }
136+ }
137+ i+=sublength+2;
138+ }
139+}
140+
141+int encode_bearer_data(char *msg, char *data)
142+{
143+ int msgid=0;
144+ unsigned int i;
145+ int b;
146+ char *start=msg;
147+
148+ for (i=0;i<strlen(data);i++)
149+ msgid+=data[i];
150+
151+ setbits(msg,0,8,0); // message id
152+ setbits(msg,8,8,3); // 3 bytes
153+ setbits(msg,16,4,2); // 2 means send
154+ setbits(msg,20,16,msgid); // use message sum for id
155+ msg+=10;
156+ setbits(msg,0,8,01); // user data
157+ setbits(msg,16,5,02); // set encoding
158+ setbits(msg,21,8,strlen(data)); // length
159+ b=29;
160+ for (i=0;i<strlen(data);i++) {
161+ setbits(msg,b,7,data[i]);
162+ b=b+7;
163+ }
164+ setbits(msg,8,8,(b+7)/8-2);
165+ msg=msg+2*((b+7)/8);
166+ setbits(msg,0,24,0x80100);
167+ setbits(msg,24,24,0x0D0100);
168+ msg=msg+12;
169+ return (msg-start)/2;
170+}
171+
172+void decode_cdma_sms(char *pdu, char *from, char *message, int *is_vm)
173+{
174+ unsigned int i=1;
175+ int code,length;
176+ strcpy(from,"000000"); // in case something fails
177+ strcpy(message,"UNKNOWN");
178+
179+ if (is_vm)
180+ *is_vm = 0;
181+
182+ while (i*2<strlen(pdu)) {
183+ get_code_and_length(pdu+i*2,&code,&length);
184+ if (code==2) // from
185+ decode_number(pdu+i*2+4,length,from);
186+ if (code==8) // bearer_data
187+ decode_bearer_data(pdu+i*2+4,length,message,is_vm);
188+ i+=length+2;
189+ }
190+}
191+
192+void encode_cdma_sms(char *pdu, char *to, char *message)
193+{
194+ int length;
195+
196+ LOGE_IF(strlen(message)>160, "Error: Message String too long");
197+ memset(pdu, '0', 512);
198+ setbits(pdu,0,16,0);
199+ setbits(pdu,16,24,0x021002);
200+ pdu=pdu+10;
201+ setbits(pdu,0,8,0x04);
202+ length=encode_number(pdu+4, to);
203+ setbits(pdu,8,8,length);
204+ pdu=pdu+length*2+4;
205+ setbits(pdu,0,24,0x060100);
206+ pdu=pdu+6;
207+ setbits(pdu,0,8,0x08);
208+ length=encode_bearer_data(pdu+4, message);
209+ LOGE_IF(length>255, "Error: Message Hex too long");
210+ setbits(pdu,8,8,length);
211+ pdu=pdu+length*2+4;
212+ *pdu=0;
213+}
214+
215+char **cdma_to_gsmpdu(char *msg)
216+{
217+ char from[256];
218+ char message[256];
219+ static char hexpdu[1024];
220+ static char *hexpdus[16];
221+ int i=0;
222+ int is_vm=0;
223+ decode_cdma_sms(msg,from,message,&is_vm);
224+ // if(strlen(message)>=160) message[159]=0;
225+ LOGD("CDMA Message:%s From:%s\n",message,from);
226+ SmsAddressRec smsaddr;
227+ SmsTimeStampRec smstime;
228+ if (is_vm) {
229+ /* voicemail notifications must have a 4 byte address */
230+ if (is_vm & 0x10) {
231+ /* set message waiting indicator */
232+ strcpy(from, "1100");
233+ } else {
234+ /* clear message waiting indicator */
235+ strcpy(from, "0100");
236+ }
237+ }
238+ sms_address_from_str(&smsaddr,from,strlen(from));
239+ if (is_vm) {
240+ /* voicemail notifications have a clear bottom nibble in toa
241+ * and an alphanumeric address type */
242+ smsaddr.toa = 0xd0;
243+ }
244+ sms_timestamp_now(&smstime);
245+ SmsPDU *pdu=smspdu_create_deliver_utf8((const unsigned char *)message,strlen(message),&smsaddr,&smstime);
246+ //hexpdu=malloc(512);
247+ char *s=hexpdu;
248+ while (*pdu) {
249+ smspdu_to_hex(*pdu, s,512);
250+ hexpdus[i]=s;
251+ s=s+strlen(s)+2;
252+ smspdu_free(*pdu);
253+ i++;
254+ pdu++;
255+ }
256+ hexpdus[i]=0;
257+ return hexpdus;
258+}
259+
260+char *gsm_to_cdmapdu(char *msg)
261+{
262+ char to[256];
263+ char message[256];
264+ static char hexpdu[512];
265+ SmsAddressRec smsaddr;
266+ sms_address_from_str(&smsaddr,"000000",6);
267+
268+ SmsPDU pdu=smspdu_create_from_hex( msg, strlen(msg) );
269+ if (smspdu_get_receiver_address(pdu,&smsaddr)<0) {
270+ LOGE("Error: no receiver address");
271+ smspdu_get_sender_address(pdu,&smsaddr);
272+ }
273+ sms_address_to_str(&smsaddr,to,256);
274+ if (to[0]=='+') { // convert + to 00 otherwise international sms doesn't work
275+ memmove(to+1,to,255);
276+ to[0]='0';
277+ to[1]='0';
278+ }
279+ int length=smspdu_get_text_message(pdu, message, 256);
280+ message[length]=0;
281+ smspdu_free(pdu);
282+ LOGD("GSM Message:%s To:%s\n",message,to);
283+ encode_cdma_sms(hexpdu,to,message);
284+ return hexpdu;
285+}
--- /dev/null
+++ b/huaweigeneric-ril/sms_gsm.c
@@ -0,0 +1,1099 @@
1+#include "sms_gsm.h"
2+#include "gsm.h"
3+#include <memory.h>
4+#include <stdlib.h>
5+//#include <assert.h>
6+
7+/* maximum number of data bytes in a SMS data message */
8+#define MAX_USER_DATA_BYTES 140
9+
10+/* maximum number of 7-bit septets in a SMS text message */
11+#define MAX_USER_DATA_SEPTETS 160
12+
13+/* size of the user data header in bytes */
14+#define USER_DATA_HEADER_SIZE 6
15+
16+/** MESSAGE TEXT
17+ **/
18+int
19+sms_utf8_from_message_str( const char* str, int strlen, unsigned char* utf8, int utf8len )
20+{
21+ const char* p = str;
22+ const char* end = p + strlen;
23+ int count = 0;
24+ int escaped = 0;
25+
26+ while (p < end) {
27+ int c = p[0];
28+
29+ /* read the value from the string */
30+ p += 1;
31+ if (c >= 128) {
32+ if ((c & 0xe0) == 0xc0)
33+ c &= 0x1f;
34+ else if ((c & 0xf0) == 0xe0)
35+ c &= 0x0f;
36+ else
37+ c &= 0x07;
38+ p++;
39+ while (p < end && (p[0] & 0xc0) == 0x80) {
40+ c = (c << 6) | (p[0] & 0x3f);
41+ p++;
42+ }
43+ }
44+ if (escaped) {
45+ switch (c) {
46+ case '\\':
47+ break;
48+ case 'n': /* \n is line feed */
49+ c = 10;
50+ break;
51+
52+ case 'x': /* \xNN, where NN is a 2-digit hexadecimal value */
53+ if (p+2 > end)
54+ return -1;
55+ c = gsm_hex2_to_byte( p );
56+ if (c < 0)
57+ return -1;
58+ break;
59+
60+ case 'u': /* \uNNNN where NNNN is a 4-digiti hexadecimal value */
61+ if (p + 4 > end)
62+ return -1;
63+ c = gsm_hex4_to_short( p );
64+ if (c < 0)
65+ return -1;
66+ break;
67+
68+ default: /* invalid escape, return -1 */
69+ return -1;
70+ }
71+ escaped = 0;
72+ } else if (c == '\\') {
73+ escaped = 1;
74+ continue;
75+ }
76+
77+ /* now, try to write it to the destination */
78+ if (c < 128) {
79+ if (count < utf8len)
80+ utf8[count] = (byte_t) c;
81+ count += 1;
82+ } else if (c < 0x800) {
83+ if (count < utf8len)
84+ utf8[count] = (byte_t)(0xc0 | ((c >> 6) & 0x1f));
85+ if (count+1 < utf8len)
86+ utf8[count+1] = (byte_t)(0x80 | (c & 0x3f));
87+ count += 2;
88+ } else {
89+ if (count < utf8len)
90+ utf8[count] = (byte_t)(0xc0 | ((c >> 12) & 0xf));
91+ if (count+1 < utf8len)
92+ utf8[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f));
93+ if (count+2 < utf8len)
94+ utf8[count+2] = (byte_t)(0x80 | (c & 0x3f));
95+ count += 3;
96+ }
97+ }
98+
99+ if (escaped) /* bad final escape */
100+ return -1;
101+
102+ return count;
103+}
104+
105+/** TIMESTAMPS
106+ **/
107+void
108+sms_timestamp_now( SmsTimeStamp stamp )
109+{
110+ time_t now_time = time(NULL);
111+ struct tm gm = *(gmtime(&now_time));
112+ struct tm local = *(localtime(&now_time));
113+ int tzdiff = 0;
114+
115+ stamp->data[0] = gsm_int_to_bcdi( local.tm_year % 100 );
116+ stamp->data[1] = gsm_int_to_bcdi( local.tm_mon+1 );
117+ stamp->data[2] = gsm_int_to_bcdi( local.tm_mday );
118+ stamp->data[3] = gsm_int_to_bcdi( local.tm_hour );
119+ stamp->data[4] = gsm_int_to_bcdi( local.tm_min );
120+ stamp->data[5] = gsm_int_to_bcdi( local.tm_sec );
121+
122+ tzdiff = (local.tm_hour*4 + local.tm_min/15) - (gm.tm_hour*4 + gm.tm_min/15);
123+ if (local.tm_yday > gm.tm_yday)
124+ tzdiff += 24*4;
125+ else if (local.tm_yday < gm.tm_yday)
126+ tzdiff -= 24*4;
127+
128+ stamp->data[6] = gsm_int_to_bcdi( tzdiff >= 0 ? tzdiff : -tzdiff );
129+ if (tzdiff < 0)
130+ stamp->data[6] |= 0x08;
131+}
132+
133+int
134+sms_timestamp_to_tm( SmsTimeStamp stamp, struct tm* tm )
135+{
136+ int tzdiff;
137+
138+ tm->tm_year = gsm_int_from_bcdi( stamp->data[0] );
139+ if (tm->tm_year < 50)
140+ tm->tm_year += 100;
141+ tm->tm_mon = gsm_int_from_bcdi( stamp->data[1] ) -1;
142+ tm->tm_mday = gsm_int_from_bcdi( stamp->data[2] );
143+ tm->tm_hour = gsm_int_from_bcdi( stamp->data[3] );
144+ tm->tm_min = gsm_int_from_bcdi( stamp->data[4] );
145+ tm->tm_sec = gsm_int_from_bcdi( stamp->data[5] );
146+
147+ tm->tm_isdst = -1;
148+
149+ tzdiff = gsm_int_from_bcdi( stamp->data[6] & 0xf7 );
150+ if (stamp->data[6] & 0x8)
151+ tzdiff = -tzdiff;
152+
153+ return tzdiff;
154+}
155+
156+static void
157+gsm_rope_add_timestamp( GsmRope rope, const SmsTimeStampRec* ts )
158+{
159+ gsm_rope_add( rope, ts->data, 7 );
160+}
161+
162+
163+/** SMS ADDRESSES
164+ **/
165+int
166+sms_address_to_str( SmsAddress address, char* str, int strlen )
167+{
168+ bytes_t data = address->data;
169+ if(address->toa == 0x91)
170+ *str++='+';
171+ int i;
172+ char c;
173+ for (i=0;i<address->len;i++) {
174+ c=data[i/2];
175+ if(i&1) c=c>>4;
176+ *str++='0'+(c&15);
177+ }
178+ *str=0;
179+ return 1;
180+}
181+
182+
183+int
184+sms_address_from_str( SmsAddress address, const char* src, int srclen )
185+{
186+ const char* end = src + srclen;
187+ int shift = 0, len = 0;
188+ bytes_t data = address->data;
189+
190+ address->len = 0;
191+ address->toa = 0x81;
192+
193+ if (src >= end)
194+ return -1;
195+
196+ if (src[0] == '+') {
197+ address->toa = 0x91;
198+ if (++src == end)
199+ goto Fail;
200+ }
201+
202+ memset( address->data, 0, sizeof(address->data) );
203+
204+ shift = 0;
205+
206+ while (src < end) {
207+ int c = *src++ - '0';
208+
209+ if ( (unsigned)c >= 10 ||
210+ data >= address->data + sizeof(address->data) )
211+ goto Fail;
212+
213+ data[0] |= c << shift;
214+ len += 1;
215+ shift += 4;
216+ if (shift == 8) {
217+ shift = 0;
218+ data += 1;
219+ }
220+ }
221+ if (shift != 0)
222+ data[0] |= 0xf0;
223+
224+ address->len = len;
225+ return 0;
226+
227+Fail:
228+ return -1;
229+}
230+
231+int
232+sms_address_from_bytes( SmsAddress address, const unsigned char* buf, int buflen )
233+{
234+ int len = sizeof(address->data), num_digits;
235+
236+ if (buflen < 2)
237+ return -1;
238+
239+ address->len = num_digits = buf[0];
240+ address->toa = buf[1];
241+
242+ len = (num_digits+1)/2;
243+ if ( len > sizeof(address->data) )
244+ return -1;
245+
246+ memcpy( address->data, buf+2, len );
247+ return 0;
248+}
249+
250+int
251+sms_address_to_bytes( SmsAddress address, unsigned char* buf, int bufsize )
252+{
253+ int len = (address->len + 1)/2 + 2;
254+
255+ if (buf == NULL)
256+ bufsize = 0;
257+
258+ if (bufsize < 1) goto Exit;
259+ buf[0] = address->len;
260+
261+ if (bufsize < 2) goto Exit;
262+ buf[1] = address->toa;
263+
264+ buf += 2;
265+ bufsize -= 2;
266+ if (bufsize > len-2)
267+ bufsize = len - 2;
268+
269+ memcpy( buf, address->data, bufsize );
270+Exit:
271+ return len;
272+}
273+
274+int
275+sms_address_from_hex ( SmsAddress address, const char* hex, int hexlen )
276+{
277+ const char* hexend = hex + hexlen;
278+ int nn, len, num_digits;
279+
280+ if (hexlen < 4)
281+ return -1;
282+
283+ address->len = num_digits = gsm_hex2_to_byte( hex );
284+ address->toa = gsm_hex2_to_byte( hex+2 );
285+ hex += 4;
286+
287+ len = (num_digits + 1)/2;
288+ if (hex + len*2 > hexend)
289+ return -1;
290+
291+ for ( nn = 0; nn < len; nn++ )
292+ address->data[nn] = gsm_hex2_to_byte( hex + nn*2 );
293+
294+ return 0;
295+}
296+
297+int
298+sms_address_to_hex ( SmsAddress address, char* hex, int hexlen )
299+{
300+ int len = (address->len + 1)/2 + 2;
301+ int nn;
302+
303+ if (hex == NULL)
304+ hexlen = 0;
305+
306+ if (hexlen < 2) goto Exit;
307+ gsm_hex_from_byte( hex, address->len );
308+ if (hexlen < 4) goto Exit;
309+ gsm_hex_from_byte( hex+2, address->toa );
310+ hex += 4;
311+ hexlen -= 4;
312+ if ( hexlen > 2*(len - 2) )
313+ hexlen = (len - 2)/2;
314+
315+ for ( nn = 0; nn < hexlen; nn += 2 )
316+ gsm_hex_from_byte( hex+nn, address->data[nn/2] );
317+
318+Exit:
319+ return len*2;
320+}
321+
322+static void
323+gsm_rope_add_address( GsmRope rope, const SmsAddressRec* addr )
324+{
325+ gsm_rope_add_c( rope, addr->len );
326+ gsm_rope_add_c( rope, addr->toa );
327+ gsm_rope_add( rope, addr->data, (addr->len+1)/2 );
328+ if (addr->len & 1) {
329+ if (!rope->error && rope->data != NULL)
330+ rope->data[ rope->pos-1 ] |= 0xf0;
331+ }
332+}
333+
334+
335+/** SMS PARSER
336+ **/
337+static int
338+sms_get_byte( cbytes_t *pcur, cbytes_t end )
339+{
340+ cbytes_t cur = *pcur;
341+ int result = -1;
342+
343+ if (cur < end) {
344+ result = cur[0];
345+ *pcur = cur + 1;
346+ }
347+ return result;
348+}
349+
350+/* parse a service center address, returns -1 in case of error */
351+static int
352+sms_get_sc_address( cbytes_t *pcur,
353+ cbytes_t end,
354+ SmsAddress address )
355+{
356+ cbytes_t cur = *pcur;
357+ int result = -1;
358+
359+ if (cur < end) {
360+ int len = cur[0];
361+ int dlen, adjust = 0;
362+
363+ cur += 1;
364+
365+ if (len == 0) { /* empty address */
366+ address->len = 0;
367+ address->toa = 0x00;
368+ result = 0;
369+ goto Exit;
370+ }
371+
372+ if (cur + len > end) {
373+ goto Exit;
374+ }
375+
376+ address->toa = *cur++;
377+ len -= 1;
378+ result = 0;
379+
380+ for (dlen = 0; dlen < len; dlen+=1) {
381+ int c = cur[dlen];
382+ int v;
383+
384+ adjust = 0;
385+ if (dlen >= sizeof(address->data)) {
386+ result = -1;
387+ break;
388+ }
389+
390+ v = (c & 0xf);
391+ if (v >= 0xe)
392+ break;
393+
394+ adjust = 1;
395+ address->data[dlen] = (byte_t) c;
396+
397+ v = (c >> 4) & 0xf;
398+ if (v >= 0xe) {
399+ break;
400+ }
401+ }
402+ address->len = 2*dlen + adjust;
403+ }
404+Exit:
405+ if (!result)
406+ *pcur = cur;
407+
408+ return result;
409+}
410+
411+static int
412+sms_skip_sc_address( cbytes_t *pcur,
413+ cbytes_t end )
414+{
415+ cbytes_t cur = *pcur;
416+ int result = -1;
417+ int len;
418+
419+ if (cur >= end)
420+ goto Exit;
421+
422+ len = cur[0];
423+ cur += 1 + len;
424+ if (cur > end)
425+ goto Exit;
426+
427+ *pcur = cur;
428+ result = 0;
429+Exit:
430+ return result;
431+}
432+
433+/* parse a sender/receiver address, returns -1 in case of error */
434+static int
435+sms_get_address( cbytes_t *pcur,
436+ cbytes_t end,
437+ SmsAddress address )
438+{
439+ cbytes_t cur = *pcur;
440+ int result = -1;
441+ int len, dlen;
442+
443+ if (cur >= end)
444+ goto Exit;
445+
446+ dlen = *cur++;
447+
448+ if (dlen == 0) {
449+ address->len = 0;
450+ address->toa = 0;
451+ result = 0;
452+ goto Exit;
453+ }
454+
455+ if (cur + 1 + (dlen+1)/2 > end)
456+ goto Exit;
457+
458+ address->len = dlen;
459+ address->toa = *cur++;
460+
461+ len = (dlen + 1)/2;
462+ if (len > sizeof(address->data))
463+ goto Exit;
464+
465+ memcpy( address->data, cur, len );
466+ cur += len;
467+ result = 0;
468+
469+Exit:
470+ if (!result)
471+ *pcur = cur;
472+
473+ return result;
474+}
475+
476+static int
477+sms_skip_address( cbytes_t *pcur,
478+ cbytes_t end )
479+{
480+ cbytes_t cur = *pcur;
481+ int result = -1;
482+ int dlen;
483+
484+ if (cur + 2 > end)
485+ goto Exit;
486+
487+ dlen = cur[0];
488+ cur += 2 + (dlen + 1)/2;
489+ if (cur > end)
490+ goto Exit;
491+
492+ result = 0;
493+Exit:
494+ return result;
495+}
496+
497+/* parse a service center timestamp */
498+static int
499+sms_get_timestamp( cbytes_t *pcur,
500+ cbytes_t end,
501+ SmsTimeStamp ts )
502+{
503+ cbytes_t cur = *pcur;
504+
505+ if (cur + 7 > end)
506+ return -1;
507+
508+ memcpy( ts->data, cur, 7 );
509+ *pcur = cur + 7;
510+ return 0;
511+}
512+
513+static int
514+sms_skip_timestamp( cbytes_t *pcur,
515+ cbytes_t end )
516+{
517+ cbytes_t cur = *pcur;
518+
519+ if (cur + 7 > end)
520+ return -1;
521+
522+ *pcur = cur + 7;
523+ return 0;
524+}
525+
526+
527+/** SMS PDU
528+ **/
529+
530+typedef struct SmsPDURec {
531+ bytes_t base;
532+ bytes_t end;
533+ bytes_t tpdu;
534+} SmsPDURec;
535+
536+void
537+smspdu_free( SmsPDU pdu )
538+{
539+ if (pdu) {
540+ free( pdu->base );
541+ pdu->base = NULL;
542+ pdu->end = NULL;
543+ pdu->tpdu = NULL;
544+ }
545+}
546+
547+SmsPduType
548+smspdu_get_type( SmsPDU pdu )
549+{
550+ cbytes_t data = pdu->tpdu;
551+ cbytes_t end = pdu->end;
552+ int mtiByte = sms_get_byte(&data, end);
553+
554+ switch (mtiByte & 3) {
555+ case 0: return SMS_PDU_DELIVER;
556+ case 1: return SMS_PDU_SUBMIT;
557+ case 2: return SMS_PDU_STATUS_REPORT;
558+ default: return SMS_PDU_INVALID;
559+ }
560+}
561+
562+int
563+smspdu_get_sender_address( SmsPDU pdu, SmsAddress address )
564+{
565+ cbytes_t data = pdu->tpdu;
566+ cbytes_t end = pdu->end;
567+ int mtiByte = sms_get_byte(&data, end);
568+
569+ switch (mtiByte & 3) {
570+ case 0: /* SMS_PDU_DELIVER; */
571+ return sms_get_sc_address( &data, end, address );
572+
573+ default: return -1;
574+ }
575+}
576+
577+int
578+smspdu_get_sc_timestamp( SmsPDU pdu, SmsTimeStamp ts )
579+{
580+ cbytes_t data = pdu->tpdu;
581+ cbytes_t end = pdu->end;
582+ int mtiByte = sms_get_byte( &data, end );
583+
584+ switch (mtiByte & 3) {
585+ case 0: /* SMS_PDU_DELIVER */
586+ {
587+ SmsAddressRec address;
588+
589+ if ( sms_get_sc_address( &data, end, &address ) < 0 )
590+ return -1;
591+
592+ data += 2; /* skip protocol identifer + coding scheme */
593+
594+ return sms_get_timestamp( &data, end, ts );
595+ }
596+
597+ default: return -1;
598+ }
599+}
600+
601+int
602+smspdu_get_receiver_address( SmsPDU pdu, SmsAddress address )
603+{
604+ cbytes_t data = pdu->tpdu;
605+ cbytes_t end = pdu->end;
606+ int mtiByte = sms_get_byte( &data, end );
607+
608+ switch (mtiByte & 3) {
609+ case 1: /* SMS_PDU_SUBMIT */
610+ {
611+ data += 1; /* skip message reference */
612+ return sms_get_address( &data, end, address );
613+ }
614+
615+ default: return -1;
616+ }
617+}
618+
619+typedef enum {
620+ SMS_CODING_SCHEME_UNKNOWN = 0,
621+ SMS_CODING_SCHEME_GSM7,
622+ SMS_CODING_SCHEME_UCS2
623+
624+} SmsCodingScheme;
625+
626+/* see TS 23.038 Section 5 for details */
627+static SmsCodingScheme
628+sms_get_coding_scheme( cbytes_t *pcur,
629+ cbytes_t end )
630+{
631+ cbytes_t cur = *pcur;
632+ int dataCoding;
633+
634+ if (cur >= end)
635+ return SMS_CODING_SCHEME_UNKNOWN;
636+
637+ dataCoding = *cur++;
638+ *pcur = cur;
639+
640+ switch (dataCoding >> 4) {
641+ case 0x00:
642+ case 0x02:
643+ case 0x03:
644+ return SMS_CODING_SCHEME_GSM7;
645+
646+ case 0x01:
647+ if (dataCoding == 0x10) return SMS_CODING_SCHEME_GSM7;
648+ if (dataCoding == 0x11) return SMS_CODING_SCHEME_UCS2;
649+ break;
650+
651+ case 0x04: case 0x05: case 0x06: case 0x07:
652+ if (dataCoding & 0x20) return SMS_CODING_SCHEME_UNKNOWN; /* compressed 7-bits */
653+ if (((dataCoding >> 2) & 3) == 0) return SMS_CODING_SCHEME_GSM7;
654+ if (((dataCoding >> 2) & 3) == 2) return SMS_CODING_SCHEME_UCS2;
655+ break;
656+
657+ case 0xF:
658+ if (!(dataCoding & 4)) return SMS_CODING_SCHEME_GSM7;
659+ break;
660+ }
661+ return SMS_CODING_SCHEME_UNKNOWN;
662+}
663+
664+
665+/* see TS 23.040 section 9.2.3.24 for details */
666+static int
667+sms_get_text_utf8( cbytes_t *pcur,
668+ cbytes_t end,
669+ int hasUDH,
670+ SmsCodingScheme coding,
671+ GsmRope rope )
672+{
673+ cbytes_t cur = *pcur;
674+ int result = -1;
675+ int len;
676+
677+#ifdef nodroid
678+ printf("sms_get_text_utf8 %d %d\n",hasUDH,coding);
679+#endif
680+ if (cur >= end)
681+ goto Exit;
682+
683+ len = *cur++;
684+
685+ /* skip user data header if any */
686+ if ( hasUDH )
687+ {
688+ int hlen;
689+
690+ if (cur >= end)
691+ goto Exit;
692+
693+ hlen = *cur++;
694+ if (cur + hlen > end)
695+ goto Exit;
696+
697+ cur += hlen;
698+
699+ if (coding == SMS_CODING_SCHEME_GSM7)
700+ len -= (hlen*2-2);
701+ else
702+ len -= hlen+1;
703+
704+ if (len < 0)
705+ goto Exit;
706+ }
707+
708+ /* switch the user data header if any */
709+ if (coding == SMS_CODING_SCHEME_GSM7) {
710+ int count = utf8_from_gsm7( cur, 0, len, NULL );
711+
712+ if (rope != NULL)
713+ {
714+ bytes_t dst = gsm_rope_reserve( rope, count );
715+ if(hasUDH && dst)
716+ *dst++=(*cur++)>>1;
717+ if (dst != NULL)
718+ utf8_from_gsm7( cur, 0, len, dst );
719+ }
720+ cur += (len+1)/2;
721+ } else if (coding == SMS_CODING_SCHEME_UCS2) {
722+ int count = ucs2_to_utf8( cur, len/2, NULL );
723+
724+ if (rope != NULL)
725+ {
726+ bytes_t dst = gsm_rope_reserve( rope, count );
727+ if (dst != NULL)
728+ ucs2_to_utf8( cur, len/2, dst );
729+ }
730+ cur += len;
731+ }
732+ result = 0;
733+
734+Exit:
735+ if (!result)
736+ *pcur = cur;
737+
738+ return result;
739+}
740+
741+/* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */
742+/* or -1 in case of error */
743+int
744+smspdu_get_text_message( SmsPDU pdu, unsigned char* utf8, int utf8len )
745+{
746+ cbytes_t data = pdu->tpdu;
747+ cbytes_t end = pdu->end;
748+ int mtiByte = sms_get_byte( &data, end );
749+
750+ switch (mtiByte & 3) {
751+ case 0: /* SMS_PDU_DELIVER */
752+ {
753+ SmsAddressRec address;
754+ SmsTimeStampRec timestamp;
755+ SmsCodingScheme coding;
756+ GsmRopeRec rope[1];
757+ int result;
758+
759+ if ( sms_get_sc_address( &data, end, &address ) < 0 )
760+ goto Fail;
761+
762+ data += 1; /* skip protocol identifier */
763+ coding = sms_get_coding_scheme( &data, end );
764+ if (coding == SMS_CODING_SCHEME_UNKNOWN)
765+ goto Fail;
766+
767+ if ( sms_get_timestamp( &data, end, &timestamp ) < 0 )
768+ goto Fail;
769+
770+ gsm_rope_init_alloc( rope, 0 );
771+ if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 )
772+ goto Fail;
773+
774+ result = rope->pos;
775+ if (utf8len > result)
776+ utf8len = result;
777+
778+ if (utf8len > 0)
779+ memcpy( utf8, rope->data, utf8len );
780+
781+ gsm_rope_done( rope );
782+ return result;
783+ }
784+
785+ case 1: /* SMS_PDU_SUBMIT */
786+ {
787+ SmsAddressRec address;
788+ SmsCodingScheme coding;
789+ GsmRopeRec rope[1];
790+ int result;
791+
792+ data += 1; /* message reference */
793+
794+ if ( sms_get_address( &data, end, &address ) < 0 )
795+ goto Fail;
796+
797+ data += 1; /* skip protocol identifier */
798+ coding = sms_get_coding_scheme( &data, end );
799+ if (coding == SMS_CODING_SCHEME_UNKNOWN)
800+ goto Fail;
801+
802+ gsm_rope_init_alloc( rope, 0 );
803+ if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 ) {
804+ gsm_rope_done( rope );
805+ goto Fail;
806+ }
807+
808+ result = rope->pos;
809+ if (utf8len > result)
810+ utf8len = result;
811+
812+ if (utf8len > 0)
813+ memcpy( utf8, rope->data, utf8len );
814+
815+ gsm_rope_done( rope );
816+ return result;
817+ }
818+ }
819+Fail:
820+ return -1;
821+}
822+
823+
824+static void
825+gsm_rope_add_sms_user_header( GsmRope rope,
826+ int ref_number,
827+ int pdu_count,
828+ int pdu_index )
829+{
830+ gsm_rope_add_c( rope, 0x05 ); /* total header length == 5 bytes */
831+ gsm_rope_add_c( rope, 0x00 ); /* element id: concatenated message reference number */
832+ gsm_rope_add_c( rope, 0x03 ); /* element len: 3 bytes */
833+ gsm_rope_add_c( rope, (byte_t)ref_number ); /* reference number */
834+ gsm_rope_add_c( rope, (byte_t)pdu_count ); /* max pdu index */
835+ gsm_rope_add_c( rope, (byte_t)pdu_index+1 ); /* current pdu index */
836+}
837+
838+/* write a SMS-DELIVER PDU into a rope */
839+static void
840+gsm_rope_add_sms_deliver_pdu( GsmRope rope,
841+ cbytes_t utf8,
842+ int utf8len,
843+ int use_gsm7,
844+ const SmsAddressRec* sender_address,
845+ const SmsTimeStampRec* timestamp,
846+ int ref_num,
847+ int pdu_count,
848+ int pdu_index)
849+{
850+ int count;
851+ int coding;
852+ int mtiByte = 0x20; /* message type - SMS DELIVER */
853+
854+ if (pdu_count > 1)
855+ mtiByte |= 0x40; /* user data header indicator */
856+
857+ gsm_rope_add_c( rope, 0 ); /* no SC Address */
858+ gsm_rope_add_c( rope, mtiByte ); /* message type - SMS-DELIVER */
859+ gsm_rope_add_address( rope, sender_address );
860+ gsm_rope_add_c( rope, 0 ); /* protocol identifier */
861+
862+ /* data coding scheme - GSM 7 bits / no class - or - 16-bit UCS2 / class 1 */
863+ coding = (use_gsm7 ? 0x00 : 0x09);
864+
865+ gsm_rope_add_c( rope, coding ); /* data coding scheme */
866+ gsm_rope_add_timestamp( rope, timestamp ); /* service center timestamp */
867+
868+ if (use_gsm7) {
869+ bytes_t dst;
870+ int count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
871+ int pad = 0;
872+
873+ //assert( count <= MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE );
874+
875+ if (pdu_count > 1) {
876+ int headerBits = 6*8; /* 6 is size of header in bytes */
877+ int headerSeptets = headerBits / 7;
878+ if (headerBits % 7 > 0)
879+ headerSeptets += 1;
880+
881+ pad = headerSeptets*7 - headerBits;
882+
883+ gsm_rope_add_c( rope, count + headerSeptets );
884+ gsm_rope_add_sms_user_header(rope, ref_num, pdu_count, pdu_index);
885+ } else {
886+ gsm_rope_add_c( rope, count );
887+ }
888+
889+ count = (count*7+pad+7)/8; /* convert to byte count */
890+
891+ dst = gsm_rope_reserve( rope, count );
892+ if (dst != NULL) {
893+ utf8_to_gsm7( utf8, utf8len, dst, pad );
894+ }
895+ } else {
896+ bytes_t dst;
897+ int count = utf8_to_ucs2( utf8, utf8len, NULL );
898+
899+ //assert( count*2 <= MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE );
900+
901+ if (pdu_count > 1) {
902+ gsm_rope_add_c( rope, count*2 + 6 );
903+ gsm_rope_add_sms_user_header( rope, ref_num, pdu_count, pdu_index );
904+ } else {
905+ gsm_rope_add_c( rope, count*2 );
906+ }
907+
908+ gsm_rope_add_c( rope, count*2 );
909+ dst = gsm_rope_reserve( rope, count*2 );
910+ if (dst != NULL) {
911+ utf8_to_ucs2( utf8, utf8len, dst );
912+ }
913+ }
914+}
915+
916+
917+static SmsPDU
918+smspdu_create_deliver( cbytes_t utf8,
919+ int utf8len,
920+ int use_gsm7,
921+ const SmsAddressRec* sender_address,
922+ const SmsTimeStampRec* timestamp,
923+ int ref_num,
924+ int pdu_count,
925+ int pdu_index )
926+{
927+ SmsPDU p;
928+ GsmRopeRec rope[1];
929+ int size;
930+
931+ p = calloc( sizeof(*p), 1 );
932+ if (!p) goto Exit;
933+
934+ gsm_rope_init( rope );
935+ gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
936+ sender_address, timestamp,
937+ ref_num, pdu_count, pdu_index);
938+ if (rope->error)
939+ goto Fail;
940+
941+ gsm_rope_init_alloc( rope, rope->pos );
942+
943+ gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
944+ sender_address, timestamp,
945+ ref_num, pdu_count, pdu_index );
946+
947+ p->base = gsm_rope_done_acquire( rope, &size );
948+ if (p->base == NULL)
949+ goto Fail;
950+
951+ p->end = p->base + size;
952+ p->tpdu = p->base + 1;
953+Exit:
954+ return p;
955+
956+Fail:
957+ free(p);
958+ return NULL;
959+}
960+
961+
962+void
963+smspdu_free_list( SmsPDU* pdus )
964+{
965+ if (pdus) {
966+ int nn;
967+ for (nn = 0; pdus[nn] != NULL; nn++)
968+ smspdu_free( pdus[nn] );
969+
970+ free( pdus );
971+ }
972+}
973+
974+
975+
976+SmsPDU*
977+smspdu_create_deliver_utf8( const unsigned char* utf8,
978+ int utf8len,
979+ const SmsAddressRec* sender_address,
980+ const SmsTimeStampRec* timestamp )
981+{
982+ SmsTimeStampRec ts0;
983+ int use_gsm7;
984+ int count, block;
985+ int num_pdus = 0;
986+ int leftover = 0;
987+ SmsPDU* list = NULL;
988+
989+ static unsigned char ref_num = 0;
990+
991+ if (timestamp == NULL) {
992+ sms_timestamp_now( &ts0 );
993+ timestamp = &ts0;
994+ }
995+
996+ /* can we encode the message with the GSM 7-bit alphabet ? */
997+ use_gsm7 = utf8_check_gsm7( utf8, utf8len );
998+
999+ /* count the number of SMS PDUs we'll need */
1000+ block = MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE;
1001+
1002+ if (use_gsm7) {
1003+ count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
1004+ } else {
1005+ count = utf8_to_ucs2( utf8, utf8len, NULL );
1006+ block = MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE;
1007+ }
1008+
1009+ num_pdus = count / block;
1010+ leftover = count - num_pdus*block;
1011+ if (leftover > 0)
1012+ num_pdus += 1;
1013+
1014+ list = calloc( sizeof(SmsPDU*), count + 1 );
1015+ if (list == NULL)
1016+ return NULL;
1017+
1018+ /* now create each SMS PDU */
1019+ {
1020+ cbytes_t src = utf8;
1021+ cbytes_t src_end = utf8 + utf8len;
1022+ int nn;
1023+
1024+ for (nn = 0; nn < num_pdus; nn++) {
1025+ int skip = block;
1026+ cbytes_t src_next;
1027+
1028+ if (leftover > 0 && nn == num_pdus-1)
1029+ skip = leftover;
1030+
1031+ src_next = utf8_skip( src, src_end, skip );
1032+ list[nn] = smspdu_create_deliver( src, src_next - src, use_gsm7, sender_address, timestamp,
1033+ ref_num, num_pdus, nn );
1034+ if (list[nn] == NULL)
1035+ goto Fail;
1036+
1037+ src = src_next;
1038+ }
1039+ }
1040+
1041+ ref_num++;
1042+
1043+Exit:
1044+ return list;
1045+
1046+Fail:
1047+ smspdu_free_list(list);
1048+ return NULL;
1049+}
1050+
1051+
1052+SmsPDU
1053+smspdu_create_from_hex( const char* hex, int hexlen )
1054+{
1055+ SmsPDU p;
1056+ cbytes_t data;
1057+
1058+ p = calloc( sizeof(*p), 1 );
1059+ if (!p) goto Exit;
1060+
1061+ p->base = malloc( (hexlen+1)/2 );
1062+ if (p->base == NULL) {
1063+ free(p);
1064+ p = NULL;
1065+ goto Exit;
1066+ }
1067+
1068+ gsm_hex_to_bytes( hex, hexlen, p->base );
1069+ p->end = p->base + (hexlen+1)/2;
1070+
1071+ data = p->base;
1072+ if ( sms_skip_sc_address( &data, p->end ) < 0 )
1073+ goto Fail;
1074+
1075+ p->tpdu = (bytes_t) data;
1076+
1077+Exit:
1078+ return p;
1079+
1080+Fail:
1081+ free(p->base);
1082+ free(p);
1083+ return NULL;
1084+}
1085+
1086+int
1087+smspdu_to_hex( SmsPDU pdu, char* hex, int hexlen )
1088+{
1089+ int result = (pdu->end - pdu->base)*2;
1090+ int nn;
1091+
1092+ if (hexlen > result)
1093+ hexlen = result;
1094+
1095+ for (nn = 0; nn*2 < hexlen; nn++) {
1096+ gsm_hex_from_byte( &hex[nn*2], pdu->base[nn] );
1097+ }
1098+ return result;
1099+}
--- /dev/null
+++ b/huaweigeneric-ril/sms_gsm.h
@@ -0,0 +1,85 @@
1+#ifndef _android_sms_h
2+#define _android_sms_h
3+
4+#include <time.h>
5+
6+/** MESSAGE TEXT
7+ **/
8+/* convert a quoted message text into a utf8 string. Note: you can use 'str' as the destination buffer
9+ * with the current implementation. always return the number of utf8 bytes corresponding to the original
10+ * message string, even if utf8 is NULL and utf8len is 0
11+ */
12+extern int sms_utf8_from_message_str( const char* str, int strlen, unsigned char* utf8, int utf8len );
13+
14+/** TIMESTAMPS
15+ **/
16+
17+/* An SMS timestamp structure */
18+typedef struct {
19+ unsigned char data[7];
20+} SmsTimeStampRec, *SmsTimeStamp;
21+
22+extern void sms_timestamp_now( SmsTimeStamp stamp );
23+extern int sms_timestamp_to_tm( SmsTimeStamp stamp, struct tm* tm );
24+
25+/** SMS ADDRESSES
26+ **/
27+
28+#define SMS_ADDRESS_MAX_SIZE 16
29+
30+typedef struct {
31+ unsigned char len;
32+ unsigned char toa;
33+ unsigned char data[ SMS_ADDRESS_MAX_SIZE ];
34+} SmsAddressRec, *SmsAddress;
35+
36+extern int sms_address_from_str( SmsAddress address, const char* src, int srclen );
37+extern int sms_address_to_str( SmsAddress address, char* src, int srclen );
38+
39+extern int sms_address_from_bytes( SmsAddress address, const unsigned char* buf, int buflen );
40+extern int sms_address_to_bytes ( SmsAddress address, unsigned char* buf, int bufsize );
41+extern int sms_address_from_hex ( SmsAddress address, const char* hex, int hexlen );
42+extern int sms_address_to_hex ( SmsAddress address, char* hex, int hexsize );
43+
44+/** SMS PROTOCOL DATA UNITS
45+ **/
46+
47+typedef struct SmsPDURec* SmsPDU;
48+
49+extern SmsPDU* smspdu_create_deliver_utf8( const unsigned char* utf8,
50+ int utf8len,
51+ const SmsAddressRec* sender_address,
52+ const SmsTimeStampRec* timestamp );
53+
54+extern void smspdu_free_list( SmsPDU* pdus );
55+
56+extern SmsPDU smspdu_create_from_hex( const char* hex, int hexlen );
57+
58+extern int smspdu_to_hex( SmsPDU pdu, char* hex, int hexsize );
59+
60+/* free a given SMS PDU */
61+extern void smspdu_free( SmsPDU pdu );
62+
63+typedef enum {
64+ SMS_PDU_INVALID = 0,
65+ SMS_PDU_DELIVER,
66+ SMS_PDU_SUBMIT,
67+ SMS_PDU_STATUS_REPORT
68+} SmsPduType;
69+
70+extern SmsPduType smspdu_get_type( SmsPDU pdu );
71+
72+/* retrieve the sender address of a SMS-DELIVER pdu, returns -1 otherwise */
73+extern int smspdu_get_sender_address( SmsPDU pdu, SmsAddress address );
74+
75+/* retrieve the service center timestamp of a SMS-DELIVER pdu, return -1 otherwise */
76+extern int smspdu_get_sc_timestamp( SmsPDU pdu, SmsTimeStamp timestamp );
77+
78+/* retrieve the receiver address of a SMS-SUBMIT pdu, return -1 otherwise */
79+extern int smspdu_get_receiver_address( SmsPDU pdu, SmsAddress address );
80+
81+/* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */
82+/* or -1 in case of error */
83+extern int smspdu_get_text_message( SmsPDU pdu, unsigned char* utf8, int utf8len );
84+
85+#endif /* _android_sms_h */
Show on old repository browser